diff --git a/venv/bin/Activate.ps1 b/venv/bin/Activate.ps1 deleted file mode 100644 index 2fb3852..0000000 --- a/venv/bin/Activate.ps1 +++ /dev/null @@ -1,241 +0,0 @@ -<# -.Synopsis -Activate a Python virtual environment for the current PowerShell session. - -.Description -Pushes the python executable for a virtual environment to the front of the -$Env:PATH environment variable and sets the prompt to signify that you are -in a Python virtual environment. Makes use of the command line switches as -well as the `pyvenv.cfg` file values present in the virtual environment. - -.Parameter VenvDir -Path to the directory that contains the virtual environment to activate. The -default value for this is the parent of the directory that the Activate.ps1 -script is located within. - -.Parameter Prompt -The prompt prefix to display when this virtual environment is activated. By -default, this prompt is the name of the virtual environment folder (VenvDir) -surrounded by parentheses and followed by a single space (ie. '(.venv) '). - -.Example -Activate.ps1 -Activates the Python virtual environment that contains the Activate.ps1 script. - -.Example -Activate.ps1 -Verbose -Activates the Python virtual environment that contains the Activate.ps1 script, -and shows extra information about the activation as it executes. - -.Example -Activate.ps1 -VenvDir C:\Users\MyUser\Common\.venv -Activates the Python virtual environment located in the specified location. - -.Example -Activate.ps1 -Prompt "MyPython" -Activates the Python virtual environment that contains the Activate.ps1 script, -and prefixes the current prompt with the specified string (surrounded in -parentheses) while the virtual environment is active. - -.Notes -On Windows, it may be required to enable this Activate.ps1 script by setting the -execution policy for the user. You can do this by issuing the following PowerShell -command: - -PS C:\> Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser - -For more information on Execution Policies: -https://go.microsoft.com/fwlink/?LinkID=135170 - -#> -Param( - [Parameter(Mandatory = $false)] - [String] - $VenvDir, - [Parameter(Mandatory = $false)] - [String] - $Prompt -) - -<# Function declarations --------------------------------------------------- #> - -<# -.Synopsis -Remove all shell session elements added by the Activate script, including the -addition of the virtual environment's Python executable from the beginning of -the PATH variable. - -.Parameter NonDestructive -If present, do not remove this function from the global namespace for the -session. - -#> -function global:deactivate ([switch]$NonDestructive) { - # Revert to original values - - # The prior prompt: - if (Test-Path -Path Function:_OLD_VIRTUAL_PROMPT) { - Copy-Item -Path Function:_OLD_VIRTUAL_PROMPT -Destination Function:prompt - Remove-Item -Path Function:_OLD_VIRTUAL_PROMPT - } - - # The prior PYTHONHOME: - if (Test-Path -Path Env:_OLD_VIRTUAL_PYTHONHOME) { - Copy-Item -Path Env:_OLD_VIRTUAL_PYTHONHOME -Destination Env:PYTHONHOME - Remove-Item -Path Env:_OLD_VIRTUAL_PYTHONHOME - } - - # The prior PATH: - if (Test-Path -Path Env:_OLD_VIRTUAL_PATH) { - Copy-Item -Path Env:_OLD_VIRTUAL_PATH -Destination Env:PATH - Remove-Item -Path Env:_OLD_VIRTUAL_PATH - } - - # Just remove the VIRTUAL_ENV altogether: - if (Test-Path -Path Env:VIRTUAL_ENV) { - Remove-Item -Path env:VIRTUAL_ENV - } - - # Just remove the _PYTHON_VENV_PROMPT_PREFIX altogether: - if (Get-Variable -Name "_PYTHON_VENV_PROMPT_PREFIX" -ErrorAction SilentlyContinue) { - Remove-Variable -Name _PYTHON_VENV_PROMPT_PREFIX -Scope Global -Force - } - - # Leave deactivate function in the global namespace if requested: - if (-not $NonDestructive) { - Remove-Item -Path function:deactivate - } -} - -<# -.Description -Get-PyVenvConfig parses the values from the pyvenv.cfg file located in the -given folder, and returns them in a map. - -For each line in the pyvenv.cfg file, if that line can be parsed into exactly -two strings separated by `=` (with any amount of whitespace surrounding the =) -then it is considered a `key = value` line. The left hand string is the key, -the right hand is the value. - -If the value starts with a `'` or a `"` then the first and last character is -stripped from the value before being captured. - -.Parameter ConfigDir -Path to the directory that contains the `pyvenv.cfg` file. -#> -function Get-PyVenvConfig( - [String] - $ConfigDir -) { - Write-Verbose "Given ConfigDir=$ConfigDir, obtain values in pyvenv.cfg" - - # Ensure the file exists, and issue a warning if it doesn't (but still allow the function to continue). - $pyvenvConfigPath = Join-Path -Resolve -Path $ConfigDir -ChildPath 'pyvenv.cfg' -ErrorAction Continue - - # An empty map will be returned if no config file is found. - $pyvenvConfig = @{ } - - if ($pyvenvConfigPath) { - - Write-Verbose "File exists, parse `key = value` lines" - $pyvenvConfigContent = Get-Content -Path $pyvenvConfigPath - - $pyvenvConfigContent | ForEach-Object { - $keyval = $PSItem -split "\s*=\s*", 2 - if ($keyval[0] -and $keyval[1]) { - $val = $keyval[1] - - # Remove extraneous quotations around a string value. - if ("'""".Contains($val.Substring(0, 1))) { - $val = $val.Substring(1, $val.Length - 2) - } - - $pyvenvConfig[$keyval[0]] = $val - Write-Verbose "Adding Key: '$($keyval[0])'='$val'" - } - } - } - return $pyvenvConfig -} - - -<# Begin Activate script --------------------------------------------------- #> - -# Determine the containing directory of this script -$VenvExecPath = Split-Path -Parent $MyInvocation.MyCommand.Definition -$VenvExecDir = Get-Item -Path $VenvExecPath - -Write-Verbose "Activation script is located in path: '$VenvExecPath'" -Write-Verbose "VenvExecDir Fullname: '$($VenvExecDir.FullName)" -Write-Verbose "VenvExecDir Name: '$($VenvExecDir.Name)" - -# Set values required in priority: CmdLine, ConfigFile, Default -# First, get the location of the virtual environment, it might not be -# VenvExecDir if specified on the command line. -if ($VenvDir) { - Write-Verbose "VenvDir given as parameter, using '$VenvDir' to determine values" -} -else { - Write-Verbose "VenvDir not given as a parameter, using parent directory name as VenvDir." - $VenvDir = $VenvExecDir.Parent.FullName.TrimEnd("\\/") - Write-Verbose "VenvDir=$VenvDir" -} - -# Next, read the `pyvenv.cfg` file to determine any required value such -# as `prompt`. -$pyvenvCfg = Get-PyVenvConfig -ConfigDir $VenvDir - -# Next, set the prompt from the command line, or the config file, or -# just use the name of the virtual environment folder. -if ($Prompt) { - Write-Verbose "Prompt specified as argument, using '$Prompt'" -} -else { - Write-Verbose "Prompt not specified as argument to script, checking pyvenv.cfg value" - if ($pyvenvCfg -and $pyvenvCfg['prompt']) { - Write-Verbose " Setting based on value in pyvenv.cfg='$($pyvenvCfg['prompt'])'" - $Prompt = $pyvenvCfg['prompt']; - } - else { - Write-Verbose " Setting prompt based on parent's directory's name. (Is the directory name passed to venv module when creating the virutal environment)" - Write-Verbose " Got leaf-name of $VenvDir='$(Split-Path -Path $venvDir -Leaf)'" - $Prompt = Split-Path -Path $venvDir -Leaf - } -} - -Write-Verbose "Prompt = '$Prompt'" -Write-Verbose "VenvDir='$VenvDir'" - -# Deactivate any currently active virtual environment, but leave the -# deactivate function in place. -deactivate -nondestructive - -# Now set the environment variable VIRTUAL_ENV, used by many tools to determine -# that there is an activated venv. -$env:VIRTUAL_ENV = $VenvDir - -if (-not $Env:VIRTUAL_ENV_DISABLE_PROMPT) { - - Write-Verbose "Setting prompt to '$Prompt'" - - # Set the prompt to include the env name - # Make sure _OLD_VIRTUAL_PROMPT is global - function global:_OLD_VIRTUAL_PROMPT { "" } - Copy-Item -Path function:prompt -Destination function:_OLD_VIRTUAL_PROMPT - New-Variable -Name _PYTHON_VENV_PROMPT_PREFIX -Description "Python virtual environment prompt prefix" -Scope Global -Option ReadOnly -Visibility Public -Value $Prompt - - function global:prompt { - Write-Host -NoNewline -ForegroundColor Green "($_PYTHON_VENV_PROMPT_PREFIX) " - _OLD_VIRTUAL_PROMPT - } -} - -# Clear PYTHONHOME -if (Test-Path -Path Env:PYTHONHOME) { - Copy-Item -Path Env:PYTHONHOME -Destination Env:_OLD_VIRTUAL_PYTHONHOME - Remove-Item -Path Env:PYTHONHOME -} - -# Add the venv to the PATH -Copy-Item -Path Env:PATH -Destination Env:_OLD_VIRTUAL_PATH -$Env:PATH = "$VenvExecDir$([System.IO.Path]::PathSeparator)$Env:PATH" diff --git a/venv/bin/activate b/venv/bin/activate deleted file mode 100644 index 0668033..0000000 --- a/venv/bin/activate +++ /dev/null @@ -1,66 +0,0 @@ -# This file must be used with "source bin/activate" *from bash* -# you cannot run it directly - -deactivate () { - # reset old environment variables - if [ -n "${_OLD_VIRTUAL_PATH:-}" ] ; then - PATH="${_OLD_VIRTUAL_PATH:-}" - export PATH - unset _OLD_VIRTUAL_PATH - fi - if [ -n "${_OLD_VIRTUAL_PYTHONHOME:-}" ] ; then - PYTHONHOME="${_OLD_VIRTUAL_PYTHONHOME:-}" - export PYTHONHOME - unset _OLD_VIRTUAL_PYTHONHOME - fi - - # This should detect bash and zsh, which have a hash command that must - # be called to get it to forget past commands. Without forgetting - # past commands the $PATH changes we made may not be respected - if [ -n "${BASH:-}" -o -n "${ZSH_VERSION:-}" ] ; then - hash -r 2> /dev/null - fi - - if [ -n "${_OLD_VIRTUAL_PS1:-}" ] ; then - PS1="${_OLD_VIRTUAL_PS1:-}" - export PS1 - unset _OLD_VIRTUAL_PS1 - fi - - unset VIRTUAL_ENV - if [ ! "${1:-}" = "nondestructive" ] ; then - # Self destruct! - unset -f deactivate - fi -} - -# unset irrelevant variables -deactivate nondestructive - -VIRTUAL_ENV=/opt/fleet-control-server/venv -export VIRTUAL_ENV - -_OLD_VIRTUAL_PATH="$PATH" -PATH="$VIRTUAL_ENV/"bin":$PATH" -export PATH - -# unset PYTHONHOME if set -# this will fail if PYTHONHOME is set to the empty string (which is bad anyway) -# could use `if (set -u; : $PYTHONHOME) ;` in bash -if [ -n "${PYTHONHOME:-}" ] ; then - _OLD_VIRTUAL_PYTHONHOME="${PYTHONHOME:-}" - unset PYTHONHOME -fi - -if [ -z "${VIRTUAL_ENV_DISABLE_PROMPT:-}" ] ; then - _OLD_VIRTUAL_PS1="${PS1:-}" - PS1='(venv) '"${PS1:-}" - export PS1 -fi - -# This should detect bash and zsh, which have a hash command that must -# be called to get it to forget past commands. Without forgetting -# past commands the $PATH changes we made may not be respected -if [ -n "${BASH:-}" -o -n "${ZSH_VERSION:-}" ] ; then - hash -r 2> /dev/null -fi diff --git a/venv/bin/activate.csh b/venv/bin/activate.csh deleted file mode 100644 index 1d115b9..0000000 --- a/venv/bin/activate.csh +++ /dev/null @@ -1,25 +0,0 @@ -# This file must be used with "source bin/activate.csh" *from csh*. -# You cannot run it directly. -# Created by Davide Di Blasi . -# Ported to Python 3.3 venv by Andrew Svetlov - -alias deactivate 'test $?_OLD_VIRTUAL_PATH != 0 && setenv PATH "$_OLD_VIRTUAL_PATH" && unset _OLD_VIRTUAL_PATH; rehash; test $?_OLD_VIRTUAL_PROMPT != 0 && set prompt="$_OLD_VIRTUAL_PROMPT" && unset _OLD_VIRTUAL_PROMPT; unsetenv VIRTUAL_ENV; test "\!:*" != "nondestructive" && unalias deactivate' - -# Unset irrelevant variables. -deactivate nondestructive - -setenv VIRTUAL_ENV /opt/fleet-control-server/venv - -set _OLD_VIRTUAL_PATH="$PATH" -setenv PATH "$VIRTUAL_ENV/"bin":$PATH" - - -set _OLD_VIRTUAL_PROMPT="$prompt" - -if (! "$?VIRTUAL_ENV_DISABLE_PROMPT") then - set prompt = '(venv) '"$prompt" -endif - -alias pydoc python -m pydoc - -rehash diff --git a/venv/bin/activate.fish b/venv/bin/activate.fish deleted file mode 100644 index 222fe07..0000000 --- a/venv/bin/activate.fish +++ /dev/null @@ -1,64 +0,0 @@ -# This file must be used with "source /bin/activate.fish" *from fish* -# (https://fishshell.com/); you cannot run it directly. - -function deactivate -d "Exit virtual environment and return to normal shell environment" - # reset old environment variables - if test -n "$_OLD_VIRTUAL_PATH" - set -gx PATH $_OLD_VIRTUAL_PATH - set -e _OLD_VIRTUAL_PATH - end - if test -n "$_OLD_VIRTUAL_PYTHONHOME" - set -gx PYTHONHOME $_OLD_VIRTUAL_PYTHONHOME - set -e _OLD_VIRTUAL_PYTHONHOME - end - - if test -n "$_OLD_FISH_PROMPT_OVERRIDE" - functions -e fish_prompt - set -e _OLD_FISH_PROMPT_OVERRIDE - functions -c _old_fish_prompt fish_prompt - functions -e _old_fish_prompt - end - - set -e VIRTUAL_ENV - if test "$argv[1]" != "nondestructive" - # Self-destruct! - functions -e deactivate - end -end - -# Unset irrelevant variables. -deactivate nondestructive - -set -gx VIRTUAL_ENV /opt/fleet-control-server/venv - -set -gx _OLD_VIRTUAL_PATH $PATH -set -gx PATH "$VIRTUAL_ENV/"bin $PATH - -# Unset PYTHONHOME if set. -if set -q PYTHONHOME - set -gx _OLD_VIRTUAL_PYTHONHOME $PYTHONHOME - set -e PYTHONHOME -end - -if test -z "$VIRTUAL_ENV_DISABLE_PROMPT" - # fish uses a function instead of an env var to generate the prompt. - - # Save the current fish_prompt function as the function _old_fish_prompt. - functions -c fish_prompt _old_fish_prompt - - # With the original prompt function renamed, we can override with our own. - function fish_prompt - # Save the return status of the last command. - set -l old_status $status - - # Output the venv prompt; color taken from the blue of the Python logo. - printf "%s%s%s" (set_color 4B8BBE) '(venv) ' (set_color normal) - - # Restore the return status of the previous command. - echo "exit $old_status" | . - # Output the original/"old" prompt. - _old_fish_prompt - end - - set -gx _OLD_FISH_PROMPT_OVERRIDE "$VIRTUAL_ENV" -end diff --git a/venv/bin/flask b/venv/bin/flask deleted file mode 100755 index 1f16b9a..0000000 --- a/venv/bin/flask +++ /dev/null @@ -1,6 +0,0 @@ -#!/opt/fleet-control-server/venv/bin/python3 -import sys -from flask.cli import main -if __name__ == '__main__': - sys.argv[0] = sys.argv[0].removesuffix('.exe') - sys.exit(main()) diff --git a/venv/bin/gunicorn b/venv/bin/gunicorn deleted file mode 100755 index 62d36de..0000000 --- a/venv/bin/gunicorn +++ /dev/null @@ -1,6 +0,0 @@ -#!/opt/fleet-control-server/venv/bin/python3 -import sys -from gunicorn.app.wsgiapp import run -if __name__ == '__main__': - sys.argv[0] = sys.argv[0].removesuffix('.exe') - sys.exit(run()) diff --git a/venv/bin/normalizer b/venv/bin/normalizer deleted file mode 100755 index bed0fb6..0000000 --- a/venv/bin/normalizer +++ /dev/null @@ -1,6 +0,0 @@ -#!/opt/fleet-control-server/venv/bin/python3 -import sys -from charset_normalizer.cli import cli_detect -if __name__ == '__main__': - sys.argv[0] = sys.argv[0].removesuffix('.exe') - sys.exit(cli_detect()) diff --git a/venv/bin/pip b/venv/bin/pip deleted file mode 100755 index 9b8ac59..0000000 --- a/venv/bin/pip +++ /dev/null @@ -1,8 +0,0 @@ -#!/opt/fleet-control-server/venv/bin/python3 -# -*- coding: utf-8 -*- -import re -import sys -from pip._internal.cli.main import main -if __name__ == '__main__': - sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0]) - sys.exit(main()) diff --git a/venv/bin/pip3 b/venv/bin/pip3 deleted file mode 100755 index 9b8ac59..0000000 --- a/venv/bin/pip3 +++ /dev/null @@ -1,8 +0,0 @@ -#!/opt/fleet-control-server/venv/bin/python3 -# -*- coding: utf-8 -*- -import re -import sys -from pip._internal.cli.main import main -if __name__ == '__main__': - sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0]) - sys.exit(main()) diff --git a/venv/bin/pip3.9 b/venv/bin/pip3.9 deleted file mode 100755 index 9b8ac59..0000000 --- a/venv/bin/pip3.9 +++ /dev/null @@ -1,8 +0,0 @@ -#!/opt/fleet-control-server/venv/bin/python3 -# -*- coding: utf-8 -*- -import re -import sys -from pip._internal.cli.main import main -if __name__ == '__main__': - sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0]) - sys.exit(main()) diff --git a/venv/bin/python b/venv/bin/python deleted file mode 120000 index b8a0adb..0000000 --- a/venv/bin/python +++ /dev/null @@ -1 +0,0 @@ -python3 \ No newline at end of file diff --git a/venv/bin/python3 b/venv/bin/python3 deleted file mode 120000 index ae65fda..0000000 --- a/venv/bin/python3 +++ /dev/null @@ -1 +0,0 @@ -/usr/bin/python3 \ No newline at end of file diff --git a/venv/bin/python3.9 b/venv/bin/python3.9 deleted file mode 120000 index b8a0adb..0000000 --- a/venv/bin/python3.9 +++ /dev/null @@ -1 +0,0 @@ -python3 \ No newline at end of file diff --git a/venv/bin/pywebpush b/venv/bin/pywebpush deleted file mode 100755 index 3b7aba6..0000000 --- a/venv/bin/pywebpush +++ /dev/null @@ -1,6 +0,0 @@ -#!/opt/fleet-control-server/venv/bin/python3 -import sys -from pywebpush.__main__ import main -if __name__ == '__main__': - sys.argv[0] = sys.argv[0].removesuffix('.exe') - sys.exit(main()) diff --git a/venv/bin/vapid b/venv/bin/vapid deleted file mode 100755 index 9976ce5..0000000 --- a/venv/bin/vapid +++ /dev/null @@ -1,6 +0,0 @@ -#!/opt/fleet-control-server/venv/bin/python3 -import sys -from py_vapid.main import main -if __name__ == '__main__': - sys.argv[0] = sys.argv[0].removesuffix('.exe') - sys.exit(main()) diff --git a/venv/bin/wheel b/venv/bin/wheel deleted file mode 100755 index 3d8d839..0000000 --- a/venv/bin/wheel +++ /dev/null @@ -1,8 +0,0 @@ -#!/opt/fleet-control-server/venv/bin/python3 -# -*- coding: utf-8 -*- -import re -import sys -from wheel._commands import main -if __name__ == '__main__': - sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0]) - sys.exit(main()) diff --git a/venv/include/site/python3.9/greenlet/greenlet.h b/venv/include/site/python3.9/greenlet/greenlet.h deleted file mode 100644 index d02a16e..0000000 --- a/venv/include/site/python3.9/greenlet/greenlet.h +++ /dev/null @@ -1,164 +0,0 @@ -/* -*- indent-tabs-mode: nil; tab-width: 4; -*- */ - -/* Greenlet object interface */ - -#ifndef Py_GREENLETOBJECT_H -#define Py_GREENLETOBJECT_H - - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/* This is deprecated and undocumented. It does not change. */ -#define GREENLET_VERSION "1.0.0" - -#ifndef GREENLET_MODULE -#define implementation_ptr_t void* -#endif - -typedef struct _greenlet { - PyObject_HEAD - PyObject* weakreflist; - PyObject* dict; - implementation_ptr_t pimpl; -} PyGreenlet; - -#define PyGreenlet_Check(op) (op && PyObject_TypeCheck(op, &PyGreenlet_Type)) - - -/* C API functions */ - -/* Total number of symbols that are exported */ -#define PyGreenlet_API_pointers 12 - -#define PyGreenlet_Type_NUM 0 -#define PyExc_GreenletError_NUM 1 -#define PyExc_GreenletExit_NUM 2 - -#define PyGreenlet_New_NUM 3 -#define PyGreenlet_GetCurrent_NUM 4 -#define PyGreenlet_Throw_NUM 5 -#define PyGreenlet_Switch_NUM 6 -#define PyGreenlet_SetParent_NUM 7 - -#define PyGreenlet_MAIN_NUM 8 -#define PyGreenlet_STARTED_NUM 9 -#define PyGreenlet_ACTIVE_NUM 10 -#define PyGreenlet_GET_PARENT_NUM 11 - -#ifndef GREENLET_MODULE -/* This section is used by modules that uses the greenlet C API */ -static void** _PyGreenlet_API = NULL; - -# define PyGreenlet_Type \ - (*(PyTypeObject*)_PyGreenlet_API[PyGreenlet_Type_NUM]) - -# define PyExc_GreenletError \ - ((PyObject*)_PyGreenlet_API[PyExc_GreenletError_NUM]) - -# define PyExc_GreenletExit \ - ((PyObject*)_PyGreenlet_API[PyExc_GreenletExit_NUM]) - -/* - * PyGreenlet_New(PyObject *args) - * - * greenlet.greenlet(run, parent=None) - */ -# define PyGreenlet_New \ - (*(PyGreenlet * (*)(PyObject * run, PyGreenlet * parent)) \ - _PyGreenlet_API[PyGreenlet_New_NUM]) - -/* - * PyGreenlet_GetCurrent(void) - * - * greenlet.getcurrent() - */ -# define PyGreenlet_GetCurrent \ - (*(PyGreenlet * (*)(void)) _PyGreenlet_API[PyGreenlet_GetCurrent_NUM]) - -/* - * PyGreenlet_Throw( - * PyGreenlet *greenlet, - * PyObject *typ, - * PyObject *val, - * PyObject *tb) - * - * g.throw(...) - */ -# define PyGreenlet_Throw \ - (*(PyObject * (*)(PyGreenlet * self, \ - PyObject * typ, \ - PyObject * val, \ - PyObject * tb)) \ - _PyGreenlet_API[PyGreenlet_Throw_NUM]) - -/* - * PyGreenlet_Switch(PyGreenlet *greenlet, PyObject *args) - * - * g.switch(*args, **kwargs) - */ -# define PyGreenlet_Switch \ - (*(PyObject * \ - (*)(PyGreenlet * greenlet, PyObject * args, PyObject * kwargs)) \ - _PyGreenlet_API[PyGreenlet_Switch_NUM]) - -/* - * PyGreenlet_SetParent(PyObject *greenlet, PyObject *new_parent) - * - * g.parent = new_parent - */ -# define PyGreenlet_SetParent \ - (*(int (*)(PyGreenlet * greenlet, PyGreenlet * nparent)) \ - _PyGreenlet_API[PyGreenlet_SetParent_NUM]) - -/* - * PyGreenlet_GetParent(PyObject* greenlet) - * - * return greenlet.parent; - * - * This could return NULL even if there is no exception active. - * If it does not return NULL, you are responsible for decrementing the - * reference count. - */ -# define PyGreenlet_GetParent \ - (*(PyGreenlet* (*)(PyGreenlet*)) \ - _PyGreenlet_API[PyGreenlet_GET_PARENT_NUM]) - -/* - * deprecated, undocumented alias. - */ -# define PyGreenlet_GET_PARENT PyGreenlet_GetParent - -# define PyGreenlet_MAIN \ - (*(int (*)(PyGreenlet*)) \ - _PyGreenlet_API[PyGreenlet_MAIN_NUM]) - -# define PyGreenlet_STARTED \ - (*(int (*)(PyGreenlet*)) \ - _PyGreenlet_API[PyGreenlet_STARTED_NUM]) - -# define PyGreenlet_ACTIVE \ - (*(int (*)(PyGreenlet*)) \ - _PyGreenlet_API[PyGreenlet_ACTIVE_NUM]) - - - - -/* Macro that imports greenlet and initializes C API */ -/* NOTE: This has actually moved to ``greenlet._greenlet._C_API``, but we - keep the older definition to be sure older code that might have a copy of - the header still works. */ -# define PyGreenlet_Import() \ - { \ - _PyGreenlet_API = (void**)PyCapsule_Import("greenlet._C_API", 0); \ - } - -#endif /* GREENLET_MODULE */ - -#ifdef __cplusplus -} -#endif -#endif /* !Py_GREENLETOBJECT_H */ diff --git a/venv/lib/python3.9/site-packages/81d243bd2c585b0f4821__mypyc.cpython-39-x86_64-linux-gnu.so b/venv/lib/python3.9/site-packages/81d243bd2c585b0f4821__mypyc.cpython-39-x86_64-linux-gnu.so deleted file mode 100755 index d914c9e..0000000 Binary files a/venv/lib/python3.9/site-packages/81d243bd2c585b0f4821__mypyc.cpython-39-x86_64-linux-gnu.so and /dev/null differ diff --git a/venv/lib/python3.9/site-packages/_cffi_backend.cpython-39-x86_64-linux-gnu.so b/venv/lib/python3.9/site-packages/_cffi_backend.cpython-39-x86_64-linux-gnu.so deleted file mode 100755 index 7341518..0000000 Binary files a/venv/lib/python3.9/site-packages/_cffi_backend.cpython-39-x86_64-linux-gnu.so and /dev/null differ diff --git a/venv/lib/python3.9/site-packages/_distutils_hack/__init__.py b/venv/lib/python3.9/site-packages/_distutils_hack/__init__.py deleted file mode 100644 index 94f71b9..0000000 --- a/venv/lib/python3.9/site-packages/_distutils_hack/__init__.py +++ /dev/null @@ -1,239 +0,0 @@ -# don't import any costly modules -import os -import sys - -report_url = ( - "https://github.com/pypa/setuptools/issues/new?template=distutils-deprecation.yml" -) - - -def warn_distutils_present(): - if 'distutils' not in sys.modules: - return - import warnings - - warnings.warn( - "Distutils was imported before Setuptools, but importing Setuptools " - "also replaces the `distutils` module in `sys.modules`. This may lead " - "to undesirable behaviors or errors. To avoid these issues, avoid " - "using distutils directly, ensure that setuptools is installed in the " - "traditional way (e.g. not an editable install), and/or make sure " - "that setuptools is always imported before distutils." - ) - - -def clear_distutils(): - if 'distutils' not in sys.modules: - return - import warnings - - warnings.warn( - "Setuptools is replacing distutils. Support for replacing " - "an already imported distutils is deprecated. In the future, " - "this condition will fail. " - f"Register concerns at {report_url}" - ) - mods = [ - name - for name in sys.modules - if name == "distutils" or name.startswith("distutils.") - ] - for name in mods: - del sys.modules[name] - - -def enabled(): - """ - Allow selection of distutils by environment variable. - """ - which = os.environ.get('SETUPTOOLS_USE_DISTUTILS', 'local') - if which == 'stdlib': - import warnings - - warnings.warn( - "Reliance on distutils from stdlib is deprecated. Users " - "must rely on setuptools to provide the distutils module. " - "Avoid importing distutils or import setuptools first, " - "and avoid setting SETUPTOOLS_USE_DISTUTILS=stdlib. " - f"Register concerns at {report_url}" - ) - return which == 'local' - - -def ensure_local_distutils(): - import importlib - - clear_distutils() - - # With the DistutilsMetaFinder in place, - # perform an import to cause distutils to be - # loaded from setuptools._distutils. Ref #2906. - with shim(): - importlib.import_module('distutils') - - # check that submodules load as expected - core = importlib.import_module('distutils.core') - assert '_distutils' in core.__file__, core.__file__ - assert 'setuptools._distutils.log' not in sys.modules - - -def do_override(): - """ - Ensure that the local copy of distutils is preferred over stdlib. - - See https://github.com/pypa/setuptools/issues/417#issuecomment-392298401 - for more motivation. - """ - if enabled(): - warn_distutils_present() - ensure_local_distutils() - - -class _TrivialRe: - def __init__(self, *patterns) -> None: - self._patterns = patterns - - def match(self, string): - return all(pat in string for pat in self._patterns) - - -class DistutilsMetaFinder: - def find_spec(self, fullname, path, target=None): - # optimization: only consider top level modules and those - # found in the CPython test suite. - if path is not None and not fullname.startswith('test.'): - return None - - method_name = 'spec_for_{fullname}'.format(**locals()) - method = getattr(self, method_name, lambda: None) - return method() - - def spec_for_distutils(self): - if self.is_cpython(): - return None - - import importlib - import importlib.abc - import importlib.util - - try: - mod = importlib.import_module('setuptools._distutils') - except Exception: - # There are a couple of cases where setuptools._distutils - # may not be present: - # - An older Setuptools without a local distutils is - # taking precedence. Ref #2957. - # - Path manipulation during sitecustomize removes - # setuptools from the path but only after the hook - # has been loaded. Ref #2980. - # In either case, fall back to stdlib behavior. - return None - - class DistutilsLoader(importlib.abc.Loader): - def create_module(self, spec): - mod.__name__ = 'distutils' - return mod - - def exec_module(self, module): - pass - - return importlib.util.spec_from_loader( - 'distutils', DistutilsLoader(), origin=mod.__file__ - ) - - @staticmethod - def is_cpython(): - """ - Suppress supplying distutils for CPython (build and tests). - Ref #2965 and #3007. - """ - return os.path.isfile('pybuilddir.txt') - - def spec_for_pip(self): - """ - Ensure stdlib distutils when running under pip. - See pypa/pip#8761 for rationale. - """ - if sys.version_info >= (3, 12) or self.pip_imported_during_build(): - return - clear_distutils() - self.spec_for_distutils = lambda: None - - @classmethod - def pip_imported_during_build(cls): - """ - Detect if pip is being imported in a build script. Ref #2355. - """ - import traceback - - return any( - cls.frame_file_is_setup(frame) for frame, line in traceback.walk_stack(None) - ) - - @staticmethod - def frame_file_is_setup(frame): - """ - Return True if the indicated frame suggests a setup.py file. - """ - # some frames may not have __file__ (#2940) - return frame.f_globals.get('__file__', '').endswith('setup.py') - - def spec_for_sensitive_tests(self): - """ - Ensure stdlib distutils when running select tests under CPython. - - python/cpython#91169 - """ - clear_distutils() - self.spec_for_distutils = lambda: None - - sensitive_tests = ( - [ - 'test.test_distutils', - 'test.test_peg_generator', - 'test.test_importlib', - ] - if sys.version_info < (3, 10) - else [ - 'test.test_distutils', - ] - ) - - -for name in DistutilsMetaFinder.sensitive_tests: - setattr( - DistutilsMetaFinder, - f'spec_for_{name}', - DistutilsMetaFinder.spec_for_sensitive_tests, - ) - - -DISTUTILS_FINDER = DistutilsMetaFinder() - - -def add_shim(): - DISTUTILS_FINDER in sys.meta_path or insert_shim() - - -class shim: - def __enter__(self) -> None: - insert_shim() - - def __exit__(self, exc: object, value: object, tb: object) -> None: - _remove_shim() - - -def insert_shim(): - sys.meta_path.insert(0, DISTUTILS_FINDER) - - -def _remove_shim(): - try: - sys.meta_path.remove(DISTUTILS_FINDER) - except ValueError: - pass - - -if sys.version_info < (3, 12): - # DistutilsMetaFinder can only be disabled in Python < 3.12 (PEP 632) - remove_shim = _remove_shim diff --git a/venv/lib/python3.9/site-packages/_distutils_hack/override.py b/venv/lib/python3.9/site-packages/_distutils_hack/override.py deleted file mode 100644 index 2cc433a..0000000 --- a/venv/lib/python3.9/site-packages/_distutils_hack/override.py +++ /dev/null @@ -1 +0,0 @@ -__import__('_distutils_hack').do_override() diff --git a/venv/lib/python3.9/site-packages/aiohappyeyeballs-2.6.1.dist-info/INSTALLER b/venv/lib/python3.9/site-packages/aiohappyeyeballs-2.6.1.dist-info/INSTALLER deleted file mode 100644 index a1b589e..0000000 --- a/venv/lib/python3.9/site-packages/aiohappyeyeballs-2.6.1.dist-info/INSTALLER +++ /dev/null @@ -1 +0,0 @@ -pip diff --git a/venv/lib/python3.9/site-packages/aiohappyeyeballs-2.6.1.dist-info/LICENSE b/venv/lib/python3.9/site-packages/aiohappyeyeballs-2.6.1.dist-info/LICENSE deleted file mode 100644 index f26bcf4..0000000 --- a/venv/lib/python3.9/site-packages/aiohappyeyeballs-2.6.1.dist-info/LICENSE +++ /dev/null @@ -1,279 +0,0 @@ -A. HISTORY OF THE SOFTWARE -========================== - -Python was created in the early 1990s by Guido van Rossum at Stichting -Mathematisch Centrum (CWI, see https://www.cwi.nl) in the Netherlands -as a successor of a language called ABC. Guido remains Python's -principal author, although it includes many contributions from others. - -In 1995, Guido continued his work on Python at the Corporation for -National Research Initiatives (CNRI, see https://www.cnri.reston.va.us) -in Reston, Virginia where he released several versions of the -software. - -In May 2000, Guido and the Python core development team moved to -BeOpen.com to form the BeOpen PythonLabs team. In October of the same -year, the PythonLabs team moved to Digital Creations, which became -Zope Corporation. In 2001, the Python Software Foundation (PSF, see -https://www.python.org/psf/) was formed, a non-profit organization -created specifically to own Python-related Intellectual Property. -Zope Corporation was a sponsoring member of the PSF. - -All Python releases are Open Source (see https://opensource.org for -the Open Source Definition). Historically, most, but not all, Python -releases have also been GPL-compatible; the table below summarizes -the various releases. - - Release Derived Year Owner GPL- - from compatible? (1) - - 0.9.0 thru 1.2 1991-1995 CWI yes - 1.3 thru 1.5.2 1.2 1995-1999 CNRI yes - 1.6 1.5.2 2000 CNRI no - 2.0 1.6 2000 BeOpen.com no - 1.6.1 1.6 2001 CNRI yes (2) - 2.1 2.0+1.6.1 2001 PSF no - 2.0.1 2.0+1.6.1 2001 PSF yes - 2.1.1 2.1+2.0.1 2001 PSF yes - 2.1.2 2.1.1 2002 PSF yes - 2.1.3 2.1.2 2002 PSF yes - 2.2 and above 2.1.1 2001-now PSF yes - -Footnotes: - -(1) GPL-compatible doesn't mean that we're distributing Python under - the GPL. All Python licenses, unlike the GPL, let you distribute - a modified version without making your changes open source. The - GPL-compatible licenses make it possible to combine Python with - other software that is released under the GPL; the others don't. - -(2) According to Richard Stallman, 1.6.1 is not GPL-compatible, - because its license has a choice of law clause. According to - CNRI, however, Stallman's lawyer has told CNRI's lawyer that 1.6.1 - is "not incompatible" with the GPL. - -Thanks to the many outside volunteers who have worked under Guido's -direction to make these releases possible. - - -B. TERMS AND CONDITIONS FOR ACCESSING OR OTHERWISE USING PYTHON -=============================================================== - -Python software and documentation are licensed under the -Python Software Foundation License Version 2. - -Starting with Python 3.8.6, examples, recipes, and other code in -the documentation are dual licensed under the PSF License Version 2 -and the Zero-Clause BSD license. - -Some software incorporated into Python is under different licenses. -The licenses are listed with code falling under that license. - - -PYTHON SOFTWARE FOUNDATION LICENSE VERSION 2 --------------------------------------------- - -1. This LICENSE AGREEMENT is between the Python Software Foundation -("PSF"), and the Individual or Organization ("Licensee") accessing and -otherwise using this software ("Python") in source or binary form and -its associated documentation. - -2. Subject to the terms and conditions of this License Agreement, PSF hereby -grants Licensee a nonexclusive, royalty-free, world-wide license to reproduce, -analyze, test, perform and/or display publicly, prepare derivative works, -distribute, and otherwise use Python alone or in any derivative version, -provided, however, that PSF's License Agreement and PSF's notice of copyright, -i.e., "Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, -2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019, 2020, 2021, 2022, 2023 Python Software Foundation; -All Rights Reserved" are retained in Python alone or in any derivative version -prepared by Licensee. - -3. In the event Licensee prepares a derivative work that is based on -or incorporates Python or any part thereof, and wants to make -the derivative work available to others as provided herein, then -Licensee hereby agrees to include in any such work a brief summary of -the changes made to Python. - -4. PSF is making Python available to Licensee on an "AS IS" -basis. PSF MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR -IMPLIED. BY WAY OF EXAMPLE, BUT NOT LIMITATION, PSF MAKES NO AND -DISCLAIMS ANY REPRESENTATION OR WARRANTY OF MERCHANTABILITY OR FITNESS -FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF PYTHON WILL NOT -INFRINGE ANY THIRD PARTY RIGHTS. - -5. PSF SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF PYTHON -FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS AS -A RESULT OF MODIFYING, DISTRIBUTING, OR OTHERWISE USING PYTHON, -OR ANY DERIVATIVE THEREOF, EVEN IF ADVISED OF THE POSSIBILITY THEREOF. - -6. This License Agreement will automatically terminate upon a material -breach of its terms and conditions. - -7. Nothing in this License Agreement shall be deemed to create any -relationship of agency, partnership, or joint venture between PSF and -Licensee. This License Agreement does not grant permission to use PSF -trademarks or trade name in a trademark sense to endorse or promote -products or services of Licensee, or any third party. - -8. By copying, installing or otherwise using Python, Licensee -agrees to be bound by the terms and conditions of this License -Agreement. - - -BEOPEN.COM LICENSE AGREEMENT FOR PYTHON 2.0 -------------------------------------------- - -BEOPEN PYTHON OPEN SOURCE LICENSE AGREEMENT VERSION 1 - -1. This LICENSE AGREEMENT is between BeOpen.com ("BeOpen"), having an -office at 160 Saratoga Avenue, Santa Clara, CA 95051, and the -Individual or Organization ("Licensee") accessing and otherwise using -this software in source or binary form and its associated -documentation ("the Software"). - -2. Subject to the terms and conditions of this BeOpen Python License -Agreement, BeOpen hereby grants Licensee a non-exclusive, -royalty-free, world-wide license to reproduce, analyze, test, perform -and/or display publicly, prepare derivative works, distribute, and -otherwise use the Software alone or in any derivative version, -provided, however, that the BeOpen Python License is retained in the -Software, alone or in any derivative version prepared by Licensee. - -3. BeOpen is making the Software available to Licensee on an "AS IS" -basis. BEOPEN MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR -IMPLIED. BY WAY OF EXAMPLE, BUT NOT LIMITATION, BEOPEN MAKES NO AND -DISCLAIMS ANY REPRESENTATION OR WARRANTY OF MERCHANTABILITY OR FITNESS -FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF THE SOFTWARE WILL NOT -INFRINGE ANY THIRD PARTY RIGHTS. - -4. BEOPEN SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF THE -SOFTWARE FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS -AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THE SOFTWARE, OR ANY -DERIVATIVE THEREOF, EVEN IF ADVISED OF THE POSSIBILITY THEREOF. - -5. This License Agreement will automatically terminate upon a material -breach of its terms and conditions. - -6. This License Agreement shall be governed by and interpreted in all -respects by the law of the State of California, excluding conflict of -law provisions. Nothing in this License Agreement shall be deemed to -create any relationship of agency, partnership, or joint venture -between BeOpen and Licensee. This License Agreement does not grant -permission to use BeOpen trademarks or trade names in a trademark -sense to endorse or promote products or services of Licensee, or any -third party. As an exception, the "BeOpen Python" logos available at -http://www.pythonlabs.com/logos.html may be used according to the -permissions granted on that web page. - -7. By copying, installing or otherwise using the software, Licensee -agrees to be bound by the terms and conditions of this License -Agreement. - - -CNRI LICENSE AGREEMENT FOR PYTHON 1.6.1 ---------------------------------------- - -1. This LICENSE AGREEMENT is between the Corporation for National -Research Initiatives, having an office at 1895 Preston White Drive, -Reston, VA 20191 ("CNRI"), and the Individual or Organization -("Licensee") accessing and otherwise using Python 1.6.1 software in -source or binary form and its associated documentation. - -2. Subject to the terms and conditions of this License Agreement, CNRI -hereby grants Licensee a nonexclusive, royalty-free, world-wide -license to reproduce, analyze, test, perform and/or display publicly, -prepare derivative works, distribute, and otherwise use Python 1.6.1 -alone or in any derivative version, provided, however, that CNRI's -License Agreement and CNRI's notice of copyright, i.e., "Copyright (c) -1995-2001 Corporation for National Research Initiatives; All Rights -Reserved" are retained in Python 1.6.1 alone or in any derivative -version prepared by Licensee. Alternately, in lieu of CNRI's License -Agreement, Licensee may substitute the following text (omitting the -quotes): "Python 1.6.1 is made available subject to the terms and -conditions in CNRI's License Agreement. This Agreement together with -Python 1.6.1 may be located on the internet using the following -unique, persistent identifier (known as a handle): 1895.22/1013. This -Agreement may also be obtained from a proxy server on the internet -using the following URL: http://hdl.handle.net/1895.22/1013". - -3. In the event Licensee prepares a derivative work that is based on -or incorporates Python 1.6.1 or any part thereof, and wants to make -the derivative work available to others as provided herein, then -Licensee hereby agrees to include in any such work a brief summary of -the changes made to Python 1.6.1. - -4. CNRI is making Python 1.6.1 available to Licensee on an "AS IS" -basis. CNRI MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR -IMPLIED. BY WAY OF EXAMPLE, BUT NOT LIMITATION, CNRI MAKES NO AND -DISCLAIMS ANY REPRESENTATION OR WARRANTY OF MERCHANTABILITY OR FITNESS -FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF PYTHON 1.6.1 WILL NOT -INFRINGE ANY THIRD PARTY RIGHTS. - -5. CNRI SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF PYTHON -1.6.1 FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS AS -A RESULT OF MODIFYING, DISTRIBUTING, OR OTHERWISE USING PYTHON 1.6.1, -OR ANY DERIVATIVE THEREOF, EVEN IF ADVISED OF THE POSSIBILITY THEREOF. - -6. This License Agreement will automatically terminate upon a material -breach of its terms and conditions. - -7. This License Agreement shall be governed by the federal -intellectual property law of the United States, including without -limitation the federal copyright law, and, to the extent such -U.S. federal law does not apply, by the law of the Commonwealth of -Virginia, excluding Virginia's conflict of law provisions. -Notwithstanding the foregoing, with regard to derivative works based -on Python 1.6.1 that incorporate non-separable material that was -previously distributed under the GNU General Public License (GPL), the -law of the Commonwealth of Virginia shall govern this License -Agreement only as to issues arising under or with respect to -Paragraphs 4, 5, and 7 of this License Agreement. Nothing in this -License Agreement shall be deemed to create any relationship of -agency, partnership, or joint venture between CNRI and Licensee. This -License Agreement does not grant permission to use CNRI trademarks or -trade name in a trademark sense to endorse or promote products or -services of Licensee, or any third party. - -8. By clicking on the "ACCEPT" button where indicated, or by copying, -installing or otherwise using Python 1.6.1, Licensee agrees to be -bound by the terms and conditions of this License Agreement. - - ACCEPT - - -CWI LICENSE AGREEMENT FOR PYTHON 0.9.0 THROUGH 1.2 --------------------------------------------------- - -Copyright (c) 1991 - 1995, Stichting Mathematisch Centrum Amsterdam, -The Netherlands. All rights reserved. - -Permission to use, copy, modify, and distribute this software and its -documentation for any purpose and without fee is hereby granted, -provided that the above copyright notice appear in all copies and that -both that copyright notice and this permission notice appear in -supporting documentation, and that the name of Stichting Mathematisch -Centrum or CWI not be used in advertising or publicity pertaining to -distribution of the software without specific, written prior -permission. - -STICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO -THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND -FITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE -FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT -OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - -ZERO-CLAUSE BSD LICENSE FOR CODE IN THE PYTHON DOCUMENTATION ----------------------------------------------------------------------- - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH -REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY -AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, -INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM -LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR -OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR -PERFORMANCE OF THIS SOFTWARE. diff --git a/venv/lib/python3.9/site-packages/aiohappyeyeballs-2.6.1.dist-info/METADATA b/venv/lib/python3.9/site-packages/aiohappyeyeballs-2.6.1.dist-info/METADATA deleted file mode 100644 index c632040..0000000 --- a/venv/lib/python3.9/site-packages/aiohappyeyeballs-2.6.1.dist-info/METADATA +++ /dev/null @@ -1,123 +0,0 @@ -Metadata-Version: 2.3 -Name: aiohappyeyeballs -Version: 2.6.1 -Summary: Happy Eyeballs for asyncio -License: PSF-2.0 -Author: J. Nick Koston -Author-email: nick@koston.org -Requires-Python: >=3.9 -Classifier: Development Status :: 5 - Production/Stable -Classifier: Intended Audience :: Developers -Classifier: Natural Language :: English -Classifier: Operating System :: OS Independent -Classifier: Topic :: Software Development :: Libraries -Classifier: Programming Language :: Python :: 3 -Classifier: Programming Language :: Python :: 3.9 -Classifier: Programming Language :: Python :: 3.10 -Classifier: Programming Language :: Python :: 3.11 -Classifier: Programming Language :: Python :: 3.12 -Classifier: Programming Language :: Python :: 3.13 -Classifier: License :: OSI Approved :: Python Software Foundation License -Project-URL: Bug Tracker, https://github.com/aio-libs/aiohappyeyeballs/issues -Project-URL: Changelog, https://github.com/aio-libs/aiohappyeyeballs/blob/main/CHANGELOG.md -Project-URL: Documentation, https://aiohappyeyeballs.readthedocs.io -Project-URL: Repository, https://github.com/aio-libs/aiohappyeyeballs -Description-Content-Type: text/markdown - -# aiohappyeyeballs - -

- - CI Status - - - Documentation Status - - - Test coverage percentage - -

-

- - Poetry - - - Ruff - - - pre-commit - -

-

- - PyPI Version - - Supported Python versions - License -

- ---- - -**Documentation**: https://aiohappyeyeballs.readthedocs.io - -**Source Code**: https://github.com/aio-libs/aiohappyeyeballs - ---- - -[Happy Eyeballs](https://en.wikipedia.org/wiki/Happy_Eyeballs) -([RFC 8305](https://www.rfc-editor.org/rfc/rfc8305.html)) - -## Use case - -This library exists to allow connecting with -[Happy Eyeballs](https://en.wikipedia.org/wiki/Happy_Eyeballs) -([RFC 8305](https://www.rfc-editor.org/rfc/rfc8305.html)) -when you -already have a list of addrinfo and not a DNS name. - -The stdlib version of `loop.create_connection()` -will only work when you pass in an unresolved name which -is not a good fit when using DNS caching or resolving -names via another method such as `zeroconf`. - -## Installation - -Install this via pip (or your favourite package manager): - -`pip install aiohappyeyeballs` - -## License - -[aiohappyeyeballs is licensed under the same terms as cpython itself.](https://github.com/python/cpython/blob/main/LICENSE) - -## Example usage - -```python - -addr_infos = await loop.getaddrinfo("example.org", 80) - -socket = await start_connection(addr_infos) -socket = await start_connection(addr_infos, local_addr_infos=local_addr_infos, happy_eyeballs_delay=0.2) - -transport, protocol = await loop.create_connection( - MyProtocol, sock=socket, ...) - -# Remove the first address for each family from addr_info -pop_addr_infos_interleave(addr_info, 1) - -# Remove all matching address from addr_info -remove_addr_infos(addr_info, "dead::beef::") - -# Convert a local_addr to local_addr_infos -local_addr_infos = addr_to_addr_infos(("127.0.0.1",0)) -``` - -## Credits - -This package contains code from cpython and is licensed under the same terms as cpython itself. - -This package was created with -[Copier](https://copier.readthedocs.io/) and the -[browniebroke/pypackage-template](https://github.com/browniebroke/pypackage-template) -project template. - diff --git a/venv/lib/python3.9/site-packages/aiohappyeyeballs-2.6.1.dist-info/RECORD b/venv/lib/python3.9/site-packages/aiohappyeyeballs-2.6.1.dist-info/RECORD deleted file mode 100644 index a3cc012..0000000 --- a/venv/lib/python3.9/site-packages/aiohappyeyeballs-2.6.1.dist-info/RECORD +++ /dev/null @@ -1,16 +0,0 @@ -aiohappyeyeballs-2.6.1.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 -aiohappyeyeballs-2.6.1.dist-info/LICENSE,sha256=Oy-B_iHRgcSZxZolbI4ZaEVdZonSaaqFNzv7avQdo78,13936 -aiohappyeyeballs-2.6.1.dist-info/METADATA,sha256=NSXlhJwAfi380eEjAo7BQ4P_TVal9xi0qkyZWibMsVM,5915 -aiohappyeyeballs-2.6.1.dist-info/RECORD,, -aiohappyeyeballs-2.6.1.dist-info/WHEEL,sha256=XbeZDeTWKc1w7CSIyre5aMDU_-PohRwTQceYnisIYYY,88 -aiohappyeyeballs/__init__.py,sha256=x7kktHEtaD9quBcWDJPuLeKyjuVAI-Jj14S9B_5hcTs,361 -aiohappyeyeballs/__pycache__/__init__.cpython-39.pyc,, -aiohappyeyeballs/__pycache__/_staggered.cpython-39.pyc,, -aiohappyeyeballs/__pycache__/impl.cpython-39.pyc,, -aiohappyeyeballs/__pycache__/types.cpython-39.pyc,, -aiohappyeyeballs/__pycache__/utils.cpython-39.pyc,, -aiohappyeyeballs/_staggered.py,sha256=edfVowFx-P-ywJjIEF3MdPtEMVODujV6CeMYr65otac,6900 -aiohappyeyeballs/impl.py,sha256=Dlcm2mTJ28ucrGnxkb_fo9CZzLAkOOBizOt7dreBbXE,9681 -aiohappyeyeballs/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 -aiohappyeyeballs/types.py,sha256=YZJIAnyoV4Dz0WFtlaf_OyE4EW7Xus1z7aIfNI6tDDQ,425 -aiohappyeyeballs/utils.py,sha256=on9GxIR0LhEfZu8P6Twi9hepX9zDanuZM20MWsb3xlQ,3028 diff --git a/venv/lib/python3.9/site-packages/aiohappyeyeballs-2.6.1.dist-info/WHEEL b/venv/lib/python3.9/site-packages/aiohappyeyeballs-2.6.1.dist-info/WHEEL deleted file mode 100644 index 0582547..0000000 --- a/venv/lib/python3.9/site-packages/aiohappyeyeballs-2.6.1.dist-info/WHEEL +++ /dev/null @@ -1,4 +0,0 @@ -Wheel-Version: 1.0 -Generator: poetry-core 2.1.1 -Root-Is-Purelib: true -Tag: py3-none-any diff --git a/venv/lib/python3.9/site-packages/aiohappyeyeballs/__init__.py b/venv/lib/python3.9/site-packages/aiohappyeyeballs/__init__.py deleted file mode 100644 index 71c689c..0000000 --- a/venv/lib/python3.9/site-packages/aiohappyeyeballs/__init__.py +++ /dev/null @@ -1,14 +0,0 @@ -__version__ = "2.6.1" - -from .impl import start_connection -from .types import AddrInfoType, SocketFactoryType -from .utils import addr_to_addr_infos, pop_addr_infos_interleave, remove_addr_infos - -__all__ = ( - "AddrInfoType", - "SocketFactoryType", - "addr_to_addr_infos", - "pop_addr_infos_interleave", - "remove_addr_infos", - "start_connection", -) diff --git a/venv/lib/python3.9/site-packages/aiohappyeyeballs/_staggered.py b/venv/lib/python3.9/site-packages/aiohappyeyeballs/_staggered.py deleted file mode 100644 index 9a4ba72..0000000 --- a/venv/lib/python3.9/site-packages/aiohappyeyeballs/_staggered.py +++ /dev/null @@ -1,207 +0,0 @@ -import asyncio -import contextlib - -# PY3.9: Import Callable from typing until we drop Python 3.9 support -# https://github.com/python/cpython/issues/87131 -from typing import ( - TYPE_CHECKING, - Any, - Awaitable, - Callable, - Iterable, - List, - Optional, - Set, - Tuple, - TypeVar, - Union, -) - -_T = TypeVar("_T") - -RE_RAISE_EXCEPTIONS = (SystemExit, KeyboardInterrupt) - - -def _set_result(wait_next: "asyncio.Future[None]") -> None: - """Set the result of a future if it is not already done.""" - if not wait_next.done(): - wait_next.set_result(None) - - -async def _wait_one( - futures: "Iterable[asyncio.Future[Any]]", - loop: asyncio.AbstractEventLoop, -) -> _T: - """Wait for the first future to complete.""" - wait_next = loop.create_future() - - def _on_completion(fut: "asyncio.Future[Any]") -> None: - if not wait_next.done(): - wait_next.set_result(fut) - - for f in futures: - f.add_done_callback(_on_completion) - - try: - return await wait_next - finally: - for f in futures: - f.remove_done_callback(_on_completion) - - -async def staggered_race( - coro_fns: Iterable[Callable[[], Awaitable[_T]]], - delay: Optional[float], - *, - loop: Optional[asyncio.AbstractEventLoop] = None, -) -> Tuple[Optional[_T], Optional[int], List[Optional[BaseException]]]: - """ - Run coroutines with staggered start times and take the first to finish. - - This method takes an iterable of coroutine functions. The first one is - started immediately. From then on, whenever the immediately preceding one - fails (raises an exception), or when *delay* seconds has passed, the next - coroutine is started. This continues until one of the coroutines complete - successfully, in which case all others are cancelled, or until all - coroutines fail. - - The coroutines provided should be well-behaved in the following way: - - * They should only ``return`` if completed successfully. - - * They should always raise an exception if they did not complete - successfully. In particular, if they handle cancellation, they should - probably reraise, like this:: - - try: - # do work - except asyncio.CancelledError: - # undo partially completed work - raise - - Args: - ---- - coro_fns: an iterable of coroutine functions, i.e. callables that - return a coroutine object when called. Use ``functools.partial`` or - lambdas to pass arguments. - - delay: amount of time, in seconds, between starting coroutines. If - ``None``, the coroutines will run sequentially. - - loop: the event loop to use. If ``None``, the running loop is used. - - Returns: - ------- - tuple *(winner_result, winner_index, exceptions)* where - - - *winner_result*: the result of the winning coroutine, or ``None`` - if no coroutines won. - - - *winner_index*: the index of the winning coroutine in - ``coro_fns``, or ``None`` if no coroutines won. If the winning - coroutine may return None on success, *winner_index* can be used - to definitively determine whether any coroutine won. - - - *exceptions*: list of exceptions returned by the coroutines. - ``len(exceptions)`` is equal to the number of coroutines actually - started, and the order is the same as in ``coro_fns``. The winning - coroutine's entry is ``None``. - - """ - loop = loop or asyncio.get_running_loop() - exceptions: List[Optional[BaseException]] = [] - tasks: Set[asyncio.Task[Optional[Tuple[_T, int]]]] = set() - - async def run_one_coro( - coro_fn: Callable[[], Awaitable[_T]], - this_index: int, - start_next: "asyncio.Future[None]", - ) -> Optional[Tuple[_T, int]]: - """ - Run a single coroutine. - - If the coroutine fails, set the exception in the exceptions list and - start the next coroutine by setting the result of the start_next. - - If the coroutine succeeds, return the result and the index of the - coroutine in the coro_fns list. - - If SystemExit or KeyboardInterrupt is raised, re-raise it. - """ - try: - result = await coro_fn() - except RE_RAISE_EXCEPTIONS: - raise - except BaseException as e: - exceptions[this_index] = e - _set_result(start_next) # Kickstart the next coroutine - return None - - return result, this_index - - start_next_timer: Optional[asyncio.TimerHandle] = None - start_next: Optional[asyncio.Future[None]] - task: asyncio.Task[Optional[Tuple[_T, int]]] - done: Union[asyncio.Future[None], asyncio.Task[Optional[Tuple[_T, int]]]] - coro_iter = iter(coro_fns) - this_index = -1 - try: - while True: - if coro_fn := next(coro_iter, None): - this_index += 1 - exceptions.append(None) - start_next = loop.create_future() - task = loop.create_task(run_one_coro(coro_fn, this_index, start_next)) - tasks.add(task) - start_next_timer = ( - loop.call_later(delay, _set_result, start_next) if delay else None - ) - elif not tasks: - # We exhausted the coro_fns list and no tasks are running - # so we have no winner and all coroutines failed. - break - - while tasks or start_next: - done = await _wait_one( - (*tasks, start_next) if start_next else tasks, loop - ) - if done is start_next: - # The current task has failed or the timer has expired - # so we need to start the next task. - start_next = None - if start_next_timer: - start_next_timer.cancel() - start_next_timer = None - - # Break out of the task waiting loop to start the next - # task. - break - - if TYPE_CHECKING: - assert isinstance(done, asyncio.Task) - - tasks.remove(done) - if winner := done.result(): - return *winner, exceptions - finally: - # We either have: - # - a winner - # - all tasks failed - # - a KeyboardInterrupt or SystemExit. - - # - # If the timer is still running, cancel it. - # - if start_next_timer: - start_next_timer.cancel() - - # - # If there are any tasks left, cancel them and than - # wait them so they fill the exceptions list. - # - for task in tasks: - task.cancel() - with contextlib.suppress(asyncio.CancelledError): - await task - - return None, None, exceptions diff --git a/venv/lib/python3.9/site-packages/aiohappyeyeballs/impl.py b/venv/lib/python3.9/site-packages/aiohappyeyeballs/impl.py deleted file mode 100644 index 8f3919a..0000000 --- a/venv/lib/python3.9/site-packages/aiohappyeyeballs/impl.py +++ /dev/null @@ -1,259 +0,0 @@ -"""Base implementation.""" - -import asyncio -import collections -import contextlib -import functools -import itertools -import socket -from typing import List, Optional, Sequence, Set, Union - -from . import _staggered -from .types import AddrInfoType, SocketFactoryType - - -async def start_connection( - addr_infos: Sequence[AddrInfoType], - *, - local_addr_infos: Optional[Sequence[AddrInfoType]] = None, - happy_eyeballs_delay: Optional[float] = None, - interleave: Optional[int] = None, - loop: Optional[asyncio.AbstractEventLoop] = None, - socket_factory: Optional[SocketFactoryType] = None, -) -> socket.socket: - """ - Connect to a TCP server. - - Create a socket connection to a specified destination. The - destination is specified as a list of AddrInfoType tuples as - returned from getaddrinfo(). - - The arguments are, in order: - - * ``family``: the address family, e.g. ``socket.AF_INET`` or - ``socket.AF_INET6``. - * ``type``: the socket type, e.g. ``socket.SOCK_STREAM`` or - ``socket.SOCK_DGRAM``. - * ``proto``: the protocol, e.g. ``socket.IPPROTO_TCP`` or - ``socket.IPPROTO_UDP``. - * ``canonname``: the canonical name of the address, e.g. - ``"www.python.org"``. - * ``sockaddr``: the socket address - - This method is a coroutine which will try to establish the connection - in the background. When successful, the coroutine returns a - socket. - - The expected use case is to use this method in conjunction with - loop.create_connection() to establish a connection to a server:: - - socket = await start_connection(addr_infos) - transport, protocol = await loop.create_connection( - MyProtocol, sock=socket, ...) - """ - if not (current_loop := loop): - current_loop = asyncio.get_running_loop() - - single_addr_info = len(addr_infos) == 1 - - if happy_eyeballs_delay is not None and interleave is None: - # If using happy eyeballs, default to interleave addresses by family - interleave = 1 - - if interleave and not single_addr_info: - addr_infos = _interleave_addrinfos(addr_infos, interleave) - - sock: Optional[socket.socket] = None - # uvloop can raise RuntimeError instead of OSError - exceptions: List[List[Union[OSError, RuntimeError]]] = [] - if happy_eyeballs_delay is None or single_addr_info: - # not using happy eyeballs - for addrinfo in addr_infos: - try: - sock = await _connect_sock( - current_loop, - exceptions, - addrinfo, - local_addr_infos, - None, - socket_factory, - ) - break - except (RuntimeError, OSError): - continue - else: # using happy eyeballs - open_sockets: Set[socket.socket] = set() - try: - sock, _, _ = await _staggered.staggered_race( - ( - functools.partial( - _connect_sock, - current_loop, - exceptions, - addrinfo, - local_addr_infos, - open_sockets, - socket_factory, - ) - for addrinfo in addr_infos - ), - happy_eyeballs_delay, - ) - finally: - # If we have a winner, staggered_race will - # cancel the other tasks, however there is a - # small race window where any of the other tasks - # can be done before they are cancelled which - # will leave the socket open. To avoid this problem - # we pass a set to _connect_sock to keep track of - # the open sockets and close them here if there - # are any "runner up" sockets. - for s in open_sockets: - if s is not sock: - with contextlib.suppress(OSError): - s.close() - open_sockets = None # type: ignore[assignment] - - if sock is None: - all_exceptions = [exc for sub in exceptions for exc in sub] - try: - first_exception = all_exceptions[0] - if len(all_exceptions) == 1: - raise first_exception - else: - # If they all have the same str(), raise one. - model = str(first_exception) - if all(str(exc) == model for exc in all_exceptions): - raise first_exception - # Raise a combined exception so the user can see all - # the various error messages. - msg = "Multiple exceptions: {}".format( - ", ".join(str(exc) for exc in all_exceptions) - ) - # If the errno is the same for all exceptions, raise - # an OSError with that errno. - if isinstance(first_exception, OSError): - first_errno = first_exception.errno - if all( - isinstance(exc, OSError) and exc.errno == first_errno - for exc in all_exceptions - ): - raise OSError(first_errno, msg) - elif isinstance(first_exception, RuntimeError) and all( - isinstance(exc, RuntimeError) for exc in all_exceptions - ): - raise RuntimeError(msg) - # We have a mix of OSError and RuntimeError - # so we have to pick which one to raise. - # and we raise OSError for compatibility - raise OSError(msg) - finally: - all_exceptions = None # type: ignore[assignment] - exceptions = None # type: ignore[assignment] - - return sock - - -async def _connect_sock( - loop: asyncio.AbstractEventLoop, - exceptions: List[List[Union[OSError, RuntimeError]]], - addr_info: AddrInfoType, - local_addr_infos: Optional[Sequence[AddrInfoType]] = None, - open_sockets: Optional[Set[socket.socket]] = None, - socket_factory: Optional[SocketFactoryType] = None, -) -> socket.socket: - """ - Create, bind and connect one socket. - - If open_sockets is passed, add the socket to the set of open sockets. - Any failure caught here will remove the socket from the set and close it. - - Callers can use this set to close any sockets that are not the winner - of all staggered tasks in the result there are runner up sockets aka - multiple winners. - """ - my_exceptions: List[Union[OSError, RuntimeError]] = [] - exceptions.append(my_exceptions) - family, type_, proto, _, address = addr_info - sock = None - try: - if socket_factory is not None: - sock = socket_factory(addr_info) - else: - sock = socket.socket(family=family, type=type_, proto=proto) - if open_sockets is not None: - open_sockets.add(sock) - sock.setblocking(False) - if local_addr_infos is not None: - for lfamily, _, _, _, laddr in local_addr_infos: - # skip local addresses of different family - if lfamily != family: - continue - try: - sock.bind(laddr) - break - except OSError as exc: - msg = ( - f"error while attempting to bind on " - f"address {laddr!r}: " - f"{(exc.strerror or '').lower()}" - ) - exc = OSError(exc.errno, msg) - my_exceptions.append(exc) - else: # all bind attempts failed - if my_exceptions: - raise my_exceptions.pop() - else: - raise OSError(f"no matching local address with {family=} found") - await loop.sock_connect(sock, address) - return sock - except (RuntimeError, OSError) as exc: - my_exceptions.append(exc) - if sock is not None: - if open_sockets is not None: - open_sockets.remove(sock) - try: - sock.close() - except OSError as e: - my_exceptions.append(e) - raise - raise - except: - if sock is not None: - if open_sockets is not None: - open_sockets.remove(sock) - try: - sock.close() - except OSError as e: - my_exceptions.append(e) - raise - raise - finally: - exceptions = my_exceptions = None # type: ignore[assignment] - - -def _interleave_addrinfos( - addrinfos: Sequence[AddrInfoType], first_address_family_count: int = 1 -) -> List[AddrInfoType]: - """Interleave list of addrinfo tuples by family.""" - # Group addresses by family - addrinfos_by_family: collections.OrderedDict[int, List[AddrInfoType]] = ( - collections.OrderedDict() - ) - for addr in addrinfos: - family = addr[0] - if family not in addrinfos_by_family: - addrinfos_by_family[family] = [] - addrinfos_by_family[family].append(addr) - addrinfos_lists = list(addrinfos_by_family.values()) - - reordered: List[AddrInfoType] = [] - if first_address_family_count > 1: - reordered.extend(addrinfos_lists[0][: first_address_family_count - 1]) - del addrinfos_lists[0][: first_address_family_count - 1] - reordered.extend( - a - for a in itertools.chain.from_iterable(itertools.zip_longest(*addrinfos_lists)) - if a is not None - ) - return reordered diff --git a/venv/lib/python3.9/site-packages/aiohappyeyeballs/py.typed b/venv/lib/python3.9/site-packages/aiohappyeyeballs/py.typed deleted file mode 100644 index e69de29..0000000 diff --git a/venv/lib/python3.9/site-packages/aiohappyeyeballs/types.py b/venv/lib/python3.9/site-packages/aiohappyeyeballs/types.py deleted file mode 100644 index e8c7507..0000000 --- a/venv/lib/python3.9/site-packages/aiohappyeyeballs/types.py +++ /dev/null @@ -1,17 +0,0 @@ -"""Types for aiohappyeyeballs.""" - -import socket - -# PY3.9: Import Callable from typing until we drop Python 3.9 support -# https://github.com/python/cpython/issues/87131 -from typing import Callable, Tuple, Union - -AddrInfoType = Tuple[ - Union[int, socket.AddressFamily], - Union[int, socket.SocketKind], - int, - str, - Tuple, # type: ignore[type-arg] -] - -SocketFactoryType = Callable[[AddrInfoType], socket.socket] diff --git a/venv/lib/python3.9/site-packages/aiohappyeyeballs/utils.py b/venv/lib/python3.9/site-packages/aiohappyeyeballs/utils.py deleted file mode 100644 index ea29adb..0000000 --- a/venv/lib/python3.9/site-packages/aiohappyeyeballs/utils.py +++ /dev/null @@ -1,97 +0,0 @@ -"""Utility functions for aiohappyeyeballs.""" - -import ipaddress -import socket -from typing import Dict, List, Optional, Tuple, Union - -from .types import AddrInfoType - - -def addr_to_addr_infos( - addr: Optional[ - Union[Tuple[str, int, int, int], Tuple[str, int, int], Tuple[str, int]] - ], -) -> Optional[List[AddrInfoType]]: - """Convert an address tuple to a list of addr_info tuples.""" - if addr is None: - return None - host = addr[0] - port = addr[1] - is_ipv6 = ":" in host - if is_ipv6: - flowinfo = 0 - scopeid = 0 - addr_len = len(addr) - if addr_len >= 4: - scopeid = addr[3] # type: ignore[misc] - if addr_len >= 3: - flowinfo = addr[2] # type: ignore[misc] - addr = (host, port, flowinfo, scopeid) - family = socket.AF_INET6 - else: - addr = (host, port) - family = socket.AF_INET - return [(family, socket.SOCK_STREAM, socket.IPPROTO_TCP, "", addr)] - - -def pop_addr_infos_interleave( - addr_infos: List[AddrInfoType], interleave: Optional[int] = None -) -> None: - """ - Pop addr_info from the list of addr_infos by family up to interleave times. - - The interleave parameter is used to know how many addr_infos for - each family should be popped of the top of the list. - """ - seen: Dict[int, int] = {} - if interleave is None: - interleave = 1 - to_remove: List[AddrInfoType] = [] - for addr_info in addr_infos: - family = addr_info[0] - if family not in seen: - seen[family] = 0 - if seen[family] < interleave: - to_remove.append(addr_info) - seen[family] += 1 - for addr_info in to_remove: - addr_infos.remove(addr_info) - - -def _addr_tuple_to_ip_address( - addr: Union[Tuple[str, int], Tuple[str, int, int, int]], -) -> Union[ - Tuple[ipaddress.IPv4Address, int], Tuple[ipaddress.IPv6Address, int, int, int] -]: - """Convert an address tuple to an IPv4Address.""" - return (ipaddress.ip_address(addr[0]), *addr[1:]) - - -def remove_addr_infos( - addr_infos: List[AddrInfoType], - addr: Union[Tuple[str, int], Tuple[str, int, int, int]], -) -> None: - """ - Remove an address from the list of addr_infos. - - The addr value is typically the return value of - sock.getpeername(). - """ - bad_addrs_infos: List[AddrInfoType] = [] - for addr_info in addr_infos: - if addr_info[-1] == addr: - bad_addrs_infos.append(addr_info) - if bad_addrs_infos: - for bad_addr_info in bad_addrs_infos: - addr_infos.remove(bad_addr_info) - return - # Slow path in case addr is formatted differently - match_addr = _addr_tuple_to_ip_address(addr) - for addr_info in addr_infos: - if match_addr == _addr_tuple_to_ip_address(addr_info[-1]): - bad_addrs_infos.append(addr_info) - if bad_addrs_infos: - for bad_addr_info in bad_addrs_infos: - addr_infos.remove(bad_addr_info) - return - raise ValueError(f"Address {addr} not found in addr_infos") diff --git a/venv/lib/python3.9/site-packages/aiohttp-3.13.5.dist-info/INSTALLER b/venv/lib/python3.9/site-packages/aiohttp-3.13.5.dist-info/INSTALLER deleted file mode 100644 index a1b589e..0000000 --- a/venv/lib/python3.9/site-packages/aiohttp-3.13.5.dist-info/INSTALLER +++ /dev/null @@ -1 +0,0 @@ -pip diff --git a/venv/lib/python3.9/site-packages/aiohttp-3.13.5.dist-info/METADATA b/venv/lib/python3.9/site-packages/aiohttp-3.13.5.dist-info/METADATA deleted file mode 100644 index 3977fcd..0000000 --- a/venv/lib/python3.9/site-packages/aiohttp-3.13.5.dist-info/METADATA +++ /dev/null @@ -1,262 +0,0 @@ -Metadata-Version: 2.4 -Name: aiohttp -Version: 3.13.5 -Summary: Async http client/server framework (asyncio) -Maintainer-email: aiohttp team -License: Apache-2.0 AND MIT -Project-URL: Homepage, https://github.com/aio-libs/aiohttp -Project-URL: Chat: Matrix, https://matrix.to/#/#aio-libs:matrix.org -Project-URL: Chat: Matrix Space, https://matrix.to/#/#aio-libs-space:matrix.org -Project-URL: CI: GitHub Actions, https://github.com/aio-libs/aiohttp/actions?query=workflow%3ACI -Project-URL: Coverage: codecov, https://codecov.io/github/aio-libs/aiohttp -Project-URL: Docs: Changelog, https://docs.aiohttp.org/en/stable/changes.html -Project-URL: Docs: RTD, https://docs.aiohttp.org -Project-URL: GitHub: issues, https://github.com/aio-libs/aiohttp/issues -Project-URL: GitHub: repo, https://github.com/aio-libs/aiohttp -Classifier: Development Status :: 5 - Production/Stable -Classifier: Framework :: AsyncIO -Classifier: Intended Audience :: Developers -Classifier: Operating System :: POSIX -Classifier: Operating System :: MacOS :: MacOS X -Classifier: Operating System :: Microsoft :: Windows -Classifier: Programming Language :: Python -Classifier: Programming Language :: Python :: 3 -Classifier: Programming Language :: Python :: 3.9 -Classifier: Programming Language :: Python :: 3.10 -Classifier: Programming Language :: Python :: 3.11 -Classifier: Programming Language :: Python :: 3.12 -Classifier: Programming Language :: Python :: 3.13 -Classifier: Programming Language :: Python :: 3.14 -Classifier: Topic :: Internet :: WWW/HTTP -Requires-Python: >=3.9 -Description-Content-Type: text/x-rst -License-File: LICENSE.txt -License-File: vendor/llhttp/LICENSE -Requires-Dist: aiohappyeyeballs>=2.5.0 -Requires-Dist: aiosignal>=1.4.0 -Requires-Dist: async-timeout<6.0,>=4.0; python_version < "3.11" -Requires-Dist: attrs>=17.3.0 -Requires-Dist: frozenlist>=1.1.1 -Requires-Dist: multidict<7.0,>=4.5 -Requires-Dist: propcache>=0.2.0 -Requires-Dist: yarl<2.0,>=1.17.0 -Provides-Extra: speedups -Requires-Dist: aiodns>=3.3.0; extra == "speedups" -Requires-Dist: Brotli>=1.2; platform_python_implementation == "CPython" and extra == "speedups" -Requires-Dist: brotlicffi>=1.2; platform_python_implementation != "CPython" and extra == "speedups" -Requires-Dist: backports.zstd; (platform_python_implementation == "CPython" and python_version < "3.14") and extra == "speedups" -Dynamic: license-file - -================================== -Async http client/server framework -================================== - -.. image:: https://raw.githubusercontent.com/aio-libs/aiohttp/master/docs/aiohttp-plain.svg - :height: 64px - :width: 64px - :alt: aiohttp logo - -| - -.. image:: https://github.com/aio-libs/aiohttp/workflows/CI/badge.svg - :target: https://github.com/aio-libs/aiohttp/actions?query=workflow%3ACI - :alt: GitHub Actions status for master branch - -.. image:: https://codecov.io/gh/aio-libs/aiohttp/branch/master/graph/badge.svg - :target: https://codecov.io/gh/aio-libs/aiohttp - :alt: codecov.io status for master branch - -.. image:: https://badge.fury.io/py/aiohttp.svg - :target: https://pypi.org/project/aiohttp - :alt: Latest PyPI package version - -.. image:: https://img.shields.io/pypi/dm/aiohttp - :target: https://pypistats.org/packages/aiohttp - :alt: Downloads count - -.. image:: https://readthedocs.org/projects/aiohttp/badge/?version=latest - :target: https://docs.aiohttp.org/ - :alt: Latest Read The Docs - -.. image:: https://img.shields.io/endpoint?url=https://codspeed.io/badge.json - :target: https://codspeed.io/aio-libs/aiohttp - :alt: Codspeed.io status for aiohttp - - -Key Features -============ - -- Supports both client and server side of HTTP protocol. -- Supports both client and server Web-Sockets out-of-the-box and avoids - Callback Hell. -- Provides Web-server with middleware and pluggable routing. - - -Getting started -=============== - -Client ------- - -To get something from the web: - -.. code-block:: python - - import aiohttp - import asyncio - - async def main(): - - async with aiohttp.ClientSession() as session: - async with session.get('http://python.org') as response: - - print("Status:", response.status) - print("Content-type:", response.headers['content-type']) - - html = await response.text() - print("Body:", html[:15], "...") - - asyncio.run(main()) - -This prints: - -.. code-block:: - - Status: 200 - Content-type: text/html; charset=utf-8 - Body: ... - -Coming from `requests `_ ? Read `why we need so many lines `_. - -Server ------- - -An example using a simple server: - -.. code-block:: python - - # examples/server_simple.py - from aiohttp import web - - async def handle(request): - name = request.match_info.get('name', "Anonymous") - text = "Hello, " + name - return web.Response(text=text) - - async def wshandle(request): - ws = web.WebSocketResponse() - await ws.prepare(request) - - async for msg in ws: - if msg.type == web.WSMsgType.text: - await ws.send_str("Hello, {}".format(msg.data)) - elif msg.type == web.WSMsgType.binary: - await ws.send_bytes(msg.data) - elif msg.type == web.WSMsgType.close: - break - - return ws - - - app = web.Application() - app.add_routes([web.get('/', handle), - web.get('/echo', wshandle), - web.get('/{name}', handle)]) - - if __name__ == '__main__': - web.run_app(app) - - -Documentation -============= - -https://aiohttp.readthedocs.io/ - - -Demos -===== - -https://github.com/aio-libs/aiohttp-demos - - -External links -============== - -* `Third party libraries - `_ -* `Built with aiohttp - `_ -* `Powered by aiohttp - `_ - -Feel free to make a Pull Request for adding your link to these pages! - - -Communication channels -====================== - -*aio-libs Discussions*: https://github.com/aio-libs/aiohttp/discussions - -*Matrix*: `#aio-libs:matrix.org `_ - -We support `Stack Overflow -`_. -Please add *aiohttp* tag to your question there. - -Requirements -============ - -- attrs_ -- multidict_ -- yarl_ -- frozenlist_ - -Optionally you may install the aiodns_ library (highly recommended for sake of speed). - -.. _aiodns: https://pypi.python.org/pypi/aiodns -.. _attrs: https://github.com/python-attrs/attrs -.. _multidict: https://pypi.python.org/pypi/multidict -.. _frozenlist: https://pypi.org/project/frozenlist/ -.. _yarl: https://pypi.python.org/pypi/yarl -.. _async-timeout: https://pypi.python.org/pypi/async_timeout - -License -======= - -``aiohttp`` is offered under the Apache 2 license. - - -Keepsafe -======== - -The aiohttp community would like to thank Keepsafe -(https://www.getkeepsafe.com) for its support in the early days of -the project. - - -Source code -=========== - -The latest developer version is available in a GitHub repository: -https://github.com/aio-libs/aiohttp - -Benchmarks -========== - -If you are interested in efficiency, the AsyncIO community maintains a -list of benchmarks on the official wiki: -https://github.com/python/asyncio/wiki/Benchmarks - --------- - -.. image:: https://img.shields.io/matrix/aio-libs:matrix.org?label=Discuss%20on%20Matrix%20at%20%23aio-libs%3Amatrix.org&logo=matrix&server_fqdn=matrix.org&style=flat - :target: https://matrix.to/#/%23aio-libs:matrix.org - :alt: Matrix Room — #aio-libs:matrix.org - -.. image:: https://img.shields.io/matrix/aio-libs-space:matrix.org?label=Discuss%20on%20Matrix%20at%20%23aio-libs-space%3Amatrix.org&logo=matrix&server_fqdn=matrix.org&style=flat - :target: https://matrix.to/#/%23aio-libs-space:matrix.org - :alt: Matrix Space — #aio-libs-space:matrix.org - -.. image:: https://insights.linuxfoundation.org/api/badge/health-score?project=aiohttp - :target: https://insights.linuxfoundation.org/project/aiohttp - :alt: LFX Health Score diff --git a/venv/lib/python3.9/site-packages/aiohttp-3.13.5.dist-info/RECORD b/venv/lib/python3.9/site-packages/aiohttp-3.13.5.dist-info/RECORD deleted file mode 100644 index 07e9ca1..0000000 --- a/venv/lib/python3.9/site-packages/aiohttp-3.13.5.dist-info/RECORD +++ /dev/null @@ -1,138 +0,0 @@ -aiohttp-3.13.5.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 -aiohttp-3.13.5.dist-info/METADATA,sha256=yVHd0XDIuuar5cgTh5EZI2mDXCREeUCWCZ-VA6gWvUQ,8145 -aiohttp-3.13.5.dist-info/RECORD,, -aiohttp-3.13.5.dist-info/WHEEL,sha256=OZLCzpIUHEX42a9RmtxH4_auVuxdXhghS0dmIdhxCRQ,184 -aiohttp-3.13.5.dist-info/licenses/LICENSE.txt,sha256=n4DQ2311WpQdtFchcsJw7L2PCCuiFd3QlZhZQu2Uqes,588 -aiohttp-3.13.5.dist-info/licenses/vendor/llhttp/LICENSE,sha256=68qFTgE0zSVtZzYnwgSZ9CV363S6zwi58ltianPJEnc,1105 -aiohttp-3.13.5.dist-info/top_level.txt,sha256=iv-JIaacmTl-hSho3QmphcKnbRRYx1st47yjz_178Ro,8 -aiohttp/.hash/_cparser.pxd.hash,sha256=pjs-sEXNw_eijXGAedwG-BHnlFp8B7sOCgUagIWaU2A,121 -aiohttp/.hash/_find_header.pxd.hash,sha256=_mbpD6vM-CVCKq3ulUvsOAz5Wdo88wrDzfpOsMQaMNA,125 -aiohttp/.hash/_http_parser.pyx.hash,sha256=T47Ily1qaTY3xOHgBgJZE5A_bKruDtCG_droC3m7BD8,125 -aiohttp/.hash/_http_writer.pyx.hash,sha256=DO9V6lTsDngY8e4y5O0ghHRc-RNGq-pVt_dLNHJy7xA,125 -aiohttp/.hash/hdrs.py.hash,sha256=v6IaKbsxjsdQxBzhb5AjP0x_9G3rUe84D7avf7AI4cs,116 -aiohttp/__init__.py,sha256=r1a3wmBz41XCNY0dqSnCcgfqrDYSDYD-_vKBN3Bfy3Y,8302 -aiohttp/__pycache__/__init__.cpython-39.pyc,, -aiohttp/__pycache__/_cookie_helpers.cpython-39.pyc,, -aiohttp/__pycache__/abc.cpython-39.pyc,, -aiohttp/__pycache__/base_protocol.cpython-39.pyc,, -aiohttp/__pycache__/client.cpython-39.pyc,, -aiohttp/__pycache__/client_exceptions.cpython-39.pyc,, -aiohttp/__pycache__/client_middleware_digest_auth.cpython-39.pyc,, -aiohttp/__pycache__/client_middlewares.cpython-39.pyc,, -aiohttp/__pycache__/client_proto.cpython-39.pyc,, -aiohttp/__pycache__/client_reqrep.cpython-39.pyc,, -aiohttp/__pycache__/client_ws.cpython-39.pyc,, -aiohttp/__pycache__/compression_utils.cpython-39.pyc,, -aiohttp/__pycache__/connector.cpython-39.pyc,, -aiohttp/__pycache__/cookiejar.cpython-39.pyc,, -aiohttp/__pycache__/formdata.cpython-39.pyc,, -aiohttp/__pycache__/hdrs.cpython-39.pyc,, -aiohttp/__pycache__/helpers.cpython-39.pyc,, -aiohttp/__pycache__/http.cpython-39.pyc,, -aiohttp/__pycache__/http_exceptions.cpython-39.pyc,, -aiohttp/__pycache__/http_parser.cpython-39.pyc,, -aiohttp/__pycache__/http_websocket.cpython-39.pyc,, -aiohttp/__pycache__/http_writer.cpython-39.pyc,, -aiohttp/__pycache__/log.cpython-39.pyc,, -aiohttp/__pycache__/multipart.cpython-39.pyc,, -aiohttp/__pycache__/payload.cpython-39.pyc,, -aiohttp/__pycache__/payload_streamer.cpython-39.pyc,, -aiohttp/__pycache__/pytest_plugin.cpython-39.pyc,, -aiohttp/__pycache__/resolver.cpython-39.pyc,, -aiohttp/__pycache__/streams.cpython-39.pyc,, -aiohttp/__pycache__/tcp_helpers.cpython-39.pyc,, -aiohttp/__pycache__/test_utils.cpython-39.pyc,, -aiohttp/__pycache__/tracing.cpython-39.pyc,, -aiohttp/__pycache__/typedefs.cpython-39.pyc,, -aiohttp/__pycache__/web.cpython-39.pyc,, -aiohttp/__pycache__/web_app.cpython-39.pyc,, -aiohttp/__pycache__/web_exceptions.cpython-39.pyc,, -aiohttp/__pycache__/web_fileresponse.cpython-39.pyc,, -aiohttp/__pycache__/web_log.cpython-39.pyc,, -aiohttp/__pycache__/web_middlewares.cpython-39.pyc,, -aiohttp/__pycache__/web_protocol.cpython-39.pyc,, -aiohttp/__pycache__/web_request.cpython-39.pyc,, -aiohttp/__pycache__/web_response.cpython-39.pyc,, -aiohttp/__pycache__/web_routedef.cpython-39.pyc,, -aiohttp/__pycache__/web_runner.cpython-39.pyc,, -aiohttp/__pycache__/web_server.cpython-39.pyc,, -aiohttp/__pycache__/web_urldispatcher.cpython-39.pyc,, -aiohttp/__pycache__/web_ws.cpython-39.pyc,, -aiohttp/__pycache__/worker.cpython-39.pyc,, -aiohttp/_cookie_helpers.py,sha256=_p7y-B8OCAk7FLjByiuwFIpDLGuNoJn3_vixzymAFnE,13659 -aiohttp/_cparser.pxd,sha256=UnbUYCHg4NdXfgyRVYAMv2KTLWClB4P-xCrvtj_r7ew,4295 -aiohttp/_find_header.pxd,sha256=0GfwFCPN2zxEKTO1_MA5sYq2UfzsG8kcV3aTqvwlz3g,68 -aiohttp/_headers.pxi,sha256=n701k28dVPjwRnx5j6LpJhLTfj7dqu2vJt7f0O60Oyg,2007 -aiohttp/_http_parser.cpython-39-x86_64-linux-gnu.so,sha256=GVgaK8L0UlvIUlat8z6Mf2L6IYPx3FxXL5ZdizvhN5g,2698432 -aiohttp/_http_parser.pyx,sha256=veuwNKb6YzBJoO3nbvrkOCaTzbcROS5MVksUJhDHNgg,30036 -aiohttp/_http_writer.cpython-39-x86_64-linux-gnu.so,sha256=s2v7ojOqKiQ0FuPxQJd8Hdzma75VFwJNtoLBC99cQy4,452304 -aiohttp/_http_writer.pyx,sha256=TXNOC90txk4wnPakxex_ygSbr3xq1UxaCi2T4gv2teY,4690 -aiohttp/_websocket/.hash/mask.pxd.hash,sha256=Y0zBddk_ck3pi9-BFzMcpkcvCKvwvZ4GTtZFb9u1nxQ,128 -aiohttp/_websocket/.hash/mask.pyx.hash,sha256=90owpXYM8_kIma4KUcOxhWSk-Uv4NVMBoCYeFM1B3d0,128 -aiohttp/_websocket/.hash/reader_c.pxd.hash,sha256=5xf3oobk6vx4xbJm-xtZ1_QufB8fYFtLQV2MNdqUc1w,132 -aiohttp/_websocket/__init__.py,sha256=Mar3R9_vBN_Ea4lsW7iTAVXD7OKswKPGqF5xgSyt77k,44 -aiohttp/_websocket/__pycache__/__init__.cpython-39.pyc,, -aiohttp/_websocket/__pycache__/helpers.cpython-39.pyc,, -aiohttp/_websocket/__pycache__/models.cpython-39.pyc,, -aiohttp/_websocket/__pycache__/reader.cpython-39.pyc,, -aiohttp/_websocket/__pycache__/reader_c.cpython-39.pyc,, -aiohttp/_websocket/__pycache__/reader_py.cpython-39.pyc,, -aiohttp/_websocket/__pycache__/writer.cpython-39.pyc,, -aiohttp/_websocket/helpers.py,sha256=P-XLv8IUaihKzDenVUqfKU5DJbWE5HvG8uhvUZK8Ic4,5038 -aiohttp/_websocket/mask.cpython-39-x86_64-linux-gnu.so,sha256=BybI5R0q5_H7fDGBMc-idAs8Nzek7C0dV_oTFGYK-N0,221640 -aiohttp/_websocket/mask.pxd,sha256=sBmZ1Amym9kW4Ge8lj1fLZ7mPPya4LzLdpkQExQXv5M,112 -aiohttp/_websocket/mask.pyx,sha256=BHjOtV0O0w7xp9p0LNADRJvGmgfPn9sGeJvSs0fL__4,1397 -aiohttp/_websocket/models.py,sha256=XAzjs_8JYszWXIgZ6R3ZRrF-tX9Q_6LiD49WRYojopM,2121 -aiohttp/_websocket/reader.py,sha256=eC4qS0c5sOeQ2ebAHLaBpIaTVFaSKX79pY2xvh3Pqyw,1030 -aiohttp/_websocket/reader_c.cpython-39-x86_64-linux-gnu.so,sha256=K-hxF7Hvw4MBsxoe4e-QW5NQdW_UKVfNL55HiXvZLLo,1695504 -aiohttp/_websocket/reader_c.pxd,sha256=nl_njtDrzlQU0rjgGGjZDB-swguE0tX_bCPobkShVa4,2625 -aiohttp/_websocket/reader_c.py,sha256=V5YtZ2gj2BjE2Q-W9sR_MdAl1VAm1pB7ZjozVJcOpbg,18868 -aiohttp/_websocket/reader_py.py,sha256=V5YtZ2gj2BjE2Q-W9sR_MdAl1VAm1pB7ZjozVJcOpbg,18868 -aiohttp/_websocket/writer.py,sha256=2OvSktPmNh_g20h1cXJt2Xu8u6IvswnPjdur7OwBbJk,11261 -aiohttp/abc.py,sha256=M66F4S6m00bIEn7y4ha_XLTMDmVQ9dPihfOVB0pGfOo,7149 -aiohttp/base_protocol.py,sha256=Tp8cxUPQvv9kUPk3w6lAzk6d2MAzV3scwI_3Go3C47c,3025 -aiohttp/client.py,sha256=JkHGrrJq1pSI7QEJw0jZKx5TLLzM87of8Yx-62m4x6g,58795 -aiohttp/client_exceptions.py,sha256=t6vDg0ZhHDvij6E89Nv473zLpNu3CyMPAp0LqLHOc9I,11744 -aiohttp/client_middleware_digest_auth.py,sha256=rInzAPEmFsaF42oVORmYSx56og1B7jZUSmmIdFD0MQ8,17641 -aiohttp/client_middlewares.py,sha256=kP5N9CMzQPMGPIEydeVUiLUTLsw8Vl8Gr4qAWYdu3vM,1918 -aiohttp/client_proto.py,sha256=eimrsOVNMt_y62gmXZ4JoBI5VZ0kGaW6WnqMkB1cnNQ,12179 -aiohttp/client_reqrep.py,sha256=eEREDrZ0M8ZFTt1wjHduR-P8_sm40K65gNz-iMGYask,53391 -aiohttp/client_ws.py,sha256=1CIjIXwyzOMIYw6AjUES4-qUwbyVHW1seJKQfg_Rta8,15109 -aiohttp/compression_utils.py,sha256=hJ2LXhN2OWukFHm5b78TJFGKcAiL2kthi9Sf5PRYO-U,11738 -aiohttp/connector.py,sha256=0AFVMAx7NwkIbovQ0qecQ3JO2bpEZpxMG_OnGZ3tP3E,69451 -aiohttp/cookiejar.py,sha256=e28ZMQwJ5P0vbPX1OX4Se7-k3zeGvocFEqzGhwpG53k,18922 -aiohttp/formdata.py,sha256=0cxe-naBSFp_NHB1l-TUSbhesU4dpNvwJMzhsLYoSns,6625 -aiohttp/hdrs.py,sha256=2rj5MyA-6yRdYPhW5UKkW4iNWhEAlGIOSBH5D4FmKNE,5111 -aiohttp/helpers.py,sha256=Q1307PCEnWz4RP8crUw8dk58c0YF2Ei3JywkKfRxz5E,30629 -aiohttp/http.py,sha256=8o8j8xH70OWjnfTWA9V44NR785QPxEPrUtzMXiAVpwc,1842 -aiohttp/http_exceptions.py,sha256=Z4IiKYxyfn1Pe947OfqW6NjXoVd12bDI4eKBZKC3Htw,3085 -aiohttp/http_parser.py,sha256=TIvopmjIH3TSTrVTbbqxpBWBpkEuOaNjkzES0-fm4-4,40472 -aiohttp/http_websocket.py,sha256=8VXFKw6KQUEmPg48GtRMB37v0gTK7A0inoxXuDxMZEc,842 -aiohttp/http_writer.py,sha256=4sbiFD_RkE0x_xlAPXwGrL0iLS53L72Qw13hBPaQLls,12508 -aiohttp/log.py,sha256=BbNKx9e3VMIm0xYjZI0IcBBoS7wjdeIeSaiJE7-qK2g,325 -aiohttp/multipart.py,sha256=qMDEHLf64qQcPQLZv4RdwKUDB2L1CC_vN-5Z-P8wDzw,42805 -aiohttp/payload.py,sha256=O6nsYNULL7AeM2cyJ6TYX73ncVnL5xJwt5AegxwMKqw,40874 -aiohttp/payload_streamer.py,sha256=ZzEYyfzcjGWkVkK3XR2pBthSCSIykYvY3Wr5cGQ2eTc,2211 -aiohttp/py.typed,sha256=sow9soTwP9T_gEAQSVh7Gb8855h04Nwmhs2We-JRgZM,7 -aiohttp/pytest_plugin.py,sha256=z4XwqmsKdyJCKxbGiA5kFf90zcedvomqk4RqjZbhKNk,12901 -aiohttp/resolver.py,sha256=gsrfUpFf8iHlcHfJvY-1fiBHW3PRvRVNb5lNZBg3zlY,10031 -aiohttp/streams.py,sha256=i32xpXEjGL2c6ifepnBxBto5y9wXobzzYAIsi8kAkKI,23920 -aiohttp/tcp_helpers.py,sha256=BSadqVWaBpMFDRWnhaaR941N9MiDZ7bdTrxgCb0CW-M,961 -aiohttp/test_utils.py,sha256=7hMcJnOUSkZ54Axgdvveeth5y6R_B2T-0H2xX7mKWYc,23130 -aiohttp/tracing.py,sha256=-6aaW6l0J9uJD45LzR4cijYH0j62pt0U_nn_aVzFku4,14558 -aiohttp/typedefs.py,sha256=wUlqwe9Mw9W8jT3HsYJcYk00qP3EMPz3nTkYXmeNN48,1657 -aiohttp/web.py,sha256=JzSNmejg5G6YeFAnkIgZfytqbU86sNu844yYKmoUpqs,17852 -aiohttp/web_app.py,sha256=lGU_aAMN-h3wy-LTTHi6SeKH8ydt1G51BXcCspgD5ZA,19452 -aiohttp/web_exceptions.py,sha256=aXW8MStpRS7JOFxYDPgPlWojMJP9RhxyAqvq2g0jOCE,10495 -aiohttp/web_fileresponse.py,sha256=arimioSXf0rZQ46H9ejCip4hVN6ri_faFWfuP_XL_us,16374 -aiohttp/web_log.py,sha256=1hhC05PJizS2POVfNxncorNM_fjYHMx2TbcpP6isxkQ,8624 -aiohttp/web_middlewares.py,sha256=sFI0AgeNjdyAjuz92QtMIpngmJSOxrqe2Jfbs4BNUu0,4165 -aiohttp/web_protocol.py,sha256=ZEwjomG6Y2olq2b967UXDezwYnuLJJHDNl48SgHpKJs,27210 -aiohttp/web_request.py,sha256=xNCrsUQSqTB64G1_9QiC9xfQmdgkJwYkGfPBwnfIYQo,30406 -aiohttp/web_response.py,sha256=DofOPOU4be_upiqouWjxfhMLyubtRFvOGnJZbIamH6s,29366 -aiohttp/web_routedef.py,sha256=VT1GAx6BrawoDh5RwBwBu5wSABSqgWwAe74AUCyZAEo,6110 -aiohttp/web_runner.py,sha256=v1G1nKiOOQgFnTSR4IMc6I9ReEFDMaHtMLvO_roDM-A,11786 -aiohttp/web_server.py,sha256=-9WDKUAiR9ll-rSdwXSqG6YjaoW79d1R4y0BGSqgUMA,2888 -aiohttp/web_urldispatcher.py,sha256=9pJ6b3LuujtZuAURNYh0tdhgCJn2ZFrakeEySNwNqhU,44512 -aiohttp/web_ws.py,sha256=lItgmyatkXh0M6EY7JoZnSZkUl6R0wv8B88X4ILqQbU,22739 -aiohttp/worker.py,sha256=o6BL8dbCGYysB76i_yGGvYagc9gyy2PyW1UisiOznjA,8345 diff --git a/venv/lib/python3.9/site-packages/aiohttp-3.13.5.dist-info/WHEEL b/venv/lib/python3.9/site-packages/aiohttp-3.13.5.dist-info/WHEEL deleted file mode 100644 index fbcc8e7..0000000 --- a/venv/lib/python3.9/site-packages/aiohttp-3.13.5.dist-info/WHEEL +++ /dev/null @@ -1,7 +0,0 @@ -Wheel-Version: 1.0 -Generator: setuptools (82.0.1) -Root-Is-Purelib: false -Tag: cp39-cp39-manylinux_2_17_x86_64 -Tag: cp39-cp39-manylinux2014_x86_64 -Tag: cp39-cp39-manylinux_2_28_x86_64 - diff --git a/venv/lib/python3.9/site-packages/aiohttp-3.13.5.dist-info/licenses/LICENSE.txt b/venv/lib/python3.9/site-packages/aiohttp-3.13.5.dist-info/licenses/LICENSE.txt deleted file mode 100644 index e497a32..0000000 --- a/venv/lib/python3.9/site-packages/aiohttp-3.13.5.dist-info/licenses/LICENSE.txt +++ /dev/null @@ -1,13 +0,0 @@ - Copyright aio-libs contributors. - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. diff --git a/venv/lib/python3.9/site-packages/aiohttp-3.13.5.dist-info/licenses/vendor/llhttp/LICENSE b/venv/lib/python3.9/site-packages/aiohttp-3.13.5.dist-info/licenses/vendor/llhttp/LICENSE deleted file mode 100644 index 6c1512d..0000000 --- a/venv/lib/python3.9/site-packages/aiohttp-3.13.5.dist-info/licenses/vendor/llhttp/LICENSE +++ /dev/null @@ -1,22 +0,0 @@ -This software is licensed under the MIT License. - -Copyright Fedor Indutny, 2018. - -Permission is hereby granted, free of charge, to any person obtaining a -copy of this software and associated documentation files (the -"Software"), to deal in the Software without restriction, including -without limitation the rights to use, copy, modify, merge, publish, -distribute, sublicense, and/or sell copies of the Software, and to permit -persons to whom the Software is furnished to do so, subject to the -following conditions: - -The above copyright notice and this permission notice shall be included -in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN -NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, -DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR -OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE -USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/venv/lib/python3.9/site-packages/aiohttp-3.13.5.dist-info/top_level.txt b/venv/lib/python3.9/site-packages/aiohttp-3.13.5.dist-info/top_level.txt deleted file mode 100644 index ee4ba4f..0000000 --- a/venv/lib/python3.9/site-packages/aiohttp-3.13.5.dist-info/top_level.txt +++ /dev/null @@ -1 +0,0 @@ -aiohttp diff --git a/venv/lib/python3.9/site-packages/aiohttp/.hash/_cparser.pxd.hash b/venv/lib/python3.9/site-packages/aiohttp/.hash/_cparser.pxd.hash deleted file mode 100644 index 3f5cd0e..0000000 --- a/venv/lib/python3.9/site-packages/aiohttp/.hash/_cparser.pxd.hash +++ /dev/null @@ -1 +0,0 @@ -5276d46021e0e0d7577e0c9155800cbf62932d60a50783fec42aefb63febedec /home/runner/work/aiohttp/aiohttp/aiohttp/_cparser.pxd diff --git a/venv/lib/python3.9/site-packages/aiohttp/.hash/_find_header.pxd.hash b/venv/lib/python3.9/site-packages/aiohttp/.hash/_find_header.pxd.hash deleted file mode 100644 index f006c2d..0000000 --- a/venv/lib/python3.9/site-packages/aiohttp/.hash/_find_header.pxd.hash +++ /dev/null @@ -1 +0,0 @@ -d067f01423cddb3c442933b5fcc039b18ab651fcec1bc91c577693aafc25cf78 /home/runner/work/aiohttp/aiohttp/aiohttp/_find_header.pxd diff --git a/venv/lib/python3.9/site-packages/aiohttp/.hash/_http_parser.pyx.hash b/venv/lib/python3.9/site-packages/aiohttp/.hash/_http_parser.pyx.hash deleted file mode 100644 index af02f94..0000000 --- a/venv/lib/python3.9/site-packages/aiohttp/.hash/_http_parser.pyx.hash +++ /dev/null @@ -1 +0,0 @@ -bdebb034a6fa633049a0ede76efae4382693cdb711392e4c564b142610c73608 /home/runner/work/aiohttp/aiohttp/aiohttp/_http_parser.pyx diff --git a/venv/lib/python3.9/site-packages/aiohttp/.hash/_http_writer.pyx.hash b/venv/lib/python3.9/site-packages/aiohttp/.hash/_http_writer.pyx.hash deleted file mode 100644 index 43c1ab1..0000000 --- a/venv/lib/python3.9/site-packages/aiohttp/.hash/_http_writer.pyx.hash +++ /dev/null @@ -1 +0,0 @@ -4d734e0bdd2dc64e309cf6a4c5ec7fca049baf7c6ad54c5a0a2d93e20bf6b5e6 /home/runner/work/aiohttp/aiohttp/aiohttp/_http_writer.pyx diff --git a/venv/lib/python3.9/site-packages/aiohttp/.hash/hdrs.py.hash b/venv/lib/python3.9/site-packages/aiohttp/.hash/hdrs.py.hash deleted file mode 100644 index c8d5524..0000000 --- a/venv/lib/python3.9/site-packages/aiohttp/.hash/hdrs.py.hash +++ /dev/null @@ -1 +0,0 @@ -dab8f933203eeb245d60f856e542a45b888d5a110094620e4811f90f816628d1 /home/runner/work/aiohttp/aiohttp/aiohttp/hdrs.py diff --git a/venv/lib/python3.9/site-packages/aiohttp/__init__.py b/venv/lib/python3.9/site-packages/aiohttp/__init__.py deleted file mode 100644 index 404f926..0000000 --- a/venv/lib/python3.9/site-packages/aiohttp/__init__.py +++ /dev/null @@ -1,278 +0,0 @@ -__version__ = "3.13.5" - -from typing import TYPE_CHECKING, Tuple - -from . import hdrs as hdrs -from .client import ( - BaseConnector, - ClientConnectionError, - ClientConnectionResetError, - ClientConnectorCertificateError, - ClientConnectorDNSError, - ClientConnectorError, - ClientConnectorSSLError, - ClientError, - ClientHttpProxyError, - ClientOSError, - ClientPayloadError, - ClientProxyConnectionError, - ClientRequest, - ClientResponse, - ClientResponseError, - ClientSession, - ClientSSLError, - ClientTimeout, - ClientWebSocketResponse, - ClientWSTimeout, - ConnectionTimeoutError, - ContentTypeError, - Fingerprint, - InvalidURL, - InvalidUrlClientError, - InvalidUrlRedirectClientError, - NamedPipeConnector, - NonHttpUrlClientError, - NonHttpUrlRedirectClientError, - RedirectClientError, - RequestInfo, - ServerConnectionError, - ServerDisconnectedError, - ServerFingerprintMismatch, - ServerTimeoutError, - SocketTimeoutError, - TCPConnector, - TooManyRedirects, - UnixConnector, - WSMessageTypeError, - WSServerHandshakeError, - request, -) -from .client_middleware_digest_auth import DigestAuthMiddleware -from .client_middlewares import ClientHandlerType, ClientMiddlewareType -from .compression_utils import set_zlib_backend -from .connector import ( - AddrInfoType as AddrInfoType, - SocketFactoryType as SocketFactoryType, -) -from .cookiejar import CookieJar as CookieJar, DummyCookieJar as DummyCookieJar -from .formdata import FormData as FormData -from .helpers import BasicAuth, ChainMapProxy, ETag -from .http import ( - HttpVersion as HttpVersion, - HttpVersion10 as HttpVersion10, - HttpVersion11 as HttpVersion11, - WebSocketError as WebSocketError, - WSCloseCode as WSCloseCode, - WSMessage as WSMessage, - WSMsgType as WSMsgType, -) -from .multipart import ( - BadContentDispositionHeader as BadContentDispositionHeader, - BadContentDispositionParam as BadContentDispositionParam, - BodyPartReader as BodyPartReader, - MultipartReader as MultipartReader, - MultipartWriter as MultipartWriter, - content_disposition_filename as content_disposition_filename, - parse_content_disposition as parse_content_disposition, -) -from .payload import ( - PAYLOAD_REGISTRY as PAYLOAD_REGISTRY, - AsyncIterablePayload as AsyncIterablePayload, - BufferedReaderPayload as BufferedReaderPayload, - BytesIOPayload as BytesIOPayload, - BytesPayload as BytesPayload, - IOBasePayload as IOBasePayload, - JsonPayload as JsonPayload, - Payload as Payload, - StringIOPayload as StringIOPayload, - StringPayload as StringPayload, - TextIOPayload as TextIOPayload, - get_payload as get_payload, - payload_type as payload_type, -) -from .payload_streamer import streamer as streamer -from .resolver import ( - AsyncResolver as AsyncResolver, - DefaultResolver as DefaultResolver, - ThreadedResolver as ThreadedResolver, -) -from .streams import ( - EMPTY_PAYLOAD as EMPTY_PAYLOAD, - DataQueue as DataQueue, - EofStream as EofStream, - FlowControlDataQueue as FlowControlDataQueue, - StreamReader as StreamReader, -) -from .tracing import ( - TraceConfig as TraceConfig, - TraceConnectionCreateEndParams as TraceConnectionCreateEndParams, - TraceConnectionCreateStartParams as TraceConnectionCreateStartParams, - TraceConnectionQueuedEndParams as TraceConnectionQueuedEndParams, - TraceConnectionQueuedStartParams as TraceConnectionQueuedStartParams, - TraceConnectionReuseconnParams as TraceConnectionReuseconnParams, - TraceDnsCacheHitParams as TraceDnsCacheHitParams, - TraceDnsCacheMissParams as TraceDnsCacheMissParams, - TraceDnsResolveHostEndParams as TraceDnsResolveHostEndParams, - TraceDnsResolveHostStartParams as TraceDnsResolveHostStartParams, - TraceRequestChunkSentParams as TraceRequestChunkSentParams, - TraceRequestEndParams as TraceRequestEndParams, - TraceRequestExceptionParams as TraceRequestExceptionParams, - TraceRequestHeadersSentParams as TraceRequestHeadersSentParams, - TraceRequestRedirectParams as TraceRequestRedirectParams, - TraceRequestStartParams as TraceRequestStartParams, - TraceResponseChunkReceivedParams as TraceResponseChunkReceivedParams, -) - -if TYPE_CHECKING: - # At runtime these are lazy-loaded at the bottom of the file. - from .worker import ( - GunicornUVLoopWebWorker as GunicornUVLoopWebWorker, - GunicornWebWorker as GunicornWebWorker, - ) - -__all__: Tuple[str, ...] = ( - "hdrs", - # client - "AddrInfoType", - "BaseConnector", - "ClientConnectionError", - "ClientConnectionResetError", - "ClientConnectorCertificateError", - "ClientConnectorDNSError", - "ClientConnectorError", - "ClientConnectorSSLError", - "ClientError", - "ClientHttpProxyError", - "ClientOSError", - "ClientPayloadError", - "ClientProxyConnectionError", - "ClientResponse", - "ClientRequest", - "ClientResponseError", - "ClientSSLError", - "ClientSession", - "ClientTimeout", - "ClientWebSocketResponse", - "ClientWSTimeout", - "ConnectionTimeoutError", - "ContentTypeError", - "Fingerprint", - "FlowControlDataQueue", - "InvalidURL", - "InvalidUrlClientError", - "InvalidUrlRedirectClientError", - "NonHttpUrlClientError", - "NonHttpUrlRedirectClientError", - "RedirectClientError", - "RequestInfo", - "ServerConnectionError", - "ServerDisconnectedError", - "ServerFingerprintMismatch", - "ServerTimeoutError", - "SocketFactoryType", - "SocketTimeoutError", - "TCPConnector", - "TooManyRedirects", - "UnixConnector", - "NamedPipeConnector", - "WSServerHandshakeError", - "request", - # client_middleware - "ClientMiddlewareType", - "ClientHandlerType", - # cookiejar - "CookieJar", - "DummyCookieJar", - # formdata - "FormData", - # helpers - "BasicAuth", - "ChainMapProxy", - "DigestAuthMiddleware", - "ETag", - "set_zlib_backend", - # http - "HttpVersion", - "HttpVersion10", - "HttpVersion11", - "WSMsgType", - "WSCloseCode", - "WSMessage", - "WebSocketError", - # multipart - "BadContentDispositionHeader", - "BadContentDispositionParam", - "BodyPartReader", - "MultipartReader", - "MultipartWriter", - "content_disposition_filename", - "parse_content_disposition", - # payload - "AsyncIterablePayload", - "BufferedReaderPayload", - "BytesIOPayload", - "BytesPayload", - "IOBasePayload", - "JsonPayload", - "PAYLOAD_REGISTRY", - "Payload", - "StringIOPayload", - "StringPayload", - "TextIOPayload", - "get_payload", - "payload_type", - # payload_streamer - "streamer", - # resolver - "AsyncResolver", - "DefaultResolver", - "ThreadedResolver", - # streams - "DataQueue", - "EMPTY_PAYLOAD", - "EofStream", - "StreamReader", - # tracing - "TraceConfig", - "TraceConnectionCreateEndParams", - "TraceConnectionCreateStartParams", - "TraceConnectionQueuedEndParams", - "TraceConnectionQueuedStartParams", - "TraceConnectionReuseconnParams", - "TraceDnsCacheHitParams", - "TraceDnsCacheMissParams", - "TraceDnsResolveHostEndParams", - "TraceDnsResolveHostStartParams", - "TraceRequestChunkSentParams", - "TraceRequestEndParams", - "TraceRequestExceptionParams", - "TraceRequestHeadersSentParams", - "TraceRequestRedirectParams", - "TraceRequestStartParams", - "TraceResponseChunkReceivedParams", - # workers (imported lazily with __getattr__) - "GunicornUVLoopWebWorker", - "GunicornWebWorker", - "WSMessageTypeError", -) - - -def __dir__() -> Tuple[str, ...]: - return __all__ + ("__doc__",) - - -def __getattr__(name: str) -> object: - global GunicornUVLoopWebWorker, GunicornWebWorker - - # Importing gunicorn takes a long time (>100ms), so only import if actually needed. - if name in ("GunicornUVLoopWebWorker", "GunicornWebWorker"): - try: - from .worker import GunicornUVLoopWebWorker as guv, GunicornWebWorker as gw - except ImportError: - return None - - GunicornUVLoopWebWorker = guv # type: ignore[misc] - GunicornWebWorker = gw # type: ignore[misc] - return guv if name == "GunicornUVLoopWebWorker" else gw - - raise AttributeError(f"module {__name__} has no attribute {name}") diff --git a/venv/lib/python3.9/site-packages/aiohttp/_cookie_helpers.py b/venv/lib/python3.9/site-packages/aiohttp/_cookie_helpers.py deleted file mode 100644 index 10e2e0e..0000000 --- a/venv/lib/python3.9/site-packages/aiohttp/_cookie_helpers.py +++ /dev/null @@ -1,338 +0,0 @@ -""" -Internal cookie handling helpers. - -This module contains internal utilities for cookie parsing and manipulation. -These are not part of the public API and may change without notice. -""" - -import re -from http.cookies import Morsel -from typing import List, Optional, Sequence, Tuple, cast - -from .log import internal_logger - -__all__ = ( - "parse_set_cookie_headers", - "parse_cookie_header", - "preserve_morsel_with_coded_value", -) - -# Cookie parsing constants -# Allow more characters in cookie names to handle real-world cookies -# that don't strictly follow RFC standards (fixes #2683) -# RFC 6265 defines cookie-name token as per RFC 2616 Section 2.2, -# but many servers send cookies with characters like {} [] () etc. -# This makes the cookie parser more tolerant of real-world cookies -# while still providing some validation to catch obviously malformed names. -_COOKIE_NAME_RE = re.compile(r"^[!#$%&\'()*+\-./0-9:<=>?@A-Z\[\]^_`a-z{|}~]+$") -_COOKIE_KNOWN_ATTRS = frozenset( # AKA Morsel._reserved - ( - "path", - "domain", - "max-age", - "expires", - "secure", - "httponly", - "samesite", - "partitioned", - "version", - "comment", - ) -) -_COOKIE_BOOL_ATTRS = frozenset( # AKA Morsel._flags - ("secure", "httponly", "partitioned") -) - -# SimpleCookie's pattern for parsing cookies with relaxed validation -# Based on http.cookies pattern but extended to allow more characters in cookie names -# to handle real-world cookies (fixes #2683) -_COOKIE_PATTERN = re.compile( - r""" - \s* # Optional whitespace at start of cookie - (?P # Start of group 'key' - # aiohttp has extended to include [] for compatibility with real-world cookies - [\w\d!#%&'~_`><@,:/\$\*\+\-\.\^\|\)\(\?\}\{\[\]]+ # Any word of at least one letter - ) # End of group 'key' - ( # Optional group: there may not be a value. - \s*=\s* # Equal Sign - (?P # Start of group 'val' - "(?:[^\\"]|\\.)*" # Any double-quoted string (properly closed) - | # or - "[^";]* # Unmatched opening quote (differs from SimpleCookie - issue #7993) - | # or - # Special case for "expires" attr - RFC 822, RFC 850, RFC 1036, RFC 1123 - (\w{3,6}day|\w{3}),\s # Day of the week or abbreviated day (with comma) - [\w\d\s-]{9,11}\s[\d:]{8}\s # Date and time in specific format - (GMT|[+-]\d{4}) # Timezone: GMT or RFC 2822 offset like -0000, +0100 - # NOTE: RFC 2822 timezone support is an aiohttp extension - # for issue #4493 - SimpleCookie does NOT support this - | # or - # ANSI C asctime() format: "Wed Jun 9 10:18:14 2021" - # NOTE: This is an aiohttp extension for issue #4327 - SimpleCookie does NOT support this format - \w{3}\s+\w{3}\s+[\s\d]\d\s+\d{2}:\d{2}:\d{2}\s+\d{4} - | # or - [\w\d!#%&'~_`><@,:/\$\*\+\-\.\^\|\)\(\?\}\{\=\[\]]* # Any word or empty string - ) # End of group 'val' - )? # End of optional value group - \s* # Any number of spaces. - (\s+|;|$) # Ending either at space, semicolon, or EOS. - """, - re.VERBOSE | re.ASCII, -) - - -def preserve_morsel_with_coded_value(cookie: Morsel[str]) -> Morsel[str]: - """ - Preserve a Morsel's coded_value exactly as received from the server. - - This function ensures that cookie encoding is preserved exactly as sent by - the server, which is critical for compatibility with old servers that have - strict requirements about cookie formats. - - This addresses the issue described in https://github.com/aio-libs/aiohttp/pull/1453 - where Python's SimpleCookie would re-encode cookies, breaking authentication - with certain servers. - - Args: - cookie: A Morsel object from SimpleCookie - - Returns: - A Morsel object with preserved coded_value - - """ - mrsl_val = cast("Morsel[str]", cookie.get(cookie.key, Morsel())) - # We use __setstate__ instead of the public set() API because it allows us to - # bypass validation and set already validated state. This is more stable than - # setting protected attributes directly and unlikely to change since it would - # break pickling. - mrsl_val.__setstate__( # type: ignore[attr-defined] - {"key": cookie.key, "value": cookie.value, "coded_value": cookie.coded_value} - ) - return mrsl_val - - -_unquote_sub = re.compile(r"\\(?:([0-3][0-7][0-7])|(.))").sub - - -def _unquote_replace(m: re.Match[str]) -> str: - """ - Replace function for _unquote_sub regex substitution. - - Handles escaped characters in cookie values: - - Octal sequences are converted to their character representation - - Other escaped characters are unescaped by removing the backslash - """ - if m[1]: - return chr(int(m[1], 8)) - return m[2] - - -def _unquote(value: str) -> str: - """ - Unquote a cookie value. - - Vendored from http.cookies._unquote to ensure compatibility. - - Note: The original implementation checked for None, but we've removed - that check since all callers already ensure the value is not None. - """ - # If there aren't any doublequotes, - # then there can't be any special characters. See RFC 2109. - if len(value) < 2: - return value - if value[0] != '"' or value[-1] != '"': - return value - - # We have to assume that we must decode this string. - # Down to work. - - # Remove the "s - value = value[1:-1] - - # Check for special sequences. Examples: - # \012 --> \n - # \" --> " - # - return _unquote_sub(_unquote_replace, value) - - -def parse_cookie_header(header: str) -> List[Tuple[str, Morsel[str]]]: - """ - Parse a Cookie header according to RFC 6265 Section 5.4. - - Cookie headers contain only name-value pairs separated by semicolons. - There are no attributes in Cookie headers - even names that match - attribute names (like 'path' or 'secure') should be treated as cookies. - - This parser uses the same regex-based approach as parse_set_cookie_headers - to properly handle quoted values that may contain semicolons. When the - regex fails to match a malformed cookie, it falls back to simple parsing - to ensure subsequent cookies are not lost - https://github.com/aio-libs/aiohttp/issues/11632 - - Args: - header: The Cookie header value to parse - - Returns: - List of (name, Morsel) tuples for compatibility with SimpleCookie.update() - """ - if not header: - return [] - - cookies: List[Tuple[str, Morsel[str]]] = [] - morsel: Morsel[str] - i = 0 - n = len(header) - - invalid_names = [] - while i < n: - # Use the same pattern as parse_set_cookie_headers to find cookies - match = _COOKIE_PATTERN.match(header, i) - if not match: - # Fallback for malformed cookies https://github.com/aio-libs/aiohttp/issues/11632 - # Find next semicolon to skip or attempt simple key=value parsing - next_semi = header.find(";", i) - eq_pos = header.find("=", i) - - # Try to extract key=value if '=' comes before ';' - if eq_pos != -1 and (next_semi == -1 or eq_pos < next_semi): - end_pos = next_semi if next_semi != -1 else n - key = header[i:eq_pos].strip() - value = header[eq_pos + 1 : end_pos].strip() - - # Validate the name (same as regex path) - if not _COOKIE_NAME_RE.match(key): - invalid_names.append(key) - else: - morsel = Morsel() - morsel.__setstate__( # type: ignore[attr-defined] - {"key": key, "value": _unquote(value), "coded_value": value} - ) - cookies.append((key, morsel)) - - # Move to next cookie or end - i = next_semi + 1 if next_semi != -1 else n - continue - - key = match.group("key") - value = match.group("val") or "" - i = match.end(0) - - # Validate the name - if not key or not _COOKIE_NAME_RE.match(key): - invalid_names.append(key) - continue - - # Create new morsel - morsel = Morsel() - # Preserve the original value as coded_value (with quotes if present) - # We use __setstate__ instead of the public set() API because it allows us to - # bypass validation and set already validated state. This is more stable than - # setting protected attributes directly and unlikely to change since it would - # break pickling. - morsel.__setstate__( # type: ignore[attr-defined] - {"key": key, "value": _unquote(value), "coded_value": value} - ) - - cookies.append((key, morsel)) - - if invalid_names: - internal_logger.debug( - "Cannot load cookie. Illegal cookie names: %r", invalid_names - ) - - return cookies - - -def parse_set_cookie_headers(headers: Sequence[str]) -> List[Tuple[str, Morsel[str]]]: - """ - Parse cookie headers using a vendored version of SimpleCookie parsing. - - This implementation is based on SimpleCookie.__parse_string to ensure - compatibility with how SimpleCookie parses cookies, including handling - of malformed cookies with missing semicolons. - - This function is used for both Cookie and Set-Cookie headers in order to be - forgiving. Ideally we would have followed RFC 6265 Section 5.2 (for Cookie - headers) and RFC 6265 Section 4.2.1 (for Set-Cookie headers), but the - real world data makes it impossible since we need to be a bit more forgiving. - - NOTE: This implementation differs from SimpleCookie in handling unmatched quotes. - SimpleCookie will stop parsing when it encounters a cookie value with an unmatched - quote (e.g., 'cookie="value'), causing subsequent cookies to be silently dropped. - This implementation handles unmatched quotes more gracefully to prevent cookie loss. - See https://github.com/aio-libs/aiohttp/issues/7993 - """ - parsed_cookies: List[Tuple[str, Morsel[str]]] = [] - - for header in headers: - if not header: - continue - - # Parse cookie string using SimpleCookie's algorithm - i = 0 - n = len(header) - current_morsel: Optional[Morsel[str]] = None - morsel_seen = False - - while 0 <= i < n: - # Start looking for a cookie - match = _COOKIE_PATTERN.match(header, i) - if not match: - # No more cookies - break - - key, value = match.group("key"), match.group("val") - i = match.end(0) - lower_key = key.lower() - - if key[0] == "$": - if not morsel_seen: - # We ignore attributes which pertain to the cookie - # mechanism as a whole, such as "$Version". - continue - # Process as attribute - if current_morsel is not None: - attr_lower_key = lower_key[1:] - if attr_lower_key in _COOKIE_KNOWN_ATTRS: - current_morsel[attr_lower_key] = value or "" - elif lower_key in _COOKIE_KNOWN_ATTRS: - if not morsel_seen: - # Invalid cookie string - attribute before cookie - break - if lower_key in _COOKIE_BOOL_ATTRS: - # Boolean attribute with any value should be True - if current_morsel is not None and current_morsel.isReservedKey(key): - current_morsel[lower_key] = True - elif value is None: - # Invalid cookie string - non-boolean attribute without value - break - elif current_morsel is not None: - # Regular attribute with value - current_morsel[lower_key] = _unquote(value) - elif value is not None: - # This is a cookie name=value pair - # Validate the name - if key in _COOKIE_KNOWN_ATTRS or not _COOKIE_NAME_RE.match(key): - internal_logger.warning( - "Can not load cookies: Illegal cookie name %r", key - ) - current_morsel = None - else: - # Create new morsel - current_morsel = Morsel() - # Preserve the original value as coded_value (with quotes if present) - # We use __setstate__ instead of the public set() API because it allows us to - # bypass validation and set already validated state. This is more stable than - # setting protected attributes directly and unlikely to change since it would - # break pickling. - current_morsel.__setstate__( # type: ignore[attr-defined] - {"key": key, "value": _unquote(value), "coded_value": value} - ) - parsed_cookies.append((key, current_morsel)) - morsel_seen = True - else: - # Invalid cookie string - no value for non-attribute - break - - return parsed_cookies diff --git a/venv/lib/python3.9/site-packages/aiohttp/_cparser.pxd b/venv/lib/python3.9/site-packages/aiohttp/_cparser.pxd deleted file mode 100644 index 1b3be6d..0000000 --- a/venv/lib/python3.9/site-packages/aiohttp/_cparser.pxd +++ /dev/null @@ -1,158 +0,0 @@ -from libc.stdint cimport int32_t, uint8_t, uint16_t, uint64_t - - -cdef extern from "llhttp.h": - - struct llhttp__internal_s: - int32_t _index - void* _span_pos0 - void* _span_cb0 - int32_t error - const char* reason - const char* error_pos - void* data - void* _current - uint64_t content_length - uint8_t type - uint8_t method - uint8_t http_major - uint8_t http_minor - uint8_t header_state - uint8_t lenient_flags - uint8_t upgrade - uint8_t finish - uint16_t flags - uint16_t status_code - void* settings - - ctypedef llhttp__internal_s llhttp__internal_t - ctypedef llhttp__internal_t llhttp_t - - ctypedef int (*llhttp_data_cb)(llhttp_t*, const char *at, size_t length) except -1 - ctypedef int (*llhttp_cb)(llhttp_t*) except -1 - - struct llhttp_settings_s: - llhttp_cb on_message_begin - llhttp_data_cb on_url - llhttp_data_cb on_status - llhttp_data_cb on_header_field - llhttp_data_cb on_header_value - llhttp_cb on_headers_complete - llhttp_data_cb on_body - llhttp_cb on_message_complete - llhttp_cb on_chunk_header - llhttp_cb on_chunk_complete - - llhttp_cb on_url_complete - llhttp_cb on_status_complete - llhttp_cb on_header_field_complete - llhttp_cb on_header_value_complete - - ctypedef llhttp_settings_s llhttp_settings_t - - enum llhttp_errno: - HPE_OK, - HPE_INTERNAL, - HPE_STRICT, - HPE_LF_EXPECTED, - HPE_UNEXPECTED_CONTENT_LENGTH, - HPE_CLOSED_CONNECTION, - HPE_INVALID_METHOD, - HPE_INVALID_URL, - HPE_INVALID_CONSTANT, - HPE_INVALID_VERSION, - HPE_INVALID_HEADER_TOKEN, - HPE_INVALID_CONTENT_LENGTH, - HPE_INVALID_CHUNK_SIZE, - HPE_INVALID_STATUS, - HPE_INVALID_EOF_STATE, - HPE_INVALID_TRANSFER_ENCODING, - HPE_CB_MESSAGE_BEGIN, - HPE_CB_HEADERS_COMPLETE, - HPE_CB_MESSAGE_COMPLETE, - HPE_CB_CHUNK_HEADER, - HPE_CB_CHUNK_COMPLETE, - HPE_PAUSED, - HPE_PAUSED_UPGRADE, - HPE_USER - - ctypedef llhttp_errno llhttp_errno_t - - enum llhttp_flags: - F_CHUNKED, - F_CONTENT_LENGTH - - enum llhttp_type: - HTTP_REQUEST, - HTTP_RESPONSE, - HTTP_BOTH - - enum llhttp_method: - HTTP_DELETE, - HTTP_GET, - HTTP_HEAD, - HTTP_POST, - HTTP_PUT, - HTTP_CONNECT, - HTTP_OPTIONS, - HTTP_TRACE, - HTTP_COPY, - HTTP_LOCK, - HTTP_MKCOL, - HTTP_MOVE, - HTTP_PROPFIND, - HTTP_PROPPATCH, - HTTP_SEARCH, - HTTP_UNLOCK, - HTTP_BIND, - HTTP_REBIND, - HTTP_UNBIND, - HTTP_ACL, - HTTP_REPORT, - HTTP_MKACTIVITY, - HTTP_CHECKOUT, - HTTP_MERGE, - HTTP_MSEARCH, - HTTP_NOTIFY, - HTTP_SUBSCRIBE, - HTTP_UNSUBSCRIBE, - HTTP_PATCH, - HTTP_PURGE, - HTTP_MKCALENDAR, - HTTP_LINK, - HTTP_UNLINK, - HTTP_SOURCE, - HTTP_PRI, - HTTP_DESCRIBE, - HTTP_ANNOUNCE, - HTTP_SETUP, - HTTP_PLAY, - HTTP_PAUSE, - HTTP_TEARDOWN, - HTTP_GET_PARAMETER, - HTTP_SET_PARAMETER, - HTTP_REDIRECT, - HTTP_RECORD, - HTTP_FLUSH - - ctypedef llhttp_method llhttp_method_t; - - void llhttp_settings_init(llhttp_settings_t* settings) - void llhttp_init(llhttp_t* parser, llhttp_type type, - const llhttp_settings_t* settings) - - llhttp_errno_t llhttp_execute(llhttp_t* parser, const char* data, size_t len) - - int llhttp_should_keep_alive(const llhttp_t* parser) - - void llhttp_resume_after_upgrade(llhttp_t* parser) - - llhttp_errno_t llhttp_get_errno(const llhttp_t* parser) - const char* llhttp_get_error_reason(const llhttp_t* parser) - const char* llhttp_get_error_pos(const llhttp_t* parser) - - const char* llhttp_method_name(llhttp_method_t method) - - void llhttp_set_lenient_headers(llhttp_t* parser, int enabled) - void llhttp_set_lenient_optional_cr_before_lf(llhttp_t* parser, int enabled) - void llhttp_set_lenient_spaces_after_chunk_size(llhttp_t* parser, int enabled) diff --git a/venv/lib/python3.9/site-packages/aiohttp/_find_header.pxd b/venv/lib/python3.9/site-packages/aiohttp/_find_header.pxd deleted file mode 100644 index 37a6c37..0000000 --- a/venv/lib/python3.9/site-packages/aiohttp/_find_header.pxd +++ /dev/null @@ -1,2 +0,0 @@ -cdef extern from "_find_header.h": - int find_header(char *, int) diff --git a/venv/lib/python3.9/site-packages/aiohttp/_headers.pxi b/venv/lib/python3.9/site-packages/aiohttp/_headers.pxi deleted file mode 100644 index 3744721..0000000 --- a/venv/lib/python3.9/site-packages/aiohttp/_headers.pxi +++ /dev/null @@ -1,83 +0,0 @@ -# The file is autogenerated from aiohttp/hdrs.py -# Run ./tools/gen.py to update it after the origin changing. - -from . import hdrs -cdef tuple headers = ( - hdrs.ACCEPT, - hdrs.ACCEPT_CHARSET, - hdrs.ACCEPT_ENCODING, - hdrs.ACCEPT_LANGUAGE, - hdrs.ACCEPT_RANGES, - hdrs.ACCESS_CONTROL_ALLOW_CREDENTIALS, - hdrs.ACCESS_CONTROL_ALLOW_HEADERS, - hdrs.ACCESS_CONTROL_ALLOW_METHODS, - hdrs.ACCESS_CONTROL_ALLOW_ORIGIN, - hdrs.ACCESS_CONTROL_EXPOSE_HEADERS, - hdrs.ACCESS_CONTROL_MAX_AGE, - hdrs.ACCESS_CONTROL_REQUEST_HEADERS, - hdrs.ACCESS_CONTROL_REQUEST_METHOD, - hdrs.AGE, - hdrs.ALLOW, - hdrs.AUTHORIZATION, - hdrs.CACHE_CONTROL, - hdrs.CONNECTION, - hdrs.CONTENT_DISPOSITION, - hdrs.CONTENT_ENCODING, - hdrs.CONTENT_LANGUAGE, - hdrs.CONTENT_LENGTH, - hdrs.CONTENT_LOCATION, - hdrs.CONTENT_MD5, - hdrs.CONTENT_RANGE, - hdrs.CONTENT_TRANSFER_ENCODING, - hdrs.CONTENT_TYPE, - hdrs.COOKIE, - hdrs.DATE, - hdrs.DESTINATION, - hdrs.DIGEST, - hdrs.ETAG, - hdrs.EXPECT, - hdrs.EXPIRES, - hdrs.FORWARDED, - hdrs.FROM, - hdrs.HOST, - hdrs.IF_MATCH, - hdrs.IF_MODIFIED_SINCE, - hdrs.IF_NONE_MATCH, - hdrs.IF_RANGE, - hdrs.IF_UNMODIFIED_SINCE, - hdrs.KEEP_ALIVE, - hdrs.LAST_EVENT_ID, - hdrs.LAST_MODIFIED, - hdrs.LINK, - hdrs.LOCATION, - hdrs.MAX_FORWARDS, - hdrs.ORIGIN, - hdrs.PRAGMA, - hdrs.PROXY_AUTHENTICATE, - hdrs.PROXY_AUTHORIZATION, - hdrs.RANGE, - hdrs.REFERER, - hdrs.RETRY_AFTER, - hdrs.SEC_WEBSOCKET_ACCEPT, - hdrs.SEC_WEBSOCKET_EXTENSIONS, - hdrs.SEC_WEBSOCKET_KEY, - hdrs.SEC_WEBSOCKET_KEY1, - hdrs.SEC_WEBSOCKET_PROTOCOL, - hdrs.SEC_WEBSOCKET_VERSION, - hdrs.SERVER, - hdrs.SET_COOKIE, - hdrs.TE, - hdrs.TRAILER, - hdrs.TRANSFER_ENCODING, - hdrs.URI, - hdrs.UPGRADE, - hdrs.USER_AGENT, - hdrs.VARY, - hdrs.VIA, - hdrs.WWW_AUTHENTICATE, - hdrs.WANT_DIGEST, - hdrs.WARNING, - hdrs.X_FORWARDED_FOR, - hdrs.X_FORWARDED_HOST, - hdrs.X_FORWARDED_PROTO, -) diff --git a/venv/lib/python3.9/site-packages/aiohttp/_http_parser.cpython-39-x86_64-linux-gnu.so b/venv/lib/python3.9/site-packages/aiohttp/_http_parser.cpython-39-x86_64-linux-gnu.so deleted file mode 100755 index d360576..0000000 Binary files a/venv/lib/python3.9/site-packages/aiohttp/_http_parser.cpython-39-x86_64-linux-gnu.so and /dev/null differ diff --git a/venv/lib/python3.9/site-packages/aiohttp/_http_parser.pyx b/venv/lib/python3.9/site-packages/aiohttp/_http_parser.pyx deleted file mode 100644 index 5da835b..0000000 --- a/venv/lib/python3.9/site-packages/aiohttp/_http_parser.pyx +++ /dev/null @@ -1,877 +0,0 @@ -# Based on https://github.com/MagicStack/httptools -# - -from cpython cimport ( - Py_buffer, - PyBUF_SIMPLE, - PyBuffer_Release, - PyBytes_AsString, - PyBytes_AsStringAndSize, - PyObject_GetBuffer, -) -from cpython.mem cimport PyMem_Free, PyMem_Malloc -from libc.limits cimport ULLONG_MAX -from libc.string cimport memcpy - -from multidict import CIMultiDict as _CIMultiDict, CIMultiDictProxy as _CIMultiDictProxy -from yarl import URL as _URL - -from aiohttp import hdrs -from aiohttp.helpers import DEBUG, set_exception - -from .http_exceptions import ( - BadHttpMessage, - BadHttpMethod, - BadStatusLine, - ContentLengthError, - InvalidHeader, - InvalidURLError, - LineTooLong, - PayloadEncodingError, - TransferEncodingError, -) -from .http_parser import DeflateBuffer as _DeflateBuffer -from .http_writer import ( - HttpVersion as _HttpVersion, - HttpVersion10 as _HttpVersion10, - HttpVersion11 as _HttpVersion11, -) -from .streams import EMPTY_PAYLOAD as _EMPTY_PAYLOAD, StreamReader as _StreamReader - -cimport cython - -from aiohttp cimport _cparser as cparser - -include "_headers.pxi" - -from aiohttp cimport _find_header - -ALLOWED_UPGRADES = frozenset({"websocket"}) -DEF DEFAULT_FREELIST_SIZE = 250 - -cdef extern from "Python.h": - int PyByteArray_Resize(object, Py_ssize_t) except -1 - Py_ssize_t PyByteArray_Size(object) except -1 - char* PyByteArray_AsString(object) - -__all__ = ('HttpRequestParser', 'HttpResponseParser', - 'RawRequestMessage', 'RawResponseMessage') - -cdef object URL = _URL -cdef object URL_build = URL.build -cdef object CIMultiDict = _CIMultiDict -cdef object CIMultiDictProxy = _CIMultiDictProxy -cdef object HttpVersion = _HttpVersion -cdef object HttpVersion10 = _HttpVersion10 -cdef object HttpVersion11 = _HttpVersion11 -cdef object SEC_WEBSOCKET_KEY1 = hdrs.SEC_WEBSOCKET_KEY1 -cdef object CONTENT_ENCODING = hdrs.CONTENT_ENCODING -cdef object EMPTY_PAYLOAD = _EMPTY_PAYLOAD -cdef object StreamReader = _StreamReader -cdef object DeflateBuffer = _DeflateBuffer -cdef bytes EMPTY_BYTES = b"" - -# RFC 9110 singleton headers — duplicates are rejected in strict mode. -# In lax mode (response parser default), the check is skipped entirely -# since real-world servers (e.g. Google APIs, Werkzeug) commonly send -# duplicate headers like Content-Type or Server. -cdef frozenset SINGLETON_HEADERS = frozenset({ - hdrs.CONTENT_LENGTH, - hdrs.CONTENT_LOCATION, - hdrs.CONTENT_RANGE, - hdrs.CONTENT_TYPE, - hdrs.ETAG, - hdrs.HOST, - hdrs.MAX_FORWARDS, - hdrs.SERVER, - hdrs.TRANSFER_ENCODING, - hdrs.USER_AGENT, -}) - -cdef inline object extend(object buf, const char* at, size_t length): - cdef Py_ssize_t s - cdef char* ptr - s = PyByteArray_Size(buf) - PyByteArray_Resize(buf, s + length) - ptr = PyByteArray_AsString(buf) - memcpy(ptr + s, at, length) - - -DEF METHODS_COUNT = 46; - -cdef list _http_method = [] - -for i in range(METHODS_COUNT): - _http_method.append( - cparser.llhttp_method_name( i).decode('ascii')) - - -cdef inline str http_method_str(int i): - if i < METHODS_COUNT: - return _http_method[i] - else: - return "" - -cdef inline object find_header(bytes raw_header): - cdef Py_ssize_t size - cdef char *buf - cdef int idx - PyBytes_AsStringAndSize(raw_header, &buf, &size) - idx = _find_header.find_header(buf, size) - if idx == -1: - return raw_header.decode('utf-8', 'surrogateescape') - return headers[idx] - - -@cython.freelist(DEFAULT_FREELIST_SIZE) -cdef class RawRequestMessage: - cdef readonly str method - cdef readonly str path - cdef readonly object version # HttpVersion - cdef readonly object headers # CIMultiDict - cdef readonly object raw_headers # tuple - cdef readonly object should_close - cdef readonly object compression - cdef readonly object upgrade - cdef readonly object chunked - cdef readonly object url # yarl.URL - - def __init__(self, method, path, version, headers, raw_headers, - should_close, compression, upgrade, chunked, url): - self.method = method - self.path = path - self.version = version - self.headers = headers - self.raw_headers = raw_headers - self.should_close = should_close - self.compression = compression - self.upgrade = upgrade - self.chunked = chunked - self.url = url - - def __repr__(self): - info = [] - info.append(("method", self.method)) - info.append(("path", self.path)) - info.append(("version", self.version)) - info.append(("headers", self.headers)) - info.append(("raw_headers", self.raw_headers)) - info.append(("should_close", self.should_close)) - info.append(("compression", self.compression)) - info.append(("upgrade", self.upgrade)) - info.append(("chunked", self.chunked)) - info.append(("url", self.url)) - sinfo = ', '.join(name + '=' + repr(val) for name, val in info) - return '' - - def _replace(self, **dct): - cdef RawRequestMessage ret - ret = _new_request_message(self.method, - self.path, - self.version, - self.headers, - self.raw_headers, - self.should_close, - self.compression, - self.upgrade, - self.chunked, - self.url) - if "method" in dct: - ret.method = dct["method"] - if "path" in dct: - ret.path = dct["path"] - if "version" in dct: - ret.version = dct["version"] - if "headers" in dct: - ret.headers = dct["headers"] - if "raw_headers" in dct: - ret.raw_headers = dct["raw_headers"] - if "should_close" in dct: - ret.should_close = dct["should_close"] - if "compression" in dct: - ret.compression = dct["compression"] - if "upgrade" in dct: - ret.upgrade = dct["upgrade"] - if "chunked" in dct: - ret.chunked = dct["chunked"] - if "url" in dct: - ret.url = dct["url"] - return ret - -cdef _new_request_message(str method, - str path, - object version, - object headers, - object raw_headers, - bint should_close, - object compression, - bint upgrade, - bint chunked, - object url): - cdef RawRequestMessage ret - ret = RawRequestMessage.__new__(RawRequestMessage) - ret.method = method - ret.path = path - ret.version = version - ret.headers = headers - ret.raw_headers = raw_headers - ret.should_close = should_close - ret.compression = compression - ret.upgrade = upgrade - ret.chunked = chunked - ret.url = url - return ret - - -@cython.freelist(DEFAULT_FREELIST_SIZE) -cdef class RawResponseMessage: - cdef readonly object version # HttpVersion - cdef readonly int code - cdef readonly str reason - cdef readonly object headers # CIMultiDict - cdef readonly object raw_headers # tuple - cdef readonly object should_close - cdef readonly object compression - cdef readonly object upgrade - cdef readonly object chunked - - def __init__(self, version, code, reason, headers, raw_headers, - should_close, compression, upgrade, chunked): - self.version = version - self.code = code - self.reason = reason - self.headers = headers - self.raw_headers = raw_headers - self.should_close = should_close - self.compression = compression - self.upgrade = upgrade - self.chunked = chunked - - def __repr__(self): - info = [] - info.append(("version", self.version)) - info.append(("code", self.code)) - info.append(("reason", self.reason)) - info.append(("headers", self.headers)) - info.append(("raw_headers", self.raw_headers)) - info.append(("should_close", self.should_close)) - info.append(("compression", self.compression)) - info.append(("upgrade", self.upgrade)) - info.append(("chunked", self.chunked)) - sinfo = ', '.join(name + '=' + repr(val) for name, val in info) - return '' - - -cdef _new_response_message(object version, - int code, - str reason, - object headers, - object raw_headers, - bint should_close, - object compression, - bint upgrade, - bint chunked): - cdef RawResponseMessage ret - ret = RawResponseMessage.__new__(RawResponseMessage) - ret.version = version - ret.code = code - ret.reason = reason - ret.headers = headers - ret.raw_headers = raw_headers - ret.should_close = should_close - ret.compression = compression - ret.upgrade = upgrade - ret.chunked = chunked - return ret - - -@cython.internal -cdef class HttpParser: - - cdef: - cparser.llhttp_t* _cparser - cparser.llhttp_settings_t* _csettings - - bytes _raw_name - object _name - bytes _raw_value - bint _has_value - int _header_name_size - - object _protocol - object _loop - object _timer - - size_t _max_line_size - size_t _max_field_size - size_t _max_headers - bint _response_with_body - bint _read_until_eof - bint _lax - - bint _started - object _url - bytearray _buf - str _path - str _reason - list _headers - set _seen_singletons - list _raw_headers - bint _upgraded - list _messages - object _payload - bint _payload_error - object _payload_exception - object _last_error - bint _auto_decompress - int _limit - - str _content_encoding - - Py_buffer py_buf - - def __cinit__(self): - self._cparser = \ - PyMem_Malloc(sizeof(cparser.llhttp_t)) - if self._cparser is NULL: - raise MemoryError() - - self._csettings = \ - PyMem_Malloc(sizeof(cparser.llhttp_settings_t)) - if self._csettings is NULL: - raise MemoryError() - - def __dealloc__(self): - PyMem_Free(self._cparser) - PyMem_Free(self._csettings) - - cdef _init( - self, cparser.llhttp_type mode, - object protocol, object loop, int limit, - object timer=None, - size_t max_line_size=8190, size_t max_headers=128, - size_t max_field_size=8190, payload_exception=None, - bint response_with_body=True, bint read_until_eof=False, - bint auto_decompress=True, - ): - cparser.llhttp_settings_init(self._csettings) - cparser.llhttp_init(self._cparser, mode, self._csettings) - self._cparser.data = self - self._cparser.content_length = 0 - - self._protocol = protocol - self._loop = loop - self._timer = timer - - self._buf = bytearray() - self._payload = None - self._payload_error = 0 - self._payload_exception = payload_exception - self._messages = [] - - self._raw_name = EMPTY_BYTES - self._raw_value = EMPTY_BYTES - self._has_value = False - self._header_name_size = 0 - - self._max_line_size = max_line_size - self._max_headers = max_headers - self._max_field_size = max_field_size - self._response_with_body = response_with_body - self._read_until_eof = read_until_eof - self._upgraded = False - self._auto_decompress = auto_decompress - self._content_encoding = None - self._lax = False - self._seen_singletons = set() - - self._csettings.on_url = cb_on_url - self._csettings.on_status = cb_on_status - self._csettings.on_header_field = cb_on_header_field - self._csettings.on_header_value = cb_on_header_value - self._csettings.on_headers_complete = cb_on_headers_complete - self._csettings.on_body = cb_on_body - self._csettings.on_message_begin = cb_on_message_begin - self._csettings.on_message_complete = cb_on_message_complete - self._csettings.on_chunk_header = cb_on_chunk_header - self._csettings.on_chunk_complete = cb_on_chunk_complete - - self._last_error = None - self._limit = limit - - cdef _process_header(self): - cdef str value - if self._raw_name is not EMPTY_BYTES: - name = find_header(self._raw_name) - value = self._raw_value.decode('utf-8', 'surrogateescape') - - # reject null bytes in header values - matches the Python parser - # check at http_parser.py. llhttp in lenient mode doesn't reject - # these itself, so we need to catch them here. - # ref: RFC 9110 section 5.5 (CTL chars forbidden in field values) - if "\x00" in value: - raise InvalidHeader(self._raw_value) - - if not self._lax and name in SINGLETON_HEADERS: - if name in self._seen_singletons: - raise BadHttpMessage(f"Duplicate '{name}' header found.") - self._seen_singletons.add(name) - self._headers.append((name, value)) - if len(self._headers) > self._max_headers: - raise BadHttpMessage("Too many headers received") - - if name is CONTENT_ENCODING: - self._content_encoding = value - - self._has_value = False - self._header_name_size = 0 - self._raw_headers.append((self._raw_name, self._raw_value)) - self._raw_name = EMPTY_BYTES - self._raw_value = EMPTY_BYTES - - cdef _on_header_field(self, char* at, size_t length): - if self._has_value: - self._process_header() - - if self._raw_name is EMPTY_BYTES: - self._raw_name = at[:length] - else: - self._raw_name += at[:length] - - cdef _on_header_value(self, char* at, size_t length): - if self._raw_value is EMPTY_BYTES: - self._raw_value = at[:length] - else: - self._raw_value += at[:length] - self._has_value = True - - cdef _on_headers_complete(self): - self._process_header() - - should_close = not cparser.llhttp_should_keep_alive(self._cparser) - upgrade = self._cparser.upgrade - chunked = self._cparser.flags & cparser.F_CHUNKED - - raw_headers = tuple(self._raw_headers) - headers = CIMultiDictProxy(CIMultiDict(self._headers)) - - if self._cparser.type == cparser.HTTP_REQUEST: - h_upg = headers.get("upgrade", "") - allowed = upgrade and h_upg.isascii() and h_upg.lower() in ALLOWED_UPGRADES - if allowed or self._cparser.method == cparser.HTTP_CONNECT: - self._upgraded = True - else: - if upgrade and self._cparser.status_code == 101: - self._upgraded = True - - # do not support old websocket spec - if SEC_WEBSOCKET_KEY1 in headers: - raise InvalidHeader(SEC_WEBSOCKET_KEY1) - - encoding = None - enc = self._content_encoding - if enc is not None: - self._content_encoding = None - if enc.isascii() and enc.lower() in {"gzip", "deflate", "br", "zstd"}: - encoding = enc - - if self._cparser.type == cparser.HTTP_REQUEST: - method = http_method_str(self._cparser.method) - msg = _new_request_message( - method, self._path, - self.http_version(), headers, raw_headers, - should_close, encoding, upgrade, chunked, self._url) - else: - msg = _new_response_message( - self.http_version(), self._cparser.status_code, self._reason, - headers, raw_headers, should_close, encoding, - upgrade, chunked) - - if ( - ULLONG_MAX > self._cparser.content_length > 0 or chunked or - self._cparser.method == cparser.HTTP_CONNECT or - (self._cparser.status_code >= 199 and - self._cparser.content_length == 0 and - self._read_until_eof) - ): - payload = StreamReader( - self._protocol, timer=self._timer, loop=self._loop, - limit=self._limit) - else: - payload = EMPTY_PAYLOAD - - self._payload = payload - if encoding is not None and self._auto_decompress: - self._payload = DeflateBuffer(payload, encoding) - - if not self._response_with_body: - payload = EMPTY_PAYLOAD - - self._messages.append((msg, payload)) - - cdef _on_message_complete(self): - self._payload.feed_eof() - self._payload = None - - cdef _on_chunk_header(self): - self._payload.begin_http_chunk_receiving() - - cdef _on_chunk_complete(self): - self._payload.end_http_chunk_receiving() - - cdef object _on_status_complete(self): - pass - - cdef inline http_version(self): - cdef cparser.llhttp_t* parser = self._cparser - - if parser.http_major == 1: - if parser.http_minor == 0: - return HttpVersion10 - elif parser.http_minor == 1: - return HttpVersion11 - - return HttpVersion(parser.http_major, parser.http_minor) - - ### Public API ### - - def feed_eof(self): - cdef bytes desc - - if self._payload is not None: - if self._cparser.flags & cparser.F_CHUNKED: - raise TransferEncodingError( - "Not enough data to satisfy transfer length header.") - elif self._cparser.flags & cparser.F_CONTENT_LENGTH: - raise ContentLengthError( - "Not enough data to satisfy content length header.") - elif cparser.llhttp_get_errno(self._cparser) != cparser.HPE_OK: - desc = cparser.llhttp_get_error_reason(self._cparser) - raise PayloadEncodingError(desc.decode('latin-1')) - else: - self._payload.feed_eof() - elif self._started: - self._on_headers_complete() - if self._messages: - return self._messages[-1][0] - - def feed_data(self, data): - cdef: - size_t data_len - size_t nb - char* base - cdef cparser.llhttp_errno_t errno - - PyObject_GetBuffer(data, &self.py_buf, PyBUF_SIMPLE) - # Cache buffer pointer before PyBuffer_Release to avoid use-after-release. - base = self.py_buf.buf - data_len = self.py_buf.len - - errno = cparser.llhttp_execute( - self._cparser, - base, - data_len) - - if errno is cparser.HPE_PAUSED_UPGRADE: - cparser.llhttp_resume_after_upgrade(self._cparser) - - nb = cparser.llhttp_get_error_pos(self._cparser) - base - - PyBuffer_Release(&self.py_buf) - - if errno not in (cparser.HPE_OK, cparser.HPE_PAUSED_UPGRADE): - if self._payload_error == 0: - if self._last_error is not None: - ex = self._last_error - self._last_error = None - else: - after = cparser.llhttp_get_error_pos(self._cparser) - before = data[:after - base] - after_b = after.split(b"\r\n", 1)[0] - before = before.rsplit(b"\r\n", 1)[-1] - data = before + after_b - pointer = " " * (len(repr(before))-1) + "^" - ex = parser_error_from_errno(self._cparser, data, pointer) - self._payload = None - raise ex - - if self._messages: - messages = self._messages - self._messages = [] - else: - messages = () - - if self._upgraded: - return messages, True, data[nb:] - else: - return messages, False, b"" - - def set_upgraded(self, val): - self._upgraded = val - - -cdef class HttpRequestParser(HttpParser): - - def __init__( - self, protocol, loop, int limit, timer=None, - size_t max_line_size=8190, size_t max_headers=128, - size_t max_field_size=8190, payload_exception=None, - bint response_with_body=True, bint read_until_eof=False, - bint auto_decompress=True, - ): - self._init(cparser.HTTP_REQUEST, protocol, loop, limit, timer, - max_line_size, max_headers, max_field_size, - payload_exception, response_with_body, read_until_eof, - auto_decompress) - - cdef object _on_status_complete(self): - cdef int idx1, idx2 - if not self._buf: - return - self._path = self._buf.decode('utf-8', 'surrogateescape') - try: - idx3 = len(self._path) - if self._cparser.method == cparser.HTTP_CONNECT: - # authority-form, - # https://datatracker.ietf.org/doc/html/rfc7230#section-5.3.3 - self._url = URL.build(authority=self._path, encoded=True) - elif idx3 > 1 and self._path[0] == '/': - # origin-form, - # https://datatracker.ietf.org/doc/html/rfc7230#section-5.3.1 - idx1 = self._path.find("?") - if idx1 == -1: - query = "" - idx2 = self._path.find("#") - if idx2 == -1: - path = self._path - fragment = "" - else: - path = self._path[0: idx2] - fragment = self._path[idx2+1:] - - else: - path = self._path[0:idx1] - idx1 += 1 - idx2 = self._path.find("#", idx1+1) - if idx2 == -1: - query = self._path[idx1:] - fragment = "" - else: - query = self._path[idx1: idx2] - fragment = self._path[idx2+1:] - - self._url = URL.build( - path=path, - query_string=query, - fragment=fragment, - encoded=True, - ) - else: - # absolute-form for proxy maybe, - # https://datatracker.ietf.org/doc/html/rfc7230#section-5.3.2 - self._url = URL(self._path, encoded=True) - finally: - PyByteArray_Resize(self._buf, 0) - - -cdef class HttpResponseParser(HttpParser): - - def __init__( - self, protocol, loop, int limit, timer=None, - size_t max_line_size=8190, size_t max_headers=128, - size_t max_field_size=8190, payload_exception=None, - bint response_with_body=True, bint read_until_eof=False, - bint auto_decompress=True - ): - self._init(cparser.HTTP_RESPONSE, protocol, loop, limit, timer, - max_line_size, max_headers, max_field_size, - payload_exception, response_with_body, read_until_eof, - auto_decompress) - # Use strict parsing on dev mode, so users are warned about broken servers. - if not DEBUG: - cparser.llhttp_set_lenient_headers(self._cparser, 1) - cparser.llhttp_set_lenient_optional_cr_before_lf(self._cparser, 1) - cparser.llhttp_set_lenient_spaces_after_chunk_size(self._cparser, 1) - self._lax = True - - cdef object _on_status_complete(self): - if self._buf: - self._reason = self._buf.decode('utf-8', 'surrogateescape') - PyByteArray_Resize(self._buf, 0) - else: - self._reason = self._reason or '' - -cdef int cb_on_message_begin(cparser.llhttp_t* parser) except -1: - cdef HttpParser pyparser = parser.data - - pyparser._started = True - pyparser._headers = [] - pyparser._seen_singletons = set() - pyparser._raw_headers = [] - PyByteArray_Resize(pyparser._buf, 0) - pyparser._path = None - pyparser._reason = None - return 0 - - -cdef int cb_on_url(cparser.llhttp_t* parser, - const char *at, size_t length) except -1: - cdef HttpParser pyparser = parser.data - try: - if length > pyparser._max_line_size: - status = pyparser._buf + at[:length] - raise LineTooLong(status[:100] + b"...", pyparser._max_line_size) - extend(pyparser._buf, at, length) - except BaseException as ex: - pyparser._last_error = ex - return -1 - else: - return 0 - - -cdef int cb_on_status(cparser.llhttp_t* parser, - const char *at, size_t length) except -1: - cdef HttpParser pyparser = parser.data - try: - if length > pyparser._max_line_size: - reason = pyparser._buf + at[:length] - raise LineTooLong(reason[:100] + b"...", pyparser._max_line_size) - extend(pyparser._buf, at, length) - except BaseException as ex: - pyparser._last_error = ex - return -1 - else: - return 0 - - -cdef int cb_on_header_field(cparser.llhttp_t* parser, - const char *at, size_t length) except -1: - cdef HttpParser pyparser = parser.data - cdef Py_ssize_t size - try: - pyparser._on_status_complete() - size = len(pyparser._raw_name) + length - if size > pyparser._max_field_size: - name = pyparser._raw_name + at[:length] - raise LineTooLong(name[:100] + b"...", pyparser._max_field_size) - pyparser._header_name_size = size - pyparser._on_header_field(at, length) - except BaseException as ex: - pyparser._last_error = ex - return -1 - else: - return 0 - - -cdef int cb_on_header_value(cparser.llhttp_t* parser, - const char *at, size_t length) except -1: - cdef HttpParser pyparser = parser.data - cdef Py_ssize_t size - try: - size = len(pyparser._raw_value) + length - if pyparser._header_name_size + size > pyparser._max_field_size: - value = pyparser._raw_value + at[:length] - raise LineTooLong(value[:100] + b"...", pyparser._max_field_size) - pyparser._on_header_value(at, length) - except BaseException as ex: - pyparser._last_error = ex - return -1 - else: - return 0 - - -cdef int cb_on_headers_complete(cparser.llhttp_t* parser) except -1: - cdef HttpParser pyparser = parser.data - try: - pyparser._on_status_complete() - pyparser._on_headers_complete() - except BaseException as exc: - pyparser._last_error = exc - return -1 - else: - if pyparser._upgraded or pyparser._cparser.method == cparser.HTTP_CONNECT: - return 2 - else: - return 0 - - -cdef int cb_on_body(cparser.llhttp_t* parser, - const char *at, size_t length) except -1: - cdef HttpParser pyparser = parser.data - cdef bytes body = at[:length] - try: - pyparser._payload.feed_data(body, length) - except BaseException as underlying_exc: - reraised_exc = underlying_exc - if pyparser._payload_exception is not None: - reraised_exc = pyparser._payload_exception(str(underlying_exc)) - - set_exception(pyparser._payload, reraised_exc, underlying_exc) - - pyparser._payload_error = 1 - return -1 - else: - return 0 - - -cdef int cb_on_message_complete(cparser.llhttp_t* parser) except -1: - cdef HttpParser pyparser = parser.data - try: - pyparser._started = False - pyparser._on_message_complete() - except BaseException as exc: - pyparser._last_error = exc - return -1 - else: - return 0 - - -cdef int cb_on_chunk_header(cparser.llhttp_t* parser) except -1: - cdef HttpParser pyparser = parser.data - try: - pyparser._on_chunk_header() - except BaseException as exc: - pyparser._last_error = exc - return -1 - else: - return 0 - - -cdef int cb_on_chunk_complete(cparser.llhttp_t* parser) except -1: - cdef HttpParser pyparser = parser.data - try: - pyparser._on_chunk_complete() - except BaseException as exc: - pyparser._last_error = exc - return -1 - else: - return 0 - - -cdef parser_error_from_errno(cparser.llhttp_t* parser, data, pointer): - cdef cparser.llhttp_errno_t errno = cparser.llhttp_get_errno(parser) - cdef bytes desc = cparser.llhttp_get_error_reason(parser) - - err_msg = "{}:\n\n {!r}\n {}".format(desc.decode("latin-1"), data, pointer) - - if errno in {cparser.HPE_CB_MESSAGE_BEGIN, - cparser.HPE_CB_HEADERS_COMPLETE, - cparser.HPE_CB_MESSAGE_COMPLETE, - cparser.HPE_CB_CHUNK_HEADER, - cparser.HPE_CB_CHUNK_COMPLETE, - cparser.HPE_INVALID_CONSTANT, - cparser.HPE_INVALID_HEADER_TOKEN, - cparser.HPE_INVALID_CONTENT_LENGTH, - cparser.HPE_INVALID_CHUNK_SIZE, - cparser.HPE_INVALID_EOF_STATE, - cparser.HPE_INVALID_TRANSFER_ENCODING}: - return BadHttpMessage(err_msg) - elif errno == cparser.HPE_INVALID_METHOD: - return BadHttpMethod(error=err_msg) - elif errno in {cparser.HPE_INVALID_STATUS, - cparser.HPE_INVALID_VERSION}: - return BadStatusLine(error=err_msg) - elif errno == cparser.HPE_INVALID_URL: - return InvalidURLError(err_msg) - - return BadHttpMessage(err_msg) diff --git a/venv/lib/python3.9/site-packages/aiohttp/_http_writer.cpython-39-x86_64-linux-gnu.so b/venv/lib/python3.9/site-packages/aiohttp/_http_writer.cpython-39-x86_64-linux-gnu.so deleted file mode 100755 index f49c306..0000000 Binary files a/venv/lib/python3.9/site-packages/aiohttp/_http_writer.cpython-39-x86_64-linux-gnu.so and /dev/null differ diff --git a/venv/lib/python3.9/site-packages/aiohttp/_http_writer.pyx b/venv/lib/python3.9/site-packages/aiohttp/_http_writer.pyx deleted file mode 100644 index ee8dcd7..0000000 --- a/venv/lib/python3.9/site-packages/aiohttp/_http_writer.pyx +++ /dev/null @@ -1,162 +0,0 @@ -from cpython.bytes cimport PyBytes_FromStringAndSize -from cpython.exc cimport PyErr_NoMemory -from cpython.mem cimport PyMem_Free, PyMem_Malloc, PyMem_Realloc -from cpython.object cimport PyObject_Str -from libc.stdint cimport uint8_t, uint64_t -from libc.string cimport memcpy - -from multidict import istr - -DEF BUF_SIZE = 16 * 1024 # 16KiB - -cdef object _istr = istr - - -# ----------------- writer --------------------------- - -cdef struct Writer: - char *buf - Py_ssize_t size - Py_ssize_t pos - bint heap_allocated - -cdef inline void _init_writer(Writer* writer, char *buf): - writer.buf = buf - writer.size = BUF_SIZE - writer.pos = 0 - writer.heap_allocated = 0 - - -cdef inline void _release_writer(Writer* writer): - if writer.heap_allocated: - PyMem_Free(writer.buf) - - -cdef inline int _write_byte(Writer* writer, uint8_t ch): - cdef char * buf - cdef Py_ssize_t size - - if writer.pos == writer.size: - # reallocate - size = writer.size + BUF_SIZE - if not writer.heap_allocated: - buf = PyMem_Malloc(size) - if buf == NULL: - PyErr_NoMemory() - return -1 - memcpy(buf, writer.buf, writer.size) - else: - buf = PyMem_Realloc(writer.buf, size) - if buf == NULL: - PyErr_NoMemory() - return -1 - writer.buf = buf - writer.size = size - writer.heap_allocated = 1 - writer.buf[writer.pos] = ch - writer.pos += 1 - return 0 - - -cdef inline int _write_utf8(Writer* writer, Py_UCS4 symbol): - cdef uint64_t utf = symbol - - if utf < 0x80: - return _write_byte(writer, utf) - elif utf < 0x800: - if _write_byte(writer, (0xc0 | (utf >> 6))) < 0: - return -1 - return _write_byte(writer, (0x80 | (utf & 0x3f))) - elif 0xD800 <= utf <= 0xDFFF: - # surogate pair, ignored - return 0 - elif utf < 0x10000: - if _write_byte(writer, (0xe0 | (utf >> 12))) < 0: - return -1 - if _write_byte(writer, (0x80 | ((utf >> 6) & 0x3f))) < 0: - return -1 - return _write_byte(writer, (0x80 | (utf & 0x3f))) - elif utf > 0x10FFFF: - # symbol is too large - return 0 - else: - if _write_byte(writer, (0xf0 | (utf >> 18))) < 0: - return -1 - if _write_byte(writer, - (0x80 | ((utf >> 12) & 0x3f))) < 0: - return -1 - if _write_byte(writer, - (0x80 | ((utf >> 6) & 0x3f))) < 0: - return -1 - return _write_byte(writer, (0x80 | (utf & 0x3f))) - - -cdef inline int _write_str(Writer* writer, str s): - cdef Py_UCS4 ch - for ch in s: - if _write_utf8(writer, ch) < 0: - return -1 - - -cdef inline int _write_str_raise_on_nlcr(Writer* writer, object s): - cdef Py_UCS4 ch - cdef str out_str - if type(s) is str: - out_str = s - elif type(s) is _istr: - out_str = PyObject_Str(s) - elif not isinstance(s, str): - raise TypeError("Cannot serialize non-str key {!r}".format(s)) - else: - out_str = str(s) - - for ch in out_str: - if ch in {0x0D, 0x0A, 0x00}: - raise ValueError( - "Newline, carriage return, or null byte detected in headers. " - "Potential header injection attack." - ) - if _write_utf8(writer, ch) < 0: - return -1 - - -# --------------- _serialize_headers ---------------------- - -def _serialize_headers(str status_line, headers): - cdef Writer writer - cdef object key - cdef object val - cdef char buf[BUF_SIZE] - - _init_writer(&writer, buf) - - try: - if _write_str_raise_on_nlcr(&writer, status_line) < 0: - raise - if _write_byte(&writer, b'\r') < 0: - raise - if _write_byte(&writer, b'\n') < 0: - raise - - for key, val in headers.items(): - if _write_str_raise_on_nlcr(&writer, key) < 0: - raise - if _write_byte(&writer, b':') < 0: - raise - if _write_byte(&writer, b' ') < 0: - raise - if _write_str_raise_on_nlcr(&writer, val) < 0: - raise - if _write_byte(&writer, b'\r') < 0: - raise - if _write_byte(&writer, b'\n') < 0: - raise - - if _write_byte(&writer, b'\r') < 0: - raise - if _write_byte(&writer, b'\n') < 0: - raise - - return PyBytes_FromStringAndSize(writer.buf, writer.pos) - finally: - _release_writer(&writer) diff --git a/venv/lib/python3.9/site-packages/aiohttp/_websocket/.hash/mask.pxd.hash b/venv/lib/python3.9/site-packages/aiohttp/_websocket/.hash/mask.pxd.hash deleted file mode 100644 index eadfed3..0000000 --- a/venv/lib/python3.9/site-packages/aiohttp/_websocket/.hash/mask.pxd.hash +++ /dev/null @@ -1 +0,0 @@ -b01999d409b29bd916e067bc963d5f2d9ee63cfc9ae0bccb769910131417bf93 /home/runner/work/aiohttp/aiohttp/aiohttp/_websocket/mask.pxd diff --git a/venv/lib/python3.9/site-packages/aiohttp/_websocket/.hash/mask.pyx.hash b/venv/lib/python3.9/site-packages/aiohttp/_websocket/.hash/mask.pyx.hash deleted file mode 100644 index 5cd7ae6..0000000 --- a/venv/lib/python3.9/site-packages/aiohttp/_websocket/.hash/mask.pyx.hash +++ /dev/null @@ -1 +0,0 @@ -0478ceb55d0ed30ef1a7da742cd003449bc69a07cf9fdb06789bd2b347cbfffe /home/runner/work/aiohttp/aiohttp/aiohttp/_websocket/mask.pyx diff --git a/venv/lib/python3.9/site-packages/aiohttp/_websocket/.hash/reader_c.pxd.hash b/venv/lib/python3.9/site-packages/aiohttp/_websocket/.hash/reader_c.pxd.hash deleted file mode 100644 index f2feb6a..0000000 --- a/venv/lib/python3.9/site-packages/aiohttp/_websocket/.hash/reader_c.pxd.hash +++ /dev/null @@ -1 +0,0 @@ -9e5fe78ed0ebce5414d2b8e01868d90c1facc20b84d2d5ff6c23e86e44a155ae /home/runner/work/aiohttp/aiohttp/aiohttp/_websocket/reader_c.pxd diff --git a/venv/lib/python3.9/site-packages/aiohttp/_websocket/__init__.py b/venv/lib/python3.9/site-packages/aiohttp/_websocket/__init__.py deleted file mode 100644 index 836257c..0000000 --- a/venv/lib/python3.9/site-packages/aiohttp/_websocket/__init__.py +++ /dev/null @@ -1 +0,0 @@ -"""WebSocket protocol versions 13 and 8.""" diff --git a/venv/lib/python3.9/site-packages/aiohttp/_websocket/helpers.py b/venv/lib/python3.9/site-packages/aiohttp/_websocket/helpers.py deleted file mode 100644 index 0bb58df..0000000 --- a/venv/lib/python3.9/site-packages/aiohttp/_websocket/helpers.py +++ /dev/null @@ -1,147 +0,0 @@ -"""Helpers for WebSocket protocol versions 13 and 8.""" - -import functools -import re -from struct import Struct -from typing import TYPE_CHECKING, Final, List, Optional, Pattern, Tuple - -from ..helpers import NO_EXTENSIONS -from .models import WSHandshakeError - -UNPACK_LEN3 = Struct("!Q").unpack_from -UNPACK_CLOSE_CODE = Struct("!H").unpack -PACK_LEN1 = Struct("!BB").pack -PACK_LEN2 = Struct("!BBH").pack -PACK_LEN3 = Struct("!BBQ").pack -PACK_CLOSE_CODE = Struct("!H").pack -PACK_RANDBITS = Struct("!L").pack -MSG_SIZE: Final[int] = 2**14 -MASK_LEN: Final[int] = 4 - -WS_KEY: Final[bytes] = b"258EAFA5-E914-47DA-95CA-C5AB0DC85B11" - - -# Used by _websocket_mask_python -@functools.lru_cache -def _xor_table() -> List[bytes]: - return [bytes(a ^ b for a in range(256)) for b in range(256)] - - -def _websocket_mask_python(mask: bytes, data: bytearray) -> None: - """Websocket masking function. - - `mask` is a `bytes` object of length 4; `data` is a `bytearray` - object of any length. The contents of `data` are masked with `mask`, - as specified in section 5.3 of RFC 6455. - - Note that this function mutates the `data` argument. - - This pure-python implementation may be replaced by an optimized - version when available. - - """ - assert isinstance(data, bytearray), data - assert len(mask) == 4, mask - - if data: - _XOR_TABLE = _xor_table() - a, b, c, d = (_XOR_TABLE[n] for n in mask) - data[::4] = data[::4].translate(a) - data[1::4] = data[1::4].translate(b) - data[2::4] = data[2::4].translate(c) - data[3::4] = data[3::4].translate(d) - - -if TYPE_CHECKING or NO_EXTENSIONS: # pragma: no cover - websocket_mask = _websocket_mask_python -else: - try: - from .mask import _websocket_mask_cython # type: ignore[import-not-found] - - websocket_mask = _websocket_mask_cython - except ImportError: # pragma: no cover - websocket_mask = _websocket_mask_python - - -_WS_EXT_RE: Final[Pattern[str]] = re.compile( - r"^(?:;\s*(?:" - r"(server_no_context_takeover)|" - r"(client_no_context_takeover)|" - r"(server_max_window_bits(?:=(\d+))?)|" - r"(client_max_window_bits(?:=(\d+))?)))*$" -) - -_WS_EXT_RE_SPLIT: Final[Pattern[str]] = re.compile(r"permessage-deflate([^,]+)?") - - -def ws_ext_parse(extstr: Optional[str], isserver: bool = False) -> Tuple[int, bool]: - if not extstr: - return 0, False - - compress = 0 - notakeover = False - for ext in _WS_EXT_RE_SPLIT.finditer(extstr): - defext = ext.group(1) - # Return compress = 15 when get `permessage-deflate` - if not defext: - compress = 15 - break - match = _WS_EXT_RE.match(defext) - if match: - compress = 15 - if isserver: - # Server never fail to detect compress handshake. - # Server does not need to send max wbit to client - if match.group(4): - compress = int(match.group(4)) - # Group3 must match if group4 matches - # Compress wbit 8 does not support in zlib - # If compress level not support, - # CONTINUE to next extension - if compress > 15 or compress < 9: - compress = 0 - continue - if match.group(1): - notakeover = True - # Ignore regex group 5 & 6 for client_max_window_bits - break - else: - if match.group(6): - compress = int(match.group(6)) - # Group5 must match if group6 matches - # Compress wbit 8 does not support in zlib - # If compress level not support, - # FAIL the parse progress - if compress > 15 or compress < 9: - raise WSHandshakeError("Invalid window size") - if match.group(2): - notakeover = True - # Ignore regex group 5 & 6 for client_max_window_bits - break - # Return Fail if client side and not match - elif not isserver: - raise WSHandshakeError("Extension for deflate not supported" + ext.group(1)) - - return compress, notakeover - - -def ws_ext_gen( - compress: int = 15, isserver: bool = False, server_notakeover: bool = False -) -> str: - # client_notakeover=False not used for server - # compress wbit 8 does not support in zlib - if compress < 9 or compress > 15: - raise ValueError( - "Compress wbits must between 9 and 15, zlib does not support wbits=8" - ) - enabledext = ["permessage-deflate"] - if not isserver: - enabledext.append("client_max_window_bits") - - if compress < 15: - enabledext.append("server_max_window_bits=" + str(compress)) - if server_notakeover: - enabledext.append("server_no_context_takeover") - # if client_notakeover: - # enabledext.append('client_no_context_takeover') - return "; ".join(enabledext) diff --git a/venv/lib/python3.9/site-packages/aiohttp/_websocket/mask.cpython-39-x86_64-linux-gnu.so b/venv/lib/python3.9/site-packages/aiohttp/_websocket/mask.cpython-39-x86_64-linux-gnu.so deleted file mode 100755 index ceeba7f..0000000 Binary files a/venv/lib/python3.9/site-packages/aiohttp/_websocket/mask.cpython-39-x86_64-linux-gnu.so and /dev/null differ diff --git a/venv/lib/python3.9/site-packages/aiohttp/_websocket/mask.pxd b/venv/lib/python3.9/site-packages/aiohttp/_websocket/mask.pxd deleted file mode 100644 index 90983de..0000000 --- a/venv/lib/python3.9/site-packages/aiohttp/_websocket/mask.pxd +++ /dev/null @@ -1,3 +0,0 @@ -"""Cython declarations for websocket masking.""" - -cpdef void _websocket_mask_cython(bytes mask, bytearray data) diff --git a/venv/lib/python3.9/site-packages/aiohttp/_websocket/mask.pyx b/venv/lib/python3.9/site-packages/aiohttp/_websocket/mask.pyx deleted file mode 100644 index 2d956c8..0000000 --- a/venv/lib/python3.9/site-packages/aiohttp/_websocket/mask.pyx +++ /dev/null @@ -1,48 +0,0 @@ -from cpython cimport PyBytes_AsString - - -#from cpython cimport PyByteArray_AsString # cython still not exports that -cdef extern from "Python.h": - char* PyByteArray_AsString(bytearray ba) except NULL - -from libc.stdint cimport uint32_t, uint64_t, uintmax_t - - -cpdef void _websocket_mask_cython(bytes mask, bytearray data): - """Note, this function mutates its `data` argument - """ - cdef: - Py_ssize_t data_len, i - # bit operations on signed integers are implementation-specific - unsigned char * in_buf - const unsigned char * mask_buf - uint32_t uint32_msk - uint64_t uint64_msk - - assert len(mask) == 4 - - data_len = len(data) - in_buf = PyByteArray_AsString(data) - mask_buf = PyBytes_AsString(mask) - uint32_msk = (mask_buf)[0] - - # TODO: align in_data ptr to achieve even faster speeds - # does it need in python ?! malloc() always aligns to sizeof(long) bytes - - if sizeof(size_t) >= 8: - uint64_msk = uint32_msk - uint64_msk = (uint64_msk << 32) | uint32_msk - - while data_len >= 8: - (in_buf)[0] ^= uint64_msk - in_buf += 8 - data_len -= 8 - - - while data_len >= 4: - (in_buf)[0] ^= uint32_msk - in_buf += 4 - data_len -= 4 - - for i in range(0, data_len): - in_buf[i] ^= mask_buf[i] diff --git a/venv/lib/python3.9/site-packages/aiohttp/_websocket/models.py b/venv/lib/python3.9/site-packages/aiohttp/_websocket/models.py deleted file mode 100644 index 7e89b96..0000000 --- a/venv/lib/python3.9/site-packages/aiohttp/_websocket/models.py +++ /dev/null @@ -1,84 +0,0 @@ -"""Models for WebSocket protocol versions 13 and 8.""" - -import json -from enum import IntEnum -from typing import Any, Callable, Final, NamedTuple, Optional, cast - -WS_DEFLATE_TRAILING: Final[bytes] = bytes([0x00, 0x00, 0xFF, 0xFF]) - - -class WSCloseCode(IntEnum): - OK = 1000 - GOING_AWAY = 1001 - PROTOCOL_ERROR = 1002 - UNSUPPORTED_DATA = 1003 - ABNORMAL_CLOSURE = 1006 - INVALID_TEXT = 1007 - POLICY_VIOLATION = 1008 - MESSAGE_TOO_BIG = 1009 - MANDATORY_EXTENSION = 1010 - INTERNAL_ERROR = 1011 - SERVICE_RESTART = 1012 - TRY_AGAIN_LATER = 1013 - BAD_GATEWAY = 1014 - - -class WSMsgType(IntEnum): - # websocket spec types - CONTINUATION = 0x0 - TEXT = 0x1 - BINARY = 0x2 - PING = 0x9 - PONG = 0xA - CLOSE = 0x8 - - # aiohttp specific types - CLOSING = 0x100 - CLOSED = 0x101 - ERROR = 0x102 - - text = TEXT - binary = BINARY - ping = PING - pong = PONG - close = CLOSE - closing = CLOSING - closed = CLOSED - error = ERROR - - -class WSMessage(NamedTuple): - type: WSMsgType - # To type correctly, this would need some kind of tagged union for each type. - data: Any - extra: Optional[str] - - def json(self, *, loads: Callable[[Any], Any] = json.loads) -> Any: - """Return parsed JSON data. - - .. versionadded:: 0.22 - """ - return loads(self.data) - - -# Constructing the tuple directly to avoid the overhead of -# the lambda and arg processing since NamedTuples are constructed -# with a run time built lambda -# https://github.com/python/cpython/blob/d83fcf8371f2f33c7797bc8f5423a8bca8c46e5c/Lib/collections/__init__.py#L441 -WS_CLOSED_MESSAGE = tuple.__new__(WSMessage, (WSMsgType.CLOSED, None, None)) -WS_CLOSING_MESSAGE = tuple.__new__(WSMessage, (WSMsgType.CLOSING, None, None)) - - -class WebSocketError(Exception): - """WebSocket protocol parser error.""" - - def __init__(self, code: int, message: str) -> None: - self.code = code - super().__init__(code, message) - - def __str__(self) -> str: - return cast(str, self.args[1]) - - -class WSHandshakeError(Exception): - """WebSocket protocol handshake error.""" diff --git a/venv/lib/python3.9/site-packages/aiohttp/_websocket/reader.py b/venv/lib/python3.9/site-packages/aiohttp/_websocket/reader.py deleted file mode 100644 index 23f3226..0000000 --- a/venv/lib/python3.9/site-packages/aiohttp/_websocket/reader.py +++ /dev/null @@ -1,31 +0,0 @@ -"""Reader for WebSocket protocol versions 13 and 8.""" - -from typing import TYPE_CHECKING - -from ..helpers import NO_EXTENSIONS - -if TYPE_CHECKING or NO_EXTENSIONS: # pragma: no cover - from .reader_py import ( - WebSocketDataQueue as WebSocketDataQueuePython, - WebSocketReader as WebSocketReaderPython, - ) - - WebSocketReader = WebSocketReaderPython - WebSocketDataQueue = WebSocketDataQueuePython -else: - try: - from .reader_c import ( # type: ignore[import-not-found] - WebSocketDataQueue as WebSocketDataQueueCython, - WebSocketReader as WebSocketReaderCython, - ) - - WebSocketReader = WebSocketReaderCython - WebSocketDataQueue = WebSocketDataQueueCython - except ImportError: # pragma: no cover - from .reader_py import ( - WebSocketDataQueue as WebSocketDataQueuePython, - WebSocketReader as WebSocketReaderPython, - ) - - WebSocketReader = WebSocketReaderPython - WebSocketDataQueue = WebSocketDataQueuePython diff --git a/venv/lib/python3.9/site-packages/aiohttp/_websocket/reader_c.cpython-39-x86_64-linux-gnu.so b/venv/lib/python3.9/site-packages/aiohttp/_websocket/reader_c.cpython-39-x86_64-linux-gnu.so deleted file mode 100755 index 3826658..0000000 Binary files a/venv/lib/python3.9/site-packages/aiohttp/_websocket/reader_c.cpython-39-x86_64-linux-gnu.so and /dev/null differ diff --git a/venv/lib/python3.9/site-packages/aiohttp/_websocket/reader_c.pxd b/venv/lib/python3.9/site-packages/aiohttp/_websocket/reader_c.pxd deleted file mode 100644 index a7620d8..0000000 --- a/venv/lib/python3.9/site-packages/aiohttp/_websocket/reader_c.pxd +++ /dev/null @@ -1,110 +0,0 @@ -import cython - -from .mask cimport _websocket_mask_cython as websocket_mask - - -cdef unsigned int READ_HEADER -cdef unsigned int READ_PAYLOAD_LENGTH -cdef unsigned int READ_PAYLOAD_MASK -cdef unsigned int READ_PAYLOAD - -cdef int OP_CODE_NOT_SET -cdef int OP_CODE_CONTINUATION -cdef int OP_CODE_TEXT -cdef int OP_CODE_BINARY -cdef int OP_CODE_CLOSE -cdef int OP_CODE_PING -cdef int OP_CODE_PONG - -cdef int COMPRESSED_NOT_SET -cdef int COMPRESSED_FALSE -cdef int COMPRESSED_TRUE - -cdef object UNPACK_LEN3 -cdef object UNPACK_CLOSE_CODE -cdef object TUPLE_NEW - -cdef object WSMsgType -cdef object WSMessage - -cdef object WS_MSG_TYPE_TEXT -cdef object WS_MSG_TYPE_BINARY - -cdef set ALLOWED_CLOSE_CODES -cdef set MESSAGE_TYPES_WITH_CONTENT - -cdef tuple EMPTY_FRAME -cdef tuple EMPTY_FRAME_ERROR - -cdef class WebSocketDataQueue: - - cdef unsigned int _size - cdef public object _protocol - cdef unsigned int _limit - cdef object _loop - cdef bint _eof - cdef object _waiter - cdef object _exception - cdef public object _buffer - cdef object _get_buffer - cdef object _put_buffer - - cdef void _release_waiter(self) - - cpdef void feed_data(self, object data, unsigned int size) - - @cython.locals(size="unsigned int") - cdef _read_from_buffer(self) - -cdef class WebSocketReader: - - cdef WebSocketDataQueue queue - cdef unsigned int _max_msg_size - - cdef Exception _exc - cdef bytearray _partial - cdef unsigned int _state - - cdef int _opcode - cdef bint _frame_fin - cdef int _frame_opcode - cdef list _payload_fragments - cdef Py_ssize_t _frame_payload_len - - cdef bytes _tail - cdef bint _has_mask - cdef bytes _frame_mask - cdef Py_ssize_t _payload_bytes_to_read - cdef unsigned int _payload_len_flag - cdef int _compressed - cdef object _decompressobj - cdef bint _compress - - cpdef tuple feed_data(self, object data) - - @cython.locals( - is_continuation=bint, - fin=bint, - has_partial=bint, - payload_merged=bytes, - ) - cpdef void _handle_frame(self, bint fin, int opcode, object payload, int compressed) except * - - @cython.locals( - start_pos=Py_ssize_t, - data_len=Py_ssize_t, - length=Py_ssize_t, - chunk_size=Py_ssize_t, - chunk_len=Py_ssize_t, - data_len=Py_ssize_t, - data_cstr="const unsigned char *", - first_byte="unsigned char", - second_byte="unsigned char", - f_start_pos=Py_ssize_t, - f_end_pos=Py_ssize_t, - has_mask=bint, - fin=bint, - had_fragments=Py_ssize_t, - payload_bytearray=bytearray, - ) - cpdef void _feed_data(self, bytes data) except * diff --git a/venv/lib/python3.9/site-packages/aiohttp/_websocket/reader_c.py b/venv/lib/python3.9/site-packages/aiohttp/_websocket/reader_c.py deleted file mode 100644 index 5166d7e..0000000 --- a/venv/lib/python3.9/site-packages/aiohttp/_websocket/reader_c.py +++ /dev/null @@ -1,478 +0,0 @@ -"""Reader for WebSocket protocol versions 13 and 8.""" - -import asyncio -import builtins -from collections import deque -from typing import Deque, Final, Optional, Set, Tuple, Union - -from ..base_protocol import BaseProtocol -from ..compression_utils import ZLibDecompressor -from ..helpers import _EXC_SENTINEL, set_exception -from ..streams import EofStream -from .helpers import UNPACK_CLOSE_CODE, UNPACK_LEN3, websocket_mask -from .models import ( - WS_DEFLATE_TRAILING, - WebSocketError, - WSCloseCode, - WSMessage, - WSMsgType, -) - -ALLOWED_CLOSE_CODES: Final[Set[int]] = {int(i) for i in WSCloseCode} - -# States for the reader, used to parse the WebSocket frame -# integer values are used so they can be cythonized -READ_HEADER = 1 -READ_PAYLOAD_LENGTH = 2 -READ_PAYLOAD_MASK = 3 -READ_PAYLOAD = 4 - -WS_MSG_TYPE_BINARY = WSMsgType.BINARY -WS_MSG_TYPE_TEXT = WSMsgType.TEXT - -# WSMsgType values unpacked so they can by cythonized to ints -OP_CODE_NOT_SET = -1 -OP_CODE_CONTINUATION = WSMsgType.CONTINUATION.value -OP_CODE_TEXT = WSMsgType.TEXT.value -OP_CODE_BINARY = WSMsgType.BINARY.value -OP_CODE_CLOSE = WSMsgType.CLOSE.value -OP_CODE_PING = WSMsgType.PING.value -OP_CODE_PONG = WSMsgType.PONG.value - -EMPTY_FRAME_ERROR = (True, b"") -EMPTY_FRAME = (False, b"") - -COMPRESSED_NOT_SET = -1 -COMPRESSED_FALSE = 0 -COMPRESSED_TRUE = 1 - -TUPLE_NEW = tuple.__new__ - -cython_int = int # Typed to int in Python, but cython with use a signed int in the pxd - - -class WebSocketDataQueue: - """WebSocketDataQueue resumes and pauses an underlying stream. - - It is a destination for WebSocket data. - """ - - def __init__( - self, protocol: BaseProtocol, limit: int, *, loop: asyncio.AbstractEventLoop - ) -> None: - self._size = 0 - self._protocol = protocol - self._limit = limit * 2 - self._loop = loop - self._eof = False - self._waiter: Optional[asyncio.Future[None]] = None - self._exception: Union[BaseException, None] = None - self._buffer: Deque[Tuple[WSMessage, int]] = deque() - self._get_buffer = self._buffer.popleft - self._put_buffer = self._buffer.append - - def is_eof(self) -> bool: - return self._eof - - def exception(self) -> Optional[BaseException]: - return self._exception - - def set_exception( - self, - exc: BaseException, - exc_cause: builtins.BaseException = _EXC_SENTINEL, - ) -> None: - self._eof = True - self._exception = exc - if (waiter := self._waiter) is not None: - self._waiter = None - set_exception(waiter, exc, exc_cause) - - def _release_waiter(self) -> None: - if (waiter := self._waiter) is None: - return - self._waiter = None - if not waiter.done(): - waiter.set_result(None) - - def feed_eof(self) -> None: - self._eof = True - self._release_waiter() - self._exception = None # Break cyclic references - - def feed_data(self, data: "WSMessage", size: "cython_int") -> None: - self._size += size - self._put_buffer((data, size)) - self._release_waiter() - if self._size > self._limit and not self._protocol._reading_paused: - self._protocol.pause_reading() - - async def read(self) -> WSMessage: - if not self._buffer and not self._eof: - assert not self._waiter - self._waiter = self._loop.create_future() - try: - await self._waiter - except (asyncio.CancelledError, asyncio.TimeoutError): - self._waiter = None - raise - return self._read_from_buffer() - - def _read_from_buffer(self) -> WSMessage: - if self._buffer: - data, size = self._get_buffer() - self._size -= size - if self._size < self._limit and self._protocol._reading_paused: - self._protocol.resume_reading() - return data - if self._exception is not None: - raise self._exception - raise EofStream - - -class WebSocketReader: - def __init__( - self, queue: WebSocketDataQueue, max_msg_size: int, compress: bool = True - ) -> None: - self.queue = queue - self._max_msg_size = max_msg_size - - self._exc: Optional[Exception] = None - self._partial = bytearray() - self._state = READ_HEADER - - self._opcode: int = OP_CODE_NOT_SET - self._frame_fin = False - self._frame_opcode: int = OP_CODE_NOT_SET - self._payload_fragments: list[bytes] = [] - self._frame_payload_len = 0 - - self._tail: bytes = b"" - self._has_mask = False - self._frame_mask: Optional[bytes] = None - self._payload_bytes_to_read = 0 - self._payload_len_flag = 0 - self._compressed: int = COMPRESSED_NOT_SET - self._decompressobj: Optional[ZLibDecompressor] = None - self._compress = compress - - def feed_eof(self) -> None: - self.queue.feed_eof() - - # data can be bytearray on Windows because proactor event loop uses bytearray - # and asyncio types this to Union[bytes, bytearray, memoryview] so we need - # coerce data to bytes if it is not - def feed_data( - self, data: Union[bytes, bytearray, memoryview] - ) -> Tuple[bool, bytes]: - if type(data) is not bytes: - data = bytes(data) - - if self._exc is not None: - return True, data - - try: - self._feed_data(data) - except Exception as exc: - self._exc = exc - set_exception(self.queue, exc) - return EMPTY_FRAME_ERROR - - return EMPTY_FRAME - - def _handle_frame( - self, - fin: bool, - opcode: Union[int, cython_int], # Union intended: Cython pxd uses C int - payload: Union[bytes, bytearray], - compressed: Union[int, cython_int], # Union intended: Cython pxd uses C int - ) -> None: - msg: WSMessage - if opcode in {OP_CODE_TEXT, OP_CODE_BINARY, OP_CODE_CONTINUATION}: - # Validate continuation frames before processing - if opcode == OP_CODE_CONTINUATION and self._opcode == OP_CODE_NOT_SET: - raise WebSocketError( - WSCloseCode.PROTOCOL_ERROR, - "Continuation frame for non started message", - ) - - # load text/binary - if not fin: - # got partial frame payload - if opcode != OP_CODE_CONTINUATION: - self._opcode = opcode - self._partial += payload - if self._max_msg_size and len(self._partial) >= self._max_msg_size: - raise WebSocketError( - WSCloseCode.MESSAGE_TOO_BIG, - f"Message size {len(self._partial)} " - f"exceeds limit {self._max_msg_size}", - ) - return - - has_partial = bool(self._partial) - if opcode == OP_CODE_CONTINUATION: - opcode = self._opcode - self._opcode = OP_CODE_NOT_SET - # previous frame was non finished - # we should get continuation opcode - elif has_partial: - raise WebSocketError( - WSCloseCode.PROTOCOL_ERROR, - "The opcode in non-fin frame is expected " - f"to be zero, got {opcode!r}", - ) - - assembled_payload: Union[bytes, bytearray] - if has_partial: - assembled_payload = self._partial + payload - self._partial.clear() - else: - assembled_payload = payload - - if self._max_msg_size and len(assembled_payload) >= self._max_msg_size: - raise WebSocketError( - WSCloseCode.MESSAGE_TOO_BIG, - f"Message size {len(assembled_payload)} " - f"exceeds limit {self._max_msg_size}", - ) - - # Decompress process must to be done after all packets - # received. - if compressed: - if not self._decompressobj: - self._decompressobj = ZLibDecompressor(suppress_deflate_header=True) - # XXX: It's possible that the zlib backend (isal is known to - # do this, maybe others too?) will return max_length bytes, - # but internally buffer more data such that the payload is - # >max_length, so we return one extra byte and if we're able - # to do that, then the message is too big. - payload_merged = self._decompressobj.decompress_sync( - assembled_payload + WS_DEFLATE_TRAILING, - ( - self._max_msg_size + 1 - if self._max_msg_size - else self._max_msg_size - ), - ) - if self._max_msg_size and len(payload_merged) > self._max_msg_size: - raise WebSocketError( - WSCloseCode.MESSAGE_TOO_BIG, - f"Decompressed message exceeds size limit {self._max_msg_size}", - ) - elif type(assembled_payload) is bytes: - payload_merged = assembled_payload - else: - payload_merged = bytes(assembled_payload) - - if opcode == OP_CODE_TEXT: - try: - text = payload_merged.decode("utf-8") - except UnicodeDecodeError as exc: - raise WebSocketError( - WSCloseCode.INVALID_TEXT, "Invalid UTF-8 text message" - ) from exc - - # XXX: The Text and Binary messages here can be a performance - # bottleneck, so we use tuple.__new__ to improve performance. - # This is not type safe, but many tests should fail in - # test_client_ws_functional.py if this is wrong. - self.queue.feed_data( - TUPLE_NEW(WSMessage, (WS_MSG_TYPE_TEXT, text, "")), - len(payload_merged), - ) - else: - self.queue.feed_data( - TUPLE_NEW(WSMessage, (WS_MSG_TYPE_BINARY, payload_merged, "")), - len(payload_merged), - ) - elif opcode == OP_CODE_CLOSE: - if len(payload) >= 2: - close_code = UNPACK_CLOSE_CODE(payload[:2])[0] - if close_code < 3000 and close_code not in ALLOWED_CLOSE_CODES: - raise WebSocketError( - WSCloseCode.PROTOCOL_ERROR, - f"Invalid close code: {close_code}", - ) - try: - close_message = payload[2:].decode("utf-8") - except UnicodeDecodeError as exc: - raise WebSocketError( - WSCloseCode.INVALID_TEXT, "Invalid UTF-8 text message" - ) from exc - msg = TUPLE_NEW(WSMessage, (WSMsgType.CLOSE, close_code, close_message)) - elif payload: - raise WebSocketError( - WSCloseCode.PROTOCOL_ERROR, - f"Invalid close frame: {fin} {opcode} {payload!r}", - ) - else: - msg = TUPLE_NEW(WSMessage, (WSMsgType.CLOSE, 0, "")) - - self.queue.feed_data(msg, 0) - elif opcode == OP_CODE_PING: - msg = TUPLE_NEW(WSMessage, (WSMsgType.PING, payload, "")) - self.queue.feed_data(msg, len(payload)) - elif opcode == OP_CODE_PONG: - msg = TUPLE_NEW(WSMessage, (WSMsgType.PONG, payload, "")) - self.queue.feed_data(msg, len(payload)) - else: - raise WebSocketError( - WSCloseCode.PROTOCOL_ERROR, f"Unexpected opcode={opcode!r}" - ) - - def _feed_data(self, data: bytes) -> None: - """Return the next frame from the socket.""" - if self._tail: - data, self._tail = self._tail + data, b"" - - start_pos: int = 0 - data_len = len(data) - data_cstr = data - - while True: - # read header - if self._state == READ_HEADER: - if data_len - start_pos < 2: - break - first_byte = data_cstr[start_pos] - second_byte = data_cstr[start_pos + 1] - start_pos += 2 - - fin = (first_byte >> 7) & 1 - rsv1 = (first_byte >> 6) & 1 - rsv2 = (first_byte >> 5) & 1 - rsv3 = (first_byte >> 4) & 1 - opcode = first_byte & 0xF - - # frame-fin = %x0 ; more frames of this message follow - # / %x1 ; final frame of this message - # frame-rsv1 = %x0 ; - # 1 bit, MUST be 0 unless negotiated otherwise - # frame-rsv2 = %x0 ; - # 1 bit, MUST be 0 unless negotiated otherwise - # frame-rsv3 = %x0 ; - # 1 bit, MUST be 0 unless negotiated otherwise - # - # Remove rsv1 from this test for deflate development - if rsv2 or rsv3 or (rsv1 and not self._compress): - raise WebSocketError( - WSCloseCode.PROTOCOL_ERROR, - "Received frame with non-zero reserved bits", - ) - - if opcode > 0x7 and fin == 0: - raise WebSocketError( - WSCloseCode.PROTOCOL_ERROR, - "Received fragmented control frame", - ) - - has_mask = (second_byte >> 7) & 1 - length = second_byte & 0x7F - - # Control frames MUST have a payload - # length of 125 bytes or less - if opcode > 0x7 and length > 125: - raise WebSocketError( - WSCloseCode.PROTOCOL_ERROR, - "Control frame payload cannot be larger than 125 bytes", - ) - - # Set compress status if last package is FIN - # OR set compress status if this is first fragment - # Raise error if not first fragment with rsv1 = 0x1 - if self._frame_fin or self._compressed == COMPRESSED_NOT_SET: - self._compressed = COMPRESSED_TRUE if rsv1 else COMPRESSED_FALSE - elif rsv1: - raise WebSocketError( - WSCloseCode.PROTOCOL_ERROR, - "Received frame with non-zero reserved bits", - ) - - self._frame_fin = bool(fin) - self._frame_opcode = opcode - self._has_mask = bool(has_mask) - self._payload_len_flag = length - self._state = READ_PAYLOAD_LENGTH - - # read payload length - if self._state == READ_PAYLOAD_LENGTH: - len_flag = self._payload_len_flag - if len_flag == 126: - if data_len - start_pos < 2: - break - first_byte = data_cstr[start_pos] - second_byte = data_cstr[start_pos + 1] - start_pos += 2 - self._payload_bytes_to_read = first_byte << 8 | second_byte - elif len_flag > 126: - if data_len - start_pos < 8: - break - self._payload_bytes_to_read = UNPACK_LEN3(data, start_pos)[0] - start_pos += 8 - else: - self._payload_bytes_to_read = len_flag - - self._state = READ_PAYLOAD_MASK if self._has_mask else READ_PAYLOAD - - # read payload mask - if self._state == READ_PAYLOAD_MASK: - if data_len - start_pos < 4: - break - self._frame_mask = data_cstr[start_pos : start_pos + 4] - start_pos += 4 - self._state = READ_PAYLOAD - - if self._state == READ_PAYLOAD: - chunk_len = data_len - start_pos - if self._payload_bytes_to_read >= chunk_len: - f_end_pos = data_len - self._payload_bytes_to_read -= chunk_len - else: - f_end_pos = start_pos + self._payload_bytes_to_read - self._payload_bytes_to_read = 0 - - had_fragments = self._frame_payload_len - self._frame_payload_len += f_end_pos - start_pos - f_start_pos = start_pos - start_pos = f_end_pos - - if self._payload_bytes_to_read != 0: - # If we don't have a complete frame, we need to save the - # data for the next call to feed_data. - self._payload_fragments.append(data_cstr[f_start_pos:f_end_pos]) - break - - payload: Union[bytes, bytearray] - if had_fragments: - # We have to join the payload fragments get the payload - self._payload_fragments.append(data_cstr[f_start_pos:f_end_pos]) - if self._has_mask: - assert self._frame_mask is not None - payload_bytearray = bytearray(b"".join(self._payload_fragments)) - websocket_mask(self._frame_mask, payload_bytearray) - payload = payload_bytearray - else: - payload = b"".join(self._payload_fragments) - self._payload_fragments.clear() - elif self._has_mask: - assert self._frame_mask is not None - payload_bytearray = data_cstr[f_start_pos:f_end_pos] # type: ignore[assignment] - if type(payload_bytearray) is not bytearray: # pragma: no branch - # Cython will do the conversion for us - # but we need to do it for Python and we - # will always get here in Python - payload_bytearray = bytearray(payload_bytearray) - websocket_mask(self._frame_mask, payload_bytearray) - payload = payload_bytearray - else: - payload = data_cstr[f_start_pos:f_end_pos] - - self._handle_frame( - self._frame_fin, self._frame_opcode, payload, self._compressed - ) - self._frame_payload_len = 0 - self._state = READ_HEADER - - # XXX: Cython needs slices to be bounded, so we can't omit the slice end here. - self._tail = data_cstr[start_pos:data_len] if start_pos < data_len else b"" diff --git a/venv/lib/python3.9/site-packages/aiohttp/_websocket/reader_py.py b/venv/lib/python3.9/site-packages/aiohttp/_websocket/reader_py.py deleted file mode 100644 index 5166d7e..0000000 --- a/venv/lib/python3.9/site-packages/aiohttp/_websocket/reader_py.py +++ /dev/null @@ -1,478 +0,0 @@ -"""Reader for WebSocket protocol versions 13 and 8.""" - -import asyncio -import builtins -from collections import deque -from typing import Deque, Final, Optional, Set, Tuple, Union - -from ..base_protocol import BaseProtocol -from ..compression_utils import ZLibDecompressor -from ..helpers import _EXC_SENTINEL, set_exception -from ..streams import EofStream -from .helpers import UNPACK_CLOSE_CODE, UNPACK_LEN3, websocket_mask -from .models import ( - WS_DEFLATE_TRAILING, - WebSocketError, - WSCloseCode, - WSMessage, - WSMsgType, -) - -ALLOWED_CLOSE_CODES: Final[Set[int]] = {int(i) for i in WSCloseCode} - -# States for the reader, used to parse the WebSocket frame -# integer values are used so they can be cythonized -READ_HEADER = 1 -READ_PAYLOAD_LENGTH = 2 -READ_PAYLOAD_MASK = 3 -READ_PAYLOAD = 4 - -WS_MSG_TYPE_BINARY = WSMsgType.BINARY -WS_MSG_TYPE_TEXT = WSMsgType.TEXT - -# WSMsgType values unpacked so they can by cythonized to ints -OP_CODE_NOT_SET = -1 -OP_CODE_CONTINUATION = WSMsgType.CONTINUATION.value -OP_CODE_TEXT = WSMsgType.TEXT.value -OP_CODE_BINARY = WSMsgType.BINARY.value -OP_CODE_CLOSE = WSMsgType.CLOSE.value -OP_CODE_PING = WSMsgType.PING.value -OP_CODE_PONG = WSMsgType.PONG.value - -EMPTY_FRAME_ERROR = (True, b"") -EMPTY_FRAME = (False, b"") - -COMPRESSED_NOT_SET = -1 -COMPRESSED_FALSE = 0 -COMPRESSED_TRUE = 1 - -TUPLE_NEW = tuple.__new__ - -cython_int = int # Typed to int in Python, but cython with use a signed int in the pxd - - -class WebSocketDataQueue: - """WebSocketDataQueue resumes and pauses an underlying stream. - - It is a destination for WebSocket data. - """ - - def __init__( - self, protocol: BaseProtocol, limit: int, *, loop: asyncio.AbstractEventLoop - ) -> None: - self._size = 0 - self._protocol = protocol - self._limit = limit * 2 - self._loop = loop - self._eof = False - self._waiter: Optional[asyncio.Future[None]] = None - self._exception: Union[BaseException, None] = None - self._buffer: Deque[Tuple[WSMessage, int]] = deque() - self._get_buffer = self._buffer.popleft - self._put_buffer = self._buffer.append - - def is_eof(self) -> bool: - return self._eof - - def exception(self) -> Optional[BaseException]: - return self._exception - - def set_exception( - self, - exc: BaseException, - exc_cause: builtins.BaseException = _EXC_SENTINEL, - ) -> None: - self._eof = True - self._exception = exc - if (waiter := self._waiter) is not None: - self._waiter = None - set_exception(waiter, exc, exc_cause) - - def _release_waiter(self) -> None: - if (waiter := self._waiter) is None: - return - self._waiter = None - if not waiter.done(): - waiter.set_result(None) - - def feed_eof(self) -> None: - self._eof = True - self._release_waiter() - self._exception = None # Break cyclic references - - def feed_data(self, data: "WSMessage", size: "cython_int") -> None: - self._size += size - self._put_buffer((data, size)) - self._release_waiter() - if self._size > self._limit and not self._protocol._reading_paused: - self._protocol.pause_reading() - - async def read(self) -> WSMessage: - if not self._buffer and not self._eof: - assert not self._waiter - self._waiter = self._loop.create_future() - try: - await self._waiter - except (asyncio.CancelledError, asyncio.TimeoutError): - self._waiter = None - raise - return self._read_from_buffer() - - def _read_from_buffer(self) -> WSMessage: - if self._buffer: - data, size = self._get_buffer() - self._size -= size - if self._size < self._limit and self._protocol._reading_paused: - self._protocol.resume_reading() - return data - if self._exception is not None: - raise self._exception - raise EofStream - - -class WebSocketReader: - def __init__( - self, queue: WebSocketDataQueue, max_msg_size: int, compress: bool = True - ) -> None: - self.queue = queue - self._max_msg_size = max_msg_size - - self._exc: Optional[Exception] = None - self._partial = bytearray() - self._state = READ_HEADER - - self._opcode: int = OP_CODE_NOT_SET - self._frame_fin = False - self._frame_opcode: int = OP_CODE_NOT_SET - self._payload_fragments: list[bytes] = [] - self._frame_payload_len = 0 - - self._tail: bytes = b"" - self._has_mask = False - self._frame_mask: Optional[bytes] = None - self._payload_bytes_to_read = 0 - self._payload_len_flag = 0 - self._compressed: int = COMPRESSED_NOT_SET - self._decompressobj: Optional[ZLibDecompressor] = None - self._compress = compress - - def feed_eof(self) -> None: - self.queue.feed_eof() - - # data can be bytearray on Windows because proactor event loop uses bytearray - # and asyncio types this to Union[bytes, bytearray, memoryview] so we need - # coerce data to bytes if it is not - def feed_data( - self, data: Union[bytes, bytearray, memoryview] - ) -> Tuple[bool, bytes]: - if type(data) is not bytes: - data = bytes(data) - - if self._exc is not None: - return True, data - - try: - self._feed_data(data) - except Exception as exc: - self._exc = exc - set_exception(self.queue, exc) - return EMPTY_FRAME_ERROR - - return EMPTY_FRAME - - def _handle_frame( - self, - fin: bool, - opcode: Union[int, cython_int], # Union intended: Cython pxd uses C int - payload: Union[bytes, bytearray], - compressed: Union[int, cython_int], # Union intended: Cython pxd uses C int - ) -> None: - msg: WSMessage - if opcode in {OP_CODE_TEXT, OP_CODE_BINARY, OP_CODE_CONTINUATION}: - # Validate continuation frames before processing - if opcode == OP_CODE_CONTINUATION and self._opcode == OP_CODE_NOT_SET: - raise WebSocketError( - WSCloseCode.PROTOCOL_ERROR, - "Continuation frame for non started message", - ) - - # load text/binary - if not fin: - # got partial frame payload - if opcode != OP_CODE_CONTINUATION: - self._opcode = opcode - self._partial += payload - if self._max_msg_size and len(self._partial) >= self._max_msg_size: - raise WebSocketError( - WSCloseCode.MESSAGE_TOO_BIG, - f"Message size {len(self._partial)} " - f"exceeds limit {self._max_msg_size}", - ) - return - - has_partial = bool(self._partial) - if opcode == OP_CODE_CONTINUATION: - opcode = self._opcode - self._opcode = OP_CODE_NOT_SET - # previous frame was non finished - # we should get continuation opcode - elif has_partial: - raise WebSocketError( - WSCloseCode.PROTOCOL_ERROR, - "The opcode in non-fin frame is expected " - f"to be zero, got {opcode!r}", - ) - - assembled_payload: Union[bytes, bytearray] - if has_partial: - assembled_payload = self._partial + payload - self._partial.clear() - else: - assembled_payload = payload - - if self._max_msg_size and len(assembled_payload) >= self._max_msg_size: - raise WebSocketError( - WSCloseCode.MESSAGE_TOO_BIG, - f"Message size {len(assembled_payload)} " - f"exceeds limit {self._max_msg_size}", - ) - - # Decompress process must to be done after all packets - # received. - if compressed: - if not self._decompressobj: - self._decompressobj = ZLibDecompressor(suppress_deflate_header=True) - # XXX: It's possible that the zlib backend (isal is known to - # do this, maybe others too?) will return max_length bytes, - # but internally buffer more data such that the payload is - # >max_length, so we return one extra byte and if we're able - # to do that, then the message is too big. - payload_merged = self._decompressobj.decompress_sync( - assembled_payload + WS_DEFLATE_TRAILING, - ( - self._max_msg_size + 1 - if self._max_msg_size - else self._max_msg_size - ), - ) - if self._max_msg_size and len(payload_merged) > self._max_msg_size: - raise WebSocketError( - WSCloseCode.MESSAGE_TOO_BIG, - f"Decompressed message exceeds size limit {self._max_msg_size}", - ) - elif type(assembled_payload) is bytes: - payload_merged = assembled_payload - else: - payload_merged = bytes(assembled_payload) - - if opcode == OP_CODE_TEXT: - try: - text = payload_merged.decode("utf-8") - except UnicodeDecodeError as exc: - raise WebSocketError( - WSCloseCode.INVALID_TEXT, "Invalid UTF-8 text message" - ) from exc - - # XXX: The Text and Binary messages here can be a performance - # bottleneck, so we use tuple.__new__ to improve performance. - # This is not type safe, but many tests should fail in - # test_client_ws_functional.py if this is wrong. - self.queue.feed_data( - TUPLE_NEW(WSMessage, (WS_MSG_TYPE_TEXT, text, "")), - len(payload_merged), - ) - else: - self.queue.feed_data( - TUPLE_NEW(WSMessage, (WS_MSG_TYPE_BINARY, payload_merged, "")), - len(payload_merged), - ) - elif opcode == OP_CODE_CLOSE: - if len(payload) >= 2: - close_code = UNPACK_CLOSE_CODE(payload[:2])[0] - if close_code < 3000 and close_code not in ALLOWED_CLOSE_CODES: - raise WebSocketError( - WSCloseCode.PROTOCOL_ERROR, - f"Invalid close code: {close_code}", - ) - try: - close_message = payload[2:].decode("utf-8") - except UnicodeDecodeError as exc: - raise WebSocketError( - WSCloseCode.INVALID_TEXT, "Invalid UTF-8 text message" - ) from exc - msg = TUPLE_NEW(WSMessage, (WSMsgType.CLOSE, close_code, close_message)) - elif payload: - raise WebSocketError( - WSCloseCode.PROTOCOL_ERROR, - f"Invalid close frame: {fin} {opcode} {payload!r}", - ) - else: - msg = TUPLE_NEW(WSMessage, (WSMsgType.CLOSE, 0, "")) - - self.queue.feed_data(msg, 0) - elif opcode == OP_CODE_PING: - msg = TUPLE_NEW(WSMessage, (WSMsgType.PING, payload, "")) - self.queue.feed_data(msg, len(payload)) - elif opcode == OP_CODE_PONG: - msg = TUPLE_NEW(WSMessage, (WSMsgType.PONG, payload, "")) - self.queue.feed_data(msg, len(payload)) - else: - raise WebSocketError( - WSCloseCode.PROTOCOL_ERROR, f"Unexpected opcode={opcode!r}" - ) - - def _feed_data(self, data: bytes) -> None: - """Return the next frame from the socket.""" - if self._tail: - data, self._tail = self._tail + data, b"" - - start_pos: int = 0 - data_len = len(data) - data_cstr = data - - while True: - # read header - if self._state == READ_HEADER: - if data_len - start_pos < 2: - break - first_byte = data_cstr[start_pos] - second_byte = data_cstr[start_pos + 1] - start_pos += 2 - - fin = (first_byte >> 7) & 1 - rsv1 = (first_byte >> 6) & 1 - rsv2 = (first_byte >> 5) & 1 - rsv3 = (first_byte >> 4) & 1 - opcode = first_byte & 0xF - - # frame-fin = %x0 ; more frames of this message follow - # / %x1 ; final frame of this message - # frame-rsv1 = %x0 ; - # 1 bit, MUST be 0 unless negotiated otherwise - # frame-rsv2 = %x0 ; - # 1 bit, MUST be 0 unless negotiated otherwise - # frame-rsv3 = %x0 ; - # 1 bit, MUST be 0 unless negotiated otherwise - # - # Remove rsv1 from this test for deflate development - if rsv2 or rsv3 or (rsv1 and not self._compress): - raise WebSocketError( - WSCloseCode.PROTOCOL_ERROR, - "Received frame with non-zero reserved bits", - ) - - if opcode > 0x7 and fin == 0: - raise WebSocketError( - WSCloseCode.PROTOCOL_ERROR, - "Received fragmented control frame", - ) - - has_mask = (second_byte >> 7) & 1 - length = second_byte & 0x7F - - # Control frames MUST have a payload - # length of 125 bytes or less - if opcode > 0x7 and length > 125: - raise WebSocketError( - WSCloseCode.PROTOCOL_ERROR, - "Control frame payload cannot be larger than 125 bytes", - ) - - # Set compress status if last package is FIN - # OR set compress status if this is first fragment - # Raise error if not first fragment with rsv1 = 0x1 - if self._frame_fin or self._compressed == COMPRESSED_NOT_SET: - self._compressed = COMPRESSED_TRUE if rsv1 else COMPRESSED_FALSE - elif rsv1: - raise WebSocketError( - WSCloseCode.PROTOCOL_ERROR, - "Received frame with non-zero reserved bits", - ) - - self._frame_fin = bool(fin) - self._frame_opcode = opcode - self._has_mask = bool(has_mask) - self._payload_len_flag = length - self._state = READ_PAYLOAD_LENGTH - - # read payload length - if self._state == READ_PAYLOAD_LENGTH: - len_flag = self._payload_len_flag - if len_flag == 126: - if data_len - start_pos < 2: - break - first_byte = data_cstr[start_pos] - second_byte = data_cstr[start_pos + 1] - start_pos += 2 - self._payload_bytes_to_read = first_byte << 8 | second_byte - elif len_flag > 126: - if data_len - start_pos < 8: - break - self._payload_bytes_to_read = UNPACK_LEN3(data, start_pos)[0] - start_pos += 8 - else: - self._payload_bytes_to_read = len_flag - - self._state = READ_PAYLOAD_MASK if self._has_mask else READ_PAYLOAD - - # read payload mask - if self._state == READ_PAYLOAD_MASK: - if data_len - start_pos < 4: - break - self._frame_mask = data_cstr[start_pos : start_pos + 4] - start_pos += 4 - self._state = READ_PAYLOAD - - if self._state == READ_PAYLOAD: - chunk_len = data_len - start_pos - if self._payload_bytes_to_read >= chunk_len: - f_end_pos = data_len - self._payload_bytes_to_read -= chunk_len - else: - f_end_pos = start_pos + self._payload_bytes_to_read - self._payload_bytes_to_read = 0 - - had_fragments = self._frame_payload_len - self._frame_payload_len += f_end_pos - start_pos - f_start_pos = start_pos - start_pos = f_end_pos - - if self._payload_bytes_to_read != 0: - # If we don't have a complete frame, we need to save the - # data for the next call to feed_data. - self._payload_fragments.append(data_cstr[f_start_pos:f_end_pos]) - break - - payload: Union[bytes, bytearray] - if had_fragments: - # We have to join the payload fragments get the payload - self._payload_fragments.append(data_cstr[f_start_pos:f_end_pos]) - if self._has_mask: - assert self._frame_mask is not None - payload_bytearray = bytearray(b"".join(self._payload_fragments)) - websocket_mask(self._frame_mask, payload_bytearray) - payload = payload_bytearray - else: - payload = b"".join(self._payload_fragments) - self._payload_fragments.clear() - elif self._has_mask: - assert self._frame_mask is not None - payload_bytearray = data_cstr[f_start_pos:f_end_pos] # type: ignore[assignment] - if type(payload_bytearray) is not bytearray: # pragma: no branch - # Cython will do the conversion for us - # but we need to do it for Python and we - # will always get here in Python - payload_bytearray = bytearray(payload_bytearray) - websocket_mask(self._frame_mask, payload_bytearray) - payload = payload_bytearray - else: - payload = data_cstr[f_start_pos:f_end_pos] - - self._handle_frame( - self._frame_fin, self._frame_opcode, payload, self._compressed - ) - self._frame_payload_len = 0 - self._state = READ_HEADER - - # XXX: Cython needs slices to be bounded, so we can't omit the slice end here. - self._tail = data_cstr[start_pos:data_len] if start_pos < data_len else b"" diff --git a/venv/lib/python3.9/site-packages/aiohttp/_websocket/writer.py b/venv/lib/python3.9/site-packages/aiohttp/_websocket/writer.py deleted file mode 100644 index 9604202..0000000 --- a/venv/lib/python3.9/site-packages/aiohttp/_websocket/writer.py +++ /dev/null @@ -1,262 +0,0 @@ -"""WebSocket protocol versions 13 and 8.""" - -import asyncio -import random -import sys -from functools import partial -from typing import Final, Optional, Set, Union - -from ..base_protocol import BaseProtocol -from ..client_exceptions import ClientConnectionResetError -from ..compression_utils import ZLibBackend, ZLibCompressor -from .helpers import ( - MASK_LEN, - MSG_SIZE, - PACK_CLOSE_CODE, - PACK_LEN1, - PACK_LEN2, - PACK_LEN3, - PACK_RANDBITS, - websocket_mask, -) -from .models import WS_DEFLATE_TRAILING, WSMsgType - -DEFAULT_LIMIT: Final[int] = 2**16 - -# WebSocket opcode boundary: opcodes 0-7 are data frames, 8-15 are control frames -# Control frames (ping, pong, close) are never compressed -WS_CONTROL_FRAME_OPCODE: Final[int] = 8 - -# For websockets, keeping latency low is extremely important as implementations -# generally expect to be able to send and receive messages quickly. We use a -# larger chunk size to reduce the number of executor calls and avoid task -# creation overhead, since both are significant sources of latency when chunks -# are small. A size of 16KiB was chosen as a balance between avoiding task -# overhead and not blocking the event loop too long with synchronous compression. - -WEBSOCKET_MAX_SYNC_CHUNK_SIZE = 16 * 1024 - - -class WebSocketWriter: - """WebSocket writer. - - The writer is responsible for sending messages to the client. It is - created by the protocol when a connection is established. The writer - should avoid implementing any application logic and should only be - concerned with the low-level details of the WebSocket protocol. - """ - - def __init__( - self, - protocol: BaseProtocol, - transport: asyncio.Transport, - *, - use_mask: bool = False, - limit: int = DEFAULT_LIMIT, - random: random.Random = random.Random(), - compress: int = 0, - notakeover: bool = False, - ) -> None: - """Initialize a WebSocket writer.""" - self.protocol = protocol - self.transport = transport - self.use_mask = use_mask - self.get_random_bits = partial(random.getrandbits, 32) - self.compress = compress - self.notakeover = notakeover - self._closing = False - self._limit = limit - self._output_size = 0 - self._compressobj: Optional[ZLibCompressor] = None - self._send_lock = asyncio.Lock() - self._background_tasks: Set[asyncio.Task[None]] = set() - - async def send_frame( - self, message: bytes, opcode: int, compress: Optional[int] = None - ) -> None: - """Send a frame over the websocket with message as its payload.""" - if self._closing and not (opcode & WSMsgType.CLOSE): - raise ClientConnectionResetError("Cannot write to closing transport") - - if not (compress or self.compress) or opcode >= WS_CONTROL_FRAME_OPCODE: - # Non-compressed frames don't need lock or shield - self._write_websocket_frame(message, opcode, 0) - elif len(message) <= WEBSOCKET_MAX_SYNC_CHUNK_SIZE: - # Small compressed payloads - compress synchronously in event loop - # We need the lock even though sync compression has no await points. - # This prevents small frames from interleaving with large frames that - # compress in the executor, avoiding compressor state corruption. - async with self._send_lock: - self._send_compressed_frame_sync(message, opcode, compress) - else: - # Large compressed frames need shield to prevent corruption - # For large compressed frames, the entire compress+send - # operation must be atomic. If cancelled after compression but - # before send, the compressor state would be advanced but data - # not sent, corrupting subsequent frames. - # Create a task to shield from cancellation - # The lock is acquired inside the shielded task so the entire - # operation (lock + compress + send) completes atomically. - # Use eager_start on Python 3.12+ to avoid scheduling overhead - loop = asyncio.get_running_loop() - coro = self._send_compressed_frame_async_locked(message, opcode, compress) - if sys.version_info >= (3, 12): - send_task = asyncio.Task(coro, loop=loop, eager_start=True) - else: - send_task = loop.create_task(coro) - # Keep a strong reference to prevent garbage collection - self._background_tasks.add(send_task) - send_task.add_done_callback(self._background_tasks.discard) - await asyncio.shield(send_task) - - # It is safe to return control to the event loop when using compression - # after this point as we have already sent or buffered all the data. - # Once we have written output_size up to the limit, we call the - # drain helper which waits for the transport to be ready to accept - # more data. This is a flow control mechanism to prevent the buffer - # from growing too large. The drain helper will return right away - # if the writer is not paused. - if self._output_size > self._limit: - self._output_size = 0 - if self.protocol._paused: - await self.protocol._drain_helper() - - def _write_websocket_frame(self, message: bytes, opcode: int, rsv: int) -> None: - """ - Write a websocket frame to the transport. - - This method handles frame header construction, masking, and writing to transport. - It does not handle compression or flow control - those are the responsibility - of the caller. - """ - msg_length = len(message) - - use_mask = self.use_mask - mask_bit = 0x80 if use_mask else 0 - - # Depending on the message length, the header is assembled differently. - # The first byte is reserved for the opcode and the RSV bits. - first_byte = 0x80 | rsv | opcode - if msg_length < 126: - header = PACK_LEN1(first_byte, msg_length | mask_bit) - header_len = 2 - elif msg_length < 65536: - header = PACK_LEN2(first_byte, 126 | mask_bit, msg_length) - header_len = 4 - else: - header = PACK_LEN3(first_byte, 127 | mask_bit, msg_length) - header_len = 10 - - if self.transport.is_closing(): - raise ClientConnectionResetError("Cannot write to closing transport") - - # https://datatracker.ietf.org/doc/html/rfc6455#section-5.3 - # If we are using a mask, we need to generate it randomly - # and apply it to the message before sending it. A mask is - # a 32-bit value that is applied to the message using a - # bitwise XOR operation. It is used to prevent certain types - # of attacks on the websocket protocol. The mask is only used - # when aiohttp is acting as a client. Servers do not use a mask. - if use_mask: - mask = PACK_RANDBITS(self.get_random_bits()) - message = bytearray(message) - websocket_mask(mask, message) - self.transport.write(header + mask + message) - self._output_size += MASK_LEN - elif msg_length > MSG_SIZE: - self.transport.write(header) - self.transport.write(message) - else: - self.transport.write(header + message) - - self._output_size += header_len + msg_length - - def _get_compressor(self, compress: Optional[int]) -> ZLibCompressor: - """Get or create a compressor object for the given compression level.""" - if compress: - # Do not set self._compress if compressing is for this frame - return ZLibCompressor( - level=ZLibBackend.Z_BEST_SPEED, - wbits=-compress, - max_sync_chunk_size=WEBSOCKET_MAX_SYNC_CHUNK_SIZE, - ) - if not self._compressobj: - self._compressobj = ZLibCompressor( - level=ZLibBackend.Z_BEST_SPEED, - wbits=-self.compress, - max_sync_chunk_size=WEBSOCKET_MAX_SYNC_CHUNK_SIZE, - ) - return self._compressobj - - def _send_compressed_frame_sync( - self, message: bytes, opcode: int, compress: Optional[int] - ) -> None: - """ - Synchronous send for small compressed frames. - - This is used for small compressed payloads that compress synchronously in the event loop. - Since there are no await points, this is inherently cancellation-safe. - """ - # RSV are the reserved bits in the frame header. They are used to - # indicate that the frame is using an extension. - # https://datatracker.ietf.org/doc/html/rfc6455#section-5.2 - compressobj = self._get_compressor(compress) - # (0x40) RSV1 is set for compressed frames - # https://datatracker.ietf.org/doc/html/rfc7692#section-7.2.3.1 - self._write_websocket_frame( - ( - compressobj.compress_sync(message) - + compressobj.flush( - ZLibBackend.Z_FULL_FLUSH - if self.notakeover - else ZLibBackend.Z_SYNC_FLUSH - ) - ).removesuffix(WS_DEFLATE_TRAILING), - opcode, - 0x40, - ) - - async def _send_compressed_frame_async_locked( - self, message: bytes, opcode: int, compress: Optional[int] - ) -> None: - """ - Async send for large compressed frames with lock. - - Acquires the lock and compresses large payloads asynchronously in - the executor. The lock is held for the entire operation to ensure - the compressor state is not corrupted by concurrent sends. - - MUST be run shielded from cancellation. If cancelled after - compression but before sending, the compressor state would be - advanced but data not sent, corrupting subsequent frames. - """ - async with self._send_lock: - # RSV are the reserved bits in the frame header. They are used to - # indicate that the frame is using an extension. - # https://datatracker.ietf.org/doc/html/rfc6455#section-5.2 - compressobj = self._get_compressor(compress) - # (0x40) RSV1 is set for compressed frames - # https://datatracker.ietf.org/doc/html/rfc7692#section-7.2.3.1 - self._write_websocket_frame( - ( - await compressobj.compress(message) - + compressobj.flush( - ZLibBackend.Z_FULL_FLUSH - if self.notakeover - else ZLibBackend.Z_SYNC_FLUSH - ) - ).removesuffix(WS_DEFLATE_TRAILING), - opcode, - 0x40, - ) - - async def close(self, code: int = 1000, message: Union[bytes, str] = b"") -> None: - """Close the websocket, sending the specified code and message.""" - if isinstance(message, str): - message = message.encode("utf-8") - try: - await self.send_frame( - PACK_CLOSE_CODE(code) + message, opcode=WSMsgType.CLOSE - ) - finally: - self._closing = True diff --git a/venv/lib/python3.9/site-packages/aiohttp/abc.py b/venv/lib/python3.9/site-packages/aiohttp/abc.py deleted file mode 100644 index faf0957..0000000 --- a/venv/lib/python3.9/site-packages/aiohttp/abc.py +++ /dev/null @@ -1,268 +0,0 @@ -import asyncio -import logging -import socket -from abc import ABC, abstractmethod -from collections.abc import Sized -from http.cookies import BaseCookie, Morsel -from typing import ( - TYPE_CHECKING, - Any, - Awaitable, - Callable, - Dict, - Generator, - Iterable, - List, - Optional, - Sequence, - Tuple, - TypedDict, - Union, -) - -from multidict import CIMultiDict -from yarl import URL - -from ._cookie_helpers import parse_set_cookie_headers -from .typedefs import LooseCookies - -if TYPE_CHECKING: - from .web_app import Application - from .web_exceptions import HTTPException - from .web_request import BaseRequest, Request - from .web_response import StreamResponse -else: - BaseRequest = Request = Application = StreamResponse = None - HTTPException = None - - -class AbstractRouter(ABC): - def __init__(self) -> None: - self._frozen = False - - def post_init(self, app: Application) -> None: - """Post init stage. - - Not an abstract method for sake of backward compatibility, - but if the router wants to be aware of the application - it can override this. - """ - - @property - def frozen(self) -> bool: - return self._frozen - - def freeze(self) -> None: - """Freeze router.""" - self._frozen = True - - @abstractmethod - async def resolve(self, request: Request) -> "AbstractMatchInfo": - """Return MATCH_INFO for given request""" - - -class AbstractMatchInfo(ABC): - - __slots__ = () - - @property # pragma: no branch - @abstractmethod - def handler(self) -> Callable[[Request], Awaitable[StreamResponse]]: - """Execute matched request handler""" - - @property - @abstractmethod - def expect_handler( - self, - ) -> Callable[[Request], Awaitable[Optional[StreamResponse]]]: - """Expect handler for 100-continue processing""" - - @property # pragma: no branch - @abstractmethod - def http_exception(self) -> Optional[HTTPException]: - """HTTPException instance raised on router's resolving, or None""" - - @abstractmethod # pragma: no branch - def get_info(self) -> Dict[str, Any]: - """Return a dict with additional info useful for introspection""" - - @property # pragma: no branch - @abstractmethod - def apps(self) -> Tuple[Application, ...]: - """Stack of nested applications. - - Top level application is left-most element. - - """ - - @abstractmethod - def add_app(self, app: Application) -> None: - """Add application to the nested apps stack.""" - - @abstractmethod - def freeze(self) -> None: - """Freeze the match info. - - The method is called after route resolution. - - After the call .add_app() is forbidden. - - """ - - -class AbstractView(ABC): - """Abstract class based view.""" - - def __init__(self, request: Request) -> None: - self._request = request - - @property - def request(self) -> Request: - """Request instance.""" - return self._request - - @abstractmethod - def __await__(self) -> Generator[None, None, StreamResponse]: - """Execute the view handler.""" - - -class ResolveResult(TypedDict): - """Resolve result. - - This is the result returned from an AbstractResolver's - resolve method. - - :param hostname: The hostname that was provided. - :param host: The IP address that was resolved. - :param port: The port that was resolved. - :param family: The address family that was resolved. - :param proto: The protocol that was resolved. - :param flags: The flags that were resolved. - """ - - hostname: str - host: str - port: int - family: int - proto: int - flags: int - - -class AbstractResolver(ABC): - """Abstract DNS resolver.""" - - @abstractmethod - async def resolve( - self, host: str, port: int = 0, family: socket.AddressFamily = socket.AF_INET - ) -> List[ResolveResult]: - """Return IP address for given hostname""" - - @abstractmethod - async def close(self) -> None: - """Release resolver""" - - -if TYPE_CHECKING: - IterableBase = Iterable[Morsel[str]] -else: - IterableBase = Iterable - - -ClearCookiePredicate = Callable[["Morsel[str]"], bool] - - -class AbstractCookieJar(Sized, IterableBase): - """Abstract Cookie Jar.""" - - def __init__(self, *, loop: Optional[asyncio.AbstractEventLoop] = None) -> None: - self._loop = loop or asyncio.get_running_loop() - - @property - @abstractmethod - def quote_cookie(self) -> bool: - """Return True if cookies should be quoted.""" - - @abstractmethod - def clear(self, predicate: Optional[ClearCookiePredicate] = None) -> None: - """Clear all cookies if no predicate is passed.""" - - @abstractmethod - def clear_domain(self, domain: str) -> None: - """Clear all cookies for domain and all subdomains.""" - - @abstractmethod - def update_cookies(self, cookies: LooseCookies, response_url: URL = URL()) -> None: - """Update cookies.""" - - def update_cookies_from_headers( - self, headers: Sequence[str], response_url: URL - ) -> None: - """Update cookies from raw Set-Cookie headers.""" - if headers and (cookies_to_update := parse_set_cookie_headers(headers)): - self.update_cookies(cookies_to_update, response_url) - - @abstractmethod - def filter_cookies(self, request_url: URL) -> "BaseCookie[str]": - """Return the jar's cookies filtered by their attributes.""" - - -class AbstractStreamWriter(ABC): - """Abstract stream writer.""" - - buffer_size: int = 0 - output_size: int = 0 - length: Optional[int] = 0 - - @abstractmethod - async def write(self, chunk: Union[bytes, bytearray, memoryview]) -> None: - """Write chunk into stream.""" - - @abstractmethod - async def write_eof(self, chunk: bytes = b"") -> None: - """Write last chunk.""" - - @abstractmethod - async def drain(self) -> None: - """Flush the write buffer.""" - - @abstractmethod - def enable_compression( - self, encoding: str = "deflate", strategy: Optional[int] = None - ) -> None: - """Enable HTTP body compression""" - - @abstractmethod - def enable_chunking(self) -> None: - """Enable HTTP chunked mode""" - - @abstractmethod - async def write_headers( - self, status_line: str, headers: "CIMultiDict[str]" - ) -> None: - """Write HTTP headers""" - - def send_headers(self) -> None: - """Force sending buffered headers if not already sent. - - Required only if write_headers() buffers headers instead of sending immediately. - For backwards compatibility, this method does nothing by default. - """ - - -class AbstractAccessLogger(ABC): - """Abstract writer to access log.""" - - __slots__ = ("logger", "log_format") - - def __init__(self, logger: logging.Logger, log_format: str) -> None: - self.logger = logger - self.log_format = log_format - - @abstractmethod - def log(self, request: BaseRequest, response: StreamResponse, time: float) -> None: - """Emit log to logger.""" - - @property - def enabled(self) -> bool: - """Check if logger is enabled.""" - return True diff --git a/venv/lib/python3.9/site-packages/aiohttp/base_protocol.py b/venv/lib/python3.9/site-packages/aiohttp/base_protocol.py deleted file mode 100644 index b0a67ed..0000000 --- a/venv/lib/python3.9/site-packages/aiohttp/base_protocol.py +++ /dev/null @@ -1,100 +0,0 @@ -import asyncio -from typing import Optional, cast - -from .client_exceptions import ClientConnectionResetError -from .helpers import set_exception -from .tcp_helpers import tcp_nodelay - - -class BaseProtocol(asyncio.Protocol): - __slots__ = ( - "_loop", - "_paused", - "_drain_waiter", - "_connection_lost", - "_reading_paused", - "transport", - ) - - def __init__(self, loop: asyncio.AbstractEventLoop) -> None: - self._loop: asyncio.AbstractEventLoop = loop - self._paused = False - self._drain_waiter: Optional[asyncio.Future[None]] = None - self._reading_paused = False - - self.transport: Optional[asyncio.Transport] = None - - @property - def connected(self) -> bool: - """Return True if the connection is open.""" - return self.transport is not None - - @property - def writing_paused(self) -> bool: - return self._paused - - def pause_writing(self) -> None: - assert not self._paused - self._paused = True - - def resume_writing(self) -> None: - assert self._paused - self._paused = False - - waiter = self._drain_waiter - if waiter is not None: - self._drain_waiter = None - if not waiter.done(): - waiter.set_result(None) - - def pause_reading(self) -> None: - if not self._reading_paused and self.transport is not None: - try: - self.transport.pause_reading() - except (AttributeError, NotImplementedError, RuntimeError): - pass - self._reading_paused = True - - def resume_reading(self) -> None: - if self._reading_paused and self.transport is not None: - try: - self.transport.resume_reading() - except (AttributeError, NotImplementedError, RuntimeError): - pass - self._reading_paused = False - - def connection_made(self, transport: asyncio.BaseTransport) -> None: - tr = cast(asyncio.Transport, transport) - tcp_nodelay(tr, True) - self.transport = tr - - def connection_lost(self, exc: Optional[BaseException]) -> None: - # Wake up the writer if currently paused. - self.transport = None - if not self._paused: - return - waiter = self._drain_waiter - if waiter is None: - return - self._drain_waiter = None - if waiter.done(): - return - if exc is None: - waiter.set_result(None) - else: - set_exception( - waiter, - ConnectionError("Connection lost"), - exc, - ) - - async def _drain_helper(self) -> None: - if self.transport is None: - raise ClientConnectionResetError("Connection lost") - if not self._paused: - return - waiter = self._drain_waiter - if waiter is None: - waiter = self._loop.create_future() - self._drain_waiter = waiter - await asyncio.shield(waiter) diff --git a/venv/lib/python3.9/site-packages/aiohttp/client.py b/venv/lib/python3.9/site-packages/aiohttp/client.py deleted file mode 100644 index 5d10d3e..0000000 --- a/venv/lib/python3.9/site-packages/aiohttp/client.py +++ /dev/null @@ -1,1646 +0,0 @@ -"""HTTP Client for asyncio.""" - -import asyncio -import base64 -import hashlib -import json -import os -import sys -import traceback -import warnings -from contextlib import suppress -from types import TracebackType -from typing import ( - TYPE_CHECKING, - Any, - Awaitable, - Callable, - Coroutine, - Final, - FrozenSet, - Generator, - Generic, - Iterable, - List, - Mapping, - Optional, - Sequence, - Set, - Tuple, - Type, - TypedDict, - TypeVar, - Union, -) - -import attr -from multidict import CIMultiDict, MultiDict, MultiDictProxy, istr -from yarl import URL - -from . import hdrs, http, payload -from ._websocket.reader import WebSocketDataQueue -from .abc import AbstractCookieJar -from .client_exceptions import ( - ClientConnectionError, - ClientConnectionResetError, - ClientConnectorCertificateError, - ClientConnectorDNSError, - ClientConnectorError, - ClientConnectorSSLError, - ClientError, - ClientHttpProxyError, - ClientOSError, - ClientPayloadError, - ClientProxyConnectionError, - ClientResponseError, - ClientSSLError, - ConnectionTimeoutError, - ContentTypeError, - InvalidURL, - InvalidUrlClientError, - InvalidUrlRedirectClientError, - NonHttpUrlClientError, - NonHttpUrlRedirectClientError, - RedirectClientError, - ServerConnectionError, - ServerDisconnectedError, - ServerFingerprintMismatch, - ServerTimeoutError, - SocketTimeoutError, - TooManyRedirects, - WSMessageTypeError, - WSServerHandshakeError, -) -from .client_middlewares import ClientMiddlewareType, build_client_middlewares -from .client_reqrep import ( - ClientRequest as ClientRequest, - ClientResponse as ClientResponse, - Fingerprint as Fingerprint, - RequestInfo as RequestInfo, - _merge_ssl_params, -) -from .client_ws import ( - DEFAULT_WS_CLIENT_TIMEOUT, - ClientWebSocketResponse as ClientWebSocketResponse, - ClientWSTimeout as ClientWSTimeout, -) -from .connector import ( - HTTP_AND_EMPTY_SCHEMA_SET, - BaseConnector as BaseConnector, - NamedPipeConnector as NamedPipeConnector, - TCPConnector as TCPConnector, - UnixConnector as UnixConnector, -) -from .cookiejar import CookieJar -from .helpers import ( - _SENTINEL, - DEBUG, - EMPTY_BODY_METHODS, - BasicAuth, - TimeoutHandle, - basicauth_from_netrc, - get_env_proxy_for_url, - netrc_from_env, - sentinel, - strip_auth_from_url, -) -from .http import WS_KEY, HttpVersion, WebSocketReader, WebSocketWriter -from .http_websocket import WSHandshakeError, ws_ext_gen, ws_ext_parse -from .tracing import Trace, TraceConfig -from .typedefs import JSONEncoder, LooseCookies, LooseHeaders, Query, StrOrURL - -__all__ = ( - # client_exceptions - "ClientConnectionError", - "ClientConnectionResetError", - "ClientConnectorCertificateError", - "ClientConnectorDNSError", - "ClientConnectorError", - "ClientConnectorSSLError", - "ClientError", - "ClientHttpProxyError", - "ClientOSError", - "ClientPayloadError", - "ClientProxyConnectionError", - "ClientResponseError", - "ClientSSLError", - "ConnectionTimeoutError", - "ContentTypeError", - "InvalidURL", - "InvalidUrlClientError", - "RedirectClientError", - "NonHttpUrlClientError", - "InvalidUrlRedirectClientError", - "NonHttpUrlRedirectClientError", - "ServerConnectionError", - "ServerDisconnectedError", - "ServerFingerprintMismatch", - "ServerTimeoutError", - "SocketTimeoutError", - "TooManyRedirects", - "WSServerHandshakeError", - # client_reqrep - "ClientRequest", - "ClientResponse", - "Fingerprint", - "RequestInfo", - # connector - "BaseConnector", - "TCPConnector", - "UnixConnector", - "NamedPipeConnector", - # client_ws - "ClientWebSocketResponse", - # client - "ClientSession", - "ClientTimeout", - "ClientWSTimeout", - "request", - "WSMessageTypeError", -) - - -if TYPE_CHECKING: - from ssl import SSLContext -else: - SSLContext = None - -if sys.version_info >= (3, 11) and TYPE_CHECKING: - from typing import Unpack - - -class _RequestOptions(TypedDict, total=False): - params: Query - data: Any - json: Any - cookies: Union[LooseCookies, None] - headers: Union[LooseHeaders, None] - skip_auto_headers: Union[Iterable[str], None] - auth: Union[BasicAuth, None] - allow_redirects: bool - max_redirects: int - compress: Union[str, bool, None] - chunked: Union[bool, None] - expect100: bool - raise_for_status: Union[None, bool, Callable[[ClientResponse], Awaitable[None]]] - read_until_eof: bool - proxy: Union[StrOrURL, None] - proxy_auth: Union[BasicAuth, None] - timeout: "Union[ClientTimeout, _SENTINEL, None]" - ssl: Union[SSLContext, bool, Fingerprint] - server_hostname: Union[str, None] - proxy_headers: Union[LooseHeaders, None] - trace_request_ctx: Union[Mapping[str, Any], None] - read_bufsize: Union[int, None] - auto_decompress: Union[bool, None] - max_line_size: Union[int, None] - max_field_size: Union[int, None] - max_headers: Union[int, None] - middlewares: Optional[Sequence[ClientMiddlewareType]] - - -@attr.s(auto_attribs=True, frozen=True, slots=True) -class ClientTimeout: - total: Optional[float] = None - connect: Optional[float] = None - sock_read: Optional[float] = None - sock_connect: Optional[float] = None - ceil_threshold: float = 5 - - # pool_queue_timeout: Optional[float] = None - # dns_resolution_timeout: Optional[float] = None - # socket_connect_timeout: Optional[float] = None - # connection_acquiring_timeout: Optional[float] = None - # new_connection_timeout: Optional[float] = None - # http_header_timeout: Optional[float] = None - # response_body_timeout: Optional[float] = None - - # to create a timeout specific for a single request, either - # - create a completely new one to overwrite the default - # - or use http://www.attrs.org/en/stable/api.html#attr.evolve - # to overwrite the defaults - - -# 5 Minute default read timeout -DEFAULT_TIMEOUT: Final[ClientTimeout] = ClientTimeout(total=5 * 60, sock_connect=30) - -# https://www.rfc-editor.org/rfc/rfc9110#section-9.2.2 -IDEMPOTENT_METHODS = frozenset({"GET", "HEAD", "OPTIONS", "TRACE", "PUT", "DELETE"}) - -_RetType = TypeVar("_RetType", ClientResponse, ClientWebSocketResponse) -_CharsetResolver = Callable[[ClientResponse, bytes], str] - - -class ClientSession: - """First-class interface for making HTTP requests.""" - - ATTRS = frozenset( - [ - "_base_url", - "_base_url_origin", - "_source_traceback", - "_connector", - "_loop", - "_cookie_jar", - "_connector_owner", - "_default_auth", - "_version", - "_json_serialize", - "_requote_redirect_url", - "_timeout", - "_raise_for_status", - "_auto_decompress", - "_trust_env", - "_default_headers", - "_skip_auto_headers", - "_request_class", - "_response_class", - "_ws_response_class", - "_trace_configs", - "_read_bufsize", - "_max_line_size", - "_max_field_size", - "_max_headers", - "_resolve_charset", - "_default_proxy", - "_default_proxy_auth", - "_retry_connection", - "_middlewares", - "requote_redirect_url", - ] - ) - - _source_traceback: Optional[traceback.StackSummary] = None - _connector: Optional[BaseConnector] = None - - def __init__( - self, - base_url: Optional[StrOrURL] = None, - *, - connector: Optional[BaseConnector] = None, - loop: Optional[asyncio.AbstractEventLoop] = None, - cookies: Optional[LooseCookies] = None, - headers: Optional[LooseHeaders] = None, - proxy: Optional[StrOrURL] = None, - proxy_auth: Optional[BasicAuth] = None, - skip_auto_headers: Optional[Iterable[str]] = None, - auth: Optional[BasicAuth] = None, - json_serialize: JSONEncoder = json.dumps, - request_class: Type[ClientRequest] = ClientRequest, - response_class: Type[ClientResponse] = ClientResponse, - ws_response_class: Type[ClientWebSocketResponse] = ClientWebSocketResponse, - version: HttpVersion = http.HttpVersion11, - cookie_jar: Optional[AbstractCookieJar] = None, - connector_owner: bool = True, - raise_for_status: Union[ - bool, Callable[[ClientResponse], Awaitable[None]] - ] = False, - read_timeout: Union[float, _SENTINEL] = sentinel, - conn_timeout: Optional[float] = None, - timeout: Union[object, ClientTimeout] = sentinel, - auto_decompress: bool = True, - trust_env: bool = False, - requote_redirect_url: bool = True, - trace_configs: Optional[List[TraceConfig]] = None, - read_bufsize: int = 2**16, - max_line_size: int = 8190, - max_field_size: int = 8190, - max_headers: int = 128, - fallback_charset_resolver: _CharsetResolver = lambda r, b: "utf-8", - middlewares: Sequence[ClientMiddlewareType] = (), - ssl_shutdown_timeout: Union[_SENTINEL, None, float] = sentinel, - ) -> None: - # We initialise _connector to None immediately, as it's referenced in __del__() - # and could cause issues if an exception occurs during initialisation. - self._connector: Optional[BaseConnector] = None - - if loop is None: - if connector is not None: - loop = connector._loop - - loop = loop or asyncio.get_running_loop() - - if base_url is None or isinstance(base_url, URL): - self._base_url: Optional[URL] = base_url - self._base_url_origin = None if base_url is None else base_url.origin() - else: - self._base_url = URL(base_url) - self._base_url_origin = self._base_url.origin() - assert self._base_url.absolute, "Only absolute URLs are supported" - if self._base_url is not None and not self._base_url.path.endswith("/"): - raise ValueError("base_url must have a trailing '/'") - - if timeout is sentinel or timeout is None: - self._timeout = DEFAULT_TIMEOUT - if read_timeout is not sentinel: - warnings.warn( - "read_timeout is deprecated, use timeout argument instead", - DeprecationWarning, - stacklevel=2, - ) - self._timeout = attr.evolve(self._timeout, total=read_timeout) - if conn_timeout is not None: - self._timeout = attr.evolve(self._timeout, connect=conn_timeout) - warnings.warn( - "conn_timeout is deprecated, use timeout argument instead", - DeprecationWarning, - stacklevel=2, - ) - else: - if not isinstance(timeout, ClientTimeout): - raise ValueError( - f"timeout parameter cannot be of {type(timeout)} type, " - "please use 'timeout=ClientTimeout(...)'", - ) - self._timeout = timeout - if read_timeout is not sentinel: - raise ValueError( - "read_timeout and timeout parameters " - "conflict, please setup " - "timeout.read" - ) - if conn_timeout is not None: - raise ValueError( - "conn_timeout and timeout parameters " - "conflict, please setup " - "timeout.connect" - ) - - if ssl_shutdown_timeout is not sentinel: - warnings.warn( - "The ssl_shutdown_timeout parameter is deprecated and will be removed in aiohttp 4.0", - DeprecationWarning, - stacklevel=2, - ) - - if connector is None: - connector = TCPConnector( - loop=loop, ssl_shutdown_timeout=ssl_shutdown_timeout - ) - - if connector._loop is not loop: - raise RuntimeError("Session and connector has to use same event loop") - - self._loop = loop - - if loop.get_debug(): - self._source_traceback = traceback.extract_stack(sys._getframe(1)) - - if cookie_jar is None: - cookie_jar = CookieJar(loop=loop) - self._cookie_jar = cookie_jar - - if cookies: - self._cookie_jar.update_cookies(cookies) - - self._connector = connector - self._connector_owner = connector_owner - self._default_auth = auth - self._version = version - self._json_serialize = json_serialize - self._raise_for_status = raise_for_status - self._auto_decompress = auto_decompress - self._trust_env = trust_env - self._requote_redirect_url = requote_redirect_url - self._read_bufsize = read_bufsize - self._max_line_size = max_line_size - self._max_field_size = max_field_size - self._max_headers = max_headers - - # Convert to list of tuples - if headers: - real_headers: CIMultiDict[str] = CIMultiDict(headers) - else: - real_headers = CIMultiDict() - self._default_headers: CIMultiDict[str] = real_headers - if skip_auto_headers is not None: - self._skip_auto_headers = frozenset(istr(i) for i in skip_auto_headers) - else: - self._skip_auto_headers = frozenset() - - self._request_class = request_class - self._response_class = response_class - self._ws_response_class = ws_response_class - - self._trace_configs = trace_configs or [] - for trace_config in self._trace_configs: - trace_config.freeze() - - self._resolve_charset = fallback_charset_resolver - - self._default_proxy = proxy - self._default_proxy_auth = proxy_auth - self._retry_connection: bool = True - self._middlewares = middlewares - - def __init_subclass__(cls: Type["ClientSession"]) -> None: - warnings.warn( - "Inheritance class {} from ClientSession " - "is discouraged".format(cls.__name__), - DeprecationWarning, - stacklevel=2, - ) - - if DEBUG: - - def __setattr__(self, name: str, val: Any) -> None: - if name not in self.ATTRS: - warnings.warn( - "Setting custom ClientSession.{} attribute " - "is discouraged".format(name), - DeprecationWarning, - stacklevel=2, - ) - super().__setattr__(name, val) - - def __del__(self, _warnings: Any = warnings) -> None: - if not self.closed: - kwargs = {"source": self} - _warnings.warn( - f"Unclosed client session {self!r}", ResourceWarning, **kwargs - ) - context = {"client_session": self, "message": "Unclosed client session"} - if self._source_traceback is not None: - context["source_traceback"] = self._source_traceback - self._loop.call_exception_handler(context) - - if sys.version_info >= (3, 11) and TYPE_CHECKING: - - def request( - self, - method: str, - url: StrOrURL, - **kwargs: Unpack[_RequestOptions], - ) -> "_RequestContextManager": ... - - else: - - def request( - self, method: str, url: StrOrURL, **kwargs: Any - ) -> "_RequestContextManager": - """Perform HTTP request.""" - return _RequestContextManager(self._request(method, url, **kwargs)) - - def _build_url(self, str_or_url: StrOrURL) -> URL: - url = URL(str_or_url) - if self._base_url and not url.absolute: - return self._base_url.join(url) - return url - - async def _request( - self, - method: str, - str_or_url: StrOrURL, - *, - params: Query = None, - data: Any = None, - json: Any = None, - cookies: Optional[LooseCookies] = None, - headers: Optional[LooseHeaders] = None, - skip_auto_headers: Optional[Iterable[str]] = None, - auth: Optional[BasicAuth] = None, - allow_redirects: bool = True, - max_redirects: int = 10, - compress: Union[str, bool, None] = None, - chunked: Optional[bool] = None, - expect100: bool = False, - raise_for_status: Union[ - None, bool, Callable[[ClientResponse], Awaitable[None]] - ] = None, - read_until_eof: bool = True, - proxy: Optional[StrOrURL] = None, - proxy_auth: Optional[BasicAuth] = None, - timeout: Union[ClientTimeout, _SENTINEL] = sentinel, - verify_ssl: Optional[bool] = None, - fingerprint: Optional[bytes] = None, - ssl_context: Optional[SSLContext] = None, - ssl: Union[SSLContext, bool, Fingerprint] = True, - server_hostname: Optional[str] = None, - proxy_headers: Optional[LooseHeaders] = None, - trace_request_ctx: Optional[Mapping[str, Any]] = None, - read_bufsize: Optional[int] = None, - auto_decompress: Optional[bool] = None, - max_line_size: Optional[int] = None, - max_field_size: Optional[int] = None, - max_headers: Optional[int] = None, - middlewares: Optional[Sequence[ClientMiddlewareType]] = None, - ) -> ClientResponse: - - # NOTE: timeout clamps existing connect and read timeouts. We cannot - # set the default to None because we need to detect if the user wants - # to use the existing timeouts by setting timeout to None. - - if self.closed: - raise RuntimeError("Session is closed") - - ssl = _merge_ssl_params(ssl, verify_ssl, ssl_context, fingerprint) - - if data is not None and json is not None: - raise ValueError( - "data and json parameters can not be used at the same time" - ) - elif json is not None: - data = payload.JsonPayload(json, dumps=self._json_serialize) - - if not isinstance(chunked, bool) and chunked is not None: - warnings.warn("Chunk size is deprecated #1615", DeprecationWarning) - - redirects = 0 - history: List[ClientResponse] = [] - version = self._version - params = params or {} - - # Merge with default headers and transform to CIMultiDict - headers = self._prepare_headers(headers) - - try: - url = self._build_url(str_or_url) - except ValueError as e: - raise InvalidUrlClientError(str_or_url) from e - - assert self._connector is not None - if url.scheme not in self._connector.allowed_protocol_schema_set: - raise NonHttpUrlClientError(url) - - skip_headers: Optional[Iterable[istr]] - if skip_auto_headers is not None: - skip_headers = { - istr(i) for i in skip_auto_headers - } | self._skip_auto_headers - elif self._skip_auto_headers: - skip_headers = self._skip_auto_headers - else: - skip_headers = None - - if proxy is None: - proxy = self._default_proxy - if proxy_auth is None: - proxy_auth = self._default_proxy_auth - - if proxy is None: - proxy_headers = None - else: - proxy_headers = self._prepare_headers(proxy_headers) - try: - proxy = URL(proxy) - except ValueError as e: - raise InvalidURL(proxy) from e - - if timeout is sentinel: - real_timeout: ClientTimeout = self._timeout - else: - if not isinstance(timeout, ClientTimeout): - real_timeout = ClientTimeout(total=timeout) - else: - real_timeout = timeout - # timeout is cumulative for all request operations - # (request, redirects, responses, data consuming) - tm = TimeoutHandle( - self._loop, real_timeout.total, ceil_threshold=real_timeout.ceil_threshold - ) - handle = tm.start() - - if read_bufsize is None: - read_bufsize = self._read_bufsize - - if auto_decompress is None: - auto_decompress = self._auto_decompress - - if max_line_size is None: - max_line_size = self._max_line_size - - if max_field_size is None: - max_field_size = self._max_field_size - - if max_headers is None: - max_headers = self._max_headers - - traces = [ - Trace( - self, - trace_config, - trace_config.trace_config_ctx(trace_request_ctx=trace_request_ctx), - ) - for trace_config in self._trace_configs - ] - - for trace in traces: - await trace.send_request_start(method, url.update_query(params), headers) - - timer = tm.timer() - try: - with timer: - # https://www.rfc-editor.org/rfc/rfc9112.html#name-retrying-requests - retry_persistent_connection = ( - self._retry_connection and method in IDEMPOTENT_METHODS - ) - while True: - url, auth_from_url = strip_auth_from_url(url) - if not url.raw_host: - # NOTE: Bail early, otherwise, causes `InvalidURL` through - # NOTE: `self._request_class()` below. - err_exc_cls = ( - InvalidUrlRedirectClientError - if redirects - else InvalidUrlClientError - ) - raise err_exc_cls(url) - # If `auth` was passed for an already authenticated URL, - # disallow only if this is the initial URL; this is to avoid issues - # with sketchy redirects that are not the caller's responsibility - if not history and (auth and auth_from_url): - raise ValueError( - "Cannot combine AUTH argument with " - "credentials encoded in URL" - ) - - # Override the auth with the one from the URL only if we - # have no auth, or if we got an auth from a redirect URL - if auth is None or (history and auth_from_url is not None): - auth = auth_from_url - - if ( - auth is None - and self._default_auth - and ( - not self._base_url or self._base_url_origin == url.origin() - ) - ): - auth = self._default_auth - - # Try netrc if auth is still None and trust_env is enabled. - if auth is None and self._trust_env and url.host is not None: - auth = await self._loop.run_in_executor( - None, self._get_netrc_auth, url.host - ) - - # It would be confusing if we support explicit - # Authorization header with auth argument - if ( - headers is not None - and auth is not None - and hdrs.AUTHORIZATION in headers - ): - raise ValueError( - "Cannot combine AUTHORIZATION header " - "with AUTH argument or credentials " - "encoded in URL" - ) - - all_cookies = self._cookie_jar.filter_cookies(url) - - if cookies is not None: - tmp_cookie_jar = CookieJar( - quote_cookie=self._cookie_jar.quote_cookie - ) - tmp_cookie_jar.update_cookies(cookies) - req_cookies = tmp_cookie_jar.filter_cookies(url) - if req_cookies: - all_cookies.load(req_cookies) - - proxy_: Optional[URL] = None - if proxy is not None: - proxy_ = URL(proxy) - elif self._trust_env: - with suppress(LookupError): - proxy_, proxy_auth = await asyncio.to_thread( - get_env_proxy_for_url, url - ) - - req = self._request_class( - method, - url, - params=params, - headers=headers, - skip_auto_headers=skip_headers, - data=data, - cookies=all_cookies, - auth=auth, - version=version, - compress=compress, - chunked=chunked, - expect100=expect100, - loop=self._loop, - response_class=self._response_class, - proxy=proxy_, - proxy_auth=proxy_auth, - timer=timer, - session=self, - ssl=ssl if ssl is not None else True, - server_hostname=server_hostname, - proxy_headers=proxy_headers, - traces=traces, - trust_env=self.trust_env, - ) - - async def _connect_and_send_request( - req: ClientRequest, - ) -> ClientResponse: - # connection timeout - assert self._connector is not None - try: - conn = await self._connector.connect( - req, traces=traces, timeout=real_timeout - ) - except asyncio.TimeoutError as exc: - raise ConnectionTimeoutError( - f"Connection timeout to host {req.url}" - ) from exc - - assert conn.protocol is not None - conn.protocol.set_response_params( - timer=timer, - skip_payload=req.method in EMPTY_BODY_METHODS, - read_until_eof=read_until_eof, - auto_decompress=auto_decompress, - read_timeout=real_timeout.sock_read, - read_bufsize=read_bufsize, - timeout_ceil_threshold=self._connector._timeout_ceil_threshold, - max_line_size=max_line_size, - max_field_size=max_field_size, - max_headers=max_headers, - ) - try: - resp = await req.send(conn) - try: - await resp.start(conn) - except BaseException: - resp.close() - raise - except BaseException: - conn.close() - raise - return resp - - # Apply middleware (if any) - per-request middleware overrides session middleware - effective_middlewares = ( - self._middlewares if middlewares is None else middlewares - ) - - if effective_middlewares: - handler = build_client_middlewares( - _connect_and_send_request, effective_middlewares - ) - else: - handler = _connect_and_send_request - - try: - resp = await handler(req) - # Client connector errors should not be retried - except ( - ConnectionTimeoutError, - ClientConnectorError, - ClientConnectorCertificateError, - ClientConnectorSSLError, - ): - raise - except (ClientOSError, ServerDisconnectedError): - if retry_persistent_connection: - retry_persistent_connection = False - continue - raise - except ClientError: - raise - except OSError as exc: - if exc.errno is None and isinstance(exc, asyncio.TimeoutError): - raise - raise ClientOSError(*exc.args) from exc - - # Update cookies from raw headers to preserve duplicates - if resp._raw_cookie_headers: - self._cookie_jar.update_cookies_from_headers( - resp._raw_cookie_headers, resp.url - ) - - # redirects - if resp.status in (301, 302, 303, 307, 308) and allow_redirects: - - for trace in traces: - await trace.send_request_redirect( - method, url.update_query(params), headers, resp - ) - - redirects += 1 - history.append(resp) - if max_redirects and redirects >= max_redirects: - if req._body is not None: - await req._body.close() - resp.close() - raise TooManyRedirects( - history[0].request_info, tuple(history) - ) - - # For 301 and 302, mimic IE, now changed in RFC - # https://github.com/kennethreitz/requests/pull/269 - if (resp.status == 303 and resp.method != hdrs.METH_HEAD) or ( - resp.status in (301, 302) and resp.method == hdrs.METH_POST - ): - method = hdrs.METH_GET - data = None - if headers.get(hdrs.CONTENT_LENGTH): - headers.pop(hdrs.CONTENT_LENGTH) - else: - # For 307/308, always preserve the request body - # For 301/302 with non-POST methods, preserve the request body - # https://www.rfc-editor.org/rfc/rfc9110#section-15.4.3-3.1 - # Use the existing payload to avoid recreating it from a potentially consumed file - data = req._body - - r_url = resp.headers.get(hdrs.LOCATION) or resp.headers.get( - hdrs.URI - ) - if r_url is None: - # see github.com/aio-libs/aiohttp/issues/2022 - break - else: - # reading from correct redirection - # response is forbidden - resp.release() - - try: - parsed_redirect_url = URL( - r_url, encoded=not self._requote_redirect_url - ) - except ValueError as e: - if req._body is not None: - await req._body.close() - resp.close() - raise InvalidUrlRedirectClientError( - r_url, - "Server attempted redirecting to a location that does not look like a URL", - ) from e - - scheme = parsed_redirect_url.scheme - if scheme not in HTTP_AND_EMPTY_SCHEMA_SET: - if req._body is not None: - await req._body.close() - resp.close() - raise NonHttpUrlRedirectClientError(r_url) - elif not scheme: - parsed_redirect_url = url.join(parsed_redirect_url) - - try: - redirect_origin = parsed_redirect_url.origin() - except ValueError as origin_val_err: - if req._body is not None: - await req._body.close() - resp.close() - raise InvalidUrlRedirectClientError( - parsed_redirect_url, - "Invalid redirect URL origin", - ) from origin_val_err - - if url.origin() != redirect_origin: - auth = None - headers.pop(hdrs.AUTHORIZATION, None) - headers.pop(hdrs.COOKIE, None) - headers.pop(hdrs.PROXY_AUTHORIZATION, None) - - url = parsed_redirect_url - params = {} - resp.release() - continue - - break - - if req._body is not None: - await req._body.close() - # check response status - if raise_for_status is None: - raise_for_status = self._raise_for_status - - if raise_for_status is None: - pass - elif callable(raise_for_status): - await raise_for_status(resp) - elif raise_for_status: - resp.raise_for_status() - - # register connection - if handle is not None: - if resp.connection is not None: - resp.connection.add_callback(handle.cancel) - else: - handle.cancel() - - resp._history = tuple(history) - - for trace in traces: - await trace.send_request_end( - method, url.update_query(params), headers, resp - ) - return resp - - except BaseException as e: - # cleanup timer - tm.close() - if handle: - handle.cancel() - handle = None - - for trace in traces: - await trace.send_request_exception( - method, url.update_query(params), headers, e - ) - raise - - def ws_connect( - self, - url: StrOrURL, - *, - method: str = hdrs.METH_GET, - protocols: Iterable[str] = (), - timeout: Union[ClientWSTimeout, _SENTINEL] = sentinel, - receive_timeout: Optional[float] = None, - autoclose: bool = True, - autoping: bool = True, - heartbeat: Optional[float] = None, - auth: Optional[BasicAuth] = None, - origin: Optional[str] = None, - params: Query = None, - headers: Optional[LooseHeaders] = None, - proxy: Optional[StrOrURL] = None, - proxy_auth: Optional[BasicAuth] = None, - ssl: Union[SSLContext, bool, Fingerprint] = True, - verify_ssl: Optional[bool] = None, - fingerprint: Optional[bytes] = None, - ssl_context: Optional[SSLContext] = None, - server_hostname: Optional[str] = None, - proxy_headers: Optional[LooseHeaders] = None, - compress: int = 0, - max_msg_size: int = 4 * 1024 * 1024, - ) -> "_WSRequestContextManager": - """Initiate websocket connection.""" - return _WSRequestContextManager( - self._ws_connect( - url, - method=method, - protocols=protocols, - timeout=timeout, - receive_timeout=receive_timeout, - autoclose=autoclose, - autoping=autoping, - heartbeat=heartbeat, - auth=auth, - origin=origin, - params=params, - headers=headers, - proxy=proxy, - proxy_auth=proxy_auth, - ssl=ssl, - verify_ssl=verify_ssl, - fingerprint=fingerprint, - ssl_context=ssl_context, - server_hostname=server_hostname, - proxy_headers=proxy_headers, - compress=compress, - max_msg_size=max_msg_size, - ) - ) - - async def _ws_connect( - self, - url: StrOrURL, - *, - method: str = hdrs.METH_GET, - protocols: Iterable[str] = (), - timeout: Union[ClientWSTimeout, _SENTINEL] = sentinel, - receive_timeout: Optional[float] = None, - autoclose: bool = True, - autoping: bool = True, - heartbeat: Optional[float] = None, - auth: Optional[BasicAuth] = None, - origin: Optional[str] = None, - params: Query = None, - headers: Optional[LooseHeaders] = None, - proxy: Optional[StrOrURL] = None, - proxy_auth: Optional[BasicAuth] = None, - ssl: Union[SSLContext, bool, Fingerprint] = True, - verify_ssl: Optional[bool] = None, - fingerprint: Optional[bytes] = None, - ssl_context: Optional[SSLContext] = None, - server_hostname: Optional[str] = None, - proxy_headers: Optional[LooseHeaders] = None, - compress: int = 0, - max_msg_size: int = 4 * 1024 * 1024, - ) -> ClientWebSocketResponse: - if timeout is not sentinel: - if isinstance(timeout, ClientWSTimeout): - ws_timeout = timeout - else: - warnings.warn( - "parameter 'timeout' of type 'float' " - "is deprecated, please use " - "'timeout=ClientWSTimeout(ws_close=...)'", - DeprecationWarning, - stacklevel=2, - ) - ws_timeout = ClientWSTimeout(ws_close=timeout) - else: - ws_timeout = DEFAULT_WS_CLIENT_TIMEOUT - if receive_timeout is not None: - warnings.warn( - "float parameter 'receive_timeout' " - "is deprecated, please use parameter " - "'timeout=ClientWSTimeout(ws_receive=...)'", - DeprecationWarning, - stacklevel=2, - ) - ws_timeout = attr.evolve(ws_timeout, ws_receive=receive_timeout) - - if headers is None: - real_headers: CIMultiDict[str] = CIMultiDict() - else: - real_headers = CIMultiDict(headers) - - default_headers = { - hdrs.UPGRADE: "websocket", - hdrs.CONNECTION: "Upgrade", - hdrs.SEC_WEBSOCKET_VERSION: "13", - } - - for key, value in default_headers.items(): - real_headers.setdefault(key, value) - - sec_key = base64.b64encode(os.urandom(16)) - real_headers[hdrs.SEC_WEBSOCKET_KEY] = sec_key.decode() - - if protocols: - real_headers[hdrs.SEC_WEBSOCKET_PROTOCOL] = ",".join(protocols) - if origin is not None: - real_headers[hdrs.ORIGIN] = origin - if compress: - extstr = ws_ext_gen(compress=compress) - real_headers[hdrs.SEC_WEBSOCKET_EXTENSIONS] = extstr - - # For the sake of backward compatibility, if user passes in None, convert it to True - if ssl is None: - warnings.warn( - "ssl=None is deprecated, please use ssl=True", - DeprecationWarning, - stacklevel=2, - ) - ssl = True - ssl = _merge_ssl_params(ssl, verify_ssl, ssl_context, fingerprint) - - # send request - resp = await self.request( - method, - url, - params=params, - headers=real_headers, - read_until_eof=False, - auth=auth, - proxy=proxy, - proxy_auth=proxy_auth, - ssl=ssl, - server_hostname=server_hostname, - proxy_headers=proxy_headers, - ) - - try: - # check handshake - if resp.status != 101: - raise WSServerHandshakeError( - resp.request_info, - resp.history, - message="Invalid response status", - status=resp.status, - headers=resp.headers, - ) - - if resp.headers.get(hdrs.UPGRADE, "").lower() != "websocket": - raise WSServerHandshakeError( - resp.request_info, - resp.history, - message="Invalid upgrade header", - status=resp.status, - headers=resp.headers, - ) - - if resp.headers.get(hdrs.CONNECTION, "").lower() != "upgrade": - raise WSServerHandshakeError( - resp.request_info, - resp.history, - message="Invalid connection header", - status=resp.status, - headers=resp.headers, - ) - - # key calculation - r_key = resp.headers.get(hdrs.SEC_WEBSOCKET_ACCEPT, "") - match = base64.b64encode(hashlib.sha1(sec_key + WS_KEY).digest()).decode() - if r_key != match: - raise WSServerHandshakeError( - resp.request_info, - resp.history, - message="Invalid challenge response", - status=resp.status, - headers=resp.headers, - ) - - # websocket protocol - protocol = None - if protocols and hdrs.SEC_WEBSOCKET_PROTOCOL in resp.headers: - resp_protocols = [ - proto.strip() - for proto in resp.headers[hdrs.SEC_WEBSOCKET_PROTOCOL].split(",") - ] - - for proto in resp_protocols: - if proto in protocols: - protocol = proto - break - - # websocket compress - notakeover = False - if compress: - compress_hdrs = resp.headers.get(hdrs.SEC_WEBSOCKET_EXTENSIONS) - if compress_hdrs: - try: - compress, notakeover = ws_ext_parse(compress_hdrs) - except WSHandshakeError as exc: - raise WSServerHandshakeError( - resp.request_info, - resp.history, - message=exc.args[0], - status=resp.status, - headers=resp.headers, - ) from exc - else: - compress = 0 - notakeover = False - - conn = resp.connection - assert conn is not None - conn_proto = conn.protocol - assert conn_proto is not None - - # For WS connection the read_timeout must be either receive_timeout or greater - # None == no timeout, i.e. infinite timeout, so None is the max timeout possible - if ws_timeout.ws_receive is None: - # Reset regardless - conn_proto.read_timeout = None - elif conn_proto.read_timeout is not None: - conn_proto.read_timeout = max( - ws_timeout.ws_receive, conn_proto.read_timeout - ) - - transport = conn.transport - assert transport is not None - reader = WebSocketDataQueue(conn_proto, 2**16, loop=self._loop) - conn_proto.set_parser(WebSocketReader(reader, max_msg_size), reader) - writer = WebSocketWriter( - conn_proto, - transport, - use_mask=True, - compress=compress, - notakeover=notakeover, - ) - except BaseException: - resp.close() - raise - else: - return self._ws_response_class( - reader, - writer, - protocol, - resp, - ws_timeout, - autoclose, - autoping, - self._loop, - heartbeat=heartbeat, - compress=compress, - client_notakeover=notakeover, - ) - - def _prepare_headers(self, headers: Optional[LooseHeaders]) -> "CIMultiDict[str]": - """Add default headers and transform it to CIMultiDict""" - # Convert headers to MultiDict - result = CIMultiDict(self._default_headers) - if headers: - if not isinstance(headers, (MultiDictProxy, MultiDict)): - headers = CIMultiDict(headers) - added_names: Set[str] = set() - for key, value in headers.items(): - if key in added_names: - result.add(key, value) - else: - result[key] = value - added_names.add(key) - return result - - def _get_netrc_auth(self, host: str) -> Optional[BasicAuth]: - """ - Get auth from netrc for the given host. - - This method is designed to be called in an executor to avoid - blocking I/O in the event loop. - """ - netrc_obj = netrc_from_env() - try: - return basicauth_from_netrc(netrc_obj, host) - except LookupError: - return None - - if sys.version_info >= (3, 11) and TYPE_CHECKING: - - def get( - self, - url: StrOrURL, - **kwargs: Unpack[_RequestOptions], - ) -> "_RequestContextManager": ... - - def options( - self, - url: StrOrURL, - **kwargs: Unpack[_RequestOptions], - ) -> "_RequestContextManager": ... - - def head( - self, - url: StrOrURL, - **kwargs: Unpack[_RequestOptions], - ) -> "_RequestContextManager": ... - - def post( - self, - url: StrOrURL, - **kwargs: Unpack[_RequestOptions], - ) -> "_RequestContextManager": ... - - def put( - self, - url: StrOrURL, - **kwargs: Unpack[_RequestOptions], - ) -> "_RequestContextManager": ... - - def patch( - self, - url: StrOrURL, - **kwargs: Unpack[_RequestOptions], - ) -> "_RequestContextManager": ... - - def delete( - self, - url: StrOrURL, - **kwargs: Unpack[_RequestOptions], - ) -> "_RequestContextManager": ... - - else: - - def get( - self, url: StrOrURL, *, allow_redirects: bool = True, **kwargs: Any - ) -> "_RequestContextManager": - """Perform HTTP GET request.""" - return _RequestContextManager( - self._request( - hdrs.METH_GET, url, allow_redirects=allow_redirects, **kwargs - ) - ) - - def options( - self, url: StrOrURL, *, allow_redirects: bool = True, **kwargs: Any - ) -> "_RequestContextManager": - """Perform HTTP OPTIONS request.""" - return _RequestContextManager( - self._request( - hdrs.METH_OPTIONS, url, allow_redirects=allow_redirects, **kwargs - ) - ) - - def head( - self, url: StrOrURL, *, allow_redirects: bool = False, **kwargs: Any - ) -> "_RequestContextManager": - """Perform HTTP HEAD request.""" - return _RequestContextManager( - self._request( - hdrs.METH_HEAD, url, allow_redirects=allow_redirects, **kwargs - ) - ) - - def post( - self, url: StrOrURL, *, data: Any = None, **kwargs: Any - ) -> "_RequestContextManager": - """Perform HTTP POST request.""" - return _RequestContextManager( - self._request(hdrs.METH_POST, url, data=data, **kwargs) - ) - - def put( - self, url: StrOrURL, *, data: Any = None, **kwargs: Any - ) -> "_RequestContextManager": - """Perform HTTP PUT request.""" - return _RequestContextManager( - self._request(hdrs.METH_PUT, url, data=data, **kwargs) - ) - - def patch( - self, url: StrOrURL, *, data: Any = None, **kwargs: Any - ) -> "_RequestContextManager": - """Perform HTTP PATCH request.""" - return _RequestContextManager( - self._request(hdrs.METH_PATCH, url, data=data, **kwargs) - ) - - def delete(self, url: StrOrURL, **kwargs: Any) -> "_RequestContextManager": - """Perform HTTP DELETE request.""" - return _RequestContextManager( - self._request(hdrs.METH_DELETE, url, **kwargs) - ) - - async def close(self) -> None: - """Close underlying connector. - - Release all acquired resources. - """ - if not self.closed: - if self._connector is not None and self._connector_owner: - await self._connector.close() - self._connector = None - - @property - def closed(self) -> bool: - """Is client session closed. - - A readonly property. - """ - return self._connector is None or self._connector.closed - - @property - def connector(self) -> Optional[BaseConnector]: - """Connector instance used for the session.""" - return self._connector - - @property - def cookie_jar(self) -> AbstractCookieJar: - """The session cookies.""" - return self._cookie_jar - - @property - def version(self) -> Tuple[int, int]: - """The session HTTP protocol version.""" - return self._version - - @property - def requote_redirect_url(self) -> bool: - """Do URL requoting on redirection handling.""" - return self._requote_redirect_url - - @requote_redirect_url.setter - def requote_redirect_url(self, val: bool) -> None: - """Do URL requoting on redirection handling.""" - warnings.warn( - "session.requote_redirect_url modification is deprecated #2778", - DeprecationWarning, - stacklevel=2, - ) - self._requote_redirect_url = val - - @property - def loop(self) -> asyncio.AbstractEventLoop: - """Session's loop.""" - warnings.warn( - "client.loop property is deprecated", DeprecationWarning, stacklevel=2 - ) - return self._loop - - @property - def timeout(self) -> ClientTimeout: - """Timeout for the session.""" - return self._timeout - - @property - def headers(self) -> "CIMultiDict[str]": - """The default headers of the client session.""" - return self._default_headers - - @property - def skip_auto_headers(self) -> FrozenSet[istr]: - """Headers for which autogeneration should be skipped""" - return self._skip_auto_headers - - @property - def auth(self) -> Optional[BasicAuth]: - """An object that represents HTTP Basic Authorization""" - return self._default_auth - - @property - def json_serialize(self) -> JSONEncoder: - """Json serializer callable""" - return self._json_serialize - - @property - def connector_owner(self) -> bool: - """Should connector be closed on session closing""" - return self._connector_owner - - @property - def raise_for_status( - self, - ) -> Union[bool, Callable[[ClientResponse], Awaitable[None]]]: - """Should `ClientResponse.raise_for_status()` be called for each response.""" - return self._raise_for_status - - @property - def auto_decompress(self) -> bool: - """Should the body response be automatically decompressed.""" - return self._auto_decompress - - @property - def trust_env(self) -> bool: - """ - Should proxies information from environment or netrc be trusted. - - Information is from HTTP_PROXY / HTTPS_PROXY environment variables - or ~/.netrc file if present. - """ - return self._trust_env - - @property - def trace_configs(self) -> List[TraceConfig]: - """A list of TraceConfig instances used for client tracing""" - return self._trace_configs - - def detach(self) -> None: - """Detach connector from session without closing the former. - - Session is switched to closed state anyway. - """ - self._connector = None - - def __enter__(self) -> None: - raise TypeError("Use async with instead") - - def __exit__( - self, - exc_type: Optional[Type[BaseException]], - exc_val: Optional[BaseException], - exc_tb: Optional[TracebackType], - ) -> None: - # __exit__ should exist in pair with __enter__ but never executed - pass # pragma: no cover - - async def __aenter__(self) -> "ClientSession": - return self - - async def __aexit__( - self, - exc_type: Optional[Type[BaseException]], - exc_val: Optional[BaseException], - exc_tb: Optional[TracebackType], - ) -> None: - await self.close() - - -class _BaseRequestContextManager(Coroutine[Any, Any, _RetType], Generic[_RetType]): - - __slots__ = ("_coro", "_resp") - - def __init__(self, coro: Coroutine["asyncio.Future[Any]", None, _RetType]) -> None: - self._coro: Coroutine["asyncio.Future[Any]", None, _RetType] = coro - - def send(self, arg: None) -> "asyncio.Future[Any]": - return self._coro.send(arg) - - def throw(self, *args: Any, **kwargs: Any) -> "asyncio.Future[Any]": - return self._coro.throw(*args, **kwargs) - - def close(self) -> None: - return self._coro.close() - - def __await__(self) -> Generator[Any, None, _RetType]: - ret = self._coro.__await__() - return ret - - def __iter__(self) -> Generator[Any, None, _RetType]: - return self.__await__() - - async def __aenter__(self) -> _RetType: - self._resp: _RetType = await self._coro - return await self._resp.__aenter__() - - async def __aexit__( - self, - exc_type: Optional[Type[BaseException]], - exc: Optional[BaseException], - tb: Optional[TracebackType], - ) -> None: - await self._resp.__aexit__(exc_type, exc, tb) - - -_RequestContextManager = _BaseRequestContextManager[ClientResponse] -_WSRequestContextManager = _BaseRequestContextManager[ClientWebSocketResponse] - - -class _SessionRequestContextManager: - - __slots__ = ("_coro", "_resp", "_session") - - def __init__( - self, - coro: Coroutine["asyncio.Future[Any]", None, ClientResponse], - session: ClientSession, - ) -> None: - self._coro = coro - self._resp: Optional[ClientResponse] = None - self._session = session - - async def __aenter__(self) -> ClientResponse: - try: - self._resp = await self._coro - except BaseException: - await self._session.close() - raise - else: - return self._resp - - async def __aexit__( - self, - exc_type: Optional[Type[BaseException]], - exc: Optional[BaseException], - tb: Optional[TracebackType], - ) -> None: - assert self._resp is not None - self._resp.close() - await self._session.close() - - -if sys.version_info >= (3, 11) and TYPE_CHECKING: - - def request( - method: str, - url: StrOrURL, - *, - version: HttpVersion = http.HttpVersion11, - connector: Optional[BaseConnector] = None, - loop: Optional[asyncio.AbstractEventLoop] = None, - **kwargs: Unpack[_RequestOptions], - ) -> _SessionRequestContextManager: ... - -else: - - def request( - method: str, - url: StrOrURL, - *, - version: HttpVersion = http.HttpVersion11, - connector: Optional[BaseConnector] = None, - loop: Optional[asyncio.AbstractEventLoop] = None, - **kwargs: Any, - ) -> _SessionRequestContextManager: - """Constructs and sends a request. - - Returns response object. - method - HTTP method - url - request url - params - (optional) Dictionary or bytes to be sent in the query - string of the new request - data - (optional) Dictionary, bytes, or file-like object to - send in the body of the request - json - (optional) Any json compatible python object - headers - (optional) Dictionary of HTTP Headers to send with - the request - cookies - (optional) Dict object to send with the request - auth - (optional) BasicAuth named tuple represent HTTP Basic Auth - auth - aiohttp.helpers.BasicAuth - allow_redirects - (optional) If set to False, do not follow - redirects - version - Request HTTP version. - compress - Set to True if request has to be compressed - with deflate encoding. - chunked - Set to chunk size for chunked transfer encoding. - expect100 - Expect 100-continue response from server. - connector - BaseConnector sub-class instance to support - connection pooling. - read_until_eof - Read response until eof if response - does not have Content-Length header. - loop - Optional event loop. - timeout - Optional ClientTimeout settings structure, 5min - total timeout by default. - Usage:: - >>> import aiohttp - >>> async with aiohttp.request('GET', 'http://python.org/') as resp: - ... print(resp) - ... data = await resp.read() - - """ - connector_owner = False - if connector is None: - connector_owner = True - connector = TCPConnector(loop=loop, force_close=True) - - session = ClientSession( - loop=loop, - cookies=kwargs.pop("cookies", None), - version=version, - timeout=kwargs.pop("timeout", sentinel), - connector=connector, - connector_owner=connector_owner, - ) - - return _SessionRequestContextManager( - session._request(method, url, **kwargs), - session, - ) diff --git a/venv/lib/python3.9/site-packages/aiohttp/client_exceptions.py b/venv/lib/python3.9/site-packages/aiohttp/client_exceptions.py deleted file mode 100644 index 4702da8..0000000 --- a/venv/lib/python3.9/site-packages/aiohttp/client_exceptions.py +++ /dev/null @@ -1,432 +0,0 @@ -"""HTTP related errors.""" - -import asyncio -import warnings -from typing import TYPE_CHECKING, Optional, Tuple, Union - -from multidict import MultiMapping - -from .typedefs import StrOrURL - -if TYPE_CHECKING: - import ssl - - SSLContext = ssl.SSLContext -else: - try: - import ssl - - SSLContext = ssl.SSLContext - except ImportError: # pragma: no cover - ssl = SSLContext = None # type: ignore[assignment] - -if TYPE_CHECKING: - from .client_reqrep import ClientResponse, ConnectionKey, Fingerprint, RequestInfo - from .http_parser import RawResponseMessage -else: - RequestInfo = ClientResponse = ConnectionKey = RawResponseMessage = None - -__all__ = ( - "ClientError", - "ClientConnectionError", - "ClientConnectionResetError", - "ClientOSError", - "ClientConnectorError", - "ClientProxyConnectionError", - "ClientSSLError", - "ClientConnectorDNSError", - "ClientConnectorSSLError", - "ClientConnectorCertificateError", - "ConnectionTimeoutError", - "SocketTimeoutError", - "ServerConnectionError", - "ServerTimeoutError", - "ServerDisconnectedError", - "ServerFingerprintMismatch", - "ClientResponseError", - "ClientHttpProxyError", - "WSServerHandshakeError", - "ContentTypeError", - "ClientPayloadError", - "InvalidURL", - "InvalidUrlClientError", - "RedirectClientError", - "NonHttpUrlClientError", - "InvalidUrlRedirectClientError", - "NonHttpUrlRedirectClientError", - "WSMessageTypeError", -) - - -class ClientError(Exception): - """Base class for client connection errors.""" - - -class ClientResponseError(ClientError): - """Base class for exceptions that occur after getting a response. - - request_info: An instance of RequestInfo. - history: A sequence of responses, if redirects occurred. - status: HTTP status code. - message: Error message. - headers: Response headers. - """ - - def __init__( - self, - request_info: RequestInfo, - history: Tuple[ClientResponse, ...], - *, - code: Optional[int] = None, - status: Optional[int] = None, - message: str = "", - headers: Optional[MultiMapping[str]] = None, - ) -> None: - self.request_info = request_info - if code is not None: - if status is not None: - raise ValueError( - "Both code and status arguments are provided; " - "code is deprecated, use status instead" - ) - warnings.warn( - "code argument is deprecated, use status instead", - DeprecationWarning, - stacklevel=2, - ) - if status is not None: - self.status = status - elif code is not None: - self.status = code - else: - self.status = 0 - self.message = message - self.headers = headers - self.history = history - self.args = (request_info, history) - - def __str__(self) -> str: - return "{}, message={!r}, url={!r}".format( - self.status, - self.message, - str(self.request_info.real_url), - ) - - def __repr__(self) -> str: - args = f"{self.request_info!r}, {self.history!r}" - if self.status != 0: - args += f", status={self.status!r}" - if self.message != "": - args += f", message={self.message!r}" - if self.headers is not None: - args += f", headers={self.headers!r}" - return f"{type(self).__name__}({args})" - - @property - def code(self) -> int: - warnings.warn( - "code property is deprecated, use status instead", - DeprecationWarning, - stacklevel=2, - ) - return self.status - - @code.setter - def code(self, value: int) -> None: - warnings.warn( - "code property is deprecated, use status instead", - DeprecationWarning, - stacklevel=2, - ) - self.status = value - - -class ContentTypeError(ClientResponseError): - """ContentType found is not valid.""" - - -class WSServerHandshakeError(ClientResponseError): - """websocket server handshake error.""" - - -class ClientHttpProxyError(ClientResponseError): - """HTTP proxy error. - - Raised in :class:`aiohttp.connector.TCPConnector` if - proxy responds with status other than ``200 OK`` - on ``CONNECT`` request. - """ - - -class TooManyRedirects(ClientResponseError): - """Client was redirected too many times.""" - - -class ClientConnectionError(ClientError): - """Base class for client socket errors.""" - - -class ClientConnectionResetError(ClientConnectionError, ConnectionResetError): - """ConnectionResetError""" - - -class ClientOSError(ClientConnectionError, OSError): - """OSError error.""" - - -class ClientConnectorError(ClientOSError): - """Client connector error. - - Raised in :class:`aiohttp.connector.TCPConnector` if - a connection can not be established. - """ - - def __init__(self, connection_key: ConnectionKey, os_error: OSError) -> None: - self._conn_key = connection_key - self._os_error = os_error - super().__init__(os_error.errno, os_error.strerror) - self.args = (connection_key, os_error) - - @property - def os_error(self) -> OSError: - return self._os_error - - @property - def host(self) -> str: - return self._conn_key.host - - @property - def port(self) -> Optional[int]: - return self._conn_key.port - - @property - def ssl(self) -> Union[SSLContext, bool, "Fingerprint"]: - return self._conn_key.ssl - - def __str__(self) -> str: - return "Cannot connect to host {0.host}:{0.port} ssl:{1} [{2}]".format( - self, "default" if self.ssl is True else self.ssl, self.strerror - ) - - # OSError.__reduce__ does too much black magick - __reduce__ = BaseException.__reduce__ - - -class ClientConnectorDNSError(ClientConnectorError): - """DNS resolution failed during client connection. - - Raised in :class:`aiohttp.connector.TCPConnector` if - DNS resolution fails. - """ - - -class ClientProxyConnectionError(ClientConnectorError): - """Proxy connection error. - - Raised in :class:`aiohttp.connector.TCPConnector` if - connection to proxy can not be established. - """ - - -class UnixClientConnectorError(ClientConnectorError): - """Unix connector error. - - Raised in :py:class:`aiohttp.connector.UnixConnector` - if connection to unix socket can not be established. - """ - - def __init__( - self, path: str, connection_key: ConnectionKey, os_error: OSError - ) -> None: - self._path = path - super().__init__(connection_key, os_error) - - @property - def path(self) -> str: - return self._path - - def __str__(self) -> str: - return "Cannot connect to unix socket {0.path} ssl:{1} [{2}]".format( - self, "default" if self.ssl is True else self.ssl, self.strerror - ) - - -class ServerConnectionError(ClientConnectionError): - """Server connection errors.""" - - -class ServerDisconnectedError(ServerConnectionError): - """Server disconnected.""" - - def __init__(self, message: Union[RawResponseMessage, str, None] = None) -> None: - if message is None: - message = "Server disconnected" - - self.args = (message,) - self.message = message - - -class ServerTimeoutError(ServerConnectionError, asyncio.TimeoutError): - """Server timeout error.""" - - -class ConnectionTimeoutError(ServerTimeoutError): - """Connection timeout error.""" - - -class SocketTimeoutError(ServerTimeoutError): - """Socket timeout error.""" - - -class ServerFingerprintMismatch(ServerConnectionError): - """SSL certificate does not match expected fingerprint.""" - - def __init__(self, expected: bytes, got: bytes, host: str, port: int) -> None: - self.expected = expected - self.got = got - self.host = host - self.port = port - self.args = (expected, got, host, port) - - def __repr__(self) -> str: - return "<{} expected={!r} got={!r} host={!r} port={!r}>".format( - self.__class__.__name__, self.expected, self.got, self.host, self.port - ) - - -class ClientPayloadError(ClientError): - """Response payload error.""" - - -class InvalidURL(ClientError, ValueError): - """Invalid URL. - - URL used for fetching is malformed, e.g. it doesn't contains host - part. - """ - - # Derive from ValueError for backward compatibility - - def __init__(self, url: StrOrURL, description: Union[str, None] = None) -> None: - # The type of url is not yarl.URL because the exception can be raised - # on URL(url) call - self._url = url - self._description = description - - if description: - super().__init__(url, description) - else: - super().__init__(url) - - @property - def url(self) -> StrOrURL: - return self._url - - @property - def description(self) -> "str | None": - return self._description - - def __repr__(self) -> str: - return f"<{self.__class__.__name__} {self}>" - - def __str__(self) -> str: - if self._description: - return f"{self._url} - {self._description}" - return str(self._url) - - -class InvalidUrlClientError(InvalidURL): - """Invalid URL client error.""" - - -class RedirectClientError(ClientError): - """Client redirect error.""" - - -class NonHttpUrlClientError(ClientError): - """Non http URL client error.""" - - -class InvalidUrlRedirectClientError(InvalidUrlClientError, RedirectClientError): - """Invalid URL redirect client error.""" - - -class NonHttpUrlRedirectClientError(NonHttpUrlClientError, RedirectClientError): - """Non http URL redirect client error.""" - - -class ClientSSLError(ClientConnectorError): - """Base error for ssl.*Errors.""" - - -if ssl is not None: - cert_errors = (ssl.CertificateError,) - cert_errors_bases = ( - ClientSSLError, - ssl.CertificateError, - ) - - ssl_errors = (ssl.SSLError,) - ssl_error_bases = (ClientSSLError, ssl.SSLError) -else: # pragma: no cover - cert_errors = tuple() - cert_errors_bases = ( - ClientSSLError, - ValueError, - ) - - ssl_errors = tuple() - ssl_error_bases = (ClientSSLError,) - - -class ClientConnectorSSLError(*ssl_error_bases): # type: ignore[misc] - """Response ssl error.""" - - -class ClientConnectorCertificateError(*cert_errors_bases): # type: ignore[misc] - """Response certificate error.""" - - _conn_key: ConnectionKey - - def __init__( - # TODO: If we require ssl in future, this can become ssl.CertificateError - self, - connection_key: ConnectionKey, - certificate_error: Exception, - ) -> None: - if isinstance(certificate_error, cert_errors + (OSError,)): - # ssl.CertificateError has errno and strerror, so we should be fine - os_error = certificate_error - else: - os_error = OSError() - - super().__init__(connection_key, os_error) - self._certificate_error = certificate_error - self.args = (connection_key, certificate_error) - - @property - def certificate_error(self) -> Exception: - return self._certificate_error - - @property - def host(self) -> str: - return self._conn_key.host - - @property - def port(self) -> Optional[int]: - return self._conn_key.port - - @property - def ssl(self) -> bool: - return self._conn_key.is_ssl - - def __str__(self) -> str: - return ( - "Cannot connect to host {0.host}:{0.port} ssl:{0.ssl} " - "[{0.certificate_error.__class__.__name__}: " - "{0.certificate_error.args}]".format(self) - ) - - -class WSMessageTypeError(TypeError): - """WebSocket message type is not valid.""" diff --git a/venv/lib/python3.9/site-packages/aiohttp/client_middleware_digest_auth.py b/venv/lib/python3.9/site-packages/aiohttp/client_middleware_digest_auth.py deleted file mode 100644 index d7f2f1e..0000000 --- a/venv/lib/python3.9/site-packages/aiohttp/client_middleware_digest_auth.py +++ /dev/null @@ -1,480 +0,0 @@ -""" -Digest authentication middleware for aiohttp client. - -This middleware implements HTTP Digest Authentication according to RFC 7616, -providing a more secure alternative to Basic Authentication. It supports all -standard hash algorithms including MD5, SHA, SHA-256, SHA-512 and their session -variants, as well as both 'auth' and 'auth-int' quality of protection (qop) options. -""" - -import hashlib -import os -import re -import sys -import time -from typing import ( - Callable, - Dict, - Final, - FrozenSet, - List, - Literal, - Tuple, - TypedDict, - Union, -) - -from yarl import URL - -from . import hdrs -from .client_exceptions import ClientError -from .client_middlewares import ClientHandlerType -from .client_reqrep import ClientRequest, ClientResponse -from .payload import Payload - - -class DigestAuthChallenge(TypedDict, total=False): - realm: str - nonce: str - qop: str - algorithm: str - opaque: str - domain: str - stale: str - - -DigestFunctions: Dict[str, Callable[[bytes], "hashlib._Hash"]] = { - "MD5": hashlib.md5, - "MD5-SESS": hashlib.md5, - "SHA": hashlib.sha1, - "SHA-SESS": hashlib.sha1, - "SHA256": hashlib.sha256, - "SHA256-SESS": hashlib.sha256, - "SHA-256": hashlib.sha256, - "SHA-256-SESS": hashlib.sha256, - "SHA512": hashlib.sha512, - "SHA512-SESS": hashlib.sha512, - "SHA-512": hashlib.sha512, - "SHA-512-SESS": hashlib.sha512, -} - - -# Compile the regex pattern once at module level for performance -_HEADER_PAIRS_PATTERN = re.compile( - r'(?:^|\s|,\s*)(\w+)\s*=\s*(?:"((?:[^"\\]|\\.)*)"|([^\s,]+))' - if sys.version_info < (3, 11) - else r'(?:^|\s|,\s*)((?>\w+))\s*=\s*(?:"((?:[^"\\]|\\.)*)"|([^\s,]+))' - # +------------|--------|--|-|-|--|----|------|----|--||-----|-> Match valid start/sep - # +--------|--|-|-|--|----|------|----|--||-----|-> alphanumeric key (atomic - # | | | | | | | | || | group reduces backtracking) - # +--|-|-|--|----|------|----|--||-----|-> maybe whitespace - # | | | | | | | || | - # +-|-|--|----|------|----|--||-----|-> = (delimiter) - # +-|--|----|------|----|--||-----|-> maybe whitespace - # | | | | | || | - # +--|----|------|----|--||-----|-> group quoted or unquoted - # | | | | || | - # +----|------|----|--||-----|-> if quoted... - # +------|----|--||-----|-> anything but " or \ - # +----|--||-----|-> escaped characters allowed - # +--||-----|-> or can be empty string - # || | - # +|-----|-> if unquoted... - # +-----|-> anything but , or - # +-> at least one char req'd -) - - -# RFC 7616: Challenge parameters to extract -CHALLENGE_FIELDS: Final[ - Tuple[ - Literal["realm", "nonce", "qop", "algorithm", "opaque", "domain", "stale"], ... - ] -] = ( - "realm", - "nonce", - "qop", - "algorithm", - "opaque", - "domain", - "stale", -) - -# Supported digest authentication algorithms -# Use a tuple of sorted keys for predictable documentation and error messages -SUPPORTED_ALGORITHMS: Final[Tuple[str, ...]] = tuple(sorted(DigestFunctions.keys())) - -# RFC 7616: Fields that require quoting in the Digest auth header -# These fields must be enclosed in double quotes in the Authorization header. -# Algorithm, qop, and nc are never quoted per RFC specifications. -# This frozen set is used by the template-based header construction to -# automatically determine which fields need quotes. -QUOTED_AUTH_FIELDS: Final[FrozenSet[str]] = frozenset( - {"username", "realm", "nonce", "uri", "response", "opaque", "cnonce"} -) - - -def escape_quotes(value: str) -> str: - """Escape double quotes for HTTP header values.""" - return value.replace('"', '\\"') - - -def unescape_quotes(value: str) -> str: - """Unescape double quotes in HTTP header values.""" - return value.replace('\\"', '"') - - -def parse_header_pairs(header: str) -> Dict[str, str]: - """ - Parse key-value pairs from WWW-Authenticate or similar HTTP headers. - - This function handles the complex format of WWW-Authenticate header values, - supporting both quoted and unquoted values, proper handling of commas in - quoted values, and whitespace variations per RFC 7616. - - Examples of supported formats: - - key1="value1", key2=value2 - - key1 = "value1" , key2="value, with, commas" - - key1=value1,key2="value2" - - realm="example.com", nonce="12345", qop="auth" - - Args: - header: The header value string to parse - - Returns: - Dictionary mapping parameter names to their values - """ - return { - stripped_key: unescape_quotes(quoted_val) if quoted_val else unquoted_val - for key, quoted_val, unquoted_val in _HEADER_PAIRS_PATTERN.findall(header) - if (stripped_key := key.strip()) - } - - -class DigestAuthMiddleware: - """ - HTTP digest authentication middleware for aiohttp client. - - This middleware intercepts 401 Unauthorized responses containing a Digest - authentication challenge, calculates the appropriate digest credentials, - and automatically retries the request with the proper Authorization header. - - Features: - - Handles all aspects of Digest authentication handshake automatically - - Supports all standard hash algorithms: - - MD5, MD5-SESS - - SHA, SHA-SESS - - SHA256, SHA256-SESS, SHA-256, SHA-256-SESS - - SHA512, SHA512-SESS, SHA-512, SHA-512-SESS - - Supports 'auth' and 'auth-int' quality of protection modes - - Properly handles quoted strings and parameter parsing - - Includes replay attack protection with client nonce count tracking - - Supports preemptive authentication per RFC 7616 Section 3.6 - - Standards compliance: - - RFC 7616: HTTP Digest Access Authentication (primary reference) - - RFC 2617: HTTP Authentication (deprecated by RFC 7616) - - RFC 1945: Section 11.1 (username restrictions) - - Implementation notes: - The core digest calculation is inspired by the implementation in - https://github.com/requests/requests/blob/v2.18.4/requests/auth.py - with added support for modern digest auth features and error handling. - """ - - def __init__( - self, - login: str, - password: str, - preemptive: bool = True, - ) -> None: - if login is None: - raise ValueError("None is not allowed as login value") - - if password is None: - raise ValueError("None is not allowed as password value") - - if ":" in login: - raise ValueError('A ":" is not allowed in username (RFC 1945#section-11.1)') - - self._login_str: Final[str] = login - self._login_bytes: Final[bytes] = login.encode("utf-8") - self._password_bytes: Final[bytes] = password.encode("utf-8") - - self._last_nonce_bytes = b"" - self._nonce_count = 0 - self._challenge: DigestAuthChallenge = {} - self._preemptive: bool = preemptive - # Set of URLs defining the protection space - self._protection_space: List[str] = [] - - async def _encode( - self, method: str, url: URL, body: Union[Payload, Literal[b""]] - ) -> str: - """ - Build digest authorization header for the current challenge. - - Args: - method: The HTTP method (GET, POST, etc.) - url: The request URL - body: The request body (used for qop=auth-int) - - Returns: - A fully formatted Digest authorization header string - - Raises: - ClientError: If the challenge is missing required parameters or - contains unsupported values - - """ - challenge = self._challenge - if "realm" not in challenge: - raise ClientError( - "Malformed Digest auth challenge: Missing 'realm' parameter" - ) - - if "nonce" not in challenge: - raise ClientError( - "Malformed Digest auth challenge: Missing 'nonce' parameter" - ) - - # Empty realm values are allowed per RFC 7616 (SHOULD, not MUST, contain host name) - realm = challenge["realm"] - nonce = challenge["nonce"] - - # Empty nonce values are not allowed as they are security-critical for replay protection - if not nonce: - raise ClientError( - "Security issue: Digest auth challenge contains empty 'nonce' value" - ) - - qop_raw = challenge.get("qop", "") - # Preserve original algorithm case for response while using uppercase for processing - algorithm_original = challenge.get("algorithm", "MD5") - algorithm = algorithm_original.upper() - opaque = challenge.get("opaque", "") - - # Convert string values to bytes once - nonce_bytes = nonce.encode("utf-8") - realm_bytes = realm.encode("utf-8") - path = URL(url).path_qs - - # Process QoP - qop = "" - qop_bytes = b"" - if qop_raw: - valid_qops = {"auth", "auth-int"}.intersection( - {q.strip() for q in qop_raw.split(",") if q.strip()} - ) - if not valid_qops: - raise ClientError( - f"Digest auth error: Unsupported Quality of Protection (qop) value(s): {qop_raw}" - ) - - qop = "auth-int" if "auth-int" in valid_qops else "auth" - qop_bytes = qop.encode("utf-8") - - if algorithm not in DigestFunctions: - raise ClientError( - f"Digest auth error: Unsupported hash algorithm: {algorithm}. " - f"Supported algorithms: {', '.join(SUPPORTED_ALGORITHMS)}" - ) - hash_fn: Final = DigestFunctions[algorithm] - - def H(x: bytes) -> bytes: - """RFC 7616 Section 3: Hash function H(data) = hex(hash(data)).""" - return hash_fn(x).hexdigest().encode() - - def KD(s: bytes, d: bytes) -> bytes: - """RFC 7616 Section 3: KD(secret, data) = H(concat(secret, ":", data)).""" - return H(b":".join((s, d))) - - # Calculate A1 and A2 - A1 = b":".join((self._login_bytes, realm_bytes, self._password_bytes)) - A2 = f"{method.upper()}:{path}".encode() - if qop == "auth-int": - if isinstance(body, Payload): # will always be empty bytes unless Payload - entity_bytes = await body.as_bytes() # Get bytes from Payload - else: - entity_bytes = body - entity_hash = H(entity_bytes) - A2 = b":".join((A2, entity_hash)) - - HA1 = H(A1) - HA2 = H(A2) - - # Nonce count handling - if nonce_bytes == self._last_nonce_bytes: - self._nonce_count += 1 - else: - self._nonce_count = 1 - - self._last_nonce_bytes = nonce_bytes - ncvalue = f"{self._nonce_count:08x}" - ncvalue_bytes = ncvalue.encode("utf-8") - - # Generate client nonce - cnonce = hashlib.sha1( - b"".join( - [ - str(self._nonce_count).encode("utf-8"), - nonce_bytes, - time.ctime().encode("utf-8"), - os.urandom(8), - ] - ) - ).hexdigest()[:16] - cnonce_bytes = cnonce.encode("utf-8") - - # Special handling for session-based algorithms - if algorithm.upper().endswith("-SESS"): - HA1 = H(b":".join((HA1, nonce_bytes, cnonce_bytes))) - - # Calculate the response digest - if qop: - noncebit = b":".join( - (nonce_bytes, ncvalue_bytes, cnonce_bytes, qop_bytes, HA2) - ) - response_digest = KD(HA1, noncebit) - else: - response_digest = KD(HA1, b":".join((nonce_bytes, HA2))) - - # Define a dict mapping of header fields to their values - # Group fields into always-present, optional, and qop-dependent - header_fields = { - # Always present fields - "username": escape_quotes(self._login_str), - "realm": escape_quotes(realm), - "nonce": escape_quotes(nonce), - "uri": path, - "response": response_digest.decode(), - "algorithm": algorithm_original, - } - - # Optional fields - if opaque: - header_fields["opaque"] = escape_quotes(opaque) - - # QoP-dependent fields - if qop: - header_fields["qop"] = qop - header_fields["nc"] = ncvalue - header_fields["cnonce"] = cnonce - - # Build header using templates for each field type - pairs: List[str] = [] - for field, value in header_fields.items(): - if field in QUOTED_AUTH_FIELDS: - pairs.append(f'{field}="{value}"') - else: - pairs.append(f"{field}={value}") - - return f"Digest {', '.join(pairs)}" - - def _in_protection_space(self, url: URL) -> bool: - """ - Check if the given URL is within the current protection space. - - According to RFC 7616, a URI is in the protection space if any URI - in the protection space is a prefix of it (after both have been made absolute). - """ - request_str = str(url) - for space_str in self._protection_space: - # Check if request starts with space URL - if not request_str.startswith(space_str): - continue - # Exact match or space ends with / (proper directory prefix) - if len(request_str) == len(space_str) or space_str[-1] == "/": - return True - # Check next char is / to ensure proper path boundary - if request_str[len(space_str)] == "/": - return True - return False - - def _authenticate(self, response: ClientResponse) -> bool: - """ - Takes the given response and tries digest-auth, if needed. - - Returns true if the original request must be resent. - """ - if response.status != 401: - return False - - auth_header = response.headers.get("www-authenticate", "") - if not auth_header: - return False # No authentication header present - - method, sep, headers = auth_header.partition(" ") - if not sep: - # No space found in www-authenticate header - return False # Malformed auth header, missing scheme separator - - if method.lower() != "digest": - # Not a digest auth challenge (could be Basic, Bearer, etc.) - return False - - if not headers: - # We have a digest scheme but no parameters - return False # Malformed digest header, missing parameters - - # We have a digest auth header with content - if not (header_pairs := parse_header_pairs(headers)): - # Failed to parse any key-value pairs - return False # Malformed digest header, no valid parameters - - # Extract challenge parameters - self._challenge = {} - for field in CHALLENGE_FIELDS: - if (value := header_pairs.get(field)) is not None: - self._challenge[field] = value - - # Update protection space based on domain parameter or default to origin - origin = response.url.origin() - - if domain := self._challenge.get("domain"): - # Parse space-separated list of URIs - self._protection_space = [] - for uri in domain.split(): - # Remove quotes if present - uri = uri.strip('"') - if uri.startswith("/"): - # Path-absolute, relative to origin - self._protection_space.append(str(origin.join(URL(uri)))) - else: - # Absolute URI - self._protection_space.append(str(URL(uri))) - else: - # No domain specified, protection space is entire origin - self._protection_space = [str(origin)] - - # Return True only if we found at least one challenge parameter - return bool(self._challenge) - - async def __call__( - self, request: ClientRequest, handler: ClientHandlerType - ) -> ClientResponse: - """Run the digest auth middleware.""" - response = None - for retry_count in range(2): - # Apply authorization header if: - # 1. This is a retry after 401 (retry_count > 0), OR - # 2. Preemptive auth is enabled AND we have a challenge AND the URL is in protection space - if retry_count > 0 or ( - self._preemptive - and self._challenge - and self._in_protection_space(request.url) - ): - request.headers[hdrs.AUTHORIZATION] = await self._encode( - request.method, request.url, request.body - ) - - # Send the request - response = await handler(request) - - # Check if we need to authenticate - if not self._authenticate(response): - break - - # At this point, response is guaranteed to be defined - assert response is not None - return response diff --git a/venv/lib/python3.9/site-packages/aiohttp/client_middlewares.py b/venv/lib/python3.9/site-packages/aiohttp/client_middlewares.py deleted file mode 100644 index 3ca2cb2..0000000 --- a/venv/lib/python3.9/site-packages/aiohttp/client_middlewares.py +++ /dev/null @@ -1,55 +0,0 @@ -"""Client middleware support.""" - -from collections.abc import Awaitable, Callable, Sequence - -from .client_reqrep import ClientRequest, ClientResponse - -__all__ = ("ClientMiddlewareType", "ClientHandlerType", "build_client_middlewares") - -# Type alias for client request handlers - functions that process requests and return responses -ClientHandlerType = Callable[[ClientRequest], Awaitable[ClientResponse]] - -# Type for client middleware - similar to server but uses ClientRequest/ClientResponse -ClientMiddlewareType = Callable[ - [ClientRequest, ClientHandlerType], Awaitable[ClientResponse] -] - - -def build_client_middlewares( - handler: ClientHandlerType, - middlewares: Sequence[ClientMiddlewareType], -) -> ClientHandlerType: - """ - Apply middlewares to request handler. - - The middlewares are applied in reverse order, so the first middleware - in the list wraps all subsequent middlewares and the handler. - - This implementation avoids using partial/update_wrapper to minimize overhead - and doesn't cache to avoid holding references to stateful middleware. - """ - # Optimize for single middleware case - if len(middlewares) == 1: - middleware = middlewares[0] - - async def single_middleware_handler(req: ClientRequest) -> ClientResponse: - return await middleware(req, handler) - - return single_middleware_handler - - # Build the chain for multiple middlewares - current_handler = handler - - for middleware in reversed(middlewares): - # Create a new closure that captures the current state - def make_wrapper( - mw: ClientMiddlewareType, next_h: ClientHandlerType - ) -> ClientHandlerType: - async def wrapped(req: ClientRequest) -> ClientResponse: - return await mw(req, next_h) - - return wrapped - - current_handler = make_wrapper(middleware, current_handler) - - return current_handler diff --git a/venv/lib/python3.9/site-packages/aiohttp/client_proto.py b/venv/lib/python3.9/site-packages/aiohttp/client_proto.py deleted file mode 100644 index aea3191..0000000 --- a/venv/lib/python3.9/site-packages/aiohttp/client_proto.py +++ /dev/null @@ -1,361 +0,0 @@ -import asyncio -from contextlib import suppress -from typing import Any, Optional, Tuple, Union - -from .base_protocol import BaseProtocol -from .client_exceptions import ( - ClientConnectionError, - ClientOSError, - ClientPayloadError, - ServerDisconnectedError, - SocketTimeoutError, -) -from .helpers import ( - _EXC_SENTINEL, - EMPTY_BODY_STATUS_CODES, - BaseTimerContext, - set_exception, - set_result, -) -from .http import HttpResponseParser, RawResponseMessage -from .http_exceptions import HttpProcessingError -from .streams import EMPTY_PAYLOAD, DataQueue, StreamReader - - -class ResponseHandler(BaseProtocol, DataQueue[Tuple[RawResponseMessage, StreamReader]]): - """Helper class to adapt between Protocol and StreamReader.""" - - def __init__(self, loop: asyncio.AbstractEventLoop) -> None: - BaseProtocol.__init__(self, loop=loop) - DataQueue.__init__(self, loop) - - self._should_close = False - - self._payload: Optional[StreamReader] = None - self._skip_payload = False - self._payload_parser = None - - self._timer = None - - self._tail = b"" - self._upgraded = False - self._parser: Optional[HttpResponseParser] = None - - self._read_timeout: Optional[float] = None - self._read_timeout_handle: Optional[asyncio.TimerHandle] = None - - self._timeout_ceil_threshold: Optional[float] = 5 - - self._closed: Union[None, asyncio.Future[None]] = None - self._connection_lost_called = False - - @property - def closed(self) -> Union[None, asyncio.Future[None]]: - """Future that is set when the connection is closed. - - This property returns a Future that will be completed when the connection - is closed. The Future is created lazily on first access to avoid creating - futures that will never be awaited. - - Returns: - - A Future[None] if the connection is still open or was closed after - this property was accessed - - None if connection_lost() was already called before this property - was ever accessed (indicating no one is waiting for the closure) - """ - if self._closed is None and not self._connection_lost_called: - self._closed = self._loop.create_future() - return self._closed - - @property - def upgraded(self) -> bool: - return self._upgraded - - @property - def should_close(self) -> bool: - return bool( - self._should_close - or (self._payload is not None and not self._payload.is_eof()) - or self._upgraded - or self._exception is not None - or self._payload_parser is not None - or self._buffer - or self._tail - ) - - def force_close(self) -> None: - self._should_close = True - - def close(self) -> None: - self._exception = None # Break cyclic references - transport = self.transport - if transport is not None: - transport.close() - self.transport = None - self._payload = None - self._drop_timeout() - - def abort(self) -> None: - self._exception = None # Break cyclic references - transport = self.transport - if transport is not None: - transport.abort() - self.transport = None - self._payload = None - self._drop_timeout() - - def is_connected(self) -> bool: - return self.transport is not None and not self.transport.is_closing() - - def connection_lost(self, exc: Optional[BaseException]) -> None: - self._connection_lost_called = True - self._drop_timeout() - - original_connection_error = exc - reraised_exc = original_connection_error - - connection_closed_cleanly = original_connection_error is None - - if self._closed is not None: - # If someone is waiting for the closed future, - # we should set it to None or an exception. If - # self._closed is None, it means that - # connection_lost() was called already - # or nobody is waiting for it. - if connection_closed_cleanly: - set_result(self._closed, None) - else: - assert original_connection_error is not None - set_exception( - self._closed, - ClientConnectionError( - f"Connection lost: {original_connection_error !s}", - ), - original_connection_error, - ) - - if self._payload_parser is not None: - with suppress(Exception): # FIXME: log this somehow? - self._payload_parser.feed_eof() - - uncompleted = None - if self._parser is not None: - try: - uncompleted = self._parser.feed_eof() - except Exception as underlying_exc: - if self._payload is not None: - client_payload_exc_msg = ( - f"Response payload is not completed: {underlying_exc !r}" - ) - if not connection_closed_cleanly: - client_payload_exc_msg = ( - f"{client_payload_exc_msg !s}. " - f"{original_connection_error !r}" - ) - set_exception( - self._payload, - ClientPayloadError(client_payload_exc_msg), - underlying_exc, - ) - - if not self.is_eof(): - if isinstance(original_connection_error, OSError): - reraised_exc = ClientOSError(*original_connection_error.args) - if connection_closed_cleanly: - reraised_exc = ServerDisconnectedError(uncompleted) - # assigns self._should_close to True as side effect, - # we do it anyway below - underlying_non_eof_exc = ( - _EXC_SENTINEL - if connection_closed_cleanly - else original_connection_error - ) - assert underlying_non_eof_exc is not None - assert reraised_exc is not None - self.set_exception(reraised_exc, underlying_non_eof_exc) - - self._should_close = True - self._parser = None - self._payload = None - self._payload_parser = None - self._reading_paused = False - - super().connection_lost(reraised_exc) - - def eof_received(self) -> None: - # should call parser.feed_eof() most likely - self._drop_timeout() - - def pause_reading(self) -> None: - super().pause_reading() - self._drop_timeout() - - def resume_reading(self) -> None: - super().resume_reading() - self._reschedule_timeout() - - def set_exception( - self, - exc: BaseException, - exc_cause: BaseException = _EXC_SENTINEL, - ) -> None: - self._should_close = True - self._drop_timeout() - super().set_exception(exc, exc_cause) - - def set_parser(self, parser: Any, payload: Any) -> None: - # TODO: actual types are: - # parser: WebSocketReader - # payload: WebSocketDataQueue - # but they are not generi enough - # Need an ABC for both types - self._payload = payload - self._payload_parser = parser - - self._drop_timeout() - - if self._tail: - data, self._tail = self._tail, b"" - self.data_received(data) - - def set_response_params( - self, - *, - timer: Optional[BaseTimerContext] = None, - skip_payload: bool = False, - read_until_eof: bool = False, - auto_decompress: bool = True, - read_timeout: Optional[float] = None, - read_bufsize: int = 2**16, - timeout_ceil_threshold: float = 5, - max_line_size: int = 8190, - max_field_size: int = 8190, - max_headers: int = 128, - ) -> None: - self._skip_payload = skip_payload - - self._read_timeout = read_timeout - - self._timeout_ceil_threshold = timeout_ceil_threshold - - self._parser = HttpResponseParser( - self, - self._loop, - read_bufsize, - timer=timer, - payload_exception=ClientPayloadError, - response_with_body=not skip_payload, - read_until_eof=read_until_eof, - auto_decompress=auto_decompress, - max_line_size=max_line_size, - max_field_size=max_field_size, - max_headers=max_headers, - ) - - if self._tail: - data, self._tail = self._tail, b"" - self.data_received(data) - - def _drop_timeout(self) -> None: - if self._read_timeout_handle is not None: - self._read_timeout_handle.cancel() - self._read_timeout_handle = None - - def _reschedule_timeout(self) -> None: - timeout = self._read_timeout - if self._read_timeout_handle is not None: - self._read_timeout_handle.cancel() - - if timeout: - self._read_timeout_handle = self._loop.call_later( - timeout, self._on_read_timeout - ) - else: - self._read_timeout_handle = None - - def start_timeout(self) -> None: - self._reschedule_timeout() - - @property - def read_timeout(self) -> Optional[float]: - return self._read_timeout - - @read_timeout.setter - def read_timeout(self, read_timeout: Optional[float]) -> None: - self._read_timeout = read_timeout - - def _on_read_timeout(self) -> None: - exc = SocketTimeoutError("Timeout on reading data from socket") - self.set_exception(exc) - if self._payload is not None: - set_exception(self._payload, exc) - - def data_received(self, data: bytes) -> None: - self._reschedule_timeout() - - if not data: - return - - # custom payload parser - currently always WebSocketReader - if self._payload_parser is not None: - eof, tail = self._payload_parser.feed_data(data) - if eof: - self._payload = None - self._payload_parser = None - - if tail: - self.data_received(tail) - return - - if self._upgraded or self._parser is None: - # i.e. websocket connection, websocket parser is not set yet - self._tail += data - return - - # parse http messages - try: - messages, upgraded, tail = self._parser.feed_data(data) - except BaseException as underlying_exc: - if self.transport is not None: - # connection.release() could be called BEFORE - # data_received(), the transport is already - # closed in this case - self.transport.close() - # should_close is True after the call - if isinstance(underlying_exc, HttpProcessingError): - exc = HttpProcessingError( - code=underlying_exc.code, - message=underlying_exc.message, - headers=underlying_exc.headers, - ) - else: - exc = HttpProcessingError() - self.set_exception(exc, underlying_exc) - return - - self._upgraded = upgraded - - payload: Optional[StreamReader] = None - for message, payload in messages: - if message.should_close: - self._should_close = True - - self._payload = payload - - if self._skip_payload or message.code in EMPTY_BODY_STATUS_CODES: - self.feed_data((message, EMPTY_PAYLOAD), 0) - else: - self.feed_data((message, payload), 0) - - if payload is not None: - # new message(s) was processed - # register timeout handler unsubscribing - # either on end-of-stream or immediately for - # EMPTY_PAYLOAD - if payload is not EMPTY_PAYLOAD: - payload.on_eof(self._drop_timeout) - else: - self._drop_timeout() - - if upgraded and tail: - self.data_received(tail) diff --git a/venv/lib/python3.9/site-packages/aiohttp/client_reqrep.py b/venv/lib/python3.9/site-packages/aiohttp/client_reqrep.py deleted file mode 100644 index a9e0795..0000000 --- a/venv/lib/python3.9/site-packages/aiohttp/client_reqrep.py +++ /dev/null @@ -1,1536 +0,0 @@ -import asyncio -import codecs -import contextlib -import functools -import io -import re -import sys -import traceback -import warnings -from collections.abc import Mapping -from hashlib import md5, sha1, sha256 -from http.cookies import Morsel, SimpleCookie -from types import MappingProxyType, TracebackType -from typing import ( - TYPE_CHECKING, - Any, - Callable, - Dict, - Iterable, - List, - Literal, - NamedTuple, - Optional, - Tuple, - Type, - Union, -) - -import attr -from multidict import CIMultiDict, CIMultiDictProxy, MultiDict, MultiDictProxy -from yarl import URL - -from . import hdrs, helpers, http, multipart, payload -from ._cookie_helpers import ( - parse_cookie_header, - parse_set_cookie_headers, - preserve_morsel_with_coded_value, -) -from .abc import AbstractStreamWriter -from .client_exceptions import ( - ClientConnectionError, - ClientOSError, - ClientResponseError, - ContentTypeError, - InvalidURL, - ServerFingerprintMismatch, -) -from .compression_utils import HAS_BROTLI, HAS_ZSTD -from .formdata import FormData -from .helpers import ( - _SENTINEL, - BaseTimerContext, - BasicAuth, - HeadersMixin, - TimerNoop, - noop, - reify, - sentinel, - set_exception, - set_result, -) -from .http import ( - SERVER_SOFTWARE, - HttpVersion, - HttpVersion10, - HttpVersion11, - StreamWriter, -) -from .streams import StreamReader -from .typedefs import ( - DEFAULT_JSON_DECODER, - JSONDecoder, - LooseCookies, - LooseHeaders, - Query, - RawHeaders, -) - -if TYPE_CHECKING: - import ssl - from ssl import SSLContext -else: - try: - import ssl - from ssl import SSLContext - except ImportError: # pragma: no cover - ssl = None # type: ignore[assignment] - SSLContext = object # type: ignore[misc,assignment] - - -__all__ = ("ClientRequest", "ClientResponse", "RequestInfo", "Fingerprint") - - -if TYPE_CHECKING: - from .client import ClientSession - from .connector import Connection - from .tracing import Trace - - -_CONNECTION_CLOSED_EXCEPTION = ClientConnectionError("Connection closed") -_CONTAINS_CONTROL_CHAR_RE = re.compile(r"[^-!#$%&'*+.^_`|~0-9a-zA-Z]") -json_re = re.compile(r"^application/(?:[\w.+-]+?\+)?json") - - -def _gen_default_accept_encoding() -> str: - encodings = [ - "gzip", - "deflate", - ] - if HAS_BROTLI: - encodings.append("br") - if HAS_ZSTD: - encodings.append("zstd") - return ", ".join(encodings) - - -@attr.s(auto_attribs=True, frozen=True, slots=True) -class ContentDisposition: - type: Optional[str] - parameters: "MappingProxyType[str, str]" - filename: Optional[str] - - -class _RequestInfo(NamedTuple): - url: URL - method: str - headers: "CIMultiDictProxy[str]" - real_url: URL - - -class RequestInfo(_RequestInfo): - - def __new__( - cls, - url: URL, - method: str, - headers: "CIMultiDictProxy[str]", - real_url: Union[URL, _SENTINEL] = sentinel, - ) -> "RequestInfo": - """Create a new RequestInfo instance. - - For backwards compatibility, the real_url parameter is optional. - """ - return tuple.__new__( - cls, (url, method, headers, url if real_url is sentinel else real_url) - ) - - -class Fingerprint: - HASHFUNC_BY_DIGESTLEN = { - 16: md5, - 20: sha1, - 32: sha256, - } - - def __init__(self, fingerprint: bytes) -> None: - digestlen = len(fingerprint) - hashfunc = self.HASHFUNC_BY_DIGESTLEN.get(digestlen) - if not hashfunc: - raise ValueError("fingerprint has invalid length") - elif hashfunc is md5 or hashfunc is sha1: - raise ValueError("md5 and sha1 are insecure and not supported. Use sha256.") - self._hashfunc = hashfunc - self._fingerprint = fingerprint - - @property - def fingerprint(self) -> bytes: - return self._fingerprint - - def check(self, transport: asyncio.Transport) -> None: - if not transport.get_extra_info("sslcontext"): - return - sslobj = transport.get_extra_info("ssl_object") - cert = sslobj.getpeercert(binary_form=True) - got = self._hashfunc(cert).digest() - if got != self._fingerprint: - host, port, *_ = transport.get_extra_info("peername") - raise ServerFingerprintMismatch(self._fingerprint, got, host, port) - - -if ssl is not None: - SSL_ALLOWED_TYPES = (ssl.SSLContext, bool, Fingerprint, type(None)) -else: # pragma: no cover - SSL_ALLOWED_TYPES = (bool, type(None)) - - -def _merge_ssl_params( - ssl: Union["SSLContext", bool, Fingerprint], - verify_ssl: Optional[bool], - ssl_context: Optional["SSLContext"], - fingerprint: Optional[bytes], -) -> Union["SSLContext", bool, Fingerprint]: - if ssl is None: - ssl = True # Double check for backwards compatibility - if verify_ssl is not None and not verify_ssl: - warnings.warn( - "verify_ssl is deprecated, use ssl=False instead", - DeprecationWarning, - stacklevel=3, - ) - if ssl is not True: - raise ValueError( - "verify_ssl, ssl_context, fingerprint and ssl " - "parameters are mutually exclusive" - ) - else: - ssl = False - if ssl_context is not None: - warnings.warn( - "ssl_context is deprecated, use ssl=context instead", - DeprecationWarning, - stacklevel=3, - ) - if ssl is not True: - raise ValueError( - "verify_ssl, ssl_context, fingerprint and ssl " - "parameters are mutually exclusive" - ) - else: - ssl = ssl_context - if fingerprint is not None: - warnings.warn( - "fingerprint is deprecated, use ssl=Fingerprint(fingerprint) instead", - DeprecationWarning, - stacklevel=3, - ) - if ssl is not True: - raise ValueError( - "verify_ssl, ssl_context, fingerprint and ssl " - "parameters are mutually exclusive" - ) - else: - ssl = Fingerprint(fingerprint) - if not isinstance(ssl, SSL_ALLOWED_TYPES): - raise TypeError( - "ssl should be SSLContext, bool, Fingerprint or None, " - "got {!r} instead.".format(ssl) - ) - return ssl - - -_SSL_SCHEMES = frozenset(("https", "wss")) - - -# ConnectionKey is a NamedTuple because it is used as a key in a dict -# and a set in the connector. Since a NamedTuple is a tuple it uses -# the fast native tuple __hash__ and __eq__ implementation in CPython. -class ConnectionKey(NamedTuple): - # the key should contain an information about used proxy / TLS - # to prevent reusing wrong connections from a pool - host: str - port: Optional[int] - is_ssl: bool - ssl: Union[SSLContext, bool, Fingerprint] - proxy: Optional[URL] - proxy_auth: Optional[BasicAuth] - proxy_headers_hash: Optional[int] # hash(CIMultiDict) - - -def _is_expected_content_type( - response_content_type: str, expected_content_type: str -) -> bool: - if expected_content_type == "application/json": - return json_re.match(response_content_type) is not None - return expected_content_type in response_content_type - - -def _warn_if_unclosed_payload(payload: payload.Payload, stacklevel: int = 2) -> None: - """Warn if the payload is not closed. - - Callers must check that the body is a Payload before calling this method. - - Args: - payload: The payload to check - stacklevel: Stack level for the warning (default 2 for direct callers) - """ - if not payload.autoclose and not payload.consumed: - warnings.warn( - "The previous request body contains unclosed resources. " - "Use await request.update_body() instead of setting request.body " - "directly to properly close resources and avoid leaks.", - ResourceWarning, - stacklevel=stacklevel, - ) - - -class ClientResponse(HeadersMixin): - - # Some of these attributes are None when created, - # but will be set by the start() method. - # As the end user will likely never see the None values, we cheat the types below. - # from the Status-Line of the response - version: Optional[HttpVersion] = None # HTTP-Version - status: int = None # type: ignore[assignment] # Status-Code - reason: Optional[str] = None # Reason-Phrase - - content: StreamReader = None # type: ignore[assignment] # Payload stream - _body: Optional[bytes] = None - _headers: CIMultiDictProxy[str] = None # type: ignore[assignment] - _history: Tuple["ClientResponse", ...] = () - _raw_headers: RawHeaders = None # type: ignore[assignment] - - _connection: Optional["Connection"] = None # current connection - _cookies: Optional[SimpleCookie] = None - _raw_cookie_headers: Optional[Tuple[str, ...]] = None - _continue: Optional["asyncio.Future[bool]"] = None - _source_traceback: Optional[traceback.StackSummary] = None - _session: Optional["ClientSession"] = None - # set up by ClientRequest after ClientResponse object creation - # post-init stage allows to not change ctor signature - _closed = True # to allow __del__ for non-initialized properly response - _released = False - _in_context = False - - _resolve_charset: Callable[["ClientResponse", bytes], str] = lambda *_: "utf-8" - - __writer: Optional["asyncio.Task[None]"] = None - - def __init__( - self, - method: str, - url: URL, - *, - writer: "Optional[asyncio.Task[None]]", - continue100: Optional["asyncio.Future[bool]"], - timer: BaseTimerContext, - request_info: RequestInfo, - traces: List["Trace"], - loop: asyncio.AbstractEventLoop, - session: "ClientSession", - ) -> None: - # URL forbids subclasses, so a simple type check is enough. - assert type(url) is URL - - self.method = method - - self._real_url = url - self._url = url.with_fragment(None) if url.raw_fragment else url - if writer is not None: - self._writer = writer - if continue100 is not None: - self._continue = continue100 - self._request_info = request_info - self._timer = timer if timer is not None else TimerNoop() - self._cache: Dict[str, Any] = {} - self._traces = traces - self._loop = loop - # Save reference to _resolve_charset, so that get_encoding() will still - # work after the response has finished reading the body. - # TODO: Fix session=None in tests (see ClientRequest.__init__). - if session is not None: - # store a reference to session #1985 - self._session = session - self._resolve_charset = session._resolve_charset - if loop.get_debug(): - self._source_traceback = traceback.extract_stack(sys._getframe(1)) - - def __reset_writer(self, _: object = None) -> None: - self.__writer = None - - @property - def _writer(self) -> Optional["asyncio.Task[None]"]: - """The writer task for streaming data. - - _writer is only provided for backwards compatibility - for subclasses that may need to access it. - """ - return self.__writer - - @_writer.setter - def _writer(self, writer: Optional["asyncio.Task[None]"]) -> None: - """Set the writer task for streaming data.""" - if self.__writer is not None: - self.__writer.remove_done_callback(self.__reset_writer) - self.__writer = writer - if writer is None: - return - if writer.done(): - # The writer is already done, so we can clear it immediately. - self.__writer = None - else: - writer.add_done_callback(self.__reset_writer) - - @property - def cookies(self) -> SimpleCookie: - if self._cookies is None: - if self._raw_cookie_headers is not None: - # Parse cookies for response.cookies (SimpleCookie for backward compatibility) - cookies = SimpleCookie() - # Use parse_set_cookie_headers for more lenient parsing that handles - # malformed cookies better than SimpleCookie.load - cookies.update(parse_set_cookie_headers(self._raw_cookie_headers)) - self._cookies = cookies - else: - self._cookies = SimpleCookie() - return self._cookies - - @cookies.setter - def cookies(self, cookies: SimpleCookie) -> None: - self._cookies = cookies - # Generate raw cookie headers from the SimpleCookie - if cookies: - self._raw_cookie_headers = tuple( - morsel.OutputString() for morsel in cookies.values() - ) - else: - self._raw_cookie_headers = None - - @reify - def url(self) -> URL: - return self._url - - @reify - def url_obj(self) -> URL: - warnings.warn("Deprecated, use .url #1654", DeprecationWarning, stacklevel=2) - return self._url - - @reify - def real_url(self) -> URL: - return self._real_url - - @reify - def host(self) -> str: - assert self._url.host is not None - return self._url.host - - @reify - def headers(self) -> "CIMultiDictProxy[str]": - return self._headers - - @reify - def raw_headers(self) -> RawHeaders: - return self._raw_headers - - @reify - def request_info(self) -> RequestInfo: - return self._request_info - - @reify - def content_disposition(self) -> Optional[ContentDisposition]: - raw = self._headers.get(hdrs.CONTENT_DISPOSITION) - if raw is None: - return None - disposition_type, params_dct = multipart.parse_content_disposition(raw) - params = MappingProxyType(params_dct) - filename = multipart.content_disposition_filename(params) - return ContentDisposition(disposition_type, params, filename) - - def __del__(self, _warnings: Any = warnings) -> None: - if self._closed: - return - - if self._connection is not None: - self._connection.release() - self._cleanup_writer() - - if self._loop.get_debug(): - kwargs = {"source": self} - _warnings.warn(f"Unclosed response {self!r}", ResourceWarning, **kwargs) - context = {"client_response": self, "message": "Unclosed response"} - if self._source_traceback: - context["source_traceback"] = self._source_traceback - self._loop.call_exception_handler(context) - - def __repr__(self) -> str: - out = io.StringIO() - ascii_encodable_url = str(self.url) - if self.reason: - ascii_encodable_reason = self.reason.encode( - "ascii", "backslashreplace" - ).decode("ascii") - else: - ascii_encodable_reason = "None" - print( - "".format( - ascii_encodable_url, self.status, ascii_encodable_reason - ), - file=out, - ) - print(self.headers, file=out) - return out.getvalue() - - @property - def connection(self) -> Optional["Connection"]: - return self._connection - - @reify - def history(self) -> Tuple["ClientResponse", ...]: - """A sequence of of responses, if redirects occurred.""" - return self._history - - @reify - def links(self) -> "MultiDictProxy[MultiDictProxy[Union[str, URL]]]": - links_str = ", ".join(self.headers.getall("link", [])) - - if not links_str: - return MultiDictProxy(MultiDict()) - - links: MultiDict[MultiDictProxy[Union[str, URL]]] = MultiDict() - - for val in re.split(r",(?=\s*<)", links_str): - match = re.match(r"\s*<(.*)>(.*)", val) - if match is None: # pragma: no cover - # the check exists to suppress mypy error - continue - url, params_str = match.groups() - params = params_str.split(";")[1:] - - link: MultiDict[Union[str, URL]] = MultiDict() - - for param in params: - match = re.match(r"^\s*(\S*)\s*=\s*(['\"]?)(.*?)(\2)\s*$", param, re.M) - if match is None: # pragma: no cover - # the check exists to suppress mypy error - continue - key, _, value, _ = match.groups() - - link.add(key, value) - - key = link.get("rel", url) - - link.add("url", self.url.join(URL(url))) - - links.add(str(key), MultiDictProxy(link)) - - return MultiDictProxy(links) - - async def start(self, connection: "Connection") -> "ClientResponse": - """Start response processing.""" - self._closed = False - self._protocol = connection.protocol - self._connection = connection - - with self._timer: - while True: - # read response - try: - protocol = self._protocol - message, payload = await protocol.read() # type: ignore[union-attr] - except http.HttpProcessingError as exc: - raise ClientResponseError( - self.request_info, - self.history, - status=exc.code, - message=exc.message, - headers=exc.headers, - ) from exc - - if message.code < 100 or message.code > 199 or message.code == 101: - break - - if self._continue is not None: - set_result(self._continue, True) - self._continue = None - - # payload eof handler - payload.on_eof(self._response_eof) - - # response status - self.version = message.version - self.status = message.code - self.reason = message.reason - - # headers - self._headers = message.headers # type is CIMultiDictProxy - self._raw_headers = message.raw_headers # type is Tuple[bytes, bytes] - - # payload - self.content = payload - - # cookies - if cookie_hdrs := self.headers.getall(hdrs.SET_COOKIE, ()): - # Store raw cookie headers for CookieJar - self._raw_cookie_headers = tuple(cookie_hdrs) - return self - - def _response_eof(self) -> None: - if self._closed: - return - - # protocol could be None because connection could be detached - protocol = self._connection and self._connection.protocol - if protocol is not None and protocol.upgraded: - return - - self._closed = True - self._cleanup_writer() - self._release_connection() - - @property - def closed(self) -> bool: - return self._closed - - def close(self) -> None: - if not self._released: - self._notify_content() - - self._closed = True - if self._loop is None or self._loop.is_closed(): - return - - self._cleanup_writer() - if self._connection is not None: - self._connection.close() - self._connection = None - - def release(self) -> Any: - if not self._released: - self._notify_content() - - self._closed = True - - self._cleanup_writer() - self._release_connection() - return noop() - - @property - def ok(self) -> bool: - """Returns ``True`` if ``status`` is less than ``400``, ``False`` if not. - - This is **not** a check for ``200 OK`` but a check that the response - status is under 400. - """ - return 400 > self.status - - def raise_for_status(self) -> None: - if not self.ok: - # reason should always be not None for a started response - assert self.reason is not None - - # If we're in a context we can rely on __aexit__() to release as the - # exception propagates. - if not self._in_context: - self.release() - - raise ClientResponseError( - self.request_info, - self.history, - status=self.status, - message=self.reason, - headers=self.headers, - ) - - def _release_connection(self) -> None: - if self._connection is not None: - if self.__writer is None: - self._connection.release() - self._connection = None - else: - self.__writer.add_done_callback(lambda f: self._release_connection()) - - async def _wait_released(self) -> None: - if self.__writer is not None: - try: - await self.__writer - except asyncio.CancelledError: - if ( - sys.version_info >= (3, 11) - and (task := asyncio.current_task()) - and task.cancelling() - ): - raise - self._release_connection() - - def _cleanup_writer(self) -> None: - if self.__writer is not None: - self.__writer.cancel() - self._session = None - - def _notify_content(self) -> None: - content = self.content - if content and content.exception() is None: - set_exception(content, _CONNECTION_CLOSED_EXCEPTION) - self._released = True - - async def wait_for_close(self) -> None: - if self.__writer is not None: - try: - await self.__writer - except asyncio.CancelledError: - if ( - sys.version_info >= (3, 11) - and (task := asyncio.current_task()) - and task.cancelling() - ): - raise - self.release() - - async def read(self) -> bytes: - """Read response payload.""" - if self._body is None: - try: - self._body = await self.content.read() - for trace in self._traces: - await trace.send_response_chunk_received( - self.method, self.url, self._body - ) - except BaseException: - self.close() - raise - elif self._released: # Response explicitly released - raise ClientConnectionError("Connection closed") - - protocol = self._connection and self._connection.protocol - if protocol is None or not protocol.upgraded: - await self._wait_released() # Underlying connection released - return self._body - - def get_encoding(self) -> str: - ctype = self.headers.get(hdrs.CONTENT_TYPE, "").lower() - mimetype = helpers.parse_mimetype(ctype) - - encoding = mimetype.parameters.get("charset") - if encoding: - with contextlib.suppress(LookupError, ValueError): - return codecs.lookup(encoding).name - - if mimetype.type == "application" and ( - mimetype.subtype == "json" or mimetype.subtype == "rdap" - ): - # RFC 7159 states that the default encoding is UTF-8. - # RFC 7483 defines application/rdap+json - return "utf-8" - - if self._body is None: - raise RuntimeError( - "Cannot compute fallback encoding of a not yet read body" - ) - - return self._resolve_charset(self, self._body) - - async def text(self, encoding: Optional[str] = None, errors: str = "strict") -> str: - """Read response payload and decode.""" - if self._body is None: - await self.read() - - if encoding is None: - encoding = self.get_encoding() - - return self._body.decode(encoding, errors=errors) # type: ignore[union-attr] - - async def json( - self, - *, - encoding: Optional[str] = None, - loads: JSONDecoder = DEFAULT_JSON_DECODER, - content_type: Optional[str] = "application/json", - ) -> Any: - """Read and decodes JSON response.""" - if self._body is None: - await self.read() - - if content_type: - ctype = self.headers.get(hdrs.CONTENT_TYPE, "").lower() - if not _is_expected_content_type(ctype, content_type): - raise ContentTypeError( - self.request_info, - self.history, - status=self.status, - message=( - "Attempt to decode JSON with unexpected mimetype: %s" % ctype - ), - headers=self.headers, - ) - - stripped = self._body.strip() # type: ignore[union-attr] - if not stripped: - return None - - if encoding is None: - encoding = self.get_encoding() - - return loads(stripped.decode(encoding)) - - async def __aenter__(self) -> "ClientResponse": - self._in_context = True - return self - - async def __aexit__( - self, - exc_type: Optional[Type[BaseException]], - exc_val: Optional[BaseException], - exc_tb: Optional[TracebackType], - ) -> None: - self._in_context = False - # similar to _RequestContextManager, we do not need to check - # for exceptions, response object can close connection - # if state is broken - self.release() - await self.wait_for_close() - - -class ClientRequest: - GET_METHODS = { - hdrs.METH_GET, - hdrs.METH_HEAD, - hdrs.METH_OPTIONS, - hdrs.METH_TRACE, - } - POST_METHODS = {hdrs.METH_PATCH, hdrs.METH_POST, hdrs.METH_PUT} - ALL_METHODS = GET_METHODS.union(POST_METHODS).union({hdrs.METH_DELETE}) - - DEFAULT_HEADERS = { - hdrs.ACCEPT: "*/*", - hdrs.ACCEPT_ENCODING: _gen_default_accept_encoding(), - } - - # Type of body depends on PAYLOAD_REGISTRY, which is dynamic. - _body: Union[None, payload.Payload] = None - auth = None - response = None - - __writer: Optional["asyncio.Task[None]"] = None # async task for streaming data - - # These class defaults help create_autospec() work correctly. - # If autospec is improved in future, maybe these can be removed. - url = URL() - method = "GET" - - _continue = None # waiter future for '100 Continue' response - - _skip_auto_headers: Optional["CIMultiDict[None]"] = None - - # N.B. - # Adding __del__ method with self._writer closing doesn't make sense - # because _writer is instance method, thus it keeps a reference to self. - # Until writer has finished finalizer will not be called. - - def __init__( - self, - method: str, - url: URL, - *, - params: Query = None, - headers: Optional[LooseHeaders] = None, - skip_auto_headers: Optional[Iterable[str]] = None, - data: Any = None, - cookies: Optional[LooseCookies] = None, - auth: Optional[BasicAuth] = None, - version: http.HttpVersion = http.HttpVersion11, - compress: Union[str, bool, None] = None, - chunked: Optional[bool] = None, - expect100: bool = False, - loop: Optional[asyncio.AbstractEventLoop] = None, - response_class: Optional[Type["ClientResponse"]] = None, - proxy: Optional[URL] = None, - proxy_auth: Optional[BasicAuth] = None, - timer: Optional[BaseTimerContext] = None, - session: Optional["ClientSession"] = None, - ssl: Union[SSLContext, bool, Fingerprint] = True, - proxy_headers: Optional[LooseHeaders] = None, - traces: Optional[List["Trace"]] = None, - trust_env: bool = False, - server_hostname: Optional[str] = None, - ): - if loop is None: - loop = asyncio.get_event_loop() - if match := _CONTAINS_CONTROL_CHAR_RE.search(method): - raise ValueError( - f"Method cannot contain non-token characters {method!r} " - f"(found at least {match.group()!r})" - ) - # URL forbids subclasses, so a simple type check is enough. - assert type(url) is URL, url - if proxy is not None: - assert type(proxy) is URL, proxy - # FIXME: session is None in tests only, need to fix tests - # assert session is not None - if TYPE_CHECKING: - assert session is not None - self._session = session - if params: - url = url.extend_query(params) - self.original_url = url - self.url = url.with_fragment(None) if url.raw_fragment else url - self.method = method.upper() - self.chunked = chunked - self.compress = compress - self.loop = loop - self.length = None - if response_class is None: - real_response_class = ClientResponse - else: - real_response_class = response_class - self.response_class: Type[ClientResponse] = real_response_class - self._timer = timer if timer is not None else TimerNoop() - self._ssl = ssl if ssl is not None else True - self.server_hostname = server_hostname - - if loop.get_debug(): - self._source_traceback = traceback.extract_stack(sys._getframe(1)) - - self.update_version(version) - self.update_host(url) - self.update_headers(headers) - self.update_auto_headers(skip_auto_headers) - self.update_cookies(cookies) - self.update_content_encoding(data) - self.update_auth(auth, trust_env) - self.update_proxy(proxy, proxy_auth, proxy_headers) - - self.update_body_from_data(data) - if data is not None or self.method not in self.GET_METHODS: - self.update_transfer_encoding() - self.update_expect_continue(expect100) - self._traces = [] if traces is None else traces - - def __reset_writer(self, _: object = None) -> None: - self.__writer = None - - def _get_content_length(self) -> Optional[int]: - """Extract and validate Content-Length header value. - - Returns parsed Content-Length value or None if not set. - Raises ValueError if header exists but cannot be parsed as an integer. - """ - if hdrs.CONTENT_LENGTH not in self.headers: - return None - - content_length_hdr = self.headers[hdrs.CONTENT_LENGTH] - try: - return int(content_length_hdr) - except ValueError: - raise ValueError( - f"Invalid Content-Length header: {content_length_hdr}" - ) from None - - @property - def skip_auto_headers(self) -> CIMultiDict[None]: - return self._skip_auto_headers or CIMultiDict() - - @property - def _writer(self) -> Optional["asyncio.Task[None]"]: - return self.__writer - - @_writer.setter - def _writer(self, writer: "asyncio.Task[None]") -> None: - if self.__writer is not None: - self.__writer.remove_done_callback(self.__reset_writer) - self.__writer = writer - writer.add_done_callback(self.__reset_writer) - - def is_ssl(self) -> bool: - return self.url.scheme in _SSL_SCHEMES - - @property - def ssl(self) -> Union["SSLContext", bool, Fingerprint]: - return self._ssl - - @property - def connection_key(self) -> ConnectionKey: - if proxy_headers := self.proxy_headers: - h: Optional[int] = hash(tuple(proxy_headers.items())) - else: - h = None - url = self.url - return tuple.__new__( - ConnectionKey, - ( - url.raw_host or "", - url.port, - url.scheme in _SSL_SCHEMES, - self._ssl, - self.proxy, - self.proxy_auth, - h, - ), - ) - - @property - def host(self) -> str: - ret = self.url.raw_host - assert ret is not None - return ret - - @property - def port(self) -> Optional[int]: - return self.url.port - - @property - def body(self) -> Union[payload.Payload, Literal[b""]]: - """Request body.""" - # empty body is represented as bytes for backwards compatibility - return self._body or b"" - - @body.setter - def body(self, value: Any) -> None: - """Set request body with warning for non-autoclose payloads. - - WARNING: This setter must be called from within an event loop and is not - thread-safe. Setting body outside of an event loop may raise RuntimeError - when closing file-based payloads. - - DEPRECATED: Direct assignment to body is deprecated and will be removed - in a future version. Use await update_body() instead for proper resource - management. - """ - # Close existing payload if present - if self._body is not None: - # Warn if the payload needs manual closing - # stacklevel=3: user code -> body setter -> _warn_if_unclosed_payload - _warn_if_unclosed_payload(self._body, stacklevel=3) - # NOTE: In the future, when we remove sync close support, - # this setter will need to be removed and only the async - # update_body() method will be available. For now, we call - # _close() for backwards compatibility. - self._body._close() - self._update_body(value) - - @property - def request_info(self) -> RequestInfo: - headers: CIMultiDictProxy[str] = CIMultiDictProxy(self.headers) - # These are created on every request, so we use a NamedTuple - # for performance reasons. We don't use the RequestInfo.__new__ - # method because it has a different signature which is provided - # for backwards compatibility only. - return tuple.__new__( - RequestInfo, (self.url, self.method, headers, self.original_url) - ) - - @property - def session(self) -> "ClientSession": - """Return the ClientSession instance. - - This property provides access to the ClientSession that initiated - this request, allowing middleware to make additional requests - using the same session. - """ - return self._session - - def update_host(self, url: URL) -> None: - """Update destination host, port and connection type (ssl).""" - # get host/port - if not url.raw_host: - raise InvalidURL(url) - - # basic auth info - if url.raw_user or url.raw_password: - self.auth = helpers.BasicAuth(url.user or "", url.password or "") - - def update_version(self, version: Union[http.HttpVersion, str]) -> None: - """Convert request version to two elements tuple. - - parser HTTP version '1.1' => (1, 1) - """ - if isinstance(version, str): - v = [part.strip() for part in version.split(".", 1)] - try: - version = http.HttpVersion(int(v[0]), int(v[1])) - except ValueError: - raise ValueError( - f"Can not parse http version number: {version}" - ) from None - self.version = version - - def update_headers(self, headers: Optional[LooseHeaders]) -> None: - """Update request headers.""" - self.headers: CIMultiDict[str] = CIMultiDict() - - # Build the host header - host = self.url.host_port_subcomponent - - # host_port_subcomponent is None when the URL is a relative URL. - # but we know we do not have a relative URL here. - assert host is not None - self.headers[hdrs.HOST] = host - - if not headers: - return - - if isinstance(headers, (dict, MultiDictProxy, MultiDict)): - headers = headers.items() - - for key, value in headers: # type: ignore[misc] - # A special case for Host header - if key in hdrs.HOST_ALL: - self.headers[key] = value - else: - self.headers.add(key, value) - - def update_auto_headers(self, skip_auto_headers: Optional[Iterable[str]]) -> None: - if skip_auto_headers is not None: - self._skip_auto_headers = CIMultiDict( - (hdr, None) for hdr in sorted(skip_auto_headers) - ) - used_headers = self.headers.copy() - used_headers.extend(self._skip_auto_headers) # type: ignore[arg-type] - else: - # Fast path when there are no headers to skip - # which is the most common case. - used_headers = self.headers - - for hdr, val in self.DEFAULT_HEADERS.items(): - if hdr not in used_headers: - self.headers[hdr] = val - - if hdrs.USER_AGENT not in used_headers: - self.headers[hdrs.USER_AGENT] = SERVER_SOFTWARE - - def update_cookies(self, cookies: Optional[LooseCookies]) -> None: - """Update request cookies header.""" - if not cookies: - return - - c = SimpleCookie() - if hdrs.COOKIE in self.headers: - # parse_cookie_header for RFC 6265 compliant Cookie header parsing - c.update(parse_cookie_header(self.headers.get(hdrs.COOKIE, ""))) - del self.headers[hdrs.COOKIE] - - if isinstance(cookies, Mapping): - iter_cookies = cookies.items() - else: - iter_cookies = cookies # type: ignore[assignment] - for name, value in iter_cookies: - if isinstance(value, Morsel): - # Use helper to preserve coded_value exactly as sent by server - c[name] = preserve_morsel_with_coded_value(value) - else: - c[name] = value # type: ignore[assignment] - - self.headers[hdrs.COOKIE] = c.output(header="", sep=";").strip() - - def update_content_encoding(self, data: Any) -> None: - """Set request content encoding.""" - if not data: - # Don't compress an empty body. - self.compress = None - return - - if self.headers.get(hdrs.CONTENT_ENCODING): - if self.compress: - raise ValueError( - "compress can not be set if Content-Encoding header is set" - ) - elif self.compress: - if not isinstance(self.compress, str): - self.compress = "deflate" - self.headers[hdrs.CONTENT_ENCODING] = self.compress - self.chunked = True # enable chunked, no need to deal with length - - def update_transfer_encoding(self) -> None: - """Analyze transfer-encoding header.""" - te = self.headers.get(hdrs.TRANSFER_ENCODING, "").lower() - - if "chunked" in te: - if self.chunked: - raise ValueError( - "chunked can not be set " - 'if "Transfer-Encoding: chunked" header is set' - ) - - elif self.chunked: - if hdrs.CONTENT_LENGTH in self.headers: - raise ValueError( - "chunked can not be set if Content-Length header is set" - ) - - self.headers[hdrs.TRANSFER_ENCODING] = "chunked" - - def update_auth(self, auth: Optional[BasicAuth], trust_env: bool = False) -> None: - """Set basic auth.""" - if auth is None: - auth = self.auth - if auth is None: - return - - if not isinstance(auth, helpers.BasicAuth): - raise TypeError("BasicAuth() tuple is required instead") - - self.headers[hdrs.AUTHORIZATION] = auth.encode() - - def update_body_from_data(self, body: Any, _stacklevel: int = 3) -> None: - """Update request body from data.""" - if self._body is not None: - _warn_if_unclosed_payload(self._body, stacklevel=_stacklevel) - - if body is None: - self._body = None - # Set Content-Length to 0 when body is None for methods that expect a body - if ( - self.method not in self.GET_METHODS - and not self.chunked - and hdrs.CONTENT_LENGTH not in self.headers - ): - self.headers[hdrs.CONTENT_LENGTH] = "0" - return - - # FormData - maybe_payload = body() if isinstance(body, FormData) else body - - try: - body_payload = payload.PAYLOAD_REGISTRY.get(maybe_payload, disposition=None) - except payload.LookupError: - body_payload = FormData(maybe_payload)() # type: ignore[arg-type] - - self._body = body_payload - # enable chunked encoding if needed - if not self.chunked and hdrs.CONTENT_LENGTH not in self.headers: - if (size := body_payload.size) is not None: - self.headers[hdrs.CONTENT_LENGTH] = str(size) - else: - self.chunked = True - - # copy payload headers - assert body_payload.headers - headers = self.headers - skip_headers = self._skip_auto_headers - for key, value in body_payload.headers.items(): - if key in headers or (skip_headers is not None and key in skip_headers): - continue - headers[key] = value - - def _update_body(self, body: Any) -> None: - """Update request body after its already been set.""" - # Remove existing Content-Length header since body is changing - if hdrs.CONTENT_LENGTH in self.headers: - del self.headers[hdrs.CONTENT_LENGTH] - - # Remove existing Transfer-Encoding header to avoid conflicts - if self.chunked and hdrs.TRANSFER_ENCODING in self.headers: - del self.headers[hdrs.TRANSFER_ENCODING] - - # Now update the body using the existing method - # Called from _update_body, add 1 to stacklevel from caller - self.update_body_from_data(body, _stacklevel=4) - - # Update transfer encoding headers if needed (same logic as __init__) - if body is not None or self.method not in self.GET_METHODS: - self.update_transfer_encoding() - - async def update_body(self, body: Any) -> None: - """ - Update request body and close previous payload if needed. - - This method safely updates the request body by first closing any existing - payload to prevent resource leaks, then setting the new body. - - IMPORTANT: Always use this method instead of setting request.body directly. - Direct assignment to request.body will leak resources if the previous body - contains file handles, streams, or other resources that need cleanup. - - Args: - body: The new body content. Can be: - - bytes/bytearray: Raw binary data - - str: Text data (will be encoded using charset from Content-Type) - - FormData: Form data that will be encoded as multipart/form-data - - Payload: A pre-configured payload object - - AsyncIterable: An async iterable of bytes chunks - - File-like object: Will be read and sent as binary data - - None: Clears the body - - Usage: - # CORRECT: Use update_body - await request.update_body(b"new request data") - - # WRONG: Don't set body directly - # request.body = b"new request data" # This will leak resources! - - # Update with form data - form_data = FormData() - form_data.add_field('field', 'value') - await request.update_body(form_data) - - # Clear body - await request.update_body(None) - - Note: - This method is async because it may need to close file handles or - other resources associated with the previous payload. Always await - this method to ensure proper cleanup. - - Warning: - Setting request.body directly is highly discouraged and can lead to: - - Resource leaks (unclosed file handles, streams) - - Memory leaks (unreleased buffers) - - Unexpected behavior with streaming payloads - - It is not recommended to change the payload type in middleware. If the - body was already set (e.g., as bytes), it's best to keep the same type - rather than converting it (e.g., to str) as this may result in unexpected - behavior. - - See Also: - - update_body_from_data: Synchronous body update without cleanup - - body property: Direct body access (STRONGLY DISCOURAGED) - - """ - # Close existing payload if it exists and needs closing - if self._body is not None: - await self._body.close() - self._update_body(body) - - def update_expect_continue(self, expect: bool = False) -> None: - if expect: - self.headers[hdrs.EXPECT] = "100-continue" - elif ( - hdrs.EXPECT in self.headers - and self.headers[hdrs.EXPECT].lower() == "100-continue" - ): - expect = True - - if expect: - self._continue = self.loop.create_future() - - def update_proxy( - self, - proxy: Optional[URL], - proxy_auth: Optional[BasicAuth], - proxy_headers: Optional[LooseHeaders], - ) -> None: - self.proxy = proxy - if proxy is None: - self.proxy_auth = None - self.proxy_headers = None - return - - if proxy_auth and not isinstance(proxy_auth, helpers.BasicAuth): - raise ValueError("proxy_auth must be None or BasicAuth() tuple") - self.proxy_auth = proxy_auth - - if proxy_headers is not None and not isinstance( - proxy_headers, (MultiDict, MultiDictProxy) - ): - proxy_headers = CIMultiDict(proxy_headers) - self.proxy_headers = proxy_headers - - async def write_bytes( - self, - writer: AbstractStreamWriter, - conn: "Connection", - content_length: Optional[int] = None, - ) -> None: - """ - Write the request body to the connection stream. - - This method handles writing different types of request bodies: - 1. Payload objects (using their specialized write_with_length method) - 2. Bytes/bytearray objects - 3. Iterable body content - - Args: - writer: The stream writer to write the body to - conn: The connection being used for this request - content_length: Optional maximum number of bytes to write from the body - (None means write the entire body) - - The method properly handles: - - Waiting for 100-Continue responses if required - - Content length constraints for chunked encoding - - Error handling for network issues, cancellation, and other exceptions - - Signaling EOF and timeout management - - Raises: - ClientOSError: When there's an OS-level error writing the body - ClientConnectionError: When there's a general connection error - asyncio.CancelledError: When the operation is cancelled - - """ - # 100 response - if self._continue is not None: - # Force headers to be sent before waiting for 100-continue - writer.send_headers() - await writer.drain() - await self._continue - - protocol = conn.protocol - assert protocol is not None - try: - # This should be a rare case but the - # self._body can be set to None while - # the task is being started or we wait above - # for the 100-continue response. - # The more likely case is we have an empty - # payload, but 100-continue is still expected. - if self._body is not None: - await self._body.write_with_length(writer, content_length) - except OSError as underlying_exc: - reraised_exc = underlying_exc - - # Distinguish between timeout and other OS errors for better error reporting - exc_is_not_timeout = underlying_exc.errno is not None or not isinstance( - underlying_exc, asyncio.TimeoutError - ) - if exc_is_not_timeout: - reraised_exc = ClientOSError( - underlying_exc.errno, - f"Can not write request body for {self.url !s}", - ) - - set_exception(protocol, reraised_exc, underlying_exc) - except asyncio.CancelledError: - # Body hasn't been fully sent, so connection can't be reused - conn.close() - raise - except Exception as underlying_exc: - set_exception( - protocol, - ClientConnectionError( - "Failed to send bytes into the underlying connection " - f"{conn !s}: {underlying_exc!r}", - ), - underlying_exc, - ) - else: - # Successfully wrote the body, signal EOF and start response timeout - await writer.write_eof() - protocol.start_timeout() - - async def send(self, conn: "Connection") -> "ClientResponse": - # Specify request target: - # - CONNECT request must send authority form URI - # - not CONNECT proxy must send absolute form URI - # - most common is origin form URI - if self.method == hdrs.METH_CONNECT: - connect_host = self.url.host_subcomponent - assert connect_host is not None - path = f"{connect_host}:{self.url.port}" - elif self.proxy and not self.is_ssl(): - path = str(self.url) - else: - path = self.url.raw_path_qs - - protocol = conn.protocol - assert protocol is not None - writer = StreamWriter( - protocol, - self.loop, - on_chunk_sent=( - functools.partial(self._on_chunk_request_sent, self.method, self.url) - if self._traces - else None - ), - on_headers_sent=( - functools.partial(self._on_headers_request_sent, self.method, self.url) - if self._traces - else None - ), - ) - - if self.compress: - writer.enable_compression(self.compress) # type: ignore[arg-type] - - if self.chunked is not None: - writer.enable_chunking() - - # set default content-type - if ( - self.method in self.POST_METHODS - and ( - self._skip_auto_headers is None - or hdrs.CONTENT_TYPE not in self._skip_auto_headers - ) - and hdrs.CONTENT_TYPE not in self.headers - ): - self.headers[hdrs.CONTENT_TYPE] = "application/octet-stream" - - v = self.version - if hdrs.CONNECTION not in self.headers: - if conn._connector.force_close: - if v == HttpVersion11: - self.headers[hdrs.CONNECTION] = "close" - elif v == HttpVersion10: - self.headers[hdrs.CONNECTION] = "keep-alive" - - # status + headers - status_line = f"{self.method} {path} HTTP/{v.major}.{v.minor}" - - # Buffer headers for potential coalescing with body - await writer.write_headers(status_line, self.headers) - - task: Optional["asyncio.Task[None]"] - if self._body or self._continue is not None or protocol.writing_paused: - coro = self.write_bytes(writer, conn, self._get_content_length()) - if sys.version_info >= (3, 12): - # Optimization for Python 3.12, try to write - # bytes immediately to avoid having to schedule - # the task on the event loop. - task = asyncio.Task(coro, loop=self.loop, eager_start=True) - else: - task = self.loop.create_task(coro) - if task.done(): - task = None - else: - self._writer = task - else: - # We have nothing to write because - # - there is no body - # - the protocol does not have writing paused - # - we are not waiting for a 100-continue response - protocol.start_timeout() - writer.set_eof() - task = None - response_class = self.response_class - assert response_class is not None - self.response = response_class( - self.method, - self.original_url, - writer=task, - continue100=self._continue, - timer=self._timer, - request_info=self.request_info, - traces=self._traces, - loop=self.loop, - session=self._session, - ) - return self.response - - async def close(self) -> None: - if self.__writer is not None: - try: - await self.__writer - except asyncio.CancelledError: - if ( - sys.version_info >= (3, 11) - and (task := asyncio.current_task()) - and task.cancelling() - ): - raise - - def terminate(self) -> None: - if self.__writer is not None: - if not self.loop.is_closed(): - self.__writer.cancel() - self.__writer.remove_done_callback(self.__reset_writer) - self.__writer = None - - async def _on_chunk_request_sent(self, method: str, url: URL, chunk: bytes) -> None: - for trace in self._traces: - await trace.send_request_chunk_sent(method, url, chunk) - - async def _on_headers_request_sent( - self, method: str, url: URL, headers: "CIMultiDict[str]" - ) -> None: - for trace in self._traces: - await trace.send_request_headers(method, url, headers) diff --git a/venv/lib/python3.9/site-packages/aiohttp/client_ws.py b/venv/lib/python3.9/site-packages/aiohttp/client_ws.py deleted file mode 100644 index daa57d1..0000000 --- a/venv/lib/python3.9/site-packages/aiohttp/client_ws.py +++ /dev/null @@ -1,428 +0,0 @@ -"""WebSocket client for asyncio.""" - -import asyncio -import sys -from types import TracebackType -from typing import Any, Optional, Type, cast - -import attr - -from ._websocket.reader import WebSocketDataQueue -from .client_exceptions import ClientError, ServerTimeoutError, WSMessageTypeError -from .client_reqrep import ClientResponse -from .helpers import calculate_timeout_when, set_result -from .http import ( - WS_CLOSED_MESSAGE, - WS_CLOSING_MESSAGE, - WebSocketError, - WSCloseCode, - WSMessage, - WSMsgType, -) -from .http_websocket import _INTERNAL_RECEIVE_TYPES, WebSocketWriter -from .streams import EofStream -from .typedefs import ( - DEFAULT_JSON_DECODER, - DEFAULT_JSON_ENCODER, - JSONDecoder, - JSONEncoder, -) - -if sys.version_info >= (3, 11): - import asyncio as async_timeout -else: - import async_timeout - - -@attr.s(frozen=True, slots=True) -class ClientWSTimeout: - ws_receive = attr.ib(type=Optional[float], default=None) - ws_close = attr.ib(type=Optional[float], default=None) - - -DEFAULT_WS_CLIENT_TIMEOUT = ClientWSTimeout(ws_receive=None, ws_close=10.0) - - -class ClientWebSocketResponse: - def __init__( - self, - reader: WebSocketDataQueue, - writer: WebSocketWriter, - protocol: Optional[str], - response: ClientResponse, - timeout: ClientWSTimeout, - autoclose: bool, - autoping: bool, - loop: asyncio.AbstractEventLoop, - *, - heartbeat: Optional[float] = None, - compress: int = 0, - client_notakeover: bool = False, - ) -> None: - self._response = response - self._conn = response.connection - - self._writer = writer - self._reader = reader - self._protocol = protocol - self._closed = False - self._closing = False - self._close_code: Optional[int] = None - self._timeout = timeout - self._autoclose = autoclose - self._autoping = autoping - self._heartbeat = heartbeat - self._heartbeat_cb: Optional[asyncio.TimerHandle] = None - self._heartbeat_when: float = 0.0 - if heartbeat is not None: - self._pong_heartbeat = heartbeat / 2.0 - self._pong_response_cb: Optional[asyncio.TimerHandle] = None - self._loop = loop - self._waiting: bool = False - self._close_wait: Optional[asyncio.Future[None]] = None - self._exception: Optional[BaseException] = None - self._compress = compress - self._client_notakeover = client_notakeover - self._ping_task: Optional[asyncio.Task[None]] = None - - self._reset_heartbeat() - - def _cancel_heartbeat(self) -> None: - self._cancel_pong_response_cb() - if self._heartbeat_cb is not None: - self._heartbeat_cb.cancel() - self._heartbeat_cb = None - if self._ping_task is not None: - self._ping_task.cancel() - self._ping_task = None - - def _cancel_pong_response_cb(self) -> None: - if self._pong_response_cb is not None: - self._pong_response_cb.cancel() - self._pong_response_cb = None - - def _reset_heartbeat(self) -> None: - if self._heartbeat is None: - return - self._cancel_pong_response_cb() - loop = self._loop - assert loop is not None - conn = self._conn - timeout_ceil_threshold = ( - conn._connector._timeout_ceil_threshold if conn is not None else 5 - ) - now = loop.time() - when = calculate_timeout_when(now, self._heartbeat, timeout_ceil_threshold) - self._heartbeat_when = when - if self._heartbeat_cb is None: - # We do not cancel the previous heartbeat_cb here because - # it generates a significant amount of TimerHandle churn - # which causes asyncio to rebuild the heap frequently. - # Instead _send_heartbeat() will reschedule the next - # heartbeat if it fires too early. - self._heartbeat_cb = loop.call_at(when, self._send_heartbeat) - - def _send_heartbeat(self) -> None: - self._heartbeat_cb = None - loop = self._loop - now = loop.time() - if now < self._heartbeat_when: - # Heartbeat fired too early, reschedule - self._heartbeat_cb = loop.call_at( - self._heartbeat_when, self._send_heartbeat - ) - return - - conn = self._conn - timeout_ceil_threshold = ( - conn._connector._timeout_ceil_threshold if conn is not None else 5 - ) - when = calculate_timeout_when(now, self._pong_heartbeat, timeout_ceil_threshold) - self._cancel_pong_response_cb() - self._pong_response_cb = loop.call_at(when, self._pong_not_received) - - coro = self._writer.send_frame(b"", WSMsgType.PING) - if sys.version_info >= (3, 12): - # Optimization for Python 3.12, try to send the ping - # immediately to avoid having to schedule - # the task on the event loop. - ping_task = asyncio.Task(coro, loop=loop, eager_start=True) - else: - ping_task = loop.create_task(coro) - - if not ping_task.done(): - self._ping_task = ping_task - ping_task.add_done_callback(self._ping_task_done) - else: - self._ping_task_done(ping_task) - - def _ping_task_done(self, task: "asyncio.Task[None]") -> None: - """Callback for when the ping task completes.""" - if not task.cancelled() and (exc := task.exception()): - self._handle_ping_pong_exception(exc) - self._ping_task = None - - def _pong_not_received(self) -> None: - self._handle_ping_pong_exception( - ServerTimeoutError(f"No PONG received after {self._pong_heartbeat} seconds") - ) - - def _handle_ping_pong_exception(self, exc: BaseException) -> None: - """Handle exceptions raised during ping/pong processing.""" - if self._closed: - return - self._set_closed() - self._close_code = WSCloseCode.ABNORMAL_CLOSURE - self._exception = exc - self._response.close() - if self._waiting and not self._closing: - self._reader.feed_data(WSMessage(WSMsgType.ERROR, exc, None), 0) - - def _set_closed(self) -> None: - """Set the connection to closed. - - Cancel any heartbeat timers and set the closed flag. - """ - self._closed = True - self._cancel_heartbeat() - - def _set_closing(self) -> None: - """Set the connection to closing. - - Cancel any heartbeat timers and set the closing flag. - """ - self._closing = True - self._cancel_heartbeat() - - @property - def closed(self) -> bool: - return self._closed - - @property - def close_code(self) -> Optional[int]: - return self._close_code - - @property - def protocol(self) -> Optional[str]: - return self._protocol - - @property - def compress(self) -> int: - return self._compress - - @property - def client_notakeover(self) -> bool: - return self._client_notakeover - - def get_extra_info(self, name: str, default: Any = None) -> Any: - """extra info from connection transport""" - conn = self._response.connection - if conn is None: - return default - transport = conn.transport - if transport is None: - return default - return transport.get_extra_info(name, default) - - def exception(self) -> Optional[BaseException]: - return self._exception - - async def ping(self, message: bytes = b"") -> None: - await self._writer.send_frame(message, WSMsgType.PING) - - async def pong(self, message: bytes = b"") -> None: - await self._writer.send_frame(message, WSMsgType.PONG) - - async def send_frame( - self, message: bytes, opcode: WSMsgType, compress: Optional[int] = None - ) -> None: - """Send a frame over the websocket.""" - await self._writer.send_frame(message, opcode, compress) - - async def send_str(self, data: str, compress: Optional[int] = None) -> None: - if not isinstance(data, str): - raise TypeError("data argument must be str (%r)" % type(data)) - await self._writer.send_frame( - data.encode("utf-8"), WSMsgType.TEXT, compress=compress - ) - - async def send_bytes(self, data: bytes, compress: Optional[int] = None) -> None: - if not isinstance(data, (bytes, bytearray, memoryview)): - raise TypeError("data argument must be byte-ish (%r)" % type(data)) - await self._writer.send_frame(data, WSMsgType.BINARY, compress=compress) - - async def send_json( - self, - data: Any, - compress: Optional[int] = None, - *, - dumps: JSONEncoder = DEFAULT_JSON_ENCODER, - ) -> None: - await self.send_str(dumps(data), compress=compress) - - async def close(self, *, code: int = WSCloseCode.OK, message: bytes = b"") -> bool: - # we need to break `receive()` cycle first, - # `close()` may be called from different task - if self._waiting and not self._closing: - assert self._loop is not None - self._close_wait = self._loop.create_future() - self._set_closing() - self._reader.feed_data(WS_CLOSING_MESSAGE, 0) - await self._close_wait - - if self._closed: - return False - - self._set_closed() - try: - await self._writer.close(code, message) - except asyncio.CancelledError: - self._close_code = WSCloseCode.ABNORMAL_CLOSURE - self._response.close() - raise - except Exception as exc: - self._close_code = WSCloseCode.ABNORMAL_CLOSURE - self._exception = exc - self._response.close() - return True - - if self._close_code: - self._response.close() - return True - - while True: - try: - async with async_timeout.timeout(self._timeout.ws_close): - msg = await self._reader.read() - except asyncio.CancelledError: - self._close_code = WSCloseCode.ABNORMAL_CLOSURE - self._response.close() - raise - except Exception as exc: - self._close_code = WSCloseCode.ABNORMAL_CLOSURE - self._exception = exc - self._response.close() - return True - - if msg.type is WSMsgType.CLOSE: - self._close_code = msg.data - self._response.close() - return True - - async def receive(self, timeout: Optional[float] = None) -> WSMessage: - receive_timeout = timeout or self._timeout.ws_receive - - while True: - if self._waiting: - raise RuntimeError("Concurrent call to receive() is not allowed") - - if self._closed: - return WS_CLOSED_MESSAGE - elif self._closing: - await self.close() - return WS_CLOSED_MESSAGE - - try: - self._waiting = True - try: - if receive_timeout: - # Entering the context manager and creating - # Timeout() object can take almost 50% of the - # run time in this loop so we avoid it if - # there is no read timeout. - async with async_timeout.timeout(receive_timeout): - msg = await self._reader.read() - else: - msg = await self._reader.read() - self._reset_heartbeat() - finally: - self._waiting = False - if self._close_wait: - set_result(self._close_wait, None) - except (asyncio.CancelledError, asyncio.TimeoutError): - self._close_code = WSCloseCode.ABNORMAL_CLOSURE - raise - except EofStream: - self._close_code = WSCloseCode.OK - await self.close() - return WSMessage(WSMsgType.CLOSED, None, None) - except ClientError: - # Likely ServerDisconnectedError when connection is lost - self._set_closed() - self._close_code = WSCloseCode.ABNORMAL_CLOSURE - return WS_CLOSED_MESSAGE - except WebSocketError as exc: - self._close_code = exc.code - await self.close(code=exc.code) - return WSMessage(WSMsgType.ERROR, exc, None) - except Exception as exc: - self._exception = exc - self._set_closing() - self._close_code = WSCloseCode.ABNORMAL_CLOSURE - await self.close() - return WSMessage(WSMsgType.ERROR, exc, None) - - if msg.type not in _INTERNAL_RECEIVE_TYPES: - # If its not a close/closing/ping/pong message - # we can return it immediately - return msg - - if msg.type is WSMsgType.CLOSE: - self._set_closing() - self._close_code = msg.data - if not self._closed and self._autoclose: - await self.close() - elif msg.type is WSMsgType.CLOSING: - self._set_closing() - elif msg.type is WSMsgType.PING and self._autoping: - await self.pong(msg.data) - continue - elif msg.type is WSMsgType.PONG and self._autoping: - continue - - return msg - - async def receive_str(self, *, timeout: Optional[float] = None) -> str: - msg = await self.receive(timeout) - if msg.type is not WSMsgType.TEXT: - raise WSMessageTypeError( - f"Received message {msg.type}:{msg.data!r} is not WSMsgType.TEXT" - ) - return cast(str, msg.data) - - async def receive_bytes(self, *, timeout: Optional[float] = None) -> bytes: - msg = await self.receive(timeout) - if msg.type is not WSMsgType.BINARY: - raise WSMessageTypeError( - f"Received message {msg.type}:{msg.data!r} is not WSMsgType.BINARY" - ) - return cast(bytes, msg.data) - - async def receive_json( - self, - *, - loads: JSONDecoder = DEFAULT_JSON_DECODER, - timeout: Optional[float] = None, - ) -> Any: - data = await self.receive_str(timeout=timeout) - return loads(data) - - def __aiter__(self) -> "ClientWebSocketResponse": - return self - - async def __anext__(self) -> WSMessage: - msg = await self.receive() - if msg.type in (WSMsgType.CLOSE, WSMsgType.CLOSING, WSMsgType.CLOSED): - raise StopAsyncIteration - return msg - - async def __aenter__(self) -> "ClientWebSocketResponse": - return self - - async def __aexit__( - self, - exc_type: Optional[Type[BaseException]], - exc_val: Optional[BaseException], - exc_tb: Optional[TracebackType], - ) -> None: - await self.close() diff --git a/venv/lib/python3.9/site-packages/aiohttp/compression_utils.py b/venv/lib/python3.9/site-packages/aiohttp/compression_utils.py deleted file mode 100644 index e478d24..0000000 --- a/venv/lib/python3.9/site-packages/aiohttp/compression_utils.py +++ /dev/null @@ -1,348 +0,0 @@ -import asyncio -import sys -import zlib -from abc import ABC, abstractmethod -from concurrent.futures import Executor -from typing import Any, Final, Optional, Protocol, TypedDict, cast - -if sys.version_info >= (3, 12): - from collections.abc import Buffer -else: - from typing import Union - - Buffer = Union[bytes, bytearray, "memoryview[int]", "memoryview[bytes]"] - -try: - try: - import brotlicffi as brotli - except ImportError: - import brotli - - HAS_BROTLI = True -except ImportError: # pragma: no cover - HAS_BROTLI = False - -try: - if sys.version_info >= (3, 14): - from compression.zstd import ZstdDecompressor # noqa: I900 - else: # TODO(PY314): Remove mentions of backports.zstd across codebase - from backports.zstd import ZstdDecompressor - - HAS_ZSTD = True -except ImportError: - HAS_ZSTD = False - - -MAX_SYNC_CHUNK_SIZE = 4096 -DEFAULT_MAX_DECOMPRESS_SIZE = 2**25 # 32MiB - -# Unlimited decompression constants - different libraries use different conventions -ZLIB_MAX_LENGTH_UNLIMITED = 0 # zlib uses 0 to mean unlimited -ZSTD_MAX_LENGTH_UNLIMITED = -1 # zstd uses -1 to mean unlimited - - -class ZLibCompressObjProtocol(Protocol): - def compress(self, data: Buffer) -> bytes: ... - def flush(self, mode: int = ..., /) -> bytes: ... - - -class ZLibDecompressObjProtocol(Protocol): - def decompress(self, data: Buffer, max_length: int = ...) -> bytes: ... - def flush(self, length: int = ..., /) -> bytes: ... - - @property - def eof(self) -> bool: ... - - -class ZLibBackendProtocol(Protocol): - MAX_WBITS: int - Z_FULL_FLUSH: int - Z_SYNC_FLUSH: int - Z_BEST_SPEED: int - Z_FINISH: int - - def compressobj( - self, - level: int = ..., - method: int = ..., - wbits: int = ..., - memLevel: int = ..., - strategy: int = ..., - zdict: Optional[Buffer] = ..., - ) -> ZLibCompressObjProtocol: ... - def decompressobj( - self, wbits: int = ..., zdict: Buffer = ... - ) -> ZLibDecompressObjProtocol: ... - - def compress( - self, data: Buffer, /, level: int = ..., wbits: int = ... - ) -> bytes: ... - def decompress( - self, data: Buffer, /, wbits: int = ..., bufsize: int = ... - ) -> bytes: ... - - -class CompressObjArgs(TypedDict, total=False): - wbits: int - strategy: int - level: int - - -class ZLibBackendWrapper: - def __init__(self, _zlib_backend: ZLibBackendProtocol): - self._zlib_backend: ZLibBackendProtocol = _zlib_backend - - @property - def name(self) -> str: - return getattr(self._zlib_backend, "__name__", "undefined") - - @property - def MAX_WBITS(self) -> int: - return self._zlib_backend.MAX_WBITS - - @property - def Z_FULL_FLUSH(self) -> int: - return self._zlib_backend.Z_FULL_FLUSH - - @property - def Z_SYNC_FLUSH(self) -> int: - return self._zlib_backend.Z_SYNC_FLUSH - - @property - def Z_BEST_SPEED(self) -> int: - return self._zlib_backend.Z_BEST_SPEED - - @property - def Z_FINISH(self) -> int: - return self._zlib_backend.Z_FINISH - - def compressobj(self, *args: Any, **kwargs: Any) -> ZLibCompressObjProtocol: - return self._zlib_backend.compressobj(*args, **kwargs) - - def decompressobj(self, *args: Any, **kwargs: Any) -> ZLibDecompressObjProtocol: - return self._zlib_backend.decompressobj(*args, **kwargs) - - def compress(self, data: Buffer, *args: Any, **kwargs: Any) -> bytes: - return self._zlib_backend.compress(data, *args, **kwargs) - - def decompress(self, data: Buffer, *args: Any, **kwargs: Any) -> bytes: - return self._zlib_backend.decompress(data, *args, **kwargs) - - # Everything not explicitly listed in the Protocol we just pass through - def __getattr__(self, attrname: str) -> Any: - return getattr(self._zlib_backend, attrname) - - -ZLibBackend: ZLibBackendWrapper = ZLibBackendWrapper(zlib) - - -def set_zlib_backend(new_zlib_backend: ZLibBackendProtocol) -> None: - ZLibBackend._zlib_backend = new_zlib_backend - - -def encoding_to_mode( - encoding: Optional[str] = None, - suppress_deflate_header: bool = False, -) -> int: - if encoding == "gzip": - return 16 + ZLibBackend.MAX_WBITS - - return -ZLibBackend.MAX_WBITS if suppress_deflate_header else ZLibBackend.MAX_WBITS - - -class DecompressionBaseHandler(ABC): - def __init__( - self, - executor: Optional[Executor] = None, - max_sync_chunk_size: Optional[int] = MAX_SYNC_CHUNK_SIZE, - ): - """Base class for decompression handlers.""" - self._executor = executor - self._max_sync_chunk_size = max_sync_chunk_size - - @abstractmethod - def decompress_sync( - self, data: bytes, max_length: int = ZLIB_MAX_LENGTH_UNLIMITED - ) -> bytes: - """Decompress the given data.""" - - async def decompress( - self, data: bytes, max_length: int = ZLIB_MAX_LENGTH_UNLIMITED - ) -> bytes: - """Decompress the given data.""" - if ( - self._max_sync_chunk_size is not None - and len(data) > self._max_sync_chunk_size - ): - return await asyncio.get_event_loop().run_in_executor( - self._executor, self.decompress_sync, data, max_length - ) - return self.decompress_sync(data, max_length) - - -class ZLibCompressor: - def __init__( - self, - encoding: Optional[str] = None, - suppress_deflate_header: bool = False, - level: Optional[int] = None, - wbits: Optional[int] = None, - strategy: Optional[int] = None, - executor: Optional[Executor] = None, - max_sync_chunk_size: Optional[int] = MAX_SYNC_CHUNK_SIZE, - ): - self._executor = executor - self._max_sync_chunk_size = max_sync_chunk_size - self._mode = ( - encoding_to_mode(encoding, suppress_deflate_header) - if wbits is None - else wbits - ) - self._zlib_backend: Final = ZLibBackendWrapper(ZLibBackend._zlib_backend) - - kwargs: CompressObjArgs = {} - kwargs["wbits"] = self._mode - if strategy is not None: - kwargs["strategy"] = strategy - if level is not None: - kwargs["level"] = level - self._compressor = self._zlib_backend.compressobj(**kwargs) - - def compress_sync(self, data: bytes) -> bytes: - return self._compressor.compress(data) - - async def compress(self, data: bytes) -> bytes: - """Compress the data and returned the compressed bytes. - - Note that flush() must be called after the last call to compress() - - If the data size is large than the max_sync_chunk_size, the compression - will be done in the executor. Otherwise, the compression will be done - in the event loop. - - **WARNING: This method is NOT cancellation-safe when used with flush().** - If this operation is cancelled, the compressor state may be corrupted. - The connection MUST be closed after cancellation to avoid data corruption - in subsequent compress operations. - - For cancellation-safe compression (e.g., WebSocket), the caller MUST wrap - compress() + flush() + send operations in a shield and lock to ensure atomicity. - """ - # For large payloads, offload compression to executor to avoid blocking event loop - should_use_executor = ( - self._max_sync_chunk_size is not None - and len(data) > self._max_sync_chunk_size - ) - if should_use_executor: - return await asyncio.get_running_loop().run_in_executor( - self._executor, self._compressor.compress, data - ) - return self.compress_sync(data) - - def flush(self, mode: Optional[int] = None) -> bytes: - """Flush the compressor synchronously. - - **WARNING: This method is NOT cancellation-safe when called after compress().** - The flush() operation accesses shared compressor state. If compress() was - cancelled, calling flush() may result in corrupted data. The connection MUST - be closed after compress() cancellation. - - For cancellation-safe compression (e.g., WebSocket), the caller MUST wrap - compress() + flush() + send operations in a shield and lock to ensure atomicity. - """ - return self._compressor.flush( - mode if mode is not None else self._zlib_backend.Z_FINISH - ) - - -class ZLibDecompressor(DecompressionBaseHandler): - def __init__( - self, - encoding: Optional[str] = None, - suppress_deflate_header: bool = False, - executor: Optional[Executor] = None, - max_sync_chunk_size: Optional[int] = MAX_SYNC_CHUNK_SIZE, - ): - super().__init__(executor=executor, max_sync_chunk_size=max_sync_chunk_size) - self._mode = encoding_to_mode(encoding, suppress_deflate_header) - self._zlib_backend: Final = ZLibBackendWrapper(ZLibBackend._zlib_backend) - self._decompressor = self._zlib_backend.decompressobj(wbits=self._mode) - - def decompress_sync( - self, data: Buffer, max_length: int = ZLIB_MAX_LENGTH_UNLIMITED - ) -> bytes: - return self._decompressor.decompress(data, max_length) - - def flush(self, length: int = 0) -> bytes: - return ( - self._decompressor.flush(length) - if length > 0 - else self._decompressor.flush() - ) - - @property - def eof(self) -> bool: - return self._decompressor.eof - - -class BrotliDecompressor(DecompressionBaseHandler): - # Supports both 'brotlipy' and 'Brotli' packages - # since they share an import name. The top branches - # are for 'brotlipy' and bottom branches for 'Brotli' - def __init__( - self, - executor: Optional[Executor] = None, - max_sync_chunk_size: Optional[int] = MAX_SYNC_CHUNK_SIZE, - ) -> None: - """Decompress data using the Brotli library.""" - if not HAS_BROTLI: - raise RuntimeError( - "The brotli decompression is not available. " - "Please install `Brotli` module" - ) - self._obj = brotli.Decompressor() - super().__init__(executor=executor, max_sync_chunk_size=max_sync_chunk_size) - - def decompress_sync( - self, data: Buffer, max_length: int = ZLIB_MAX_LENGTH_UNLIMITED - ) -> bytes: - """Decompress the given data.""" - if hasattr(self._obj, "decompress"): - return cast(bytes, self._obj.decompress(data, max_length)) - return cast(bytes, self._obj.process(data, max_length)) - - def flush(self) -> bytes: - """Flush the decompressor.""" - if hasattr(self._obj, "flush"): - return cast(bytes, self._obj.flush()) - return b"" - - -class ZSTDDecompressor(DecompressionBaseHandler): - def __init__( - self, - executor: Optional[Executor] = None, - max_sync_chunk_size: Optional[int] = MAX_SYNC_CHUNK_SIZE, - ) -> None: - if not HAS_ZSTD: - raise RuntimeError( - "The zstd decompression is not available. " - "Please install `backports.zstd` module" - ) - self._obj = ZstdDecompressor() - super().__init__(executor=executor, max_sync_chunk_size=max_sync_chunk_size) - - def decompress_sync( - self, data: bytes, max_length: int = ZLIB_MAX_LENGTH_UNLIMITED - ) -> bytes: - # zstd uses -1 for unlimited, while zlib uses 0 for unlimited - # Convert the zlib convention (0=unlimited) to zstd convention (-1=unlimited) - zstd_max_length = ( - ZSTD_MAX_LENGTH_UNLIMITED - if max_length == ZLIB_MAX_LENGTH_UNLIMITED - else max_length - ) - return self._obj.decompress(data, zstd_max_length) - - def flush(self) -> bytes: - return b"" diff --git a/venv/lib/python3.9/site-packages/aiohttp/connector.py b/venv/lib/python3.9/site-packages/aiohttp/connector.py deleted file mode 100644 index ce28ce0..0000000 --- a/venv/lib/python3.9/site-packages/aiohttp/connector.py +++ /dev/null @@ -1,1854 +0,0 @@ -import asyncio -import functools -import random -import socket -import sys -import traceback -import warnings -from collections import OrderedDict, defaultdict, deque -from contextlib import suppress -from http import HTTPStatus -from itertools import chain, cycle, islice -from time import monotonic -from types import TracebackType -from typing import ( - TYPE_CHECKING, - Any, - Awaitable, - Callable, - DefaultDict, - Deque, - Dict, - Iterator, - List, - Literal, - Optional, - Sequence, - Set, - Tuple, - Type, - Union, - cast, -) - -import aiohappyeyeballs -from aiohappyeyeballs import AddrInfoType, SocketFactoryType - -from . import hdrs, helpers -from .abc import AbstractResolver, ResolveResult -from .client_exceptions import ( - ClientConnectionError, - ClientConnectorCertificateError, - ClientConnectorDNSError, - ClientConnectorError, - ClientConnectorSSLError, - ClientHttpProxyError, - ClientProxyConnectionError, - ServerFingerprintMismatch, - UnixClientConnectorError, - cert_errors, - ssl_errors, -) -from .client_proto import ResponseHandler -from .client_reqrep import ClientRequest, Fingerprint, _merge_ssl_params -from .helpers import ( - _SENTINEL, - ceil_timeout, - is_ip_address, - noop, - sentinel, - set_exception, - set_result, -) -from .log import client_logger -from .resolver import DefaultResolver - -if sys.version_info >= (3, 12): - from collections.abc import Buffer -else: - Buffer = Union[bytes, bytearray, "memoryview[int]", "memoryview[bytes]"] - -if TYPE_CHECKING: - import ssl - - SSLContext = ssl.SSLContext -else: - try: - import ssl - - SSLContext = ssl.SSLContext - except ImportError: # pragma: no cover - ssl = None # type: ignore[assignment] - SSLContext = object # type: ignore[misc,assignment] - -EMPTY_SCHEMA_SET = frozenset({""}) -HTTP_SCHEMA_SET = frozenset({"http", "https"}) -WS_SCHEMA_SET = frozenset({"ws", "wss"}) - -HTTP_AND_EMPTY_SCHEMA_SET = HTTP_SCHEMA_SET | EMPTY_SCHEMA_SET -HIGH_LEVEL_SCHEMA_SET = HTTP_AND_EMPTY_SCHEMA_SET | WS_SCHEMA_SET - -NEEDS_CLEANUP_CLOSED = (3, 13, 0) <= sys.version_info < ( - 3, - 13, - 1, -) or sys.version_info < (3, 12, 8) -# Cleanup closed is no longer needed after https://github.com/python/cpython/pull/118960 -# which first appeared in Python 3.12.8 and 3.13.1 - - -__all__ = ( - "BaseConnector", - "TCPConnector", - "UnixConnector", - "NamedPipeConnector", - "AddrInfoType", - "SocketFactoryType", -) - - -if TYPE_CHECKING: - from .client import ClientTimeout - from .client_reqrep import ConnectionKey - from .tracing import Trace - - -class _DeprecationWaiter: - __slots__ = ("_awaitable", "_awaited") - - def __init__(self, awaitable: Awaitable[Any]) -> None: - self._awaitable = awaitable - self._awaited = False - - def __await__(self) -> Any: - self._awaited = True - return self._awaitable.__await__() - - def __del__(self) -> None: - if not self._awaited: - warnings.warn( - "Connector.close() is a coroutine, " - "please use await connector.close()", - DeprecationWarning, - ) - - -async def _wait_for_close(waiters: List[Awaitable[object]]) -> None: - """Wait for all waiters to finish closing.""" - results = await asyncio.gather(*waiters, return_exceptions=True) - for res in results: - if isinstance(res, Exception): - client_logger.debug("Error while closing connector: %r", res) - - -class Connection: - - _source_traceback = None - - def __init__( - self, - connector: "BaseConnector", - key: "ConnectionKey", - protocol: ResponseHandler, - loop: asyncio.AbstractEventLoop, - ) -> None: - self._key = key - self._connector = connector - self._loop = loop - self._protocol: Optional[ResponseHandler] = protocol - self._callbacks: List[Callable[[], None]] = [] - - if loop.get_debug(): - self._source_traceback = traceback.extract_stack(sys._getframe(1)) - - def __repr__(self) -> str: - return f"Connection<{self._key}>" - - def __del__(self, _warnings: Any = warnings) -> None: - if self._protocol is not None: - kwargs = {"source": self} - _warnings.warn(f"Unclosed connection {self!r}", ResourceWarning, **kwargs) - if self._loop.is_closed(): - return - - self._connector._release(self._key, self._protocol, should_close=True) - - context = {"client_connection": self, "message": "Unclosed connection"} - if self._source_traceback is not None: - context["source_traceback"] = self._source_traceback - self._loop.call_exception_handler(context) - - def __bool__(self) -> Literal[True]: - """Force subclasses to not be falsy, to make checks simpler.""" - return True - - @property - def loop(self) -> asyncio.AbstractEventLoop: - warnings.warn( - "connector.loop property is deprecated", DeprecationWarning, stacklevel=2 - ) - return self._loop - - @property - def transport(self) -> Optional[asyncio.Transport]: - if self._protocol is None: - return None - return self._protocol.transport - - @property - def protocol(self) -> Optional[ResponseHandler]: - return self._protocol - - def add_callback(self, callback: Callable[[], None]) -> None: - if callback is not None: - self._callbacks.append(callback) - - def _notify_release(self) -> None: - callbacks, self._callbacks = self._callbacks[:], [] - - for cb in callbacks: - with suppress(Exception): - cb() - - def close(self) -> None: - self._notify_release() - - if self._protocol is not None: - self._connector._release(self._key, self._protocol, should_close=True) - self._protocol = None - - def release(self) -> None: - self._notify_release() - - if self._protocol is not None: - self._connector._release(self._key, self._protocol) - self._protocol = None - - @property - def closed(self) -> bool: - return self._protocol is None or not self._protocol.is_connected() - - -class _ConnectTunnelConnection(Connection): - """Special connection wrapper for CONNECT tunnels that must never be pooled. - - This connection wraps the proxy connection that will be upgraded with TLS. - It must never be released to the pool because: - 1. Its 'closed' future will never complete, causing session.close() to hang - 2. It represents an intermediate state, not a reusable connection - 3. The real connection (with TLS) will be created separately - """ - - def release(self) -> None: - """Do nothing - don't pool or close the connection. - - These connections are an intermediate state during the CONNECT tunnel - setup and will be cleaned up naturally after the TLS upgrade. If they - were to be pooled, they would never be properly closed, causing - session.close() to wait forever for their 'closed' future. - """ - - -class _TransportPlaceholder: - """placeholder for BaseConnector.connect function""" - - __slots__ = ("closed", "transport") - - def __init__(self, closed_future: asyncio.Future[Optional[Exception]]) -> None: - """Initialize a placeholder for a transport.""" - self.closed = closed_future - self.transport = None - - def close(self) -> None: - """Close the placeholder.""" - - def abort(self) -> None: - """Abort the placeholder (does nothing).""" - - -class BaseConnector: - """Base connector class. - - keepalive_timeout - (optional) Keep-alive timeout. - force_close - Set to True to force close and do reconnect - after each request (and between redirects). - limit - The total number of simultaneous connections. - limit_per_host - Number of simultaneous connections to one host. - enable_cleanup_closed - Enables clean-up closed ssl transports. - Disabled by default. - timeout_ceil_threshold - Trigger ceiling of timeout values when - it's above timeout_ceil_threshold. - loop - Optional event loop. - """ - - _closed = True # prevent AttributeError in __del__ if ctor was failed - _source_traceback = None - - # abort transport after 2 seconds (cleanup broken connections) - _cleanup_closed_period = 2.0 - - allowed_protocol_schema_set = HIGH_LEVEL_SCHEMA_SET - - def __init__( - self, - *, - keepalive_timeout: Union[object, None, float] = sentinel, - force_close: bool = False, - limit: int = 100, - limit_per_host: int = 0, - enable_cleanup_closed: bool = False, - loop: Optional[asyncio.AbstractEventLoop] = None, - timeout_ceil_threshold: float = 5, - ) -> None: - - if force_close: - if keepalive_timeout is not None and keepalive_timeout is not sentinel: - raise ValueError( - "keepalive_timeout cannot be set if force_close is True" - ) - else: - if keepalive_timeout is sentinel: - keepalive_timeout = 15.0 - - loop = loop or asyncio.get_running_loop() - self._timeout_ceil_threshold = timeout_ceil_threshold - - self._closed = False - if loop.get_debug(): - self._source_traceback = traceback.extract_stack(sys._getframe(1)) - - # Connection pool of reusable connections. - # We use a deque to store connections because it has O(1) popleft() - # and O(1) append() operations to implement a FIFO queue. - self._conns: DefaultDict[ - ConnectionKey, Deque[Tuple[ResponseHandler, float]] - ] = defaultdict(deque) - self._limit = limit - self._limit_per_host = limit_per_host - self._acquired: Set[ResponseHandler] = set() - self._acquired_per_host: DefaultDict[ConnectionKey, Set[ResponseHandler]] = ( - defaultdict(set) - ) - self._keepalive_timeout = cast(float, keepalive_timeout) - self._force_close = force_close - - # {host_key: FIFO list of waiters} - # The FIFO is implemented with an OrderedDict with None keys because - # python does not have an ordered set. - self._waiters: DefaultDict[ - ConnectionKey, OrderedDict[asyncio.Future[None], None] - ] = defaultdict(OrderedDict) - - self._loop = loop - self._factory = functools.partial(ResponseHandler, loop=loop) - - # start keep-alive connection cleanup task - self._cleanup_handle: Optional[asyncio.TimerHandle] = None - - # start cleanup closed transports task - self._cleanup_closed_handle: Optional[asyncio.TimerHandle] = None - - if enable_cleanup_closed and not NEEDS_CLEANUP_CLOSED: - warnings.warn( - "enable_cleanup_closed ignored because " - "https://github.com/python/cpython/pull/118960 is fixed " - f"in Python version {sys.version_info}", - DeprecationWarning, - stacklevel=2, - ) - enable_cleanup_closed = False - - self._cleanup_closed_disabled = not enable_cleanup_closed - self._cleanup_closed_transports: List[Optional[asyncio.Transport]] = [] - self._placeholder_future: asyncio.Future[Optional[Exception]] = ( - loop.create_future() - ) - self._placeholder_future.set_result(None) - self._cleanup_closed() - - def __del__(self, _warnings: Any = warnings) -> None: - if self._closed: - return - if not self._conns: - return - - conns = [repr(c) for c in self._conns.values()] - - self._close() - - kwargs = {"source": self} - _warnings.warn(f"Unclosed connector {self!r}", ResourceWarning, **kwargs) - context = { - "connector": self, - "connections": conns, - "message": "Unclosed connector", - } - if self._source_traceback is not None: - context["source_traceback"] = self._source_traceback - self._loop.call_exception_handler(context) - - def __enter__(self) -> "BaseConnector": - warnings.warn( - '"with Connector():" is deprecated, ' - 'use "async with Connector():" instead', - DeprecationWarning, - ) - return self - - def __exit__(self, *exc: Any) -> None: - self._close() - - async def __aenter__(self) -> "BaseConnector": - return self - - async def __aexit__( - self, - exc_type: Optional[Type[BaseException]] = None, - exc_value: Optional[BaseException] = None, - exc_traceback: Optional[TracebackType] = None, - ) -> None: - await self.close() - - @property - def force_close(self) -> bool: - """Ultimately close connection on releasing if True.""" - return self._force_close - - @property - def limit(self) -> int: - """The total number for simultaneous connections. - - If limit is 0 the connector has no limit. - The default limit size is 100. - """ - return self._limit - - @property - def limit_per_host(self) -> int: - """The limit for simultaneous connections to the same endpoint. - - Endpoints are the same if they are have equal - (host, port, is_ssl) triple. - """ - return self._limit_per_host - - def _cleanup(self) -> None: - """Cleanup unused transports.""" - if self._cleanup_handle: - self._cleanup_handle.cancel() - # _cleanup_handle should be unset, otherwise _release() will not - # recreate it ever! - self._cleanup_handle = None - - now = monotonic() - timeout = self._keepalive_timeout - - if self._conns: - connections = defaultdict(deque) - deadline = now - timeout - for key, conns in self._conns.items(): - alive: Deque[Tuple[ResponseHandler, float]] = deque() - for proto, use_time in conns: - if proto.is_connected() and use_time - deadline >= 0: - alive.append((proto, use_time)) - continue - transport = proto.transport - proto.close() - if not self._cleanup_closed_disabled and key.is_ssl: - self._cleanup_closed_transports.append(transport) - - if alive: - connections[key] = alive - - self._conns = connections - - if self._conns: - self._cleanup_handle = helpers.weakref_handle( - self, - "_cleanup", - timeout, - self._loop, - timeout_ceil_threshold=self._timeout_ceil_threshold, - ) - - def _cleanup_closed(self) -> None: - """Double confirmation for transport close. - - Some broken ssl servers may leave socket open without proper close. - """ - if self._cleanup_closed_handle: - self._cleanup_closed_handle.cancel() - - for transport in self._cleanup_closed_transports: - if transport is not None: - transport.abort() - - self._cleanup_closed_transports = [] - - if not self._cleanup_closed_disabled: - self._cleanup_closed_handle = helpers.weakref_handle( - self, - "_cleanup_closed", - self._cleanup_closed_period, - self._loop, - timeout_ceil_threshold=self._timeout_ceil_threshold, - ) - - def close(self, *, abort_ssl: bool = False) -> Awaitable[None]: - """Close all opened transports. - - :param abort_ssl: If True, SSL connections will be aborted immediately - without performing the shutdown handshake. This provides - faster cleanup at the cost of less graceful disconnection. - """ - if not (waiters := self._close(abort_ssl=abort_ssl)): - # If there are no connections to close, we can return a noop - # awaitable to avoid scheduling a task on the event loop. - return _DeprecationWaiter(noop()) - coro = _wait_for_close(waiters) - if sys.version_info >= (3, 12): - # Optimization for Python 3.12, try to close connections - # immediately to avoid having to schedule the task on the event loop. - task = asyncio.Task(coro, loop=self._loop, eager_start=True) - else: - task = self._loop.create_task(coro) - return _DeprecationWaiter(task) - - def _close(self, *, abort_ssl: bool = False) -> List[Awaitable[object]]: - waiters: List[Awaitable[object]] = [] - - if self._closed: - return waiters - - self._closed = True - - try: - if self._loop.is_closed(): - return waiters - - # cancel cleanup task - if self._cleanup_handle: - self._cleanup_handle.cancel() - - # cancel cleanup close task - if self._cleanup_closed_handle: - self._cleanup_closed_handle.cancel() - - for data in self._conns.values(): - for proto, _ in data: - if ( - abort_ssl - and proto.transport - and proto.transport.get_extra_info("sslcontext") is not None - ): - proto.abort() - else: - proto.close() - if closed := proto.closed: - waiters.append(closed) - - for proto in self._acquired: - if ( - abort_ssl - and proto.transport - and proto.transport.get_extra_info("sslcontext") is not None - ): - proto.abort() - else: - proto.close() - if closed := proto.closed: - waiters.append(closed) - - for transport in self._cleanup_closed_transports: - if transport is not None: - transport.abort() - - return waiters - - finally: - self._conns.clear() - self._acquired.clear() - for keyed_waiters in self._waiters.values(): - for keyed_waiter in keyed_waiters: - keyed_waiter.cancel() - self._waiters.clear() - self._cleanup_handle = None - self._cleanup_closed_transports.clear() - self._cleanup_closed_handle = None - - @property - def closed(self) -> bool: - """Is connector closed. - - A readonly property. - """ - return self._closed - - def _available_connections(self, key: "ConnectionKey") -> int: - """ - Return number of available connections. - - The limit, limit_per_host and the connection key are taken into account. - - If it returns less than 1 means that there are no connections - available. - """ - # check total available connections - # If there are no limits, this will always return 1 - total_remain = 1 - - if self._limit and (total_remain := self._limit - len(self._acquired)) <= 0: - return total_remain - - # check limit per host - if host_remain := self._limit_per_host: - if acquired := self._acquired_per_host.get(key): - host_remain -= len(acquired) - if total_remain > host_remain: - return host_remain - - return total_remain - - def _update_proxy_auth_header_and_build_proxy_req( - self, req: ClientRequest - ) -> ClientRequest: - """Set Proxy-Authorization header for non-SSL proxy requests and builds the proxy request for SSL proxy requests.""" - url = req.proxy - assert url is not None - headers: Dict[str, str] = {} - if req.proxy_headers is not None: - headers = req.proxy_headers # type: ignore[assignment] - headers[hdrs.HOST] = req.headers[hdrs.HOST] - proxy_req = ClientRequest( - hdrs.METH_GET, - url, - headers=headers, - auth=req.proxy_auth, - loop=self._loop, - ssl=req.ssl, - ) - auth = proxy_req.headers.pop(hdrs.AUTHORIZATION, None) - if auth is not None: - if not req.is_ssl(): - req.headers[hdrs.PROXY_AUTHORIZATION] = auth - else: - proxy_req.headers[hdrs.PROXY_AUTHORIZATION] = auth - return proxy_req - - async def connect( - self, req: ClientRequest, traces: List["Trace"], timeout: "ClientTimeout" - ) -> Connection: - """Get from pool or create new connection.""" - key = req.connection_key - if (conn := await self._get(key, traces)) is not None: - # If we do not have to wait and we can get a connection from the pool - # we can avoid the timeout ceil logic and directly return the connection - if req.proxy: - self._update_proxy_auth_header_and_build_proxy_req(req) - return conn - - async with ceil_timeout(timeout.connect, timeout.ceil_threshold): - if self._available_connections(key) <= 0: - await self._wait_for_available_connection(key, traces) - if (conn := await self._get(key, traces)) is not None: - if req.proxy: - self._update_proxy_auth_header_and_build_proxy_req(req) - return conn - - placeholder = cast( - ResponseHandler, _TransportPlaceholder(self._placeholder_future) - ) - self._acquired.add(placeholder) - if self._limit_per_host: - self._acquired_per_host[key].add(placeholder) - - try: - # Traces are done inside the try block to ensure that the - # that the placeholder is still cleaned up if an exception - # is raised. - if traces: - for trace in traces: - await trace.send_connection_create_start() - proto = await self._create_connection(req, traces, timeout) - if traces: - for trace in traces: - await trace.send_connection_create_end() - except BaseException: - self._release_acquired(key, placeholder) - raise - else: - if self._closed: - proto.close() - raise ClientConnectionError("Connector is closed.") - - # The connection was successfully created, drop the placeholder - # and add the real connection to the acquired set. There should - # be no awaits after the proto is added to the acquired set - # to ensure that the connection is not left in the acquired set - # on cancellation. - self._acquired.remove(placeholder) - self._acquired.add(proto) - if self._limit_per_host: - acquired_per_host = self._acquired_per_host[key] - acquired_per_host.remove(placeholder) - acquired_per_host.add(proto) - return Connection(self, key, proto, self._loop) - - async def _wait_for_available_connection( - self, key: "ConnectionKey", traces: List["Trace"] - ) -> None: - """Wait for an available connection slot.""" - # We loop here because there is a race between - # the connection limit check and the connection - # being acquired. If the connection is acquired - # between the check and the await statement, we - # need to loop again to check if the connection - # slot is still available. - attempts = 0 - while True: - fut: asyncio.Future[None] = self._loop.create_future() - keyed_waiters = self._waiters[key] - keyed_waiters[fut] = None - if attempts: - # If we have waited before, we need to move the waiter - # to the front of the queue as otherwise we might get - # starved and hit the timeout. - keyed_waiters.move_to_end(fut, last=False) - - try: - # Traces happen in the try block to ensure that the - # the waiter is still cleaned up if an exception is raised. - if traces: - for trace in traces: - await trace.send_connection_queued_start() - await fut - if traces: - for trace in traces: - await trace.send_connection_queued_end() - finally: - # pop the waiter from the queue if its still - # there and not already removed by _release_waiter - keyed_waiters.pop(fut, None) - if not self._waiters.get(key, True): - del self._waiters[key] - - if self._available_connections(key) > 0: - break - attempts += 1 - - async def _get( - self, key: "ConnectionKey", traces: List["Trace"] - ) -> Optional[Connection]: - """Get next reusable connection for the key or None. - - The connection will be marked as acquired. - """ - if (conns := self._conns.get(key)) is None: - return None - - t1 = monotonic() - while conns: - proto, t0 = conns.popleft() - # We will we reuse the connection if its connected and - # the keepalive timeout has not been exceeded - if proto.is_connected() and t1 - t0 <= self._keepalive_timeout: - if not conns: - # The very last connection was reclaimed: drop the key - del self._conns[key] - self._acquired.add(proto) - if self._limit_per_host: - self._acquired_per_host[key].add(proto) - if traces: - for trace in traces: - try: - await trace.send_connection_reuseconn() - except BaseException: - self._release_acquired(key, proto) - raise - return Connection(self, key, proto, self._loop) - - # Connection cannot be reused, close it - transport = proto.transport - proto.close() - # only for SSL transports - if not self._cleanup_closed_disabled and key.is_ssl: - self._cleanup_closed_transports.append(transport) - - # No more connections: drop the key - del self._conns[key] - return None - - def _release_waiter(self) -> None: - """ - Iterates over all waiters until one to be released is found. - - The one to be released is not finished and - belongs to a host that has available connections. - """ - if not self._waiters: - return - - # Having the dict keys ordered this avoids to iterate - # at the same order at each call. - queues = list(self._waiters) - random.shuffle(queues) - - for key in queues: - if self._available_connections(key) < 1: - continue - - waiters = self._waiters[key] - while waiters: - waiter, _ = waiters.popitem(last=False) - if not waiter.done(): - waiter.set_result(None) - return - - def _release_acquired(self, key: "ConnectionKey", proto: ResponseHandler) -> None: - """Release acquired connection.""" - if self._closed: - # acquired connection is already released on connector closing - return - - self._acquired.discard(proto) - if self._limit_per_host and (conns := self._acquired_per_host.get(key)): - conns.discard(proto) - if not conns: - del self._acquired_per_host[key] - self._release_waiter() - - def _release( - self, - key: "ConnectionKey", - protocol: ResponseHandler, - *, - should_close: bool = False, - ) -> None: - if self._closed: - # acquired connection is already released on connector closing - return - - self._release_acquired(key, protocol) - - if self._force_close or should_close or protocol.should_close: - transport = protocol.transport - protocol.close() - - if key.is_ssl and not self._cleanup_closed_disabled: - self._cleanup_closed_transports.append(transport) - return - - self._conns[key].append((protocol, monotonic())) - - if self._cleanup_handle is None: - self._cleanup_handle = helpers.weakref_handle( - self, - "_cleanup", - self._keepalive_timeout, - self._loop, - timeout_ceil_threshold=self._timeout_ceil_threshold, - ) - - async def _create_connection( - self, req: ClientRequest, traces: List["Trace"], timeout: "ClientTimeout" - ) -> ResponseHandler: - raise NotImplementedError() - - -class _DNSCacheTable: - def __init__(self, ttl: Optional[float] = None, max_size: int = 1000) -> None: - self._addrs_rr: OrderedDict[ - Tuple[str, int], Tuple[Iterator[ResolveResult], int] - ] = OrderedDict() - self._timestamps: Dict[Tuple[str, int], float] = {} - self._ttl = ttl - self._max_size = max_size - - def __contains__(self, host: object) -> bool: - return host in self._addrs_rr - - def add(self, key: Tuple[str, int], addrs: List[ResolveResult]) -> None: - if key in self._addrs_rr: - self._addrs_rr.move_to_end(key) - - self._addrs_rr[key] = (cycle(addrs), len(addrs)) - - if self._ttl is not None: - self._timestamps[key] = monotonic() - - if len(self._addrs_rr) > self._max_size: - oldest_key, _ = self._addrs_rr.popitem(last=False) - self._timestamps.pop(oldest_key, None) - - def remove(self, key: Tuple[str, int]) -> None: - self._addrs_rr.pop(key, None) - self._timestamps.pop(key, None) - - def clear(self) -> None: - self._addrs_rr.clear() - self._timestamps.clear() - - def next_addrs(self, key: Tuple[str, int]) -> List[ResolveResult]: - loop, length = self._addrs_rr[key] - addrs = list(islice(loop, length)) - # Consume one more element to shift internal state of `cycle` - next(loop) - self._addrs_rr.move_to_end(key) - return addrs - - def expired(self, key: Tuple[str, int]) -> bool: - if self._ttl is None: - return False - - return self._timestamps[key] + self._ttl < monotonic() - - -def _make_ssl_context(verified: bool) -> SSLContext: - """Create SSL context. - - This method is not async-friendly and should be called from a thread - because it will load certificates from disk and do other blocking I/O. - """ - if ssl is None: - # No ssl support - return None - if verified: - sslcontext = ssl.create_default_context() - else: - sslcontext = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT) - sslcontext.options |= ssl.OP_NO_SSLv2 - sslcontext.options |= ssl.OP_NO_SSLv3 - sslcontext.check_hostname = False - sslcontext.verify_mode = ssl.CERT_NONE - sslcontext.options |= ssl.OP_NO_COMPRESSION - sslcontext.set_default_verify_paths() - sslcontext.set_alpn_protocols(("http/1.1",)) - return sslcontext - - -# The default SSLContext objects are created at import time -# since they do blocking I/O to load certificates from disk, -# and imports should always be done before the event loop starts -# or in a thread. -_SSL_CONTEXT_VERIFIED = _make_ssl_context(True) -_SSL_CONTEXT_UNVERIFIED = _make_ssl_context(False) - - -class TCPConnector(BaseConnector): - """TCP connector. - - verify_ssl - Set to True to check ssl certifications. - fingerprint - Pass the binary sha256 - digest of the expected certificate in DER format to verify - that the certificate the server presents matches. See also - https://en.wikipedia.org/wiki/HTTP_Public_Key_Pinning - resolver - Enable DNS lookups and use this - resolver - use_dns_cache - Use memory cache for DNS lookups. - ttl_dns_cache - Max seconds having cached a DNS entry, None forever. - family - socket address family - local_addr - local tuple of (host, port) to bind socket to - - keepalive_timeout - (optional) Keep-alive timeout. - force_close - Set to True to force close and do reconnect - after each request (and between redirects). - limit - The total number of simultaneous connections. - limit_per_host - Number of simultaneous connections to one host. - enable_cleanup_closed - Enables clean-up closed ssl transports. - Disabled by default. - happy_eyeballs_delay - This is the “Connection Attempt Delay” - as defined in RFC 8305. To disable - the happy eyeballs algorithm, set to None. - interleave - “First Address Family Count” as defined in RFC 8305 - loop - Optional event loop. - socket_factory - A SocketFactoryType function that, if supplied, - will be used to create sockets given an - AddrInfoType. - ssl_shutdown_timeout - DEPRECATED. Will be removed in aiohttp 4.0. - Grace period for SSL shutdown handshake on TLS - connections. Default is 0 seconds (immediate abort). - This parameter allowed for a clean SSL shutdown by - notifying the remote peer of connection closure, - while avoiding excessive delays during connector cleanup. - Note: Only takes effect on Python 3.11+. - """ - - allowed_protocol_schema_set = HIGH_LEVEL_SCHEMA_SET | frozenset({"tcp"}) - - def __init__( - self, - *, - verify_ssl: bool = True, - fingerprint: Optional[bytes] = None, - use_dns_cache: bool = True, - ttl_dns_cache: Optional[int] = 10, - dns_cache_max_size: int = 1000, - family: socket.AddressFamily = socket.AddressFamily.AF_UNSPEC, - ssl_context: Optional[SSLContext] = None, - ssl: Union[bool, Fingerprint, SSLContext] = True, - local_addr: Optional[Tuple[str, int]] = None, - resolver: Optional[AbstractResolver] = None, - keepalive_timeout: Union[None, float, object] = sentinel, - force_close: bool = False, - limit: int = 100, - limit_per_host: int = 0, - enable_cleanup_closed: bool = False, - loop: Optional[asyncio.AbstractEventLoop] = None, - timeout_ceil_threshold: float = 5, - happy_eyeballs_delay: Optional[float] = 0.25, - interleave: Optional[int] = None, - socket_factory: Optional[SocketFactoryType] = None, - ssl_shutdown_timeout: Union[_SENTINEL, None, float] = sentinel, - ): - super().__init__( - keepalive_timeout=keepalive_timeout, - force_close=force_close, - limit=limit, - limit_per_host=limit_per_host, - enable_cleanup_closed=enable_cleanup_closed, - loop=loop, - timeout_ceil_threshold=timeout_ceil_threshold, - ) - - self._ssl = _merge_ssl_params(ssl, verify_ssl, ssl_context, fingerprint) - - self._resolver: AbstractResolver - if resolver is None: - self._resolver = DefaultResolver(loop=self._loop) - self._resolver_owner = True - else: - self._resolver = resolver - self._resolver_owner = False - - self._use_dns_cache = use_dns_cache - self._cached_hosts = _DNSCacheTable( - ttl=ttl_dns_cache, max_size=dns_cache_max_size - ) - self._throttle_dns_futures: Dict[ - Tuple[str, int], Set["asyncio.Future[None]"] - ] = {} - self._family = family - self._local_addr_infos = aiohappyeyeballs.addr_to_addr_infos(local_addr) - self._happy_eyeballs_delay = happy_eyeballs_delay - self._interleave = interleave - self._resolve_host_tasks: Set["asyncio.Task[List[ResolveResult]]"] = set() - self._socket_factory = socket_factory - self._ssl_shutdown_timeout: Optional[float] - # Handle ssl_shutdown_timeout with warning for Python < 3.11 - if ssl_shutdown_timeout is sentinel: - self._ssl_shutdown_timeout = 0 - else: - # Deprecation warning for ssl_shutdown_timeout parameter - warnings.warn( - "The ssl_shutdown_timeout parameter is deprecated and will be removed in aiohttp 4.0", - DeprecationWarning, - stacklevel=2, - ) - if ( - sys.version_info < (3, 11) - and ssl_shutdown_timeout is not None - and ssl_shutdown_timeout != 0 - ): - warnings.warn( - f"ssl_shutdown_timeout={ssl_shutdown_timeout} is ignored on Python < 3.11; " - "only ssl_shutdown_timeout=0 is supported. The timeout will be ignored.", - RuntimeWarning, - stacklevel=2, - ) - self._ssl_shutdown_timeout = ssl_shutdown_timeout - - def _close(self, *, abort_ssl: bool = False) -> List[Awaitable[object]]: - """Close all ongoing DNS calls.""" - for fut in chain.from_iterable(self._throttle_dns_futures.values()): - fut.cancel() - - waiters = super()._close(abort_ssl=abort_ssl) - - for t in self._resolve_host_tasks: - t.cancel() - waiters.append(t) - - return waiters - - async def close(self, *, abort_ssl: bool = False) -> None: - """ - Close all opened transports. - - :param abort_ssl: If True, SSL connections will be aborted immediately - without performing the shutdown handshake. If False (default), - the behavior is determined by ssl_shutdown_timeout: - - If ssl_shutdown_timeout=0: connections are aborted - - If ssl_shutdown_timeout>0: graceful shutdown is performed - """ - if self._resolver_owner: - await self._resolver.close() - # Use abort_ssl param if explicitly set, otherwise use ssl_shutdown_timeout default - await super().close(abort_ssl=abort_ssl or self._ssl_shutdown_timeout == 0) - - @property - def family(self) -> int: - """Socket family like AF_INET.""" - return self._family - - @property - def use_dns_cache(self) -> bool: - """True if local DNS caching is enabled.""" - return self._use_dns_cache - - def clear_dns_cache( - self, host: Optional[str] = None, port: Optional[int] = None - ) -> None: - """Remove specified host/port or clear all dns local cache.""" - if host is not None and port is not None: - self._cached_hosts.remove((host, port)) - elif host is not None or port is not None: - raise ValueError("either both host and port or none of them are allowed") - else: - self._cached_hosts.clear() - - async def _resolve_host( - self, host: str, port: int, traces: Optional[Sequence["Trace"]] = None - ) -> List[ResolveResult]: - """Resolve host and return list of addresses.""" - if is_ip_address(host): - return [ - { - "hostname": host, - "host": host, - "port": port, - "family": self._family, - "proto": 0, - "flags": 0, - } - ] - - if not self._use_dns_cache: - - if traces: - for trace in traces: - await trace.send_dns_resolvehost_start(host) - - res = await self._resolver.resolve(host, port, family=self._family) - - if traces: - for trace in traces: - await trace.send_dns_resolvehost_end(host) - - return res - - key = (host, port) - if key in self._cached_hosts and not self._cached_hosts.expired(key): - # get result early, before any await (#4014) - result = self._cached_hosts.next_addrs(key) - - if traces: - for trace in traces: - await trace.send_dns_cache_hit(host) - return result - - futures: Set["asyncio.Future[None]"] - # - # If multiple connectors are resolving the same host, we wait - # for the first one to resolve and then use the result for all of them. - # We use a throttle to ensure that we only resolve the host once - # and then use the result for all the waiters. - # - if key in self._throttle_dns_futures: - # get futures early, before any await (#4014) - futures = self._throttle_dns_futures[key] - future: asyncio.Future[None] = self._loop.create_future() - futures.add(future) - if traces: - for trace in traces: - await trace.send_dns_cache_hit(host) - try: - await future - finally: - futures.discard(future) - return self._cached_hosts.next_addrs(key) - - # update dict early, before any await (#4014) - self._throttle_dns_futures[key] = futures = set() - # In this case we need to create a task to ensure that we can shield - # the task from cancellation as cancelling this lookup should not cancel - # the underlying lookup or else the cancel event will get broadcast to - # all the waiters across all connections. - # - coro = self._resolve_host_with_throttle(key, host, port, futures, traces) - loop = asyncio.get_running_loop() - if sys.version_info >= (3, 12): - # Optimization for Python 3.12, try to send immediately - resolved_host_task = asyncio.Task(coro, loop=loop, eager_start=True) - else: - resolved_host_task = loop.create_task(coro) - - if not resolved_host_task.done(): - self._resolve_host_tasks.add(resolved_host_task) - resolved_host_task.add_done_callback(self._resolve_host_tasks.discard) - - try: - return await asyncio.shield(resolved_host_task) - except asyncio.CancelledError: - - def drop_exception(fut: "asyncio.Future[List[ResolveResult]]") -> None: - with suppress(Exception, asyncio.CancelledError): - fut.result() - - resolved_host_task.add_done_callback(drop_exception) - raise - - async def _resolve_host_with_throttle( - self, - key: Tuple[str, int], - host: str, - port: int, - futures: Set["asyncio.Future[None]"], - traces: Optional[Sequence["Trace"]], - ) -> List[ResolveResult]: - """Resolve host and set result for all waiters. - - This method must be run in a task and shielded from cancellation - to avoid cancelling the underlying lookup. - """ - try: - if traces: - for trace in traces: - await trace.send_dns_cache_miss(host) - - for trace in traces: - await trace.send_dns_resolvehost_start(host) - - addrs = await self._resolver.resolve(host, port, family=self._family) - if traces: - for trace in traces: - await trace.send_dns_resolvehost_end(host) - - self._cached_hosts.add(key, addrs) - for fut in futures: - set_result(fut, None) - except BaseException as e: - # any DNS exception is set for the waiters to raise the same exception. - # This coro is always run in task that is shielded from cancellation so - # we should never be propagating cancellation here. - for fut in futures: - set_exception(fut, e) - raise - finally: - self._throttle_dns_futures.pop(key) - - return self._cached_hosts.next_addrs(key) - - async def _create_connection( - self, req: ClientRequest, traces: List["Trace"], timeout: "ClientTimeout" - ) -> ResponseHandler: - """Create connection. - - Has same keyword arguments as BaseEventLoop.create_connection. - """ - if req.proxy: - _, proto = await self._create_proxy_connection(req, traces, timeout) - else: - _, proto = await self._create_direct_connection(req, traces, timeout) - - return proto - - def _get_ssl_context(self, req: ClientRequest) -> Optional[SSLContext]: - """Logic to get the correct SSL context - - 0. if req.ssl is false, return None - - 1. if ssl_context is specified in req, use it - 2. if _ssl_context is specified in self, use it - 3. otherwise: - 1. if verify_ssl is not specified in req, use self.ssl_context - (will generate a default context according to self.verify_ssl) - 2. if verify_ssl is True in req, generate a default SSL context - 3. if verify_ssl is False in req, generate a SSL context that - won't verify - """ - if not req.is_ssl(): - return None - - if ssl is None: # pragma: no cover - raise RuntimeError("SSL is not supported.") - sslcontext = req.ssl - if isinstance(sslcontext, ssl.SSLContext): - return sslcontext - if sslcontext is not True: - # not verified or fingerprinted - return _SSL_CONTEXT_UNVERIFIED - sslcontext = self._ssl - if isinstance(sslcontext, ssl.SSLContext): - return sslcontext - if sslcontext is not True: - # not verified or fingerprinted - return _SSL_CONTEXT_UNVERIFIED - return _SSL_CONTEXT_VERIFIED - - def _get_fingerprint(self, req: ClientRequest) -> Optional["Fingerprint"]: - ret = req.ssl - if isinstance(ret, Fingerprint): - return ret - ret = self._ssl - if isinstance(ret, Fingerprint): - return ret - return None - - async def _wrap_create_connection( - self, - *args: Any, - addr_infos: List[AddrInfoType], - req: ClientRequest, - timeout: "ClientTimeout", - client_error: Type[Exception] = ClientConnectorError, - **kwargs: Any, - ) -> Tuple[asyncio.Transport, ResponseHandler]: - try: - async with ceil_timeout( - timeout.sock_connect, ceil_threshold=timeout.ceil_threshold - ): - sock = await aiohappyeyeballs.start_connection( - addr_infos=addr_infos, - local_addr_infos=self._local_addr_infos, - happy_eyeballs_delay=self._happy_eyeballs_delay, - interleave=self._interleave, - loop=self._loop, - socket_factory=self._socket_factory, - ) - # Add ssl_shutdown_timeout for Python 3.11+ when SSL is used - if ( - kwargs.get("ssl") - and self._ssl_shutdown_timeout - and sys.version_info >= (3, 11) - ): - kwargs["ssl_shutdown_timeout"] = self._ssl_shutdown_timeout - return await self._loop.create_connection(*args, **kwargs, sock=sock) - except cert_errors as exc: - raise ClientConnectorCertificateError(req.connection_key, exc) from exc - except ssl_errors as exc: - raise ClientConnectorSSLError(req.connection_key, exc) from exc - except OSError as exc: - if exc.errno is None and isinstance(exc, asyncio.TimeoutError): - raise - raise client_error(req.connection_key, exc) from exc - - async def _wrap_existing_connection( - self, - *args: Any, - req: ClientRequest, - timeout: "ClientTimeout", - client_error: Type[Exception] = ClientConnectorError, - **kwargs: Any, - ) -> Tuple[asyncio.Transport, ResponseHandler]: - try: - async with ceil_timeout( - timeout.sock_connect, ceil_threshold=timeout.ceil_threshold - ): - return await self._loop.create_connection(*args, **kwargs) - except cert_errors as exc: - raise ClientConnectorCertificateError(req.connection_key, exc) from exc - except ssl_errors as exc: - raise ClientConnectorSSLError(req.connection_key, exc) from exc - except OSError as exc: - if exc.errno is None and isinstance(exc, asyncio.TimeoutError): - raise - raise client_error(req.connection_key, exc) from exc - - def _fail_on_no_start_tls(self, req: "ClientRequest") -> None: - """Raise a :py:exc:`RuntimeError` on missing ``start_tls()``. - - It is necessary for TLS-in-TLS so that it is possible to - send HTTPS queries through HTTPS proxies. - - This doesn't affect regular HTTP requests, though. - """ - if not req.is_ssl(): - return - - proxy_url = req.proxy - assert proxy_url is not None - if proxy_url.scheme != "https": - return - - self._check_loop_for_start_tls() - - def _check_loop_for_start_tls(self) -> None: - try: - self._loop.start_tls - except AttributeError as attr_exc: - raise RuntimeError( - "An HTTPS request is being sent through an HTTPS proxy. " - "This needs support for TLS in TLS but it is not implemented " - "in your runtime for the stdlib asyncio.\n\n" - "Please upgrade to Python 3.11 or higher. For more details, " - "please see:\n" - "* https://bugs.python.org/issue37179\n" - "* https://github.com/python/cpython/pull/28073\n" - "* https://docs.aiohttp.org/en/stable/" - "client_advanced.html#proxy-support\n" - "* https://github.com/aio-libs/aiohttp/discussions/6044\n", - ) from attr_exc - - def _loop_supports_start_tls(self) -> bool: - try: - self._check_loop_for_start_tls() - except RuntimeError: - return False - else: - return True - - def _warn_about_tls_in_tls( - self, - underlying_transport: asyncio.Transport, - req: ClientRequest, - ) -> None: - """Issue a warning if the requested URL has HTTPS scheme.""" - if req.request_info.url.scheme != "https": - return - - # Check if uvloop is being used, which supports TLS in TLS, - # otherwise assume that asyncio's native transport is being used. - if type(underlying_transport).__module__.startswith("uvloop"): - return - - # Support in asyncio was added in Python 3.11 (bpo-44011) - asyncio_supports_tls_in_tls = sys.version_info >= (3, 11) or getattr( - underlying_transport, - "_start_tls_compatible", - False, - ) - - if asyncio_supports_tls_in_tls: - return - - warnings.warn( - "An HTTPS request is being sent through an HTTPS proxy. " - "This support for TLS in TLS is known to be disabled " - "in the stdlib asyncio (Python <3.11). This is why you'll probably see " - "an error in the log below.\n\n" - "It is possible to enable it via monkeypatching. " - "For more details, see:\n" - "* https://bugs.python.org/issue37179\n" - "* https://github.com/python/cpython/pull/28073\n\n" - "You can temporarily patch this as follows:\n" - "* https://docs.aiohttp.org/en/stable/client_advanced.html#proxy-support\n" - "* https://github.com/aio-libs/aiohttp/discussions/6044\n", - RuntimeWarning, - source=self, - # Why `4`? At least 3 of the calls in the stack originate - # from the methods in this class. - stacklevel=3, - ) - - async def _start_tls_connection( - self, - underlying_transport: asyncio.Transport, - req: ClientRequest, - timeout: "ClientTimeout", - client_error: Type[Exception] = ClientConnectorError, - ) -> Tuple[asyncio.BaseTransport, ResponseHandler]: - """Wrap the raw TCP transport with TLS.""" - tls_proto = self._factory() # Create a brand new proto for TLS - sslcontext = self._get_ssl_context(req) - if TYPE_CHECKING: - # _start_tls_connection is unreachable in the current code path - # if sslcontext is None. - assert sslcontext is not None - - try: - async with ceil_timeout( - timeout.sock_connect, ceil_threshold=timeout.ceil_threshold - ): - try: - # ssl_shutdown_timeout is only available in Python 3.11+ - if sys.version_info >= (3, 11) and self._ssl_shutdown_timeout: - tls_transport = await self._loop.start_tls( - underlying_transport, - tls_proto, - sslcontext, - server_hostname=req.server_hostname or req.host, - ssl_handshake_timeout=timeout.total or None, - ssl_shutdown_timeout=self._ssl_shutdown_timeout, - ) - else: - tls_transport = await self._loop.start_tls( - underlying_transport, - tls_proto, - sslcontext, - server_hostname=req.server_hostname or req.host, - ssl_handshake_timeout=timeout.total or None, - ) - except BaseException: - # We need to close the underlying transport since - # `start_tls()` probably failed before it had a - # chance to do this: - if self._ssl_shutdown_timeout == 0: - underlying_transport.abort() - else: - underlying_transport.close() - raise - if isinstance(tls_transport, asyncio.Transport): - fingerprint = self._get_fingerprint(req) - if fingerprint: - try: - fingerprint.check(tls_transport) - except ServerFingerprintMismatch: - tls_transport.close() - if not self._cleanup_closed_disabled: - self._cleanup_closed_transports.append(tls_transport) - raise - except cert_errors as exc: - raise ClientConnectorCertificateError(req.connection_key, exc) from exc - except ssl_errors as exc: - raise ClientConnectorSSLError(req.connection_key, exc) from exc - except OSError as exc: - if exc.errno is None and isinstance(exc, asyncio.TimeoutError): - raise - raise client_error(req.connection_key, exc) from exc - except TypeError as type_err: - # Example cause looks like this: - # TypeError: transport is not supported by start_tls() - - raise ClientConnectionError( - "Cannot initialize a TLS-in-TLS connection to host " - f"{req.host!s}:{req.port:d} through an underlying connection " - f"to an HTTPS proxy {req.proxy!s} ssl:{req.ssl or 'default'} " - f"[{type_err!s}]" - ) from type_err - else: - if tls_transport is None: - msg = "Failed to start TLS (possibly caused by closing transport)" - raise client_error(req.connection_key, OSError(msg)) - tls_proto.connection_made( - tls_transport - ) # Kick the state machine of the new TLS protocol - - return tls_transport, tls_proto - - def _convert_hosts_to_addr_infos( - self, hosts: List[ResolveResult] - ) -> List[AddrInfoType]: - """Converts the list of hosts to a list of addr_infos. - - The list of hosts is the result of a DNS lookup. The list of - addr_infos is the result of a call to `socket.getaddrinfo()`. - """ - addr_infos: List[AddrInfoType] = [] - for hinfo in hosts: - host = hinfo["host"] - is_ipv6 = ":" in host - family = socket.AF_INET6 if is_ipv6 else socket.AF_INET - if self._family and self._family != family: - continue - addr = (host, hinfo["port"], 0, 0) if is_ipv6 else (host, hinfo["port"]) - addr_infos.append( - (family, socket.SOCK_STREAM, socket.IPPROTO_TCP, "", addr) - ) - return addr_infos - - async def _create_direct_connection( - self, - req: ClientRequest, - traces: List["Trace"], - timeout: "ClientTimeout", - *, - client_error: Type[Exception] = ClientConnectorError, - ) -> Tuple[asyncio.Transport, ResponseHandler]: - sslcontext = self._get_ssl_context(req) - fingerprint = self._get_fingerprint(req) - - host = req.url.raw_host - assert host is not None - # Replace multiple trailing dots with a single one. - # A trailing dot is only present for fully-qualified domain names. - # See https://github.com/aio-libs/aiohttp/pull/7364. - if host.endswith(".."): - host = host.rstrip(".") + "." - port = req.port - assert port is not None - try: - # Cancelling this lookup should not cancel the underlying lookup - # or else the cancel event will get broadcast to all the waiters - # across all connections. - hosts = await self._resolve_host(host, port, traces=traces) - except OSError as exc: - if exc.errno is None and isinstance(exc, asyncio.TimeoutError): - raise - # in case of proxy it is not ClientProxyConnectionError - # it is problem of resolving proxy ip itself - raise ClientConnectorDNSError(req.connection_key, exc) from exc - - last_exc: Optional[Exception] = None - addr_infos = self._convert_hosts_to_addr_infos(hosts) - while addr_infos: - # Strip trailing dots, certificates contain FQDN without dots. - # See https://github.com/aio-libs/aiohttp/issues/3636 - server_hostname = ( - (req.server_hostname or host).rstrip(".") if sslcontext else None - ) - - try: - transp, proto = await self._wrap_create_connection( - self._factory, - timeout=timeout, - ssl=sslcontext, - addr_infos=addr_infos, - server_hostname=server_hostname, - req=req, - client_error=client_error, - ) - except (ClientConnectorError, asyncio.TimeoutError) as exc: - last_exc = exc - aiohappyeyeballs.pop_addr_infos_interleave(addr_infos, self._interleave) - continue - - if req.is_ssl() and fingerprint: - try: - fingerprint.check(transp) - except ServerFingerprintMismatch as exc: - transp.close() - if not self._cleanup_closed_disabled: - self._cleanup_closed_transports.append(transp) - last_exc = exc - # Remove the bad peer from the list of addr_infos - sock: socket.socket = transp.get_extra_info("socket") - bad_peer = sock.getpeername() - aiohappyeyeballs.remove_addr_infos(addr_infos, bad_peer) - continue - - return transp, proto - else: - assert last_exc is not None - raise last_exc - - async def _create_proxy_connection( - self, req: ClientRequest, traces: List["Trace"], timeout: "ClientTimeout" - ) -> Tuple[asyncio.BaseTransport, ResponseHandler]: - self._fail_on_no_start_tls(req) - runtime_has_start_tls = self._loop_supports_start_tls() - proxy_req = self._update_proxy_auth_header_and_build_proxy_req(req) - - # create connection to proxy server - transport, proto = await self._create_direct_connection( - proxy_req, [], timeout, client_error=ClientProxyConnectionError - ) - - if req.is_ssl(): - if runtime_has_start_tls: - self._warn_about_tls_in_tls(transport, req) - - # For HTTPS requests over HTTP proxy - # we must notify proxy to tunnel connection - # so we send CONNECT command: - # CONNECT www.python.org:443 HTTP/1.1 - # Host: www.python.org - # - # next we must do TLS handshake and so on - # to do this we must wrap raw socket into secure one - # asyncio handles this perfectly - proxy_req.method = hdrs.METH_CONNECT - proxy_req.url = req.url - key = req.connection_key._replace( - proxy=None, proxy_auth=None, proxy_headers_hash=None - ) - conn = _ConnectTunnelConnection(self, key, proto, self._loop) - proxy_resp = await proxy_req.send(conn) - try: - protocol = conn._protocol - assert protocol is not None - - # read_until_eof=True will ensure the connection isn't closed - # once the response is received and processed allowing - # START_TLS to work on the connection below. - protocol.set_response_params( - read_until_eof=runtime_has_start_tls, - timeout_ceil_threshold=self._timeout_ceil_threshold, - ) - resp = await proxy_resp.start(conn) - except BaseException: - proxy_resp.close() - conn.close() - raise - else: - conn._protocol = None - try: - if resp.status != 200: - message = resp.reason - if message is None: - message = HTTPStatus(resp.status).phrase - raise ClientHttpProxyError( - proxy_resp.request_info, - resp.history, - status=resp.status, - message=message, - headers=resp.headers, - ) - if not runtime_has_start_tls: - rawsock = transport.get_extra_info("socket", default=None) - if rawsock is None: - raise RuntimeError( - "Transport does not expose socket instance" - ) - # Duplicate the socket, so now we can close proxy transport - rawsock = rawsock.dup() - except BaseException: - # It shouldn't be closed in `finally` because it's fed to - # `loop.start_tls()` and the docs say not to touch it after - # passing there. - transport.close() - raise - finally: - if not runtime_has_start_tls: - transport.close() - - if not runtime_has_start_tls: - # HTTP proxy with support for upgrade to HTTPS - sslcontext = self._get_ssl_context(req) - return await self._wrap_existing_connection( - self._factory, - timeout=timeout, - ssl=sslcontext, - sock=rawsock, - server_hostname=req.host, - req=req, - ) - - return await self._start_tls_connection( - # Access the old transport for the last time before it's - # closed and forgotten forever: - transport, - req=req, - timeout=timeout, - ) - finally: - proxy_resp.close() - - return transport, proto - - -class UnixConnector(BaseConnector): - """Unix socket connector. - - path - Unix socket path. - keepalive_timeout - (optional) Keep-alive timeout. - force_close - Set to True to force close and do reconnect - after each request (and between redirects). - limit - The total number of simultaneous connections. - limit_per_host - Number of simultaneous connections to one host. - loop - Optional event loop. - """ - - allowed_protocol_schema_set = HIGH_LEVEL_SCHEMA_SET | frozenset({"unix"}) - - def __init__( - self, - path: str, - force_close: bool = False, - keepalive_timeout: Union[object, float, None] = sentinel, - limit: int = 100, - limit_per_host: int = 0, - loop: Optional[asyncio.AbstractEventLoop] = None, - ) -> None: - super().__init__( - force_close=force_close, - keepalive_timeout=keepalive_timeout, - limit=limit, - limit_per_host=limit_per_host, - loop=loop, - ) - self._path = path - - @property - def path(self) -> str: - """Path to unix socket.""" - return self._path - - async def _create_connection( - self, req: ClientRequest, traces: List["Trace"], timeout: "ClientTimeout" - ) -> ResponseHandler: - try: - async with ceil_timeout( - timeout.sock_connect, ceil_threshold=timeout.ceil_threshold - ): - _, proto = await self._loop.create_unix_connection( - self._factory, self._path - ) - except OSError as exc: - if exc.errno is None and isinstance(exc, asyncio.TimeoutError): - raise - raise UnixClientConnectorError(self.path, req.connection_key, exc) from exc - - return proto - - -class NamedPipeConnector(BaseConnector): - """Named pipe connector. - - Only supported by the proactor event loop. - See also: https://docs.python.org/3/library/asyncio-eventloop.html - - path - Windows named pipe path. - keepalive_timeout - (optional) Keep-alive timeout. - force_close - Set to True to force close and do reconnect - after each request (and between redirects). - limit - The total number of simultaneous connections. - limit_per_host - Number of simultaneous connections to one host. - loop - Optional event loop. - """ - - allowed_protocol_schema_set = HIGH_LEVEL_SCHEMA_SET | frozenset({"npipe"}) - - def __init__( - self, - path: str, - force_close: bool = False, - keepalive_timeout: Union[object, float, None] = sentinel, - limit: int = 100, - limit_per_host: int = 0, - loop: Optional[asyncio.AbstractEventLoop] = None, - ) -> None: - super().__init__( - force_close=force_close, - keepalive_timeout=keepalive_timeout, - limit=limit, - limit_per_host=limit_per_host, - loop=loop, - ) - if not isinstance( - self._loop, - asyncio.ProactorEventLoop, # type: ignore[attr-defined] - ): - raise RuntimeError( - "Named Pipes only available in proactor loop under windows" - ) - self._path = path - - @property - def path(self) -> str: - """Path to the named pipe.""" - return self._path - - async def _create_connection( - self, req: ClientRequest, traces: List["Trace"], timeout: "ClientTimeout" - ) -> ResponseHandler: - try: - async with ceil_timeout( - timeout.sock_connect, ceil_threshold=timeout.ceil_threshold - ): - _, proto = await self._loop.create_pipe_connection( # type: ignore[attr-defined] - self._factory, self._path - ) - # the drain is required so that the connection_made is called - # and transport is set otherwise it is not set before the - # `assert conn.transport is not None` - # in client.py's _request method - await asyncio.sleep(0) - # other option is to manually set transport like - # `proto.transport = trans` - except OSError as exc: - if exc.errno is None and isinstance(exc, asyncio.TimeoutError): - raise - raise ClientConnectorError(req.connection_key, exc) from exc - - return cast(ResponseHandler, proto) diff --git a/venv/lib/python3.9/site-packages/aiohttp/cookiejar.py b/venv/lib/python3.9/site-packages/aiohttp/cookiejar.py deleted file mode 100644 index 193648d..0000000 --- a/venv/lib/python3.9/site-packages/aiohttp/cookiejar.py +++ /dev/null @@ -1,522 +0,0 @@ -import asyncio -import calendar -import contextlib -import datetime -import heapq -import itertools -import os # noqa -import pathlib -import pickle -import re -import time -import warnings -from collections import defaultdict -from collections.abc import Mapping -from http.cookies import BaseCookie, Morsel, SimpleCookie -from typing import ( - DefaultDict, - Dict, - Iterable, - Iterator, - List, - Optional, - Set, - Tuple, - Union, -) - -from yarl import URL - -from ._cookie_helpers import preserve_morsel_with_coded_value -from .abc import AbstractCookieJar, ClearCookiePredicate -from .helpers import is_ip_address -from .typedefs import LooseCookies, PathLike, StrOrURL - -__all__ = ("CookieJar", "DummyCookieJar") - - -CookieItem = Union[str, "Morsel[str]"] - -# We cache these string methods here as their use is in performance critical code. -_FORMAT_PATH = "{}/{}".format -_FORMAT_DOMAIN_REVERSED = "{1}.{0}".format - -# The minimum number of scheduled cookie expirations before we start cleaning up -# the expiration heap. This is a performance optimization to avoid cleaning up the -# heap too often when there are only a few scheduled expirations. -_MIN_SCHEDULED_COOKIE_EXPIRATION = 100 -_SIMPLE_COOKIE = SimpleCookie() - - -class CookieJar(AbstractCookieJar): - """Implements cookie storage adhering to RFC 6265.""" - - DATE_TOKENS_RE = re.compile( - r"[\x09\x20-\x2F\x3B-\x40\x5B-\x60\x7B-\x7E]*" - r"(?P[\x00-\x08\x0A-\x1F\d:a-zA-Z\x7F-\xFF]+)" - ) - - DATE_HMS_TIME_RE = re.compile(r"(\d{1,2}):(\d{1,2}):(\d{1,2})") - - DATE_DAY_OF_MONTH_RE = re.compile(r"(\d{1,2})") - - DATE_MONTH_RE = re.compile( - "(jan)|(feb)|(mar)|(apr)|(may)|(jun)|(jul)|(aug)|(sep)|(oct)|(nov)|(dec)", - re.I, - ) - - DATE_YEAR_RE = re.compile(r"(\d{2,4})") - - # calendar.timegm() fails for timestamps after datetime.datetime.max - # Minus one as a loss of precision occurs when timestamp() is called. - MAX_TIME = ( - int(datetime.datetime.max.replace(tzinfo=datetime.timezone.utc).timestamp()) - 1 - ) - try: - calendar.timegm(time.gmtime(MAX_TIME)) - except (OSError, ValueError): - # Hit the maximum representable time on Windows - # https://learn.microsoft.com/en-us/cpp/c-runtime-library/reference/localtime-localtime32-localtime64 - # Throws ValueError on PyPy 3.9, OSError elsewhere - MAX_TIME = calendar.timegm((3000, 12, 31, 23, 59, 59, -1, -1, -1)) - except OverflowError: - # #4515: datetime.max may not be representable on 32-bit platforms - MAX_TIME = 2**31 - 1 - # Avoid minuses in the future, 3x faster - SUB_MAX_TIME = MAX_TIME - 1 - - def __init__( - self, - *, - unsafe: bool = False, - quote_cookie: bool = True, - treat_as_secure_origin: Union[StrOrURL, List[StrOrURL], None] = None, - loop: Optional[asyncio.AbstractEventLoop] = None, - ) -> None: - super().__init__(loop=loop) - self._cookies: DefaultDict[Tuple[str, str], SimpleCookie] = defaultdict( - SimpleCookie - ) - self._morsel_cache: DefaultDict[Tuple[str, str], Dict[str, Morsel[str]]] = ( - defaultdict(dict) - ) - self._host_only_cookies: Set[Tuple[str, str]] = set() - self._unsafe = unsafe - self._quote_cookie = quote_cookie - if treat_as_secure_origin is None: - treat_as_secure_origin = [] - elif isinstance(treat_as_secure_origin, URL): - treat_as_secure_origin = [treat_as_secure_origin.origin()] - elif isinstance(treat_as_secure_origin, str): - treat_as_secure_origin = [URL(treat_as_secure_origin).origin()] - else: - treat_as_secure_origin = [ - URL(url).origin() if isinstance(url, str) else url.origin() - for url in treat_as_secure_origin - ] - self._treat_as_secure_origin = treat_as_secure_origin - self._expire_heap: List[Tuple[float, Tuple[str, str, str]]] = [] - self._expirations: Dict[Tuple[str, str, str], float] = {} - - @property - def quote_cookie(self) -> bool: - return self._quote_cookie - - def save(self, file_path: PathLike) -> None: - file_path = pathlib.Path(file_path) - with file_path.open(mode="wb") as f: - pickle.dump(self._cookies, f, pickle.HIGHEST_PROTOCOL) - - def load(self, file_path: PathLike) -> None: - file_path = pathlib.Path(file_path) - with file_path.open(mode="rb") as f: - self._cookies = pickle.load(f) - - def clear(self, predicate: Optional[ClearCookiePredicate] = None) -> None: - if predicate is None: - self._expire_heap.clear() - self._cookies.clear() - self._morsel_cache.clear() - self._host_only_cookies.clear() - self._expirations.clear() - return - - now = time.time() - to_del = [ - key - for (domain, path), cookie in self._cookies.items() - for name, morsel in cookie.items() - if ( - (key := (domain, path, name)) in self._expirations - and self._expirations[key] <= now - ) - or predicate(morsel) - ] - if to_del: - self._delete_cookies(to_del) - - def clear_domain(self, domain: str) -> None: - self.clear(lambda x: self._is_domain_match(domain, x["domain"])) - - def __iter__(self) -> "Iterator[Morsel[str]]": - self._do_expiration() - for val in self._cookies.values(): - yield from val.values() - - def __len__(self) -> int: - """Return number of cookies. - - This function does not iterate self to avoid unnecessary expiration - checks. - """ - return sum(len(cookie.values()) for cookie in self._cookies.values()) - - def _do_expiration(self) -> None: - """Remove expired cookies.""" - if not (expire_heap_len := len(self._expire_heap)): - return - - # If the expiration heap grows larger than the number expirations - # times two, we clean it up to avoid keeping expired entries in - # the heap and consuming memory. We guard this with a minimum - # threshold to avoid cleaning up the heap too often when there are - # only a few scheduled expirations. - if ( - expire_heap_len > _MIN_SCHEDULED_COOKIE_EXPIRATION - and expire_heap_len > len(self._expirations) * 2 - ): - # Remove any expired entries from the expiration heap - # that do not match the expiration time in the expirations - # as it means the cookie has been re-added to the heap - # with a different expiration time. - self._expire_heap = [ - entry - for entry in self._expire_heap - if self._expirations.get(entry[1]) == entry[0] - ] - heapq.heapify(self._expire_heap) - - now = time.time() - to_del: List[Tuple[str, str, str]] = [] - # Find any expired cookies and add them to the to-delete list - while self._expire_heap: - when, cookie_key = self._expire_heap[0] - if when > now: - break - heapq.heappop(self._expire_heap) - # Check if the cookie hasn't been re-added to the heap - # with a different expiration time as it will be removed - # later when it reaches the top of the heap and its - # expiration time is met. - if self._expirations.get(cookie_key) == when: - to_del.append(cookie_key) - - if to_del: - self._delete_cookies(to_del) - - def _delete_cookies(self, to_del: List[Tuple[str, str, str]]) -> None: - for domain, path, name in to_del: - self._host_only_cookies.discard((domain, name)) - self._cookies[(domain, path)].pop(name, None) - self._morsel_cache[(domain, path)].pop(name, None) - self._expirations.pop((domain, path, name), None) - - def _expire_cookie(self, when: float, domain: str, path: str, name: str) -> None: - cookie_key = (domain, path, name) - if self._expirations.get(cookie_key) == when: - # Avoid adding duplicates to the heap - return - heapq.heappush(self._expire_heap, (when, cookie_key)) - self._expirations[cookie_key] = when - - def update_cookies(self, cookies: LooseCookies, response_url: URL = URL()) -> None: - """Update cookies.""" - hostname = response_url.raw_host - - if not self._unsafe and is_ip_address(hostname): - # Don't accept cookies from IPs - return - - if isinstance(cookies, Mapping): - cookies = cookies.items() - - for name, cookie in cookies: - if not isinstance(cookie, Morsel): - tmp = SimpleCookie() - tmp[name] = cookie # type: ignore[assignment] - cookie = tmp[name] - - domain = cookie["domain"] - - # ignore domains with trailing dots - if domain and domain[-1] == ".": - domain = "" - del cookie["domain"] - - if not domain and hostname is not None: - # Set the cookie's domain to the response hostname - # and set its host-only-flag - self._host_only_cookies.add((hostname, name)) - domain = cookie["domain"] = hostname - - if domain and domain[0] == ".": - # Remove leading dot - domain = domain[1:] - cookie["domain"] = domain - - if hostname and not self._is_domain_match(domain, hostname): - # Setting cookies for different domains is not allowed - continue - - path = cookie["path"] - if not path or path[0] != "/": - # Set the cookie's path to the response path - path = response_url.path - if not path.startswith("/"): - path = "/" - else: - # Cut everything from the last slash to the end - path = "/" + path[1 : path.rfind("/")] - cookie["path"] = path - path = path.rstrip("/") - - if max_age := cookie["max-age"]: - try: - delta_seconds = int(max_age) - max_age_expiration = min(time.time() + delta_seconds, self.MAX_TIME) - self._expire_cookie(max_age_expiration, domain, path, name) - except ValueError: - cookie["max-age"] = "" - - elif expires := cookie["expires"]: - if expire_time := self._parse_date(expires): - self._expire_cookie(expire_time, domain, path, name) - else: - cookie["expires"] = "" - - key = (domain, path) - if self._cookies[key].get(name) != cookie: - # Don't blow away the cache if the same - # cookie gets set again - self._cookies[key][name] = cookie - self._morsel_cache[key].pop(name, None) - - self._do_expiration() - - def filter_cookies(self, request_url: URL = URL()) -> "BaseCookie[str]": - """Returns this jar's cookies filtered by their attributes.""" - # We always use BaseCookie now since all - # cookies set on on filtered are fully constructed - # Morsels, not just names and values. - filtered: BaseCookie[str] = BaseCookie() - if not self._cookies: - # Skip do_expiration() if there are no cookies. - return filtered - self._do_expiration() - if not self._cookies: - # Skip rest of function if no non-expired cookies. - return filtered - if type(request_url) is not URL: - warnings.warn( - "filter_cookies expects yarl.URL instances only," - f"and will stop working in 4.x, got {type(request_url)}", - DeprecationWarning, - stacklevel=2, - ) - request_url = URL(request_url) - hostname = request_url.raw_host or "" - - is_not_secure = request_url.scheme not in ("https", "wss") - if is_not_secure and self._treat_as_secure_origin: - request_origin = URL() - with contextlib.suppress(ValueError): - request_origin = request_url.origin() - is_not_secure = request_origin not in self._treat_as_secure_origin - - # Send shared cookie - key = ("", "") - for c in self._cookies[key].values(): - # Check cache first - if c.key in self._morsel_cache[key]: - filtered[c.key] = self._morsel_cache[key][c.key] - continue - - # Build and cache the morsel - mrsl_val = self._build_morsel(c) - self._morsel_cache[key][c.key] = mrsl_val - filtered[c.key] = mrsl_val - - if is_ip_address(hostname): - if not self._unsafe: - return filtered - domains: Iterable[str] = (hostname,) - else: - # Get all the subdomains that might match a cookie (e.g. "foo.bar.com", "bar.com", "com") - domains = itertools.accumulate( - reversed(hostname.split(".")), _FORMAT_DOMAIN_REVERSED - ) - - # Get all the path prefixes that might match a cookie (e.g. "", "/foo", "/foo/bar") - paths = itertools.accumulate(request_url.path.split("/"), _FORMAT_PATH) - # Create every combination of (domain, path) pairs. - pairs = itertools.product(domains, paths) - - path_len = len(request_url.path) - # Point 2: https://www.rfc-editor.org/rfc/rfc6265.html#section-5.4 - for p in pairs: - if p not in self._cookies: - continue - for name, cookie in self._cookies[p].items(): - domain = cookie["domain"] - - if (domain, name) in self._host_only_cookies and domain != hostname: - continue - - # Skip edge case when the cookie has a trailing slash but request doesn't. - if len(cookie["path"]) > path_len: - continue - - if is_not_secure and cookie["secure"]: - continue - - # We already built the Morsel so reuse it here - if name in self._morsel_cache[p]: - filtered[name] = self._morsel_cache[p][name] - continue - - # Build and cache the morsel - mrsl_val = self._build_morsel(cookie) - self._morsel_cache[p][name] = mrsl_val - filtered[name] = mrsl_val - - return filtered - - def _build_morsel(self, cookie: Morsel[str]) -> Morsel[str]: - """Build a morsel for sending, respecting quote_cookie setting.""" - if self._quote_cookie and cookie.coded_value and cookie.coded_value[0] == '"': - return preserve_morsel_with_coded_value(cookie) - morsel: Morsel[str] = Morsel() - if self._quote_cookie: - value, coded_value = _SIMPLE_COOKIE.value_encode(cookie.value) - else: - coded_value = value = cookie.value - # We use __setstate__ instead of the public set() API because it allows us to - # bypass validation and set already validated state. This is more stable than - # setting protected attributes directly and unlikely to change since it would - # break pickling. - morsel.__setstate__({"key": cookie.key, "value": value, "coded_value": coded_value}) # type: ignore[attr-defined] - return morsel - - @staticmethod - def _is_domain_match(domain: str, hostname: str) -> bool: - """Implements domain matching adhering to RFC 6265.""" - if hostname == domain: - return True - - if not hostname.endswith(domain): - return False - - non_matching = hostname[: -len(domain)] - - if not non_matching.endswith("."): - return False - - return not is_ip_address(hostname) - - @classmethod - def _parse_date(cls, date_str: str) -> Optional[int]: - """Implements date string parsing adhering to RFC 6265.""" - if not date_str: - return None - - found_time = False - found_day = False - found_month = False - found_year = False - - hour = minute = second = 0 - day = 0 - month = 0 - year = 0 - - for token_match in cls.DATE_TOKENS_RE.finditer(date_str): - - token = token_match.group("token") - - if not found_time: - time_match = cls.DATE_HMS_TIME_RE.match(token) - if time_match: - found_time = True - hour, minute, second = (int(s) for s in time_match.groups()) - continue - - if not found_day: - day_match = cls.DATE_DAY_OF_MONTH_RE.match(token) - if day_match: - found_day = True - day = int(day_match.group()) - continue - - if not found_month: - month_match = cls.DATE_MONTH_RE.match(token) - if month_match: - found_month = True - assert month_match.lastindex is not None - month = month_match.lastindex - continue - - if not found_year: - year_match = cls.DATE_YEAR_RE.match(token) - if year_match: - found_year = True - year = int(year_match.group()) - - if 70 <= year <= 99: - year += 1900 - elif 0 <= year <= 69: - year += 2000 - - if False in (found_day, found_month, found_year, found_time): - return None - - if not 1 <= day <= 31: - return None - - if year < 1601 or hour > 23 or minute > 59 or second > 59: - return None - - return calendar.timegm((year, month, day, hour, minute, second, -1, -1, -1)) - - -class DummyCookieJar(AbstractCookieJar): - """Implements a dummy cookie storage. - - It can be used with the ClientSession when no cookie processing is needed. - - """ - - def __init__(self, *, loop: Optional[asyncio.AbstractEventLoop] = None) -> None: - super().__init__(loop=loop) - - def __iter__(self) -> "Iterator[Morsel[str]]": - while False: - yield None - - def __len__(self) -> int: - return 0 - - @property - def quote_cookie(self) -> bool: - return True - - def clear(self, predicate: Optional[ClearCookiePredicate] = None) -> None: - pass - - def clear_domain(self, domain: str) -> None: - pass - - def update_cookies(self, cookies: LooseCookies, response_url: URL = URL()) -> None: - pass - - def filter_cookies(self, request_url: URL) -> "BaseCookie[str]": - return SimpleCookie() diff --git a/venv/lib/python3.9/site-packages/aiohttp/formdata.py b/venv/lib/python3.9/site-packages/aiohttp/formdata.py deleted file mode 100644 index 17d219a..0000000 --- a/venv/lib/python3.9/site-packages/aiohttp/formdata.py +++ /dev/null @@ -1,184 +0,0 @@ -import io -import warnings -from typing import Any, Iterable, List, Optional -from urllib.parse import urlencode - -from multidict import MultiDict, MultiDictProxy - -from . import hdrs, multipart, payload -from .helpers import guess_filename -from .payload import Payload - -__all__ = ("FormData",) - - -class FormData: - """Helper class for form body generation. - - Supports multipart/form-data and application/x-www-form-urlencoded. - """ - - def __init__( - self, - fields: Iterable[Any] = (), - quote_fields: bool = True, - charset: Optional[str] = None, - *, - default_to_multipart: bool = False, - ) -> None: - self._writer = multipart.MultipartWriter("form-data") - self._fields: List[Any] = [] - self._is_multipart = default_to_multipart - self._quote_fields = quote_fields - self._charset = charset - - if isinstance(fields, dict): - fields = list(fields.items()) - elif not isinstance(fields, (list, tuple)): - fields = (fields,) - self.add_fields(*fields) - - @property - def is_multipart(self) -> bool: - return self._is_multipart - - def add_field( - self, - name: str, - value: Any, - *, - content_type: Optional[str] = None, - filename: Optional[str] = None, - content_transfer_encoding: Optional[str] = None, - ) -> None: - - if isinstance(value, io.IOBase): - self._is_multipart = True - elif isinstance(value, (bytes, bytearray, memoryview)): - msg = ( - "In v4, passing bytes will no longer create a file field. " - "Please explicitly use the filename parameter or pass a BytesIO object." - ) - if filename is None and content_transfer_encoding is None: - warnings.warn(msg, DeprecationWarning) - filename = name - - type_options: MultiDict[str] = MultiDict({"name": name}) - if filename is not None and not isinstance(filename, str): - raise TypeError("filename must be an instance of str. Got: %s" % filename) - if filename is None and isinstance(value, io.IOBase): - filename = guess_filename(value, name) - if filename is not None: - type_options["filename"] = filename - self._is_multipart = True - - headers = {} - if content_type is not None: - if not isinstance(content_type, str): - raise TypeError( - "content_type must be an instance of str. Got: %s" % content_type - ) - if "\r" in content_type or "\n" in content_type: - raise ValueError( - "Newline or carriage return detected in headers. " - "Potential header injection attack." - ) - headers[hdrs.CONTENT_TYPE] = content_type - self._is_multipart = True - if content_transfer_encoding is not None: - if not isinstance(content_transfer_encoding, str): - raise TypeError( - "content_transfer_encoding must be an instance" - " of str. Got: %s" % content_transfer_encoding - ) - msg = ( - "content_transfer_encoding is deprecated. " - "To maintain compatibility with v4 please pass a BytesPayload." - ) - warnings.warn(msg, DeprecationWarning) - self._is_multipart = True - - self._fields.append((type_options, headers, value)) - - def add_fields(self, *fields: Any) -> None: - to_add = list(fields) - - while to_add: - rec = to_add.pop(0) - - if isinstance(rec, io.IOBase): - k = guess_filename(rec, "unknown") - self.add_field(k, rec) # type: ignore[arg-type] - - elif isinstance(rec, (MultiDictProxy, MultiDict)): - to_add.extend(rec.items()) - - elif isinstance(rec, (list, tuple)) and len(rec) == 2: - k, fp = rec - self.add_field(k, fp) - - else: - raise TypeError( - "Only io.IOBase, multidict and (name, file) " - "pairs allowed, use .add_field() for passing " - "more complex parameters, got {!r}".format(rec) - ) - - def _gen_form_urlencoded(self) -> payload.BytesPayload: - # form data (x-www-form-urlencoded) - data = [] - for type_options, _, value in self._fields: - data.append((type_options["name"], value)) - - charset = self._charset if self._charset is not None else "utf-8" - - if charset == "utf-8": - content_type = "application/x-www-form-urlencoded" - else: - content_type = "application/x-www-form-urlencoded; charset=%s" % charset - - return payload.BytesPayload( - urlencode(data, doseq=True, encoding=charset).encode(), - content_type=content_type, - ) - - def _gen_form_data(self) -> multipart.MultipartWriter: - """Encode a list of fields using the multipart/form-data MIME format""" - for dispparams, headers, value in self._fields: - try: - if hdrs.CONTENT_TYPE in headers: - part = payload.get_payload( - value, - content_type=headers[hdrs.CONTENT_TYPE], - headers=headers, - encoding=self._charset, - ) - else: - part = payload.get_payload( - value, headers=headers, encoding=self._charset - ) - except Exception as exc: - raise TypeError( - "Can not serialize value type: %r\n " - "headers: %r\n value: %r" % (type(value), headers, value) - ) from exc - - if dispparams: - part.set_content_disposition( - "form-data", quote_fields=self._quote_fields, **dispparams - ) - # FIXME cgi.FieldStorage doesn't likes body parts with - # Content-Length which were sent via chunked transfer encoding - assert part.headers is not None - part.headers.popall(hdrs.CONTENT_LENGTH, None) - - self._writer.append_payload(part) - - self._fields.clear() - return self._writer - - def __call__(self) -> Payload: - if self._is_multipart: - return self._gen_form_data() - else: - return self._gen_form_urlencoded() diff --git a/venv/lib/python3.9/site-packages/aiohttp/hdrs.py b/venv/lib/python3.9/site-packages/aiohttp/hdrs.py deleted file mode 100644 index c8d6b35..0000000 --- a/venv/lib/python3.9/site-packages/aiohttp/hdrs.py +++ /dev/null @@ -1,121 +0,0 @@ -"""HTTP Headers constants.""" - -# After changing the file content call ./tools/gen.py -# to regenerate the headers parser -import itertools -from typing import Final, Set - -from multidict import istr - -METH_ANY: Final[str] = "*" -METH_CONNECT: Final[str] = "CONNECT" -METH_HEAD: Final[str] = "HEAD" -METH_GET: Final[str] = "GET" -METH_DELETE: Final[str] = "DELETE" -METH_OPTIONS: Final[str] = "OPTIONS" -METH_PATCH: Final[str] = "PATCH" -METH_POST: Final[str] = "POST" -METH_PUT: Final[str] = "PUT" -METH_TRACE: Final[str] = "TRACE" - -METH_ALL: Final[Set[str]] = { - METH_CONNECT, - METH_HEAD, - METH_GET, - METH_DELETE, - METH_OPTIONS, - METH_PATCH, - METH_POST, - METH_PUT, - METH_TRACE, -} - -ACCEPT: Final[istr] = istr("Accept") -ACCEPT_CHARSET: Final[istr] = istr("Accept-Charset") -ACCEPT_ENCODING: Final[istr] = istr("Accept-Encoding") -ACCEPT_LANGUAGE: Final[istr] = istr("Accept-Language") -ACCEPT_RANGES: Final[istr] = istr("Accept-Ranges") -ACCESS_CONTROL_MAX_AGE: Final[istr] = istr("Access-Control-Max-Age") -ACCESS_CONTROL_ALLOW_CREDENTIALS: Final[istr] = istr("Access-Control-Allow-Credentials") -ACCESS_CONTROL_ALLOW_HEADERS: Final[istr] = istr("Access-Control-Allow-Headers") -ACCESS_CONTROL_ALLOW_METHODS: Final[istr] = istr("Access-Control-Allow-Methods") -ACCESS_CONTROL_ALLOW_ORIGIN: Final[istr] = istr("Access-Control-Allow-Origin") -ACCESS_CONTROL_EXPOSE_HEADERS: Final[istr] = istr("Access-Control-Expose-Headers") -ACCESS_CONTROL_REQUEST_HEADERS: Final[istr] = istr("Access-Control-Request-Headers") -ACCESS_CONTROL_REQUEST_METHOD: Final[istr] = istr("Access-Control-Request-Method") -AGE: Final[istr] = istr("Age") -ALLOW: Final[istr] = istr("Allow") -AUTHORIZATION: Final[istr] = istr("Authorization") -CACHE_CONTROL: Final[istr] = istr("Cache-Control") -CONNECTION: Final[istr] = istr("Connection") -CONTENT_DISPOSITION: Final[istr] = istr("Content-Disposition") -CONTENT_ENCODING: Final[istr] = istr("Content-Encoding") -CONTENT_LANGUAGE: Final[istr] = istr("Content-Language") -CONTENT_LENGTH: Final[istr] = istr("Content-Length") -CONTENT_LOCATION: Final[istr] = istr("Content-Location") -CONTENT_MD5: Final[istr] = istr("Content-MD5") -CONTENT_RANGE: Final[istr] = istr("Content-Range") -CONTENT_TRANSFER_ENCODING: Final[istr] = istr("Content-Transfer-Encoding") -CONTENT_TYPE: Final[istr] = istr("Content-Type") -COOKIE: Final[istr] = istr("Cookie") -DATE: Final[istr] = istr("Date") -DESTINATION: Final[istr] = istr("Destination") -DIGEST: Final[istr] = istr("Digest") -ETAG: Final[istr] = istr("Etag") -EXPECT: Final[istr] = istr("Expect") -EXPIRES: Final[istr] = istr("Expires") -FORWARDED: Final[istr] = istr("Forwarded") -FROM: Final[istr] = istr("From") -HOST: Final[istr] = istr("Host") -IF_MATCH: Final[istr] = istr("If-Match") -IF_MODIFIED_SINCE: Final[istr] = istr("If-Modified-Since") -IF_NONE_MATCH: Final[istr] = istr("If-None-Match") -IF_RANGE: Final[istr] = istr("If-Range") -IF_UNMODIFIED_SINCE: Final[istr] = istr("If-Unmodified-Since") -KEEP_ALIVE: Final[istr] = istr("Keep-Alive") -LAST_EVENT_ID: Final[istr] = istr("Last-Event-ID") -LAST_MODIFIED: Final[istr] = istr("Last-Modified") -LINK: Final[istr] = istr("Link") -LOCATION: Final[istr] = istr("Location") -MAX_FORWARDS: Final[istr] = istr("Max-Forwards") -ORIGIN: Final[istr] = istr("Origin") -PRAGMA: Final[istr] = istr("Pragma") -PROXY_AUTHENTICATE: Final[istr] = istr("Proxy-Authenticate") -PROXY_AUTHORIZATION: Final[istr] = istr("Proxy-Authorization") -RANGE: Final[istr] = istr("Range") -REFERER: Final[istr] = istr("Referer") -RETRY_AFTER: Final[istr] = istr("Retry-After") -SEC_WEBSOCKET_ACCEPT: Final[istr] = istr("Sec-WebSocket-Accept") -SEC_WEBSOCKET_VERSION: Final[istr] = istr("Sec-WebSocket-Version") -SEC_WEBSOCKET_PROTOCOL: Final[istr] = istr("Sec-WebSocket-Protocol") -SEC_WEBSOCKET_EXTENSIONS: Final[istr] = istr("Sec-WebSocket-Extensions") -SEC_WEBSOCKET_KEY: Final[istr] = istr("Sec-WebSocket-Key") -SEC_WEBSOCKET_KEY1: Final[istr] = istr("Sec-WebSocket-Key1") -SERVER: Final[istr] = istr("Server") -SET_COOKIE: Final[istr] = istr("Set-Cookie") -TE: Final[istr] = istr("TE") -TRAILER: Final[istr] = istr("Trailer") -TRANSFER_ENCODING: Final[istr] = istr("Transfer-Encoding") -UPGRADE: Final[istr] = istr("Upgrade") -URI: Final[istr] = istr("URI") -USER_AGENT: Final[istr] = istr("User-Agent") -VARY: Final[istr] = istr("Vary") -VIA: Final[istr] = istr("Via") -WANT_DIGEST: Final[istr] = istr("Want-Digest") -WARNING: Final[istr] = istr("Warning") -WWW_AUTHENTICATE: Final[istr] = istr("WWW-Authenticate") -X_FORWARDED_FOR: Final[istr] = istr("X-Forwarded-For") -X_FORWARDED_HOST: Final[istr] = istr("X-Forwarded-Host") -X_FORWARDED_PROTO: Final[istr] = istr("X-Forwarded-Proto") - -# These are the upper/lower case variants of the headers/methods -# Example: {'hOst', 'host', 'HoST', 'HOSt', 'hOsT', 'HosT', 'hoSt', ...} -METH_HEAD_ALL: Final = frozenset( - map("".join, itertools.product(*zip(METH_HEAD.upper(), METH_HEAD.lower()))) -) -METH_CONNECT_ALL: Final = frozenset( - map("".join, itertools.product(*zip(METH_CONNECT.upper(), METH_CONNECT.lower()))) -) -HOST_ALL: Final = frozenset( - map("".join, itertools.product(*zip(HOST.upper(), HOST.lower()))) -) diff --git a/venv/lib/python3.9/site-packages/aiohttp/helpers.py b/venv/lib/python3.9/site-packages/aiohttp/helpers.py deleted file mode 100644 index dfab987..0000000 --- a/venv/lib/python3.9/site-packages/aiohttp/helpers.py +++ /dev/null @@ -1,986 +0,0 @@ -"""Various helper functions""" - -import asyncio -import base64 -import binascii -import contextlib -import datetime -import enum -import functools -import inspect -import netrc -import os -import platform -import re -import sys -import time -import weakref -from collections import namedtuple -from contextlib import suppress -from email.message import EmailMessage -from email.parser import HeaderParser -from email.policy import HTTP -from email.utils import parsedate -from math import ceil -from pathlib import Path -from types import MappingProxyType, TracebackType -from typing import ( - Any, - Callable, - ContextManager, - Dict, - Generator, - Generic, - Iterable, - Iterator, - List, - Mapping, - Optional, - Protocol, - Tuple, - Type, - TypeVar, - Union, - get_args, - overload, -) -from urllib.parse import quote -from urllib.request import getproxies, proxy_bypass - -import attr -from multidict import MultiDict, MultiDictProxy, MultiMapping -from propcache.api import under_cached_property as reify -from yarl import URL - -from . import hdrs -from .log import client_logger - -if sys.version_info >= (3, 11): - import asyncio as async_timeout -else: - import async_timeout - -__all__ = ("BasicAuth", "ChainMapProxy", "ETag", "reify") - -IS_MACOS = platform.system() == "Darwin" -IS_WINDOWS = platform.system() == "Windows" - -PY_310 = sys.version_info >= (3, 10) -PY_311 = sys.version_info >= (3, 11) - - -_T = TypeVar("_T") -_S = TypeVar("_S") - -_SENTINEL = enum.Enum("_SENTINEL", "sentinel") -sentinel = _SENTINEL.sentinel - -NO_EXTENSIONS = bool(os.environ.get("AIOHTTP_NO_EXTENSIONS")) - -# https://datatracker.ietf.org/doc/html/rfc9112#section-6.3-2.1 -EMPTY_BODY_STATUS_CODES = frozenset((204, 304, *range(100, 200))) -# https://datatracker.ietf.org/doc/html/rfc9112#section-6.3-2.1 -# https://datatracker.ietf.org/doc/html/rfc9112#section-6.3-2.2 -EMPTY_BODY_METHODS = hdrs.METH_HEAD_ALL - -DEBUG = sys.flags.dev_mode or ( - not sys.flags.ignore_environment and bool(os.environ.get("PYTHONASYNCIODEBUG")) -) - - -CHAR = {chr(i) for i in range(0, 128)} -CTL = {chr(i) for i in range(0, 32)} | { - chr(127), -} -SEPARATORS = { - "(", - ")", - "<", - ">", - "@", - ",", - ";", - ":", - "\\", - '"', - "/", - "[", - "]", - "?", - "=", - "{", - "}", - " ", - chr(9), -} -TOKEN = CHAR ^ CTL ^ SEPARATORS - - -class noop: - def __await__(self) -> Generator[None, None, None]: - yield - - -class BasicAuth(namedtuple("BasicAuth", ["login", "password", "encoding"])): - """Http basic authentication helper.""" - - def __new__( - cls, login: str, password: str = "", encoding: str = "latin1" - ) -> "BasicAuth": - if login is None: - raise ValueError("None is not allowed as login value") - - if password is None: - raise ValueError("None is not allowed as password value") - - if ":" in login: - raise ValueError('A ":" is not allowed in login (RFC 1945#section-11.1)') - - return super().__new__(cls, login, password, encoding) - - @classmethod - def decode(cls, auth_header: str, encoding: str = "latin1") -> "BasicAuth": - """Create a BasicAuth object from an Authorization HTTP header.""" - try: - auth_type, encoded_credentials = auth_header.split(" ", 1) - except ValueError: - raise ValueError("Could not parse authorization header.") - - if auth_type.lower() != "basic": - raise ValueError("Unknown authorization method %s" % auth_type) - - try: - decoded = base64.b64decode( - encoded_credentials.encode("ascii"), validate=True - ).decode(encoding) - except binascii.Error: - raise ValueError("Invalid base64 encoding.") - - try: - # RFC 2617 HTTP Authentication - # https://www.ietf.org/rfc/rfc2617.txt - # the colon must be present, but the username and password may be - # otherwise blank. - username, password = decoded.split(":", 1) - except ValueError: - raise ValueError("Invalid credentials.") - - return cls(username, password, encoding=encoding) - - @classmethod - def from_url(cls, url: URL, *, encoding: str = "latin1") -> Optional["BasicAuth"]: - """Create BasicAuth from url.""" - if not isinstance(url, URL): - raise TypeError("url should be yarl.URL instance") - # Check raw_user and raw_password first as yarl is likely - # to already have these values parsed from the netloc in the cache. - if url.raw_user is None and url.raw_password is None: - return None - return cls(url.user or "", url.password or "", encoding=encoding) - - def encode(self) -> str: - """Encode credentials.""" - creds = (f"{self.login}:{self.password}").encode(self.encoding) - return "Basic %s" % base64.b64encode(creds).decode(self.encoding) - - -def strip_auth_from_url(url: URL) -> Tuple[URL, Optional[BasicAuth]]: - """Remove user and password from URL if present and return BasicAuth object.""" - # Check raw_user and raw_password first as yarl is likely - # to already have these values parsed from the netloc in the cache. - if url.raw_user is None and url.raw_password is None: - return url, None - return url.with_user(None), BasicAuth(url.user or "", url.password or "") - - -def netrc_from_env() -> Optional[netrc.netrc]: - """Load netrc from file. - - Attempt to load it from the path specified by the env-var - NETRC or in the default location in the user's home directory. - - Returns None if it couldn't be found or fails to parse. - """ - netrc_env = os.environ.get("NETRC") - - if netrc_env is not None: - netrc_path = Path(netrc_env) - else: - try: - home_dir = Path.home() - except RuntimeError as e: # pragma: no cover - # if pathlib can't resolve home, it may raise a RuntimeError - client_logger.debug( - "Could not resolve home directory when " - "trying to look for .netrc file: %s", - e, - ) - return None - - netrc_path = home_dir / ("_netrc" if IS_WINDOWS else ".netrc") - - try: - return netrc.netrc(str(netrc_path)) - except netrc.NetrcParseError as e: - client_logger.warning("Could not parse .netrc file: %s", e) - except OSError as e: - netrc_exists = False - with contextlib.suppress(OSError): - netrc_exists = netrc_path.is_file() - # we couldn't read the file (doesn't exist, permissions, etc.) - if netrc_env or netrc_exists: - # only warn if the environment wanted us to load it, - # or it appears like the default file does actually exist - client_logger.warning("Could not read .netrc file: %s", e) - - return None - - -@attr.s(auto_attribs=True, frozen=True, slots=True) -class ProxyInfo: - proxy: URL - proxy_auth: Optional[BasicAuth] - - -def basicauth_from_netrc(netrc_obj: Optional[netrc.netrc], host: str) -> BasicAuth: - """ - Return :py:class:`~aiohttp.BasicAuth` credentials for ``host`` from ``netrc_obj``. - - :raises LookupError: if ``netrc_obj`` is :py:data:`None` or if no - entry is found for the ``host``. - """ - if netrc_obj is None: - raise LookupError("No .netrc file found") - auth_from_netrc = netrc_obj.authenticators(host) - - if auth_from_netrc is None: - raise LookupError(f"No entry for {host!s} found in the `.netrc` file.") - login, account, password = auth_from_netrc - - # TODO(PY311): username = login or account - # Up to python 3.10, account could be None if not specified, - # and login will be empty string if not specified. From 3.11, - # login and account will be empty string if not specified. - username = login if (login or account is None) else account - - # TODO(PY311): Remove this, as password will be empty string - # if not specified - if password is None: - password = "" - - return BasicAuth(username, password) - - -def proxies_from_env() -> Dict[str, ProxyInfo]: - proxy_urls = { - k: URL(v) - for k, v in getproxies().items() - if k in ("http", "https", "ws", "wss") - } - netrc_obj = netrc_from_env() - stripped = {k: strip_auth_from_url(v) for k, v in proxy_urls.items()} - ret = {} - for proto, val in stripped.items(): - proxy, auth = val - if proxy.scheme in ("https", "wss"): - client_logger.warning( - "%s proxies %s are not supported, ignoring", proxy.scheme.upper(), proxy - ) - continue - if netrc_obj and auth is None: - if proxy.host is not None: - try: - auth = basicauth_from_netrc(netrc_obj, proxy.host) - except LookupError: - auth = None - ret[proto] = ProxyInfo(proxy, auth) - return ret - - -def get_env_proxy_for_url(url: URL) -> Tuple[URL, Optional[BasicAuth]]: - """Get a permitted proxy for the given URL from the env.""" - if url.host is not None and proxy_bypass(url.host): - raise LookupError(f"Proxying is disallowed for `{url.host!r}`") - - proxies_in_env = proxies_from_env() - try: - proxy_info = proxies_in_env[url.scheme] - except KeyError: - raise LookupError(f"No proxies found for `{url!s}` in the env") - else: - return proxy_info.proxy, proxy_info.proxy_auth - - -@attr.s(auto_attribs=True, frozen=True, slots=True) -class MimeType: - type: str - subtype: str - suffix: str - parameters: "MultiDictProxy[str]" - - -@functools.lru_cache(maxsize=56) -def parse_mimetype(mimetype: str) -> MimeType: - """Parses a MIME type into its components. - - mimetype is a MIME type string. - - Returns a MimeType object. - - Example: - - >>> parse_mimetype('text/html; charset=utf-8') - MimeType(type='text', subtype='html', suffix='', - parameters={'charset': 'utf-8'}) - - """ - if not mimetype: - return MimeType( - type="", subtype="", suffix="", parameters=MultiDictProxy(MultiDict()) - ) - - parts = mimetype.split(";") - params: MultiDict[str] = MultiDict() - for item in parts[1:]: - if not item: - continue - key, _, value = item.partition("=") - params.add(key.lower().strip(), value.strip(' "')) - - fulltype = parts[0].strip().lower() - if fulltype == "*": - fulltype = "*/*" - - mtype, _, stype = fulltype.partition("/") - stype, _, suffix = stype.partition("+") - - return MimeType( - type=mtype, subtype=stype, suffix=suffix, parameters=MultiDictProxy(params) - ) - - -class EnsureOctetStream(EmailMessage): - def __init__(self) -> None: - super().__init__() - # https://www.rfc-editor.org/rfc/rfc9110#section-8.3-5 - self.set_default_type("application/octet-stream") - - def get_content_type(self) -> str: - """Re-implementation from Message - - Returns application/octet-stream in place of plain/text when - value is wrong. - - The way this class is used guarantees that content-type will - be present so simplify the checks wrt to the base implementation. - """ - value = self.get("content-type", "").lower() - - # Based on the implementation of _splitparam in the standard library - ctype, _, _ = value.partition(";") - ctype = ctype.strip() - if ctype.count("/") != 1: - return self.get_default_type() - return ctype - - -@functools.lru_cache(maxsize=56) -def parse_content_type(raw: str) -> Tuple[str, MappingProxyType[str, str]]: - """Parse Content-Type header. - - Returns a tuple of the parsed content type and a - MappingProxyType of parameters. The default returned value - is `application/octet-stream` - """ - msg = HeaderParser(EnsureOctetStream, policy=HTTP).parsestr(f"Content-Type: {raw}") - content_type = msg.get_content_type() - params = msg.get_params(()) - content_dict = dict(params[1:]) # First element is content type again - return content_type, MappingProxyType(content_dict) - - -def guess_filename(obj: Any, default: Optional[str] = None) -> Optional[str]: - name = getattr(obj, "name", None) - if name and isinstance(name, str) and name[0] != "<" and name[-1] != ">": - return Path(name).name - return default - - -not_qtext_re = re.compile(r"[^\041\043-\133\135-\176]") -QCONTENT = {chr(i) for i in range(0x20, 0x7F)} | {"\t"} - - -def quoted_string(content: str) -> str: - """Return 7-bit content as quoted-string. - - Format content into a quoted-string as defined in RFC5322 for - Internet Message Format. Notice that this is not the 8-bit HTTP - format, but the 7-bit email format. Content must be in usascii or - a ValueError is raised. - """ - if not (QCONTENT > set(content)): - raise ValueError(f"bad content for quoted-string {content!r}") - return not_qtext_re.sub(lambda x: "\\" + x.group(0), content) - - -def content_disposition_header( - disptype: str, quote_fields: bool = True, _charset: str = "utf-8", **params: str -) -> str: - """Sets ``Content-Disposition`` header for MIME. - - This is the MIME payload Content-Disposition header from RFC 2183 - and RFC 7579 section 4.2, not the HTTP Content-Disposition from - RFC 6266. - - disptype is a disposition type: inline, attachment, form-data. - Should be valid extension token (see RFC 2183) - - quote_fields performs value quoting to 7-bit MIME headers - according to RFC 7578. Set to quote_fields to False if recipient - can take 8-bit file names and field values. - - _charset specifies the charset to use when quote_fields is True. - - params is a dict with disposition params. - """ - if not disptype or not (TOKEN > set(disptype)): - raise ValueError(f"bad content disposition type {disptype!r}") - - value = disptype - if params: - lparams = [] - for key, val in params.items(): - if not key or not (TOKEN > set(key)): - raise ValueError(f"bad content disposition parameter {key!r}={val!r}") - if quote_fields: - if key.lower() == "filename": - qval = quote(val, "", encoding=_charset) - lparams.append((key, '"%s"' % qval)) - else: - try: - qval = quoted_string(val) - except ValueError: - qval = "".join( - (_charset, "''", quote(val, "", encoding=_charset)) - ) - lparams.append((key + "*", qval)) - else: - lparams.append((key, '"%s"' % qval)) - else: - qval = val.replace("\\", "\\\\").replace('"', '\\"') - lparams.append((key, '"%s"' % qval)) - sparams = "; ".join("=".join(pair) for pair in lparams) - value = "; ".join((value, sparams)) - return value - - -def is_ip_address(host: Optional[str]) -> bool: - """Check if host looks like an IP Address. - - This check is only meant as a heuristic to ensure that - a host is not a domain name. - """ - if not host: - return False - # For a host to be an ipv4 address, it must be all numeric. - # The host must contain a colon to be an IPv6 address. - return ":" in host or host.replace(".", "").isdigit() - - -_cached_current_datetime: Optional[int] = None -_cached_formatted_datetime = "" - - -def rfc822_formatted_time() -> str: - global _cached_current_datetime - global _cached_formatted_datetime - - now = int(time.time()) - if now != _cached_current_datetime: - # Weekday and month names for HTTP date/time formatting; - # always English! - # Tuples are constants stored in codeobject! - _weekdayname = ("Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun") - _monthname = ( - "", # Dummy so we can use 1-based month numbers - "Jan", - "Feb", - "Mar", - "Apr", - "May", - "Jun", - "Jul", - "Aug", - "Sep", - "Oct", - "Nov", - "Dec", - ) - - year, month, day, hh, mm, ss, wd, *tail = time.gmtime(now) - _cached_formatted_datetime = "%s, %02d %3s %4d %02d:%02d:%02d GMT" % ( - _weekdayname[wd], - day, - _monthname[month], - year, - hh, - mm, - ss, - ) - _cached_current_datetime = now - return _cached_formatted_datetime - - -def _weakref_handle(info: "Tuple[weakref.ref[object], str]") -> None: - ref, name = info - ob = ref() - if ob is not None: - with suppress(Exception): - getattr(ob, name)() - - -def weakref_handle( - ob: object, - name: str, - timeout: float, - loop: asyncio.AbstractEventLoop, - timeout_ceil_threshold: float = 5, -) -> Optional[asyncio.TimerHandle]: - if timeout is not None and timeout > 0: - when = loop.time() + timeout - if timeout >= timeout_ceil_threshold: - when = ceil(when) - - return loop.call_at(when, _weakref_handle, (weakref.ref(ob), name)) - return None - - -def call_later( - cb: Callable[[], Any], - timeout: float, - loop: asyncio.AbstractEventLoop, - timeout_ceil_threshold: float = 5, -) -> Optional[asyncio.TimerHandle]: - if timeout is None or timeout <= 0: - return None - now = loop.time() - when = calculate_timeout_when(now, timeout, timeout_ceil_threshold) - return loop.call_at(when, cb) - - -def calculate_timeout_when( - loop_time: float, - timeout: float, - timeout_ceiling_threshold: float, -) -> float: - """Calculate when to execute a timeout.""" - when = loop_time + timeout - if timeout > timeout_ceiling_threshold: - return ceil(when) - return when - - -class TimeoutHandle: - """Timeout handle""" - - __slots__ = ("_timeout", "_loop", "_ceil_threshold", "_callbacks") - - def __init__( - self, - loop: asyncio.AbstractEventLoop, - timeout: Optional[float], - ceil_threshold: float = 5, - ) -> None: - self._timeout = timeout - self._loop = loop - self._ceil_threshold = ceil_threshold - self._callbacks: List[ - Tuple[Callable[..., None], Tuple[Any, ...], Dict[str, Any]] - ] = [] - - def register( - self, callback: Callable[..., None], *args: Any, **kwargs: Any - ) -> None: - self._callbacks.append((callback, args, kwargs)) - - def close(self) -> None: - self._callbacks.clear() - - def start(self) -> Optional[asyncio.TimerHandle]: - timeout = self._timeout - if timeout is not None and timeout > 0: - when = self._loop.time() + timeout - if timeout >= self._ceil_threshold: - when = ceil(when) - return self._loop.call_at(when, self.__call__) - else: - return None - - def timer(self) -> "BaseTimerContext": - if self._timeout is not None and self._timeout > 0: - timer = TimerContext(self._loop) - self.register(timer.timeout) - return timer - else: - return TimerNoop() - - def __call__(self) -> None: - for cb, args, kwargs in self._callbacks: - with suppress(Exception): - cb(*args, **kwargs) - - self._callbacks.clear() - - -class BaseTimerContext(ContextManager["BaseTimerContext"]): - - __slots__ = () - - def assert_timeout(self) -> None: - """Raise TimeoutError if timeout has been exceeded.""" - - -class TimerNoop(BaseTimerContext): - - __slots__ = () - - def __enter__(self) -> BaseTimerContext: - return self - - def __exit__( - self, - exc_type: Optional[Type[BaseException]], - exc_val: Optional[BaseException], - exc_tb: Optional[TracebackType], - ) -> None: - return - - -class TimerContext(BaseTimerContext): - """Low resolution timeout context manager""" - - __slots__ = ("_loop", "_tasks", "_cancelled", "_cancelling") - - def __init__(self, loop: asyncio.AbstractEventLoop) -> None: - self._loop = loop - self._tasks: List[asyncio.Task[Any]] = [] - self._cancelled = False - self._cancelling = 0 - - def assert_timeout(self) -> None: - """Raise TimeoutError if timer has already been cancelled.""" - if self._cancelled: - raise asyncio.TimeoutError from None - - def __enter__(self) -> BaseTimerContext: - task = asyncio.current_task(loop=self._loop) - if task is None: - raise RuntimeError("Timeout context manager should be used inside a task") - - if sys.version_info >= (3, 11): - # Remember if the task was already cancelling - # so when we __exit__ we can decide if we should - # raise asyncio.TimeoutError or let the cancellation propagate - self._cancelling = task.cancelling() - - if self._cancelled: - raise asyncio.TimeoutError from None - - self._tasks.append(task) - return self - - def __exit__( - self, - exc_type: Optional[Type[BaseException]], - exc_val: Optional[BaseException], - exc_tb: Optional[TracebackType], - ) -> Optional[bool]: - enter_task: Optional[asyncio.Task[Any]] = None - if self._tasks: - enter_task = self._tasks.pop() - - if exc_type is asyncio.CancelledError and self._cancelled: - assert enter_task is not None - # The timeout was hit, and the task was cancelled - # so we need to uncancel the last task that entered the context manager - # since the cancellation should not leak out of the context manager - if sys.version_info >= (3, 11): - # If the task was already cancelling don't raise - # asyncio.TimeoutError and instead return None - # to allow the cancellation to propagate - if enter_task.uncancel() > self._cancelling: - return None - raise asyncio.TimeoutError from exc_val - return None - - def timeout(self) -> None: - if not self._cancelled: - for task in set(self._tasks): - task.cancel() - - self._cancelled = True - - -def ceil_timeout( - delay: Optional[float], ceil_threshold: float = 5 -) -> async_timeout.Timeout: - if delay is None or delay <= 0: - return async_timeout.timeout(None) - - loop = asyncio.get_running_loop() - now = loop.time() - when = now + delay - if delay > ceil_threshold: - when = ceil(when) - return async_timeout.timeout_at(when) - - -class HeadersMixin: - """Mixin for handling headers.""" - - ATTRS = frozenset(["_content_type", "_content_dict", "_stored_content_type"]) - - _headers: MultiMapping[str] - _content_type: Optional[str] = None - _content_dict: Optional[Dict[str, str]] = None - _stored_content_type: Union[str, None, _SENTINEL] = sentinel - - def _parse_content_type(self, raw: Optional[str]) -> None: - self._stored_content_type = raw - if raw is None: - # default value according to RFC 2616 - self._content_type = "application/octet-stream" - self._content_dict = {} - else: - content_type, content_mapping_proxy = parse_content_type(raw) - self._content_type = content_type - # _content_dict needs to be mutable so we can update it - self._content_dict = content_mapping_proxy.copy() - - @property - def content_type(self) -> str: - """The value of content part for Content-Type HTTP header.""" - raw = self._headers.get(hdrs.CONTENT_TYPE) - if self._stored_content_type != raw: - self._parse_content_type(raw) - assert self._content_type is not None - return self._content_type - - @property - def charset(self) -> Optional[str]: - """The value of charset part for Content-Type HTTP header.""" - raw = self._headers.get(hdrs.CONTENT_TYPE) - if self._stored_content_type != raw: - self._parse_content_type(raw) - assert self._content_dict is not None - return self._content_dict.get("charset") - - @property - def content_length(self) -> Optional[int]: - """The value of Content-Length HTTP header.""" - content_length = self._headers.get(hdrs.CONTENT_LENGTH) - return None if content_length is None else int(content_length) - - -def set_result(fut: "asyncio.Future[_T]", result: _T) -> None: - if not fut.done(): - fut.set_result(result) - - -_EXC_SENTINEL = BaseException() - - -class ErrorableProtocol(Protocol): - def set_exception( - self, - exc: BaseException, - exc_cause: BaseException = ..., - ) -> None: ... # pragma: no cover - - -def set_exception( - fut: "asyncio.Future[_T] | ErrorableProtocol", - exc: BaseException, - exc_cause: BaseException = _EXC_SENTINEL, -) -> None: - """Set future exception. - - If the future is marked as complete, this function is a no-op. - - :param exc_cause: An exception that is a direct cause of ``exc``. - Only set if provided. - """ - if asyncio.isfuture(fut) and fut.done(): - return - - exc_is_sentinel = exc_cause is _EXC_SENTINEL - exc_causes_itself = exc is exc_cause - if not exc_is_sentinel and not exc_causes_itself: - exc.__cause__ = exc_cause - - fut.set_exception(exc) - - -@functools.total_ordering -class AppKey(Generic[_T]): - """Keys for static typing support in Application.""" - - __slots__ = ("_name", "_t", "__orig_class__") - - # This may be set by Python when instantiating with a generic type. We need to - # support this, in order to support types that are not concrete classes, - # like Iterable, which can't be passed as the second parameter to __init__. - __orig_class__: Type[object] - - def __init__(self, name: str, t: Optional[Type[_T]] = None): - # Prefix with module name to help deduplicate key names. - frame = inspect.currentframe() - while frame: - if frame.f_code.co_name == "": - module: str = frame.f_globals["__name__"] - break - frame = frame.f_back - - self._name = module + "." + name - self._t = t - - def __lt__(self, other: object) -> bool: - if isinstance(other, AppKey): - return self._name < other._name - return True # Order AppKey above other types. - - def __repr__(self) -> str: - t = self._t - if t is None: - with suppress(AttributeError): - # Set to type arg. - t = get_args(self.__orig_class__)[0] - - if t is None: - t_repr = "<>" - elif isinstance(t, type): - if t.__module__ == "builtins": - t_repr = t.__qualname__ - else: - t_repr = f"{t.__module__}.{t.__qualname__}" - else: - t_repr = repr(t) - return f"" - - -class ChainMapProxy(Mapping[Union[str, AppKey[Any]], Any]): - __slots__ = ("_maps",) - - def __init__(self, maps: Iterable[Mapping[Union[str, AppKey[Any]], Any]]) -> None: - self._maps = tuple(maps) - - def __init_subclass__(cls) -> None: - raise TypeError( - "Inheritance class {} from ChainMapProxy " - "is forbidden".format(cls.__name__) - ) - - @overload # type: ignore[override] - def __getitem__(self, key: AppKey[_T]) -> _T: ... - - @overload - def __getitem__(self, key: str) -> Any: ... - - def __getitem__(self, key: Union[str, AppKey[_T]]) -> Any: - for mapping in self._maps: - try: - return mapping[key] - except KeyError: - pass - raise KeyError(key) - - @overload # type: ignore[override] - def get(self, key: AppKey[_T], default: _S) -> Union[_T, _S]: ... - - @overload - def get(self, key: AppKey[_T], default: None = ...) -> Optional[_T]: ... - - @overload - def get(self, key: str, default: Any = ...) -> Any: ... - - def get(self, key: Union[str, AppKey[_T]], default: Any = None) -> Any: - try: - return self[key] - except KeyError: - return default - - def __len__(self) -> int: - # reuses stored hash values if possible - return len(set().union(*self._maps)) - - def __iter__(self) -> Iterator[Union[str, AppKey[Any]]]: - d: Dict[Union[str, AppKey[Any]], Any] = {} - for mapping in reversed(self._maps): - # reuses stored hash values if possible - d.update(mapping) - return iter(d) - - def __contains__(self, key: object) -> bool: - return any(key in m for m in self._maps) - - def __bool__(self) -> bool: - return any(self._maps) - - def __repr__(self) -> str: - content = ", ".join(map(repr, self._maps)) - return f"ChainMapProxy({content})" - - -# https://tools.ietf.org/html/rfc7232#section-2.3 -_ETAGC = r"[!\x23-\x7E\x80-\xff]+" -_ETAGC_RE = re.compile(_ETAGC) -_QUOTED_ETAG = rf'(W/)?"({_ETAGC})"' -QUOTED_ETAG_RE = re.compile(_QUOTED_ETAG) -LIST_QUOTED_ETAG_RE = re.compile(rf"({_QUOTED_ETAG})(?:\s*,\s*|$)|(.)") - -ETAG_ANY = "*" - - -@attr.s(auto_attribs=True, frozen=True, slots=True) -class ETag: - value: str - is_weak: bool = False - - -def validate_etag_value(value: str) -> None: - if value != ETAG_ANY and not _ETAGC_RE.fullmatch(value): - raise ValueError( - f"Value {value!r} is not a valid etag. Maybe it contains '\"'?" - ) - - -def parse_http_date(date_str: Optional[str]) -> Optional[datetime.datetime]: - """Process a date string, return a datetime object""" - if date_str is not None: - timetuple = parsedate(date_str) - if timetuple is not None: - with suppress(ValueError): - return datetime.datetime(*timetuple[:6], tzinfo=datetime.timezone.utc) - return None - - -@functools.lru_cache -def must_be_empty_body(method: str, code: int) -> bool: - """Check if a request must return an empty body.""" - return ( - code in EMPTY_BODY_STATUS_CODES - or method in EMPTY_BODY_METHODS - or (200 <= code < 300 and method in hdrs.METH_CONNECT_ALL) - ) - - -def should_remove_content_length(method: str, code: int) -> bool: - """Check if a Content-Length header should be removed. - - This should always be a subset of must_be_empty_body - """ - # https://www.rfc-editor.org/rfc/rfc9110.html#section-8.6-8 - # https://www.rfc-editor.org/rfc/rfc9110.html#section-15.4.5-4 - return code in EMPTY_BODY_STATUS_CODES or ( - 200 <= code < 300 and method in hdrs.METH_CONNECT_ALL - ) diff --git a/venv/lib/python3.9/site-packages/aiohttp/http.py b/venv/lib/python3.9/site-packages/aiohttp/http.py deleted file mode 100644 index a1feae2..0000000 --- a/venv/lib/python3.9/site-packages/aiohttp/http.py +++ /dev/null @@ -1,72 +0,0 @@ -import sys -from http import HTTPStatus -from typing import Mapping, Tuple - -from . import __version__ -from .http_exceptions import HttpProcessingError as HttpProcessingError -from .http_parser import ( - HeadersParser as HeadersParser, - HttpParser as HttpParser, - HttpRequestParser as HttpRequestParser, - HttpResponseParser as HttpResponseParser, - RawRequestMessage as RawRequestMessage, - RawResponseMessage as RawResponseMessage, -) -from .http_websocket import ( - WS_CLOSED_MESSAGE as WS_CLOSED_MESSAGE, - WS_CLOSING_MESSAGE as WS_CLOSING_MESSAGE, - WS_KEY as WS_KEY, - WebSocketError as WebSocketError, - WebSocketReader as WebSocketReader, - WebSocketWriter as WebSocketWriter, - WSCloseCode as WSCloseCode, - WSMessage as WSMessage, - WSMsgType as WSMsgType, - ws_ext_gen as ws_ext_gen, - ws_ext_parse as ws_ext_parse, -) -from .http_writer import ( - HttpVersion as HttpVersion, - HttpVersion10 as HttpVersion10, - HttpVersion11 as HttpVersion11, - StreamWriter as StreamWriter, -) - -__all__ = ( - "HttpProcessingError", - "RESPONSES", - "SERVER_SOFTWARE", - # .http_writer - "StreamWriter", - "HttpVersion", - "HttpVersion10", - "HttpVersion11", - # .http_parser - "HeadersParser", - "HttpParser", - "HttpRequestParser", - "HttpResponseParser", - "RawRequestMessage", - "RawResponseMessage", - # .http_websocket - "WS_CLOSED_MESSAGE", - "WS_CLOSING_MESSAGE", - "WS_KEY", - "WebSocketReader", - "WebSocketWriter", - "ws_ext_gen", - "ws_ext_parse", - "WSMessage", - "WebSocketError", - "WSMsgType", - "WSCloseCode", -) - - -SERVER_SOFTWARE: str = "Python/{0[0]}.{0[1]} aiohttp/{1}".format( - sys.version_info, __version__ -) - -RESPONSES: Mapping[int, Tuple[str, str]] = { - v: (v.phrase, v.description) for v in HTTPStatus.__members__.values() -} diff --git a/venv/lib/python3.9/site-packages/aiohttp/http_exceptions.py b/venv/lib/python3.9/site-packages/aiohttp/http_exceptions.py deleted file mode 100644 index a389e94..0000000 --- a/venv/lib/python3.9/site-packages/aiohttp/http_exceptions.py +++ /dev/null @@ -1,117 +0,0 @@ -"""Low-level http related exceptions.""" - -from textwrap import indent -from typing import Optional, Union - -from .typedefs import _CIMultiDict - -__all__ = ("HttpProcessingError",) - - -class HttpProcessingError(Exception): - """HTTP error. - - Shortcut for raising HTTP errors with custom code, message and headers. - - code: HTTP Error code. - message: (optional) Error message. - headers: (optional) Headers to be sent in response, a list of pairs - """ - - code = 0 - message = "" - headers = None - - def __init__( - self, - *, - code: Optional[int] = None, - message: str = "", - headers: Optional[_CIMultiDict] = None, - ) -> None: - if code is not None: - self.code = code - self.headers = headers - self.message = message - - def __str__(self) -> str: - msg = indent(self.message, " ") - return f"{self.code}, message:\n{msg}" - - def __repr__(self) -> str: - return f"<{self.__class__.__name__}: {self.code}, message={self.message!r}>" - - -class BadHttpMessage(HttpProcessingError): - - code = 400 - message = "Bad Request" - - def __init__(self, message: str, *, headers: Optional[_CIMultiDict] = None) -> None: - super().__init__(message=message, headers=headers) - self.args = (message,) - - -class HttpBadRequest(BadHttpMessage): - - code = 400 - message = "Bad Request" - - -class PayloadEncodingError(BadHttpMessage): - """Base class for payload errors""" - - -class ContentEncodingError(PayloadEncodingError): - """Content encoding error.""" - - -class TransferEncodingError(PayloadEncodingError): - """transfer encoding error.""" - - -class ContentLengthError(PayloadEncodingError): - """Not enough data to satisfy content length header.""" - - -class DecompressSizeError(PayloadEncodingError): - """Decompressed size exceeds the configured limit.""" - - -class LineTooLong(BadHttpMessage): - def __init__( - self, - line: Union[str, bytes], - limit: Union[str, int] = "Unknown", - actual_size: str = "Unknown", - ) -> None: - super().__init__(f"Got more than {limit} bytes when reading: {line!r}.") - self.args = (line, limit, actual_size) - - -class InvalidHeader(BadHttpMessage): - def __init__(self, hdr: Union[bytes, str]) -> None: - hdr_s = hdr.decode(errors="backslashreplace") if isinstance(hdr, bytes) else hdr - super().__init__(f"Invalid HTTP header: {hdr!r}") - self.hdr = hdr_s - self.args = (hdr,) - - -class BadStatusLine(BadHttpMessage): - def __init__(self, line: str = "", error: Optional[str] = None) -> None: - if not isinstance(line, str): - line = repr(line) - super().__init__(error or f"Bad status line {line!r}") - self.args = (line,) - self.line = line - - -class BadHttpMethod(BadStatusLine): - """Invalid HTTP method in status line.""" - - def __init__(self, line: str = "", error: Optional[str] = None) -> None: - super().__init__(line, error or f"Bad HTTP method in status line {line!r}") - - -class InvalidURLError(BadHttpMessage): - pass diff --git a/venv/lib/python3.9/site-packages/aiohttp/http_parser.py b/venv/lib/python3.9/site-packages/aiohttp/http_parser.py deleted file mode 100644 index 6a471cd..0000000 --- a/venv/lib/python3.9/site-packages/aiohttp/http_parser.py +++ /dev/null @@ -1,1125 +0,0 @@ -import abc -import asyncio -import re -import string -from contextlib import suppress -from enum import IntEnum -from typing import ( - Any, - ClassVar, - Final, - Generic, - List, - Literal, - NamedTuple, - Optional, - Pattern, - Set, - Tuple, - Type, - TypeVar, - Union, -) - -from multidict import CIMultiDict, CIMultiDictProxy, istr -from yarl import URL - -from . import hdrs -from .base_protocol import BaseProtocol -from .compression_utils import ( - DEFAULT_MAX_DECOMPRESS_SIZE, - HAS_BROTLI, - HAS_ZSTD, - BrotliDecompressor, - ZLibDecompressor, - ZSTDDecompressor, -) -from .helpers import ( - _EXC_SENTINEL, - DEBUG, - EMPTY_BODY_METHODS, - EMPTY_BODY_STATUS_CODES, - NO_EXTENSIONS, - BaseTimerContext, - set_exception, -) -from .http_exceptions import ( - BadHttpMessage, - BadHttpMethod, - BadStatusLine, - ContentEncodingError, - ContentLengthError, - DecompressSizeError, - InvalidHeader, - InvalidURLError, - LineTooLong, - TransferEncodingError, -) -from .http_writer import HttpVersion, HttpVersion10 -from .streams import EMPTY_PAYLOAD, StreamReader -from .typedefs import RawHeaders - -__all__ = ( - "HeadersParser", - "HttpParser", - "HttpRequestParser", - "HttpResponseParser", - "RawRequestMessage", - "RawResponseMessage", -) - -_SEP = Literal[b"\r\n", b"\n"] - -ASCIISET: Final[Set[str]] = set(string.printable) - -# See https://www.rfc-editor.org/rfc/rfc9110.html#name-overview -# and https://www.rfc-editor.org/rfc/rfc9110.html#name-tokens -# -# method = token -# tchar = "!" / "#" / "$" / "%" / "&" / "'" / "*" / "+" / "-" / "." / -# "^" / "_" / "`" / "|" / "~" / DIGIT / ALPHA -# token = 1*tchar -_TCHAR_SPECIALS: Final[str] = re.escape("!#$%&'*+-.^_`|~") -TOKENRE: Final[Pattern[str]] = re.compile(f"[0-9A-Za-z{_TCHAR_SPECIALS}]+") -# https://www.rfc-editor.org/rfc/rfc9110#section-5.5-5 -_FIELD_VALUE_FORBIDDEN_CTL_RE: Final[Pattern[str]] = re.compile( - r"[\x00-\x08\x0a-\x1f\x7f]" -) -VERSRE: Final[Pattern[str]] = re.compile(r"HTTP/(\d)\.(\d)", re.ASCII) -DIGITS: Final[Pattern[str]] = re.compile(r"\d+", re.ASCII) -HEXDIGITS: Final[Pattern[bytes]] = re.compile(rb"[0-9a-fA-F]+") - -# RFC 9110 singleton headers — duplicates are rejected in strict mode. -# In lax mode (response parser default), the check is skipped entirely -# since real-world servers (e.g. Google APIs, Werkzeug) commonly send -# duplicate headers like Content-Type or Server. -# Lowercased for case-insensitive matching against wire names. -SINGLETON_HEADERS: Final[frozenset[str]] = frozenset( - { - "content-length", - "content-location", - "content-range", - "content-type", - "etag", - "host", - "max-forwards", - "server", - "transfer-encoding", - "user-agent", - } -) - - -class RawRequestMessage(NamedTuple): - method: str - path: str - version: HttpVersion - headers: "CIMultiDictProxy[str]" - raw_headers: RawHeaders - should_close: bool - compression: Optional[str] - upgrade: bool - chunked: bool - url: URL - - -class RawResponseMessage(NamedTuple): - version: HttpVersion - code: int - reason: str - headers: CIMultiDictProxy[str] - raw_headers: RawHeaders - should_close: bool - compression: Optional[str] - upgrade: bool - chunked: bool - - -_MsgT = TypeVar("_MsgT", RawRequestMessage, RawResponseMessage) - - -class ParseState(IntEnum): - - PARSE_NONE = 0 - PARSE_LENGTH = 1 - PARSE_CHUNKED = 2 - PARSE_UNTIL_EOF = 3 - - -class ChunkState(IntEnum): - PARSE_CHUNKED_SIZE = 0 - PARSE_CHUNKED_CHUNK = 1 - PARSE_CHUNKED_CHUNK_EOF = 2 - PARSE_MAYBE_TRAILERS = 3 - PARSE_TRAILERS = 4 - - -class HeadersParser: - def __init__( - self, - max_line_size: int = 8190, - max_headers: int = 32768, - max_field_size: int = 8190, - lax: bool = False, - ) -> None: - self.max_line_size = max_line_size - self.max_headers = max_headers - self.max_field_size = max_field_size - self._lax = lax - - def parse_headers( - self, lines: List[bytes] - ) -> Tuple["CIMultiDictProxy[str]", RawHeaders]: - headers: CIMultiDict[str] = CIMultiDict() - # note: "raw" does not mean inclusion of OWS before/after the field value - raw_headers = [] - - lines_idx = 0 - line = lines[lines_idx] - line_count = len(lines) - - while line: - # Parse initial header name : value pair. - try: - bname, bvalue = line.split(b":", 1) - except ValueError: - raise InvalidHeader(line) from None - - if len(bname) == 0: - raise InvalidHeader(bname) - - # https://www.rfc-editor.org/rfc/rfc9112.html#section-5.1-2 - if {bname[0], bname[-1]} & {32, 9}: # {" ", "\t"} - raise InvalidHeader(line) - - bvalue = bvalue.lstrip(b" \t") - name = bname.decode("utf-8", "surrogateescape") - if not TOKENRE.fullmatch(name): - raise InvalidHeader(bname) - - # next line - lines_idx += 1 - line = lines[lines_idx] - - # consume continuation lines - continuation = self._lax and line and line[0] in (32, 9) # (' ', '\t') - - # Deprecated: https://www.rfc-editor.org/rfc/rfc9112.html#name-obsolete-line-folding - if continuation: - header_length = len(bvalue) - bvalue_lst = [bvalue] - while continuation: - header_length += len(line) - if header_length > self.max_field_size: - header_line = bname + b": " + b"".join(bvalue_lst) - raise LineTooLong( - header_line[:100] + b"...", self.max_field_size - ) - bvalue_lst.append(line) - - # next line - lines_idx += 1 - if lines_idx < line_count: - line = lines[lines_idx] - if line: - continuation = line[0] in (32, 9) # (' ', '\t') - else: - line = b"" - break - bvalue = b"".join(bvalue_lst) - - bvalue = bvalue.strip(b" \t") - value = bvalue.decode("utf-8", "surrogateescape") - - # https://www.rfc-editor.org/rfc/rfc9110.html#section-5.5-5 - if self._lax: - if "\n" in value or "\r" in value or "\x00" in value: - raise InvalidHeader(bvalue) - elif _FIELD_VALUE_FORBIDDEN_CTL_RE.search(value): - raise InvalidHeader(bvalue) - - if not self._lax and name in headers and name.lower() in SINGLETON_HEADERS: - raise BadHttpMessage(f"Duplicate '{name}' header found.") - headers.add(name, value) - raw_headers.append((bname, bvalue)) - - return (CIMultiDictProxy(headers), tuple(raw_headers)) - - -def _is_supported_upgrade(headers: CIMultiDictProxy[str]) -> bool: - """Check if the upgrade header is supported.""" - u = headers.get(hdrs.UPGRADE, "") - # .lower() can transform non-ascii characters. - return u.isascii() and u.lower() in {"tcp", "websocket"} - - -class HttpParser(abc.ABC, Generic[_MsgT]): - lax: ClassVar[bool] = False - - def __init__( - self, - protocol: Optional[BaseProtocol] = None, - loop: Optional[asyncio.AbstractEventLoop] = None, - limit: int = 2**16, - max_line_size: int = 8190, - max_headers: int = 128, - max_field_size: int = 8190, - timer: Optional[BaseTimerContext] = None, - code: Optional[int] = None, - method: Optional[str] = None, - payload_exception: Optional[Type[BaseException]] = None, - response_with_body: bool = True, - read_until_eof: bool = False, - auto_decompress: bool = True, - ) -> None: - self.protocol = protocol - self.loop = loop - self.max_line_size = max_line_size - self.max_headers = max_headers - self.max_field_size = max_field_size - self.max_headers = max_headers - self.timer = timer - self.code = code - self.method = method - self.payload_exception = payload_exception - self.response_with_body = response_with_body - self.read_until_eof = read_until_eof - - self._lines: List[bytes] = [] - self._tail = b"" - self._upgraded = False - self._payload = None - self._payload_parser: Optional[HttpPayloadParser] = None - self._auto_decompress = auto_decompress - self._limit = limit - self._headers_parser = HeadersParser( - max_line_size, max_headers, max_field_size, self.lax - ) - - @abc.abstractmethod - def parse_message(self, lines: List[bytes]) -> _MsgT: ... - - @abc.abstractmethod - def _is_chunked_te(self, te: str) -> bool: ... - - def feed_eof(self) -> Optional[_MsgT]: - if self._payload_parser is not None: - self._payload_parser.feed_eof() - self._payload_parser = None - else: - # try to extract partial message - if self._tail: - self._lines.append(self._tail) - - if self._lines: - if self._lines[-1] != "\r\n": - self._lines.append(b"") - with suppress(Exception): - return self.parse_message(self._lines) - return None - - def feed_data( - self, - data: bytes, - SEP: _SEP = b"\r\n", - EMPTY: bytes = b"", - CONTENT_LENGTH: istr = hdrs.CONTENT_LENGTH, - METH_CONNECT: str = hdrs.METH_CONNECT, - SEC_WEBSOCKET_KEY1: istr = hdrs.SEC_WEBSOCKET_KEY1, - ) -> Tuple[List[Tuple[_MsgT, StreamReader]], bool, bytes]: - - messages = [] - - if self._tail: - data, self._tail = self._tail + data, b"" - - data_len = len(data) - start_pos = 0 - loop = self.loop - max_line_length = self.max_line_size - - should_close = False - while start_pos < data_len: - - # read HTTP message (request/response line + headers), \r\n\r\n - # and split by lines - if self._payload_parser is None and not self._upgraded: - pos = data.find(SEP, start_pos) - # consume \r\n - if pos == start_pos and not self._lines: - start_pos = pos + len(SEP) - continue - - if pos >= start_pos: - if should_close: - raise BadHttpMessage("Data after `Connection: close`") - - # line found - line = data[start_pos:pos] - if SEP == b"\n": # For lax response parsing - line = line.rstrip(b"\r") - if len(line) > max_line_length: - raise LineTooLong(line[:100] + b"...", max_line_length) - - self._lines.append(line) - # After processing the status/request line, everything is a header. - max_line_length = self.max_field_size - - if len(self._lines) > self.max_headers: - raise BadHttpMessage("Too many headers received") - - start_pos = pos + len(SEP) - - # \r\n\r\n found - if self._lines[-1] == EMPTY: - max_trailers = self.max_headers - len(self._lines) - try: - msg: _MsgT = self.parse_message(self._lines) - finally: - self._lines.clear() - - def get_content_length() -> Optional[int]: - # payload length - length_hdr = msg.headers.get(CONTENT_LENGTH) - if length_hdr is None: - return None - - # Shouldn't allow +/- or other number formats. - # https://www.rfc-editor.org/rfc/rfc9110#section-8.6-2 - # msg.headers is already stripped of leading/trailing wsp - if not DIGITS.fullmatch(length_hdr): - raise InvalidHeader(CONTENT_LENGTH) - - return int(length_hdr) - - length = get_content_length() - # do not support old websocket spec - if SEC_WEBSOCKET_KEY1 in msg.headers: - raise InvalidHeader(SEC_WEBSOCKET_KEY1) - - self._upgraded = msg.upgrade and _is_supported_upgrade( - msg.headers - ) - - method = getattr(msg, "method", self.method) - # code is only present on responses - code = getattr(msg, "code", 0) - - assert self.protocol is not None - # calculate payload - empty_body = code in EMPTY_BODY_STATUS_CODES or bool( - method and method in EMPTY_BODY_METHODS - ) - if not empty_body and ( - ((length is not None and length > 0) or msg.chunked) - and not self._upgraded - ): - payload = StreamReader( - self.protocol, - timer=self.timer, - loop=loop, - limit=self._limit, - ) - payload_parser = HttpPayloadParser( - payload, - length=length, - chunked=msg.chunked, - method=method, - compression=msg.compression, - code=self.code, - response_with_body=self.response_with_body, - auto_decompress=self._auto_decompress, - lax=self.lax, - headers_parser=self._headers_parser, - max_line_size=self.max_line_size, - max_field_size=self.max_field_size, - max_trailers=max_trailers, - ) - if not payload_parser.done: - self._payload_parser = payload_parser - elif method == METH_CONNECT: - assert isinstance(msg, RawRequestMessage) - payload = StreamReader( - self.protocol, - timer=self.timer, - loop=loop, - limit=self._limit, - ) - self._upgraded = True - self._payload_parser = HttpPayloadParser( - payload, - method=msg.method, - compression=msg.compression, - auto_decompress=self._auto_decompress, - lax=self.lax, - headers_parser=self._headers_parser, - max_line_size=self.max_line_size, - max_field_size=self.max_field_size, - max_trailers=max_trailers, - ) - elif not empty_body and length is None and self.read_until_eof: - payload = StreamReader( - self.protocol, - timer=self.timer, - loop=loop, - limit=self._limit, - ) - payload_parser = HttpPayloadParser( - payload, - length=length, - chunked=msg.chunked, - method=method, - compression=msg.compression, - code=self.code, - response_with_body=self.response_with_body, - auto_decompress=self._auto_decompress, - lax=self.lax, - headers_parser=self._headers_parser, - max_line_size=self.max_line_size, - max_field_size=self.max_field_size, - max_trailers=max_trailers, - ) - if not payload_parser.done: - self._payload_parser = payload_parser - else: - payload = EMPTY_PAYLOAD - - messages.append((msg, payload)) - should_close = msg.should_close - else: - self._tail = data[start_pos:] - if len(self._tail) > self.max_line_size: - raise LineTooLong(self._tail[:100] + b"...", self.max_line_size) - data = EMPTY - break - - # no parser, just store - elif self._payload_parser is None and self._upgraded: - assert not self._lines - break - - # feed payload - elif data and start_pos < data_len: - assert not self._lines - assert self._payload_parser is not None - try: - eof, data = self._payload_parser.feed_data(data[start_pos:], SEP) - except BaseException as underlying_exc: - reraised_exc = underlying_exc - if self.payload_exception is not None: - reraised_exc = self.payload_exception(str(underlying_exc)) - - set_exception( - self._payload_parser.payload, - reraised_exc, - underlying_exc, - ) - - eof = True - data = b"" - if isinstance( - underlying_exc, (InvalidHeader, TransferEncodingError) - ): - raise - - if eof: - start_pos = 0 - data_len = len(data) - self._payload_parser = None - continue - else: - break - - if data and start_pos < data_len: - data = data[start_pos:] - else: - data = EMPTY - - return messages, self._upgraded, data - - def parse_headers( - self, lines: List[bytes] - ) -> Tuple[ - "CIMultiDictProxy[str]", RawHeaders, Optional[bool], Optional[str], bool, bool - ]: - """Parses RFC 5322 headers from a stream. - - Line continuations are supported. Returns list of header name - and value pairs. Header name is in upper case. - """ - headers, raw_headers = self._headers_parser.parse_headers(lines) - close_conn = None - encoding = None - upgrade = False - chunked = False - - # keep-alive and protocol switching - # RFC 9110 section 7.6.1 defines Connection as a comma-separated list. - conn_values = headers.getall(hdrs.CONNECTION, ()) - if conn_values: - conn_tokens = { - token.lower() - for conn_value in conn_values - for token in (part.strip(" \t") for part in conn_value.split(",")) - if token and token.isascii() - } - - if "close" in conn_tokens: - close_conn = True - elif "keep-alive" in conn_tokens: - close_conn = False - - # https://www.rfc-editor.org/rfc/rfc9110.html#name-101-switching-protocols - if "upgrade" in conn_tokens and headers.get(hdrs.UPGRADE): - upgrade = True - - # encoding - enc = headers.get(hdrs.CONTENT_ENCODING, "") - if enc.isascii() and enc.lower() in {"gzip", "deflate", "br", "zstd"}: - encoding = enc - - # chunking - te = headers.get(hdrs.TRANSFER_ENCODING) - if te is not None: - if self._is_chunked_te(te): - chunked = True - - if hdrs.CONTENT_LENGTH in headers: - raise BadHttpMessage( - "Transfer-Encoding can't be present with Content-Length", - ) - - return (headers, raw_headers, close_conn, encoding, upgrade, chunked) - - def set_upgraded(self, val: bool) -> None: - """Set connection upgraded (to websocket) mode. - - :param bool val: new state. - """ - self._upgraded = val - - -class HttpRequestParser(HttpParser[RawRequestMessage]): - """Read request status line. - - Exception .http_exceptions.BadStatusLine - could be raised in case of any errors in status line. - Returns RawRequestMessage. - """ - - def parse_message(self, lines: List[bytes]) -> RawRequestMessage: - # request line - line = lines[0].decode("utf-8", "surrogateescape") - try: - method, path, version = line.split(" ", maxsplit=2) - except ValueError: - raise BadHttpMethod(line) from None - - # method - if not TOKENRE.fullmatch(method): - raise BadHttpMethod(method) - - # version - match = VERSRE.fullmatch(version) - if match is None: - raise BadStatusLine(line) - version_o = HttpVersion(int(match.group(1)), int(match.group(2))) - - if method == "CONNECT": - # authority-form, - # https://datatracker.ietf.org/doc/html/rfc7230#section-5.3.3 - url = URL.build(authority=path, encoded=True) - elif path.startswith("/"): - # origin-form, - # https://datatracker.ietf.org/doc/html/rfc7230#section-5.3.1 - path_part, _hash_separator, url_fragment = path.partition("#") - path_part, _question_mark_separator, qs_part = path_part.partition("?") - - # NOTE: `yarl.URL.build()` is used to mimic what the Cython-based - # NOTE: parser does, otherwise it results into the same - # NOTE: HTTP Request-Line input producing different - # NOTE: `yarl.URL()` objects - url = URL.build( - path=path_part, - query_string=qs_part, - fragment=url_fragment, - encoded=True, - ) - elif path == "*" and method == "OPTIONS": - # asterisk-form, - url = URL(path, encoded=True) - else: - # absolute-form for proxy maybe, - # https://datatracker.ietf.org/doc/html/rfc7230#section-5.3.2 - url = URL(path, encoded=True) - if url.scheme == "": - # not absolute-form - raise InvalidURLError( - path.encode(errors="surrogateescape").decode("latin1") - ) - - # read headers - ( - headers, - raw_headers, - close, - compression, - upgrade, - chunked, - ) = self.parse_headers(lines[1:]) - - if close is None: # then the headers weren't set in the request - if version_o <= HttpVersion10: # HTTP 1.0 must asks to not close - close = True - else: # HTTP 1.1 must ask to close. - close = False - - return RawRequestMessage( - method, - path, - version_o, - headers, - raw_headers, - close, - compression, - upgrade, - chunked, - url, - ) - - def _is_chunked_te(self, te: str) -> bool: - te = te.rsplit(",", maxsplit=1)[-1].strip(" \t") - # .lower() transforms some non-ascii chars, so must check first. - if te.isascii() and te.lower() == "chunked": - return True - # https://www.rfc-editor.org/rfc/rfc9112#section-6.3-2.4.3 - raise BadHttpMessage("Request has invalid `Transfer-Encoding`") - - -class HttpResponseParser(HttpParser[RawResponseMessage]): - """Read response status line and headers. - - BadStatusLine could be raised in case of any errors in status line. - Returns RawResponseMessage. - """ - - # Lax mode should only be enabled on response parser. - lax = not DEBUG - - def feed_data( - self, - data: bytes, - SEP: Optional[_SEP] = None, - *args: Any, - **kwargs: Any, - ) -> Tuple[List[Tuple[RawResponseMessage, StreamReader]], bool, bytes]: - if SEP is None: - SEP = b"\r\n" if DEBUG else b"\n" - return super().feed_data(data, SEP, *args, **kwargs) - - def parse_message(self, lines: List[bytes]) -> RawResponseMessage: - line = lines[0].decode("utf-8", "surrogateescape") - try: - version, status = line.split(maxsplit=1) - except ValueError: - raise BadStatusLine(line) from None - - try: - status, reason = status.split(maxsplit=1) - except ValueError: - status = status.strip() - reason = "" - - # version - match = VERSRE.fullmatch(version) - if match is None: - raise BadStatusLine(line) - version_o = HttpVersion(int(match.group(1)), int(match.group(2))) - - # The status code is a three-digit ASCII number, no padding - if len(status) != 3 or not DIGITS.fullmatch(status): - raise BadStatusLine(line) - status_i = int(status) - - # read headers - ( - headers, - raw_headers, - close, - compression, - upgrade, - chunked, - ) = self.parse_headers(lines[1:]) - - if close is None: - if version_o <= HttpVersion10: - close = True - # https://www.rfc-editor.org/rfc/rfc9112.html#name-message-body-length - elif 100 <= status_i < 200 or status_i in {204, 304}: - close = False - elif hdrs.CONTENT_LENGTH in headers or hdrs.TRANSFER_ENCODING in headers: - close = False - else: - # https://www.rfc-editor.org/rfc/rfc9112.html#section-6.3-2.8 - close = True - - return RawResponseMessage( - version_o, - status_i, - reason.strip(), - headers, - raw_headers, - close, - compression, - upgrade, - chunked, - ) - - def _is_chunked_te(self, te: str) -> bool: - # https://www.rfc-editor.org/rfc/rfc9112#section-6.3-2.4.2 - return te.rsplit(",", maxsplit=1)[-1].strip(" \t").lower() == "chunked" - - -class HttpPayloadParser: - def __init__( - self, - payload: StreamReader, - length: Optional[int] = None, - chunked: bool = False, - compression: Optional[str] = None, - code: Optional[int] = None, - method: Optional[str] = None, - response_with_body: bool = True, - auto_decompress: bool = True, - lax: bool = False, - *, - headers_parser: HeadersParser, - max_line_size: int = 8190, - max_field_size: int = 8190, - max_trailers: int = 128, - ) -> None: - self._length = 0 - self._type = ParseState.PARSE_UNTIL_EOF - self._chunk = ChunkState.PARSE_CHUNKED_SIZE - self._chunk_size = 0 - self._chunk_tail = b"" - self._auto_decompress = auto_decompress - self._lax = lax - self._headers_parser = headers_parser - self._max_line_size = max_line_size - self._max_field_size = max_field_size - self._max_trailers = max_trailers - self._trailer_lines: list[bytes] = [] - self.done = False - - # payload decompression wrapper - if response_with_body and compression and self._auto_decompress: - real_payload: Union[StreamReader, DeflateBuffer] = DeflateBuffer( - payload, compression - ) - else: - real_payload = payload - - # payload parser - if not response_with_body: - # don't parse payload if it's not expected to be received - self._type = ParseState.PARSE_NONE - real_payload.feed_eof() - self.done = True - elif chunked: - self._type = ParseState.PARSE_CHUNKED - elif length is not None: - self._type = ParseState.PARSE_LENGTH - self._length = length - if self._length == 0: - real_payload.feed_eof() - self.done = True - - self.payload = real_payload - - def feed_eof(self) -> None: - if self._type == ParseState.PARSE_UNTIL_EOF: - self.payload.feed_eof() - elif self._type == ParseState.PARSE_LENGTH: - raise ContentLengthError( - "Not enough data to satisfy content length header." - ) - elif self._type == ParseState.PARSE_CHUNKED: - raise TransferEncodingError( - "Not enough data to satisfy transfer length header." - ) - - def feed_data( - self, chunk: bytes, SEP: _SEP = b"\r\n", CHUNK_EXT: bytes = b";" - ) -> Tuple[bool, bytes]: - # Read specified amount of bytes - if self._type == ParseState.PARSE_LENGTH: - required = self._length - chunk_len = len(chunk) - - if required >= chunk_len: - self._length = required - chunk_len - self.payload.feed_data(chunk, chunk_len) - if self._length == 0: - self.payload.feed_eof() - return True, b"" - else: - self._length = 0 - self.payload.feed_data(chunk[:required], required) - self.payload.feed_eof() - return True, chunk[required:] - - # Chunked transfer encoding parser - elif self._type == ParseState.PARSE_CHUNKED: - if self._chunk_tail: - # We should never have a tail if we're inside the payload body. - assert self._chunk != ChunkState.PARSE_CHUNKED_CHUNK - # We should check the length is sane. - max_line_length = self._max_line_size - if self._chunk == ChunkState.PARSE_TRAILERS: - max_line_length = self._max_field_size - if len(self._chunk_tail) > max_line_length: - raise LineTooLong(self._chunk_tail[:100] + b"...", max_line_length) - - chunk = self._chunk_tail + chunk - self._chunk_tail = b"" - - while chunk: - - # read next chunk size - if self._chunk == ChunkState.PARSE_CHUNKED_SIZE: - pos = chunk.find(SEP) - if pos >= 0: - i = chunk.find(CHUNK_EXT, 0, pos) - if i >= 0: - size_b = chunk[:i] # strip chunk-extensions - # Verify no LF in the chunk-extension - if b"\n" in (ext := chunk[i:pos]): - exc = TransferEncodingError( - f"Unexpected LF in chunk-extension: {ext!r}" - ) - set_exception(self.payload, exc) - raise exc - else: - size_b = chunk[:pos] - - if self._lax: # Allow whitespace in lax mode. - size_b = size_b.strip() - - if not re.fullmatch(HEXDIGITS, size_b): - exc = TransferEncodingError( - chunk[:pos].decode("ascii", "surrogateescape") - ) - set_exception(self.payload, exc) - raise exc - size = int(bytes(size_b), 16) - - chunk = chunk[pos + len(SEP) :] - if size == 0: # eof marker - self._chunk = ChunkState.PARSE_TRAILERS - if self._lax and chunk.startswith(b"\r"): - chunk = chunk[1:] - else: - self._chunk = ChunkState.PARSE_CHUNKED_CHUNK - self._chunk_size = size - self.payload.begin_http_chunk_receiving() - else: - self._chunk_tail = chunk - return False, b"" - - # read chunk and feed buffer - if self._chunk == ChunkState.PARSE_CHUNKED_CHUNK: - required = self._chunk_size - chunk_len = len(chunk) - - if required > chunk_len: - self._chunk_size = required - chunk_len - self.payload.feed_data(chunk, chunk_len) - return False, b"" - else: - self._chunk_size = 0 - self.payload.feed_data(chunk[:required], required) - chunk = chunk[required:] - self._chunk = ChunkState.PARSE_CHUNKED_CHUNK_EOF - self.payload.end_http_chunk_receiving() - - # toss the CRLF at the end of the chunk - if self._chunk == ChunkState.PARSE_CHUNKED_CHUNK_EOF: - if self._lax and chunk.startswith(b"\r"): - chunk = chunk[1:] - if chunk[: len(SEP)] == SEP: - chunk = chunk[len(SEP) :] - self._chunk = ChunkState.PARSE_CHUNKED_SIZE - elif len(chunk) >= len(SEP) or chunk != SEP[: len(chunk)]: - exc = TransferEncodingError( - "Chunk size mismatch: expected CRLF after chunk data" - ) - set_exception(self.payload, exc) - raise exc - else: - self._chunk_tail = chunk - return False, b"" - - if self._chunk == ChunkState.PARSE_TRAILERS: - pos = chunk.find(SEP) - if pos < 0: # No line found - self._chunk_tail = chunk - return False, b"" - - line = chunk[:pos] - chunk = chunk[pos + len(SEP) :] - if SEP == b"\n": # For lax response parsing - line = line.rstrip(b"\r") - - if len(line) > self._max_field_size: - raise LineTooLong(line[:100] + b"...", self._max_field_size) - - self._trailer_lines.append(line) - - if len(self._trailer_lines) > self._max_trailers: - raise BadHttpMessage("Too many trailers received") - - # \r\n\r\n found, end of stream - if self._trailer_lines[-1] == b"": - # Headers and trailers are defined the same way, - # so we reuse the HeadersParser here. - try: - trailers, raw_trailers = self._headers_parser.parse_headers( - self._trailer_lines - ) - finally: - self._trailer_lines.clear() - self.payload.feed_eof() - return True, chunk - - # Read all bytes until eof - elif self._type == ParseState.PARSE_UNTIL_EOF: - self.payload.feed_data(chunk, len(chunk)) - - return False, b"" - - -class DeflateBuffer: - """DeflateStream decompress stream and feed data into specified stream.""" - - decompressor: Any - - def __init__( - self, - out: StreamReader, - encoding: Optional[str], - max_decompress_size: int = DEFAULT_MAX_DECOMPRESS_SIZE, - ) -> None: - self.out = out - self.size = 0 - out.total_compressed_bytes = self.size - self.encoding = encoding - self._started_decoding = False - - self.decompressor: Union[BrotliDecompressor, ZLibDecompressor, ZSTDDecompressor] - if encoding == "br": - if not HAS_BROTLI: # pragma: no cover - raise ContentEncodingError( - "Can not decode content-encoding: brotli (br). " - "Please install `Brotli`" - ) - self.decompressor = BrotliDecompressor() - elif encoding == "zstd": - if not HAS_ZSTD: - raise ContentEncodingError( - "Can not decode content-encoding: zstandard (zstd). " - "Please install `backports.zstd`" - ) - self.decompressor = ZSTDDecompressor() - else: - self.decompressor = ZLibDecompressor(encoding=encoding) - - self._max_decompress_size = max_decompress_size - - def set_exception( - self, - exc: BaseException, - exc_cause: BaseException = _EXC_SENTINEL, - ) -> None: - set_exception(self.out, exc, exc_cause) - - def feed_data(self, chunk: bytes, size: int) -> None: - if not size: - return - - self.size += size - self.out.total_compressed_bytes = self.size - - # RFC1950 - # bits 0..3 = CM = 0b1000 = 8 = "deflate" - # bits 4..7 = CINFO = 1..7 = windows size. - if ( - not self._started_decoding - and self.encoding == "deflate" - and chunk[0] & 0xF != 8 - ): - # Change the decoder to decompress incorrectly compressed data - # Actually we should issue a warning about non-RFC-compliant data. - self.decompressor = ZLibDecompressor( - encoding=self.encoding, suppress_deflate_header=True - ) - - try: - # Decompress with limit + 1 so we can detect if output exceeds limit - chunk = self.decompressor.decompress_sync( - chunk, max_length=self._max_decompress_size + 1 - ) - except Exception: - raise ContentEncodingError( - "Can not decode content-encoding: %s" % self.encoding - ) - - self._started_decoding = True - - # Check if decompression limit was exceeded - if len(chunk) > self._max_decompress_size: - raise DecompressSizeError( - "Decompressed data exceeds the configured limit of %d bytes" - % self._max_decompress_size - ) - - if chunk: - self.out.feed_data(chunk, len(chunk)) - - def feed_eof(self) -> None: - chunk = self.decompressor.flush() - - if chunk or self.size > 0: - self.out.feed_data(chunk, len(chunk)) - if self.encoding == "deflate" and not self.decompressor.eof: - raise ContentEncodingError("deflate") - - self.out.feed_eof() - - def begin_http_chunk_receiving(self) -> None: - self.out.begin_http_chunk_receiving() - - def end_http_chunk_receiving(self) -> None: - self.out.end_http_chunk_receiving() - - -HttpRequestParserPy = HttpRequestParser -HttpResponseParserPy = HttpResponseParser -RawRequestMessagePy = RawRequestMessage -RawResponseMessagePy = RawResponseMessage - -try: - if not NO_EXTENSIONS: - from ._http_parser import ( # type: ignore[import-not-found,no-redef] - HttpRequestParser, - HttpResponseParser, - RawRequestMessage, - RawResponseMessage, - ) - - HttpRequestParserC = HttpRequestParser - HttpResponseParserC = HttpResponseParser - RawRequestMessageC = RawRequestMessage - RawResponseMessageC = RawResponseMessage -except ImportError: # pragma: no cover - pass diff --git a/venv/lib/python3.9/site-packages/aiohttp/http_websocket.py b/venv/lib/python3.9/site-packages/aiohttp/http_websocket.py deleted file mode 100644 index 6b4b30e..0000000 --- a/venv/lib/python3.9/site-packages/aiohttp/http_websocket.py +++ /dev/null @@ -1,36 +0,0 @@ -"""WebSocket protocol versions 13 and 8.""" - -from ._websocket.helpers import WS_KEY, ws_ext_gen, ws_ext_parse -from ._websocket.models import ( - WS_CLOSED_MESSAGE, - WS_CLOSING_MESSAGE, - WebSocketError, - WSCloseCode, - WSHandshakeError, - WSMessage, - WSMsgType, -) -from ._websocket.reader import WebSocketReader -from ._websocket.writer import WebSocketWriter - -# Messages that the WebSocketResponse.receive needs to handle internally -_INTERNAL_RECEIVE_TYPES = frozenset( - (WSMsgType.CLOSE, WSMsgType.CLOSING, WSMsgType.PING, WSMsgType.PONG) -) - - -__all__ = ( - "WS_CLOSED_MESSAGE", - "WS_CLOSING_MESSAGE", - "WS_KEY", - "WebSocketReader", - "WebSocketWriter", - "WSMessage", - "WebSocketError", - "WSMsgType", - "WSCloseCode", - "ws_ext_gen", - "ws_ext_parse", - "WSHandshakeError", - "WSMessage", -) diff --git a/venv/lib/python3.9/site-packages/aiohttp/http_writer.py b/venv/lib/python3.9/site-packages/aiohttp/http_writer.py deleted file mode 100644 index 8c1c910..0000000 --- a/venv/lib/python3.9/site-packages/aiohttp/http_writer.py +++ /dev/null @@ -1,379 +0,0 @@ -"""Http related parsers and protocol.""" - -import asyncio -import sys -from typing import ( # noqa - TYPE_CHECKING, - Any, - Awaitable, - Callable, - Iterable, - List, - NamedTuple, - Optional, - Union, -) - -from multidict import CIMultiDict - -from .abc import AbstractStreamWriter -from .base_protocol import BaseProtocol -from .client_exceptions import ClientConnectionResetError -from .compression_utils import ZLibCompressor -from .helpers import NO_EXTENSIONS - -__all__ = ("StreamWriter", "HttpVersion", "HttpVersion10", "HttpVersion11") - - -MIN_PAYLOAD_FOR_WRITELINES = 2048 -IS_PY313_BEFORE_313_2 = (3, 13, 0) <= sys.version_info < (3, 13, 2) -IS_PY_BEFORE_312_9 = sys.version_info < (3, 12, 9) -SKIP_WRITELINES = IS_PY313_BEFORE_313_2 or IS_PY_BEFORE_312_9 -# writelines is not safe for use -# on Python 3.12+ until 3.12.9 -# on Python 3.13+ until 3.13.2 -# and on older versions it not any faster than write -# CVE-2024-12254: https://github.com/python/cpython/pull/127656 - - -class HttpVersion(NamedTuple): - major: int - minor: int - - -HttpVersion10 = HttpVersion(1, 0) -HttpVersion11 = HttpVersion(1, 1) - - -_T_OnChunkSent = Optional[Callable[[bytes], Awaitable[None]]] -_T_OnHeadersSent = Optional[Callable[["CIMultiDict[str]"], Awaitable[None]]] - - -class StreamWriter(AbstractStreamWriter): - - length: Optional[int] = None - chunked: bool = False - _eof: bool = False - _compress: Optional[ZLibCompressor] = None - - def __init__( - self, - protocol: BaseProtocol, - loop: asyncio.AbstractEventLoop, - on_chunk_sent: _T_OnChunkSent = None, - on_headers_sent: _T_OnHeadersSent = None, - ) -> None: - self._protocol = protocol - self.loop = loop - self._on_chunk_sent: _T_OnChunkSent = on_chunk_sent - self._on_headers_sent: _T_OnHeadersSent = on_headers_sent - self._headers_buf: Optional[bytes] = None - self._headers_written: bool = False - - @property - def transport(self) -> Optional[asyncio.Transport]: - return self._protocol.transport - - @property - def protocol(self) -> BaseProtocol: - return self._protocol - - def enable_chunking(self) -> None: - self.chunked = True - - def enable_compression( - self, encoding: str = "deflate", strategy: Optional[int] = None - ) -> None: - self._compress = ZLibCompressor(encoding=encoding, strategy=strategy) - - def _write(self, chunk: Union[bytes, bytearray, memoryview]) -> None: - size = len(chunk) - self.buffer_size += size - self.output_size += size - transport = self._protocol.transport - if transport is None or transport.is_closing(): - raise ClientConnectionResetError("Cannot write to closing transport") - transport.write(chunk) - - def _writelines(self, chunks: Iterable[bytes]) -> None: - size = 0 - for chunk in chunks: - size += len(chunk) - self.buffer_size += size - self.output_size += size - transport = self._protocol.transport - if transport is None or transport.is_closing(): - raise ClientConnectionResetError("Cannot write to closing transport") - if SKIP_WRITELINES or size < MIN_PAYLOAD_FOR_WRITELINES: - transport.write(b"".join(chunks)) - else: - transport.writelines(chunks) - - def _write_chunked_payload( - self, chunk: Union[bytes, bytearray, "memoryview[int]", "memoryview[bytes]"] - ) -> None: - """Write a chunk with proper chunked encoding.""" - chunk_len_pre = f"{len(chunk):x}\r\n".encode("ascii") - self._writelines((chunk_len_pre, chunk, b"\r\n")) - - def _send_headers_with_payload( - self, - chunk: Union[bytes, bytearray, "memoryview[int]", "memoryview[bytes]"], - is_eof: bool, - ) -> None: - """Send buffered headers with payload, coalescing into single write.""" - # Mark headers as written - self._headers_written = True - headers_buf = self._headers_buf - self._headers_buf = None - - if TYPE_CHECKING: - # Safe because callers (write() and write_eof()) only invoke this method - # after checking that self._headers_buf is truthy - assert headers_buf is not None - - if not self.chunked: - # Non-chunked: coalesce headers with body - if chunk: - self._writelines((headers_buf, chunk)) - else: - self._write(headers_buf) - return - - # Coalesce headers with chunked data - if chunk: - chunk_len_pre = f"{len(chunk):x}\r\n".encode("ascii") - if is_eof: - self._writelines((headers_buf, chunk_len_pre, chunk, b"\r\n0\r\n\r\n")) - else: - self._writelines((headers_buf, chunk_len_pre, chunk, b"\r\n")) - elif is_eof: - self._writelines((headers_buf, b"0\r\n\r\n")) - else: - self._write(headers_buf) - - async def write( - self, - chunk: Union[bytes, bytearray, memoryview], - *, - drain: bool = True, - LIMIT: int = 0x10000, - ) -> None: - """ - Writes chunk of data to a stream. - - write_eof() indicates end of stream. - writer can't be used after write_eof() method being called. - write() return drain future. - """ - if self._on_chunk_sent is not None: - await self._on_chunk_sent(chunk) - - if isinstance(chunk, memoryview): - if chunk.nbytes != len(chunk): - # just reshape it - chunk = chunk.cast("c") - - if self._compress is not None: - chunk = await self._compress.compress(chunk) - if not chunk: - return - - if self.length is not None: - chunk_len = len(chunk) - if self.length >= chunk_len: - self.length = self.length - chunk_len - else: - chunk = chunk[: self.length] - self.length = 0 - if not chunk: - return - - # Handle buffered headers for small payload optimization - if self._headers_buf and not self._headers_written: - self._send_headers_with_payload(chunk, False) - if drain and self.buffer_size > LIMIT: - self.buffer_size = 0 - await self.drain() - return - - if chunk: - if self.chunked: - self._write_chunked_payload(chunk) - else: - self._write(chunk) - - if drain and self.buffer_size > LIMIT: - self.buffer_size = 0 - await self.drain() - - async def write_headers( - self, status_line: str, headers: "CIMultiDict[str]" - ) -> None: - """Write headers to the stream.""" - if self._on_headers_sent is not None: - await self._on_headers_sent(headers) - # status + headers - buf = _serialize_headers(status_line, headers) - self._headers_written = False - self._headers_buf = buf - - def send_headers(self) -> None: - """Force sending buffered headers if not already sent.""" - if not self._headers_buf or self._headers_written: - return - - self._headers_written = True - headers_buf = self._headers_buf - self._headers_buf = None - - if TYPE_CHECKING: - # Safe because we only enter this block when self._headers_buf is truthy - assert headers_buf is not None - - self._write(headers_buf) - - def set_eof(self) -> None: - """Indicate that the message is complete.""" - if self._eof: - return - - # If headers haven't been sent yet, send them now - # This handles the case where there's no body at all - if self._headers_buf and not self._headers_written: - self._headers_written = True - headers_buf = self._headers_buf - self._headers_buf = None - - if TYPE_CHECKING: - # Safe because we only enter this block when self._headers_buf is truthy - assert headers_buf is not None - - # Combine headers and chunked EOF marker in a single write - if self.chunked: - self._writelines((headers_buf, b"0\r\n\r\n")) - else: - self._write(headers_buf) - elif self.chunked and self._headers_written: - # Headers already sent, just send the final chunk marker - self._write(b"0\r\n\r\n") - - self._eof = True - - async def write_eof(self, chunk: bytes = b"") -> None: - if self._eof: - return - - if chunk and self._on_chunk_sent is not None: - await self._on_chunk_sent(chunk) - - # Handle body/compression - if self._compress: - chunks: List[bytes] = [] - chunks_len = 0 - if chunk and (compressed_chunk := await self._compress.compress(chunk)): - chunks_len = len(compressed_chunk) - chunks.append(compressed_chunk) - - flush_chunk = self._compress.flush() - chunks_len += len(flush_chunk) - chunks.append(flush_chunk) - assert chunks_len - - # Send buffered headers with compressed data if not yet sent - if self._headers_buf and not self._headers_written: - self._headers_written = True - headers_buf = self._headers_buf - self._headers_buf = None - - if self.chunked: - # Coalesce headers with compressed chunked data - chunk_len_pre = f"{chunks_len:x}\r\n".encode("ascii") - self._writelines( - (headers_buf, chunk_len_pre, *chunks, b"\r\n0\r\n\r\n") - ) - else: - # Coalesce headers with compressed data - self._writelines((headers_buf, *chunks)) - await self.drain() - self._eof = True - return - - # Headers already sent, just write compressed data - if self.chunked: - chunk_len_pre = f"{chunks_len:x}\r\n".encode("ascii") - self._writelines((chunk_len_pre, *chunks, b"\r\n0\r\n\r\n")) - elif len(chunks) > 1: - self._writelines(chunks) - else: - self._write(chunks[0]) - await self.drain() - self._eof = True - return - - # No compression - send buffered headers if not yet sent - if self._headers_buf and not self._headers_written: - # Use helper to send headers with payload - self._send_headers_with_payload(chunk, True) - await self.drain() - self._eof = True - return - - # Handle remaining body - if self.chunked: - if chunk: - # Write final chunk with EOF marker - self._writelines( - (f"{len(chunk):x}\r\n".encode("ascii"), chunk, b"\r\n0\r\n\r\n") - ) - else: - self._write(b"0\r\n\r\n") - await self.drain() - self._eof = True - return - - if chunk: - self._write(chunk) - await self.drain() - - self._eof = True - - async def drain(self) -> None: - """Flush the write buffer. - - The intended use is to write - - await w.write(data) - await w.drain() - """ - protocol = self._protocol - if protocol.transport is not None and protocol._paused: - await protocol._drain_helper() - - -def _safe_header(string: str) -> str: - if "\r" in string or "\n" in string or "\x00" in string: - raise ValueError( - "Newline, carriage return, or null byte detected in headers. " - "Potential header injection attack." - ) - return string - - -def _py_serialize_headers(status_line: str, headers: "CIMultiDict[str]") -> bytes: - _safe_header(status_line) - headers_gen = (_safe_header(k) + ": " + _safe_header(v) for k, v in headers.items()) - line = status_line + "\r\n" + "\r\n".join(headers_gen) + "\r\n\r\n" - return line.encode("utf-8") - - -_serialize_headers = _py_serialize_headers - -try: - import aiohttp._http_writer as _http_writer # type: ignore[import-not-found] - - _c_serialize_headers = _http_writer._serialize_headers - if not NO_EXTENSIONS: - _serialize_headers = _c_serialize_headers -except ImportError: - pass diff --git a/venv/lib/python3.9/site-packages/aiohttp/log.py b/venv/lib/python3.9/site-packages/aiohttp/log.py deleted file mode 100644 index 3cecea2..0000000 --- a/venv/lib/python3.9/site-packages/aiohttp/log.py +++ /dev/null @@ -1,8 +0,0 @@ -import logging - -access_logger = logging.getLogger("aiohttp.access") -client_logger = logging.getLogger("aiohttp.client") -internal_logger = logging.getLogger("aiohttp.internal") -server_logger = logging.getLogger("aiohttp.server") -web_logger = logging.getLogger("aiohttp.web") -ws_logger = logging.getLogger("aiohttp.websocket") diff --git a/venv/lib/python3.9/site-packages/aiohttp/multipart.py b/venv/lib/python3.9/site-packages/aiohttp/multipart.py deleted file mode 100644 index ec8b82b..0000000 --- a/venv/lib/python3.9/site-packages/aiohttp/multipart.py +++ /dev/null @@ -1,1213 +0,0 @@ -import base64 -import binascii -import json -import re -import sys -import uuid -import warnings -from collections import deque -from collections.abc import Mapping, Sequence -from types import TracebackType -from typing import ( - TYPE_CHECKING, - Any, - AsyncIterator, - Deque, - Dict, - Iterator, - List, - Optional, - Tuple, - Type, - Union, - cast, -) -from urllib.parse import parse_qsl, unquote, urlencode - -from multidict import CIMultiDict, CIMultiDictProxy - -from .abc import AbstractStreamWriter -from .compression_utils import ( - DEFAULT_MAX_DECOMPRESS_SIZE, - ZLibCompressor, - ZLibDecompressor, -) -from .hdrs import ( - CONTENT_DISPOSITION, - CONTENT_ENCODING, - CONTENT_LENGTH, - CONTENT_TRANSFER_ENCODING, - CONTENT_TYPE, -) -from .helpers import CHAR, TOKEN, parse_mimetype, reify -from .http import HeadersParser -from .http_exceptions import BadHttpMessage -from .log import internal_logger -from .payload import ( - JsonPayload, - LookupError, - Order, - Payload, - StringPayload, - get_payload, - payload_type, -) -from .streams import StreamReader - -if sys.version_info >= (3, 11): - from typing import Self -else: - from typing import TypeVar - - Self = TypeVar("Self", bound="BodyPartReader") - -__all__ = ( - "MultipartReader", - "MultipartWriter", - "BodyPartReader", - "BadContentDispositionHeader", - "BadContentDispositionParam", - "parse_content_disposition", - "content_disposition_filename", -) - - -if TYPE_CHECKING: - from .client_reqrep import ClientResponse - - -class BadContentDispositionHeader(RuntimeWarning): - pass - - -class BadContentDispositionParam(RuntimeWarning): - pass - - -def parse_content_disposition( - header: Optional[str], -) -> Tuple[Optional[str], Dict[str, str]]: - def is_token(string: str) -> bool: - return bool(string) and TOKEN >= set(string) - - def is_quoted(string: str) -> bool: - return string[0] == string[-1] == '"' - - def is_rfc5987(string: str) -> bool: - return is_token(string) and string.count("'") == 2 - - def is_extended_param(string: str) -> bool: - return string.endswith("*") - - def is_continuous_param(string: str) -> bool: - pos = string.find("*") + 1 - if not pos: - return False - substring = string[pos:-1] if string.endswith("*") else string[pos:] - return substring.isdigit() - - def unescape(text: str, *, chars: str = "".join(map(re.escape, CHAR))) -> str: - return re.sub(f"\\\\([{chars}])", "\\1", text) - - if not header: - return None, {} - - disptype, *parts = header.split(";") - if not is_token(disptype): - warnings.warn(BadContentDispositionHeader(header)) - return None, {} - - params: Dict[str, str] = {} - while parts: - item = parts.pop(0) - - if not item: # To handle trailing semicolons - warnings.warn(BadContentDispositionHeader(header)) - continue - - if "=" not in item: - warnings.warn(BadContentDispositionHeader(header)) - return None, {} - - key, value = item.split("=", 1) - key = key.lower().strip() - value = value.lstrip() - - if key in params: - warnings.warn(BadContentDispositionHeader(header)) - return None, {} - - if not is_token(key): - warnings.warn(BadContentDispositionParam(item)) - continue - - elif is_continuous_param(key): - if is_quoted(value): - value = unescape(value[1:-1]) - elif not is_token(value): - warnings.warn(BadContentDispositionParam(item)) - continue - - elif is_extended_param(key): - if is_rfc5987(value): - encoding, _, value = value.split("'", 2) - encoding = encoding or "utf-8" - else: - warnings.warn(BadContentDispositionParam(item)) - continue - - try: - value = unquote(value, encoding, "strict") - except UnicodeDecodeError: # pragma: nocover - warnings.warn(BadContentDispositionParam(item)) - continue - - else: - failed = True - if is_quoted(value): - failed = False - value = unescape(value[1:-1].lstrip("\\/")) - elif is_token(value): - failed = False - elif parts: - # maybe just ; in filename, in any case this is just - # one case fix, for proper fix we need to redesign parser - _value = f"{value};{parts[0]}" - if is_quoted(_value): - parts.pop(0) - value = unescape(_value[1:-1].lstrip("\\/")) - failed = False - - if failed: - warnings.warn(BadContentDispositionHeader(header)) - return None, {} - - params[key] = value - - return disptype.lower(), params - - -def content_disposition_filename( - params: Mapping[str, str], name: str = "filename" -) -> Optional[str]: - name_suf = "%s*" % name - if not params: - return None - elif name_suf in params: - return params[name_suf] - elif name in params: - return params[name] - else: - parts = [] - fnparams = sorted( - (key, value) for key, value in params.items() if key.startswith(name_suf) - ) - for num, (key, value) in enumerate(fnparams): - _, tail = key.split("*", 1) - if tail.endswith("*"): - tail = tail[:-1] - if tail == str(num): - parts.append(value) - else: - break - if not parts: - return None - value = "".join(parts) - if "'" in value: - encoding, _, value = value.split("'", 2) - encoding = encoding or "utf-8" - return unquote(value, encoding, "strict") - return value - - -class MultipartResponseWrapper: - """Wrapper around the MultipartReader. - - It takes care about - underlying connection and close it when it needs in. - """ - - def __init__( - self, - resp: "ClientResponse", - stream: "MultipartReader", - ) -> None: - self.resp = resp - self.stream = stream - - def __aiter__(self) -> "MultipartResponseWrapper": - return self - - async def __anext__( - self, - ) -> Union["MultipartReader", "BodyPartReader"]: - part = await self.next() - if part is None: - raise StopAsyncIteration - return part - - def at_eof(self) -> bool: - """Returns True when all response data had been read.""" - return self.resp.content.at_eof() - - async def next( - self, - ) -> Optional[Union["MultipartReader", "BodyPartReader"]]: - """Emits next multipart reader object.""" - item = await self.stream.next() - if self.stream.at_eof(): - await self.release() - return item - - async def release(self) -> None: - """Release the connection gracefully. - - All remaining content is read to the void. - """ - await self.resp.release() - - -class BodyPartReader: - """Multipart reader for single body part.""" - - chunk_size = 8192 - - def __init__( - self, - boundary: bytes, - headers: "CIMultiDictProxy[str]", - content: StreamReader, - *, - subtype: str = "mixed", - default_charset: Optional[str] = None, - max_decompress_size: int = DEFAULT_MAX_DECOMPRESS_SIZE, - ) -> None: - self.headers = headers - self._boundary = boundary - self._boundary_len = len(boundary) + 2 # Boundary + \r\n - self._content = content - self._default_charset = default_charset - self._at_eof = False - self._is_form_data = subtype == "form-data" - # https://datatracker.ietf.org/doc/html/rfc7578#section-4.8 - length = None if self._is_form_data else self.headers.get(CONTENT_LENGTH, None) - self._length = int(length) if length is not None else None - self._read_bytes = 0 - self._unread: Deque[bytes] = deque() - self._prev_chunk: Optional[bytes] = None - self._content_eof = 0 - self._cache: Dict[str, Any] = {} - self._max_decompress_size = max_decompress_size - - def __aiter__(self: Self) -> Self: - return self - - async def __anext__(self) -> bytes: - part = await self.next() - if part is None: - raise StopAsyncIteration - return part - - async def next(self) -> Optional[bytes]: - item = await self.read() - if not item: - return None - return item - - async def read(self, *, decode: bool = False) -> bytes: - """Reads body part data. - - decode: Decodes data following by encoding - method from Content-Encoding header. If it missed - data remains untouched - """ - if self._at_eof: - return b"" - data = bytearray() - while not self._at_eof: - data.extend(await self.read_chunk(self.chunk_size)) - if decode: - decoded_data = bytearray() - async for d in self.decode_iter(data): - decoded_data.extend(d) - return decoded_data - return data - - async def read_chunk(self, size: int = chunk_size) -> bytes: - """Reads body part content chunk of the specified size. - - size: chunk size - """ - if self._at_eof: - return b"" - if self._length: - chunk = await self._read_chunk_from_length(size) - else: - chunk = await self._read_chunk_from_stream(size) - - # For the case of base64 data, we must read a fragment of size with a - # remainder of 0 by dividing by 4 for string without symbols \n or \r - encoding = self.headers.get(CONTENT_TRANSFER_ENCODING) - if encoding and encoding.lower() == "base64": - stripped_chunk = b"".join(chunk.split()) - remainder = len(stripped_chunk) % 4 - - while remainder != 0 and not self.at_eof(): - over_chunk_size = 4 - remainder - over_chunk = b"" - - if self._prev_chunk: - over_chunk = self._prev_chunk[:over_chunk_size] - self._prev_chunk = self._prev_chunk[len(over_chunk) :] - - if len(over_chunk) != over_chunk_size: - over_chunk += await self._content.read(4 - len(over_chunk)) - - if not over_chunk: - self._at_eof = True - - stripped_chunk += b"".join(over_chunk.split()) - chunk += over_chunk - remainder = len(stripped_chunk) % 4 - - self._read_bytes += len(chunk) - if self._read_bytes == self._length: - self._at_eof = True - if self._at_eof and await self._content.readline() != b"\r\n": - raise ValueError("Reader did not read all the data or it is malformed") - return chunk - - async def _read_chunk_from_length(self, size: int) -> bytes: - # Reads body part content chunk of the specified size. - # The body part must has Content-Length header with proper value. - assert self._length is not None, "Content-Length required for chunked read" - chunk_size = min(size, self._length - self._read_bytes) - chunk = await self._content.read(chunk_size) - if self._content.at_eof(): - self._at_eof = True - return chunk - - async def _read_chunk_from_stream(self, size: int) -> bytes: - # Reads content chunk of body part with unknown length. - # The Content-Length header for body part is not necessary. - assert ( - size >= self._boundary_len - ), "Chunk size must be greater or equal than boundary length + 2" - first_chunk = self._prev_chunk is None - if first_chunk: - # We need to re-add the CRLF that got removed from headers parsing. - self._prev_chunk = b"\r\n" + await self._content.read(size) - - chunk = b"" - # content.read() may return less than size, so we need to loop to ensure - # we have enough data to detect the boundary. - while len(chunk) < self._boundary_len: - chunk += await self._content.read(size) - self._content_eof += int(self._content.at_eof()) - if self._content_eof > 2: - raise ValueError("Reading after EOF") - if self._content_eof: - break - if len(chunk) > size: - self._content.unread_data(chunk[size:]) - chunk = chunk[:size] - - assert self._prev_chunk is not None - window = self._prev_chunk + chunk - sub = b"\r\n" + self._boundary - if first_chunk: - idx = window.find(sub) - else: - idx = window.find(sub, max(0, len(self._prev_chunk) - len(sub))) - if idx >= 0: - # pushing boundary back to content - with warnings.catch_warnings(): - warnings.filterwarnings("ignore", category=DeprecationWarning) - self._content.unread_data(window[idx:]) - self._prev_chunk = self._prev_chunk[:idx] - chunk = window[len(self._prev_chunk) : idx] - if not chunk: - self._at_eof = True - result = self._prev_chunk[2 if first_chunk else 0 :] # Strip initial CRLF - self._prev_chunk = chunk - return result - - async def readline(self) -> bytes: - """Reads body part by line by line.""" - if self._at_eof: - return b"" - - if self._unread: - line = self._unread.popleft() - else: - line = await self._content.readline() - - if line.startswith(self._boundary): - # the very last boundary may not come with \r\n, - # so set single rules for everyone - sline = line.rstrip(b"\r\n") - boundary = self._boundary - last_boundary = self._boundary + b"--" - # ensure that we read exactly the boundary, not something alike - if sline == boundary or sline == last_boundary: - self._at_eof = True - self._unread.append(line) - return b"" - else: - next_line = await self._content.readline() - if next_line.startswith(self._boundary): - line = line[:-2] # strip CRLF but only once - self._unread.append(next_line) - - return line - - async def release(self) -> None: - """Like read(), but reads all the data to the void.""" - if self._at_eof: - return - while not self._at_eof: - await self.read_chunk(self.chunk_size) - - async def text(self, *, encoding: Optional[str] = None) -> str: - """Like read(), but assumes that body part contains text data.""" - data = await self.read(decode=True) - # see https://www.w3.org/TR/html5/forms.html#multipart/form-data-encoding-algorithm - # and https://dvcs.w3.org/hg/xhr/raw-file/tip/Overview.html#dom-xmlhttprequest-send - encoding = encoding or self.get_charset(default="utf-8") - return data.decode(encoding) - - async def json(self, *, encoding: Optional[str] = None) -> Optional[Dict[str, Any]]: - """Like read(), but assumes that body parts contains JSON data.""" - data = await self.read(decode=True) - if not data: - return None - encoding = encoding or self.get_charset(default="utf-8") - return cast(Dict[str, Any], json.loads(data.decode(encoding))) - - async def form(self, *, encoding: Optional[str] = None) -> List[Tuple[str, str]]: - """Like read(), but assumes that body parts contain form urlencoded data.""" - data = await self.read(decode=True) - if not data: - return [] - if encoding is not None: - real_encoding = encoding - else: - real_encoding = self.get_charset(default="utf-8") - try: - decoded_data = data.rstrip().decode(real_encoding) - except UnicodeDecodeError: - raise ValueError("data cannot be decoded with %s encoding" % real_encoding) - - return parse_qsl( - decoded_data, - keep_blank_values=True, - encoding=real_encoding, - ) - - def at_eof(self) -> bool: - """Returns True if the boundary was reached or False otherwise.""" - return self._at_eof - - def _apply_content_transfer_decoding(self, data: bytes) -> bytes: - """Apply Content-Transfer-Encoding decoding if header is present.""" - if CONTENT_TRANSFER_ENCODING in self.headers: - return self._decode_content_transfer(data) - return data - - def _needs_content_decoding(self) -> bool: - """Check if Content-Encoding decoding should be applied.""" - # https://datatracker.ietf.org/doc/html/rfc7578#section-4.8 - return not self._is_form_data and CONTENT_ENCODING in self.headers - - def decode(self, data: bytes) -> bytes: - """Decodes data synchronously. - - Decodes data according the specified Content-Encoding - or Content-Transfer-Encoding headers value. - - Note: For large payloads, consider using decode_iter() instead - to avoid blocking the event loop during decompression. - """ - data = self._apply_content_transfer_decoding(data) - if self._needs_content_decoding(): - return self._decode_content(data) - return data - - async def decode_iter(self, data: bytes) -> AsyncIterator[bytes]: - """Async generator that yields decoded data chunks. - - Decodes data according the specified Content-Encoding - or Content-Transfer-Encoding headers value. - - This method offloads decompression to an executor for large payloads - to avoid blocking the event loop. - """ - data = self._apply_content_transfer_decoding(data) - if self._needs_content_decoding(): - async for d in self._decode_content_async(data): - yield d - else: - yield data - - def _decode_content(self, data: bytes) -> bytes: - encoding = self.headers.get(CONTENT_ENCODING, "").lower() - if encoding == "identity": - return data - if encoding in {"deflate", "gzip"}: - return ZLibDecompressor( - encoding=encoding, - suppress_deflate_header=True, - ).decompress_sync(data, max_length=self._max_decompress_size) - - raise RuntimeError(f"unknown content encoding: {encoding}") - - async def _decode_content_async(self, data: bytes) -> AsyncIterator[bytes]: - encoding = self.headers.get(CONTENT_ENCODING, "").lower() - if encoding == "identity": - yield data - elif encoding in {"deflate", "gzip"}: - d = ZLibDecompressor( - encoding=encoding, - suppress_deflate_header=True, - ) - yield await d.decompress(data, max_length=self._max_decompress_size) - else: - raise RuntimeError(f"unknown content encoding: {encoding}") - - def _decode_content_transfer(self, data: bytes) -> bytes: - encoding = self.headers.get(CONTENT_TRANSFER_ENCODING, "").lower() - - if encoding == "base64": - return base64.b64decode(data) - elif encoding == "quoted-printable": - return binascii.a2b_qp(data) - elif encoding in ("binary", "8bit", "7bit"): - return data - else: - raise RuntimeError(f"unknown content transfer encoding: {encoding}") - - def get_charset(self, default: str) -> str: - """Returns charset parameter from Content-Type header or default.""" - ctype = self.headers.get(CONTENT_TYPE, "") - mimetype = parse_mimetype(ctype) - return mimetype.parameters.get("charset", self._default_charset or default) - - @reify - def name(self) -> Optional[str]: - """Returns name specified in Content-Disposition header. - - If the header is missing or malformed, returns None. - """ - _, params = parse_content_disposition(self.headers.get(CONTENT_DISPOSITION)) - return content_disposition_filename(params, "name") - - @reify - def filename(self) -> Optional[str]: - """Returns filename specified in Content-Disposition header. - - Returns None if the header is missing or malformed. - """ - _, params = parse_content_disposition(self.headers.get(CONTENT_DISPOSITION)) - return content_disposition_filename(params, "filename") - - -@payload_type(BodyPartReader, order=Order.try_first) -class BodyPartReaderPayload(Payload): - _value: BodyPartReader - # _autoclose = False (inherited) - Streaming reader that may have resources - - def __init__(self, value: BodyPartReader, *args: Any, **kwargs: Any) -> None: - super().__init__(value, *args, **kwargs) - - params: Dict[str, str] = {} - if value.name is not None: - params["name"] = value.name - if value.filename is not None: - params["filename"] = value.filename - - if params: - self.set_content_disposition("attachment", True, **params) - - def decode(self, encoding: str = "utf-8", errors: str = "strict") -> str: - raise TypeError("Unable to decode.") - - async def as_bytes(self, encoding: str = "utf-8", errors: str = "strict") -> bytes: - """Raises TypeError as body parts should be consumed via write(). - - This is intentional: BodyPartReader payloads are designed for streaming - large data (potentially gigabytes) and must be consumed only once via - the write() method to avoid memory exhaustion. They cannot be buffered - in memory for reuse. - """ - raise TypeError("Unable to read body part as bytes. Use write() to consume.") - - async def write(self, writer: AbstractStreamWriter) -> None: - field = self._value - while chunk := await field.read_chunk(size=2**18): - async for d in field.decode_iter(chunk): - await writer.write(d) - - -class MultipartReader: - """Multipart body reader.""" - - #: Response wrapper, used when multipart readers constructs from response. - response_wrapper_cls = MultipartResponseWrapper - #: Multipart reader class, used to handle multipart/* body parts. - #: None points to type(self) - multipart_reader_cls: Optional[Type["MultipartReader"]] = None - #: Body part reader class for non multipart/* content types. - part_reader_cls = BodyPartReader - - def __init__( - self, - headers: Mapping[str, str], - content: StreamReader, - *, - max_field_size: int = 8190, - max_headers: int = 128, - ) -> None: - self._mimetype = parse_mimetype(headers[CONTENT_TYPE]) - assert self._mimetype.type == "multipart", "multipart/* content type expected" - if "boundary" not in self._mimetype.parameters: - raise ValueError( - "boundary missed for Content-Type: %s" % headers[CONTENT_TYPE] - ) - - self.headers = headers - self._boundary = ("--" + self._get_boundary()).encode() - self._content = content - self._default_charset: str | None = None - self._last_part: MultipartReader | BodyPartReader | None = None - self._max_field_size = max_field_size - self._max_headers = max_headers - self._at_eof = False - self._at_bof = True - self._unread: List[bytes] = [] - - def __aiter__(self: Self) -> Self: - return self - - async def __anext__( - self, - ) -> Optional[Union["MultipartReader", BodyPartReader]]: - part = await self.next() - if part is None: - raise StopAsyncIteration - return part - - @classmethod - def from_response( - cls, - response: "ClientResponse", - ) -> MultipartResponseWrapper: - """Constructs reader instance from HTTP response. - - :param response: :class:`~aiohttp.client.ClientResponse` instance - """ - obj = cls.response_wrapper_cls( - response, cls(response.headers, response.content) - ) - return obj - - def at_eof(self) -> bool: - """Returns True if the final boundary was reached, false otherwise.""" - return self._at_eof - - async def next( - self, - ) -> Optional[Union["MultipartReader", BodyPartReader]]: - """Emits the next multipart body part.""" - # So, if we're at BOF, we need to skip till the boundary. - if self._at_eof: - return None - await self._maybe_release_last_part() - if self._at_bof: - await self._read_until_first_boundary() - self._at_bof = False - else: - await self._read_boundary() - if self._at_eof: # we just read the last boundary, nothing to do there - return None - - part = await self.fetch_next_part() - # https://datatracker.ietf.org/doc/html/rfc7578#section-4.6 - if ( - self._last_part is None - and self._mimetype.subtype == "form-data" - and isinstance(part, BodyPartReader) - ): - _, params = parse_content_disposition(part.headers.get(CONTENT_DISPOSITION)) - if params.get("name") == "_charset_": - # Longest encoding in https://encoding.spec.whatwg.org/encodings.json - # is 19 characters, so 32 should be more than enough for any valid encoding. - charset = await part.read_chunk(32) - if len(charset) > 31: - raise RuntimeError("Invalid default charset") - self._default_charset = charset.strip().decode() - part = await self.fetch_next_part() - self._last_part = part - return self._last_part - - async def release(self) -> None: - """Reads all the body parts to the void till the final boundary.""" - while not self._at_eof: - item = await self.next() - if item is None: - break - await item.release() - - async def fetch_next_part( - self, - ) -> Union["MultipartReader", BodyPartReader]: - """Returns the next body part reader.""" - headers = await self._read_headers() - return self._get_part_reader(headers) - - def _get_part_reader( - self, - headers: "CIMultiDictProxy[str]", - ) -> Union["MultipartReader", BodyPartReader]: - """Dispatches the response by the `Content-Type` header. - - Returns a suitable reader instance. - - :param dict headers: Response headers - """ - ctype = headers.get(CONTENT_TYPE, "") - mimetype = parse_mimetype(ctype) - - if mimetype.type == "multipart": - if self.multipart_reader_cls is None: - return type(self)(headers, self._content) - return self.multipart_reader_cls( - headers, - self._content, - max_field_size=self._max_field_size, - max_headers=self._max_headers, - ) - else: - return self.part_reader_cls( - self._boundary, - headers, - self._content, - subtype=self._mimetype.subtype, - default_charset=self._default_charset, - ) - - def _get_boundary(self) -> str: - boundary = self._mimetype.parameters["boundary"] - if len(boundary) > 70: - raise ValueError("boundary %r is too long (70 chars max)" % boundary) - - return boundary - - async def _readline(self) -> bytes: - if self._unread: - return self._unread.pop() - return await self._content.readline() - - async def _read_until_first_boundary(self) -> None: - while True: - chunk = await self._readline() - if chunk == b"": - raise ValueError( - "Could not find starting boundary %r" % (self._boundary) - ) - chunk = chunk.rstrip() - if chunk == self._boundary: - return - elif chunk == self._boundary + b"--": - self._at_eof = True - return - - async def _read_boundary(self) -> None: - chunk = (await self._readline()).rstrip() - if chunk == self._boundary: - pass - elif chunk == self._boundary + b"--": - self._at_eof = True - epilogue = await self._readline() - next_line = await self._readline() - - # the epilogue is expected and then either the end of input or the - # parent multipart boundary, if the parent boundary is found then - # it should be marked as unread and handed to the parent for - # processing - if next_line[:2] == b"--": - self._unread.append(next_line) - # otherwise the request is likely missing an epilogue and both - # lines should be passed to the parent for processing - # (this handles the old behavior gracefully) - else: - self._unread.extend([next_line, epilogue]) - else: - raise ValueError(f"Invalid boundary {chunk!r}, expected {self._boundary!r}") - - async def _read_headers(self) -> "CIMultiDictProxy[str]": - lines = [] - while True: - chunk = await self._content.readline(max_line_length=self._max_field_size) - chunk = chunk.rstrip(b"\r\n") - lines.append(chunk) - if not chunk: - break - if len(lines) > self._max_headers: - raise BadHttpMessage("Too many headers received") - parser = HeadersParser(max_field_size=self._max_field_size) - headers, raw_headers = parser.parse_headers(lines) - return headers - - async def _maybe_release_last_part(self) -> None: - """Ensures that the last read body part is read completely.""" - if self._last_part is not None: - if not self._last_part.at_eof(): - await self._last_part.release() - self._unread.extend(self._last_part._unread) - self._last_part = None - - -_Part = Tuple[Payload, str, str] - - -class MultipartWriter(Payload): - """Multipart body writer.""" - - _value: None - # _consumed = False (inherited) - Can be encoded multiple times - _autoclose = True # No file handles, just collects parts in memory - - def __init__(self, subtype: str = "mixed", boundary: Optional[str] = None) -> None: - boundary = boundary if boundary is not None else uuid.uuid4().hex - # The underlying Payload API demands a str (utf-8), not bytes, - # so we need to ensure we don't lose anything during conversion. - # As a result, require the boundary to be ASCII only. - # In both situations. - - try: - self._boundary = boundary.encode("ascii") - except UnicodeEncodeError: - raise ValueError("boundary should contain ASCII only chars") from None - ctype = f"multipart/{subtype}; boundary={self._boundary_value}" - - super().__init__(None, content_type=ctype) - - self._parts: List[_Part] = [] - self._is_form_data = subtype == "form-data" - - def __enter__(self) -> "MultipartWriter": - return self - - def __exit__( - self, - exc_type: Optional[Type[BaseException]], - exc_val: Optional[BaseException], - exc_tb: Optional[TracebackType], - ) -> None: - pass - - def __iter__(self) -> Iterator[_Part]: - return iter(self._parts) - - def __len__(self) -> int: - return len(self._parts) - - def __bool__(self) -> bool: - return True - - _valid_tchar_regex = re.compile(rb"\A[!#$%&'*+\-.^_`|~\w]+\Z") - _invalid_qdtext_char_regex = re.compile(rb"[\x00-\x08\x0A-\x1F\x7F]") - - @property - def _boundary_value(self) -> str: - """Wrap boundary parameter value in quotes, if necessary. - - Reads self.boundary and returns a unicode string. - """ - # Refer to RFCs 7231, 7230, 5234. - # - # parameter = token "=" ( token / quoted-string ) - # token = 1*tchar - # quoted-string = DQUOTE *( qdtext / quoted-pair ) DQUOTE - # qdtext = HTAB / SP / %x21 / %x23-5B / %x5D-7E / obs-text - # obs-text = %x80-FF - # quoted-pair = "\" ( HTAB / SP / VCHAR / obs-text ) - # tchar = "!" / "#" / "$" / "%" / "&" / "'" / "*" - # / "+" / "-" / "." / "^" / "_" / "`" / "|" / "~" - # / DIGIT / ALPHA - # ; any VCHAR, except delimiters - # VCHAR = %x21-7E - value = self._boundary - if re.match(self._valid_tchar_regex, value): - return value.decode("ascii") # cannot fail - - if re.search(self._invalid_qdtext_char_regex, value): - raise ValueError("boundary value contains invalid characters") - - # escape %x5C and %x22 - quoted_value_content = value.replace(b"\\", b"\\\\") - quoted_value_content = quoted_value_content.replace(b'"', b'\\"') - - return '"' + quoted_value_content.decode("ascii") + '"' - - @property - def boundary(self) -> str: - return self._boundary.decode("ascii") - - def append(self, obj: Any, headers: Optional[Mapping[str, str]] = None) -> Payload: - if headers is None: - headers = CIMultiDict() - - if isinstance(obj, Payload): - obj.headers.update(headers) - return self.append_payload(obj) - else: - try: - payload = get_payload(obj, headers=headers) - except LookupError: - raise TypeError("Cannot create payload from %r" % obj) - else: - return self.append_payload(payload) - - def append_payload(self, payload: Payload) -> Payload: - """Adds a new body part to multipart writer.""" - encoding: Optional[str] = None - te_encoding: Optional[str] = None - if self._is_form_data: - # https://datatracker.ietf.org/doc/html/rfc7578#section-4.7 - # https://datatracker.ietf.org/doc/html/rfc7578#section-4.8 - assert ( - not {CONTENT_ENCODING, CONTENT_LENGTH, CONTENT_TRANSFER_ENCODING} - & payload.headers.keys() - ) - # Set default Content-Disposition in case user doesn't create one - if CONTENT_DISPOSITION not in payload.headers: - name = f"section-{len(self._parts)}" - payload.set_content_disposition("form-data", name=name) - else: - # compression - encoding = payload.headers.get(CONTENT_ENCODING, "").lower() - if encoding and encoding not in ("deflate", "gzip", "identity"): - raise RuntimeError(f"unknown content encoding: {encoding}") - if encoding == "identity": - encoding = None - - # te encoding - te_encoding = payload.headers.get(CONTENT_TRANSFER_ENCODING, "").lower() - if te_encoding not in ("", "base64", "quoted-printable", "binary"): - raise RuntimeError(f"unknown content transfer encoding: {te_encoding}") - if te_encoding == "binary": - te_encoding = None - - # size - size = payload.size - if size is not None and not (encoding or te_encoding): - payload.headers[CONTENT_LENGTH] = str(size) - - self._parts.append((payload, encoding, te_encoding)) # type: ignore[arg-type] - return payload - - def append_json( - self, obj: Any, headers: Optional[Mapping[str, str]] = None - ) -> Payload: - """Helper to append JSON part.""" - if headers is None: - headers = CIMultiDict() - - return self.append_payload(JsonPayload(obj, headers=headers)) - - def append_form( - self, - obj: Union[Sequence[Tuple[str, str]], Mapping[str, str]], - headers: Optional[Mapping[str, str]] = None, - ) -> Payload: - """Helper to append form urlencoded part.""" - assert isinstance(obj, (Sequence, Mapping)) - - if headers is None: - headers = CIMultiDict() - - if isinstance(obj, Mapping): - obj = list(obj.items()) - data = urlencode(obj, doseq=True) - - return self.append_payload( - StringPayload( - data, headers=headers, content_type="application/x-www-form-urlencoded" - ) - ) - - @property - def size(self) -> Optional[int]: - """Size of the payload.""" - total = 0 - for part, encoding, te_encoding in self._parts: - part_size = part.size - if encoding or te_encoding or part_size is None: - return None - - total += int( - 2 - + len(self._boundary) - + 2 - + part_size # b'--'+self._boundary+b'\r\n' - + len(part._binary_headers) - + 2 # b'\r\n' - ) - - total += 2 + len(self._boundary) + 4 # b'--'+self._boundary+b'--\r\n' - return total - - def decode(self, encoding: str = "utf-8", errors: str = "strict") -> str: - """Return string representation of the multipart data. - - WARNING: This method may do blocking I/O if parts contain file payloads. - It should not be called in the event loop. Use as_bytes().decode() instead. - """ - return "".join( - "--" - + self.boundary - + "\r\n" - + part._binary_headers.decode(encoding, errors) - + part.decode() - for part, _e, _te in self._parts - ) - - async def as_bytes(self, encoding: str = "utf-8", errors: str = "strict") -> bytes: - """Return bytes representation of the multipart data. - - This method is async-safe and calls as_bytes on underlying payloads. - """ - parts: List[bytes] = [] - - # Process each part - for part, _e, _te in self._parts: - # Add boundary - parts.append(b"--" + self._boundary + b"\r\n") - - # Add headers - parts.append(part._binary_headers) - - # Add payload content using as_bytes for async safety - part_bytes = await part.as_bytes(encoding, errors) - parts.append(part_bytes) - - # Add trailing CRLF - parts.append(b"\r\n") - - # Add closing boundary - parts.append(b"--" + self._boundary + b"--\r\n") - - return b"".join(parts) - - async def write( - self, writer: AbstractStreamWriter, close_boundary: bool = True - ) -> None: - """Write body.""" - for part, encoding, te_encoding in self._parts: - if self._is_form_data: - # https://datatracker.ietf.org/doc/html/rfc7578#section-4.2 - assert CONTENT_DISPOSITION in part.headers - assert "name=" in part.headers[CONTENT_DISPOSITION] - - await writer.write(b"--" + self._boundary + b"\r\n") - await writer.write(part._binary_headers) - - if encoding or te_encoding: - w = MultipartPayloadWriter(writer) - if encoding: - w.enable_compression(encoding) - if te_encoding: - w.enable_encoding(te_encoding) - await part.write(w) # type: ignore[arg-type] - await w.write_eof() - else: - await part.write(writer) - - await writer.write(b"\r\n") - - if close_boundary: - await writer.write(b"--" + self._boundary + b"--\r\n") - - async def close(self) -> None: - """ - Close all part payloads that need explicit closing. - - IMPORTANT: This method must not await anything that might not finish - immediately, as it may be called during cleanup/cancellation. Schedule - any long-running operations without awaiting them. - """ - if self._consumed: - return - self._consumed = True - - # Close all parts that need explicit closing - # We catch and log exceptions to ensure all parts get a chance to close - # we do not use asyncio.gather() here because we are not allowed - # to suspend given we may be called during cleanup - for idx, (part, _, _) in enumerate(self._parts): - if not part.autoclose and not part.consumed: - try: - await part.close() - except Exception as exc: - internal_logger.error( - "Failed to close multipart part %d: %s", idx, exc, exc_info=True - ) - - -class MultipartPayloadWriter: - def __init__(self, writer: AbstractStreamWriter) -> None: - self._writer = writer - self._encoding: Optional[str] = None - self._compress: Optional[ZLibCompressor] = None - self._encoding_buffer: Optional[bytearray] = None - - def enable_encoding(self, encoding: str) -> None: - if encoding == "base64": - self._encoding = encoding - self._encoding_buffer = bytearray() - elif encoding == "quoted-printable": - self._encoding = "quoted-printable" - - def enable_compression( - self, encoding: str = "deflate", strategy: Optional[int] = None - ) -> None: - self._compress = ZLibCompressor( - encoding=encoding, - suppress_deflate_header=True, - strategy=strategy, - ) - - async def write_eof(self) -> None: - if self._compress is not None: - chunk = self._compress.flush() - if chunk: - self._compress = None - await self.write(chunk) - - if self._encoding == "base64": - if self._encoding_buffer: - await self._writer.write(base64.b64encode(self._encoding_buffer)) - - async def write(self, chunk: bytes) -> None: - if self._compress is not None: - if chunk: - chunk = await self._compress.compress(chunk) - if not chunk: - return - - if self._encoding == "base64": - buf = self._encoding_buffer - assert buf is not None - buf.extend(chunk) - - if buf: - div, mod = divmod(len(buf), 3) - enc_chunk, self._encoding_buffer = (buf[: div * 3], buf[div * 3 :]) - if enc_chunk: - b64chunk = base64.b64encode(enc_chunk) - await self._writer.write(b64chunk) - elif self._encoding == "quoted-printable": - await self._writer.write(binascii.b2a_qp(chunk)) - else: - await self._writer.write(chunk) diff --git a/venv/lib/python3.9/site-packages/aiohttp/payload.py b/venv/lib/python3.9/site-packages/aiohttp/payload.py deleted file mode 100644 index 5b88fa0..0000000 --- a/venv/lib/python3.9/site-packages/aiohttp/payload.py +++ /dev/null @@ -1,1120 +0,0 @@ -import asyncio -import enum -import io -import json -import mimetypes -import os -import sys -import warnings -from abc import ABC, abstractmethod -from collections.abc import Iterable -from itertools import chain -from typing import ( - IO, - TYPE_CHECKING, - Any, - Dict, - Final, - List, - Optional, - Set, - TextIO, - Tuple, - Type, - Union, -) - -from multidict import CIMultiDict - -from . import hdrs -from .abc import AbstractStreamWriter -from .helpers import ( - _SENTINEL, - content_disposition_header, - guess_filename, - parse_mimetype, - sentinel, -) -from .streams import StreamReader -from .typedefs import JSONEncoder, _CIMultiDict - -__all__ = ( - "PAYLOAD_REGISTRY", - "get_payload", - "payload_type", - "Payload", - "BytesPayload", - "StringPayload", - "IOBasePayload", - "BytesIOPayload", - "BufferedReaderPayload", - "TextIOPayload", - "StringIOPayload", - "JsonPayload", - "AsyncIterablePayload", -) - -TOO_LARGE_BYTES_BODY: Final[int] = 2**20 # 1 MB -READ_SIZE: Final[int] = 2**16 # 64 KB -_CLOSE_FUTURES: Set[asyncio.Future[None]] = set() - - -class LookupError(Exception): - """Raised when no payload factory is found for the given data type.""" - - -class Order(str, enum.Enum): - normal = "normal" - try_first = "try_first" - try_last = "try_last" - - -def get_payload(data: Any, *args: Any, **kwargs: Any) -> "Payload": - return PAYLOAD_REGISTRY.get(data, *args, **kwargs) - - -def register_payload( - factory: Type["Payload"], type: Any, *, order: Order = Order.normal -) -> None: - PAYLOAD_REGISTRY.register(factory, type, order=order) - - -class payload_type: - def __init__(self, type: Any, *, order: Order = Order.normal) -> None: - self.type = type - self.order = order - - def __call__(self, factory: Type["Payload"]) -> Type["Payload"]: - register_payload(factory, self.type, order=self.order) - return factory - - -PayloadType = Type["Payload"] -_PayloadRegistryItem = Tuple[PayloadType, Any] - - -class PayloadRegistry: - """Payload registry. - - note: we need zope.interface for more efficient adapter search - """ - - __slots__ = ("_first", "_normal", "_last", "_normal_lookup") - - def __init__(self) -> None: - self._first: List[_PayloadRegistryItem] = [] - self._normal: List[_PayloadRegistryItem] = [] - self._last: List[_PayloadRegistryItem] = [] - self._normal_lookup: Dict[Any, PayloadType] = {} - - def get( - self, - data: Any, - *args: Any, - _CHAIN: "Type[chain[_PayloadRegistryItem]]" = chain, - **kwargs: Any, - ) -> "Payload": - if self._first: - for factory, type_ in self._first: - if isinstance(data, type_): - return factory(data, *args, **kwargs) - # Try the fast lookup first - if lookup_factory := self._normal_lookup.get(type(data)): - return lookup_factory(data, *args, **kwargs) - # Bail early if its already a Payload - if isinstance(data, Payload): - return data - # Fallback to the slower linear search - for factory, type_ in _CHAIN(self._normal, self._last): - if isinstance(data, type_): - return factory(data, *args, **kwargs) - raise LookupError() - - def register( - self, factory: PayloadType, type: Any, *, order: Order = Order.normal - ) -> None: - if order is Order.try_first: - self._first.append((factory, type)) - elif order is Order.normal: - self._normal.append((factory, type)) - if isinstance(type, Iterable): - for t in type: - self._normal_lookup[t] = factory - else: - self._normal_lookup[type] = factory - elif order is Order.try_last: - self._last.append((factory, type)) - else: - raise ValueError(f"Unsupported order {order!r}") - - -class Payload(ABC): - - _default_content_type: str = "application/octet-stream" - _size: Optional[int] = None - _consumed: bool = False # Default: payload has not been consumed yet - _autoclose: bool = False # Default: assume resource needs explicit closing - - def __init__( - self, - value: Any, - headers: Optional[ - Union[_CIMultiDict, Dict[str, str], Iterable[Tuple[str, str]]] - ] = None, - content_type: Union[str, None, _SENTINEL] = sentinel, - filename: Optional[str] = None, - encoding: Optional[str] = None, - **kwargs: Any, - ) -> None: - self._encoding = encoding - self._filename = filename - self._headers: _CIMultiDict = CIMultiDict() - self._value = value - if content_type is not sentinel and content_type is not None: - self._headers[hdrs.CONTENT_TYPE] = content_type - elif self._filename is not None: - if sys.version_info >= (3, 13): - guesser = mimetypes.guess_file_type - else: - guesser = mimetypes.guess_type - content_type = guesser(self._filename)[0] - if content_type is None: - content_type = self._default_content_type - self._headers[hdrs.CONTENT_TYPE] = content_type - else: - self._headers[hdrs.CONTENT_TYPE] = self._default_content_type - if headers: - self._headers.update(headers) - - @property - def size(self) -> Optional[int]: - """Size of the payload in bytes. - - Returns the number of bytes that will be transmitted when the payload - is written. For string payloads, this is the size after encoding to bytes, - not the length of the string. - """ - return self._size - - @property - def filename(self) -> Optional[str]: - """Filename of the payload.""" - return self._filename - - @property - def headers(self) -> _CIMultiDict: - """Custom item headers""" - return self._headers - - @property - def _binary_headers(self) -> bytes: - return ( - "".join([k + ": " + v + "\r\n" for k, v in self.headers.items()]).encode( - "utf-8" - ) - + b"\r\n" - ) - - @property - def encoding(self) -> Optional[str]: - """Payload encoding""" - return self._encoding - - @property - def content_type(self) -> str: - """Content type""" - return self._headers[hdrs.CONTENT_TYPE] - - @property - def consumed(self) -> bool: - """Whether the payload has been consumed and cannot be reused.""" - return self._consumed - - @property - def autoclose(self) -> bool: - """ - Whether the payload can close itself automatically. - - Returns True if the payload has no file handles or resources that need - explicit closing. If False, callers must await close() to release resources. - """ - return self._autoclose - - def set_content_disposition( - self, - disptype: str, - quote_fields: bool = True, - _charset: str = "utf-8", - **params: Any, - ) -> None: - """Sets ``Content-Disposition`` header.""" - self._headers[hdrs.CONTENT_DISPOSITION] = content_disposition_header( - disptype, quote_fields=quote_fields, _charset=_charset, **params - ) - - @abstractmethod - def decode(self, encoding: str = "utf-8", errors: str = "strict") -> str: - """ - Return string representation of the value. - - This is named decode() to allow compatibility with bytes objects. - """ - - @abstractmethod - async def write(self, writer: AbstractStreamWriter) -> None: - """ - Write payload to the writer stream. - - Args: - writer: An AbstractStreamWriter instance that handles the actual writing - - This is a legacy method that writes the entire payload without length constraints. - - Important: - For new implementations, use write_with_length() instead of this method. - This method is maintained for backwards compatibility and will eventually - delegate to write_with_length(writer, None) in all implementations. - - All payload subclasses must override this method for backwards compatibility, - but new code should use write_with_length for more flexibility and control. - - """ - - # write_with_length is new in aiohttp 3.12 - # it should be overridden by subclasses - async def write_with_length( - self, writer: AbstractStreamWriter, content_length: Optional[int] - ) -> None: - """ - Write payload with a specific content length constraint. - - Args: - writer: An AbstractStreamWriter instance that handles the actual writing - content_length: Maximum number of bytes to write (None for unlimited) - - This method allows writing payload content with a specific length constraint, - which is particularly useful for HTTP responses with Content-Length header. - - Note: - This is the base implementation that provides backwards compatibility - for subclasses that don't override this method. Specific payload types - should override this method to implement proper length-constrained writing. - - """ - # Backwards compatibility for subclasses that don't override this method - # and for the default implementation - await self.write(writer) - - async def as_bytes(self, encoding: str = "utf-8", errors: str = "strict") -> bytes: - """ - Return bytes representation of the value. - - This is a convenience method that calls decode() and encodes the result - to bytes using the specified encoding. - """ - # Use instance encoding if available, otherwise use parameter - actual_encoding = self._encoding or encoding - return self.decode(actual_encoding, errors).encode(actual_encoding) - - def _close(self) -> None: - """ - Async safe synchronous close operations for backwards compatibility. - - This method exists only for backwards compatibility with code that - needs to clean up payloads synchronously. In the future, we will - drop this method and only support the async close() method. - - WARNING: This method must be safe to call from within the event loop - without blocking. Subclasses should not perform any blocking I/O here. - - WARNING: This method must be called from within an event loop for - certain payload types (e.g., IOBasePayload). Calling it outside an - event loop may raise RuntimeError. - """ - # This is a no-op by default, but subclasses can override it - # for non-blocking cleanup operations. - - async def close(self) -> None: - """ - Close the payload if it holds any resources. - - IMPORTANT: This method must not await anything that might not finish - immediately, as it may be called during cleanup/cancellation. Schedule - any long-running operations without awaiting them. - - In the future, this will be the only close method supported. - """ - self._close() - - -class BytesPayload(Payload): - _value: bytes - # _consumed = False (inherited) - Bytes are immutable and can be reused - _autoclose = True # No file handle, just bytes in memory - - def __init__( - self, value: Union[bytes, bytearray, memoryview], *args: Any, **kwargs: Any - ) -> None: - if "content_type" not in kwargs: - kwargs["content_type"] = "application/octet-stream" - - super().__init__(value, *args, **kwargs) - - if isinstance(value, memoryview): - self._size = value.nbytes - elif isinstance(value, (bytes, bytearray)): - self._size = len(value) - else: - raise TypeError(f"value argument must be byte-ish, not {type(value)!r}") - - if self._size > TOO_LARGE_BYTES_BODY: - kwargs = {"source": self} - warnings.warn( - "Sending a large body directly with raw bytes might" - " lock the event loop. You should probably pass an " - "io.BytesIO object instead", - ResourceWarning, - **kwargs, - ) - - def decode(self, encoding: str = "utf-8", errors: str = "strict") -> str: - return self._value.decode(encoding, errors) - - async def as_bytes(self, encoding: str = "utf-8", errors: str = "strict") -> bytes: - """ - Return bytes representation of the value. - - This method returns the raw bytes content of the payload. - It is equivalent to accessing the _value attribute directly. - """ - return self._value - - async def write(self, writer: AbstractStreamWriter) -> None: - """ - Write the entire bytes payload to the writer stream. - - Args: - writer: An AbstractStreamWriter instance that handles the actual writing - - This method writes the entire bytes content without any length constraint. - - Note: - For new implementations that need length control, use write_with_length(). - This method is maintained for backwards compatibility and is equivalent - to write_with_length(writer, None). - - """ - await writer.write(self._value) - - async def write_with_length( - self, writer: AbstractStreamWriter, content_length: Optional[int] - ) -> None: - """ - Write bytes payload with a specific content length constraint. - - Args: - writer: An AbstractStreamWriter instance that handles the actual writing - content_length: Maximum number of bytes to write (None for unlimited) - - This method writes either the entire byte sequence or a slice of it - up to the specified content_length. For BytesPayload, this operation - is performed efficiently using array slicing. - - """ - if content_length is not None: - await writer.write(self._value[:content_length]) - else: - await writer.write(self._value) - - -class StringPayload(BytesPayload): - def __init__( - self, - value: str, - *args: Any, - encoding: Optional[str] = None, - content_type: Optional[str] = None, - **kwargs: Any, - ) -> None: - - if encoding is None: - if content_type is None: - real_encoding = "utf-8" - content_type = "text/plain; charset=utf-8" - else: - mimetype = parse_mimetype(content_type) - real_encoding = mimetype.parameters.get("charset", "utf-8") - else: - if content_type is None: - content_type = "text/plain; charset=%s" % encoding - real_encoding = encoding - - super().__init__( - value.encode(real_encoding), - encoding=real_encoding, - content_type=content_type, - *args, - **kwargs, - ) - - -class StringIOPayload(StringPayload): - def __init__(self, value: IO[str], *args: Any, **kwargs: Any) -> None: - super().__init__(value.read(), *args, **kwargs) - - -class IOBasePayload(Payload): - _value: io.IOBase - # _consumed = False (inherited) - File can be re-read from the same position - _start_position: Optional[int] = None - # _autoclose = False (inherited) - Has file handle that needs explicit closing - - def __init__( - self, value: IO[Any], disposition: str = "attachment", *args: Any, **kwargs: Any - ) -> None: - if "filename" not in kwargs: - kwargs["filename"] = guess_filename(value) - - super().__init__(value, *args, **kwargs) - - if self._filename is not None and disposition is not None: - if hdrs.CONTENT_DISPOSITION not in self.headers: - self.set_content_disposition(disposition, filename=self._filename) - - def _set_or_restore_start_position(self) -> None: - """Set or restore the start position of the file-like object.""" - if self._start_position is None: - try: - self._start_position = self._value.tell() - except (OSError, AttributeError): - self._consumed = True # Cannot seek, mark as consumed - return - try: - self._value.seek(self._start_position) - except (OSError, AttributeError): - # Failed to seek back - mark as consumed since we've already read - self._consumed = True - - def _read_and_available_len( - self, remaining_content_len: Optional[int] - ) -> Tuple[Optional[int], bytes]: - """ - Read the file-like object and return both its total size and the first chunk. - - Args: - remaining_content_len: Optional limit on how many bytes to read in this operation. - If None, READ_SIZE will be used as the default chunk size. - - Returns: - A tuple containing: - - The total size of the remaining unread content (None if size cannot be determined) - - The first chunk of bytes read from the file object - - This method is optimized to perform both size calculation and initial read - in a single operation, which is executed in a single executor job to minimize - context switches and file operations when streaming content. - - """ - self._set_or_restore_start_position() - size = self.size # Call size only once since it does I/O - return size, self._value.read( - min(READ_SIZE, size or READ_SIZE, remaining_content_len or READ_SIZE) - ) - - def _read(self, remaining_content_len: Optional[int]) -> bytes: - """ - Read a chunk of data from the file-like object. - - Args: - remaining_content_len: Optional maximum number of bytes to read. - If None, READ_SIZE will be used as the default chunk size. - - Returns: - A chunk of bytes read from the file object, respecting the - remaining_content_len limit if specified. - - This method is used for subsequent reads during streaming after - the initial _read_and_available_len call has been made. - - """ - return self._value.read(remaining_content_len or READ_SIZE) # type: ignore[no-any-return] - - @property - def size(self) -> Optional[int]: - """ - Size of the payload in bytes. - - Returns the total size of the payload content from the initial position. - This ensures consistent Content-Length for requests, including 307/308 redirects - where the same payload instance is reused. - - Returns None if the size cannot be determined (e.g., for unseekable streams). - """ - try: - # Store the start position on first access. - # This is critical when the same payload instance is reused (e.g., 307/308 - # redirects). Without storing the initial position, after the payload is - # read once, the file position would be at EOF, which would cause the - # size calculation to return 0 (file_size - EOF position). - # By storing the start position, we ensure the size calculation always - # returns the correct total size for any subsequent use. - if self._start_position is None: - self._start_position = self._value.tell() - - # Return the total size from the start position - # This ensures Content-Length is correct even after reading - return os.fstat(self._value.fileno()).st_size - self._start_position - except (AttributeError, OSError): - return None - - async def write(self, writer: AbstractStreamWriter) -> None: - """ - Write the entire file-like payload to the writer stream. - - Args: - writer: An AbstractStreamWriter instance that handles the actual writing - - This method writes the entire file content without any length constraint. - It delegates to write_with_length() with no length limit for implementation - consistency. - - Note: - For new implementations that need length control, use write_with_length() directly. - This method is maintained for backwards compatibility with existing code. - - """ - await self.write_with_length(writer, None) - - async def write_with_length( - self, writer: AbstractStreamWriter, content_length: Optional[int] - ) -> None: - """ - Write file-like payload with a specific content length constraint. - - Args: - writer: An AbstractStreamWriter instance that handles the actual writing - content_length: Maximum number of bytes to write (None for unlimited) - - This method implements optimized streaming of file content with length constraints: - - 1. File reading is performed in a thread pool to avoid blocking the event loop - 2. Content is read and written in chunks to maintain memory efficiency - 3. Writing stops when either: - - All available file content has been written (when size is known) - - The specified content_length has been reached - 4. File resources are properly closed even if the operation is cancelled - - The implementation carefully handles both known-size and unknown-size payloads, - as well as constrained and unconstrained content lengths. - - """ - loop = asyncio.get_running_loop() - total_written_len = 0 - remaining_content_len = content_length - - # Get initial data and available length - available_len, chunk = await loop.run_in_executor( - None, self._read_and_available_len, remaining_content_len - ) - # Process data chunks until done - while chunk: - chunk_len = len(chunk) - - # Write data with or without length constraint - if remaining_content_len is None: - await writer.write(chunk) - else: - await writer.write(chunk[:remaining_content_len]) - remaining_content_len -= chunk_len - - total_written_len += chunk_len - - # Check if we're done writing - if self._should_stop_writing( - available_len, total_written_len, remaining_content_len - ): - return - - # Read next chunk - chunk = await loop.run_in_executor( - None, - self._read, - ( - min(READ_SIZE, remaining_content_len) - if remaining_content_len is not None - else READ_SIZE - ), - ) - - def _should_stop_writing( - self, - available_len: Optional[int], - total_written_len: int, - remaining_content_len: Optional[int], - ) -> bool: - """ - Determine if we should stop writing data. - - Args: - available_len: Known size of the payload if available (None if unknown) - total_written_len: Number of bytes already written - remaining_content_len: Remaining bytes to be written for content-length limited responses - - Returns: - True if we should stop writing data, based on either: - - Having written all available data (when size is known) - - Having written all requested content (when content-length is specified) - - """ - return (available_len is not None and total_written_len >= available_len) or ( - remaining_content_len is not None and remaining_content_len <= 0 - ) - - def _close(self) -> None: - """ - Async safe synchronous close operations for backwards compatibility. - - This method exists only for backwards - compatibility. Use the async close() method instead. - - WARNING: This method MUST be called from within an event loop. - Calling it outside an event loop will raise RuntimeError. - """ - # Skip if already consumed - if self._consumed: - return - self._consumed = True # Mark as consumed to prevent further writes - # Schedule file closing without awaiting to prevent cancellation issues - loop = asyncio.get_running_loop() - close_future = loop.run_in_executor(None, self._value.close) - # Hold a strong reference to the future to prevent it from being - # garbage collected before it completes. - _CLOSE_FUTURES.add(close_future) - close_future.add_done_callback(_CLOSE_FUTURES.remove) - - async def close(self) -> None: - """ - Close the payload if it holds any resources. - - IMPORTANT: This method must not await anything that might not finish - immediately, as it may be called during cleanup/cancellation. Schedule - any long-running operations without awaiting them. - """ - self._close() - - def decode(self, encoding: str = "utf-8", errors: str = "strict") -> str: - """ - Return string representation of the value. - - WARNING: This method does blocking I/O and should not be called in the event loop. - """ - return self._read_all().decode(encoding, errors) - - def _read_all(self) -> bytes: - """Read the entire file-like object and return its content as bytes.""" - self._set_or_restore_start_position() - # Use readlines() to ensure we get all content - return b"".join(self._value.readlines()) - - async def as_bytes(self, encoding: str = "utf-8", errors: str = "strict") -> bytes: - """ - Return bytes representation of the value. - - This method reads the entire file content and returns it as bytes. - It is equivalent to reading the file-like object directly. - The file reading is performed in an executor to avoid blocking the event loop. - """ - loop = asyncio.get_running_loop() - return await loop.run_in_executor(None, self._read_all) - - -class TextIOPayload(IOBasePayload): - _value: io.TextIOBase - # _autoclose = False (inherited) - Has text file handle that needs explicit closing - - def __init__( - self, - value: TextIO, - *args: Any, - encoding: Optional[str] = None, - content_type: Optional[str] = None, - **kwargs: Any, - ) -> None: - - if encoding is None: - if content_type is None: - encoding = "utf-8" - content_type = "text/plain; charset=utf-8" - else: - mimetype = parse_mimetype(content_type) - encoding = mimetype.parameters.get("charset", "utf-8") - else: - if content_type is None: - content_type = "text/plain; charset=%s" % encoding - - super().__init__( - value, - content_type=content_type, - encoding=encoding, - *args, - **kwargs, - ) - - def _read_and_available_len( - self, remaining_content_len: Optional[int] - ) -> Tuple[Optional[int], bytes]: - """ - Read the text file-like object and return both its total size and the first chunk. - - Args: - remaining_content_len: Optional limit on how many bytes to read in this operation. - If None, READ_SIZE will be used as the default chunk size. - - Returns: - A tuple containing: - - The total size of the remaining unread content (None if size cannot be determined) - - The first chunk of bytes read from the file object, encoded using the payload's encoding - - This method is optimized to perform both size calculation and initial read - in a single operation, which is executed in a single executor job to minimize - context switches and file operations when streaming content. - - Note: - TextIOPayload handles encoding of the text content before writing it - to the stream. If no encoding is specified, UTF-8 is used as the default. - - """ - self._set_or_restore_start_position() - size = self.size - chunk = self._value.read( - min(READ_SIZE, size or READ_SIZE, remaining_content_len or READ_SIZE) - ) - return size, chunk.encode(self._encoding) if self._encoding else chunk.encode() - - def _read(self, remaining_content_len: Optional[int]) -> bytes: - """ - Read a chunk of data from the text file-like object. - - Args: - remaining_content_len: Optional maximum number of bytes to read. - If None, READ_SIZE will be used as the default chunk size. - - Returns: - A chunk of bytes read from the file object and encoded using the payload's - encoding. The data is automatically converted from text to bytes. - - This method is used for subsequent reads during streaming after - the initial _read_and_available_len call has been made. It properly - handles text encoding, converting the text content to bytes using - the specified encoding (or UTF-8 if none was provided). - - """ - chunk = self._value.read(remaining_content_len or READ_SIZE) - return chunk.encode(self._encoding) if self._encoding else chunk.encode() - - def decode(self, encoding: str = "utf-8", errors: str = "strict") -> str: - """ - Return string representation of the value. - - WARNING: This method does blocking I/O and should not be called in the event loop. - """ - self._set_or_restore_start_position() - return self._value.read() - - async def as_bytes(self, encoding: str = "utf-8", errors: str = "strict") -> bytes: - """ - Return bytes representation of the value. - - This method reads the entire text file content and returns it as bytes. - It encodes the text content using the specified encoding. - The file reading is performed in an executor to avoid blocking the event loop. - """ - loop = asyncio.get_running_loop() - - # Use instance encoding if available, otherwise use parameter - actual_encoding = self._encoding or encoding - - def _read_and_encode() -> bytes: - self._set_or_restore_start_position() - # TextIO read() always returns the full content - return self._value.read().encode(actual_encoding, errors) - - return await loop.run_in_executor(None, _read_and_encode) - - -class BytesIOPayload(IOBasePayload): - _value: io.BytesIO - _size: int # Always initialized in __init__ - _autoclose = True # BytesIO is in-memory, safe to auto-close - - def __init__(self, value: io.BytesIO, *args: Any, **kwargs: Any) -> None: - super().__init__(value, *args, **kwargs) - # Calculate size once during initialization - self._size = len(self._value.getbuffer()) - self._value.tell() - - @property - def size(self) -> int: - """Size of the payload in bytes. - - Returns the number of bytes in the BytesIO buffer that will be transmitted. - This is calculated once during initialization for efficiency. - """ - return self._size - - def decode(self, encoding: str = "utf-8", errors: str = "strict") -> str: - self._set_or_restore_start_position() - return self._value.read().decode(encoding, errors) - - async def write(self, writer: AbstractStreamWriter) -> None: - return await self.write_with_length(writer, None) - - async def write_with_length( - self, writer: AbstractStreamWriter, content_length: Optional[int] - ) -> None: - """ - Write BytesIO payload with a specific content length constraint. - - Args: - writer: An AbstractStreamWriter instance that handles the actual writing - content_length: Maximum number of bytes to write (None for unlimited) - - This implementation is specifically optimized for BytesIO objects: - - 1. Reads content in chunks to maintain memory efficiency - 2. Yields control back to the event loop periodically to prevent blocking - when dealing with large BytesIO objects - 3. Respects content_length constraints when specified - 4. Properly cleans up by closing the BytesIO object when done or on error - - The periodic yielding to the event loop is important for maintaining - responsiveness when processing large in-memory buffers. - - """ - self._set_or_restore_start_position() - loop_count = 0 - remaining_bytes = content_length - while chunk := self._value.read(READ_SIZE): - if loop_count > 0: - # Avoid blocking the event loop - # if they pass a large BytesIO object - # and we are not in the first iteration - # of the loop - await asyncio.sleep(0) - if remaining_bytes is None: - await writer.write(chunk) - else: - await writer.write(chunk[:remaining_bytes]) - remaining_bytes -= len(chunk) - if remaining_bytes <= 0: - return - loop_count += 1 - - async def as_bytes(self, encoding: str = "utf-8", errors: str = "strict") -> bytes: - """ - Return bytes representation of the value. - - This method reads the entire BytesIO content and returns it as bytes. - It is equivalent to accessing the _value attribute directly. - """ - self._set_or_restore_start_position() - return self._value.read() - - async def close(self) -> None: - """ - Close the BytesIO payload. - - This does nothing since BytesIO is in-memory and does not require explicit closing. - """ - - -class BufferedReaderPayload(IOBasePayload): - _value: io.BufferedIOBase - # _autoclose = False (inherited) - Has buffered file handle that needs explicit closing - - def decode(self, encoding: str = "utf-8", errors: str = "strict") -> str: - self._set_or_restore_start_position() - return self._value.read().decode(encoding, errors) - - -class JsonPayload(BytesPayload): - def __init__( - self, - value: Any, - encoding: str = "utf-8", - content_type: str = "application/json", - dumps: JSONEncoder = json.dumps, - *args: Any, - **kwargs: Any, - ) -> None: - - super().__init__( - dumps(value).encode(encoding), - content_type=content_type, - encoding=encoding, - *args, - **kwargs, - ) - - -if TYPE_CHECKING: - from typing import AsyncIterable, AsyncIterator - - _AsyncIterator = AsyncIterator[bytes] - _AsyncIterable = AsyncIterable[bytes] -else: - from collections.abc import AsyncIterable, AsyncIterator - - _AsyncIterator = AsyncIterator - _AsyncIterable = AsyncIterable - - -class AsyncIterablePayload(Payload): - - _iter: Optional[_AsyncIterator] = None - _value: _AsyncIterable - _cached_chunks: Optional[List[bytes]] = None - # _consumed stays False to allow reuse with cached content - _autoclose = True # Iterator doesn't need explicit closing - - def __init__(self, value: _AsyncIterable, *args: Any, **kwargs: Any) -> None: - if not isinstance(value, AsyncIterable): - raise TypeError( - "value argument must support " - "collections.abc.AsyncIterable interface, " - "got {!r}".format(type(value)) - ) - - if "content_type" not in kwargs: - kwargs["content_type"] = "application/octet-stream" - - super().__init__(value, *args, **kwargs) - - self._iter = value.__aiter__() - - async def write(self, writer: AbstractStreamWriter) -> None: - """ - Write the entire async iterable payload to the writer stream. - - Args: - writer: An AbstractStreamWriter instance that handles the actual writing - - This method iterates through the async iterable and writes each chunk - to the writer without any length constraint. - - Note: - For new implementations that need length control, use write_with_length() directly. - This method is maintained for backwards compatibility with existing code. - - """ - await self.write_with_length(writer, None) - - async def write_with_length( - self, writer: AbstractStreamWriter, content_length: Optional[int] - ) -> None: - """ - Write async iterable payload with a specific content length constraint. - - Args: - writer: An AbstractStreamWriter instance that handles the actual writing - content_length: Maximum number of bytes to write (None for unlimited) - - This implementation handles streaming of async iterable content with length constraints: - - 1. If cached chunks are available, writes from them - 2. Otherwise iterates through the async iterable one chunk at a time - 3. Respects content_length constraints when specified - 4. Does NOT generate cache - that's done by as_bytes() - - """ - # If we have cached chunks, use them - if self._cached_chunks is not None: - remaining_bytes = content_length - for chunk in self._cached_chunks: - if remaining_bytes is None: - await writer.write(chunk) - elif remaining_bytes > 0: - await writer.write(chunk[:remaining_bytes]) - remaining_bytes -= len(chunk) - else: - break - return - - # If iterator is exhausted and we don't have cached chunks, nothing to write - if self._iter is None: - return - - # Stream from the iterator - remaining_bytes = content_length - - try: - while True: - if sys.version_info >= (3, 10): - chunk = await anext(self._iter) - else: - chunk = await self._iter.__anext__() - if remaining_bytes is None: - await writer.write(chunk) - # If we have a content length limit - elif remaining_bytes > 0: - await writer.write(chunk[:remaining_bytes]) - remaining_bytes -= len(chunk) - # We still want to exhaust the iterator even - # if we have reached the content length limit - # since the file handle may not get closed by - # the iterator if we don't do this - except StopAsyncIteration: - # Iterator is exhausted - self._iter = None - self._consumed = True # Mark as consumed when streamed without caching - - def decode(self, encoding: str = "utf-8", errors: str = "strict") -> str: - """Decode the payload content as a string if cached chunks are available.""" - if self._cached_chunks is not None: - return b"".join(self._cached_chunks).decode(encoding, errors) - raise TypeError("Unable to decode - content not cached. Call as_bytes() first.") - - async def as_bytes(self, encoding: str = "utf-8", errors: str = "strict") -> bytes: - """ - Return bytes representation of the value. - - This method reads the entire async iterable content and returns it as bytes. - It generates and caches the chunks for future reuse. - """ - # If we have cached chunks, return them joined - if self._cached_chunks is not None: - return b"".join(self._cached_chunks) - - # If iterator is exhausted and no cache, return empty - if self._iter is None: - return b"" - - # Read all chunks and cache them - chunks: List[bytes] = [] - async for chunk in self._iter: - chunks.append(chunk) - - # Iterator is exhausted, cache the chunks - self._iter = None - self._cached_chunks = chunks - # Keep _consumed as False to allow reuse with cached chunks - - return b"".join(chunks) - - -class StreamReaderPayload(AsyncIterablePayload): - def __init__(self, value: StreamReader, *args: Any, **kwargs: Any) -> None: - super().__init__(value.iter_any(), *args, **kwargs) - - -PAYLOAD_REGISTRY = PayloadRegistry() -PAYLOAD_REGISTRY.register(BytesPayload, (bytes, bytearray, memoryview)) -PAYLOAD_REGISTRY.register(StringPayload, str) -PAYLOAD_REGISTRY.register(StringIOPayload, io.StringIO) -PAYLOAD_REGISTRY.register(TextIOPayload, io.TextIOBase) -PAYLOAD_REGISTRY.register(BytesIOPayload, io.BytesIO) -PAYLOAD_REGISTRY.register(BufferedReaderPayload, (io.BufferedReader, io.BufferedRandom)) -PAYLOAD_REGISTRY.register(IOBasePayload, io.IOBase) -PAYLOAD_REGISTRY.register(StreamReaderPayload, StreamReader) -# try_last for giving a chance to more specialized async interables like -# multipart.BodyPartReaderPayload override the default -PAYLOAD_REGISTRY.register(AsyncIterablePayload, AsyncIterable, order=Order.try_last) diff --git a/venv/lib/python3.9/site-packages/aiohttp/payload_streamer.py b/venv/lib/python3.9/site-packages/aiohttp/payload_streamer.py deleted file mode 100644 index 831fdc0..0000000 --- a/venv/lib/python3.9/site-packages/aiohttp/payload_streamer.py +++ /dev/null @@ -1,78 +0,0 @@ -""" -Payload implementation for coroutines as data provider. - -As a simple case, you can upload data from file:: - - @aiohttp.streamer - async def file_sender(writer, file_name=None): - with open(file_name, 'rb') as f: - chunk = f.read(2**16) - while chunk: - await writer.write(chunk) - - chunk = f.read(2**16) - -Then you can use `file_sender` like this: - - async with session.post('http://httpbin.org/post', - data=file_sender(file_name='huge_file')) as resp: - print(await resp.text()) - -..note:: Coroutine must accept `writer` as first argument - -""" - -import types -import warnings -from typing import Any, Awaitable, Callable, Dict, Tuple - -from .abc import AbstractStreamWriter -from .payload import Payload, payload_type - -__all__ = ("streamer",) - - -class _stream_wrapper: - def __init__( - self, - coro: Callable[..., Awaitable[None]], - args: Tuple[Any, ...], - kwargs: Dict[str, Any], - ) -> None: - self.coro = types.coroutine(coro) - self.args = args - self.kwargs = kwargs - - async def __call__(self, writer: AbstractStreamWriter) -> None: - await self.coro(writer, *self.args, **self.kwargs) - - -class streamer: - def __init__(self, coro: Callable[..., Awaitable[None]]) -> None: - warnings.warn( - "@streamer is deprecated, use async generators instead", - DeprecationWarning, - stacklevel=2, - ) - self.coro = coro - - def __call__(self, *args: Any, **kwargs: Any) -> _stream_wrapper: - return _stream_wrapper(self.coro, args, kwargs) - - -@payload_type(_stream_wrapper) -class StreamWrapperPayload(Payload): - async def write(self, writer: AbstractStreamWriter) -> None: - await self._value(writer) - - def decode(self, encoding: str = "utf-8", errors: str = "strict") -> str: - raise TypeError("Unable to decode.") - - -@payload_type(streamer) -class StreamPayload(StreamWrapperPayload): - def __init__(self, value: Any, *args: Any, **kwargs: Any) -> None: - super().__init__(value(), *args, **kwargs) - - async def write(self, writer: AbstractStreamWriter) -> None: - await self._value(writer) diff --git a/venv/lib/python3.9/site-packages/aiohttp/py.typed b/venv/lib/python3.9/site-packages/aiohttp/py.typed deleted file mode 100644 index f5642f7..0000000 --- a/venv/lib/python3.9/site-packages/aiohttp/py.typed +++ /dev/null @@ -1 +0,0 @@ -Marker diff --git a/venv/lib/python3.9/site-packages/aiohttp/pytest_plugin.py b/venv/lib/python3.9/site-packages/aiohttp/pytest_plugin.py deleted file mode 100644 index 7d59fe8..0000000 --- a/venv/lib/python3.9/site-packages/aiohttp/pytest_plugin.py +++ /dev/null @@ -1,444 +0,0 @@ -import asyncio -import contextlib -import inspect -import warnings -from typing import ( - Any, - Awaitable, - Callable, - Dict, - Iterator, - Optional, - Protocol, - Union, - overload, -) - -import pytest - -from .test_utils import ( - BaseTestServer, - RawTestServer, - TestClient, - TestServer, - loop_context, - setup_test_loop, - teardown_test_loop, - unused_port as _unused_port, -) -from .web import Application, BaseRequest, Request -from .web_protocol import _RequestHandler - -try: - import uvloop -except ImportError: # pragma: no cover - uvloop = None # type: ignore[assignment] - - -class AiohttpClient(Protocol): - @overload - async def __call__( - self, - __param: Application, - *, - server_kwargs: Optional[Dict[str, Any]] = None, - **kwargs: Any, - ) -> TestClient[Request, Application]: ... - @overload - async def __call__( - self, - __param: BaseTestServer, - *, - server_kwargs: Optional[Dict[str, Any]] = None, - **kwargs: Any, - ) -> TestClient[BaseRequest, None]: ... - - -class AiohttpServer(Protocol): - def __call__( - self, app: Application, *, port: Optional[int] = None, **kwargs: Any - ) -> Awaitable[TestServer]: ... - - -class AiohttpRawServer(Protocol): - def __call__( - self, handler: _RequestHandler, *, port: Optional[int] = None, **kwargs: Any - ) -> Awaitable[RawTestServer]: ... - - -def pytest_addoption(parser): # type: ignore[no-untyped-def] - parser.addoption( - "--aiohttp-fast", - action="store_true", - default=False, - help="run tests faster by disabling extra checks", - ) - parser.addoption( - "--aiohttp-loop", - action="store", - default="pyloop", - help="run tests with specific loop: pyloop, uvloop or all", - ) - parser.addoption( - "--aiohttp-enable-loop-debug", - action="store_true", - default=False, - help="enable event loop debug mode", - ) - - -def pytest_fixture_setup(fixturedef): # type: ignore[no-untyped-def] - """Set up pytest fixture. - - Allow fixtures to be coroutines. Run coroutine fixtures in an event loop. - """ - func = fixturedef.func - - if inspect.isasyncgenfunction(func): - # async generator fixture - is_async_gen = True - elif inspect.iscoroutinefunction(func): - # regular async fixture - is_async_gen = False - else: - # not an async fixture, nothing to do - return - - strip_request = False - if "request" not in fixturedef.argnames: - fixturedef.argnames += ("request",) - strip_request = True - - def wrapper(*args, **kwargs): # type: ignore[no-untyped-def] - request = kwargs["request"] - if strip_request: - del kwargs["request"] - - # if neither the fixture nor the test use the 'loop' fixture, - # 'getfixturevalue' will fail because the test is not parameterized - # (this can be removed someday if 'loop' is no longer parameterized) - if "loop" not in request.fixturenames: - raise Exception( - "Asynchronous fixtures must depend on the 'loop' fixture or " - "be used in tests depending from it." - ) - - _loop = request.getfixturevalue("loop") - - if is_async_gen: - # for async generators, we need to advance the generator once, - # then advance it again in a finalizer - gen = func(*args, **kwargs) - - def finalizer(): # type: ignore[no-untyped-def] - try: - return _loop.run_until_complete(gen.__anext__()) - except StopAsyncIteration: - pass - - request.addfinalizer(finalizer) - return _loop.run_until_complete(gen.__anext__()) - else: - return _loop.run_until_complete(func(*args, **kwargs)) - - fixturedef.func = wrapper - - -@pytest.fixture -def fast(request): # type: ignore[no-untyped-def] - """--fast config option""" - return request.config.getoption("--aiohttp-fast") - - -@pytest.fixture -def loop_debug(request): # type: ignore[no-untyped-def] - """--enable-loop-debug config option""" - return request.config.getoption("--aiohttp-enable-loop-debug") - - -@contextlib.contextmanager -def _runtime_warning_context(): # type: ignore[no-untyped-def] - """Context manager which checks for RuntimeWarnings. - - This exists specifically to - avoid "coroutine 'X' was never awaited" warnings being missed. - - If RuntimeWarnings occur in the context a RuntimeError is raised. - """ - with warnings.catch_warnings(record=True) as _warnings: - yield - rw = [ - "{w.filename}:{w.lineno}:{w.message}".format(w=w) - for w in _warnings - if w.category == RuntimeWarning - ] - if rw: - raise RuntimeError( - "{} Runtime Warning{},\n{}".format( - len(rw), "" if len(rw) == 1 else "s", "\n".join(rw) - ) - ) - - -@contextlib.contextmanager -def _passthrough_loop_context(loop, fast=False): # type: ignore[no-untyped-def] - """Passthrough loop context. - - Sets up and tears down a loop unless one is passed in via the loop - argument when it's passed straight through. - """ - if loop: - # loop already exists, pass it straight through - yield loop - else: - # this shadows loop_context's standard behavior - loop = setup_test_loop() - yield loop - teardown_test_loop(loop, fast=fast) - - -def pytest_pycollect_makeitem(collector, name, obj): # type: ignore[no-untyped-def] - """Fix pytest collecting for coroutines.""" - if collector.funcnamefilter(name) and inspect.iscoroutinefunction(obj): - return list(collector._genfunctions(name, obj)) - - -def pytest_pyfunc_call(pyfuncitem): # type: ignore[no-untyped-def] - """Run coroutines in an event loop instead of a normal function call.""" - fast = pyfuncitem.config.getoption("--aiohttp-fast") - if inspect.iscoroutinefunction(pyfuncitem.function): - existing_loop = ( - pyfuncitem.funcargs.get("proactor_loop") - or pyfuncitem.funcargs.get("selector_loop") - or pyfuncitem.funcargs.get("uvloop_loop") - or pyfuncitem.funcargs.get("loop", None) - ) - - with _runtime_warning_context(): - with _passthrough_loop_context(existing_loop, fast=fast) as _loop: - testargs = { - arg: pyfuncitem.funcargs[arg] - for arg in pyfuncitem._fixtureinfo.argnames - } - _loop.run_until_complete(pyfuncitem.obj(**testargs)) - - return True - - -def pytest_generate_tests(metafunc): # type: ignore[no-untyped-def] - if "loop_factory" not in metafunc.fixturenames: - return - - loops = metafunc.config.option.aiohttp_loop - avail_factories: dict[str, Callable[[], asyncio.AbstractEventLoop]] - avail_factories = {"pyloop": asyncio.new_event_loop} - - if uvloop is not None: # pragma: no cover - avail_factories["uvloop"] = uvloop.new_event_loop - - if loops == "all": - loops = "pyloop,uvloop?" - - factories = {} # type: ignore[var-annotated] - for name in loops.split(","): - required = not name.endswith("?") - name = name.strip(" ?") - if name not in avail_factories: # pragma: no cover - if required: - raise ValueError( - "Unknown loop '%s', available loops: %s" - % (name, list(factories.keys())) - ) - else: - continue - factories[name] = avail_factories[name] - metafunc.parametrize( - "loop_factory", list(factories.values()), ids=list(factories.keys()) - ) - - -@pytest.fixture -def loop( - loop_factory: Callable[[], asyncio.AbstractEventLoop], - fast: bool, - loop_debug: bool, -) -> Iterator[asyncio.AbstractEventLoop]: - """Return an instance of the event loop.""" - with loop_context(loop_factory, fast=fast) as _loop: - if loop_debug: - _loop.set_debug(True) # pragma: no cover - asyncio.set_event_loop(_loop) - yield _loop - - -@pytest.fixture -def proactor_loop() -> Iterator[asyncio.AbstractEventLoop]: - factory = asyncio.ProactorEventLoop # type: ignore[attr-defined] - - with loop_context(factory) as _loop: - asyncio.set_event_loop(_loop) - yield _loop - - -@pytest.fixture -def unused_port(aiohttp_unused_port: Callable[[], int]) -> Callable[[], int]: - warnings.warn( - "Deprecated, use aiohttp_unused_port fixture instead", - DeprecationWarning, - stacklevel=2, - ) - return aiohttp_unused_port - - -@pytest.fixture -def aiohttp_unused_port() -> Callable[[], int]: - """Return a port that is unused on the current host.""" - return _unused_port - - -@pytest.fixture -def aiohttp_server(loop: asyncio.AbstractEventLoop) -> Iterator[AiohttpServer]: - """Factory to create a TestServer instance, given an app. - - aiohttp_server(app, **kwargs) - """ - servers = [] - - async def go( - app: Application, - *, - host: str = "127.0.0.1", - port: Optional[int] = None, - **kwargs: Any, - ) -> TestServer: - server = TestServer(app, host=host, port=port) - await server.start_server(loop=loop, **kwargs) - servers.append(server) - return server - - yield go - - async def finalize() -> None: - while servers: - await servers.pop().close() - - loop.run_until_complete(finalize()) - - -@pytest.fixture -def test_server(aiohttp_server): # type: ignore[no-untyped-def] # pragma: no cover - warnings.warn( - "Deprecated, use aiohttp_server fixture instead", - DeprecationWarning, - stacklevel=2, - ) - return aiohttp_server - - -@pytest.fixture -def aiohttp_raw_server(loop: asyncio.AbstractEventLoop) -> Iterator[AiohttpRawServer]: - """Factory to create a RawTestServer instance, given a web handler. - - aiohttp_raw_server(handler, **kwargs) - """ - servers = [] - - async def go( - handler: _RequestHandler, *, port: Optional[int] = None, **kwargs: Any - ) -> RawTestServer: - server = RawTestServer(handler, port=port) - await server.start_server(loop=loop, **kwargs) - servers.append(server) - return server - - yield go - - async def finalize() -> None: - while servers: - await servers.pop().close() - - loop.run_until_complete(finalize()) - - -@pytest.fixture -def raw_test_server( # type: ignore[no-untyped-def] # pragma: no cover - aiohttp_raw_server, -): - warnings.warn( - "Deprecated, use aiohttp_raw_server fixture instead", - DeprecationWarning, - stacklevel=2, - ) - return aiohttp_raw_server - - -@pytest.fixture -def aiohttp_client(loop: asyncio.AbstractEventLoop) -> Iterator[AiohttpClient]: - """Factory to create a TestClient instance. - - aiohttp_client(app, **kwargs) - aiohttp_client(server, **kwargs) - aiohttp_client(raw_server, **kwargs) - """ - clients = [] - - @overload - async def go( - __param: Application, - *, - server_kwargs: Optional[Dict[str, Any]] = None, - **kwargs: Any, - ) -> TestClient[Request, Application]: ... - - @overload - async def go( - __param: BaseTestServer, - *, - server_kwargs: Optional[Dict[str, Any]] = None, - **kwargs: Any, - ) -> TestClient[BaseRequest, None]: ... - - async def go( - __param: Union[Application, BaseTestServer], - *args: Any, - server_kwargs: Optional[Dict[str, Any]] = None, - **kwargs: Any, - ) -> TestClient[Any, Any]: - if isinstance(__param, Callable) and not isinstance( # type: ignore[arg-type] - __param, (Application, BaseTestServer) - ): - __param = __param(loop, *args, **kwargs) - kwargs = {} - else: - assert not args, "args should be empty" - - if isinstance(__param, Application): - server_kwargs = server_kwargs or {} - server = TestServer(__param, loop=loop, **server_kwargs) - client = TestClient(server, loop=loop, **kwargs) - elif isinstance(__param, BaseTestServer): - client = TestClient(__param, loop=loop, **kwargs) - else: - raise ValueError("Unknown argument type: %r" % type(__param)) - - await client.start_server() - clients.append(client) - return client - - yield go - - async def finalize() -> None: - while clients: - await clients.pop().close() - - loop.run_until_complete(finalize()) - - -@pytest.fixture -def test_client(aiohttp_client): # type: ignore[no-untyped-def] # pragma: no cover - warnings.warn( - "Deprecated, use aiohttp_client fixture instead", - DeprecationWarning, - stacklevel=2, - ) - return aiohttp_client diff --git a/venv/lib/python3.9/site-packages/aiohttp/resolver.py b/venv/lib/python3.9/site-packages/aiohttp/resolver.py deleted file mode 100644 index b20e567..0000000 --- a/venv/lib/python3.9/site-packages/aiohttp/resolver.py +++ /dev/null @@ -1,274 +0,0 @@ -import asyncio -import socket -import weakref -from typing import Any, Dict, Final, List, Optional, Tuple, Type, Union - -from .abc import AbstractResolver, ResolveResult - -__all__ = ("ThreadedResolver", "AsyncResolver", "DefaultResolver") - - -try: - import aiodns - - aiodns_default = hasattr(aiodns.DNSResolver, "getaddrinfo") -except ImportError: # pragma: no cover - aiodns = None # type: ignore[assignment] - aiodns_default = False - - -_NUMERIC_SOCKET_FLAGS = socket.AI_NUMERICHOST | socket.AI_NUMERICSERV -_NAME_SOCKET_FLAGS = socket.NI_NUMERICHOST | socket.NI_NUMERICSERV -_AI_ADDRCONFIG = socket.AI_ADDRCONFIG -if hasattr(socket, "AI_MASK"): - _AI_ADDRCONFIG &= socket.AI_MASK - - -class ThreadedResolver(AbstractResolver): - """Threaded resolver. - - Uses an Executor for synchronous getaddrinfo() calls. - concurrent.futures.ThreadPoolExecutor is used by default. - """ - - def __init__(self, loop: Optional[asyncio.AbstractEventLoop] = None) -> None: - self._loop = loop or asyncio.get_running_loop() - - async def resolve( - self, host: str, port: int = 0, family: socket.AddressFamily = socket.AF_INET - ) -> List[ResolveResult]: - infos = await self._loop.getaddrinfo( - host, - port, - type=socket.SOCK_STREAM, - family=family, - flags=_AI_ADDRCONFIG, - ) - - hosts: List[ResolveResult] = [] - for family, _, proto, _, address in infos: - if family == socket.AF_INET6: - if len(address) < 3: - # IPv6 is not supported by Python build, - # or IPv6 is not enabled in the host - continue - if address[3]: - # This is essential for link-local IPv6 addresses. - # LL IPv6 is a VERY rare case. Strictly speaking, we should use - # getnameinfo() unconditionally, but performance makes sense. - resolved_host, _port = await self._loop.getnameinfo( - address, _NAME_SOCKET_FLAGS - ) - port = int(_port) - else: - resolved_host, port = address[:2] - else: # IPv4 - assert family == socket.AF_INET - resolved_host, port = address # type: ignore[misc] - hosts.append( - ResolveResult( - hostname=host, - host=resolved_host, - port=port, - family=family, - proto=proto, - flags=_NUMERIC_SOCKET_FLAGS, - ) - ) - - return hosts - - async def close(self) -> None: - pass - - -class AsyncResolver(AbstractResolver): - """Use the `aiodns` package to make asynchronous DNS lookups""" - - def __init__( - self, - loop: Optional[asyncio.AbstractEventLoop] = None, - *args: Any, - **kwargs: Any, - ) -> None: - if aiodns is None: - raise RuntimeError("Resolver requires aiodns library") - - self._loop = loop or asyncio.get_running_loop() - self._manager: Optional[_DNSResolverManager] = None - # If custom args are provided, create a dedicated resolver instance - # This means each AsyncResolver with custom args gets its own - # aiodns.DNSResolver instance - if args or kwargs: - self._resolver = aiodns.DNSResolver(*args, **kwargs) - return - # Use the shared resolver from the manager for default arguments - self._manager = _DNSResolverManager() - self._resolver = self._manager.get_resolver(self, self._loop) - - if not hasattr(self._resolver, "gethostbyname"): - # aiodns 1.1 is not available, fallback to DNSResolver.query - self.resolve = self._resolve_with_query # type: ignore - - async def resolve( - self, host: str, port: int = 0, family: socket.AddressFamily = socket.AF_INET - ) -> List[ResolveResult]: - try: - resp = await self._resolver.getaddrinfo( - host, - port=port, - type=socket.SOCK_STREAM, - family=family, - flags=_AI_ADDRCONFIG, - ) - except aiodns.error.DNSError as exc: - msg = exc.args[1] if len(exc.args) >= 1 else "DNS lookup failed" - raise OSError(None, msg) from exc - hosts: List[ResolveResult] = [] - for node in resp.nodes: - address: Union[Tuple[bytes, int], Tuple[bytes, int, int, int]] = node.addr - family = node.family - if family == socket.AF_INET6: - if len(address) > 3 and address[3]: - # This is essential for link-local IPv6 addresses. - # LL IPv6 is a VERY rare case. Strictly speaking, we should use - # getnameinfo() unconditionally, but performance makes sense. - result = await self._resolver.getnameinfo( - (address[0].decode("ascii"), *address[1:]), - _NAME_SOCKET_FLAGS, - ) - resolved_host = result.node - else: - resolved_host = address[0].decode("ascii") - port = address[1] - else: # IPv4 - assert family == socket.AF_INET - resolved_host = address[0].decode("ascii") - port = address[1] - hosts.append( - ResolveResult( - hostname=host, - host=resolved_host, - port=port, - family=family, - proto=0, - flags=_NUMERIC_SOCKET_FLAGS, - ) - ) - - if not hosts: - raise OSError(None, "DNS lookup failed") - - return hosts - - async def _resolve_with_query( - self, host: str, port: int = 0, family: int = socket.AF_INET - ) -> List[Dict[str, Any]]: - qtype: Final = "AAAA" if family == socket.AF_INET6 else "A" - - try: - resp = await self._resolver.query(host, qtype) - except aiodns.error.DNSError as exc: - msg = exc.args[1] if len(exc.args) >= 1 else "DNS lookup failed" - raise OSError(None, msg) from exc - - hosts = [] - for rr in resp: - hosts.append( - { - "hostname": host, - "host": rr.host, - "port": port, - "family": family, - "proto": 0, - "flags": socket.AI_NUMERICHOST, - } - ) - - if not hosts: - raise OSError(None, "DNS lookup failed") - - return hosts - - async def close(self) -> None: - if self._manager: - # Release the resolver from the manager if using the shared resolver - self._manager.release_resolver(self, self._loop) - self._manager = None # Clear reference to manager - self._resolver = None # type: ignore[assignment] # Clear reference to resolver - return - # Otherwise cancel our dedicated resolver - if self._resolver is not None: - self._resolver.cancel() - self._resolver = None # type: ignore[assignment] # Clear reference - - -class _DNSResolverManager: - """Manager for aiodns.DNSResolver objects. - - This class manages shared aiodns.DNSResolver instances - with no custom arguments across different event loops. - """ - - _instance: Optional["_DNSResolverManager"] = None - - def __new__(cls) -> "_DNSResolverManager": - if cls._instance is None: - cls._instance = super().__new__(cls) - cls._instance._init() - return cls._instance - - def _init(self) -> None: - # Use WeakKeyDictionary to allow event loops to be garbage collected - self._loop_data: weakref.WeakKeyDictionary[ - asyncio.AbstractEventLoop, - tuple["aiodns.DNSResolver", weakref.WeakSet["AsyncResolver"]], - ] = weakref.WeakKeyDictionary() - - def get_resolver( - self, client: "AsyncResolver", loop: asyncio.AbstractEventLoop - ) -> "aiodns.DNSResolver": - """Get or create the shared aiodns.DNSResolver instance for a specific event loop. - - Args: - client: The AsyncResolver instance requesting the resolver. - This is required to track resolver usage. - loop: The event loop to use for the resolver. - """ - # Create a new resolver and client set for this loop if it doesn't exist - if loop not in self._loop_data: - resolver = aiodns.DNSResolver(loop=loop) - client_set: weakref.WeakSet["AsyncResolver"] = weakref.WeakSet() - self._loop_data[loop] = (resolver, client_set) - else: - # Get the existing resolver and client set - resolver, client_set = self._loop_data[loop] - - # Register this client with the loop - client_set.add(client) - return resolver - - def release_resolver( - self, client: "AsyncResolver", loop: asyncio.AbstractEventLoop - ) -> None: - """Release the resolver for an AsyncResolver client when it's closed. - - Args: - client: The AsyncResolver instance to release. - loop: The event loop the resolver was using. - """ - # Remove client from its loop's tracking - current_loop_data = self._loop_data.get(loop) - if current_loop_data is None: - return - resolver, client_set = current_loop_data - client_set.discard(client) - # If no more clients for this loop, cancel and remove its resolver - if not client_set: - if resolver is not None: - resolver.cancel() - del self._loop_data[loop] - - -_DefaultType = Type[Union[AsyncResolver, ThreadedResolver]] -DefaultResolver: _DefaultType = AsyncResolver if aiodns_default else ThreadedResolver diff --git a/venv/lib/python3.9/site-packages/aiohttp/streams.py b/venv/lib/python3.9/site-packages/aiohttp/streams.py deleted file mode 100644 index 921827e..0000000 --- a/venv/lib/python3.9/site-packages/aiohttp/streams.py +++ /dev/null @@ -1,762 +0,0 @@ -import asyncio -import collections -import warnings -from typing import ( - Awaitable, - Callable, - Deque, - Final, - Generic, - List, - Optional, - Tuple, - TypeVar, -) - -from .base_protocol import BaseProtocol -from .helpers import ( - _EXC_SENTINEL, - BaseTimerContext, - TimerNoop, - set_exception, - set_result, -) -from .http_exceptions import LineTooLong -from .log import internal_logger - -__all__ = ( - "EMPTY_PAYLOAD", - "EofStream", - "StreamReader", - "DataQueue", -) - -_T = TypeVar("_T") - - -class EofStream(Exception): - """eof stream indication.""" - - -class AsyncStreamIterator(Generic[_T]): - - __slots__ = ("read_func",) - - def __init__(self, read_func: Callable[[], Awaitable[_T]]) -> None: - self.read_func = read_func - - def __aiter__(self) -> "AsyncStreamIterator[_T]": - return self - - async def __anext__(self) -> _T: - try: - rv = await self.read_func() - except EofStream: - raise StopAsyncIteration - if rv == b"": - raise StopAsyncIteration - return rv - - -class ChunkTupleAsyncStreamIterator: - - __slots__ = ("_stream",) - - def __init__(self, stream: "StreamReader") -> None: - self._stream = stream - - def __aiter__(self) -> "ChunkTupleAsyncStreamIterator": - return self - - async def __anext__(self) -> Tuple[bytes, bool]: - rv = await self._stream.readchunk() - if rv == (b"", False): - raise StopAsyncIteration - return rv - - -class AsyncStreamReaderMixin: - - __slots__ = () - - def __aiter__(self) -> AsyncStreamIterator[bytes]: - return AsyncStreamIterator(self.readline) # type: ignore[attr-defined] - - def iter_chunked(self, n: int) -> AsyncStreamIterator[bytes]: - """Returns an asynchronous iterator that yields chunks of size n.""" - return AsyncStreamIterator(lambda: self.read(n)) # type: ignore[attr-defined] - - def iter_any(self) -> AsyncStreamIterator[bytes]: - """Yield all available data as soon as it is received.""" - return AsyncStreamIterator(self.readany) # type: ignore[attr-defined] - - def iter_chunks(self) -> ChunkTupleAsyncStreamIterator: - """Yield chunks of data as they are received by the server. - - The yielded objects are tuples - of (bytes, bool) as returned by the StreamReader.readchunk method. - """ - return ChunkTupleAsyncStreamIterator(self) # type: ignore[arg-type] - - -class StreamReader(AsyncStreamReaderMixin): - """An enhancement of asyncio.StreamReader. - - Supports asynchronous iteration by line, chunk or as available:: - - async for line in reader: - ... - async for chunk in reader.iter_chunked(1024): - ... - async for slice in reader.iter_any(): - ... - - """ - - __slots__ = ( - "_protocol", - "_low_water", - "_high_water", - "_low_water_chunks", - "_high_water_chunks", - "_loop", - "_size", - "_cursor", - "_http_chunk_splits", - "_buffer", - "_buffer_offset", - "_eof", - "_waiter", - "_eof_waiter", - "_exception", - "_timer", - "_eof_callbacks", - "_eof_counter", - "total_bytes", - "total_compressed_bytes", - ) - - def __init__( - self, - protocol: BaseProtocol, - limit: int, - *, - timer: Optional[BaseTimerContext] = None, - loop: Optional[asyncio.AbstractEventLoop] = None, - ) -> None: - self._protocol = protocol - self._low_water = limit - self._high_water = limit * 2 - if loop is None: - loop = asyncio.get_event_loop() - # Ensure high_water_chunks >= 3 so it's always > low_water_chunks. - self._high_water_chunks = max(3, limit // 4) - # Use max(2, ...) because there's always at least 1 chunk split remaining - # (the current position), so we need low_water >= 2 to allow resume. - self._low_water_chunks = max(2, self._high_water_chunks // 2) - self._loop = loop - self._size = 0 - self._cursor = 0 - self._http_chunk_splits: Optional[Deque[int]] = None - self._buffer: Deque[bytes] = collections.deque() - self._buffer_offset = 0 - self._eof = False - self._waiter: Optional[asyncio.Future[None]] = None - self._eof_waiter: Optional[asyncio.Future[None]] = None - self._exception: Optional[BaseException] = None - self._timer = TimerNoop() if timer is None else timer - self._eof_callbacks: List[Callable[[], None]] = [] - self._eof_counter = 0 - self.total_bytes = 0 - self.total_compressed_bytes: Optional[int] = None - - def __repr__(self) -> str: - info = [self.__class__.__name__] - if self._size: - info.append("%d bytes" % self._size) - if self._eof: - info.append("eof") - if self._low_water != 2**16: # default limit - info.append("low=%d high=%d" % (self._low_water, self._high_water)) - if self._waiter: - info.append("w=%r" % self._waiter) - if self._exception: - info.append("e=%r" % self._exception) - return "<%s>" % " ".join(info) - - def get_read_buffer_limits(self) -> Tuple[int, int]: - return (self._low_water, self._high_water) - - def exception(self) -> Optional[BaseException]: - return self._exception - - def set_exception( - self, - exc: BaseException, - exc_cause: BaseException = _EXC_SENTINEL, - ) -> None: - self._exception = exc - self._eof_callbacks.clear() - - waiter = self._waiter - if waiter is not None: - self._waiter = None - set_exception(waiter, exc, exc_cause) - - waiter = self._eof_waiter - if waiter is not None: - self._eof_waiter = None - set_exception(waiter, exc, exc_cause) - - def on_eof(self, callback: Callable[[], None]) -> None: - if self._eof: - try: - callback() - except Exception: - internal_logger.exception("Exception in eof callback") - else: - self._eof_callbacks.append(callback) - - def feed_eof(self) -> None: - self._eof = True - - waiter = self._waiter - if waiter is not None: - self._waiter = None - set_result(waiter, None) - - waiter = self._eof_waiter - if waiter is not None: - self._eof_waiter = None - set_result(waiter, None) - - if self._protocol._reading_paused: - self._protocol.resume_reading() - - for cb in self._eof_callbacks: - try: - cb() - except Exception: - internal_logger.exception("Exception in eof callback") - - self._eof_callbacks.clear() - - def is_eof(self) -> bool: - """Return True if 'feed_eof' was called.""" - return self._eof - - def at_eof(self) -> bool: - """Return True if the buffer is empty and 'feed_eof' was called.""" - return self._eof and not self._buffer - - async def wait_eof(self) -> None: - if self._eof: - return - - assert self._eof_waiter is None - self._eof_waiter = self._loop.create_future() - try: - await self._eof_waiter - finally: - self._eof_waiter = None - - @property - def total_raw_bytes(self) -> int: - if self.total_compressed_bytes is None: - return self.total_bytes - return self.total_compressed_bytes - - def unread_data(self, data: bytes) -> None: - """rollback reading some data from stream, inserting it to buffer head.""" - warnings.warn( - "unread_data() is deprecated " - "and will be removed in future releases (#3260)", - DeprecationWarning, - stacklevel=2, - ) - if not data: - return - - if self._buffer_offset: - self._buffer[0] = self._buffer[0][self._buffer_offset :] - self._buffer_offset = 0 - self._size += len(data) - self._cursor -= len(data) - self._buffer.appendleft(data) - self._eof_counter = 0 - - # TODO: size is ignored, remove the param later - def feed_data(self, data: bytes, size: int = 0) -> None: - assert not self._eof, "feed_data after feed_eof" - - if not data: - return - - data_len = len(data) - self._size += data_len - self._buffer.append(data) - self.total_bytes += data_len - - waiter = self._waiter - if waiter is not None: - self._waiter = None - set_result(waiter, None) - - if self._size > self._high_water and not self._protocol._reading_paused: - self._protocol.pause_reading() - - def begin_http_chunk_receiving(self) -> None: - if self._http_chunk_splits is None: - if self.total_bytes: - raise RuntimeError( - "Called begin_http_chunk_receiving when some data was already fed" - ) - self._http_chunk_splits = collections.deque() - - def end_http_chunk_receiving(self) -> None: - if self._http_chunk_splits is None: - raise RuntimeError( - "Called end_chunk_receiving without calling " - "begin_chunk_receiving first" - ) - - # self._http_chunk_splits contains logical byte offsets from start of - # the body transfer. Each offset is the offset of the end of a chunk. - # "Logical" means bytes, accessible for a user. - # If no chunks containing logical data were received, current position - # is difinitely zero. - pos = self._http_chunk_splits[-1] if self._http_chunk_splits else 0 - - if self.total_bytes == pos: - # We should not add empty chunks here. So we check for that. - # Note, when chunked + gzip is used, we can receive a chunk - # of compressed data, but that data may not be enough for gzip FSM - # to yield any uncompressed data. That's why current position may - # not change after receiving a chunk. - return - - self._http_chunk_splits.append(self.total_bytes) - - # If we get too many small chunks before self._high_water is reached, then any - # .read() call becomes computationally expensive, and could block the event loop - # for too long, hence an additional self._high_water_chunks here. - if ( - len(self._http_chunk_splits) > self._high_water_chunks - and not self._protocol._reading_paused - ): - self._protocol.pause_reading() - - # wake up readchunk when end of http chunk received - waiter = self._waiter - if waiter is not None: - self._waiter = None - set_result(waiter, None) - - async def _wait(self, func_name: str) -> None: - if not self._protocol.connected: - raise RuntimeError("Connection closed.") - - # StreamReader uses a future to link the protocol feed_data() method - # to a read coroutine. Running two read coroutines at the same time - # would have an unexpected behaviour. It would not possible to know - # which coroutine would get the next data. - if self._waiter is not None: - raise RuntimeError( - "%s() called while another coroutine is " - "already waiting for incoming data" % func_name - ) - - waiter = self._waiter = self._loop.create_future() - try: - with self._timer: - await waiter - finally: - self._waiter = None - - async def readline(self, *, max_line_length: Optional[int] = None) -> bytes: - return await self.readuntil(max_size=max_line_length) - - async def readuntil( - self, separator: bytes = b"\n", *, max_size: Optional[int] = None - ) -> bytes: - seplen = len(separator) - if seplen == 0: - raise ValueError("Separator should be at least one-byte string") - - if self._exception is not None: - raise self._exception - - chunk = b"" - chunk_size = 0 - not_enough = True - max_size = max_size or self._high_water - - while not_enough: - while self._buffer and not_enough: - offset = self._buffer_offset - ichar = self._buffer[0].find(separator, offset) + 1 - # Read from current offset to found separator or to the end. - data = self._read_nowait_chunk( - ichar - offset + seplen - 1 if ichar else -1 - ) - chunk += data - chunk_size += len(data) - if ichar: - not_enough = False - - if chunk_size > max_size: - raise LineTooLong(chunk[:100] + b"...", max_size) - - if self._eof: - break - - if not_enough: - await self._wait("readuntil") - - return chunk - - async def read(self, n: int = -1) -> bytes: - if self._exception is not None: - raise self._exception - - # migration problem; with DataQueue you have to catch - # EofStream exception, so common way is to run payload.read() inside - # infinite loop. what can cause real infinite loop with StreamReader - # lets keep this code one major release. - if __debug__: - if self._eof and not self._buffer: - self._eof_counter = getattr(self, "_eof_counter", 0) + 1 - if self._eof_counter > 5: - internal_logger.warning( - "Multiple access to StreamReader in eof state, " - "might be infinite loop.", - stack_info=True, - ) - - if not n: - return b"" - - if n < 0: - # This used to just loop creating a new waiter hoping to - # collect everything in self._buffer, but that would - # deadlock if the subprocess sends more than self.limit - # bytes. So just call self.readany() until EOF. - blocks = [] - while True: - block = await self.readany() - if not block: - break - blocks.append(block) - return b"".join(blocks) - - # TODO: should be `if` instead of `while` - # because waiter maybe triggered on chunk end, - # without feeding any data - while not self._buffer and not self._eof: - await self._wait("read") - - return self._read_nowait(n) - - async def readany(self) -> bytes: - if self._exception is not None: - raise self._exception - - # TODO: should be `if` instead of `while` - # because waiter maybe triggered on chunk end, - # without feeding any data - while not self._buffer and not self._eof: - await self._wait("readany") - - return self._read_nowait(-1) - - async def readchunk(self) -> Tuple[bytes, bool]: - """Returns a tuple of (data, end_of_http_chunk). - - When chunked transfer - encoding is used, end_of_http_chunk is a boolean indicating if the end - of the data corresponds to the end of a HTTP chunk , otherwise it is - always False. - """ - while True: - if self._exception is not None: - raise self._exception - - while self._http_chunk_splits: - pos = self._http_chunk_splits.popleft() - if pos == self._cursor: - return (b"", True) - if pos > self._cursor: - return (self._read_nowait(pos - self._cursor), True) - internal_logger.warning( - "Skipping HTTP chunk end due to data " - "consumption beyond chunk boundary" - ) - - if self._buffer: - return (self._read_nowait_chunk(-1), False) - # return (self._read_nowait(-1), False) - - if self._eof: - # Special case for signifying EOF. - # (b'', True) is not a final return value actually. - return (b"", False) - - await self._wait("readchunk") - - async def readexactly(self, n: int) -> bytes: - if self._exception is not None: - raise self._exception - - blocks: List[bytes] = [] - while n > 0: - block = await self.read(n) - if not block: - partial = b"".join(blocks) - raise asyncio.IncompleteReadError(partial, len(partial) + n) - blocks.append(block) - n -= len(block) - - return b"".join(blocks) - - def read_nowait(self, n: int = -1) -> bytes: - # default was changed to be consistent with .read(-1) - # - # I believe the most users don't know about the method and - # they are not affected. - if self._exception is not None: - raise self._exception - - if self._waiter and not self._waiter.done(): - raise RuntimeError( - "Called while some coroutine is waiting for incoming data." - ) - - return self._read_nowait(n) - - def _read_nowait_chunk(self, n: int) -> bytes: - first_buffer = self._buffer[0] - offset = self._buffer_offset - if n != -1 and len(first_buffer) - offset > n: - data = first_buffer[offset : offset + n] - self._buffer_offset += n - - elif offset: - self._buffer.popleft() - data = first_buffer[offset:] - self._buffer_offset = 0 - - else: - data = self._buffer.popleft() - - data_len = len(data) - self._size -= data_len - self._cursor += data_len - - chunk_splits = self._http_chunk_splits - # Prevent memory leak: drop useless chunk splits - while chunk_splits and chunk_splits[0] < self._cursor: - chunk_splits.popleft() - - if ( - self._protocol._reading_paused - and self._size < self._low_water - and ( - self._http_chunk_splits is None - or len(self._http_chunk_splits) < self._low_water_chunks - ) - ): - self._protocol.resume_reading() - return data - - def _read_nowait(self, n: int) -> bytes: - """Read not more than n bytes, or whole buffer if n == -1""" - self._timer.assert_timeout() - - chunks = [] - while self._buffer: - chunk = self._read_nowait_chunk(n) - chunks.append(chunk) - if n != -1: - n -= len(chunk) - if n == 0: - break - - return b"".join(chunks) if chunks else b"" - - -class EmptyStreamReader(StreamReader): # lgtm [py/missing-call-to-init] - - __slots__ = ("_read_eof_chunk",) - - def __init__(self) -> None: - self._read_eof_chunk = False - self.total_bytes = 0 - - def __repr__(self) -> str: - return "<%s>" % self.__class__.__name__ - - def exception(self) -> Optional[BaseException]: - return None - - def set_exception( - self, - exc: BaseException, - exc_cause: BaseException = _EXC_SENTINEL, - ) -> None: - pass - - def on_eof(self, callback: Callable[[], None]) -> None: - try: - callback() - except Exception: - internal_logger.exception("Exception in eof callback") - - def feed_eof(self) -> None: - pass - - def is_eof(self) -> bool: - return True - - def at_eof(self) -> bool: - return True - - async def wait_eof(self) -> None: - return - - def feed_data(self, data: bytes, n: int = 0) -> None: - pass - - async def readline(self, *, max_line_length: Optional[int] = None) -> bytes: - return b"" - - async def read(self, n: int = -1) -> bytes: - return b"" - - # TODO add async def readuntil - - async def readany(self) -> bytes: - return b"" - - async def readchunk(self) -> Tuple[bytes, bool]: - if not self._read_eof_chunk: - self._read_eof_chunk = True - return (b"", False) - - return (b"", True) - - async def readexactly(self, n: int) -> bytes: - raise asyncio.IncompleteReadError(b"", n) - - def read_nowait(self, n: int = -1) -> bytes: - return b"" - - -EMPTY_PAYLOAD: Final[StreamReader] = EmptyStreamReader() - - -class DataQueue(Generic[_T]): - """DataQueue is a general-purpose blocking queue with one reader.""" - - def __init__(self, loop: asyncio.AbstractEventLoop) -> None: - self._loop = loop - self._eof = False - self._waiter: Optional[asyncio.Future[None]] = None - self._exception: Optional[BaseException] = None - self._buffer: Deque[Tuple[_T, int]] = collections.deque() - - def __len__(self) -> int: - return len(self._buffer) - - def is_eof(self) -> bool: - return self._eof - - def at_eof(self) -> bool: - return self._eof and not self._buffer - - def exception(self) -> Optional[BaseException]: - return self._exception - - def set_exception( - self, - exc: BaseException, - exc_cause: BaseException = _EXC_SENTINEL, - ) -> None: - self._eof = True - self._exception = exc - if (waiter := self._waiter) is not None: - self._waiter = None - set_exception(waiter, exc, exc_cause) - - def feed_data(self, data: _T, size: int = 0) -> None: - self._buffer.append((data, size)) - if (waiter := self._waiter) is not None: - self._waiter = None - set_result(waiter, None) - - def feed_eof(self) -> None: - self._eof = True - if (waiter := self._waiter) is not None: - self._waiter = None - set_result(waiter, None) - - async def read(self) -> _T: - if not self._buffer and not self._eof: - assert not self._waiter - self._waiter = self._loop.create_future() - try: - await self._waiter - except (asyncio.CancelledError, asyncio.TimeoutError): - self._waiter = None - raise - if self._buffer: - data, _ = self._buffer.popleft() - return data - if self._exception is not None: - raise self._exception - raise EofStream - - def __aiter__(self) -> AsyncStreamIterator[_T]: - return AsyncStreamIterator(self.read) - - -class FlowControlDataQueue(DataQueue[_T]): - """FlowControlDataQueue resumes and pauses an underlying stream. - - It is a destination for parsed data. - - This class is deprecated and will be removed in version 4.0. - """ - - def __init__( - self, protocol: BaseProtocol, limit: int, *, loop: asyncio.AbstractEventLoop - ) -> None: - super().__init__(loop=loop) - self._size = 0 - self._protocol = protocol - self._limit = limit * 2 - - def feed_data(self, data: _T, size: int = 0) -> None: - super().feed_data(data, size) - self._size += size - - if self._size > self._limit and not self._protocol._reading_paused: - self._protocol.pause_reading() - - async def read(self) -> _T: - if not self._buffer and not self._eof: - assert not self._waiter - self._waiter = self._loop.create_future() - try: - await self._waiter - except (asyncio.CancelledError, asyncio.TimeoutError): - self._waiter = None - raise - if self._buffer: - data, size = self._buffer.popleft() - self._size -= size - if self._size < self._limit and self._protocol._reading_paused: - self._protocol.resume_reading() - return data - if self._exception is not None: - raise self._exception - raise EofStream diff --git a/venv/lib/python3.9/site-packages/aiohttp/tcp_helpers.py b/venv/lib/python3.9/site-packages/aiohttp/tcp_helpers.py deleted file mode 100644 index 88b2442..0000000 --- a/venv/lib/python3.9/site-packages/aiohttp/tcp_helpers.py +++ /dev/null @@ -1,37 +0,0 @@ -"""Helper methods to tune a TCP connection""" - -import asyncio -import socket -from contextlib import suppress -from typing import Optional # noqa - -__all__ = ("tcp_keepalive", "tcp_nodelay") - - -if hasattr(socket, "SO_KEEPALIVE"): - - def tcp_keepalive(transport: asyncio.Transport) -> None: - sock = transport.get_extra_info("socket") - if sock is not None: - sock.setsockopt(socket.SOL_SOCKET, socket.SO_KEEPALIVE, 1) - -else: - - def tcp_keepalive(transport: asyncio.Transport) -> None: # pragma: no cover - pass - - -def tcp_nodelay(transport: asyncio.Transport, value: bool) -> None: - sock = transport.get_extra_info("socket") - - if sock is None: - return - - if sock.family not in (socket.AF_INET, socket.AF_INET6): - return - - value = bool(value) - - # socket may be closed already, on windows OSError get raised - with suppress(OSError): - sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, value) diff --git a/venv/lib/python3.9/site-packages/aiohttp/test_utils.py b/venv/lib/python3.9/site-packages/aiohttp/test_utils.py deleted file mode 100644 index 34b77d4..0000000 --- a/venv/lib/python3.9/site-packages/aiohttp/test_utils.py +++ /dev/null @@ -1,777 +0,0 @@ -"""Utilities shared by tests.""" - -import asyncio -import contextlib -import gc -import inspect -import ipaddress -import os -import socket -import sys -import warnings -from abc import ABC, abstractmethod -from types import TracebackType -from typing import ( - TYPE_CHECKING, - Any, - Callable, - Generic, - Iterator, - List, - Optional, - Type, - TypeVar, - cast, - overload, -) -from unittest import IsolatedAsyncioTestCase, mock - -from aiosignal import Signal -from multidict import CIMultiDict, CIMultiDictProxy -from yarl import URL - -import aiohttp -from aiohttp.client import ( - _RequestContextManager, - _RequestOptions, - _WSRequestContextManager, -) - -from . import ClientSession, hdrs -from .abc import AbstractCookieJar -from .client_reqrep import ClientResponse -from .client_ws import ClientWebSocketResponse -from .helpers import sentinel -from .http import HttpVersion, RawRequestMessage -from .streams import EMPTY_PAYLOAD, StreamReader -from .typedefs import StrOrURL -from .web import ( - Application, - AppRunner, - BaseRequest, - BaseRunner, - Request, - Server, - ServerRunner, - SockSite, - UrlMappingMatchInfo, -) -from .web_protocol import _RequestHandler - -if TYPE_CHECKING: - from ssl import SSLContext -else: - SSLContext = None - -if sys.version_info >= (3, 11) and TYPE_CHECKING: - from typing import Unpack - -if sys.version_info >= (3, 11): - from typing import Self -else: - Self = Any - -_ApplicationNone = TypeVar("_ApplicationNone", Application, None) -_Request = TypeVar("_Request", bound=BaseRequest) - -REUSE_ADDRESS = os.name == "posix" and sys.platform != "cygwin" - - -def get_unused_port_socket( - host: str, family: socket.AddressFamily = socket.AF_INET -) -> socket.socket: - return get_port_socket(host, 0, family) - - -def get_port_socket( - host: str, port: int, family: socket.AddressFamily -) -> socket.socket: - s = socket.socket(family, socket.SOCK_STREAM) - if REUSE_ADDRESS: - # Windows has different semantics for SO_REUSEADDR, - # so don't set it. Ref: - # https://docs.microsoft.com/en-us/windows/win32/winsock/using-so-reuseaddr-and-so-exclusiveaddruse - s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) - s.bind((host, port)) - return s - - -def unused_port() -> int: - """Return a port that is unused on the current host.""" - with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s: - s.bind(("127.0.0.1", 0)) - return cast(int, s.getsockname()[1]) - - -class BaseTestServer(ABC): - __test__ = False - - def __init__( - self, - *, - scheme: str = "", - loop: Optional[asyncio.AbstractEventLoop] = None, - host: str = "127.0.0.1", - port: Optional[int] = None, - skip_url_asserts: bool = False, - socket_factory: Callable[ - [str, int, socket.AddressFamily], socket.socket - ] = get_port_socket, - **kwargs: Any, - ) -> None: - self._loop = loop - self.runner: Optional[BaseRunner] = None - self._root: Optional[URL] = None - self.host = host - self.port = port - self._closed = False - self.scheme = scheme - self.skip_url_asserts = skip_url_asserts - self.socket_factory = socket_factory - - async def start_server( - self, loop: Optional[asyncio.AbstractEventLoop] = None, **kwargs: Any - ) -> None: - if self.runner: - return - self._loop = loop - self._ssl = kwargs.pop("ssl", None) - self.runner = await self._make_runner(handler_cancellation=True, **kwargs) - await self.runner.setup() - if not self.port: - self.port = 0 - absolute_host = self.host - try: - version = ipaddress.ip_address(self.host).version - except ValueError: - version = 4 - if version == 6: - absolute_host = f"[{self.host}]" - family = socket.AF_INET6 if version == 6 else socket.AF_INET - _sock = self.socket_factory(self.host, self.port, family) - self.host, self.port = _sock.getsockname()[:2] - site = SockSite(self.runner, sock=_sock, ssl_context=self._ssl) - await site.start() - server = site._server - assert server is not None - sockets = server.sockets # type: ignore[attr-defined] - assert sockets is not None - self.port = sockets[0].getsockname()[1] - if not self.scheme: - self.scheme = "https" if self._ssl else "http" - self._root = URL(f"{self.scheme}://{absolute_host}:{self.port}") - - @abstractmethod # pragma: no cover - async def _make_runner(self, **kwargs: Any) -> BaseRunner: - pass - - def make_url(self, path: StrOrURL) -> URL: - assert self._root is not None - url = URL(path) - if not self.skip_url_asserts: - assert not url.absolute - return self._root.join(url) - else: - return URL(str(self._root) + str(path)) - - @property - def started(self) -> bool: - return self.runner is not None - - @property - def closed(self) -> bool: - return self._closed - - @property - def handler(self) -> Server: - # for backward compatibility - # web.Server instance - runner = self.runner - assert runner is not None - assert runner.server is not None - return runner.server - - async def close(self) -> None: - """Close all fixtures created by the test client. - - After that point, the TestClient is no longer usable. - - This is an idempotent function: running close multiple times - will not have any additional effects. - - close is also run when the object is garbage collected, and on - exit when used as a context manager. - - """ - if self.started and not self.closed: - assert self.runner is not None - await self.runner.cleanup() - self._root = None - self.port = None - self._closed = True - - def __enter__(self) -> None: - raise TypeError("Use async with instead") - - def __exit__( - self, - exc_type: Optional[Type[BaseException]], - exc_value: Optional[BaseException], - traceback: Optional[TracebackType], - ) -> None: - # __exit__ should exist in pair with __enter__ but never executed - pass # pragma: no cover - - async def __aenter__(self) -> "BaseTestServer": - await self.start_server(loop=self._loop) - return self - - async def __aexit__( - self, - exc_type: Optional[Type[BaseException]], - exc_value: Optional[BaseException], - traceback: Optional[TracebackType], - ) -> None: - await self.close() - - -class TestServer(BaseTestServer): - def __init__( - self, - app: Application, - *, - scheme: str = "", - host: str = "127.0.0.1", - port: Optional[int] = None, - **kwargs: Any, - ): - self.app = app - super().__init__(scheme=scheme, host=host, port=port, **kwargs) - - async def _make_runner(self, **kwargs: Any) -> BaseRunner: - return AppRunner(self.app, **kwargs) - - -class RawTestServer(BaseTestServer): - def __init__( - self, - handler: _RequestHandler, - *, - scheme: str = "", - host: str = "127.0.0.1", - port: Optional[int] = None, - **kwargs: Any, - ) -> None: - self._handler = handler - super().__init__(scheme=scheme, host=host, port=port, **kwargs) - - async def _make_runner(self, debug: bool = True, **kwargs: Any) -> ServerRunner: - srv = Server(self._handler, loop=self._loop, debug=debug, **kwargs) - return ServerRunner(srv, debug=debug, **kwargs) - - -class TestClient(Generic[_Request, _ApplicationNone]): - """ - A test client implementation. - - To write functional tests for aiohttp based servers. - - """ - - __test__ = False - - @overload - def __init__( - self: "TestClient[Request, Application]", - server: TestServer, - *, - cookie_jar: Optional[AbstractCookieJar] = None, - **kwargs: Any, - ) -> None: ... - @overload - def __init__( - self: "TestClient[_Request, None]", - server: BaseTestServer, - *, - cookie_jar: Optional[AbstractCookieJar] = None, - **kwargs: Any, - ) -> None: ... - def __init__( - self, - server: BaseTestServer, - *, - cookie_jar: Optional[AbstractCookieJar] = None, - loop: Optional[asyncio.AbstractEventLoop] = None, - **kwargs: Any, - ) -> None: - if not isinstance(server, BaseTestServer): - raise TypeError( - "server must be TestServer instance, found type: %r" % type(server) - ) - self._server = server - self._loop = loop - if cookie_jar is None: - cookie_jar = aiohttp.CookieJar(unsafe=True, loop=loop) - self._session = ClientSession(loop=loop, cookie_jar=cookie_jar, **kwargs) - self._session._retry_connection = False - self._closed = False - self._responses: List[ClientResponse] = [] - self._websockets: List[ClientWebSocketResponse] = [] - - async def start_server(self) -> None: - await self._server.start_server(loop=self._loop) - - @property - def host(self) -> str: - return self._server.host - - @property - def port(self) -> Optional[int]: - return self._server.port - - @property - def server(self) -> BaseTestServer: - return self._server - - @property - def app(self) -> _ApplicationNone: - return getattr(self._server, "app", None) # type: ignore[return-value] - - @property - def session(self) -> ClientSession: - """An internal aiohttp.ClientSession. - - Unlike the methods on the TestClient, client session requests - do not automatically include the host in the url queried, and - will require an absolute path to the resource. - - """ - return self._session - - def make_url(self, path: StrOrURL) -> URL: - return self._server.make_url(path) - - async def _request( - self, method: str, path: StrOrURL, **kwargs: Any - ) -> ClientResponse: - resp = await self._session.request(method, self.make_url(path), **kwargs) - # save it to close later - self._responses.append(resp) - return resp - - if sys.version_info >= (3, 11) and TYPE_CHECKING: - - def request( - self, method: str, path: StrOrURL, **kwargs: Unpack[_RequestOptions] - ) -> _RequestContextManager: ... - - def get( - self, - path: StrOrURL, - **kwargs: Unpack[_RequestOptions], - ) -> _RequestContextManager: ... - - def options( - self, - path: StrOrURL, - **kwargs: Unpack[_RequestOptions], - ) -> _RequestContextManager: ... - - def head( - self, - path: StrOrURL, - **kwargs: Unpack[_RequestOptions], - ) -> _RequestContextManager: ... - - def post( - self, - path: StrOrURL, - **kwargs: Unpack[_RequestOptions], - ) -> _RequestContextManager: ... - - def put( - self, - path: StrOrURL, - **kwargs: Unpack[_RequestOptions], - ) -> _RequestContextManager: ... - - def patch( - self, - path: StrOrURL, - **kwargs: Unpack[_RequestOptions], - ) -> _RequestContextManager: ... - - def delete( - self, - path: StrOrURL, - **kwargs: Unpack[_RequestOptions], - ) -> _RequestContextManager: ... - - else: - - def request( - self, method: str, path: StrOrURL, **kwargs: Any - ) -> _RequestContextManager: - """Routes a request to tested http server. - - The interface is identical to aiohttp.ClientSession.request, - except the loop kwarg is overridden by the instance used by the - test server. - - """ - return _RequestContextManager(self._request(method, path, **kwargs)) - - def get(self, path: StrOrURL, **kwargs: Any) -> _RequestContextManager: - """Perform an HTTP GET request.""" - return _RequestContextManager(self._request(hdrs.METH_GET, path, **kwargs)) - - def post(self, path: StrOrURL, **kwargs: Any) -> _RequestContextManager: - """Perform an HTTP POST request.""" - return _RequestContextManager(self._request(hdrs.METH_POST, path, **kwargs)) - - def options(self, path: StrOrURL, **kwargs: Any) -> _RequestContextManager: - """Perform an HTTP OPTIONS request.""" - return _RequestContextManager( - self._request(hdrs.METH_OPTIONS, path, **kwargs) - ) - - def head(self, path: StrOrURL, **kwargs: Any) -> _RequestContextManager: - """Perform an HTTP HEAD request.""" - return _RequestContextManager(self._request(hdrs.METH_HEAD, path, **kwargs)) - - def put(self, path: StrOrURL, **kwargs: Any) -> _RequestContextManager: - """Perform an HTTP PUT request.""" - return _RequestContextManager(self._request(hdrs.METH_PUT, path, **kwargs)) - - def patch(self, path: StrOrURL, **kwargs: Any) -> _RequestContextManager: - """Perform an HTTP PATCH request.""" - return _RequestContextManager( - self._request(hdrs.METH_PATCH, path, **kwargs) - ) - - def delete(self, path: StrOrURL, **kwargs: Any) -> _RequestContextManager: - """Perform an HTTP PATCH request.""" - return _RequestContextManager( - self._request(hdrs.METH_DELETE, path, **kwargs) - ) - - def ws_connect(self, path: StrOrURL, **kwargs: Any) -> _WSRequestContextManager: - """Initiate websocket connection. - - The api corresponds to aiohttp.ClientSession.ws_connect. - - """ - return _WSRequestContextManager(self._ws_connect(path, **kwargs)) - - async def _ws_connect( - self, path: StrOrURL, **kwargs: Any - ) -> ClientWebSocketResponse: - ws = await self._session.ws_connect(self.make_url(path), **kwargs) - self._websockets.append(ws) - return ws - - async def close(self) -> None: - """Close all fixtures created by the test client. - - After that point, the TestClient is no longer usable. - - This is an idempotent function: running close multiple times - will not have any additional effects. - - close is also run on exit when used as a(n) (asynchronous) - context manager. - - """ - if not self._closed: - for resp in self._responses: - resp.close() - for ws in self._websockets: - await ws.close() - await self._session.close() - await self._server.close() - self._closed = True - - def __enter__(self) -> None: - raise TypeError("Use async with instead") - - def __exit__( - self, - exc_type: Optional[Type[BaseException]], - exc: Optional[BaseException], - tb: Optional[TracebackType], - ) -> None: - # __exit__ should exist in pair with __enter__ but never executed - pass # pragma: no cover - - async def __aenter__(self) -> Self: - await self.start_server() - return self - - async def __aexit__( - self, - exc_type: Optional[Type[BaseException]], - exc: Optional[BaseException], - tb: Optional[TracebackType], - ) -> None: - await self.close() - - -class AioHTTPTestCase(IsolatedAsyncioTestCase): - """A base class to allow for unittest web applications using aiohttp. - - Provides the following: - - * self.client (aiohttp.test_utils.TestClient): an aiohttp test client. - * self.loop (asyncio.BaseEventLoop): the event loop in which the - application and server are running. - * self.app (aiohttp.web.Application): the application returned by - self.get_application() - - Note that the TestClient's methods are asynchronous: you have to - execute function on the test client using asynchronous methods. - """ - - async def get_application(self) -> Application: - """Get application. - - This method should be overridden - to return the aiohttp.web.Application - object to test. - """ - return self.get_app() - - def get_app(self) -> Application: - """Obsolete method used to constructing web application. - - Use .get_application() coroutine instead. - """ - raise RuntimeError("Did you forget to define get_application()?") - - async def asyncSetUp(self) -> None: - self.loop = asyncio.get_running_loop() - return await self.setUpAsync() - - async def setUpAsync(self) -> None: - self.app = await self.get_application() - self.server = await self.get_server(self.app) - self.client = await self.get_client(self.server) - - await self.client.start_server() - - async def asyncTearDown(self) -> None: - return await self.tearDownAsync() - - async def tearDownAsync(self) -> None: - await self.client.close() - - async def get_server(self, app: Application) -> TestServer: - """Return a TestServer instance.""" - return TestServer(app, loop=self.loop) - - async def get_client(self, server: TestServer) -> TestClient[Request, Application]: - """Return a TestClient instance.""" - return TestClient(server, loop=self.loop) - - -def unittest_run_loop(func: Any, *args: Any, **kwargs: Any) -> Any: - """ - A decorator dedicated to use with asynchronous AioHTTPTestCase test methods. - - In 3.8+, this does nothing. - """ - warnings.warn( - "Decorator `@unittest_run_loop` is no longer needed in aiohttp 3.8+", - DeprecationWarning, - stacklevel=2, - ) - return func - - -_LOOP_FACTORY = Callable[[], asyncio.AbstractEventLoop] - - -@contextlib.contextmanager -def loop_context( - loop_factory: _LOOP_FACTORY = asyncio.new_event_loop, fast: bool = False -) -> Iterator[asyncio.AbstractEventLoop]: - """A contextmanager that creates an event_loop, for test purposes. - - Handles the creation and cleanup of a test loop. - """ - loop = setup_test_loop(loop_factory) - yield loop - teardown_test_loop(loop, fast=fast) - - -def setup_test_loop( - loop_factory: _LOOP_FACTORY = asyncio.new_event_loop, -) -> asyncio.AbstractEventLoop: - """Create and return an asyncio.BaseEventLoop instance. - - The caller should also call teardown_test_loop, - once they are done with the loop. - """ - loop = loop_factory() - asyncio.set_event_loop(loop) - return loop - - -def teardown_test_loop(loop: asyncio.AbstractEventLoop, fast: bool = False) -> None: - """Teardown and cleanup an event_loop created by setup_test_loop.""" - closed = loop.is_closed() - if not closed: - loop.call_soon(loop.stop) - loop.run_forever() - loop.close() - - if not fast: - gc.collect() - - asyncio.set_event_loop(None) - - -def _create_app_mock() -> mock.MagicMock: - def get_dict(app: Any, key: str) -> Any: - return app.__app_dict[key] - - def set_dict(app: Any, key: str, value: Any) -> None: - app.__app_dict[key] = value - - app = mock.MagicMock(spec=Application) - app.__app_dict = {} - app.__getitem__ = get_dict - app.__setitem__ = set_dict - - app._debug = False - app.on_response_prepare = Signal(app) - app.on_response_prepare.freeze() - return app - - -def _create_transport(sslcontext: Optional[SSLContext] = None) -> mock.Mock: - transport = mock.Mock() - - def get_extra_info(key: str) -> Optional[SSLContext]: - if key == "sslcontext": - return sslcontext - else: - return None - - transport.get_extra_info.side_effect = get_extra_info - return transport - - -def make_mocked_request( - method: str, - path: str, - headers: Any = None, - *, - match_info: Any = sentinel, - version: HttpVersion = HttpVersion(1, 1), - closing: bool = False, - app: Any = None, - writer: Any = sentinel, - protocol: Any = sentinel, - transport: Any = sentinel, - payload: StreamReader = EMPTY_PAYLOAD, - sslcontext: Optional[SSLContext] = None, - client_max_size: int = 1024**2, - loop: Any = ..., -) -> Request: - """Creates mocked web.Request testing purposes. - - Useful in unit tests, when spinning full web server is overkill or - specific conditions and errors are hard to trigger. - """ - task = mock.Mock() - if loop is ...: - # no loop passed, try to get the current one if - # its is running as we need a real loop to create - # executor jobs to be able to do testing - # with a real executor - try: - loop = asyncio.get_running_loop() - except RuntimeError: - loop = mock.Mock() - loop.create_future.return_value = () - - if version < HttpVersion(1, 1): - closing = True - - if headers: - headers = CIMultiDictProxy(CIMultiDict(headers)) - raw_hdrs = tuple( - (k.encode("utf-8"), v.encode("utf-8")) for k, v in headers.items() - ) - else: - headers = CIMultiDictProxy(CIMultiDict()) - raw_hdrs = () - - chunked = "chunked" in headers.get(hdrs.TRANSFER_ENCODING, "").lower() - - message = RawRequestMessage( - method, - path, - version, - headers, - raw_hdrs, - closing, - None, - False, - chunked, - URL(path), - ) - if app is None: - app = _create_app_mock() - - if transport is sentinel: - transport = _create_transport(sslcontext) - - if protocol is sentinel: - protocol = mock.Mock() - protocol.max_field_size = 8190 - protocol.max_line_length = 8190 - protocol.max_headers = 128 - protocol.transport = transport - type(protocol).peername = mock.PropertyMock( - return_value=transport.get_extra_info("peername") - ) - type(protocol).ssl_context = mock.PropertyMock(return_value=sslcontext) - - if writer is sentinel: - writer = mock.Mock() - writer.write_headers = make_mocked_coro(None) - writer.write = make_mocked_coro(None) - writer.write_eof = make_mocked_coro(None) - writer.drain = make_mocked_coro(None) - writer.transport = transport - - protocol.transport = transport - protocol.writer = writer - - req = Request( - message, payload, protocol, writer, task, loop, client_max_size=client_max_size - ) - - match_info = UrlMappingMatchInfo( - {} if match_info is sentinel else match_info, mock.Mock() - ) - match_info.add_app(app) - req._match_info = match_info - - return req - - -def make_mocked_coro( - return_value: Any = sentinel, raise_exception: Any = sentinel -) -> Any: - """Creates a coroutine mock.""" - - async def mock_coro(*args: Any, **kwargs: Any) -> Any: - if raise_exception is not sentinel: - raise raise_exception - if not inspect.isawaitable(return_value): - return return_value - await return_value - - return mock.Mock(wraps=mock_coro) diff --git a/venv/lib/python3.9/site-packages/aiohttp/tracing.py b/venv/lib/python3.9/site-packages/aiohttp/tracing.py deleted file mode 100644 index 568fa7f..0000000 --- a/venv/lib/python3.9/site-packages/aiohttp/tracing.py +++ /dev/null @@ -1,455 +0,0 @@ -from types import SimpleNamespace -from typing import TYPE_CHECKING, Mapping, Optional, Type, TypeVar - -import attr -from aiosignal import Signal -from multidict import CIMultiDict -from yarl import URL - -from .client_reqrep import ClientResponse - -if TYPE_CHECKING: - from .client import ClientSession - - _ParamT_contra = TypeVar("_ParamT_contra", contravariant=True) - _TracingSignal = Signal[ClientSession, SimpleNamespace, _ParamT_contra] - - -__all__ = ( - "TraceConfig", - "TraceRequestStartParams", - "TraceRequestEndParams", - "TraceRequestExceptionParams", - "TraceConnectionQueuedStartParams", - "TraceConnectionQueuedEndParams", - "TraceConnectionCreateStartParams", - "TraceConnectionCreateEndParams", - "TraceConnectionReuseconnParams", - "TraceDnsResolveHostStartParams", - "TraceDnsResolveHostEndParams", - "TraceDnsCacheHitParams", - "TraceDnsCacheMissParams", - "TraceRequestRedirectParams", - "TraceRequestChunkSentParams", - "TraceResponseChunkReceivedParams", - "TraceRequestHeadersSentParams", -) - - -class TraceConfig: - """First-class used to trace requests launched via ClientSession objects.""" - - def __init__( - self, trace_config_ctx_factory: Type[SimpleNamespace] = SimpleNamespace - ) -> None: - self._on_request_start: _TracingSignal[TraceRequestStartParams] = Signal(self) - self._on_request_chunk_sent: _TracingSignal[TraceRequestChunkSentParams] = ( - Signal(self) - ) - self._on_response_chunk_received: _TracingSignal[ - TraceResponseChunkReceivedParams - ] = Signal(self) - self._on_request_end: _TracingSignal[TraceRequestEndParams] = Signal(self) - self._on_request_exception: _TracingSignal[TraceRequestExceptionParams] = ( - Signal(self) - ) - self._on_request_redirect: _TracingSignal[TraceRequestRedirectParams] = Signal( - self - ) - self._on_connection_queued_start: _TracingSignal[ - TraceConnectionQueuedStartParams - ] = Signal(self) - self._on_connection_queued_end: _TracingSignal[ - TraceConnectionQueuedEndParams - ] = Signal(self) - self._on_connection_create_start: _TracingSignal[ - TraceConnectionCreateStartParams - ] = Signal(self) - self._on_connection_create_end: _TracingSignal[ - TraceConnectionCreateEndParams - ] = Signal(self) - self._on_connection_reuseconn: _TracingSignal[ - TraceConnectionReuseconnParams - ] = Signal(self) - self._on_dns_resolvehost_start: _TracingSignal[ - TraceDnsResolveHostStartParams - ] = Signal(self) - self._on_dns_resolvehost_end: _TracingSignal[TraceDnsResolveHostEndParams] = ( - Signal(self) - ) - self._on_dns_cache_hit: _TracingSignal[TraceDnsCacheHitParams] = Signal(self) - self._on_dns_cache_miss: _TracingSignal[TraceDnsCacheMissParams] = Signal(self) - self._on_request_headers_sent: _TracingSignal[TraceRequestHeadersSentParams] = ( - Signal(self) - ) - - self._trace_config_ctx_factory = trace_config_ctx_factory - - def trace_config_ctx( - self, trace_request_ctx: Optional[Mapping[str, str]] = None - ) -> SimpleNamespace: - """Return a new trace_config_ctx instance""" - return self._trace_config_ctx_factory(trace_request_ctx=trace_request_ctx) - - def freeze(self) -> None: - self._on_request_start.freeze() - self._on_request_chunk_sent.freeze() - self._on_response_chunk_received.freeze() - self._on_request_end.freeze() - self._on_request_exception.freeze() - self._on_request_redirect.freeze() - self._on_connection_queued_start.freeze() - self._on_connection_queued_end.freeze() - self._on_connection_create_start.freeze() - self._on_connection_create_end.freeze() - self._on_connection_reuseconn.freeze() - self._on_dns_resolvehost_start.freeze() - self._on_dns_resolvehost_end.freeze() - self._on_dns_cache_hit.freeze() - self._on_dns_cache_miss.freeze() - self._on_request_headers_sent.freeze() - - @property - def on_request_start(self) -> "_TracingSignal[TraceRequestStartParams]": - return self._on_request_start - - @property - def on_request_chunk_sent( - self, - ) -> "_TracingSignal[TraceRequestChunkSentParams]": - return self._on_request_chunk_sent - - @property - def on_response_chunk_received( - self, - ) -> "_TracingSignal[TraceResponseChunkReceivedParams]": - return self._on_response_chunk_received - - @property - def on_request_end(self) -> "_TracingSignal[TraceRequestEndParams]": - return self._on_request_end - - @property - def on_request_exception( - self, - ) -> "_TracingSignal[TraceRequestExceptionParams]": - return self._on_request_exception - - @property - def on_request_redirect( - self, - ) -> "_TracingSignal[TraceRequestRedirectParams]": - return self._on_request_redirect - - @property - def on_connection_queued_start( - self, - ) -> "_TracingSignal[TraceConnectionQueuedStartParams]": - return self._on_connection_queued_start - - @property - def on_connection_queued_end( - self, - ) -> "_TracingSignal[TraceConnectionQueuedEndParams]": - return self._on_connection_queued_end - - @property - def on_connection_create_start( - self, - ) -> "_TracingSignal[TraceConnectionCreateStartParams]": - return self._on_connection_create_start - - @property - def on_connection_create_end( - self, - ) -> "_TracingSignal[TraceConnectionCreateEndParams]": - return self._on_connection_create_end - - @property - def on_connection_reuseconn( - self, - ) -> "_TracingSignal[TraceConnectionReuseconnParams]": - return self._on_connection_reuseconn - - @property - def on_dns_resolvehost_start( - self, - ) -> "_TracingSignal[TraceDnsResolveHostStartParams]": - return self._on_dns_resolvehost_start - - @property - def on_dns_resolvehost_end( - self, - ) -> "_TracingSignal[TraceDnsResolveHostEndParams]": - return self._on_dns_resolvehost_end - - @property - def on_dns_cache_hit(self) -> "_TracingSignal[TraceDnsCacheHitParams]": - return self._on_dns_cache_hit - - @property - def on_dns_cache_miss(self) -> "_TracingSignal[TraceDnsCacheMissParams]": - return self._on_dns_cache_miss - - @property - def on_request_headers_sent( - self, - ) -> "_TracingSignal[TraceRequestHeadersSentParams]": - return self._on_request_headers_sent - - -@attr.s(auto_attribs=True, frozen=True, slots=True) -class TraceRequestStartParams: - """Parameters sent by the `on_request_start` signal""" - - method: str - url: URL - headers: "CIMultiDict[str]" - - -@attr.s(auto_attribs=True, frozen=True, slots=True) -class TraceRequestChunkSentParams: - """Parameters sent by the `on_request_chunk_sent` signal""" - - method: str - url: URL - chunk: bytes - - -@attr.s(auto_attribs=True, frozen=True, slots=True) -class TraceResponseChunkReceivedParams: - """Parameters sent by the `on_response_chunk_received` signal""" - - method: str - url: URL - chunk: bytes - - -@attr.s(auto_attribs=True, frozen=True, slots=True) -class TraceRequestEndParams: - """Parameters sent by the `on_request_end` signal""" - - method: str - url: URL - headers: "CIMultiDict[str]" - response: ClientResponse - - -@attr.s(auto_attribs=True, frozen=True, slots=True) -class TraceRequestExceptionParams: - """Parameters sent by the `on_request_exception` signal""" - - method: str - url: URL - headers: "CIMultiDict[str]" - exception: BaseException - - -@attr.s(auto_attribs=True, frozen=True, slots=True) -class TraceRequestRedirectParams: - """Parameters sent by the `on_request_redirect` signal""" - - method: str - url: URL - headers: "CIMultiDict[str]" - response: ClientResponse - - -@attr.s(auto_attribs=True, frozen=True, slots=True) -class TraceConnectionQueuedStartParams: - """Parameters sent by the `on_connection_queued_start` signal""" - - -@attr.s(auto_attribs=True, frozen=True, slots=True) -class TraceConnectionQueuedEndParams: - """Parameters sent by the `on_connection_queued_end` signal""" - - -@attr.s(auto_attribs=True, frozen=True, slots=True) -class TraceConnectionCreateStartParams: - """Parameters sent by the `on_connection_create_start` signal""" - - -@attr.s(auto_attribs=True, frozen=True, slots=True) -class TraceConnectionCreateEndParams: - """Parameters sent by the `on_connection_create_end` signal""" - - -@attr.s(auto_attribs=True, frozen=True, slots=True) -class TraceConnectionReuseconnParams: - """Parameters sent by the `on_connection_reuseconn` signal""" - - -@attr.s(auto_attribs=True, frozen=True, slots=True) -class TraceDnsResolveHostStartParams: - """Parameters sent by the `on_dns_resolvehost_start` signal""" - - host: str - - -@attr.s(auto_attribs=True, frozen=True, slots=True) -class TraceDnsResolveHostEndParams: - """Parameters sent by the `on_dns_resolvehost_end` signal""" - - host: str - - -@attr.s(auto_attribs=True, frozen=True, slots=True) -class TraceDnsCacheHitParams: - """Parameters sent by the `on_dns_cache_hit` signal""" - - host: str - - -@attr.s(auto_attribs=True, frozen=True, slots=True) -class TraceDnsCacheMissParams: - """Parameters sent by the `on_dns_cache_miss` signal""" - - host: str - - -@attr.s(auto_attribs=True, frozen=True, slots=True) -class TraceRequestHeadersSentParams: - """Parameters sent by the `on_request_headers_sent` signal""" - - method: str - url: URL - headers: "CIMultiDict[str]" - - -class Trace: - """Internal dependency holder class. - - Used to keep together the main dependencies used - at the moment of send a signal. - """ - - def __init__( - self, - session: "ClientSession", - trace_config: TraceConfig, - trace_config_ctx: SimpleNamespace, - ) -> None: - self._trace_config = trace_config - self._trace_config_ctx = trace_config_ctx - self._session = session - - async def send_request_start( - self, method: str, url: URL, headers: "CIMultiDict[str]" - ) -> None: - return await self._trace_config.on_request_start.send( - self._session, - self._trace_config_ctx, - TraceRequestStartParams(method, url, headers), - ) - - async def send_request_chunk_sent( - self, method: str, url: URL, chunk: bytes - ) -> None: - return await self._trace_config.on_request_chunk_sent.send( - self._session, - self._trace_config_ctx, - TraceRequestChunkSentParams(method, url, chunk), - ) - - async def send_response_chunk_received( - self, method: str, url: URL, chunk: bytes - ) -> None: - return await self._trace_config.on_response_chunk_received.send( - self._session, - self._trace_config_ctx, - TraceResponseChunkReceivedParams(method, url, chunk), - ) - - async def send_request_end( - self, - method: str, - url: URL, - headers: "CIMultiDict[str]", - response: ClientResponse, - ) -> None: - return await self._trace_config.on_request_end.send( - self._session, - self._trace_config_ctx, - TraceRequestEndParams(method, url, headers, response), - ) - - async def send_request_exception( - self, - method: str, - url: URL, - headers: "CIMultiDict[str]", - exception: BaseException, - ) -> None: - return await self._trace_config.on_request_exception.send( - self._session, - self._trace_config_ctx, - TraceRequestExceptionParams(method, url, headers, exception), - ) - - async def send_request_redirect( - self, - method: str, - url: URL, - headers: "CIMultiDict[str]", - response: ClientResponse, - ) -> None: - return await self._trace_config._on_request_redirect.send( - self._session, - self._trace_config_ctx, - TraceRequestRedirectParams(method, url, headers, response), - ) - - async def send_connection_queued_start(self) -> None: - return await self._trace_config.on_connection_queued_start.send( - self._session, self._trace_config_ctx, TraceConnectionQueuedStartParams() - ) - - async def send_connection_queued_end(self) -> None: - return await self._trace_config.on_connection_queued_end.send( - self._session, self._trace_config_ctx, TraceConnectionQueuedEndParams() - ) - - async def send_connection_create_start(self) -> None: - return await self._trace_config.on_connection_create_start.send( - self._session, self._trace_config_ctx, TraceConnectionCreateStartParams() - ) - - async def send_connection_create_end(self) -> None: - return await self._trace_config.on_connection_create_end.send( - self._session, self._trace_config_ctx, TraceConnectionCreateEndParams() - ) - - async def send_connection_reuseconn(self) -> None: - return await self._trace_config.on_connection_reuseconn.send( - self._session, self._trace_config_ctx, TraceConnectionReuseconnParams() - ) - - async def send_dns_resolvehost_start(self, host: str) -> None: - return await self._trace_config.on_dns_resolvehost_start.send( - self._session, self._trace_config_ctx, TraceDnsResolveHostStartParams(host) - ) - - async def send_dns_resolvehost_end(self, host: str) -> None: - return await self._trace_config.on_dns_resolvehost_end.send( - self._session, self._trace_config_ctx, TraceDnsResolveHostEndParams(host) - ) - - async def send_dns_cache_hit(self, host: str) -> None: - return await self._trace_config.on_dns_cache_hit.send( - self._session, self._trace_config_ctx, TraceDnsCacheHitParams(host) - ) - - async def send_dns_cache_miss(self, host: str) -> None: - return await self._trace_config.on_dns_cache_miss.send( - self._session, self._trace_config_ctx, TraceDnsCacheMissParams(host) - ) - - async def send_request_headers( - self, method: str, url: URL, headers: "CIMultiDict[str]" - ) -> None: - return await self._trace_config._on_request_headers_sent.send( - self._session, - self._trace_config_ctx, - TraceRequestHeadersSentParams(method, url, headers), - ) diff --git a/venv/lib/python3.9/site-packages/aiohttp/typedefs.py b/venv/lib/python3.9/site-packages/aiohttp/typedefs.py deleted file mode 100644 index cc8c082..0000000 --- a/venv/lib/python3.9/site-packages/aiohttp/typedefs.py +++ /dev/null @@ -1,69 +0,0 @@ -import json -import os -from typing import ( - TYPE_CHECKING, - Any, - Awaitable, - Callable, - Iterable, - Mapping, - Protocol, - Tuple, - Union, -) - -from multidict import CIMultiDict, CIMultiDictProxy, MultiDict, MultiDictProxy, istr -from yarl import URL, Query as _Query - -Query = _Query - -DEFAULT_JSON_ENCODER = json.dumps -DEFAULT_JSON_DECODER = json.loads - -if TYPE_CHECKING: - _CIMultiDict = CIMultiDict[str] - _CIMultiDictProxy = CIMultiDictProxy[str] - _MultiDict = MultiDict[str] - _MultiDictProxy = MultiDictProxy[str] - from http.cookies import BaseCookie, Morsel - - from .web import Request, StreamResponse -else: - _CIMultiDict = CIMultiDict - _CIMultiDictProxy = CIMultiDictProxy - _MultiDict = MultiDict - _MultiDictProxy = MultiDictProxy - -Byteish = Union[bytes, bytearray, memoryview] -JSONEncoder = Callable[[Any], str] -JSONDecoder = Callable[[str], Any] -LooseHeaders = Union[ - Mapping[str, str], - Mapping[istr, str], - _CIMultiDict, - _CIMultiDictProxy, - Iterable[Tuple[Union[str, istr], str]], -] -RawHeaders = Tuple[Tuple[bytes, bytes], ...] -StrOrURL = Union[str, URL] - -LooseCookiesMappings = Mapping[str, Union[str, "BaseCookie[str]", "Morsel[Any]"]] -LooseCookiesIterables = Iterable[ - Tuple[str, Union[str, "BaseCookie[str]", "Morsel[Any]"]] -] -LooseCookies = Union[ - LooseCookiesMappings, - LooseCookiesIterables, - "BaseCookie[str]", -] - -Handler = Callable[["Request"], Awaitable["StreamResponse"]] - - -class Middleware(Protocol): - def __call__( - self, request: "Request", handler: Handler - ) -> Awaitable["StreamResponse"]: ... - - -PathLike = Union[str, "os.PathLike[str]"] diff --git a/venv/lib/python3.9/site-packages/aiohttp/web.py b/venv/lib/python3.9/site-packages/aiohttp/web.py deleted file mode 100644 index 5a1fc96..0000000 --- a/venv/lib/python3.9/site-packages/aiohttp/web.py +++ /dev/null @@ -1,592 +0,0 @@ -import asyncio -import logging -import os -import socket -import sys -import warnings -from argparse import ArgumentParser -from collections.abc import Iterable -from contextlib import suppress -from importlib import import_module -from typing import ( - TYPE_CHECKING, - Any, - Awaitable, - Callable, - Iterable as TypingIterable, - List, - Optional, - Set, - Type, - Union, - cast, -) - -from .abc import AbstractAccessLogger -from .helpers import AppKey as AppKey -from .log import access_logger -from .typedefs import PathLike -from .web_app import Application as Application, CleanupError as CleanupError -from .web_exceptions import ( - HTTPAccepted as HTTPAccepted, - HTTPBadGateway as HTTPBadGateway, - HTTPBadRequest as HTTPBadRequest, - HTTPClientError as HTTPClientError, - HTTPConflict as HTTPConflict, - HTTPCreated as HTTPCreated, - HTTPError as HTTPError, - HTTPException as HTTPException, - HTTPExpectationFailed as HTTPExpectationFailed, - HTTPFailedDependency as HTTPFailedDependency, - HTTPForbidden as HTTPForbidden, - HTTPFound as HTTPFound, - HTTPGatewayTimeout as HTTPGatewayTimeout, - HTTPGone as HTTPGone, - HTTPInsufficientStorage as HTTPInsufficientStorage, - HTTPInternalServerError as HTTPInternalServerError, - HTTPLengthRequired as HTTPLengthRequired, - HTTPMethodNotAllowed as HTTPMethodNotAllowed, - HTTPMisdirectedRequest as HTTPMisdirectedRequest, - HTTPMove as HTTPMove, - HTTPMovedPermanently as HTTPMovedPermanently, - HTTPMultipleChoices as HTTPMultipleChoices, - HTTPNetworkAuthenticationRequired as HTTPNetworkAuthenticationRequired, - HTTPNoContent as HTTPNoContent, - HTTPNonAuthoritativeInformation as HTTPNonAuthoritativeInformation, - HTTPNotAcceptable as HTTPNotAcceptable, - HTTPNotExtended as HTTPNotExtended, - HTTPNotFound as HTTPNotFound, - HTTPNotImplemented as HTTPNotImplemented, - HTTPNotModified as HTTPNotModified, - HTTPOk as HTTPOk, - HTTPPartialContent as HTTPPartialContent, - HTTPPaymentRequired as HTTPPaymentRequired, - HTTPPermanentRedirect as HTTPPermanentRedirect, - HTTPPreconditionFailed as HTTPPreconditionFailed, - HTTPPreconditionRequired as HTTPPreconditionRequired, - HTTPProxyAuthenticationRequired as HTTPProxyAuthenticationRequired, - HTTPRedirection as HTTPRedirection, - HTTPRequestEntityTooLarge as HTTPRequestEntityTooLarge, - HTTPRequestHeaderFieldsTooLarge as HTTPRequestHeaderFieldsTooLarge, - HTTPRequestRangeNotSatisfiable as HTTPRequestRangeNotSatisfiable, - HTTPRequestTimeout as HTTPRequestTimeout, - HTTPRequestURITooLong as HTTPRequestURITooLong, - HTTPResetContent as HTTPResetContent, - HTTPSeeOther as HTTPSeeOther, - HTTPServerError as HTTPServerError, - HTTPServiceUnavailable as HTTPServiceUnavailable, - HTTPSuccessful as HTTPSuccessful, - HTTPTemporaryRedirect as HTTPTemporaryRedirect, - HTTPTooManyRequests as HTTPTooManyRequests, - HTTPUnauthorized as HTTPUnauthorized, - HTTPUnavailableForLegalReasons as HTTPUnavailableForLegalReasons, - HTTPUnprocessableEntity as HTTPUnprocessableEntity, - HTTPUnsupportedMediaType as HTTPUnsupportedMediaType, - HTTPUpgradeRequired as HTTPUpgradeRequired, - HTTPUseProxy as HTTPUseProxy, - HTTPVariantAlsoNegotiates as HTTPVariantAlsoNegotiates, - HTTPVersionNotSupported as HTTPVersionNotSupported, - NotAppKeyWarning as NotAppKeyWarning, -) -from .web_fileresponse import FileResponse as FileResponse -from .web_log import AccessLogger -from .web_middlewares import ( - middleware as middleware, - normalize_path_middleware as normalize_path_middleware, -) -from .web_protocol import ( - PayloadAccessError as PayloadAccessError, - RequestHandler as RequestHandler, - RequestPayloadError as RequestPayloadError, -) -from .web_request import ( - BaseRequest as BaseRequest, - FileField as FileField, - Request as Request, -) -from .web_response import ( - ContentCoding as ContentCoding, - Response as Response, - StreamResponse as StreamResponse, - json_response as json_response, -) -from .web_routedef import ( - AbstractRouteDef as AbstractRouteDef, - RouteDef as RouteDef, - RouteTableDef as RouteTableDef, - StaticDef as StaticDef, - delete as delete, - get as get, - head as head, - options as options, - patch as patch, - post as post, - put as put, - route as route, - static as static, - view as view, -) -from .web_runner import ( - AppRunner as AppRunner, - BaseRunner as BaseRunner, - BaseSite as BaseSite, - GracefulExit as GracefulExit, - NamedPipeSite as NamedPipeSite, - ServerRunner as ServerRunner, - SockSite as SockSite, - TCPSite as TCPSite, - UnixSite as UnixSite, -) -from .web_server import Server as Server -from .web_urldispatcher import ( - AbstractResource as AbstractResource, - AbstractRoute as AbstractRoute, - DynamicResource as DynamicResource, - PlainResource as PlainResource, - PrefixedSubAppResource as PrefixedSubAppResource, - Resource as Resource, - ResourceRoute as ResourceRoute, - StaticResource as StaticResource, - UrlDispatcher as UrlDispatcher, - UrlMappingMatchInfo as UrlMappingMatchInfo, - View as View, -) -from .web_ws import ( - WebSocketReady as WebSocketReady, - WebSocketResponse as WebSocketResponse, - WSMsgType as WSMsgType, -) - -__all__ = ( - # web_app - "AppKey", - "Application", - "CleanupError", - # web_exceptions - "NotAppKeyWarning", - "HTTPAccepted", - "HTTPBadGateway", - "HTTPBadRequest", - "HTTPClientError", - "HTTPConflict", - "HTTPCreated", - "HTTPError", - "HTTPException", - "HTTPExpectationFailed", - "HTTPFailedDependency", - "HTTPForbidden", - "HTTPFound", - "HTTPGatewayTimeout", - "HTTPGone", - "HTTPInsufficientStorage", - "HTTPInternalServerError", - "HTTPLengthRequired", - "HTTPMethodNotAllowed", - "HTTPMisdirectedRequest", - "HTTPMove", - "HTTPMovedPermanently", - "HTTPMultipleChoices", - "HTTPNetworkAuthenticationRequired", - "HTTPNoContent", - "HTTPNonAuthoritativeInformation", - "HTTPNotAcceptable", - "HTTPNotExtended", - "HTTPNotFound", - "HTTPNotImplemented", - "HTTPNotModified", - "HTTPOk", - "HTTPPartialContent", - "HTTPPaymentRequired", - "HTTPPermanentRedirect", - "HTTPPreconditionFailed", - "HTTPPreconditionRequired", - "HTTPProxyAuthenticationRequired", - "HTTPRedirection", - "HTTPRequestEntityTooLarge", - "HTTPRequestHeaderFieldsTooLarge", - "HTTPRequestRangeNotSatisfiable", - "HTTPRequestTimeout", - "HTTPRequestURITooLong", - "HTTPResetContent", - "HTTPSeeOther", - "HTTPServerError", - "HTTPServiceUnavailable", - "HTTPSuccessful", - "HTTPTemporaryRedirect", - "HTTPTooManyRequests", - "HTTPUnauthorized", - "HTTPUnavailableForLegalReasons", - "HTTPUnprocessableEntity", - "HTTPUnsupportedMediaType", - "HTTPUpgradeRequired", - "HTTPUseProxy", - "HTTPVariantAlsoNegotiates", - "HTTPVersionNotSupported", - # web_fileresponse - "FileResponse", - # web_middlewares - "middleware", - "normalize_path_middleware", - # web_protocol - "PayloadAccessError", - "RequestHandler", - "RequestPayloadError", - # web_request - "BaseRequest", - "FileField", - "Request", - # web_response - "ContentCoding", - "Response", - "StreamResponse", - "json_response", - # web_routedef - "AbstractRouteDef", - "RouteDef", - "RouteTableDef", - "StaticDef", - "delete", - "get", - "head", - "options", - "patch", - "post", - "put", - "route", - "static", - "view", - # web_runner - "AppRunner", - "BaseRunner", - "BaseSite", - "GracefulExit", - "ServerRunner", - "SockSite", - "TCPSite", - "UnixSite", - "NamedPipeSite", - # web_server - "Server", - # web_urldispatcher - "AbstractResource", - "AbstractRoute", - "DynamicResource", - "PlainResource", - "PrefixedSubAppResource", - "Resource", - "ResourceRoute", - "StaticResource", - "UrlDispatcher", - "UrlMappingMatchInfo", - "View", - # web_ws - "WebSocketReady", - "WebSocketResponse", - "WSMsgType", - # web - "run_app", -) - - -if TYPE_CHECKING: - from ssl import SSLContext -else: - try: - from ssl import SSLContext - except ImportError: # pragma: no cover - SSLContext = object # type: ignore[misc,assignment] - -# Only display warning when using -Wdefault, -We, -X dev or similar. -warnings.filterwarnings("ignore", category=NotAppKeyWarning, append=True) - -HostSequence = TypingIterable[str] - - -async def _run_app( - app: Union[Application, Awaitable[Application]], - *, - host: Optional[Union[str, HostSequence]] = None, - port: Optional[int] = None, - path: Union[PathLike, TypingIterable[PathLike], None] = None, - sock: Optional[Union[socket.socket, TypingIterable[socket.socket]]] = None, - ssl_context: Optional[SSLContext] = None, - print: Optional[Callable[..., None]] = print, - backlog: int = 128, - reuse_address: Optional[bool] = None, - reuse_port: Optional[bool] = None, - **kwargs: Any, # TODO(PY311): Use Unpack -) -> None: - # An internal function to actually do all dirty job for application running - if asyncio.iscoroutine(app): - app = await app - - app = cast(Application, app) - - runner = AppRunner(app, **kwargs) - - await runner.setup() - - sites: List[BaseSite] = [] - - try: - if host is not None: - if isinstance(host, str): - sites.append( - TCPSite( - runner, - host, - port, - ssl_context=ssl_context, - backlog=backlog, - reuse_address=reuse_address, - reuse_port=reuse_port, - ) - ) - else: - for h in host: - sites.append( - TCPSite( - runner, - h, - port, - ssl_context=ssl_context, - backlog=backlog, - reuse_address=reuse_address, - reuse_port=reuse_port, - ) - ) - elif path is None and sock is None or port is not None: - sites.append( - TCPSite( - runner, - port=port, - ssl_context=ssl_context, - backlog=backlog, - reuse_address=reuse_address, - reuse_port=reuse_port, - ) - ) - - if path is not None: - if isinstance(path, (str, os.PathLike)): - sites.append( - UnixSite( - runner, - path, - ssl_context=ssl_context, - backlog=backlog, - ) - ) - else: - for p in path: - sites.append( - UnixSite( - runner, - p, - ssl_context=ssl_context, - backlog=backlog, - ) - ) - - if sock is not None: - if not isinstance(sock, Iterable): - sites.append( - SockSite( - runner, - sock, - ssl_context=ssl_context, - backlog=backlog, - ) - ) - else: - for s in sock: - sites.append( - SockSite( - runner, - s, - ssl_context=ssl_context, - backlog=backlog, - ) - ) - for site in sites: - await site.start() - - if print: # pragma: no branch - names = sorted(str(s.name) for s in runner.sites) - print( - "======== Running on {} ========\n" - "(Press CTRL+C to quit)".format(", ".join(names)) - ) - - # sleep forever by 1 hour intervals, - while True: - await asyncio.sleep(3600) - finally: - await runner.cleanup() - - -def _cancel_tasks( - to_cancel: Set["asyncio.Task[Any]"], loop: asyncio.AbstractEventLoop -) -> None: - if not to_cancel: - return - - for task in to_cancel: - task.cancel() - - loop.run_until_complete(asyncio.gather(*to_cancel, return_exceptions=True)) - - for task in to_cancel: - if task.cancelled(): - continue - if task.exception() is not None: - loop.call_exception_handler( - { - "message": "unhandled exception during asyncio.run() shutdown", - "exception": task.exception(), - "task": task, - } - ) - - -def run_app( - app: Union[Application, Awaitable[Application]], - *, - host: Optional[Union[str, HostSequence]] = None, - port: Optional[int] = None, - path: Union[PathLike, TypingIterable[PathLike], None] = None, - sock: Optional[Union[socket.socket, TypingIterable[socket.socket]]] = None, - shutdown_timeout: float = 60.0, - keepalive_timeout: float = 75.0, - ssl_context: Optional[SSLContext] = None, - print: Optional[Callable[..., None]] = print, - backlog: int = 128, - access_log_class: Type[AbstractAccessLogger] = AccessLogger, - access_log_format: str = AccessLogger.LOG_FORMAT, - access_log: Optional[logging.Logger] = access_logger, - handle_signals: bool = True, - reuse_address: Optional[bool] = None, - reuse_port: Optional[bool] = None, - handler_cancellation: bool = False, - loop: Optional[asyncio.AbstractEventLoop] = None, - **kwargs: Any, -) -> None: - """Run an app locally""" - if loop is None: - loop = asyncio.new_event_loop() - - # Configure if and only if in debugging mode and using the default logger - if loop.get_debug() and access_log and access_log.name == "aiohttp.access": - if access_log.level == logging.NOTSET: - access_log.setLevel(logging.DEBUG) - if not access_log.hasHandlers(): - access_log.addHandler(logging.StreamHandler()) - - main_task = loop.create_task( - _run_app( - app, - host=host, - port=port, - path=path, - sock=sock, - shutdown_timeout=shutdown_timeout, - keepalive_timeout=keepalive_timeout, - ssl_context=ssl_context, - print=print, - backlog=backlog, - access_log_class=access_log_class, - access_log_format=access_log_format, - access_log=access_log, - handle_signals=handle_signals, - reuse_address=reuse_address, - reuse_port=reuse_port, - handler_cancellation=handler_cancellation, - **kwargs, - ) - ) - - try: - asyncio.set_event_loop(loop) - loop.run_until_complete(main_task) - except (GracefulExit, KeyboardInterrupt): # pragma: no cover - pass - finally: - try: - main_task.cancel() - with suppress(asyncio.CancelledError): - loop.run_until_complete(main_task) - finally: - _cancel_tasks(asyncio.all_tasks(loop), loop) - loop.run_until_complete(loop.shutdown_asyncgens()) - loop.close() - - -def main(argv: List[str]) -> None: - arg_parser = ArgumentParser( - description="aiohttp.web Application server", prog="aiohttp.web" - ) - arg_parser.add_argument( - "entry_func", - help=( - "Callable returning the `aiohttp.web.Application` instance to " - "run. Should be specified in the 'module:function' syntax." - ), - metavar="entry-func", - ) - arg_parser.add_argument( - "-H", - "--hostname", - help="TCP/IP hostname to serve on (default: localhost)", - default=None, - ) - arg_parser.add_argument( - "-P", - "--port", - help="TCP/IP port to serve on (default: %(default)r)", - type=int, - default=8080, - ) - arg_parser.add_argument( - "-U", - "--path", - help="Unix file system path to serve on. Can be combined with hostname " - "to serve on both Unix and TCP.", - ) - args, extra_argv = arg_parser.parse_known_args(argv) - - # Import logic - mod_str, _, func_str = args.entry_func.partition(":") - if not func_str or not mod_str: - arg_parser.error("'entry-func' not in 'module:function' syntax") - if mod_str.startswith("."): - arg_parser.error("relative module names not supported") - try: - module = import_module(mod_str) - except ImportError as ex: - arg_parser.error(f"unable to import {mod_str}: {ex}") - try: - func = getattr(module, func_str) - except AttributeError: - arg_parser.error(f"module {mod_str!r} has no attribute {func_str!r}") - - # Compatibility logic - if args.path is not None and not hasattr(socket, "AF_UNIX"): - arg_parser.error( - "file system paths not supported by your operating environment" - ) - - logging.basicConfig(level=logging.DEBUG) - - if args.path and args.hostname is None: - host = port = None - else: - host = args.hostname or "localhost" - port = args.port - - app = func(extra_argv) - run_app(app, host=host, port=port, path=args.path) - arg_parser.exit(message="Stopped\n") - - -if __name__ == "__main__": # pragma: no branch - main(sys.argv[1:]) # pragma: no cover diff --git a/venv/lib/python3.9/site-packages/aiohttp/web_app.py b/venv/lib/python3.9/site-packages/aiohttp/web_app.py deleted file mode 100644 index 619c008..0000000 --- a/venv/lib/python3.9/site-packages/aiohttp/web_app.py +++ /dev/null @@ -1,620 +0,0 @@ -import asyncio -import logging -import warnings -from functools import lru_cache, partial, update_wrapper -from typing import ( - TYPE_CHECKING, - Any, - AsyncIterator, - Awaitable, - Callable, - Dict, - Iterable, - Iterator, - List, - Mapping, - MutableMapping, - Optional, - Sequence, - Tuple, - Type, - TypeVar, - Union, - cast, - overload, -) - -from aiosignal import Signal -from frozenlist import FrozenList - -from . import hdrs -from .abc import ( - AbstractAccessLogger, - AbstractMatchInfo, - AbstractRouter, - AbstractStreamWriter, -) -from .helpers import DEBUG, AppKey -from .http_parser import RawRequestMessage -from .log import web_logger -from .streams import StreamReader -from .typedefs import Handler, Middleware -from .web_exceptions import NotAppKeyWarning -from .web_log import AccessLogger -from .web_middlewares import _fix_request_current_app -from .web_protocol import RequestHandler -from .web_request import Request -from .web_response import StreamResponse -from .web_routedef import AbstractRouteDef -from .web_server import Server -from .web_urldispatcher import ( - AbstractResource, - AbstractRoute, - Domain, - MaskDomain, - MatchedSubAppResource, - PrefixedSubAppResource, - SystemRoute, - UrlDispatcher, -) - -__all__ = ("Application", "CleanupError") - - -if TYPE_CHECKING: - _AppSignal = Signal["Application"] - _RespPrepareSignal = Signal[Request, StreamResponse] - _Middlewares = FrozenList[Middleware] - _MiddlewaresHandlers = Optional[Sequence[Tuple[Middleware, bool]]] - _Subapps = List["Application"] -else: - # No type checker mode, skip types - _AppSignal = Signal - _RespPrepareSignal = Signal - _Middlewares = FrozenList - _MiddlewaresHandlers = Optional[Sequence] - _Subapps = List - -_T = TypeVar("_T") -_U = TypeVar("_U") -_Resource = TypeVar("_Resource", bound=AbstractResource) - - -def _build_middlewares( - handler: Handler, apps: Tuple["Application", ...] -) -> Callable[[Request], Awaitable[StreamResponse]]: - """Apply middlewares to handler.""" - for app in apps[::-1]: - for m, _ in app._middlewares_handlers: # type: ignore[union-attr] - handler = update_wrapper(partial(m, handler=handler), handler) - return handler - - -_cached_build_middleware = lru_cache(maxsize=1024)(_build_middlewares) - - -class Application(MutableMapping[Union[str, AppKey[Any]], Any]): - ATTRS = frozenset( - [ - "logger", - "_debug", - "_router", - "_loop", - "_handler_args", - "_middlewares", - "_middlewares_handlers", - "_has_legacy_middlewares", - "_run_middlewares", - "_state", - "_frozen", - "_pre_frozen", - "_subapps", - "_on_response_prepare", - "_on_startup", - "_on_shutdown", - "_on_cleanup", - "_client_max_size", - "_cleanup_ctx", - ] - ) - - def __init__( - self, - *, - logger: logging.Logger = web_logger, - router: Optional[UrlDispatcher] = None, - middlewares: Iterable[Middleware] = (), - handler_args: Optional[Mapping[str, Any]] = None, - client_max_size: int = 1024**2, - loop: Optional[asyncio.AbstractEventLoop] = None, - debug: Any = ..., # mypy doesn't support ellipsis - ) -> None: - if router is None: - router = UrlDispatcher() - else: - warnings.warn( - "router argument is deprecated", DeprecationWarning, stacklevel=2 - ) - assert isinstance(router, AbstractRouter), router - - if loop is not None: - warnings.warn( - "loop argument is deprecated", DeprecationWarning, stacklevel=2 - ) - - if debug is not ...: - warnings.warn( - "debug argument is deprecated", DeprecationWarning, stacklevel=2 - ) - self._debug = debug - self._router: UrlDispatcher = router - self._loop = loop - self._handler_args = handler_args - self.logger = logger - - self._middlewares: _Middlewares = FrozenList(middlewares) - - # initialized on freezing - self._middlewares_handlers: _MiddlewaresHandlers = None - # initialized on freezing - self._run_middlewares: Optional[bool] = None - self._has_legacy_middlewares: bool = True - - self._state: Dict[Union[AppKey[Any], str], object] = {} - self._frozen = False - self._pre_frozen = False - self._subapps: _Subapps = [] - - self._on_response_prepare: _RespPrepareSignal = Signal(self) - self._on_startup: _AppSignal = Signal(self) - self._on_shutdown: _AppSignal = Signal(self) - self._on_cleanup: _AppSignal = Signal(self) - self._cleanup_ctx = CleanupContext() - self._on_startup.append(self._cleanup_ctx._on_startup) - self._on_cleanup.append(self._cleanup_ctx._on_cleanup) - self._client_max_size = client_max_size - - def __init_subclass__(cls: Type["Application"]) -> None: - warnings.warn( - "Inheritance class {} from web.Application " - "is discouraged".format(cls.__name__), - DeprecationWarning, - stacklevel=3, - ) - - if DEBUG: # pragma: no cover - - def __setattr__(self, name: str, val: Any) -> None: - if name not in self.ATTRS: - warnings.warn( - "Setting custom web.Application.{} attribute " - "is discouraged".format(name), - DeprecationWarning, - stacklevel=2, - ) - super().__setattr__(name, val) - - # MutableMapping API - - def __eq__(self, other: object) -> bool: - return self is other - - @overload # type: ignore[override] - def __getitem__(self, key: AppKey[_T]) -> _T: ... - - @overload - def __getitem__(self, key: str) -> Any: ... - - def __getitem__(self, key: Union[str, AppKey[_T]]) -> Any: - return self._state[key] - - def _check_frozen(self) -> None: - if self._frozen: - warnings.warn( - "Changing state of started or joined application is deprecated", - DeprecationWarning, - stacklevel=3, - ) - - @overload # type: ignore[override] - def __setitem__(self, key: AppKey[_T], value: _T) -> None: ... - - @overload - def __setitem__(self, key: str, value: Any) -> None: ... - - def __setitem__(self, key: Union[str, AppKey[_T]], value: Any) -> None: - self._check_frozen() - if not isinstance(key, AppKey): - warnings.warn( - "It is recommended to use web.AppKey instances for keys.\n" - + "https://docs.aiohttp.org/en/stable/web_advanced.html" - + "#application-s-config", - category=NotAppKeyWarning, - stacklevel=2, - ) - self._state[key] = value - - def __delitem__(self, key: Union[str, AppKey[_T]]) -> None: - self._check_frozen() - del self._state[key] - - def __len__(self) -> int: - return len(self._state) - - def __iter__(self) -> Iterator[Union[str, AppKey[Any]]]: - return iter(self._state) - - def __hash__(self) -> int: - return id(self) - - @overload # type: ignore[override] - def get(self, key: AppKey[_T], default: None = ...) -> Optional[_T]: ... - - @overload - def get(self, key: AppKey[_T], default: _U) -> Union[_T, _U]: ... - - @overload - def get(self, key: str, default: Any = ...) -> Any: ... - - def get(self, key: Union[str, AppKey[_T]], default: Any = None) -> Any: - return self._state.get(key, default) - - ######## - @property - def loop(self) -> asyncio.AbstractEventLoop: - # Technically the loop can be None - # but we mask it by explicit type cast - # to provide more convenient type annotation - warnings.warn("loop property is deprecated", DeprecationWarning, stacklevel=2) - return cast(asyncio.AbstractEventLoop, self._loop) - - def _set_loop(self, loop: Optional[asyncio.AbstractEventLoop]) -> None: - if loop is None: - loop = asyncio.get_event_loop() - if self._loop is not None and self._loop is not loop: - raise RuntimeError( - "web.Application instance initialized with different loop" - ) - - self._loop = loop - - # set loop debug - if self._debug is ...: - self._debug = loop.get_debug() - - # set loop to sub applications - for subapp in self._subapps: - subapp._set_loop(loop) - - @property - def pre_frozen(self) -> bool: - return self._pre_frozen - - def pre_freeze(self) -> None: - if self._pre_frozen: - return - - self._pre_frozen = True - self._middlewares.freeze() - self._router.freeze() - self._on_response_prepare.freeze() - self._cleanup_ctx.freeze() - self._on_startup.freeze() - self._on_shutdown.freeze() - self._on_cleanup.freeze() - self._middlewares_handlers = tuple(self._prepare_middleware()) - self._has_legacy_middlewares = any( - not new_style for _, new_style in self._middlewares_handlers - ) - - # If current app and any subapp do not have middlewares avoid run all - # of the code footprint that it implies, which have a middleware - # hardcoded per app that sets up the current_app attribute. If no - # middlewares are configured the handler will receive the proper - # current_app without needing all of this code. - self._run_middlewares = True if self.middlewares else False - - for subapp in self._subapps: - subapp.pre_freeze() - self._run_middlewares = self._run_middlewares or subapp._run_middlewares - - @property - def frozen(self) -> bool: - return self._frozen - - def freeze(self) -> None: - if self._frozen: - return - - self.pre_freeze() - self._frozen = True - for subapp in self._subapps: - subapp.freeze() - - @property - def debug(self) -> bool: - warnings.warn("debug property is deprecated", DeprecationWarning, stacklevel=2) - return self._debug # type: ignore[no-any-return] - - def _reg_subapp_signals(self, subapp: "Application") -> None: - def reg_handler(signame: str) -> None: - subsig = getattr(subapp, signame) - - async def handler(app: "Application") -> None: - await subsig.send(subapp) - - appsig = getattr(self, signame) - appsig.append(handler) - - reg_handler("on_startup") - reg_handler("on_shutdown") - reg_handler("on_cleanup") - - def add_subapp(self, prefix: str, subapp: "Application") -> PrefixedSubAppResource: - if not isinstance(prefix, str): - raise TypeError("Prefix must be str") - prefix = prefix.rstrip("/") - if not prefix: - raise ValueError("Prefix cannot be empty") - factory = partial(PrefixedSubAppResource, prefix, subapp) - return self._add_subapp(factory, subapp) - - def _add_subapp( - self, resource_factory: Callable[[], _Resource], subapp: "Application" - ) -> _Resource: - if self.frozen: - raise RuntimeError("Cannot add sub application to frozen application") - if subapp.frozen: - raise RuntimeError("Cannot add frozen application") - resource = resource_factory() - self.router.register_resource(resource) - self._reg_subapp_signals(subapp) - self._subapps.append(subapp) - subapp.pre_freeze() - if self._loop is not None: - subapp._set_loop(self._loop) - return resource - - def add_domain(self, domain: str, subapp: "Application") -> MatchedSubAppResource: - if not isinstance(domain, str): - raise TypeError("Domain must be str") - elif "*" in domain: - rule: Domain = MaskDomain(domain) - else: - rule = Domain(domain) - factory = partial(MatchedSubAppResource, rule, subapp) - return self._add_subapp(factory, subapp) - - def add_routes(self, routes: Iterable[AbstractRouteDef]) -> List[AbstractRoute]: - return self.router.add_routes(routes) - - @property - def on_response_prepare(self) -> _RespPrepareSignal: - return self._on_response_prepare - - @property - def on_startup(self) -> _AppSignal: - return self._on_startup - - @property - def on_shutdown(self) -> _AppSignal: - return self._on_shutdown - - @property - def on_cleanup(self) -> _AppSignal: - return self._on_cleanup - - @property - def cleanup_ctx(self) -> "CleanupContext": - return self._cleanup_ctx - - @property - def router(self) -> UrlDispatcher: - return self._router - - @property - def middlewares(self) -> _Middlewares: - return self._middlewares - - def _make_handler( - self, - *, - loop: Optional[asyncio.AbstractEventLoop] = None, - access_log_class: Type[AbstractAccessLogger] = AccessLogger, - **kwargs: Any, - ) -> Server: - - if not issubclass(access_log_class, AbstractAccessLogger): - raise TypeError( - "access_log_class must be subclass of " - "aiohttp.abc.AbstractAccessLogger, got {}".format(access_log_class) - ) - - self._set_loop(loop) - self.freeze() - - kwargs["debug"] = self._debug - kwargs["access_log_class"] = access_log_class - if self._handler_args: - for k, v in self._handler_args.items(): - kwargs[k] = v - - return Server( - self._handle, # type: ignore[arg-type] - request_factory=self._make_request, - loop=self._loop, - **kwargs, - ) - - def make_handler( - self, - *, - loop: Optional[asyncio.AbstractEventLoop] = None, - access_log_class: Type[AbstractAccessLogger] = AccessLogger, - **kwargs: Any, - ) -> Server: - - warnings.warn( - "Application.make_handler(...) is deprecated, use AppRunner API instead", - DeprecationWarning, - stacklevel=2, - ) - - return self._make_handler( - loop=loop, access_log_class=access_log_class, **kwargs - ) - - async def startup(self) -> None: - """Causes on_startup signal - - Should be called in the event loop along with the request handler. - """ - await self.on_startup.send(self) - - async def shutdown(self) -> None: - """Causes on_shutdown signal - - Should be called before cleanup() - """ - await self.on_shutdown.send(self) - - async def cleanup(self) -> None: - """Causes on_cleanup signal - - Should be called after shutdown() - """ - if self.on_cleanup.frozen: - await self.on_cleanup.send(self) - else: - # If an exception occurs in startup, ensure cleanup contexts are completed. - await self._cleanup_ctx._on_cleanup(self) - - def _make_request( - self, - message: RawRequestMessage, - payload: StreamReader, - protocol: RequestHandler, - writer: AbstractStreamWriter, - task: "asyncio.Task[None]", - _cls: Type[Request] = Request, - ) -> Request: - if TYPE_CHECKING: - assert self._loop is not None - return _cls( - message, - payload, - protocol, - writer, - task, - self._loop, - client_max_size=self._client_max_size, - ) - - def _prepare_middleware(self) -> Iterator[Tuple[Middleware, bool]]: - for m in reversed(self._middlewares): - if getattr(m, "__middleware_version__", None) == 1: - yield m, True - else: - warnings.warn( - f'old-style middleware "{m!r}" deprecated, see #2252', - DeprecationWarning, - stacklevel=2, - ) - yield m, False - - yield _fix_request_current_app(self), True - - async def _handle(self, request: Request) -> StreamResponse: - loop = asyncio.get_event_loop() - debug = loop.get_debug() - match_info = await self._router.resolve(request) - if debug: # pragma: no cover - if not isinstance(match_info, AbstractMatchInfo): - raise TypeError( - "match_info should be AbstractMatchInfo " - "instance, not {!r}".format(match_info) - ) - match_info.add_app(self) - - match_info.freeze() - - request._match_info = match_info - - if request.headers.get(hdrs.EXPECT): - resp = await match_info.expect_handler(request) - await request.writer.drain() - if resp is not None: - return resp - - handler = match_info.handler - - if self._run_middlewares: - # If its a SystemRoute, don't cache building the middlewares since - # they are constructed for every MatchInfoError as a new handler - # is made each time. - if not self._has_legacy_middlewares and not isinstance( - match_info.route, SystemRoute - ): - handler = _cached_build_middleware(handler, match_info.apps) - else: - for app in match_info.apps[::-1]: - for m, new_style in app._middlewares_handlers: # type: ignore[union-attr] - if new_style: - handler = update_wrapper( - partial(m, handler=handler), handler - ) - else: - handler = await m(app, handler) # type: ignore[arg-type,assignment] - - return await handler(request) - - def __call__(self) -> "Application": - """gunicorn compatibility""" - return self - - def __repr__(self) -> str: - return f"" - - def __bool__(self) -> bool: - return True - - -class CleanupError(RuntimeError): - @property - def exceptions(self) -> List[BaseException]: - return cast(List[BaseException], self.args[1]) - - -if TYPE_CHECKING: - _CleanupContextBase = FrozenList[Callable[[Application], AsyncIterator[None]]] -else: - _CleanupContextBase = FrozenList - - -class CleanupContext(_CleanupContextBase): - def __init__(self) -> None: - super().__init__() - self._exits: List[AsyncIterator[None]] = [] - - async def _on_startup(self, app: Application) -> None: - for cb in self: - it = cb(app).__aiter__() - await it.__anext__() - self._exits.append(it) - - async def _on_cleanup(self, app: Application) -> None: - errors = [] - for it in reversed(self._exits): - try: - await it.__anext__() - except StopAsyncIteration: - pass - except (Exception, asyncio.CancelledError) as exc: - errors.append(exc) - else: - errors.append(RuntimeError(f"{it!r} has more than one 'yield'")) - if errors: - if len(errors) == 1: - raise errors[0] - else: - raise CleanupError("Multiple errors on cleanup stage", errors) diff --git a/venv/lib/python3.9/site-packages/aiohttp/web_exceptions.py b/venv/lib/python3.9/site-packages/aiohttp/web_exceptions.py deleted file mode 100644 index 30792c2..0000000 --- a/venv/lib/python3.9/site-packages/aiohttp/web_exceptions.py +++ /dev/null @@ -1,454 +0,0 @@ -import warnings -from typing import Any, Dict, Iterable, List, Optional, Set # noqa - -from yarl import URL - -from .typedefs import LooseHeaders, StrOrURL -from .web_response import Response - -__all__ = ( - "HTTPException", - "HTTPError", - "HTTPRedirection", - "HTTPSuccessful", - "HTTPOk", - "HTTPCreated", - "HTTPAccepted", - "HTTPNonAuthoritativeInformation", - "HTTPNoContent", - "HTTPResetContent", - "HTTPPartialContent", - "HTTPMove", - "HTTPMultipleChoices", - "HTTPMovedPermanently", - "HTTPFound", - "HTTPSeeOther", - "HTTPNotModified", - "HTTPUseProxy", - "HTTPTemporaryRedirect", - "HTTPPermanentRedirect", - "HTTPClientError", - "HTTPBadRequest", - "HTTPUnauthorized", - "HTTPPaymentRequired", - "HTTPForbidden", - "HTTPNotFound", - "HTTPMethodNotAllowed", - "HTTPNotAcceptable", - "HTTPProxyAuthenticationRequired", - "HTTPRequestTimeout", - "HTTPConflict", - "HTTPGone", - "HTTPLengthRequired", - "HTTPPreconditionFailed", - "HTTPRequestEntityTooLarge", - "HTTPRequestURITooLong", - "HTTPUnsupportedMediaType", - "HTTPRequestRangeNotSatisfiable", - "HTTPExpectationFailed", - "HTTPMisdirectedRequest", - "HTTPUnprocessableEntity", - "HTTPFailedDependency", - "HTTPUpgradeRequired", - "HTTPPreconditionRequired", - "HTTPTooManyRequests", - "HTTPRequestHeaderFieldsTooLarge", - "HTTPUnavailableForLegalReasons", - "HTTPServerError", - "HTTPInternalServerError", - "HTTPNotImplemented", - "HTTPBadGateway", - "HTTPServiceUnavailable", - "HTTPGatewayTimeout", - "HTTPVersionNotSupported", - "HTTPVariantAlsoNegotiates", - "HTTPInsufficientStorage", - "HTTPNotExtended", - "HTTPNetworkAuthenticationRequired", -) - - -class NotAppKeyWarning(UserWarning): - """Warning when not using AppKey in Application.""" - - -############################################################ -# HTTP Exceptions -############################################################ - - -class HTTPException(Response, Exception): - - # You should set in subclasses: - # status = 200 - - status_code = -1 - empty_body = False - - __http_exception__ = True - - def __init__( - self, - *, - headers: Optional[LooseHeaders] = None, - reason: Optional[str] = None, - body: Any = None, - text: Optional[str] = None, - content_type: Optional[str] = None, - ) -> None: - if body is not None: - warnings.warn( - "body argument is deprecated for http web exceptions", - DeprecationWarning, - ) - if reason is not None and ("\r" in reason or "\n" in reason): - raise ValueError("Reason cannot contain \\r or \\n") - Response.__init__( - self, - status=self.status_code, - headers=headers, - reason=reason, - body=body, - text=text, - content_type=content_type, - ) - Exception.__init__(self, self.reason) - if self.body is None and not self.empty_body: - self.text = f"{self.status}: {self.reason}" - - def __bool__(self) -> bool: - return True - - -class HTTPError(HTTPException): - """Base class for exceptions with status codes in the 400s and 500s.""" - - -class HTTPRedirection(HTTPException): - """Base class for exceptions with status codes in the 300s.""" - - -class HTTPSuccessful(HTTPException): - """Base class for exceptions with status codes in the 200s.""" - - -class HTTPOk(HTTPSuccessful): - status_code = 200 - - -class HTTPCreated(HTTPSuccessful): - status_code = 201 - - -class HTTPAccepted(HTTPSuccessful): - status_code = 202 - - -class HTTPNonAuthoritativeInformation(HTTPSuccessful): - status_code = 203 - - -class HTTPNoContent(HTTPSuccessful): - status_code = 204 - empty_body = True - - -class HTTPResetContent(HTTPSuccessful): - status_code = 205 - empty_body = True - - -class HTTPPartialContent(HTTPSuccessful): - status_code = 206 - - -############################################################ -# 3xx redirection -############################################################ - - -class HTTPMove(HTTPRedirection): - def __init__( - self, - location: StrOrURL, - *, - headers: Optional[LooseHeaders] = None, - reason: Optional[str] = None, - body: Any = None, - text: Optional[str] = None, - content_type: Optional[str] = None, - ) -> None: - if not location: - raise ValueError("HTTP redirects need a location to redirect to.") - super().__init__( - headers=headers, - reason=reason, - body=body, - text=text, - content_type=content_type, - ) - self.headers["Location"] = str(URL(location)) - self.location = location - - -class HTTPMultipleChoices(HTTPMove): - status_code = 300 - - -class HTTPMovedPermanently(HTTPMove): - status_code = 301 - - -class HTTPFound(HTTPMove): - status_code = 302 - - -# This one is safe after a POST (the redirected location will be -# retrieved with GET): -class HTTPSeeOther(HTTPMove): - status_code = 303 - - -class HTTPNotModified(HTTPRedirection): - # FIXME: this should include a date or etag header - status_code = 304 - empty_body = True - - -class HTTPUseProxy(HTTPMove): - # Not a move, but looks a little like one - status_code = 305 - - -class HTTPTemporaryRedirect(HTTPMove): - status_code = 307 - - -class HTTPPermanentRedirect(HTTPMove): - status_code = 308 - - -############################################################ -# 4xx client error -############################################################ - - -class HTTPClientError(HTTPError): - pass - - -class HTTPBadRequest(HTTPClientError): - status_code = 400 - - -class HTTPUnauthorized(HTTPClientError): - status_code = 401 - - -class HTTPPaymentRequired(HTTPClientError): - status_code = 402 - - -class HTTPForbidden(HTTPClientError): - status_code = 403 - - -class HTTPNotFound(HTTPClientError): - status_code = 404 - - -class HTTPMethodNotAllowed(HTTPClientError): - status_code = 405 - - def __init__( - self, - method: str, - allowed_methods: Iterable[str], - *, - headers: Optional[LooseHeaders] = None, - reason: Optional[str] = None, - body: Any = None, - text: Optional[str] = None, - content_type: Optional[str] = None, - ) -> None: - allow = ",".join(sorted(allowed_methods)) - super().__init__( - headers=headers, - reason=reason, - body=body, - text=text, - content_type=content_type, - ) - self.headers["Allow"] = allow - self.allowed_methods: Set[str] = set(allowed_methods) - self.method = method.upper() - - -class HTTPNotAcceptable(HTTPClientError): - status_code = 406 - - -class HTTPProxyAuthenticationRequired(HTTPClientError): - status_code = 407 - - -class HTTPRequestTimeout(HTTPClientError): - status_code = 408 - - -class HTTPConflict(HTTPClientError): - status_code = 409 - - -class HTTPGone(HTTPClientError): - status_code = 410 - - -class HTTPLengthRequired(HTTPClientError): - status_code = 411 - - -class HTTPPreconditionFailed(HTTPClientError): - status_code = 412 - - -class HTTPRequestEntityTooLarge(HTTPClientError): - status_code = 413 - - def __init__(self, max_size: float, actual_size: float, **kwargs: Any) -> None: - kwargs.setdefault( - "text", - "Maximum request body size {} exceeded, " - "actual body size {}".format(max_size, actual_size), - ) - super().__init__(**kwargs) - - -class HTTPRequestURITooLong(HTTPClientError): - status_code = 414 - - -class HTTPUnsupportedMediaType(HTTPClientError): - status_code = 415 - - -class HTTPRequestRangeNotSatisfiable(HTTPClientError): - status_code = 416 - - -class HTTPExpectationFailed(HTTPClientError): - status_code = 417 - - -class HTTPMisdirectedRequest(HTTPClientError): - status_code = 421 - - -class HTTPUnprocessableEntity(HTTPClientError): - status_code = 422 - - -class HTTPFailedDependency(HTTPClientError): - status_code = 424 - - -class HTTPUpgradeRequired(HTTPClientError): - status_code = 426 - - -class HTTPPreconditionRequired(HTTPClientError): - status_code = 428 - - -class HTTPTooManyRequests(HTTPClientError): - status_code = 429 - - -class HTTPRequestHeaderFieldsTooLarge(HTTPClientError): - status_code = 431 - - -class HTTPUnavailableForLegalReasons(HTTPClientError): - status_code = 451 - - def __init__( - self, - link: Optional[StrOrURL], - *, - headers: Optional[LooseHeaders] = None, - reason: Optional[str] = None, - body: Any = None, - text: Optional[str] = None, - content_type: Optional[str] = None, - ) -> None: - super().__init__( - headers=headers, - reason=reason, - body=body, - text=text, - content_type=content_type, - ) - self._link = None - if link: - self._link = URL(link) - self.headers["Link"] = f'<{str(self._link)}>; rel="blocked-by"' - - @property - def link(self) -> Optional[URL]: - return self._link - - -############################################################ -# 5xx Server Error -############################################################ -# Response status codes beginning with the digit "5" indicate cases in -# which the server is aware that it has erred or is incapable of -# performing the request. Except when responding to a HEAD request, the -# server SHOULD include an entity containing an explanation of the error -# situation, and whether it is a temporary or permanent condition. User -# agents SHOULD display any included entity to the user. These response -# codes are applicable to any request method. - - -class HTTPServerError(HTTPError): - pass - - -class HTTPInternalServerError(HTTPServerError): - status_code = 500 - - -class HTTPNotImplemented(HTTPServerError): - status_code = 501 - - -class HTTPBadGateway(HTTPServerError): - status_code = 502 - - -class HTTPServiceUnavailable(HTTPServerError): - status_code = 503 - - -class HTTPGatewayTimeout(HTTPServerError): - status_code = 504 - - -class HTTPVersionNotSupported(HTTPServerError): - status_code = 505 - - -class HTTPVariantAlsoNegotiates(HTTPServerError): - status_code = 506 - - -class HTTPInsufficientStorage(HTTPServerError): - status_code = 507 - - -class HTTPNotExtended(HTTPServerError): - status_code = 510 - - -class HTTPNetworkAuthenticationRequired(HTTPServerError): - status_code = 511 diff --git a/venv/lib/python3.9/site-packages/aiohttp/web_fileresponse.py b/venv/lib/python3.9/site-packages/aiohttp/web_fileresponse.py deleted file mode 100644 index bba2c2c..0000000 --- a/venv/lib/python3.9/site-packages/aiohttp/web_fileresponse.py +++ /dev/null @@ -1,418 +0,0 @@ -import asyncio -import io -import os -import pathlib -import sys -from contextlib import suppress -from enum import Enum, auto -from mimetypes import MimeTypes -from stat import S_ISREG -from types import MappingProxyType -from typing import ( # noqa - IO, - TYPE_CHECKING, - Any, - Awaitable, - Callable, - Final, - Iterator, - List, - Optional, - Set, - Tuple, - Union, - cast, -) - -from . import hdrs -from .abc import AbstractStreamWriter -from .helpers import ETAG_ANY, ETag, must_be_empty_body -from .typedefs import LooseHeaders, PathLike -from .web_exceptions import ( - HTTPForbidden, - HTTPNotFound, - HTTPNotModified, - HTTPPartialContent, - HTTPPreconditionFailed, - HTTPRequestRangeNotSatisfiable, -) -from .web_response import StreamResponse - -__all__ = ("FileResponse",) - -if TYPE_CHECKING: - from .web_request import BaseRequest - - -_T_OnChunkSent = Optional[Callable[[bytes], Awaitable[None]]] - - -NOSENDFILE: Final[bool] = bool(os.environ.get("AIOHTTP_NOSENDFILE")) - -CONTENT_TYPES: Final[MimeTypes] = MimeTypes() - -# File extension to IANA encodings map that will be checked in the order defined. -ENCODING_EXTENSIONS = MappingProxyType( - {ext: CONTENT_TYPES.encodings_map[ext] for ext in (".br", ".gz")} -) - -FALLBACK_CONTENT_TYPE = "application/octet-stream" - -# Provide additional MIME type/extension pairs to be recognized. -# https://en.wikipedia.org/wiki/List_of_archive_formats#Compression_only -ADDITIONAL_CONTENT_TYPES = MappingProxyType( - { - "application/gzip": ".gz", - "application/x-brotli": ".br", - "application/x-bzip2": ".bz2", - "application/x-compress": ".Z", - "application/x-xz": ".xz", - } -) - - -class _FileResponseResult(Enum): - """The result of the file response.""" - - SEND_FILE = auto() # Ie a regular file to send - NOT_ACCEPTABLE = auto() # Ie a socket, or non-regular file - PRE_CONDITION_FAILED = auto() # Ie If-Match or If-None-Match failed - NOT_MODIFIED = auto() # 304 Not Modified - - -# Add custom pairs and clear the encodings map so guess_type ignores them. -CONTENT_TYPES.encodings_map.clear() -for content_type, extension in ADDITIONAL_CONTENT_TYPES.items(): - CONTENT_TYPES.add_type(content_type, extension) - - -_CLOSE_FUTURES: Set[asyncio.Future[None]] = set() - - -class FileResponse(StreamResponse): - """A response object can be used to send files.""" - - def __init__( - self, - path: PathLike, - chunk_size: int = 256 * 1024, - status: int = 200, - reason: Optional[str] = None, - headers: Optional[LooseHeaders] = None, - ) -> None: - super().__init__(status=status, reason=reason, headers=headers) - - self._path = pathlib.Path(path) - self._chunk_size = chunk_size - - def _seek_and_read(self, fobj: IO[Any], offset: int, chunk_size: int) -> bytes: - fobj.seek(offset) - return fobj.read(chunk_size) # type: ignore[no-any-return] - - async def _sendfile_fallback( - self, writer: AbstractStreamWriter, fobj: IO[Any], offset: int, count: int - ) -> AbstractStreamWriter: - # To keep memory usage low,fobj is transferred in chunks - # controlled by the constructor's chunk_size argument. - - chunk_size = self._chunk_size - loop = asyncio.get_event_loop() - chunk = await loop.run_in_executor( - None, self._seek_and_read, fobj, offset, min(chunk_size, count) - ) - while chunk: - await writer.write(chunk) - count = count - len(chunk) - if count <= 0: - break - chunk = await loop.run_in_executor(None, fobj.read, min(chunk_size, count)) - - await writer.drain() - return writer - - async def _sendfile( - self, request: "BaseRequest", fobj: IO[Any], offset: int, count: int - ) -> AbstractStreamWriter: - writer = await super().prepare(request) - assert writer is not None - - if NOSENDFILE or self.compression: - return await self._sendfile_fallback(writer, fobj, offset, count) - - loop = request._loop - transport = request.transport - assert transport is not None - - try: - await loop.sendfile(transport, fobj, offset, count) - except NotImplementedError: - return await self._sendfile_fallback(writer, fobj, offset, count) - - await super().write_eof() - return writer - - @staticmethod - def _etag_match(etag_value: str, etags: Tuple[ETag, ...], *, weak: bool) -> bool: - if len(etags) == 1 and etags[0].value == ETAG_ANY: - return True - return any( - etag.value == etag_value for etag in etags if weak or not etag.is_weak - ) - - async def _not_modified( - self, request: "BaseRequest", etag_value: str, last_modified: float - ) -> Optional[AbstractStreamWriter]: - self.set_status(HTTPNotModified.status_code) - self._length_check = False - self.etag = etag_value - self.last_modified = last_modified - # Delete any Content-Length headers provided by user. HTTP 304 - # should always have empty response body - return await super().prepare(request) - - async def _precondition_failed( - self, request: "BaseRequest" - ) -> Optional[AbstractStreamWriter]: - self.set_status(HTTPPreconditionFailed.status_code) - self.content_length = 0 - return await super().prepare(request) - - def _make_response( - self, request: "BaseRequest", accept_encoding: str - ) -> Tuple[ - _FileResponseResult, Optional[io.BufferedReader], os.stat_result, Optional[str] - ]: - """Return the response result, io object, stat result, and encoding. - - If an uncompressed file is returned, the encoding is set to - :py:data:`None`. - - This method should be called from a thread executor - since it calls os.stat which may block. - """ - file_path, st, file_encoding = self._get_file_path_stat_encoding( - accept_encoding - ) - if not file_path: - return _FileResponseResult.NOT_ACCEPTABLE, None, st, None - - etag_value = f"{st.st_mtime_ns:x}-{st.st_size:x}" - - # https://www.rfc-editor.org/rfc/rfc9110#section-13.1.1-2 - if (ifmatch := request.if_match) is not None and not self._etag_match( - etag_value, ifmatch, weak=False - ): - return _FileResponseResult.PRE_CONDITION_FAILED, None, st, file_encoding - - if ( - (unmodsince := request.if_unmodified_since) is not None - and ifmatch is None - and st.st_mtime > unmodsince.timestamp() - ): - return _FileResponseResult.PRE_CONDITION_FAILED, None, st, file_encoding - - # https://www.rfc-editor.org/rfc/rfc9110#section-13.1.2-2 - if (ifnonematch := request.if_none_match) is not None and self._etag_match( - etag_value, ifnonematch, weak=True - ): - return _FileResponseResult.NOT_MODIFIED, None, st, file_encoding - - if ( - (modsince := request.if_modified_since) is not None - and ifnonematch is None - and st.st_mtime <= modsince.timestamp() - ): - return _FileResponseResult.NOT_MODIFIED, None, st, file_encoding - - fobj = file_path.open("rb") - with suppress(OSError): - # fstat() may not be available on all platforms - # Once we open the file, we want the fstat() to ensure - # the file has not changed between the first stat() - # and the open(). - st = os.stat(fobj.fileno()) - return _FileResponseResult.SEND_FILE, fobj, st, file_encoding - - def _get_file_path_stat_encoding( - self, accept_encoding: str - ) -> Tuple[Optional[pathlib.Path], os.stat_result, Optional[str]]: - file_path = self._path - for file_extension, file_encoding in ENCODING_EXTENSIONS.items(): - if file_encoding not in accept_encoding: - continue - - compressed_path = file_path.with_suffix(file_path.suffix + file_extension) - with suppress(OSError): - # Do not follow symlinks and ignore any non-regular files. - st = compressed_path.lstat() - if S_ISREG(st.st_mode): - return compressed_path, st, file_encoding - - # Fallback to the uncompressed file - st = file_path.stat() - return file_path if S_ISREG(st.st_mode) else None, st, None - - async def prepare(self, request: "BaseRequest") -> Optional[AbstractStreamWriter]: - loop = asyncio.get_running_loop() - # Encoding comparisons should be case-insensitive - # https://www.rfc-editor.org/rfc/rfc9110#section-8.4.1 - accept_encoding = request.headers.get(hdrs.ACCEPT_ENCODING, "").lower() - try: - response_result, fobj, st, file_encoding = await loop.run_in_executor( - None, self._make_response, request, accept_encoding - ) - except PermissionError: - self.set_status(HTTPForbidden.status_code) - return await super().prepare(request) - except OSError: - # Most likely to be FileNotFoundError or OSError for circular - # symlinks in python >= 3.13, so respond with 404. - self.set_status(HTTPNotFound.status_code) - return await super().prepare(request) - - # Forbid special files like sockets, pipes, devices, etc. - if response_result is _FileResponseResult.NOT_ACCEPTABLE: - self.set_status(HTTPForbidden.status_code) - return await super().prepare(request) - - if response_result is _FileResponseResult.PRE_CONDITION_FAILED: - return await self._precondition_failed(request) - - if response_result is _FileResponseResult.NOT_MODIFIED: - etag_value = f"{st.st_mtime_ns:x}-{st.st_size:x}" - last_modified = st.st_mtime - return await self._not_modified(request, etag_value, last_modified) - - assert fobj is not None - try: - return await self._prepare_open_file(request, fobj, st, file_encoding) - finally: - # We do not await here because we do not want to wait - # for the executor to finish before returning the response - # so the connection can begin servicing another request - # as soon as possible. - close_future = loop.run_in_executor(None, fobj.close) - # Hold a strong reference to the future to prevent it from being - # garbage collected before it completes. - _CLOSE_FUTURES.add(close_future) - close_future.add_done_callback(_CLOSE_FUTURES.remove) - - async def _prepare_open_file( - self, - request: "BaseRequest", - fobj: io.BufferedReader, - st: os.stat_result, - file_encoding: Optional[str], - ) -> Optional[AbstractStreamWriter]: - status = self._status - file_size: int = st.st_size - file_mtime: float = st.st_mtime - count: int = file_size - start: Optional[int] = None - - if (ifrange := request.if_range) is None or file_mtime <= ifrange.timestamp(): - # If-Range header check: - # condition = cached date >= last modification date - # return 206 if True else 200. - # if False: - # Range header would not be processed, return 200 - # if True but Range header missing - # return 200 - try: - rng = request.http_range - start = rng.start - end: Optional[int] = rng.stop - except ValueError: - # https://tools.ietf.org/html/rfc7233: - # A server generating a 416 (Range Not Satisfiable) response to - # a byte-range request SHOULD send a Content-Range header field - # with an unsatisfied-range value. - # The complete-length in a 416 response indicates the current - # length of the selected representation. - # - # Will do the same below. Many servers ignore this and do not - # send a Content-Range header with HTTP 416 - self._headers[hdrs.CONTENT_RANGE] = f"bytes */{file_size}" - self.set_status(HTTPRequestRangeNotSatisfiable.status_code) - return await super().prepare(request) - - # If a range request has been made, convert start, end slice - # notation into file pointer offset and count - if start is not None: - if start < 0 and end is None: # return tail of file - start += file_size - if start < 0: - # if Range:bytes=-1000 in request header but file size - # is only 200, there would be trouble without this - start = 0 - count = file_size - start - else: - # rfc7233:If the last-byte-pos value is - # absent, or if the value is greater than or equal to - # the current length of the representation data, - # the byte range is interpreted as the remainder - # of the representation (i.e., the server replaces the - # value of last-byte-pos with a value that is one less than - # the current length of the selected representation). - count = ( - min(end if end is not None else file_size, file_size) - start - ) - - if start >= file_size: - # HTTP 416 should be returned in this case. - # - # According to https://tools.ietf.org/html/rfc7233: - # If a valid byte-range-set includes at least one - # byte-range-spec with a first-byte-pos that is less than - # the current length of the representation, or at least one - # suffix-byte-range-spec with a non-zero suffix-length, - # then the byte-range-set is satisfiable. Otherwise, the - # byte-range-set is unsatisfiable. - self._headers[hdrs.CONTENT_RANGE] = f"bytes */{file_size}" - self.set_status(HTTPRequestRangeNotSatisfiable.status_code) - return await super().prepare(request) - - status = HTTPPartialContent.status_code - # Even though you are sending the whole file, you should still - # return a HTTP 206 for a Range request. - self.set_status(status) - - # If the Content-Type header is not already set, guess it based on the - # extension of the request path. The encoding returned by guess_type - # can be ignored since the map was cleared above. - if hdrs.CONTENT_TYPE not in self._headers: - if sys.version_info >= (3, 13): - guesser = CONTENT_TYPES.guess_file_type - else: - guesser = CONTENT_TYPES.guess_type - self.content_type = guesser(self._path)[0] or FALLBACK_CONTENT_TYPE - - if file_encoding: - self._headers[hdrs.CONTENT_ENCODING] = file_encoding - self._headers[hdrs.VARY] = hdrs.ACCEPT_ENCODING - # Disable compression if we are already sending - # a compressed file since we don't want to double - # compress. - self._compression = False - - self.etag = f"{st.st_mtime_ns:x}-{st.st_size:x}" - self.last_modified = file_mtime - self.content_length = count - - self._headers[hdrs.ACCEPT_RANGES] = "bytes" - - if status == HTTPPartialContent.status_code: - real_start = start - assert real_start is not None - self._headers[hdrs.CONTENT_RANGE] = "bytes {}-{}/{}".format( - real_start, real_start + count - 1, file_size - ) - - # If we are sending 0 bytes calling sendfile() will throw a ValueError - if count == 0 or must_be_empty_body(request.method, status): - return await super().prepare(request) - - # be aware that start could be None or int=0 here. - offset = start or 0 - - return await self._sendfile(request, fobj, offset, count) diff --git a/venv/lib/python3.9/site-packages/aiohttp/web_log.py b/venv/lib/python3.9/site-packages/aiohttp/web_log.py deleted file mode 100644 index 02a545a..0000000 --- a/venv/lib/python3.9/site-packages/aiohttp/web_log.py +++ /dev/null @@ -1,234 +0,0 @@ -import datetime -import functools -import logging -import os -import re -import time as time_mod -from collections import namedtuple -from collections.abc import Iterable -from typing import Callable, ClassVar, Dict, List, Optional, Tuple - -from .abc import AbstractAccessLogger -from .web_request import BaseRequest -from .web_response import StreamResponse - -KeyMethod = namedtuple("KeyMethod", "key method") - - -class AccessLogger(AbstractAccessLogger): - """Helper object to log access. - - Usage: - log = logging.getLogger("spam") - log_format = "%a %{User-Agent}i" - access_logger = AccessLogger(log, log_format) - access_logger.log(request, response, time) - - Format: - %% The percent sign - %a Remote IP-address (IP-address of proxy if using reverse proxy) - %t Time when the request was started to process - %P The process ID of the child that serviced the request - %r First line of request - %s Response status code - %b Size of response in bytes, including HTTP headers - %T Time taken to serve the request, in seconds - %Tf Time taken to serve the request, in seconds with floating fraction - in .06f format - %D Time taken to serve the request, in microseconds - %{FOO}i request.headers['FOO'] - %{FOO}o response.headers['FOO'] - %{FOO}e os.environ['FOO'] - - """ - - LOG_FORMAT_MAP = { - "a": "remote_address", - "t": "request_start_time", - "P": "process_id", - "r": "first_request_line", - "s": "response_status", - "b": "response_size", - "T": "request_time", - "Tf": "request_time_frac", - "D": "request_time_micro", - "i": "request_header", - "o": "response_header", - } - - LOG_FORMAT = '%a %t "%r" %s %b "%{Referer}i" "%{User-Agent}i"' - FORMAT_RE = re.compile(r"%(\{([A-Za-z0-9\-_]+)\}([ioe])|[atPrsbOD]|Tf?)") - CLEANUP_RE = re.compile(r"(%[^s])") - _FORMAT_CACHE: Dict[str, Tuple[str, List[KeyMethod]]] = {} - - _cached_tz: ClassVar[Optional[datetime.timezone]] = None - _cached_tz_expires: ClassVar[float] = 0.0 - - def __init__(self, logger: logging.Logger, log_format: str = LOG_FORMAT) -> None: - """Initialise the logger. - - logger is a logger object to be used for logging. - log_format is a string with apache compatible log format description. - - """ - super().__init__(logger, log_format=log_format) - - _compiled_format = AccessLogger._FORMAT_CACHE.get(log_format) - if not _compiled_format: - _compiled_format = self.compile_format(log_format) - AccessLogger._FORMAT_CACHE[log_format] = _compiled_format - - self._log_format, self._methods = _compiled_format - - def compile_format(self, log_format: str) -> Tuple[str, List[KeyMethod]]: - """Translate log_format into form usable by modulo formatting - - All known atoms will be replaced with %s - Also methods for formatting of those atoms will be added to - _methods in appropriate order - - For example we have log_format = "%a %t" - This format will be translated to "%s %s" - Also contents of _methods will be - [self._format_a, self._format_t] - These method will be called and results will be passed - to translated string format. - - Each _format_* method receive 'args' which is list of arguments - given to self.log - - Exceptions are _format_e, _format_i and _format_o methods which - also receive key name (by functools.partial) - - """ - # list of (key, method) tuples, we don't use an OrderedDict as users - # can repeat the same key more than once - methods = list() - - for atom in self.FORMAT_RE.findall(log_format): - if atom[1] == "": - format_key1 = self.LOG_FORMAT_MAP[atom[0]] - m = getattr(AccessLogger, "_format_%s" % atom[0]) - key_method = KeyMethod(format_key1, m) - else: - format_key2 = (self.LOG_FORMAT_MAP[atom[2]], atom[1]) - m = getattr(AccessLogger, "_format_%s" % atom[2]) - key_method = KeyMethod(format_key2, functools.partial(m, atom[1])) - - methods.append(key_method) - - log_format = self.FORMAT_RE.sub(r"%s", log_format) - log_format = self.CLEANUP_RE.sub(r"%\1", log_format) - return log_format, methods - - @staticmethod - def _format_i( - key: str, request: BaseRequest, response: StreamResponse, time: float - ) -> str: - if request is None: - return "(no headers)" - - # suboptimal, make istr(key) once - return request.headers.get(key, "-") - - @staticmethod - def _format_o( - key: str, request: BaseRequest, response: StreamResponse, time: float - ) -> str: - # suboptimal, make istr(key) once - return response.headers.get(key, "-") - - @staticmethod - def _format_a(request: BaseRequest, response: StreamResponse, time: float) -> str: - if request is None: - return "-" - ip = request.remote - return ip if ip is not None else "-" - - @classmethod - def _get_local_time(cls) -> datetime.datetime: - if cls._cached_tz is None or time_mod.time() >= cls._cached_tz_expires: - gmtoff = time_mod.localtime().tm_gmtoff - cls._cached_tz = tz = datetime.timezone(datetime.timedelta(seconds=gmtoff)) - - now = datetime.datetime.now(tz) - # Expire at every 30 mins, as any DST change should occur at 0/30 mins past. - d = now + datetime.timedelta(minutes=30) - d = d.replace(minute=30 if d.minute >= 30 else 0, second=0, microsecond=0) - cls._cached_tz_expires = d.timestamp() - return now - - return datetime.datetime.now(cls._cached_tz) - - @staticmethod - def _format_t(request: BaseRequest, response: StreamResponse, time: float) -> str: - now = AccessLogger._get_local_time() - start_time = now - datetime.timedelta(seconds=time) - return start_time.strftime("[%d/%b/%Y:%H:%M:%S %z]") - - @staticmethod - def _format_P(request: BaseRequest, response: StreamResponse, time: float) -> str: - return "<%s>" % os.getpid() - - @staticmethod - def _format_r(request: BaseRequest, response: StreamResponse, time: float) -> str: - if request is None: - return "-" - return "{} {} HTTP/{}.{}".format( - request.method, - request.path_qs, - request.version.major, - request.version.minor, - ) - - @staticmethod - def _format_s(request: BaseRequest, response: StreamResponse, time: float) -> int: - return response.status - - @staticmethod - def _format_b(request: BaseRequest, response: StreamResponse, time: float) -> int: - return response.body_length - - @staticmethod - def _format_T(request: BaseRequest, response: StreamResponse, time: float) -> str: - return str(round(time)) - - @staticmethod - def _format_Tf(request: BaseRequest, response: StreamResponse, time: float) -> str: - return "%06f" % time - - @staticmethod - def _format_D(request: BaseRequest, response: StreamResponse, time: float) -> str: - return str(round(time * 1000000)) - - def _format_line( - self, request: BaseRequest, response: StreamResponse, time: float - ) -> Iterable[Tuple[str, Callable[[BaseRequest, StreamResponse, float], str]]]: - return [(key, method(request, response, time)) for key, method in self._methods] - - @property - def enabled(self) -> bool: - """Check if logger is enabled.""" - # Avoid formatting the log line if it will not be emitted. - return self.logger.isEnabledFor(logging.INFO) - - def log(self, request: BaseRequest, response: StreamResponse, time: float) -> None: - try: - fmt_info = self._format_line(request, response, time) - - values = list() - extra = dict() - for key, value in fmt_info: - values.append(value) - - if key.__class__ is str: - extra[key] = value - else: - k1, k2 = key # type: ignore[misc] - dct = extra.get(k1, {}) # type: ignore[var-annotated,has-type] - dct[k2] = value # type: ignore[index,has-type] - extra[k1] = dct # type: ignore[has-type,assignment] - - self.logger.info(self._log_format % tuple(values), extra=extra) - except Exception: - self.logger.exception("Error in logging") diff --git a/venv/lib/python3.9/site-packages/aiohttp/web_middlewares.py b/venv/lib/python3.9/site-packages/aiohttp/web_middlewares.py deleted file mode 100644 index 2f1f5f5..0000000 --- a/venv/lib/python3.9/site-packages/aiohttp/web_middlewares.py +++ /dev/null @@ -1,121 +0,0 @@ -import re -from typing import TYPE_CHECKING, Tuple, Type, TypeVar - -from .typedefs import Handler, Middleware -from .web_exceptions import HTTPMove, HTTPPermanentRedirect -from .web_request import Request -from .web_response import StreamResponse -from .web_urldispatcher import SystemRoute - -__all__ = ( - "middleware", - "normalize_path_middleware", -) - -if TYPE_CHECKING: - from .web_app import Application - -_Func = TypeVar("_Func") - - -async def _check_request_resolves(request: Request, path: str) -> Tuple[bool, Request]: - alt_request = request.clone(rel_url=path) - - match_info = await request.app.router.resolve(alt_request) - alt_request._match_info = match_info - - if match_info.http_exception is None: - return True, alt_request - - return False, request - - -def middleware(f: _Func) -> _Func: - f.__middleware_version__ = 1 # type: ignore[attr-defined] - return f - - -def normalize_path_middleware( - *, - append_slash: bool = True, - remove_slash: bool = False, - merge_slashes: bool = True, - redirect_class: Type[HTTPMove] = HTTPPermanentRedirect, -) -> Middleware: - """Factory for producing a middleware that normalizes the path of a request. - - Normalizing means: - - Add or remove a trailing slash to the path. - - Double slashes are replaced by one. - - The middleware returns as soon as it finds a path that resolves - correctly. The order if both merge and append/remove are enabled is - 1) merge slashes - 2) append/remove slash - 3) both merge slashes and append/remove slash. - If the path resolves with at least one of those conditions, it will - redirect to the new path. - - Only one of `append_slash` and `remove_slash` can be enabled. If both - are `True` the factory will raise an assertion error - - If `append_slash` is `True` the middleware will append a slash when - needed. If a resource is defined with trailing slash and the request - comes without it, it will append it automatically. - - If `remove_slash` is `True`, `append_slash` must be `False`. When enabled - the middleware will remove trailing slashes and redirect if the resource - is defined - - If merge_slashes is True, merge multiple consecutive slashes in the - path into one. - """ - correct_configuration = not (append_slash and remove_slash) - assert correct_configuration, "Cannot both remove and append slash" - - @middleware - async def impl(request: Request, handler: Handler) -> StreamResponse: - if isinstance(request.match_info.route, SystemRoute): - paths_to_check = [] - if "?" in request.raw_path: - path, query = request.raw_path.split("?", 1) - query = "?" + query - else: - query = "" - path = request.raw_path - - if merge_slashes: - paths_to_check.append(re.sub("//+", "/", path)) - if append_slash and not request.path.endswith("/"): - paths_to_check.append(path + "/") - if remove_slash and request.path.endswith("/"): - paths_to_check.append(path[:-1]) - if merge_slashes and append_slash: - paths_to_check.append(re.sub("//+", "/", path + "/")) - if merge_slashes and remove_slash: - merged_slashes = re.sub("//+", "/", path) - paths_to_check.append(merged_slashes[:-1]) - - for path in paths_to_check: - path = re.sub("^//+", "/", path) # SECURITY: GHSA-v6wp-4m6f-gcjg - resolves, request = await _check_request_resolves(request, path) - if resolves: - raise redirect_class(request.raw_path + query) - - return await handler(request) - - return impl - - -def _fix_request_current_app(app: "Application") -> Middleware: - @middleware - async def impl(request: Request, handler: Handler) -> StreamResponse: - match_info = request.match_info - prev = match_info.current_app - match_info.current_app = app - try: - return await handler(request) - finally: - match_info.current_app = prev - - return impl diff --git a/venv/lib/python3.9/site-packages/aiohttp/web_protocol.py b/venv/lib/python3.9/site-packages/aiohttp/web_protocol.py deleted file mode 100644 index 84e70e5..0000000 --- a/venv/lib/python3.9/site-packages/aiohttp/web_protocol.py +++ /dev/null @@ -1,799 +0,0 @@ -import asyncio -import asyncio.streams -import sys -import traceback -import warnings -from collections import deque -from contextlib import suppress -from html import escape as html_escape -from http import HTTPStatus -from logging import Logger -from typing import ( - TYPE_CHECKING, - Any, - Awaitable, - Callable, - Deque, - Optional, - Sequence, - Tuple, - Type, - Union, - cast, -) - -import attr -import yarl -from propcache import under_cached_property - -from .abc import AbstractAccessLogger, AbstractStreamWriter -from .base_protocol import BaseProtocol -from .helpers import ceil_timeout -from .http import ( - HttpProcessingError, - HttpRequestParser, - HttpVersion10, - RawRequestMessage, - StreamWriter, -) -from .http_exceptions import BadHttpMethod -from .log import access_logger, server_logger -from .streams import EMPTY_PAYLOAD, StreamReader -from .tcp_helpers import tcp_keepalive -from .web_exceptions import HTTPException, HTTPInternalServerError -from .web_log import AccessLogger -from .web_request import BaseRequest -from .web_response import Response, StreamResponse - -__all__ = ("RequestHandler", "RequestPayloadError", "PayloadAccessError") - -if TYPE_CHECKING: - import ssl - - from .web_server import Server - - -_RequestFactory = Callable[ - [ - RawRequestMessage, - StreamReader, - "RequestHandler", - AbstractStreamWriter, - "asyncio.Task[None]", - ], - BaseRequest, -] - -_RequestHandler = Callable[[BaseRequest], Awaitable[StreamResponse]] - -ERROR = RawRequestMessage( - "UNKNOWN", - "/", - HttpVersion10, - {}, # type: ignore[arg-type] - {}, # type: ignore[arg-type] - True, - None, - False, - False, - yarl.URL("/"), -) - - -class RequestPayloadError(Exception): - """Payload parsing error.""" - - -class PayloadAccessError(Exception): - """Payload was accessed after response was sent.""" - - -_PAYLOAD_ACCESS_ERROR = PayloadAccessError() - - -@attr.s(auto_attribs=True, frozen=True, slots=True) -class _ErrInfo: - status: int - exc: BaseException - message: str - - -_MsgType = Tuple[Union[RawRequestMessage, _ErrInfo], StreamReader] - - -class RequestHandler(BaseProtocol): - """HTTP protocol implementation. - - RequestHandler handles incoming HTTP request. It reads request line, - request headers and request payload and calls handle_request() method. - By default it always returns with 404 response. - - RequestHandler handles errors in incoming request, like bad - status line, bad headers or incomplete payload. If any error occurs, - connection gets closed. - - keepalive_timeout -- number of seconds before closing - keep-alive connection - - tcp_keepalive -- TCP keep-alive is on, default is on - - debug -- enable debug mode - - logger -- custom logger object - - access_log_class -- custom class for access_logger - - access_log -- custom logging object - - access_log_format -- access log format string - - loop -- Optional event loop - - max_line_size -- Optional maximum header line size - - max_field_size -- Optional maximum header field size - - max_headers -- Optional maximum header size - - timeout_ceil_threshold -- Optional value to specify - threshold to ceil() timeout - values - - """ - - __slots__ = ( - "max_field_size", - "max_headers", - "max_line_size", - "_request_count", - "_keepalive", - "_manager", - "_request_handler", - "_request_factory", - "_tcp_keepalive", - "_next_keepalive_close_time", - "_keepalive_handle", - "_keepalive_timeout", - "_lingering_time", - "_messages", - "_message_tail", - "_handler_waiter", - "_waiter", - "_task_handler", - "_upgrade", - "_payload_parser", - "_request_parser", - "_reading_paused", - "logger", - "debug", - "access_log", - "access_logger", - "_close", - "_force_close", - "_current_request", - "_timeout_ceil_threshold", - "_request_in_progress", - "_logging_enabled", - "_cache", - ) - - def __init__( - self, - manager: "Server", - *, - loop: asyncio.AbstractEventLoop, - # Default should be high enough that it's likely longer than a reverse proxy. - keepalive_timeout: float = 3630, - tcp_keepalive: bool = True, - logger: Logger = server_logger, - access_log_class: Type[AbstractAccessLogger] = AccessLogger, - access_log: Logger = access_logger, - access_log_format: str = AccessLogger.LOG_FORMAT, - debug: bool = False, - max_line_size: int = 8190, - max_headers: int = 128, - max_field_size: int = 8190, - lingering_time: float = 10.0, - read_bufsize: int = 2**16, - auto_decompress: bool = True, - timeout_ceil_threshold: float = 5, - ): - super().__init__(loop) - - # _request_count is the number of requests processed with the same connection. - self._request_count = 0 - self._keepalive = False - self._current_request: Optional[BaseRequest] = None - self._manager: Optional[Server] = manager - self._request_handler: Optional[_RequestHandler] = manager.request_handler - self._request_factory: Optional[_RequestFactory] = manager.request_factory - - self.max_line_size = max_line_size - self.max_headers = max_headers - self.max_field_size = max_field_size - - self._tcp_keepalive = tcp_keepalive - # placeholder to be replaced on keepalive timeout setup - self._next_keepalive_close_time = 0.0 - self._keepalive_handle: Optional[asyncio.Handle] = None - self._keepalive_timeout = keepalive_timeout - self._lingering_time = float(lingering_time) - - self._messages: Deque[_MsgType] = deque() - self._message_tail = b"" - - self._waiter: Optional[asyncio.Future[None]] = None - self._handler_waiter: Optional[asyncio.Future[None]] = None - self._task_handler: Optional[asyncio.Task[None]] = None - - self._upgrade = False - self._payload_parser: Any = None - self._request_parser: Optional[HttpRequestParser] = HttpRequestParser( - self, - loop, - read_bufsize, - max_line_size=max_line_size, - max_field_size=max_field_size, - max_headers=max_headers, - payload_exception=RequestPayloadError, - auto_decompress=auto_decompress, - ) - - self._timeout_ceil_threshold: float = 5 - try: - self._timeout_ceil_threshold = float(timeout_ceil_threshold) - except (TypeError, ValueError): - pass - - self.logger = logger - self.debug = debug - self.access_log = access_log - if access_log: - self.access_logger: Optional[AbstractAccessLogger] = access_log_class( - access_log, access_log_format - ) - self._logging_enabled = self.access_logger.enabled - else: - self.access_logger = None - self._logging_enabled = False - - self._close = False - self._force_close = False - self._request_in_progress = False - self._cache: dict[str, Any] = {} - - def __repr__(self) -> str: - return "<{} {}>".format( - self.__class__.__name__, - "connected" if self.transport is not None else "disconnected", - ) - - @under_cached_property - def ssl_context(self) -> Optional["ssl.SSLContext"]: - """Return SSLContext if available.""" - return ( - None - if self.transport is None - else self.transport.get_extra_info("sslcontext") - ) - - @under_cached_property - def peername( - self, - ) -> Optional[Union[str, Tuple[str, int, int, int], Tuple[str, int]]]: - """Return peername if available.""" - return ( - None - if self.transport is None - else self.transport.get_extra_info("peername") - ) - - @property - def keepalive_timeout(self) -> float: - return self._keepalive_timeout - - async def shutdown(self, timeout: Optional[float] = 15.0) -> None: - """Do worker process exit preparations. - - We need to clean up everything and stop accepting requests. - It is especially important for keep-alive connections. - """ - self._force_close = True - - if self._keepalive_handle is not None: - self._keepalive_handle.cancel() - - # Wait for graceful handler completion - if self._request_in_progress: - # The future is only created when we are shutting - # down while the handler is still processing a request - # to avoid creating a future for every request. - self._handler_waiter = self._loop.create_future() - try: - async with ceil_timeout(timeout): - await self._handler_waiter - except (asyncio.CancelledError, asyncio.TimeoutError): - self._handler_waiter = None - if ( - sys.version_info >= (3, 11) - and (task := asyncio.current_task()) - and task.cancelling() - ): - raise - # Then cancel handler and wait - try: - async with ceil_timeout(timeout): - if self._current_request is not None: - self._current_request._cancel(asyncio.CancelledError()) - - if self._task_handler is not None and not self._task_handler.done(): - await asyncio.shield(self._task_handler) - except (asyncio.CancelledError, asyncio.TimeoutError): - if ( - sys.version_info >= (3, 11) - and (task := asyncio.current_task()) - and task.cancelling() - ): - raise - - # force-close non-idle handler - if self._task_handler is not None: - self._task_handler.cancel() - - self.force_close() - - def connection_made(self, transport: asyncio.BaseTransport) -> None: - super().connection_made(transport) - - real_transport = cast(asyncio.Transport, transport) - if self._tcp_keepalive: - tcp_keepalive(real_transport) - - assert self._manager is not None - self._manager.connection_made(self, real_transport) - - loop = self._loop - if sys.version_info >= (3, 12): - task = asyncio.Task(self.start(), loop=loop, eager_start=True) - else: - task = loop.create_task(self.start()) - self._task_handler = task - - def connection_lost(self, exc: Optional[BaseException]) -> None: - if self._manager is None: - return - self._manager.connection_lost(self, exc) - - # Grab value before setting _manager to None. - handler_cancellation = self._manager.handler_cancellation - - self.force_close() - super().connection_lost(exc) - self._manager = None - self._request_factory = None - self._request_handler = None - self._request_parser = None - - if self._keepalive_handle is not None: - self._keepalive_handle.cancel() - - if self._current_request is not None: - if exc is None: - exc = ConnectionResetError("Connection lost") - self._current_request._cancel(exc) - - if handler_cancellation and self._task_handler is not None: - self._task_handler.cancel() - - self._task_handler = None - - if self._payload_parser is not None: - self._payload_parser.feed_eof() - self._payload_parser = None - - def set_parser(self, parser: Any) -> None: - # Actual type is WebReader - assert self._payload_parser is None - - self._payload_parser = parser - - if self._message_tail: - self._payload_parser.feed_data(self._message_tail) - self._message_tail = b"" - - def eof_received(self) -> None: - pass - - def data_received(self, data: bytes) -> None: - if self._force_close or self._close: - return - # parse http messages - messages: Sequence[_MsgType] - if self._payload_parser is None and not self._upgrade: - assert self._request_parser is not None - try: - messages, upgraded, tail = self._request_parser.feed_data(data) - except HttpProcessingError as exc: - messages = [ - (_ErrInfo(status=400, exc=exc, message=exc.message), EMPTY_PAYLOAD) - ] - upgraded = False - tail = b"" - - for msg, payload in messages or (): - self._request_count += 1 - self._messages.append((msg, payload)) - - waiter = self._waiter - if messages and waiter is not None and not waiter.done(): - # don't set result twice - waiter.set_result(None) - - self._upgrade = upgraded - if upgraded and tail: - self._message_tail = tail - - # no parser, just store - elif self._payload_parser is None and self._upgrade and data: - self._message_tail += data - - # feed payload - elif data: - eof, tail = self._payload_parser.feed_data(data) - if eof: - self.close() - - def keep_alive(self, val: bool) -> None: - """Set keep-alive connection mode. - - :param bool val: new state. - """ - self._keepalive = val - if self._keepalive_handle: - self._keepalive_handle.cancel() - self._keepalive_handle = None - - def close(self) -> None: - """Close connection. - - Stop accepting new pipelining messages and close - connection when handlers done processing messages. - """ - self._close = True - if self._waiter: - self._waiter.cancel() - - def force_close(self) -> None: - """Forcefully close connection.""" - self._force_close = True - if self._waiter: - self._waiter.cancel() - if self.transport is not None: - self.transport.close() - self.transport = None - - def log_access( - self, request: BaseRequest, response: StreamResponse, time: Optional[float] - ) -> None: - if self._logging_enabled and self.access_logger is not None: - if TYPE_CHECKING: - assert time is not None - self.access_logger.log(request, response, self._loop.time() - time) - - def log_debug(self, *args: Any, **kw: Any) -> None: - if self.debug: - self.logger.debug(*args, **kw) - - def log_exception(self, *args: Any, **kw: Any) -> None: - self.logger.exception(*args, **kw) - - def _process_keepalive(self) -> None: - self._keepalive_handle = None - if self._force_close or not self._keepalive: - return - - loop = self._loop - now = loop.time() - close_time = self._next_keepalive_close_time - if now < close_time: - # Keep alive close check fired too early, reschedule - self._keepalive_handle = loop.call_at(close_time, self._process_keepalive) - return - - # handler in idle state - if self._waiter and not self._waiter.done(): - self.force_close() - - async def _handle_request( - self, - request: BaseRequest, - start_time: Optional[float], - request_handler: Callable[[BaseRequest], Awaitable[StreamResponse]], - ) -> Tuple[StreamResponse, bool]: - self._request_in_progress = True - try: - try: - self._current_request = request - resp = await request_handler(request) - finally: - self._current_request = None - except HTTPException as exc: - resp = exc - resp, reset = await self.finish_response(request, resp, start_time) - except asyncio.CancelledError: - raise - except asyncio.TimeoutError as exc: - self.log_debug("Request handler timed out.", exc_info=exc) - resp = self.handle_error(request, 504) - resp, reset = await self.finish_response(request, resp, start_time) - except Exception as exc: - resp = self.handle_error(request, 500, exc) - resp, reset = await self.finish_response(request, resp, start_time) - else: - # Deprecation warning (See #2415) - if getattr(resp, "__http_exception__", False): - warnings.warn( - "returning HTTPException object is deprecated " - "(#2415) and will be removed, " - "please raise the exception instead", - DeprecationWarning, - ) - - resp, reset = await self.finish_response(request, resp, start_time) - finally: - self._request_in_progress = False - if self._handler_waiter is not None: - self._handler_waiter.set_result(None) - - return resp, reset - - async def start(self) -> None: - """Process incoming request. - - It reads request line, request headers and request payload, then - calls handle_request() method. Subclass has to override - handle_request(). start() handles various exceptions in request - or response handling. Connection is being closed always unless - keep_alive(True) specified. - """ - loop = self._loop - manager = self._manager - assert manager is not None - keepalive_timeout = self._keepalive_timeout - resp = None - assert self._request_factory is not None - assert self._request_handler is not None - - while not self._force_close: - if not self._messages: - try: - # wait for next request - self._waiter = loop.create_future() - await self._waiter - finally: - self._waiter = None - - message, payload = self._messages.popleft() - - # time is only fetched if logging is enabled as otherwise - # its thrown away and never used. - start = loop.time() if self._logging_enabled else None - - manager.requests_count += 1 - writer = StreamWriter(self, loop) - if isinstance(message, _ErrInfo): - # make request_factory work - request_handler = self._make_error_handler(message) - message = ERROR - else: - request_handler = self._request_handler - - # Important don't hold a reference to the current task - # as on traceback it will prevent the task from being - # collected and will cause a memory leak. - request = self._request_factory( - message, - payload, - self, - writer, - self._task_handler or asyncio.current_task(loop), # type: ignore[arg-type] - ) - try: - # a new task is used for copy context vars (#3406) - coro = self._handle_request(request, start, request_handler) - if sys.version_info >= (3, 12): - task = asyncio.Task(coro, loop=loop, eager_start=True) - else: - task = loop.create_task(coro) - try: - resp, reset = await task - except ConnectionError: - self.log_debug("Ignored premature client disconnection") - break - - # Drop the processed task from asyncio.Task.all_tasks() early - del task - if reset: - self.log_debug("Ignored premature client disconnection 2") - break - - # notify server about keep-alive - self._keepalive = bool(resp.keep_alive) - - # check payload - if not payload.is_eof(): - lingering_time = self._lingering_time - if not self._force_close and lingering_time: - self.log_debug( - "Start lingering close timer for %s sec.", lingering_time - ) - - now = loop.time() - end_t = now + lingering_time - - try: - while not payload.is_eof() and now < end_t: - async with ceil_timeout(end_t - now): - # read and ignore - await payload.readany() - now = loop.time() - except (asyncio.CancelledError, asyncio.TimeoutError): - if ( - sys.version_info >= (3, 11) - and (t := asyncio.current_task()) - and t.cancelling() - ): - raise - - # if payload still uncompleted - if not payload.is_eof() and not self._force_close: - self.log_debug("Uncompleted request.") - self.close() - - payload.set_exception(_PAYLOAD_ACCESS_ERROR) - - except asyncio.CancelledError: - self.log_debug("Ignored premature client disconnection") - self.force_close() - raise - except Exception as exc: - self.log_exception("Unhandled exception", exc_info=exc) - self.force_close() - except BaseException: - self.force_close() - raise - finally: - request._task = None # type: ignore[assignment] # Break reference cycle in case of exception - if self.transport is None and resp is not None: - self.log_debug("Ignored premature client disconnection.") - - if self._keepalive and not self._close and not self._force_close: - # start keep-alive timer - close_time = loop.time() + keepalive_timeout - self._next_keepalive_close_time = close_time - if self._keepalive_handle is None: - self._keepalive_handle = loop.call_at( - close_time, self._process_keepalive - ) - else: - break - - # remove handler, close transport if no handlers left - if not self._force_close: - self._task_handler = None - if self.transport is not None: - self.transport.close() - - async def finish_response( - self, request: BaseRequest, resp: StreamResponse, start_time: Optional[float] - ) -> Tuple[StreamResponse, bool]: - """Prepare the response and write_eof, then log access. - - This has to - be called within the context of any exception so the access logger - can get exception information. Returns True if the client disconnects - prematurely. - """ - request._finish() - if self._request_parser is not None: - self._request_parser.set_upgraded(False) - self._upgrade = False - if self._message_tail: - self._request_parser.feed_data(self._message_tail) - self._message_tail = b"" - try: - prepare_meth = resp.prepare - except AttributeError: - if resp is None: - self.log_exception("Missing return statement on request handler") - else: - self.log_exception( - "Web-handler should return a response instance, " - "got {!r}".format(resp) - ) - exc = HTTPInternalServerError() - resp = Response( - status=exc.status, reason=exc.reason, text=exc.text, headers=exc.headers - ) - prepare_meth = resp.prepare - try: - await prepare_meth(request) - await resp.write_eof() - except ConnectionError: - self.log_access(request, resp, start_time) - return resp, True - - self.log_access(request, resp, start_time) - return resp, False - - def handle_error( - self, - request: BaseRequest, - status: int = 500, - exc: Optional[BaseException] = None, - message: Optional[str] = None, - ) -> StreamResponse: - """Handle errors. - - Returns HTTP response with specific status code. Logs additional - information. It always closes current connection. - """ - if self._request_count == 1 and isinstance(exc, BadHttpMethod): - # BadHttpMethod is common when a client sends non-HTTP - # or encrypted traffic to an HTTP port. This is expected - # to happen when connected to the public internet so we log - # it at the debug level as to not fill logs with noise. - self.logger.debug( - "Error handling request from %s", request.remote, exc_info=exc - ) - else: - self.log_exception( - "Error handling request from %s", request.remote, exc_info=exc - ) - - # some data already got sent, connection is broken - if request.writer.output_size > 0: - raise ConnectionError( - "Response is sent already, cannot send another response " - "with the error message" - ) - - ct = "text/plain" - if status == HTTPStatus.INTERNAL_SERVER_ERROR: - title = "{0.value} {0.phrase}".format(HTTPStatus.INTERNAL_SERVER_ERROR) - msg = HTTPStatus.INTERNAL_SERVER_ERROR.description - tb = None - if self.debug: - with suppress(Exception): - tb = traceback.format_exc() - - if "text/html" in request.headers.get("Accept", ""): - if tb: - tb = html_escape(tb) - msg = f"

Traceback:

\n
{tb}
" - message = ( - "" - "{title}" - "\n

{title}

" - "\n{msg}\n\n" - ).format(title=title, msg=msg) - ct = "text/html" - else: - if tb: - msg = tb - message = title + "\n\n" + msg - - resp = Response(status=status, text=message, content_type=ct) - resp.force_close() - - return resp - - def _make_error_handler( - self, err_info: _ErrInfo - ) -> Callable[[BaseRequest], Awaitable[StreamResponse]]: - async def handler(request: BaseRequest) -> StreamResponse: - return self.handle_error( - request, err_info.status, err_info.exc, err_info.message - ) - - return handler diff --git a/venv/lib/python3.9/site-packages/aiohttp/web_request.py b/venv/lib/python3.9/site-packages/aiohttp/web_request.py deleted file mode 100644 index f2d4c51..0000000 --- a/venv/lib/python3.9/site-packages/aiohttp/web_request.py +++ /dev/null @@ -1,927 +0,0 @@ -import asyncio -import datetime -import io -import re -import socket -import string -import tempfile -import types -import warnings -from types import MappingProxyType -from typing import ( - TYPE_CHECKING, - Any, - Dict, - Final, - Iterator, - Mapping, - MutableMapping, - Optional, - Pattern, - Tuple, - Union, - cast, -) -from urllib.parse import parse_qsl - -import attr -from multidict import ( - CIMultiDict, - CIMultiDictProxy, - MultiDict, - MultiDictProxy, - MultiMapping, -) -from yarl import URL - -from . import hdrs -from ._cookie_helpers import parse_cookie_header -from .abc import AbstractStreamWriter -from .helpers import ( - _SENTINEL, - DEBUG, - ETAG_ANY, - LIST_QUOTED_ETAG_RE, - ChainMapProxy, - ETag, - HeadersMixin, - parse_http_date, - reify, - sentinel, - set_exception, -) -from .http_parser import RawRequestMessage -from .http_writer import HttpVersion -from .multipart import BodyPartReader, MultipartReader -from .streams import EmptyStreamReader, StreamReader -from .typedefs import ( - DEFAULT_JSON_DECODER, - JSONDecoder, - LooseHeaders, - RawHeaders, - StrOrURL, -) -from .web_exceptions import HTTPRequestEntityTooLarge -from .web_response import StreamResponse - -__all__ = ("BaseRequest", "FileField", "Request") - - -if TYPE_CHECKING: - from .web_app import Application - from .web_protocol import RequestHandler - from .web_urldispatcher import UrlMappingMatchInfo - - -@attr.s(auto_attribs=True, frozen=True, slots=True) -class FileField: - name: str - filename: str - file: io.BufferedReader - content_type: str - headers: CIMultiDictProxy[str] - - -_TCHAR: Final[str] = string.digits + string.ascii_letters + r"!#$%&'*+.^_`|~-" -# '-' at the end to prevent interpretation as range in a char class - -_TOKEN: Final[str] = rf"[{_TCHAR}]+" - -_QDTEXT: Final[str] = r"[{}]".format( - r"".join(chr(c) for c in (0x09, 0x20, 0x21) + tuple(range(0x23, 0x7F))) -) -# qdtext includes 0x5C to escape 0x5D ('\]') -# qdtext excludes obs-text (because obsoleted, and encoding not specified) - -_QUOTED_PAIR: Final[str] = r"\\[\t !-~]" - -_QUOTED_STRING: Final[str] = r'"(?:{quoted_pair}|{qdtext})*"'.format( - qdtext=_QDTEXT, quoted_pair=_QUOTED_PAIR -) - -_FORWARDED_PAIR: Final[str] = ( - r"({token})=({token}|{quoted_string})(:\d{{1,4}})?".format( - token=_TOKEN, quoted_string=_QUOTED_STRING - ) -) - -_QUOTED_PAIR_REPLACE_RE: Final[Pattern[str]] = re.compile(r"\\([\t !-~])") -# same pattern as _QUOTED_PAIR but contains a capture group - -_FORWARDED_PAIR_RE: Final[Pattern[str]] = re.compile(_FORWARDED_PAIR) - -############################################################ -# HTTP Request -############################################################ - - -class BaseRequest(MutableMapping[str, Any], HeadersMixin): - - POST_METHODS = { - hdrs.METH_PATCH, - hdrs.METH_POST, - hdrs.METH_PUT, - hdrs.METH_TRACE, - hdrs.METH_DELETE, - } - - ATTRS = HeadersMixin.ATTRS | frozenset( - [ - "_message", - "_protocol", - "_payload_writer", - "_payload", - "_headers", - "_method", - "_version", - "_rel_url", - "_post", - "_read_bytes", - "_state", - "_cache", - "_task", - "_client_max_size", - "_loop", - "_transport_sslcontext", - "_transport_peername", - ] - ) - _post: Optional[MultiDictProxy[Union[str, bytes, FileField]]] = None - _read_bytes: Optional[bytes] = None - - def __init__( - self, - message: RawRequestMessage, - payload: StreamReader, - protocol: "RequestHandler", - payload_writer: AbstractStreamWriter, - task: "asyncio.Task[None]", - loop: asyncio.AbstractEventLoop, - *, - client_max_size: int = 1024**2, - state: Optional[Dict[str, Any]] = None, - scheme: Optional[str] = None, - host: Optional[str] = None, - remote: Optional[str] = None, - ) -> None: - self._message = message - self._protocol = protocol - self._payload_writer = payload_writer - - self._payload = payload - self._headers: CIMultiDictProxy[str] = message.headers - self._method = message.method - self._version = message.version - self._cache: Dict[str, Any] = {} - url = message.url - if url.absolute: - if scheme is not None: - url = url.with_scheme(scheme) - if host is not None: - url = url.with_host(host) - # absolute URL is given, - # override auto-calculating url, host, and scheme - # all other properties should be good - self._cache["url"] = url - self._cache["host"] = url.host - self._cache["scheme"] = url.scheme - self._rel_url = url.relative() - else: - self._rel_url = url - if scheme is not None: - self._cache["scheme"] = scheme - if host is not None: - self._cache["host"] = host - - self._state = {} if state is None else state - self._task = task - self._client_max_size = client_max_size - self._loop = loop - - self._transport_sslcontext = protocol.ssl_context - self._transport_peername = protocol.peername - - if remote is not None: - self._cache["remote"] = remote - - def clone( - self, - *, - method: Union[str, _SENTINEL] = sentinel, - rel_url: Union[StrOrURL, _SENTINEL] = sentinel, - headers: Union[LooseHeaders, _SENTINEL] = sentinel, - scheme: Union[str, _SENTINEL] = sentinel, - host: Union[str, _SENTINEL] = sentinel, - remote: Union[str, _SENTINEL] = sentinel, - client_max_size: Union[int, _SENTINEL] = sentinel, - ) -> "BaseRequest": - """Clone itself with replacement some attributes. - - Creates and returns a new instance of Request object. If no parameters - are given, an exact copy is returned. If a parameter is not passed, it - will reuse the one from the current request object. - """ - if self._read_bytes: - raise RuntimeError("Cannot clone request after reading its content") - - dct: Dict[str, Any] = {} - if method is not sentinel: - dct["method"] = method - if rel_url is not sentinel: - new_url: URL = URL(rel_url) - dct["url"] = new_url - dct["path"] = str(new_url) - if headers is not sentinel: - # a copy semantic - dct["headers"] = CIMultiDictProxy(CIMultiDict(headers)) - dct["raw_headers"] = tuple( - (k.encode("utf-8"), v.encode("utf-8")) - for k, v in dct["headers"].items() - ) - - message = self._message._replace(**dct) - - kwargs = {} - if scheme is not sentinel: - kwargs["scheme"] = scheme - if host is not sentinel: - kwargs["host"] = host - if remote is not sentinel: - kwargs["remote"] = remote - if client_max_size is sentinel: - client_max_size = self._client_max_size - - return self.__class__( - message, - self._payload, - self._protocol, - self._payload_writer, - self._task, - self._loop, - client_max_size=client_max_size, - state=self._state.copy(), - **kwargs, - ) - - @property - def task(self) -> "asyncio.Task[None]": - return self._task - - @property - def protocol(self) -> "RequestHandler": - return self._protocol - - @property - def transport(self) -> Optional[asyncio.Transport]: - if self._protocol is None: - return None - return self._protocol.transport - - @property - def writer(self) -> AbstractStreamWriter: - return self._payload_writer - - @property - def client_max_size(self) -> int: - return self._client_max_size - - @reify - def message(self) -> RawRequestMessage: - warnings.warn("Request.message is deprecated", DeprecationWarning, stacklevel=3) - return self._message - - @reify - def rel_url(self) -> URL: - return self._rel_url - - @reify - def loop(self) -> asyncio.AbstractEventLoop: - warnings.warn( - "request.loop property is deprecated", DeprecationWarning, stacklevel=2 - ) - return self._loop - - # MutableMapping API - - def __getitem__(self, key: str) -> Any: - return self._state[key] - - def __setitem__(self, key: str, value: Any) -> None: - self._state[key] = value - - def __delitem__(self, key: str) -> None: - del self._state[key] - - def __len__(self) -> int: - return len(self._state) - - def __iter__(self) -> Iterator[str]: - return iter(self._state) - - ######## - - @reify - def secure(self) -> bool: - """A bool indicating if the request is handled with SSL.""" - return self.scheme == "https" - - @reify - def forwarded(self) -> Tuple[Mapping[str, str], ...]: - """A tuple containing all parsed Forwarded header(s). - - Makes an effort to parse Forwarded headers as specified by RFC 7239: - - - It adds one (immutable) dictionary per Forwarded 'field-value', ie - per proxy. The element corresponds to the data in the Forwarded - field-value added by the first proxy encountered by the client. Each - subsequent item corresponds to those added by later proxies. - - It checks that every value has valid syntax in general as specified - in section 4: either a 'token' or a 'quoted-string'. - - It un-escapes found escape sequences. - - It does NOT validate 'by' and 'for' contents as specified in section - 6. - - It does NOT validate 'host' contents (Host ABNF). - - It does NOT validate 'proto' contents for valid URI scheme names. - - Returns a tuple containing one or more immutable dicts - """ - elems = [] - for field_value in self._message.headers.getall(hdrs.FORWARDED, ()): - length = len(field_value) - pos = 0 - need_separator = False - elem: Dict[str, str] = {} - elems.append(types.MappingProxyType(elem)) - while 0 <= pos < length: - match = _FORWARDED_PAIR_RE.match(field_value, pos) - if match is not None: # got a valid forwarded-pair - if need_separator: - # bad syntax here, skip to next comma - pos = field_value.find(",", pos) - else: - name, value, port = match.groups() - if value[0] == '"': - # quoted string: remove quotes and unescape - value = _QUOTED_PAIR_REPLACE_RE.sub(r"\1", value[1:-1]) - if port: - value += port - elem[name.lower()] = value - pos += len(match.group(0)) - need_separator = True - elif field_value[pos] == ",": # next forwarded-element - need_separator = False - elem = {} - elems.append(types.MappingProxyType(elem)) - pos += 1 - elif field_value[pos] == ";": # next forwarded-pair - need_separator = False - pos += 1 - elif field_value[pos] in " \t": - # Allow whitespace even between forwarded-pairs, though - # RFC 7239 doesn't. This simplifies code and is in line - # with Postel's law. - pos += 1 - else: - # bad syntax here, skip to next comma - pos = field_value.find(",", pos) - return tuple(elems) - - @reify - def scheme(self) -> str: - """A string representing the scheme of the request. - - Hostname is resolved in this order: - - - overridden value by .clone(scheme=new_scheme) call. - - type of connection to peer: HTTPS if socket is SSL, HTTP otherwise. - - 'http' or 'https'. - """ - if self._transport_sslcontext: - return "https" - else: - return "http" - - @reify - def method(self) -> str: - """Read only property for getting HTTP method. - - The value is upper-cased str like 'GET', 'POST', 'PUT' etc. - """ - return self._method - - @reify - def version(self) -> HttpVersion: - """Read only property for getting HTTP version of request. - - Returns aiohttp.protocol.HttpVersion instance. - """ - return self._version - - @reify - def host(self) -> str: - """Hostname of the request. - - Hostname is resolved in this order: - - - overridden value by .clone(host=new_host) call. - - HOST HTTP header - - socket.getfqdn() value - - For example, 'example.com' or 'localhost:8080'. - - For historical reasons, the port number may be included. - """ - host = self._message.headers.get(hdrs.HOST) - if host is not None: - return host - return socket.getfqdn() - - @reify - def remote(self) -> Optional[str]: - """Remote IP of client initiated HTTP request. - - The IP is resolved in this order: - - - overridden value by .clone(remote=new_remote) call. - - peername of opened socket - """ - if self._transport_peername is None: - return None - if isinstance(self._transport_peername, (list, tuple)): - return str(self._transport_peername[0]) - return str(self._transport_peername) - - @reify - def url(self) -> URL: - """The full URL of the request.""" - # authority is used here because it may include the port number - # and we want yarl to parse it correctly - return URL.build(scheme=self.scheme, authority=self.host).join(self._rel_url) - - @reify - def path(self) -> str: - """The URL including *PATH INFO* without the host or scheme. - - E.g., ``/app/blog`` - """ - return self._rel_url.path - - @reify - def path_qs(self) -> str: - """The URL including PATH_INFO and the query string. - - E.g, /app/blog?id=10 - """ - return str(self._rel_url) - - @reify - def raw_path(self) -> str: - """The URL including raw *PATH INFO* without the host or scheme. - - Warning, the path is unquoted and may contains non valid URL characters - - E.g., ``/my%2Fpath%7Cwith%21some%25strange%24characters`` - """ - return self._message.path - - @reify - def query(self) -> "MultiMapping[str]": - """A multidict with all the variables in the query string.""" - return self._rel_url.query - - @reify - def query_string(self) -> str: - """The query string in the URL. - - E.g., id=10 - """ - return self._rel_url.query_string - - @reify - def headers(self) -> CIMultiDictProxy[str]: - """A case-insensitive multidict proxy with all headers.""" - return self._headers - - @reify - def raw_headers(self) -> RawHeaders: - """A sequence of pairs for all headers.""" - return self._message.raw_headers - - @reify - def if_modified_since(self) -> Optional[datetime.datetime]: - """The value of If-Modified-Since HTTP header, or None. - - This header is represented as a `datetime` object. - """ - return parse_http_date(self.headers.get(hdrs.IF_MODIFIED_SINCE)) - - @reify - def if_unmodified_since(self) -> Optional[datetime.datetime]: - """The value of If-Unmodified-Since HTTP header, or None. - - This header is represented as a `datetime` object. - """ - return parse_http_date(self.headers.get(hdrs.IF_UNMODIFIED_SINCE)) - - @staticmethod - def _etag_values(etag_header: str) -> Iterator[ETag]: - """Extract `ETag` objects from raw header.""" - if etag_header == ETAG_ANY: - yield ETag( - is_weak=False, - value=ETAG_ANY, - ) - else: - for match in LIST_QUOTED_ETAG_RE.finditer(etag_header): - is_weak, value, garbage = match.group(2, 3, 4) - # Any symbol captured by 4th group means - # that the following sequence is invalid. - if garbage: - break - - yield ETag( - is_weak=bool(is_weak), - value=value, - ) - - @classmethod - def _if_match_or_none_impl( - cls, header_value: Optional[str] - ) -> Optional[Tuple[ETag, ...]]: - if not header_value: - return None - - return tuple(cls._etag_values(header_value)) - - @reify - def if_match(self) -> Optional[Tuple[ETag, ...]]: - """The value of If-Match HTTP header, or None. - - This header is represented as a `tuple` of `ETag` objects. - """ - return self._if_match_or_none_impl(self.headers.get(hdrs.IF_MATCH)) - - @reify - def if_none_match(self) -> Optional[Tuple[ETag, ...]]: - """The value of If-None-Match HTTP header, or None. - - This header is represented as a `tuple` of `ETag` objects. - """ - return self._if_match_or_none_impl(self.headers.get(hdrs.IF_NONE_MATCH)) - - @reify - def if_range(self) -> Optional[datetime.datetime]: - """The value of If-Range HTTP header, or None. - - This header is represented as a `datetime` object. - """ - return parse_http_date(self.headers.get(hdrs.IF_RANGE)) - - @reify - def keep_alive(self) -> bool: - """Is keepalive enabled by client?""" - return not self._message.should_close - - @reify - def cookies(self) -> Mapping[str, str]: - """Return request cookies. - - A read-only dictionary-like object. - """ - # Use parse_cookie_header for RFC 6265 compliant Cookie header parsing - # that accepts special characters in cookie names (fixes #2683) - parsed = parse_cookie_header(self.headers.get(hdrs.COOKIE, "")) - # Extract values from Morsel objects - return MappingProxyType({name: morsel.value for name, morsel in parsed}) - - @reify - def http_range(self) -> slice: - """The content of Range HTTP header. - - Return a slice instance. - - """ - rng = self._headers.get(hdrs.RANGE) - start, end = None, None - if rng is not None: - try: - pattern = r"^bytes=(\d*)-(\d*)$" - start, end = re.findall(pattern, rng, re.ASCII)[0] - except IndexError: # pattern was not found in header - raise ValueError("range not in acceptable format") - - end = int(end) if end else None - start = int(start) if start else None - - if start is None and end is not None: - # end with no start is to return tail of content - start = -end - end = None - - if start is not None and end is not None: - # end is inclusive in range header, exclusive for slice - end += 1 - - if start >= end: - raise ValueError("start cannot be after end") - - if start is end is None: # No valid range supplied - raise ValueError("No start or end of range specified") - - return slice(start, end, 1) - - @reify - def content(self) -> StreamReader: - """Return raw payload stream.""" - return self._payload - - @property - def has_body(self) -> bool: - """Return True if request's HTTP BODY can be read, False otherwise.""" - warnings.warn( - "Deprecated, use .can_read_body #2005", DeprecationWarning, stacklevel=2 - ) - return not self._payload.at_eof() - - @property - def can_read_body(self) -> bool: - """Return True if request's HTTP BODY can be read, False otherwise.""" - return not self._payload.at_eof() - - @reify - def body_exists(self) -> bool: - """Return True if request has HTTP BODY, False otherwise.""" - return type(self._payload) is not EmptyStreamReader - - async def release(self) -> None: - """Release request. - - Eat unread part of HTTP BODY if present. - """ - while not self._payload.at_eof(): - await self._payload.readany() - - async def read(self) -> bytes: - """Read request body if present. - - Returns bytes object with full request content. - """ - if self._read_bytes is None: - body = bytearray() - while True: - chunk = await self._payload.readany() - body.extend(chunk) - if self._client_max_size: - body_size = len(body) - if body_size >= self._client_max_size: - raise HTTPRequestEntityTooLarge( - max_size=self._client_max_size, actual_size=body_size - ) - if not chunk: - break - self._read_bytes = bytes(body) - return self._read_bytes - - async def text(self) -> str: - """Return BODY as text using encoding from .charset.""" - bytes_body = await self.read() - encoding = self.charset or "utf-8" - return bytes_body.decode(encoding) - - async def json(self, *, loads: JSONDecoder = DEFAULT_JSON_DECODER) -> Any: - """Return BODY as JSON.""" - body = await self.text() - return loads(body) - - async def multipart(self) -> MultipartReader: - """Return async iterator to process BODY as multipart.""" - return MultipartReader( - self._headers, - self._payload, - max_field_size=self._protocol.max_field_size, - max_headers=self._protocol.max_headers, - ) - - async def post(self) -> "MultiDictProxy[Union[str, bytes, FileField]]": - """Return POST parameters.""" - if self._post is not None: - return self._post - if self._method not in self.POST_METHODS: - self._post = MultiDictProxy(MultiDict()) - return self._post - - content_type = self.content_type - if content_type not in ( - "", - "application/x-www-form-urlencoded", - "multipart/form-data", - ): - self._post = MultiDictProxy(MultiDict()) - return self._post - - out: MultiDict[Union[str, bytes, FileField]] = MultiDict() - - if content_type == "multipart/form-data": - multipart = await self.multipart() - max_size = self._client_max_size - - size = 0 - while (field := await multipart.next()) is not None: - field_ct = field.headers.get(hdrs.CONTENT_TYPE) - - if isinstance(field, BodyPartReader): - if field.name is None: - raise ValueError("Multipart field missing name.") - - # Note that according to RFC 7578, the Content-Type header - # is optional, even for files, so we can't assume it's - # present. - # https://tools.ietf.org/html/rfc7578#section-4.4 - if field.filename: - # store file in temp file - tmp = await self._loop.run_in_executor( - None, tempfile.TemporaryFile - ) - while chunk := await field.read_chunk(size=2**18): - async for decoded_chunk in field.decode_iter(chunk): - await self._loop.run_in_executor( - None, tmp.write, decoded_chunk - ) - size += len(decoded_chunk) - if 0 < max_size < size: - await self._loop.run_in_executor(None, tmp.close) - raise HTTPRequestEntityTooLarge( - max_size=max_size, actual_size=size - ) - await self._loop.run_in_executor(None, tmp.seek, 0) - - if field_ct is None: - field_ct = "application/octet-stream" - - ff = FileField( - field.name, - field.filename, - cast(io.BufferedReader, tmp), - field_ct, - field.headers, - ) - out.add(field.name, ff) - else: - # deal with ordinary data - raw_data = bytearray() - while chunk := await field.read_chunk(): - size += len(chunk) - if 0 < max_size < size: - raise HTTPRequestEntityTooLarge( - max_size=max_size, actual_size=size - ) - raw_data.extend(chunk) - - value = bytearray() - # form-data doesn't support compression, so don't need to check size again. - async for d in field.decode_iter(raw_data): - value.extend(d) - - if field_ct is None or field_ct.startswith("text/"): - charset = field.get_charset(default="utf-8") - out.add(field.name, value.decode(charset)) - else: - out.add(field.name, value) - else: - raise ValueError( - "To decode nested multipart you need to use custom reader", - ) - else: - data = await self.read() - if data: - charset = self.charset or "utf-8" - out.extend( - parse_qsl( - data.rstrip().decode(charset), - keep_blank_values=True, - encoding=charset, - ) - ) - - self._post = MultiDictProxy(out) - return self._post - - def get_extra_info(self, name: str, default: Any = None) -> Any: - """Extra info from protocol transport""" - protocol = self._protocol - if protocol is None: - return default - - transport = protocol.transport - if transport is None: - return default - - return transport.get_extra_info(name, default) - - def __repr__(self) -> str: - ascii_encodable_path = self.path.encode("ascii", "backslashreplace").decode( - "ascii" - ) - return "<{} {} {} >".format( - self.__class__.__name__, self._method, ascii_encodable_path - ) - - def __eq__(self, other: object) -> bool: - return id(self) == id(other) - - def __bool__(self) -> bool: - return True - - async def _prepare_hook(self, response: StreamResponse) -> None: - return - - def _cancel(self, exc: BaseException) -> None: - set_exception(self._payload, exc) - - def _finish(self) -> None: - if self._post is None or self.content_type != "multipart/form-data": - return - - # NOTE: Release file descriptors for the - # NOTE: `tempfile.Temporaryfile`-created `_io.BufferedRandom` - # NOTE: instances of files sent within multipart request body - # NOTE: via HTTP POST request. - for file_name, file_field_object in self._post.items(): - if isinstance(file_field_object, FileField): - file_field_object.file.close() - - -class Request(BaseRequest): - - ATTRS = BaseRequest.ATTRS | frozenset(["_match_info"]) - - _match_info: Optional["UrlMappingMatchInfo"] = None - - if DEBUG: - - def __setattr__(self, name: str, val: Any) -> None: - if name not in self.ATTRS: - warnings.warn( - "Setting custom {}.{} attribute " - "is discouraged".format(self.__class__.__name__, name), - DeprecationWarning, - stacklevel=2, - ) - super().__setattr__(name, val) - - def clone( - self, - *, - method: Union[str, _SENTINEL] = sentinel, - rel_url: Union[StrOrURL, _SENTINEL] = sentinel, - headers: Union[LooseHeaders, _SENTINEL] = sentinel, - scheme: Union[str, _SENTINEL] = sentinel, - host: Union[str, _SENTINEL] = sentinel, - remote: Union[str, _SENTINEL] = sentinel, - client_max_size: Union[int, _SENTINEL] = sentinel, - ) -> "Request": - ret = super().clone( - method=method, - rel_url=rel_url, - headers=headers, - scheme=scheme, - host=host, - remote=remote, - client_max_size=client_max_size, - ) - new_ret = cast(Request, ret) - new_ret._match_info = self._match_info - return new_ret - - @reify - def match_info(self) -> "UrlMappingMatchInfo": - """Result of route resolving.""" - match_info = self._match_info - assert match_info is not None - return match_info - - @property - def app(self) -> "Application": - """Application instance.""" - match_info = self._match_info - assert match_info is not None - return match_info.current_app - - @property - def config_dict(self) -> ChainMapProxy: - match_info = self._match_info - assert match_info is not None - lst = match_info.apps - app = self.app - idx = lst.index(app) - sublist = list(reversed(lst[: idx + 1])) - return ChainMapProxy(sublist) - - async def _prepare_hook(self, response: StreamResponse) -> None: - match_info = self._match_info - if match_info is None: - return - for app in match_info._apps: - if on_response_prepare := app.on_response_prepare: - await on_response_prepare.send(self, response) diff --git a/venv/lib/python3.9/site-packages/aiohttp/web_response.py b/venv/lib/python3.9/site-packages/aiohttp/web_response.py deleted file mode 100644 index 364270e..0000000 --- a/venv/lib/python3.9/site-packages/aiohttp/web_response.py +++ /dev/null @@ -1,856 +0,0 @@ -import asyncio -import collections.abc -import datetime -import enum -import json -import math -import time -import warnings -from concurrent.futures import Executor -from http import HTTPStatus -from http.cookies import SimpleCookie -from typing import ( - TYPE_CHECKING, - Any, - Dict, - Iterator, - MutableMapping, - Optional, - Union, - cast, -) - -from multidict import CIMultiDict, istr - -from . import hdrs, payload -from .abc import AbstractStreamWriter -from .compression_utils import ZLibCompressor -from .helpers import ( - ETAG_ANY, - QUOTED_ETAG_RE, - ETag, - HeadersMixin, - must_be_empty_body, - parse_http_date, - rfc822_formatted_time, - sentinel, - should_remove_content_length, - validate_etag_value, -) -from .http import SERVER_SOFTWARE, HttpVersion10, HttpVersion11 -from .payload import Payload -from .typedefs import JSONEncoder, LooseHeaders - -REASON_PHRASES = {http_status.value: http_status.phrase for http_status in HTTPStatus} -LARGE_BODY_SIZE = 1024**2 - -__all__ = ("ContentCoding", "StreamResponse", "Response", "json_response") - - -if TYPE_CHECKING: - from .web_request import BaseRequest - - BaseClass = MutableMapping[str, Any] -else: - BaseClass = collections.abc.MutableMapping - - -# TODO(py311): Convert to StrEnum for wider use -class ContentCoding(enum.Enum): - # The content codings that we have support for. - # - # Additional registered codings are listed at: - # https://www.iana.org/assignments/http-parameters/http-parameters.xhtml#content-coding - deflate = "deflate" - gzip = "gzip" - identity = "identity" - - -CONTENT_CODINGS = {coding.value: coding for coding in ContentCoding} - -############################################################ -# HTTP Response classes -############################################################ - - -class StreamResponse(BaseClass, HeadersMixin): - - _body: Union[None, bytes, bytearray, Payload] - _length_check = True - _body = None - _keep_alive: Optional[bool] = None - _chunked: bool = False - _compression: bool = False - _compression_strategy: Optional[int] = None - _compression_force: Optional[ContentCoding] = None - _req: Optional["BaseRequest"] = None - _payload_writer: Optional[AbstractStreamWriter] = None - _eof_sent: bool = False - _must_be_empty_body: Optional[bool] = None - _body_length = 0 - _cookies: Optional[SimpleCookie] = None - _send_headers_immediately = True - - def __init__( - self, - *, - status: int = 200, - reason: Optional[str] = None, - headers: Optional[LooseHeaders] = None, - _real_headers: Optional[CIMultiDict[str]] = None, - ) -> None: - """Initialize a new stream response object. - - _real_headers is an internal parameter used to pass a pre-populated - headers object. It is used by the `Response` class to avoid copying - the headers when creating a new response object. It is not intended - to be used by external code. - """ - self._state: Dict[str, Any] = {} - - if _real_headers is not None: - self._headers = _real_headers - elif headers is not None: - self._headers: CIMultiDict[str] = CIMultiDict(headers) - else: - self._headers = CIMultiDict() - - self._set_status(status, reason) - - @property - def prepared(self) -> bool: - return self._eof_sent or self._payload_writer is not None - - @property - def task(self) -> "Optional[asyncio.Task[None]]": - if self._req: - return self._req.task - else: - return None - - @property - def status(self) -> int: - return self._status - - @property - def chunked(self) -> bool: - return self._chunked - - @property - def compression(self) -> bool: - return self._compression - - @property - def reason(self) -> str: - return self._reason - - def set_status( - self, - status: int, - reason: Optional[str] = None, - ) -> None: - assert ( - not self.prepared - ), "Cannot change the response status code after the headers have been sent" - self._set_status(status, reason) - - def _set_status(self, status: int, reason: Optional[str]) -> None: - self._status = int(status) - if reason is None: - reason = REASON_PHRASES.get(self._status, "") - elif "\r" in reason or "\n" in reason: - raise ValueError("Reason cannot contain \\r or \\n") - self._reason = reason - - @property - def keep_alive(self) -> Optional[bool]: - return self._keep_alive - - def force_close(self) -> None: - self._keep_alive = False - - @property - def body_length(self) -> int: - return self._body_length - - @property - def output_length(self) -> int: - warnings.warn("output_length is deprecated", DeprecationWarning) - assert self._payload_writer - return self._payload_writer.buffer_size - - def enable_chunked_encoding(self, chunk_size: Optional[int] = None) -> None: - """Enables automatic chunked transfer encoding.""" - if hdrs.CONTENT_LENGTH in self._headers: - raise RuntimeError( - "You can't enable chunked encoding when a content length is set" - ) - if chunk_size is not None: - warnings.warn("Chunk size is deprecated #1615", DeprecationWarning) - self._chunked = True - - def enable_compression( - self, - force: Optional[Union[bool, ContentCoding]] = None, - strategy: Optional[int] = None, - ) -> None: - """Enables response compression encoding.""" - # Backwards compatibility for when force was a bool <0.17. - if isinstance(force, bool): - force = ContentCoding.deflate if force else ContentCoding.identity - warnings.warn( - "Using boolean for force is deprecated #3318", DeprecationWarning - ) - elif force is not None: - assert isinstance( - force, ContentCoding - ), "force should one of None, bool or ContentEncoding" - - self._compression = True - self._compression_force = force - self._compression_strategy = strategy - - @property - def headers(self) -> "CIMultiDict[str]": - return self._headers - - @property - def cookies(self) -> SimpleCookie: - if self._cookies is None: - self._cookies = SimpleCookie() - return self._cookies - - def set_cookie( - self, - name: str, - value: str, - *, - expires: Optional[str] = None, - domain: Optional[str] = None, - max_age: Optional[Union[int, str]] = None, - path: str = "/", - secure: Optional[bool] = None, - httponly: Optional[bool] = None, - version: Optional[str] = None, - samesite: Optional[str] = None, - partitioned: Optional[bool] = None, - ) -> None: - """Set or update response cookie. - - Sets new cookie or updates existent with new value. - Also updates only those params which are not None. - """ - if self._cookies is None: - self._cookies = SimpleCookie() - - self._cookies[name] = value - c = self._cookies[name] - - if expires is not None: - c["expires"] = expires - elif c.get("expires") == "Thu, 01 Jan 1970 00:00:00 GMT": - del c["expires"] - - if domain is not None: - c["domain"] = domain - - if max_age is not None: - c["max-age"] = str(max_age) - elif "max-age" in c: - del c["max-age"] - - c["path"] = path - - if secure is not None: - c["secure"] = secure - if httponly is not None: - c["httponly"] = httponly - if version is not None: - c["version"] = version - if samesite is not None: - c["samesite"] = samesite - - if partitioned is not None: - c["partitioned"] = partitioned - - def del_cookie( - self, - name: str, - *, - domain: Optional[str] = None, - path: str = "/", - secure: Optional[bool] = None, - httponly: Optional[bool] = None, - samesite: Optional[str] = None, - ) -> None: - """Delete cookie. - - Creates new empty expired cookie. - """ - # TODO: do we need domain/path here? - if self._cookies is not None: - self._cookies.pop(name, None) - self.set_cookie( - name, - "", - max_age=0, - expires="Thu, 01 Jan 1970 00:00:00 GMT", - domain=domain, - path=path, - secure=secure, - httponly=httponly, - samesite=samesite, - ) - - @property - def content_length(self) -> Optional[int]: - # Just a placeholder for adding setter - return super().content_length - - @content_length.setter - def content_length(self, value: Optional[int]) -> None: - if value is not None: - value = int(value) - if self._chunked: - raise RuntimeError( - "You can't set content length when chunked encoding is enable" - ) - self._headers[hdrs.CONTENT_LENGTH] = str(value) - else: - self._headers.pop(hdrs.CONTENT_LENGTH, None) - - @property - def content_type(self) -> str: - # Just a placeholder for adding setter - return super().content_type - - @content_type.setter - def content_type(self, value: str) -> None: - self.content_type # read header values if needed - self._content_type = str(value) - self._generate_content_type_header() - - @property - def charset(self) -> Optional[str]: - # Just a placeholder for adding setter - return super().charset - - @charset.setter - def charset(self, value: Optional[str]) -> None: - ctype = self.content_type # read header values if needed - if ctype == "application/octet-stream": - raise RuntimeError( - "Setting charset for application/octet-stream " - "doesn't make sense, setup content_type first" - ) - assert self._content_dict is not None - if value is None: - self._content_dict.pop("charset", None) - else: - self._content_dict["charset"] = str(value).lower() - self._generate_content_type_header() - - @property - def last_modified(self) -> Optional[datetime.datetime]: - """The value of Last-Modified HTTP header, or None. - - This header is represented as a `datetime` object. - """ - return parse_http_date(self._headers.get(hdrs.LAST_MODIFIED)) - - @last_modified.setter - def last_modified( - self, value: Optional[Union[int, float, datetime.datetime, str]] - ) -> None: - if value is None: - self._headers.pop(hdrs.LAST_MODIFIED, None) - elif isinstance(value, (int, float)): - self._headers[hdrs.LAST_MODIFIED] = time.strftime( - "%a, %d %b %Y %H:%M:%S GMT", time.gmtime(math.ceil(value)) - ) - elif isinstance(value, datetime.datetime): - self._headers[hdrs.LAST_MODIFIED] = time.strftime( - "%a, %d %b %Y %H:%M:%S GMT", value.utctimetuple() - ) - elif isinstance(value, str): - self._headers[hdrs.LAST_MODIFIED] = value - else: - msg = f"Unsupported type for last_modified: {type(value).__name__}" - raise TypeError(msg) - - @property - def etag(self) -> Optional[ETag]: - quoted_value = self._headers.get(hdrs.ETAG) - if not quoted_value: - return None - elif quoted_value == ETAG_ANY: - return ETag(value=ETAG_ANY) - match = QUOTED_ETAG_RE.fullmatch(quoted_value) - if not match: - return None - is_weak, value = match.group(1, 2) - return ETag( - is_weak=bool(is_weak), - value=value, - ) - - @etag.setter - def etag(self, value: Optional[Union[ETag, str]]) -> None: - if value is None: - self._headers.pop(hdrs.ETAG, None) - elif (isinstance(value, str) and value == ETAG_ANY) or ( - isinstance(value, ETag) and value.value == ETAG_ANY - ): - self._headers[hdrs.ETAG] = ETAG_ANY - elif isinstance(value, str): - validate_etag_value(value) - self._headers[hdrs.ETAG] = f'"{value}"' - elif isinstance(value, ETag) and isinstance(value.value, str): - validate_etag_value(value.value) - hdr_value = f'W/"{value.value}"' if value.is_weak else f'"{value.value}"' - self._headers[hdrs.ETAG] = hdr_value - else: - raise ValueError( - f"Unsupported etag type: {type(value)}. " - f"etag must be str, ETag or None" - ) - - def _generate_content_type_header( - self, CONTENT_TYPE: istr = hdrs.CONTENT_TYPE - ) -> None: - assert self._content_dict is not None - assert self._content_type is not None - params = "; ".join(f"{k}={v}" for k, v in self._content_dict.items()) - if params: - ctype = self._content_type + "; " + params - else: - ctype = self._content_type - self._headers[CONTENT_TYPE] = ctype - - async def _do_start_compression(self, coding: ContentCoding) -> None: - if coding is ContentCoding.identity: - return - assert self._payload_writer is not None - self._headers[hdrs.CONTENT_ENCODING] = coding.value - self._payload_writer.enable_compression( - coding.value, self._compression_strategy - ) - # Compressed payload may have different content length, - # remove the header - self._headers.popall(hdrs.CONTENT_LENGTH, None) - - async def _start_compression(self, request: "BaseRequest") -> None: - if self._compression_force: - await self._do_start_compression(self._compression_force) - return - # Encoding comparisons should be case-insensitive - # https://www.rfc-editor.org/rfc/rfc9110#section-8.4.1 - accept_encoding = request.headers.get(hdrs.ACCEPT_ENCODING, "").lower() - for value, coding in CONTENT_CODINGS.items(): - if value in accept_encoding: - await self._do_start_compression(coding) - return - - async def prepare(self, request: "BaseRequest") -> Optional[AbstractStreamWriter]: - if self._eof_sent: - return None - if self._payload_writer is not None: - return self._payload_writer - self._must_be_empty_body = must_be_empty_body(request.method, self.status) - return await self._start(request) - - async def _start(self, request: "BaseRequest") -> AbstractStreamWriter: - self._req = request - writer = self._payload_writer = request._payload_writer - - await self._prepare_headers() - await request._prepare_hook(self) - await self._write_headers() - - return writer - - async def _prepare_headers(self) -> None: - request = self._req - assert request is not None - writer = self._payload_writer - assert writer is not None - keep_alive = self._keep_alive - if keep_alive is None: - keep_alive = request.keep_alive - self._keep_alive = keep_alive - - version = request.version - - headers = self._headers - if self._cookies: - for cookie in self._cookies.values(): - value = cookie.output(header="")[1:] - headers.add(hdrs.SET_COOKIE, value) - - if self._compression: - await self._start_compression(request) - - if self._chunked: - if version != HttpVersion11: - raise RuntimeError( - "Using chunked encoding is forbidden " - "for HTTP/{0.major}.{0.minor}".format(request.version) - ) - if not self._must_be_empty_body: - writer.enable_chunking() - headers[hdrs.TRANSFER_ENCODING] = "chunked" - elif self._length_check: # Disabled for WebSockets - writer.length = self.content_length - if writer.length is None: - if version >= HttpVersion11: - if not self._must_be_empty_body: - writer.enable_chunking() - headers[hdrs.TRANSFER_ENCODING] = "chunked" - elif not self._must_be_empty_body: - keep_alive = False - - # HTTP 1.1: https://tools.ietf.org/html/rfc7230#section-3.3.2 - # HTTP 1.0: https://tools.ietf.org/html/rfc1945#section-10.4 - if self._must_be_empty_body: - if hdrs.CONTENT_LENGTH in headers and should_remove_content_length( - request.method, self.status - ): - del headers[hdrs.CONTENT_LENGTH] - # https://datatracker.ietf.org/doc/html/rfc9112#section-6.1-10 - # https://datatracker.ietf.org/doc/html/rfc9112#section-6.1-13 - if hdrs.TRANSFER_ENCODING in headers: - del headers[hdrs.TRANSFER_ENCODING] - elif (writer.length if self._length_check else self.content_length) != 0: - # https://www.rfc-editor.org/rfc/rfc9110#section-8.3-5 - headers.setdefault(hdrs.CONTENT_TYPE, "application/octet-stream") - headers.setdefault(hdrs.DATE, rfc822_formatted_time()) - headers.setdefault(hdrs.SERVER, SERVER_SOFTWARE) - - # connection header - if hdrs.CONNECTION not in headers: - if keep_alive: - if version == HttpVersion10: - headers[hdrs.CONNECTION] = "keep-alive" - elif version == HttpVersion11: - headers[hdrs.CONNECTION] = "close" - - async def _write_headers(self) -> None: - request = self._req - assert request is not None - writer = self._payload_writer - assert writer is not None - # status line - version = request.version - status_line = f"HTTP/{version[0]}.{version[1]} {self._status} {self._reason}" - await writer.write_headers(status_line, self._headers) - # Send headers immediately if not opted into buffering - if self._send_headers_immediately: - writer.send_headers() - - async def write(self, data: Union[bytes, bytearray, memoryview]) -> None: - assert isinstance( - data, (bytes, bytearray, memoryview) - ), "data argument must be byte-ish (%r)" % type(data) - - if self._eof_sent: - raise RuntimeError("Cannot call write() after write_eof()") - if self._payload_writer is None: - raise RuntimeError("Cannot call write() before prepare()") - - await self._payload_writer.write(data) - - async def drain(self) -> None: - assert not self._eof_sent, "EOF has already been sent" - assert self._payload_writer is not None, "Response has not been started" - warnings.warn( - "drain method is deprecated, use await resp.write()", - DeprecationWarning, - stacklevel=2, - ) - await self._payload_writer.drain() - - async def write_eof(self, data: bytes = b"") -> None: - assert isinstance( - data, (bytes, bytearray, memoryview) - ), "data argument must be byte-ish (%r)" % type(data) - - if self._eof_sent: - return - - assert self._payload_writer is not None, "Response has not been started" - - await self._payload_writer.write_eof(data) - self._eof_sent = True - self._req = None - self._body_length = self._payload_writer.output_size - self._payload_writer = None - - def __repr__(self) -> str: - if self._eof_sent: - info = "eof" - elif self.prepared: - assert self._req is not None - info = f"{self._req.method} {self._req.path} " - else: - info = "not prepared" - return f"<{self.__class__.__name__} {self.reason} {info}>" - - def __getitem__(self, key: str) -> Any: - return self._state[key] - - def __setitem__(self, key: str, value: Any) -> None: - self._state[key] = value - - def __delitem__(self, key: str) -> None: - del self._state[key] - - def __len__(self) -> int: - return len(self._state) - - def __iter__(self) -> Iterator[str]: - return iter(self._state) - - def __hash__(self) -> int: - return hash(id(self)) - - def __eq__(self, other: object) -> bool: - return self is other - - def __bool__(self) -> bool: - return True - - -class Response(StreamResponse): - - _compressed_body: Optional[bytes] = None - _send_headers_immediately = False - - def __init__( - self, - *, - body: Any = None, - status: int = 200, - reason: Optional[str] = None, - text: Optional[str] = None, - headers: Optional[LooseHeaders] = None, - content_type: Optional[str] = None, - charset: Optional[str] = None, - zlib_executor_size: Optional[int] = None, - zlib_executor: Optional[Executor] = None, - ) -> None: - if body is not None and text is not None: - raise ValueError("body and text are not allowed together") - - if headers is None: - real_headers: CIMultiDict[str] = CIMultiDict() - else: - real_headers = CIMultiDict(headers) - - if content_type is not None and "charset" in content_type: - raise ValueError("charset must not be in content_type argument") - - if text is not None: - if hdrs.CONTENT_TYPE in real_headers: - if content_type or charset: - raise ValueError( - "passing both Content-Type header and " - "content_type or charset params " - "is forbidden" - ) - else: - # fast path for filling headers - if not isinstance(text, str): - raise TypeError("text argument must be str (%r)" % type(text)) - if content_type is None: - content_type = "text/plain" - if charset is None: - charset = "utf-8" - real_headers[hdrs.CONTENT_TYPE] = content_type + "; charset=" + charset - body = text.encode(charset) - text = None - elif hdrs.CONTENT_TYPE in real_headers: - if content_type is not None or charset is not None: - raise ValueError( - "passing both Content-Type header and " - "content_type or charset params " - "is forbidden" - ) - elif content_type is not None: - if charset is not None: - content_type += "; charset=" + charset - real_headers[hdrs.CONTENT_TYPE] = content_type - - super().__init__(status=status, reason=reason, _real_headers=real_headers) - - if text is not None: - self.text = text - else: - self.body = body - - self._zlib_executor_size = zlib_executor_size - self._zlib_executor = zlib_executor - - @property - def body(self) -> Optional[Union[bytes, Payload]]: - return self._body - - @body.setter - def body(self, body: Any) -> None: - if body is None: - self._body = None - elif isinstance(body, (bytes, bytearray)): - self._body = body - else: - try: - self._body = body = payload.PAYLOAD_REGISTRY.get(body) - except payload.LookupError: - raise ValueError("Unsupported body type %r" % type(body)) - - headers = self._headers - - # set content-type - if hdrs.CONTENT_TYPE not in headers: - headers[hdrs.CONTENT_TYPE] = body.content_type - - # copy payload headers - if body.headers: - for key, value in body.headers.items(): - if key not in headers: - headers[key] = value - - self._compressed_body = None - - @property - def text(self) -> Optional[str]: - if self._body is None: - return None - # Note: When _body is a Payload (e.g. FilePayload), this may do blocking I/O - # This is generally safe as most common payloads (BytesPayload, StringPayload) - # don't do blocking I/O, but be careful with file-based payloads - return self._body.decode(self.charset or "utf-8") - - @text.setter - def text(self, text: str) -> None: - assert text is None or isinstance( - text, str - ), "text argument must be str (%r)" % type(text) - - if self.content_type == "application/octet-stream": - self.content_type = "text/plain" - if self.charset is None: - self.charset = "utf-8" - - self._body = text.encode(self.charset) - self._compressed_body = None - - @property - def content_length(self) -> Optional[int]: - if self._chunked: - return None - - if hdrs.CONTENT_LENGTH in self._headers: - return int(self._headers[hdrs.CONTENT_LENGTH]) - - if self._compressed_body is not None: - # Return length of the compressed body - return len(self._compressed_body) - elif isinstance(self._body, Payload): - # A payload without content length, or a compressed payload - return None - elif self._body is not None: - return len(self._body) - else: - return 0 - - @content_length.setter - def content_length(self, value: Optional[int]) -> None: - raise RuntimeError("Content length is set automatically") - - async def write_eof(self, data: bytes = b"") -> None: - if self._eof_sent: - return - if self._compressed_body is None: - body: Optional[Union[bytes, Payload]] = self._body - else: - body = self._compressed_body - assert not data, f"data arg is not supported, got {data!r}" - assert self._req is not None - assert self._payload_writer is not None - if body is None or self._must_be_empty_body: - await super().write_eof() - elif isinstance(self._body, Payload): - await self._body.write(self._payload_writer) - await self._body.close() - await super().write_eof() - else: - await super().write_eof(cast(bytes, body)) - - async def _start(self, request: "BaseRequest") -> AbstractStreamWriter: - if hdrs.CONTENT_LENGTH in self._headers: - if should_remove_content_length(request.method, self.status): - del self._headers[hdrs.CONTENT_LENGTH] - elif not self._chunked: - if isinstance(self._body, Payload): - if (size := self._body.size) is not None: - self._headers[hdrs.CONTENT_LENGTH] = str(size) - else: - body_len = len(self._body) if self._body else "0" - # https://www.rfc-editor.org/rfc/rfc9110.html#section-8.6-7 - if body_len != "0" or ( - self.status != 304 and request.method not in hdrs.METH_HEAD_ALL - ): - self._headers[hdrs.CONTENT_LENGTH] = str(body_len) - - return await super()._start(request) - - async def _do_start_compression(self, coding: ContentCoding) -> None: - if self._chunked or isinstance(self._body, Payload): - return await super()._do_start_compression(coding) - if coding is ContentCoding.identity: - return - # Instead of using _payload_writer.enable_compression, - # compress the whole body - compressor = ZLibCompressor( - encoding=coding.value, - max_sync_chunk_size=self._zlib_executor_size, - executor=self._zlib_executor, - ) - assert self._body is not None - if self._zlib_executor_size is None and len(self._body) > LARGE_BODY_SIZE: - warnings.warn( - "Synchronous compression of large response bodies " - f"({len(self._body)} bytes) might block the async event loop. " - "Consider providing a custom value to zlib_executor_size/" - "zlib_executor response properties or disabling compression on it." - ) - self._compressed_body = ( - await compressor.compress(self._body) + compressor.flush() - ) - self._headers[hdrs.CONTENT_ENCODING] = coding.value - self._headers[hdrs.CONTENT_LENGTH] = str(len(self._compressed_body)) - - -def json_response( - data: Any = sentinel, - *, - text: Optional[str] = None, - body: Optional[bytes] = None, - status: int = 200, - reason: Optional[str] = None, - headers: Optional[LooseHeaders] = None, - content_type: str = "application/json", - dumps: JSONEncoder = json.dumps, -) -> Response: - if data is not sentinel: - if text or body: - raise ValueError("only one of data, text, or body should be specified") - else: - text = dumps(data) - return Response( - text=text, - body=body, - status=status, - reason=reason, - headers=headers, - content_type=content_type, - ) diff --git a/venv/lib/python3.9/site-packages/aiohttp/web_routedef.py b/venv/lib/python3.9/site-packages/aiohttp/web_routedef.py deleted file mode 100644 index f51b6cd..0000000 --- a/venv/lib/python3.9/site-packages/aiohttp/web_routedef.py +++ /dev/null @@ -1,214 +0,0 @@ -import abc -import os # noqa -from typing import ( - TYPE_CHECKING, - Any, - Callable, - Dict, - Iterator, - List, - Optional, - Sequence, - Type, - Union, - overload, -) - -import attr - -from . import hdrs -from .abc import AbstractView -from .typedefs import Handler, PathLike - -if TYPE_CHECKING: - from .web_request import Request - from .web_response import StreamResponse - from .web_urldispatcher import AbstractRoute, UrlDispatcher -else: - Request = StreamResponse = UrlDispatcher = AbstractRoute = None - - -__all__ = ( - "AbstractRouteDef", - "RouteDef", - "StaticDef", - "RouteTableDef", - "head", - "options", - "get", - "post", - "patch", - "put", - "delete", - "route", - "view", - "static", -) - - -class AbstractRouteDef(abc.ABC): - @abc.abstractmethod - def register(self, router: UrlDispatcher) -> List[AbstractRoute]: - pass # pragma: no cover - - -_HandlerType = Union[Type[AbstractView], Handler] - - -@attr.s(auto_attribs=True, frozen=True, repr=False, slots=True) -class RouteDef(AbstractRouteDef): - method: str - path: str - handler: _HandlerType - kwargs: Dict[str, Any] - - def __repr__(self) -> str: - info = [] - for name, value in sorted(self.kwargs.items()): - info.append(f", {name}={value!r}") - return " {handler.__name__!r}{info}>".format( - method=self.method, path=self.path, handler=self.handler, info="".join(info) - ) - - def register(self, router: UrlDispatcher) -> List[AbstractRoute]: - if self.method in hdrs.METH_ALL: - reg = getattr(router, "add_" + self.method.lower()) - return [reg(self.path, self.handler, **self.kwargs)] - else: - return [ - router.add_route(self.method, self.path, self.handler, **self.kwargs) - ] - - -@attr.s(auto_attribs=True, frozen=True, repr=False, slots=True) -class StaticDef(AbstractRouteDef): - prefix: str - path: PathLike - kwargs: Dict[str, Any] - - def __repr__(self) -> str: - info = [] - for name, value in sorted(self.kwargs.items()): - info.append(f", {name}={value!r}") - return " {path}{info}>".format( - prefix=self.prefix, path=self.path, info="".join(info) - ) - - def register(self, router: UrlDispatcher) -> List[AbstractRoute]: - resource = router.add_static(self.prefix, self.path, **self.kwargs) - routes = resource.get_info().get("routes", {}) - return list(routes.values()) - - -def route(method: str, path: str, handler: _HandlerType, **kwargs: Any) -> RouteDef: - return RouteDef(method, path, handler, kwargs) - - -def head(path: str, handler: _HandlerType, **kwargs: Any) -> RouteDef: - return route(hdrs.METH_HEAD, path, handler, **kwargs) - - -def options(path: str, handler: _HandlerType, **kwargs: Any) -> RouteDef: - return route(hdrs.METH_OPTIONS, path, handler, **kwargs) - - -def get( - path: str, - handler: _HandlerType, - *, - name: Optional[str] = None, - allow_head: bool = True, - **kwargs: Any, -) -> RouteDef: - return route( - hdrs.METH_GET, path, handler, name=name, allow_head=allow_head, **kwargs - ) - - -def post(path: str, handler: _HandlerType, **kwargs: Any) -> RouteDef: - return route(hdrs.METH_POST, path, handler, **kwargs) - - -def put(path: str, handler: _HandlerType, **kwargs: Any) -> RouteDef: - return route(hdrs.METH_PUT, path, handler, **kwargs) - - -def patch(path: str, handler: _HandlerType, **kwargs: Any) -> RouteDef: - return route(hdrs.METH_PATCH, path, handler, **kwargs) - - -def delete(path: str, handler: _HandlerType, **kwargs: Any) -> RouteDef: - return route(hdrs.METH_DELETE, path, handler, **kwargs) - - -def view(path: str, handler: Type[AbstractView], **kwargs: Any) -> RouteDef: - return route(hdrs.METH_ANY, path, handler, **kwargs) - - -def static(prefix: str, path: PathLike, **kwargs: Any) -> StaticDef: - return StaticDef(prefix, path, kwargs) - - -_Deco = Callable[[_HandlerType], _HandlerType] - - -class RouteTableDef(Sequence[AbstractRouteDef]): - """Route definition table""" - - def __init__(self) -> None: - self._items: List[AbstractRouteDef] = [] - - def __repr__(self) -> str: - return f"" - - @overload - def __getitem__(self, index: int) -> AbstractRouteDef: ... - - @overload - def __getitem__(self, index: slice) -> List[AbstractRouteDef]: ... - - def __getitem__(self, index): # type: ignore[no-untyped-def] - return self._items[index] - - def __iter__(self) -> Iterator[AbstractRouteDef]: - return iter(self._items) - - def __len__(self) -> int: - return len(self._items) - - def __contains__(self, item: object) -> bool: - return item in self._items - - def route(self, method: str, path: str, **kwargs: Any) -> _Deco: - def inner(handler: _HandlerType) -> _HandlerType: - self._items.append(RouteDef(method, path, handler, kwargs)) - return handler - - return inner - - def head(self, path: str, **kwargs: Any) -> _Deco: - return self.route(hdrs.METH_HEAD, path, **kwargs) - - def get(self, path: str, **kwargs: Any) -> _Deco: - return self.route(hdrs.METH_GET, path, **kwargs) - - def post(self, path: str, **kwargs: Any) -> _Deco: - return self.route(hdrs.METH_POST, path, **kwargs) - - def put(self, path: str, **kwargs: Any) -> _Deco: - return self.route(hdrs.METH_PUT, path, **kwargs) - - def patch(self, path: str, **kwargs: Any) -> _Deco: - return self.route(hdrs.METH_PATCH, path, **kwargs) - - def delete(self, path: str, **kwargs: Any) -> _Deco: - return self.route(hdrs.METH_DELETE, path, **kwargs) - - def options(self, path: str, **kwargs: Any) -> _Deco: - return self.route(hdrs.METH_OPTIONS, path, **kwargs) - - def view(self, path: str, **kwargs: Any) -> _Deco: - return self.route(hdrs.METH_ANY, path, **kwargs) - - def static(self, prefix: str, path: PathLike, **kwargs: Any) -> None: - self._items.append(StaticDef(prefix, path, kwargs)) diff --git a/venv/lib/python3.9/site-packages/aiohttp/web_runner.py b/venv/lib/python3.9/site-packages/aiohttp/web_runner.py deleted file mode 100644 index bcfec72..0000000 --- a/venv/lib/python3.9/site-packages/aiohttp/web_runner.py +++ /dev/null @@ -1,399 +0,0 @@ -import asyncio -import signal -import socket -import warnings -from abc import ABC, abstractmethod -from typing import TYPE_CHECKING, Any, List, Optional, Set - -from yarl import URL - -from .typedefs import PathLike -from .web_app import Application -from .web_server import Server - -if TYPE_CHECKING: - from ssl import SSLContext -else: - try: - from ssl import SSLContext - except ImportError: # pragma: no cover - SSLContext = object # type: ignore[misc,assignment] - -__all__ = ( - "BaseSite", - "TCPSite", - "UnixSite", - "NamedPipeSite", - "SockSite", - "BaseRunner", - "AppRunner", - "ServerRunner", - "GracefulExit", -) - - -class GracefulExit(SystemExit): - code = 1 - - -def _raise_graceful_exit() -> None: - raise GracefulExit() - - -class BaseSite(ABC): - __slots__ = ("_runner", "_ssl_context", "_backlog", "_server") - - def __init__( - self, - runner: "BaseRunner", - *, - shutdown_timeout: float = 60.0, - ssl_context: Optional[SSLContext] = None, - backlog: int = 128, - ) -> None: - if runner.server is None: - raise RuntimeError("Call runner.setup() before making a site") - if shutdown_timeout != 60.0: - msg = "shutdown_timeout should be set on BaseRunner" - warnings.warn(msg, DeprecationWarning, stacklevel=2) - runner._shutdown_timeout = shutdown_timeout - self._runner = runner - self._ssl_context = ssl_context - self._backlog = backlog - self._server: Optional[asyncio.AbstractServer] = None - - @property - @abstractmethod - def name(self) -> str: - pass # pragma: no cover - - @abstractmethod - async def start(self) -> None: - self._runner._reg_site(self) - - async def stop(self) -> None: - self._runner._check_site(self) - if self._server is not None: # Maybe not started yet - self._server.close() - - self._runner._unreg_site(self) - - -class TCPSite(BaseSite): - __slots__ = ("_host", "_port", "_reuse_address", "_reuse_port") - - def __init__( - self, - runner: "BaseRunner", - host: Optional[str] = None, - port: Optional[int] = None, - *, - shutdown_timeout: float = 60.0, - ssl_context: Optional[SSLContext] = None, - backlog: int = 128, - reuse_address: Optional[bool] = None, - reuse_port: Optional[bool] = None, - ) -> None: - super().__init__( - runner, - shutdown_timeout=shutdown_timeout, - ssl_context=ssl_context, - backlog=backlog, - ) - self._host = host - if port is None: - port = 8443 if self._ssl_context else 8080 - self._port = port - self._reuse_address = reuse_address - self._reuse_port = reuse_port - - @property - def name(self) -> str: - scheme = "https" if self._ssl_context else "http" - host = "0.0.0.0" if not self._host else self._host - return str(URL.build(scheme=scheme, host=host, port=self._port)) - - async def start(self) -> None: - await super().start() - loop = asyncio.get_event_loop() - server = self._runner.server - assert server is not None - self._server = await loop.create_server( - server, - self._host, - self._port, - ssl=self._ssl_context, - backlog=self._backlog, - reuse_address=self._reuse_address, - reuse_port=self._reuse_port, - ) - - -class UnixSite(BaseSite): - __slots__ = ("_path",) - - def __init__( - self, - runner: "BaseRunner", - path: PathLike, - *, - shutdown_timeout: float = 60.0, - ssl_context: Optional[SSLContext] = None, - backlog: int = 128, - ) -> None: - super().__init__( - runner, - shutdown_timeout=shutdown_timeout, - ssl_context=ssl_context, - backlog=backlog, - ) - self._path = path - - @property - def name(self) -> str: - scheme = "https" if self._ssl_context else "http" - return f"{scheme}://unix:{self._path}:" - - async def start(self) -> None: - await super().start() - loop = asyncio.get_event_loop() - server = self._runner.server - assert server is not None - self._server = await loop.create_unix_server( - server, - self._path, - ssl=self._ssl_context, - backlog=self._backlog, - ) - - -class NamedPipeSite(BaseSite): - __slots__ = ("_path",) - - def __init__( - self, runner: "BaseRunner", path: str, *, shutdown_timeout: float = 60.0 - ) -> None: - loop = asyncio.get_event_loop() - if not isinstance( - loop, asyncio.ProactorEventLoop # type: ignore[attr-defined] - ): - raise RuntimeError( - "Named Pipes only available in proactor loop under windows" - ) - super().__init__(runner, shutdown_timeout=shutdown_timeout) - self._path = path - - @property - def name(self) -> str: - return self._path - - async def start(self) -> None: - await super().start() - loop = asyncio.get_event_loop() - server = self._runner.server - assert server is not None - _server = await loop.start_serving_pipe( # type: ignore[attr-defined] - server, self._path - ) - self._server = _server[0] - - -class SockSite(BaseSite): - __slots__ = ("_sock", "_name") - - def __init__( - self, - runner: "BaseRunner", - sock: socket.socket, - *, - shutdown_timeout: float = 60.0, - ssl_context: Optional[SSLContext] = None, - backlog: int = 128, - ) -> None: - super().__init__( - runner, - shutdown_timeout=shutdown_timeout, - ssl_context=ssl_context, - backlog=backlog, - ) - self._sock = sock - scheme = "https" if self._ssl_context else "http" - if hasattr(socket, "AF_UNIX") and sock.family == socket.AF_UNIX: - name = f"{scheme}://unix:{sock.getsockname()}:" - else: - host, port = sock.getsockname()[:2] - name = str(URL.build(scheme=scheme, host=host, port=port)) - self._name = name - - @property - def name(self) -> str: - return self._name - - async def start(self) -> None: - await super().start() - loop = asyncio.get_event_loop() - server = self._runner.server - assert server is not None - self._server = await loop.create_server( - server, sock=self._sock, ssl=self._ssl_context, backlog=self._backlog - ) - - -class BaseRunner(ABC): - __slots__ = ("_handle_signals", "_kwargs", "_server", "_sites", "_shutdown_timeout") - - def __init__( - self, - *, - handle_signals: bool = False, - shutdown_timeout: float = 60.0, - **kwargs: Any, - ) -> None: - self._handle_signals = handle_signals - self._kwargs = kwargs - self._server: Optional[Server] = None - self._sites: List[BaseSite] = [] - self._shutdown_timeout = shutdown_timeout - - @property - def server(self) -> Optional[Server]: - return self._server - - @property - def addresses(self) -> List[Any]: - ret: List[Any] = [] - for site in self._sites: - server = site._server - if server is not None: - sockets = server.sockets # type: ignore[attr-defined] - if sockets is not None: - for sock in sockets: - ret.append(sock.getsockname()) - return ret - - @property - def sites(self) -> Set[BaseSite]: - return set(self._sites) - - async def setup(self) -> None: - loop = asyncio.get_event_loop() - - if self._handle_signals: - try: - loop.add_signal_handler(signal.SIGINT, _raise_graceful_exit) - loop.add_signal_handler(signal.SIGTERM, _raise_graceful_exit) - except NotImplementedError: # pragma: no cover - # add_signal_handler is not implemented on Windows - pass - - self._server = await self._make_server() - - @abstractmethod - async def shutdown(self) -> None: - """Call any shutdown hooks to help server close gracefully.""" - - async def cleanup(self) -> None: - # The loop over sites is intentional, an exception on gather() - # leaves self._sites in unpredictable state. - # The loop guaranties that a site is either deleted on success or - # still present on failure - for site in list(self._sites): - await site.stop() - - if self._server: # If setup succeeded - # Yield to event loop to ensure incoming requests prior to stopping the sites - # have all started to be handled before we proceed to close idle connections. - await asyncio.sleep(0) - self._server.pre_shutdown() - await self.shutdown() - await self._server.shutdown(self._shutdown_timeout) - await self._cleanup_server() - - self._server = None - if self._handle_signals: - loop = asyncio.get_running_loop() - try: - loop.remove_signal_handler(signal.SIGINT) - loop.remove_signal_handler(signal.SIGTERM) - except NotImplementedError: # pragma: no cover - # remove_signal_handler is not implemented on Windows - pass - - @abstractmethod - async def _make_server(self) -> Server: - pass # pragma: no cover - - @abstractmethod - async def _cleanup_server(self) -> None: - pass # pragma: no cover - - def _reg_site(self, site: BaseSite) -> None: - if site in self._sites: - raise RuntimeError(f"Site {site} is already registered in runner {self}") - self._sites.append(site) - - def _check_site(self, site: BaseSite) -> None: - if site not in self._sites: - raise RuntimeError(f"Site {site} is not registered in runner {self}") - - def _unreg_site(self, site: BaseSite) -> None: - if site not in self._sites: - raise RuntimeError(f"Site {site} is not registered in runner {self}") - self._sites.remove(site) - - -class ServerRunner(BaseRunner): - """Low-level web server runner""" - - __slots__ = ("_web_server",) - - def __init__( - self, web_server: Server, *, handle_signals: bool = False, **kwargs: Any - ) -> None: - super().__init__(handle_signals=handle_signals, **kwargs) - self._web_server = web_server - - async def shutdown(self) -> None: - pass - - async def _make_server(self) -> Server: - return self._web_server - - async def _cleanup_server(self) -> None: - pass - - -class AppRunner(BaseRunner): - """Web Application runner""" - - __slots__ = ("_app",) - - def __init__( - self, app: Application, *, handle_signals: bool = False, **kwargs: Any - ) -> None: - super().__init__(handle_signals=handle_signals, **kwargs) - if not isinstance(app, Application): - raise TypeError( - "The first argument should be web.Application " - "instance, got {!r}".format(app) - ) - self._app = app - - @property - def app(self) -> Application: - return self._app - - async def shutdown(self) -> None: - await self._app.shutdown() - - async def _make_server(self) -> Server: - loop = asyncio.get_event_loop() - self._app._set_loop(loop) - self._app.on_startup.freeze() - await self._app.startup() - self._app.freeze() - - return self._app._make_handler(loop=loop, **self._kwargs) - - async def _cleanup_server(self) -> None: - await self._app.cleanup() diff --git a/venv/lib/python3.9/site-packages/aiohttp/web_server.py b/venv/lib/python3.9/site-packages/aiohttp/web_server.py deleted file mode 100644 index 328aca1..0000000 --- a/venv/lib/python3.9/site-packages/aiohttp/web_server.py +++ /dev/null @@ -1,84 +0,0 @@ -"""Low level HTTP server.""" - -import asyncio -from typing import Any, Awaitable, Callable, Dict, List, Optional # noqa - -from .abc import AbstractStreamWriter -from .http_parser import RawRequestMessage -from .streams import StreamReader -from .web_protocol import RequestHandler, _RequestFactory, _RequestHandler -from .web_request import BaseRequest - -__all__ = ("Server",) - - -class Server: - def __init__( - self, - handler: _RequestHandler, - *, - request_factory: Optional[_RequestFactory] = None, - handler_cancellation: bool = False, - loop: Optional[asyncio.AbstractEventLoop] = None, - **kwargs: Any, - ) -> None: - self._loop = loop or asyncio.get_running_loop() - self._connections: Dict[RequestHandler, asyncio.Transport] = {} - self._kwargs = kwargs - # requests_count is the number of requests being processed by the server - # for the lifetime of the server. - self.requests_count = 0 - self.request_handler = handler - self.request_factory = request_factory or self._make_request - self.handler_cancellation = handler_cancellation - - @property - def connections(self) -> List[RequestHandler]: - return list(self._connections.keys()) - - def connection_made( - self, handler: RequestHandler, transport: asyncio.Transport - ) -> None: - self._connections[handler] = transport - - def connection_lost( - self, handler: RequestHandler, exc: Optional[BaseException] = None - ) -> None: - if handler in self._connections: - if handler._task_handler: - handler._task_handler.add_done_callback( - lambda f: self._connections.pop(handler, None) - ) - else: - del self._connections[handler] - - def _make_request( - self, - message: RawRequestMessage, - payload: StreamReader, - protocol: RequestHandler, - writer: AbstractStreamWriter, - task: "asyncio.Task[None]", - ) -> BaseRequest: - return BaseRequest(message, payload, protocol, writer, task, self._loop) - - def pre_shutdown(self) -> None: - for conn in self._connections: - conn.close() - - async def shutdown(self, timeout: Optional[float] = None) -> None: - coros = (conn.shutdown(timeout) for conn in self._connections) - await asyncio.gather(*coros) - self._connections.clear() - - def __call__(self) -> RequestHandler: - try: - return RequestHandler(self, loop=self._loop, **self._kwargs) - except TypeError: - # Failsafe creation: remove all custom handler_args - kwargs = { - k: v - for k, v in self._kwargs.items() - if k in ["debug", "access_log_class"] - } - return RequestHandler(self, loop=self._loop, **kwargs) diff --git a/venv/lib/python3.9/site-packages/aiohttp/web_urldispatcher.py b/venv/lib/python3.9/site-packages/aiohttp/web_urldispatcher.py deleted file mode 100644 index 48465b5..0000000 --- a/venv/lib/python3.9/site-packages/aiohttp/web_urldispatcher.py +++ /dev/null @@ -1,1309 +0,0 @@ -import abc -import asyncio -import base64 -import functools -import hashlib -import html -import inspect -import keyword -import os -import platform -import re -import sys -import warnings -from functools import wraps -from pathlib import Path -from types import MappingProxyType -from typing import ( - TYPE_CHECKING, - Any, - Awaitable, - Callable, - Container, - Dict, - Final, - Generator, - Iterable, - Iterator, - List, - Mapping, - NoReturn, - Optional, - Pattern, - Set, - Sized, - Tuple, - Type, - TypedDict, - Union, - cast, -) - -from yarl import URL, __version__ as yarl_version - -from . import hdrs -from .abc import AbstractMatchInfo, AbstractRouter, AbstractView -from .helpers import DEBUG -from .http import HttpVersion11 -from .typedefs import Handler, PathLike -from .web_exceptions import ( - HTTPException, - HTTPExpectationFailed, - HTTPForbidden, - HTTPMethodNotAllowed, - HTTPNotFound, -) -from .web_fileresponse import FileResponse -from .web_request import Request -from .web_response import Response, StreamResponse -from .web_routedef import AbstractRouteDef - -__all__ = ( - "UrlDispatcher", - "UrlMappingMatchInfo", - "AbstractResource", - "Resource", - "PlainResource", - "DynamicResource", - "AbstractRoute", - "ResourceRoute", - "StaticResource", - "View", -) - - -if TYPE_CHECKING: - from .web_app import Application - - BaseDict = Dict[str, str] -else: - BaseDict = dict - -CIRCULAR_SYMLINK_ERROR = ( - (OSError,) - if sys.version_info < (3, 10) and sys.platform.startswith("win32") - else (RuntimeError,) if sys.version_info < (3, 13) else () -) - -YARL_VERSION: Final[Tuple[int, ...]] = tuple(map(int, yarl_version.split(".")[:2])) - -HTTP_METHOD_RE: Final[Pattern[str]] = re.compile( - r"^[0-9A-Za-z!#\$%&'\*\+\-\.\^_`\|~]+$" -) -ROUTE_RE: Final[Pattern[str]] = re.compile( - r"(\{[_a-zA-Z][^{}]*(?:\{[^{}]*\}[^{}]*)*\})" -) -PATH_SEP: Final[str] = re.escape("/") - -IS_WINDOWS: Final[bool] = platform.system() == "Windows" - -_ExpectHandler = Callable[[Request], Awaitable[Optional[StreamResponse]]] -_Resolve = Tuple[Optional["UrlMappingMatchInfo"], Set[str]] - -html_escape = functools.partial(html.escape, quote=True) - - -class _InfoDict(TypedDict, total=False): - path: str - - formatter: str - pattern: Pattern[str] - - directory: Path - prefix: str - routes: Mapping[str, "AbstractRoute"] - - app: "Application" - - domain: str - - rule: "AbstractRuleMatching" - - http_exception: HTTPException - - -class AbstractResource(Sized, Iterable["AbstractRoute"]): - def __init__(self, *, name: Optional[str] = None) -> None: - self._name = name - - @property - def name(self) -> Optional[str]: - return self._name - - @property - @abc.abstractmethod - def canonical(self) -> str: - """Exposes the resource's canonical path. - - For example '/foo/bar/{name}' - - """ - - @abc.abstractmethod # pragma: no branch - def url_for(self, **kwargs: str) -> URL: - """Construct url for resource with additional params.""" - - @abc.abstractmethod # pragma: no branch - async def resolve(self, request: Request) -> _Resolve: - """Resolve resource. - - Return (UrlMappingMatchInfo, allowed_methods) pair. - """ - - @abc.abstractmethod - def add_prefix(self, prefix: str) -> None: - """Add a prefix to processed URLs. - - Required for subapplications support. - """ - - @abc.abstractmethod - def get_info(self) -> _InfoDict: - """Return a dict with additional info useful for introspection""" - - def freeze(self) -> None: - pass - - @abc.abstractmethod - def raw_match(self, path: str) -> bool: - """Perform a raw match against path""" - - -class AbstractRoute(abc.ABC): - def __init__( - self, - method: str, - handler: Union[Handler, Type[AbstractView]], - *, - expect_handler: Optional[_ExpectHandler] = None, - resource: Optional[AbstractResource] = None, - ) -> None: - - if expect_handler is None: - expect_handler = _default_expect_handler - - assert inspect.iscoroutinefunction(expect_handler) or ( - sys.version_info < (3, 14) and asyncio.iscoroutinefunction(expect_handler) - ), f"Coroutine is expected, got {expect_handler!r}" - - method = method.upper() - if not HTTP_METHOD_RE.match(method): - raise ValueError(f"{method} is not allowed HTTP method") - - assert callable(handler), handler - if inspect.iscoroutinefunction(handler) or ( - sys.version_info < (3, 14) and asyncio.iscoroutinefunction(handler) - ): - pass - elif inspect.isgeneratorfunction(handler): - if TYPE_CHECKING: - assert False - warnings.warn( - "Bare generators are deprecated, use @coroutine wrapper", - DeprecationWarning, - ) - elif isinstance(handler, type) and issubclass(handler, AbstractView): - pass - else: - warnings.warn( - "Bare functions are deprecated, use async ones", DeprecationWarning - ) - - @wraps(handler) - async def handler_wrapper(request: Request) -> StreamResponse: - result = old_handler(request) # type: ignore[call-arg] - if asyncio.iscoroutine(result): - result = await result - assert isinstance(result, StreamResponse) - return result - - old_handler = handler - handler = handler_wrapper - - self._method = method - self._handler = handler - self._expect_handler = expect_handler - self._resource = resource - - @property - def method(self) -> str: - return self._method - - @property - def handler(self) -> Handler: - return self._handler - - @property - @abc.abstractmethod - def name(self) -> Optional[str]: - """Optional route's name, always equals to resource's name.""" - - @property - def resource(self) -> Optional[AbstractResource]: - return self._resource - - @abc.abstractmethod - def get_info(self) -> _InfoDict: - """Return a dict with additional info useful for introspection""" - - @abc.abstractmethod # pragma: no branch - def url_for(self, *args: str, **kwargs: str) -> URL: - """Construct url for route with additional params.""" - - async def handle_expect_header(self, request: Request) -> Optional[StreamResponse]: - return await self._expect_handler(request) - - -class UrlMappingMatchInfo(BaseDict, AbstractMatchInfo): - - __slots__ = ("_route", "_apps", "_current_app", "_frozen") - - def __init__(self, match_dict: Dict[str, str], route: AbstractRoute) -> None: - super().__init__(match_dict) - self._route = route - self._apps: List[Application] = [] - self._current_app: Optional[Application] = None - self._frozen = False - - @property - def handler(self) -> Handler: - return self._route.handler - - @property - def route(self) -> AbstractRoute: - return self._route - - @property - def expect_handler(self) -> _ExpectHandler: - return self._route.handle_expect_header - - @property - def http_exception(self) -> Optional[HTTPException]: - return None - - def get_info(self) -> _InfoDict: # type: ignore[override] - return self._route.get_info() - - @property - def apps(self) -> Tuple["Application", ...]: - return tuple(self._apps) - - def add_app(self, app: "Application") -> None: - if self._frozen: - raise RuntimeError("Cannot change apps stack after .freeze() call") - if self._current_app is None: - self._current_app = app - self._apps.insert(0, app) - - @property - def current_app(self) -> "Application": - app = self._current_app - assert app is not None - return app - - @current_app.setter - def current_app(self, app: "Application") -> None: - if DEBUG: # pragma: no cover - if app not in self._apps: - raise RuntimeError( - "Expected one of the following apps {!r}, got {!r}".format( - self._apps, app - ) - ) - self._current_app = app - - def freeze(self) -> None: - self._frozen = True - - def __repr__(self) -> str: - return f"" - - -class MatchInfoError(UrlMappingMatchInfo): - - __slots__ = ("_exception",) - - def __init__(self, http_exception: HTTPException) -> None: - self._exception = http_exception - super().__init__({}, SystemRoute(self._exception)) - - @property - def http_exception(self) -> HTTPException: - return self._exception - - def __repr__(self) -> str: - return "".format( - self._exception.status, self._exception.reason - ) - - -async def _default_expect_handler(request: Request) -> None: - """Default handler for Expect header. - - Just send "100 Continue" to client. - raise HTTPExpectationFailed if value of header is not "100-continue" - """ - expect = request.headers.get(hdrs.EXPECT, "") - if request.version == HttpVersion11: - if expect.lower() == "100-continue": - await request.writer.write(b"HTTP/1.1 100 Continue\r\n\r\n") - # Reset output_size as we haven't started the main body yet. - request.writer.output_size = 0 - else: - raise HTTPExpectationFailed(text="Unknown Expect: %s" % expect) - - -class Resource(AbstractResource): - def __init__(self, *, name: Optional[str] = None) -> None: - super().__init__(name=name) - self._routes: Dict[str, ResourceRoute] = {} - self._any_route: Optional[ResourceRoute] = None - self._allowed_methods: Set[str] = set() - - def add_route( - self, - method: str, - handler: Union[Type[AbstractView], Handler], - *, - expect_handler: Optional[_ExpectHandler] = None, - ) -> "ResourceRoute": - if route := self._routes.get(method, self._any_route): - raise RuntimeError( - "Added route will never be executed, " - f"method {route.method} is already " - "registered" - ) - - route_obj = ResourceRoute(method, handler, self, expect_handler=expect_handler) - self.register_route(route_obj) - return route_obj - - def register_route(self, route: "ResourceRoute") -> None: - assert isinstance( - route, ResourceRoute - ), f"Instance of Route class is required, got {route!r}" - if route.method == hdrs.METH_ANY: - self._any_route = route - self._allowed_methods.add(route.method) - self._routes[route.method] = route - - async def resolve(self, request: Request) -> _Resolve: - if (match_dict := self._match(request.rel_url.path_safe)) is None: - return None, set() - if route := self._routes.get(request.method, self._any_route): - return UrlMappingMatchInfo(match_dict, route), self._allowed_methods - return None, self._allowed_methods - - @abc.abstractmethod - def _match(self, path: str) -> Optional[Dict[str, str]]: - pass # pragma: no cover - - def __len__(self) -> int: - return len(self._routes) - - def __iter__(self) -> Iterator["ResourceRoute"]: - return iter(self._routes.values()) - - # TODO: implement all abstract methods - - -class PlainResource(Resource): - def __init__(self, path: str, *, name: Optional[str] = None) -> None: - super().__init__(name=name) - assert not path or path.startswith("/") - self._path = path - - @property - def canonical(self) -> str: - return self._path - - def freeze(self) -> None: - if not self._path: - self._path = "/" - - def add_prefix(self, prefix: str) -> None: - assert prefix.startswith("/") - assert not prefix.endswith("/") - assert len(prefix) > 1 - self._path = prefix + self._path - - def _match(self, path: str) -> Optional[Dict[str, str]]: - # string comparison is about 10 times faster than regexp matching - if self._path == path: - return {} - return None - - def raw_match(self, path: str) -> bool: - return self._path == path - - def get_info(self) -> _InfoDict: - return {"path": self._path} - - def url_for(self) -> URL: # type: ignore[override] - return URL.build(path=self._path, encoded=True) - - def __repr__(self) -> str: - name = "'" + self.name + "' " if self.name is not None else "" - return f"" - - -class DynamicResource(Resource): - - DYN = re.compile(r"\{(?P[_a-zA-Z][_a-zA-Z0-9]*)\}") - DYN_WITH_RE = re.compile(r"\{(?P[_a-zA-Z][_a-zA-Z0-9]*):(?P.+)\}") - GOOD = r"[^{}/]+" - - def __init__(self, path: str, *, name: Optional[str] = None) -> None: - super().__init__(name=name) - self._orig_path = path - pattern = "" - formatter = "" - for part in ROUTE_RE.split(path): - match = self.DYN.fullmatch(part) - if match: - pattern += "(?P<{}>{})".format(match.group("var"), self.GOOD) - formatter += "{" + match.group("var") + "}" - continue - - match = self.DYN_WITH_RE.fullmatch(part) - if match: - pattern += "(?P<{var}>{re})".format(**match.groupdict()) - formatter += "{" + match.group("var") + "}" - continue - - if "{" in part or "}" in part: - raise ValueError(f"Invalid path '{path}'['{part}']") - - part = _requote_path(part) - formatter += part - pattern += re.escape(part) - - try: - compiled = re.compile(pattern) - except re.error as exc: - raise ValueError(f"Bad pattern '{pattern}': {exc}") from None - assert compiled.pattern.startswith(PATH_SEP) - assert formatter.startswith("/") - self._pattern = compiled - self._formatter = formatter - - @property - def canonical(self) -> str: - return self._formatter - - def add_prefix(self, prefix: str) -> None: - assert prefix.startswith("/") - assert not prefix.endswith("/") - assert len(prefix) > 1 - self._pattern = re.compile(re.escape(prefix) + self._pattern.pattern) - self._formatter = prefix + self._formatter - - def _match(self, path: str) -> Optional[Dict[str, str]]: - match = self._pattern.fullmatch(path) - if match is None: - return None - return { - key: _unquote_path_safe(value) for key, value in match.groupdict().items() - } - - def raw_match(self, path: str) -> bool: - return self._orig_path == path - - def get_info(self) -> _InfoDict: - return {"formatter": self._formatter, "pattern": self._pattern} - - def url_for(self, **parts: str) -> URL: - url = self._formatter.format_map({k: _quote_path(v) for k, v in parts.items()}) - return URL.build(path=url, encoded=True) - - def __repr__(self) -> str: - name = "'" + self.name + "' " if self.name is not None else "" - return "".format( - name=name, formatter=self._formatter - ) - - -class PrefixResource(AbstractResource): - def __init__(self, prefix: str, *, name: Optional[str] = None) -> None: - assert not prefix or prefix.startswith("/"), prefix - assert prefix in ("", "/") or not prefix.endswith("/"), prefix - super().__init__(name=name) - self._prefix = _requote_path(prefix) - self._prefix2 = self._prefix + "/" - - @property - def canonical(self) -> str: - return self._prefix - - def add_prefix(self, prefix: str) -> None: - assert prefix.startswith("/") - assert not prefix.endswith("/") - assert len(prefix) > 1 - self._prefix = prefix + self._prefix - self._prefix2 = self._prefix + "/" - - def raw_match(self, prefix: str) -> bool: - return False - - # TODO: impl missing abstract methods - - -class StaticResource(PrefixResource): - VERSION_KEY = "v" - - def __init__( - self, - prefix: str, - directory: PathLike, - *, - name: Optional[str] = None, - expect_handler: Optional[_ExpectHandler] = None, - chunk_size: int = 256 * 1024, - show_index: bool = False, - follow_symlinks: bool = False, - append_version: bool = False, - ) -> None: - super().__init__(prefix, name=name) - try: - directory = Path(directory).expanduser().resolve(strict=True) - except FileNotFoundError as error: - raise ValueError(f"'{directory}' does not exist") from error - if not directory.is_dir(): - raise ValueError(f"'{directory}' is not a directory") - self._directory = directory - self._show_index = show_index - self._chunk_size = chunk_size - self._follow_symlinks = follow_symlinks - self._expect_handler = expect_handler - self._append_version = append_version - - self._routes = { - "GET": ResourceRoute( - "GET", self._handle, self, expect_handler=expect_handler - ), - "HEAD": ResourceRoute( - "HEAD", self._handle, self, expect_handler=expect_handler - ), - } - self._allowed_methods = set(self._routes) - - def url_for( # type: ignore[override] - self, - *, - filename: PathLike, - append_version: Optional[bool] = None, - ) -> URL: - if append_version is None: - append_version = self._append_version - filename = str(filename).lstrip("/") - - url = URL.build(path=self._prefix, encoded=True) - # filename is not encoded - if YARL_VERSION < (1, 6): - url = url / filename.replace("%", "%25") - else: - url = url / filename - - if append_version: - unresolved_path = self._directory.joinpath(filename) - try: - if self._follow_symlinks: - normalized_path = Path(os.path.normpath(unresolved_path)) - normalized_path.relative_to(self._directory) - filepath = normalized_path.resolve() - else: - filepath = unresolved_path.resolve() - filepath.relative_to(self._directory) - except (ValueError, FileNotFoundError): - # ValueError for case when path point to symlink - # with follow_symlinks is False - return url # relatively safe - if filepath.is_file(): - # TODO cache file content - # with file watcher for cache invalidation - with filepath.open("rb") as f: - file_bytes = f.read() - h = self._get_file_hash(file_bytes) - url = url.with_query({self.VERSION_KEY: h}) - return url - return url - - @staticmethod - def _get_file_hash(byte_array: bytes) -> str: - m = hashlib.sha256() # todo sha256 can be configurable param - m.update(byte_array) - b64 = base64.urlsafe_b64encode(m.digest()) - return b64.decode("ascii") - - def get_info(self) -> _InfoDict: - return { - "directory": self._directory, - "prefix": self._prefix, - "routes": self._routes, - } - - def set_options_route(self, handler: Handler) -> None: - if "OPTIONS" in self._routes: - raise RuntimeError("OPTIONS route was set already") - self._routes["OPTIONS"] = ResourceRoute( - "OPTIONS", handler, self, expect_handler=self._expect_handler - ) - self._allowed_methods.add("OPTIONS") - - async def resolve(self, request: Request) -> _Resolve: - path = request.rel_url.path_safe - method = request.method - # We normalise here to avoid matches that traverse below the static root. - # e.g. /static/../../../../home/user/webapp/static/ - norm_path = os.path.normpath(path) - if IS_WINDOWS: - norm_path = norm_path.replace("\\", "/") - if not norm_path.startswith(self._prefix2) and norm_path != self._prefix: - return None, set() - - allowed_methods = self._allowed_methods - if method not in allowed_methods: - return None, allowed_methods - - match_dict = {"filename": _unquote_path_safe(path[len(self._prefix) + 1 :])} - return (UrlMappingMatchInfo(match_dict, self._routes[method]), allowed_methods) - - def __len__(self) -> int: - return len(self._routes) - - def __iter__(self) -> Iterator[AbstractRoute]: - return iter(self._routes.values()) - - async def _handle(self, request: Request) -> StreamResponse: - filename = request.match_info["filename"] - if Path(filename).is_absolute(): - # filename is an absolute path e.g. //network/share or D:\path - # which could be a UNC path leading to NTLM credential theft - raise HTTPNotFound() - unresolved_path = self._directory.joinpath(filename) - loop = asyncio.get_running_loop() - return await loop.run_in_executor( - None, self._resolve_path_to_response, unresolved_path - ) - - def _resolve_path_to_response(self, unresolved_path: Path) -> StreamResponse: - """Take the unresolved path and query the file system to form a response.""" - # Check for access outside the root directory. For follow symlinks, URI - # cannot traverse out, but symlinks can. Otherwise, no access outside - # root is permitted. - try: - if self._follow_symlinks: - normalized_path = Path(os.path.normpath(unresolved_path)) - normalized_path.relative_to(self._directory) - file_path = normalized_path.resolve() - else: - file_path = unresolved_path.resolve() - file_path.relative_to(self._directory) - except (ValueError, *CIRCULAR_SYMLINK_ERROR) as error: - # ValueError is raised for the relative check. Circular symlinks - # raise here on resolving for python < 3.13. - raise HTTPNotFound() from error - - # if path is a directory, return the contents if permitted. Note the - # directory check will raise if a segment is not readable. - try: - if file_path.is_dir(): - if self._show_index: - return Response( - text=self._directory_as_html(file_path), - content_type="text/html", - ) - else: - raise HTTPForbidden() - except PermissionError as error: - raise HTTPForbidden() from error - - # Return the file response, which handles all other checks. - return FileResponse(file_path, chunk_size=self._chunk_size) - - def _directory_as_html(self, dir_path: Path) -> str: - """returns directory's index as html.""" - assert dir_path.is_dir() - - relative_path_to_dir = dir_path.relative_to(self._directory).as_posix() - index_of = f"Index of /{html_escape(relative_path_to_dir)}" - h1 = f"

{index_of}

" - - index_list = [] - dir_index = dir_path.iterdir() - for _file in sorted(dir_index): - # show file url as relative to static path - rel_path = _file.relative_to(self._directory).as_posix() - quoted_file_url = _quote_path(f"{self._prefix}/{rel_path}") - - # if file is a directory, add '/' to the end of the name - if _file.is_dir(): - file_name = f"{_file.name}/" - else: - file_name = _file.name - - index_list.append( - f'
  • {html_escape(file_name)}
  • ' - ) - ul = "
      \n{}\n
    ".format("\n".join(index_list)) - body = f"\n{h1}\n{ul}\n" - - head_str = f"\n{index_of}\n" - html = f"\n{head_str}\n{body}\n" - - return html - - def __repr__(self) -> str: - name = "'" + self.name + "'" if self.name is not None else "" - return " {directory!r}>".format( - name=name, path=self._prefix, directory=self._directory - ) - - -class PrefixedSubAppResource(PrefixResource): - def __init__(self, prefix: str, app: "Application") -> None: - super().__init__(prefix) - self._app = app - self._add_prefix_to_resources(prefix) - - def add_prefix(self, prefix: str) -> None: - super().add_prefix(prefix) - self._add_prefix_to_resources(prefix) - - def _add_prefix_to_resources(self, prefix: str) -> None: - router = self._app.router - for resource in router.resources(): - # Since the canonical path of a resource is about - # to change, we need to unindex it and then reindex - router.unindex_resource(resource) - resource.add_prefix(prefix) - router.index_resource(resource) - - def url_for(self, *args: str, **kwargs: str) -> URL: - raise RuntimeError(".url_for() is not supported by sub-application root") - - def get_info(self) -> _InfoDict: - return {"app": self._app, "prefix": self._prefix} - - async def resolve(self, request: Request) -> _Resolve: - match_info = await self._app.router.resolve(request) - match_info.add_app(self._app) - if isinstance(match_info.http_exception, HTTPMethodNotAllowed): - methods = match_info.http_exception.allowed_methods - else: - methods = set() - return match_info, methods - - def __len__(self) -> int: - return len(self._app.router.routes()) - - def __iter__(self) -> Iterator[AbstractRoute]: - return iter(self._app.router.routes()) - - def __repr__(self) -> str: - return " {app!r}>".format( - prefix=self._prefix, app=self._app - ) - - -class AbstractRuleMatching(abc.ABC): - @abc.abstractmethod # pragma: no branch - async def match(self, request: Request) -> bool: - """Return bool if the request satisfies the criteria""" - - @abc.abstractmethod # pragma: no branch - def get_info(self) -> _InfoDict: - """Return a dict with additional info useful for introspection""" - - @property - @abc.abstractmethod # pragma: no branch - def canonical(self) -> str: - """Return a str""" - - -class Domain(AbstractRuleMatching): - re_part = re.compile(r"(?!-)[a-z\d-]{1,63}(? None: - super().__init__() - self._domain = self.validation(domain) - - @property - def canonical(self) -> str: - return self._domain - - def validation(self, domain: str) -> str: - if not isinstance(domain, str): - raise TypeError("Domain must be str") - domain = domain.rstrip(".").lower() - if not domain: - raise ValueError("Domain cannot be empty") - elif "://" in domain: - raise ValueError("Scheme not supported") - url = URL("http://" + domain) - assert url.raw_host is not None - if not all(self.re_part.fullmatch(x) for x in url.raw_host.split(".")): - raise ValueError("Domain not valid") - if url.port == 80: - return url.raw_host - return f"{url.raw_host}:{url.port}" - - async def match(self, request: Request) -> bool: - host = request.headers.get(hdrs.HOST) - if not host: - return False - return self.match_domain(host) - - def match_domain(self, host: str) -> bool: - return host.lower() == self._domain - - def get_info(self) -> _InfoDict: - return {"domain": self._domain} - - -class MaskDomain(Domain): - re_part = re.compile(r"(?!-)[a-z\d\*-]{1,63}(? None: - super().__init__(domain) - mask = self._domain.replace(".", r"\.").replace("*", ".*") - self._mask = re.compile(mask) - - @property - def canonical(self) -> str: - return self._mask.pattern - - def match_domain(self, host: str) -> bool: - return self._mask.fullmatch(host) is not None - - -class MatchedSubAppResource(PrefixedSubAppResource): - def __init__(self, rule: AbstractRuleMatching, app: "Application") -> None: - AbstractResource.__init__(self) - self._prefix = "" - self._app = app - self._rule = rule - - @property - def canonical(self) -> str: - return self._rule.canonical - - def get_info(self) -> _InfoDict: - return {"app": self._app, "rule": self._rule} - - async def resolve(self, request: Request) -> _Resolve: - if not await self._rule.match(request): - return None, set() - match_info = await self._app.router.resolve(request) - match_info.add_app(self._app) - if isinstance(match_info.http_exception, HTTPMethodNotAllowed): - methods = match_info.http_exception.allowed_methods - else: - methods = set() - return match_info, methods - - def __repr__(self) -> str: - return f" {self._app!r}>" - - -class ResourceRoute(AbstractRoute): - """A route with resource""" - - def __init__( - self, - method: str, - handler: Union[Handler, Type[AbstractView]], - resource: AbstractResource, - *, - expect_handler: Optional[_ExpectHandler] = None, - ) -> None: - super().__init__( - method, handler, expect_handler=expect_handler, resource=resource - ) - - def __repr__(self) -> str: - return " {handler!r}".format( - method=self.method, resource=self._resource, handler=self.handler - ) - - @property - def name(self) -> Optional[str]: - if self._resource is None: - return None - return self._resource.name - - def url_for(self, *args: str, **kwargs: str) -> URL: - """Construct url for route with additional params.""" - assert self._resource is not None - return self._resource.url_for(*args, **kwargs) - - def get_info(self) -> _InfoDict: - assert self._resource is not None - return self._resource.get_info() - - -class SystemRoute(AbstractRoute): - def __init__(self, http_exception: HTTPException) -> None: - super().__init__(hdrs.METH_ANY, self._handle) - self._http_exception = http_exception - - def url_for(self, *args: str, **kwargs: str) -> URL: - raise RuntimeError(".url_for() is not allowed for SystemRoute") - - @property - def name(self) -> Optional[str]: - return None - - def get_info(self) -> _InfoDict: - return {"http_exception": self._http_exception} - - async def _handle(self, request: Request) -> StreamResponse: - raise self._http_exception - - @property - def status(self) -> int: - return self._http_exception.status - - @property - def reason(self) -> str: - return self._http_exception.reason - - def __repr__(self) -> str: - return "".format(self=self) - - -class View(AbstractView): - async def _iter(self) -> StreamResponse: - if self.request.method not in hdrs.METH_ALL: - self._raise_allowed_methods() - method: Optional[Callable[[], Awaitable[StreamResponse]]] - method = getattr(self, self.request.method.lower(), None) - if method is None: - self._raise_allowed_methods() - ret = await method() - assert isinstance(ret, StreamResponse) - return ret - - def __await__(self) -> Generator[None, None, StreamResponse]: - return self._iter().__await__() - - def _raise_allowed_methods(self) -> NoReturn: - allowed_methods = {m for m in hdrs.METH_ALL if hasattr(self, m.lower())} - raise HTTPMethodNotAllowed(self.request.method, allowed_methods) - - -class ResourcesView(Sized, Iterable[AbstractResource], Container[AbstractResource]): - def __init__(self, resources: List[AbstractResource]) -> None: - self._resources = resources - - def __len__(self) -> int: - return len(self._resources) - - def __iter__(self) -> Iterator[AbstractResource]: - yield from self._resources - - def __contains__(self, resource: object) -> bool: - return resource in self._resources - - -class RoutesView(Sized, Iterable[AbstractRoute], Container[AbstractRoute]): - def __init__(self, resources: List[AbstractResource]): - self._routes: List[AbstractRoute] = [] - for resource in resources: - for route in resource: - self._routes.append(route) - - def __len__(self) -> int: - return len(self._routes) - - def __iter__(self) -> Iterator[AbstractRoute]: - yield from self._routes - - def __contains__(self, route: object) -> bool: - return route in self._routes - - -class UrlDispatcher(AbstractRouter, Mapping[str, AbstractResource]): - - NAME_SPLIT_RE = re.compile(r"[.:-]") - - def __init__(self) -> None: - super().__init__() - self._resources: List[AbstractResource] = [] - self._named_resources: Dict[str, AbstractResource] = {} - self._resource_index: dict[str, list[AbstractResource]] = {} - self._matched_sub_app_resources: List[MatchedSubAppResource] = [] - - async def resolve(self, request: Request) -> UrlMappingMatchInfo: - resource_index = self._resource_index - allowed_methods: Set[str] = set() - - # MatchedSubAppResource is primarily used to match on domain names - # (though custom rules could match on other things). This means that - # the traversal algorithm below can't be applied, and that we likely - # need to check these first so a sub app that defines the same path - # as a parent app will get priority if there's a domain match. - # - # For most cases we do not expect there to be many of these since - # currently they are only added by `.add_domain()`. - for resource in self._matched_sub_app_resources: - match_dict, allowed = await resource.resolve(request) - if match_dict is not None: - return match_dict - else: - allowed_methods |= allowed - - # Walk the url parts looking for candidates. We walk the url backwards - # to ensure the most explicit match is found first. If there are multiple - # candidates for a given url part because there are multiple resources - # registered for the same canonical path, we resolve them in a linear - # fashion to ensure registration order is respected. - url_part = request.rel_url.path_safe - while url_part: - for candidate in resource_index.get(url_part, ()): - match_dict, allowed = await candidate.resolve(request) - if match_dict is not None: - return match_dict - else: - allowed_methods |= allowed - if url_part == "/": - break - url_part = url_part.rpartition("/")[0] or "/" - - if allowed_methods: - return MatchInfoError(HTTPMethodNotAllowed(request.method, allowed_methods)) - - return MatchInfoError(HTTPNotFound()) - - def __iter__(self) -> Iterator[str]: - return iter(self._named_resources) - - def __len__(self) -> int: - return len(self._named_resources) - - def __contains__(self, resource: object) -> bool: - return resource in self._named_resources - - def __getitem__(self, name: str) -> AbstractResource: - return self._named_resources[name] - - def resources(self) -> ResourcesView: - return ResourcesView(self._resources) - - def routes(self) -> RoutesView: - return RoutesView(self._resources) - - def named_resources(self) -> Mapping[str, AbstractResource]: - return MappingProxyType(self._named_resources) - - def register_resource(self, resource: AbstractResource) -> None: - assert isinstance( - resource, AbstractResource - ), f"Instance of AbstractResource class is required, got {resource!r}" - if self.frozen: - raise RuntimeError("Cannot register a resource into frozen router.") - - name = resource.name - - if name is not None: - parts = self.NAME_SPLIT_RE.split(name) - for part in parts: - if keyword.iskeyword(part): - raise ValueError( - f"Incorrect route name {name!r}, " - "python keywords cannot be used " - "for route name" - ) - if not part.isidentifier(): - raise ValueError( - "Incorrect route name {!r}, " - "the name should be a sequence of " - "python identifiers separated " - "by dash, dot or column".format(name) - ) - if name in self._named_resources: - raise ValueError( - "Duplicate {!r}, " - "already handled by {!r}".format(name, self._named_resources[name]) - ) - self._named_resources[name] = resource - self._resources.append(resource) - - if isinstance(resource, MatchedSubAppResource): - # We cannot index match sub-app resources because they have match rules - self._matched_sub_app_resources.append(resource) - else: - self.index_resource(resource) - - def _get_resource_index_key(self, resource: AbstractResource) -> str: - """Return a key to index the resource in the resource index.""" - if "{" in (index_key := resource.canonical): - # strip at the first { to allow for variables, and than - # rpartition at / to allow for variable parts in the path - # For example if the canonical path is `/core/locations{tail:.*}` - # the index key will be `/core` since index is based on the - # url parts split by `/` - index_key = index_key.partition("{")[0].rpartition("/")[0] - return index_key.rstrip("/") or "/" - - def index_resource(self, resource: AbstractResource) -> None: - """Add a resource to the resource index.""" - resource_key = self._get_resource_index_key(resource) - # There may be multiple resources for a canonical path - # so we keep them in a list to ensure that registration - # order is respected. - self._resource_index.setdefault(resource_key, []).append(resource) - - def unindex_resource(self, resource: AbstractResource) -> None: - """Remove a resource from the resource index.""" - resource_key = self._get_resource_index_key(resource) - self._resource_index[resource_key].remove(resource) - - def add_resource(self, path: str, *, name: Optional[str] = None) -> Resource: - if path and not path.startswith("/"): - raise ValueError("path should be started with / or be empty") - # Reuse last added resource if path and name are the same - if self._resources: - resource = self._resources[-1] - if resource.name == name and resource.raw_match(path): - return cast(Resource, resource) - if not ("{" in path or "}" in path or ROUTE_RE.search(path)): - resource = PlainResource(path, name=name) - self.register_resource(resource) - return resource - resource = DynamicResource(path, name=name) - self.register_resource(resource) - return resource - - def add_route( - self, - method: str, - path: str, - handler: Union[Handler, Type[AbstractView]], - *, - name: Optional[str] = None, - expect_handler: Optional[_ExpectHandler] = None, - ) -> AbstractRoute: - resource = self.add_resource(path, name=name) - return resource.add_route(method, handler, expect_handler=expect_handler) - - def add_static( - self, - prefix: str, - path: PathLike, - *, - name: Optional[str] = None, - expect_handler: Optional[_ExpectHandler] = None, - chunk_size: int = 256 * 1024, - show_index: bool = False, - follow_symlinks: bool = False, - append_version: bool = False, - ) -> AbstractResource: - """Add static files view. - - prefix - url prefix - path - folder with files - - """ - assert prefix.startswith("/") - if prefix.endswith("/"): - prefix = prefix[:-1] - resource = StaticResource( - prefix, - path, - name=name, - expect_handler=expect_handler, - chunk_size=chunk_size, - show_index=show_index, - follow_symlinks=follow_symlinks, - append_version=append_version, - ) - self.register_resource(resource) - return resource - - def add_head(self, path: str, handler: Handler, **kwargs: Any) -> AbstractRoute: - """Shortcut for add_route with method HEAD.""" - return self.add_route(hdrs.METH_HEAD, path, handler, **kwargs) - - def add_options(self, path: str, handler: Handler, **kwargs: Any) -> AbstractRoute: - """Shortcut for add_route with method OPTIONS.""" - return self.add_route(hdrs.METH_OPTIONS, path, handler, **kwargs) - - def add_get( - self, - path: str, - handler: Handler, - *, - name: Optional[str] = None, - allow_head: bool = True, - **kwargs: Any, - ) -> AbstractRoute: - """Shortcut for add_route with method GET. - - If allow_head is true, another - route is added allowing head requests to the same endpoint. - """ - resource = self.add_resource(path, name=name) - if allow_head: - resource.add_route(hdrs.METH_HEAD, handler, **kwargs) - return resource.add_route(hdrs.METH_GET, handler, **kwargs) - - def add_post(self, path: str, handler: Handler, **kwargs: Any) -> AbstractRoute: - """Shortcut for add_route with method POST.""" - return self.add_route(hdrs.METH_POST, path, handler, **kwargs) - - def add_put(self, path: str, handler: Handler, **kwargs: Any) -> AbstractRoute: - """Shortcut for add_route with method PUT.""" - return self.add_route(hdrs.METH_PUT, path, handler, **kwargs) - - def add_patch(self, path: str, handler: Handler, **kwargs: Any) -> AbstractRoute: - """Shortcut for add_route with method PATCH.""" - return self.add_route(hdrs.METH_PATCH, path, handler, **kwargs) - - def add_delete(self, path: str, handler: Handler, **kwargs: Any) -> AbstractRoute: - """Shortcut for add_route with method DELETE.""" - return self.add_route(hdrs.METH_DELETE, path, handler, **kwargs) - - def add_view( - self, path: str, handler: Type[AbstractView], **kwargs: Any - ) -> AbstractRoute: - """Shortcut for add_route with ANY methods for a class-based view.""" - return self.add_route(hdrs.METH_ANY, path, handler, **kwargs) - - def freeze(self) -> None: - super().freeze() - for resource in self._resources: - resource.freeze() - - def add_routes(self, routes: Iterable[AbstractRouteDef]) -> List[AbstractRoute]: - """Append routes to route table. - - Parameter should be a sequence of RouteDef objects. - - Returns a list of registered AbstractRoute instances. - """ - registered_routes = [] - for route_def in routes: - registered_routes.extend(route_def.register(self)) - return registered_routes - - -def _quote_path(value: str) -> str: - if YARL_VERSION < (1, 6): - value = value.replace("%", "%25") - return URL.build(path=value, encoded=False).raw_path - - -def _unquote_path_safe(value: str) -> str: - if "%" not in value: - return value - return value.replace("%2F", "/").replace("%25", "%") - - -def _requote_path(value: str) -> str: - # Quote non-ascii characters and other characters which must be quoted, - # but preserve existing %-sequences. - result = _quote_path(value) - if "%" in value: - result = result.replace("%25", "%") - return result diff --git a/venv/lib/python3.9/site-packages/aiohttp/web_ws.py b/venv/lib/python3.9/site-packages/aiohttp/web_ws.py deleted file mode 100644 index 575f9a3..0000000 --- a/venv/lib/python3.9/site-packages/aiohttp/web_ws.py +++ /dev/null @@ -1,631 +0,0 @@ -import asyncio -import base64 -import binascii -import hashlib -import json -import sys -from typing import Any, Final, Iterable, Optional, Tuple, Union, cast - -import attr -from multidict import CIMultiDict - -from . import hdrs -from ._websocket.reader import WebSocketDataQueue -from ._websocket.writer import DEFAULT_LIMIT -from .abc import AbstractStreamWriter -from .client_exceptions import WSMessageTypeError -from .helpers import calculate_timeout_when, set_exception, set_result -from .http import ( - WS_CLOSED_MESSAGE, - WS_CLOSING_MESSAGE, - WS_KEY, - WebSocketError, - WebSocketReader, - WebSocketWriter, - WSCloseCode, - WSMessage, - WSMsgType as WSMsgType, - ws_ext_gen, - ws_ext_parse, -) -from .http_websocket import _INTERNAL_RECEIVE_TYPES -from .log import ws_logger -from .streams import EofStream -from .typedefs import JSONDecoder, JSONEncoder -from .web_exceptions import HTTPBadRequest, HTTPException -from .web_request import BaseRequest -from .web_response import StreamResponse - -if sys.version_info >= (3, 11): - import asyncio as async_timeout -else: - import async_timeout - -__all__ = ( - "WebSocketResponse", - "WebSocketReady", - "WSMsgType", -) - -THRESHOLD_CONNLOST_ACCESS: Final[int] = 5 - - -@attr.s(auto_attribs=True, frozen=True, slots=True) -class WebSocketReady: - ok: bool - protocol: Optional[str] - - def __bool__(self) -> bool: - return self.ok - - -class WebSocketResponse(StreamResponse): - - _length_check: bool = False - _ws_protocol: Optional[str] = None - _writer: Optional[WebSocketWriter] = None - _reader: Optional[WebSocketDataQueue] = None - _closed: bool = False - _closing: bool = False - _conn_lost: int = 0 - _close_code: Optional[int] = None - _loop: Optional[asyncio.AbstractEventLoop] = None - _waiting: bool = False - _close_wait: Optional[asyncio.Future[None]] = None - _exception: Optional[BaseException] = None - _heartbeat_when: float = 0.0 - _heartbeat_cb: Optional[asyncio.TimerHandle] = None - _pong_response_cb: Optional[asyncio.TimerHandle] = None - _ping_task: Optional[asyncio.Task[None]] = None - - def __init__( - self, - *, - timeout: float = 10.0, - receive_timeout: Optional[float] = None, - autoclose: bool = True, - autoping: bool = True, - heartbeat: Optional[float] = None, - protocols: Iterable[str] = (), - compress: bool = True, - max_msg_size: int = 4 * 1024 * 1024, - writer_limit: int = DEFAULT_LIMIT, - ) -> None: - super().__init__(status=101) - self._protocols = protocols - self._timeout = timeout - self._receive_timeout = receive_timeout - self._autoclose = autoclose - self._autoping = autoping - self._heartbeat = heartbeat - if heartbeat is not None: - self._pong_heartbeat = heartbeat / 2.0 - self._compress: Union[bool, int] = compress - self._max_msg_size = max_msg_size - self._writer_limit = writer_limit - - def _cancel_heartbeat(self) -> None: - self._cancel_pong_response_cb() - if self._heartbeat_cb is not None: - self._heartbeat_cb.cancel() - self._heartbeat_cb = None - if self._ping_task is not None: - self._ping_task.cancel() - self._ping_task = None - - def _cancel_pong_response_cb(self) -> None: - if self._pong_response_cb is not None: - self._pong_response_cb.cancel() - self._pong_response_cb = None - - def _reset_heartbeat(self) -> None: - if self._heartbeat is None: - return - self._cancel_pong_response_cb() - req = self._req - timeout_ceil_threshold = ( - req._protocol._timeout_ceil_threshold if req is not None else 5 - ) - loop = self._loop - assert loop is not None - now = loop.time() - when = calculate_timeout_when(now, self._heartbeat, timeout_ceil_threshold) - self._heartbeat_when = when - if self._heartbeat_cb is None: - # We do not cancel the previous heartbeat_cb here because - # it generates a significant amount of TimerHandle churn - # which causes asyncio to rebuild the heap frequently. - # Instead _send_heartbeat() will reschedule the next - # heartbeat if it fires too early. - self._heartbeat_cb = loop.call_at(when, self._send_heartbeat) - - def _send_heartbeat(self) -> None: - self._heartbeat_cb = None - loop = self._loop - assert loop is not None and self._writer is not None - now = loop.time() - if now < self._heartbeat_when: - # Heartbeat fired too early, reschedule - self._heartbeat_cb = loop.call_at( - self._heartbeat_when, self._send_heartbeat - ) - return - - req = self._req - timeout_ceil_threshold = ( - req._protocol._timeout_ceil_threshold if req is not None else 5 - ) - when = calculate_timeout_when(now, self._pong_heartbeat, timeout_ceil_threshold) - self._cancel_pong_response_cb() - self._pong_response_cb = loop.call_at(when, self._pong_not_received) - - coro = self._writer.send_frame(b"", WSMsgType.PING) - if sys.version_info >= (3, 12): - # Optimization for Python 3.12, try to send the ping - # immediately to avoid having to schedule - # the task on the event loop. - ping_task = asyncio.Task(coro, loop=loop, eager_start=True) - else: - ping_task = loop.create_task(coro) - - if not ping_task.done(): - self._ping_task = ping_task - ping_task.add_done_callback(self._ping_task_done) - else: - self._ping_task_done(ping_task) - - def _ping_task_done(self, task: "asyncio.Task[None]") -> None: - """Callback for when the ping task completes.""" - if not task.cancelled() and (exc := task.exception()): - self._handle_ping_pong_exception(exc) - self._ping_task = None - - def _pong_not_received(self) -> None: - if self._req is not None and self._req.transport is not None: - self._handle_ping_pong_exception( - asyncio.TimeoutError( - f"No PONG received after {self._pong_heartbeat} seconds" - ) - ) - - def _handle_ping_pong_exception(self, exc: BaseException) -> None: - """Handle exceptions raised during ping/pong processing.""" - if self._closed: - return - self._set_closed() - self._set_code_close_transport(WSCloseCode.ABNORMAL_CLOSURE) - self._exception = exc - if self._waiting and not self._closing and self._reader is not None: - self._reader.feed_data(WSMessage(WSMsgType.ERROR, exc, None), 0) - - def _set_closed(self) -> None: - """Set the connection to closed. - - Cancel any heartbeat timers and set the closed flag. - """ - self._closed = True - self._cancel_heartbeat() - - async def prepare(self, request: BaseRequest) -> AbstractStreamWriter: - # make pre-check to don't hide it by do_handshake() exceptions - if self._payload_writer is not None: - return self._payload_writer - - protocol, writer = self._pre_start(request) - payload_writer = await super().prepare(request) - assert payload_writer is not None - self._post_start(request, protocol, writer) - await payload_writer.drain() - return payload_writer - - def _handshake( - self, request: BaseRequest - ) -> Tuple["CIMultiDict[str]", Optional[str], int, bool]: - headers = request.headers - if "websocket" != headers.get(hdrs.UPGRADE, "").lower().strip(): - raise HTTPBadRequest( - text=( - "No WebSocket UPGRADE hdr: {}\n Can " - '"Upgrade" only to "WebSocket".' - ).format(headers.get(hdrs.UPGRADE)) - ) - - if "upgrade" not in headers.get(hdrs.CONNECTION, "").lower(): - raise HTTPBadRequest( - text="No CONNECTION upgrade hdr: {}".format( - headers.get(hdrs.CONNECTION) - ) - ) - - # find common sub-protocol between client and server - protocol: Optional[str] = None - if hdrs.SEC_WEBSOCKET_PROTOCOL in headers: - req_protocols = [ - str(proto.strip()) - for proto in headers[hdrs.SEC_WEBSOCKET_PROTOCOL].split(",") - ] - - for proto in req_protocols: - if proto in self._protocols: - protocol = proto - break - else: - # No overlap found: Return no protocol as per spec - ws_logger.warning( - "%s: Client protocols %r don’t overlap server-known ones %r", - request.remote, - req_protocols, - self._protocols, - ) - - # check supported version - version = headers.get(hdrs.SEC_WEBSOCKET_VERSION, "") - if version not in ("13", "8", "7"): - raise HTTPBadRequest(text=f"Unsupported version: {version}") - - # check client handshake for validity - key = headers.get(hdrs.SEC_WEBSOCKET_KEY) - try: - if not key or len(base64.b64decode(key)) != 16: - raise HTTPBadRequest(text=f"Handshake error: {key!r}") - except binascii.Error: - raise HTTPBadRequest(text=f"Handshake error: {key!r}") from None - - accept_val = base64.b64encode( - hashlib.sha1(key.encode() + WS_KEY).digest() - ).decode() - response_headers = CIMultiDict( - { - hdrs.UPGRADE: "websocket", - hdrs.CONNECTION: "upgrade", - hdrs.SEC_WEBSOCKET_ACCEPT: accept_val, - } - ) - - notakeover = False - compress = 0 - if self._compress: - extensions = headers.get(hdrs.SEC_WEBSOCKET_EXTENSIONS) - # Server side always get return with no exception. - # If something happened, just drop compress extension - compress, notakeover = ws_ext_parse(extensions, isserver=True) - if compress: - enabledext = ws_ext_gen( - compress=compress, isserver=True, server_notakeover=notakeover - ) - response_headers[hdrs.SEC_WEBSOCKET_EXTENSIONS] = enabledext - - if protocol: - response_headers[hdrs.SEC_WEBSOCKET_PROTOCOL] = protocol - return ( - response_headers, - protocol, - compress, - notakeover, - ) - - def _pre_start(self, request: BaseRequest) -> Tuple[Optional[str], WebSocketWriter]: - self._loop = request._loop - - headers, protocol, compress, notakeover = self._handshake(request) - - self.set_status(101) - self.headers.update(headers) - self.force_close() - self._compress = compress - transport = request._protocol.transport - assert transport is not None - writer = WebSocketWriter( - request._protocol, - transport, - compress=compress, - notakeover=notakeover, - limit=self._writer_limit, - ) - - return protocol, writer - - def _post_start( - self, request: BaseRequest, protocol: Optional[str], writer: WebSocketWriter - ) -> None: - self._ws_protocol = protocol - self._writer = writer - - self._reset_heartbeat() - - loop = self._loop - assert loop is not None - self._reader = WebSocketDataQueue(request._protocol, 2**16, loop=loop) - request.protocol.set_parser( - WebSocketReader( - self._reader, self._max_msg_size, compress=bool(self._compress) - ) - ) - # disable HTTP keepalive for WebSocket - request.protocol.keep_alive(False) - - def can_prepare(self, request: BaseRequest) -> WebSocketReady: - if self._writer is not None: - raise RuntimeError("Already started") - try: - _, protocol, _, _ = self._handshake(request) - except HTTPException: - return WebSocketReady(False, None) - else: - return WebSocketReady(True, protocol) - - @property - def prepared(self) -> bool: - return self._writer is not None - - @property - def closed(self) -> bool: - return self._closed - - @property - def close_code(self) -> Optional[int]: - return self._close_code - - @property - def ws_protocol(self) -> Optional[str]: - return self._ws_protocol - - @property - def compress(self) -> Union[int, bool]: - return self._compress - - def get_extra_info(self, name: str, default: Any = None) -> Any: - """Get optional transport information. - - If no value associated with ``name`` is found, ``default`` is returned. - """ - writer = self._writer - if writer is None: - return default - transport = writer.transport - if transport is None: - return default - return transport.get_extra_info(name, default) - - def exception(self) -> Optional[BaseException]: - return self._exception - - async def ping(self, message: bytes = b"") -> None: - if self._writer is None: - raise RuntimeError("Call .prepare() first") - await self._writer.send_frame(message, WSMsgType.PING) - - async def pong(self, message: bytes = b"") -> None: - # unsolicited pong - if self._writer is None: - raise RuntimeError("Call .prepare() first") - await self._writer.send_frame(message, WSMsgType.PONG) - - async def send_frame( - self, message: bytes, opcode: WSMsgType, compress: Optional[int] = None - ) -> None: - """Send a frame over the websocket.""" - if self._writer is None: - raise RuntimeError("Call .prepare() first") - await self._writer.send_frame(message, opcode, compress) - - async def send_str(self, data: str, compress: Optional[int] = None) -> None: - if self._writer is None: - raise RuntimeError("Call .prepare() first") - if not isinstance(data, str): - raise TypeError("data argument must be str (%r)" % type(data)) - await self._writer.send_frame( - data.encode("utf-8"), WSMsgType.TEXT, compress=compress - ) - - async def send_bytes(self, data: bytes, compress: Optional[int] = None) -> None: - if self._writer is None: - raise RuntimeError("Call .prepare() first") - if not isinstance(data, (bytes, bytearray, memoryview)): - raise TypeError("data argument must be byte-ish (%r)" % type(data)) - await self._writer.send_frame(data, WSMsgType.BINARY, compress=compress) - - async def send_json( - self, - data: Any, - compress: Optional[int] = None, - *, - dumps: JSONEncoder = json.dumps, - ) -> None: - await self.send_str(dumps(data), compress=compress) - - async def write_eof(self) -> None: # type: ignore[override] - if self._eof_sent: - return - if self._payload_writer is None: - raise RuntimeError("Response has not been started") - - await self.close() - self._eof_sent = True - - async def close( - self, *, code: int = WSCloseCode.OK, message: bytes = b"", drain: bool = True - ) -> bool: - """Close websocket connection.""" - if self._writer is None: - raise RuntimeError("Call .prepare() first") - - if self._closed: - return False - self._set_closed() - - try: - await self._writer.close(code, message) - writer = self._payload_writer - assert writer is not None - if drain: - await writer.drain() - except (asyncio.CancelledError, asyncio.TimeoutError): - self._set_code_close_transport(WSCloseCode.ABNORMAL_CLOSURE) - raise - except Exception as exc: - self._exception = exc - self._set_code_close_transport(WSCloseCode.ABNORMAL_CLOSURE) - return True - - reader = self._reader - assert reader is not None - # we need to break `receive()` cycle before we can call - # `reader.read()` as `close()` may be called from different task - if self._waiting: - assert self._loop is not None - assert self._close_wait is None - self._close_wait = self._loop.create_future() - reader.feed_data(WS_CLOSING_MESSAGE, 0) - await self._close_wait - - if self._closing: - self._close_transport() - return True - - try: - async with async_timeout.timeout(self._timeout): - while True: - msg = await reader.read() - if msg.type is WSMsgType.CLOSE: - self._set_code_close_transport(msg.data) - return True - except asyncio.CancelledError: - self._set_code_close_transport(WSCloseCode.ABNORMAL_CLOSURE) - raise - except Exception as exc: - self._exception = exc - self._set_code_close_transport(WSCloseCode.ABNORMAL_CLOSURE) - return True - - def _set_closing(self, code: WSCloseCode) -> None: - """Set the close code and mark the connection as closing.""" - self._closing = True - self._close_code = code - self._cancel_heartbeat() - - def _set_code_close_transport(self, code: WSCloseCode) -> None: - """Set the close code and close the transport.""" - self._close_code = code - self._close_transport() - - def _close_transport(self) -> None: - """Close the transport.""" - if self._req is not None and self._req.transport is not None: - self._req.transport.close() - - async def receive(self, timeout: Optional[float] = None) -> WSMessage: - if self._reader is None: - raise RuntimeError("Call .prepare() first") - - receive_timeout = timeout or self._receive_timeout - while True: - if self._waiting: - raise RuntimeError("Concurrent call to receive() is not allowed") - - if self._closed: - self._conn_lost += 1 - if self._conn_lost >= THRESHOLD_CONNLOST_ACCESS: - raise RuntimeError("WebSocket connection is closed.") - return WS_CLOSED_MESSAGE - elif self._closing: - return WS_CLOSING_MESSAGE - - try: - self._waiting = True - try: - if receive_timeout: - # Entering the context manager and creating - # Timeout() object can take almost 50% of the - # run time in this loop so we avoid it if - # there is no read timeout. - async with async_timeout.timeout(receive_timeout): - msg = await self._reader.read() - else: - msg = await self._reader.read() - self._reset_heartbeat() - finally: - self._waiting = False - if self._close_wait: - set_result(self._close_wait, None) - except asyncio.TimeoutError: - raise - except EofStream: - self._close_code = WSCloseCode.OK - await self.close() - return WSMessage(WSMsgType.CLOSED, None, None) - except WebSocketError as exc: - self._close_code = exc.code - await self.close(code=exc.code) - return WSMessage(WSMsgType.ERROR, exc, None) - except Exception as exc: - self._exception = exc - self._set_closing(WSCloseCode.ABNORMAL_CLOSURE) - await self.close() - return WSMessage(WSMsgType.ERROR, exc, None) - - if msg.type not in _INTERNAL_RECEIVE_TYPES: - # If its not a close/closing/ping/pong message - # we can return it immediately - return msg - - if msg.type is WSMsgType.CLOSE: - self._set_closing(msg.data) - # Could be closed while awaiting reader. - if not self._closed and self._autoclose: - # The client is likely going to close the - # connection out from under us so we do not - # want to drain any pending writes as it will - # likely result writing to a broken pipe. - await self.close(drain=False) - elif msg.type is WSMsgType.CLOSING: - self._set_closing(WSCloseCode.OK) - elif msg.type is WSMsgType.PING and self._autoping: - await self.pong(msg.data) - continue - elif msg.type is WSMsgType.PONG and self._autoping: - continue - - return msg - - async def receive_str(self, *, timeout: Optional[float] = None) -> str: - msg = await self.receive(timeout) - if msg.type is not WSMsgType.TEXT: - raise WSMessageTypeError( - f"Received message {msg.type}:{msg.data!r} is not WSMsgType.TEXT" - ) - return cast(str, msg.data) - - async def receive_bytes(self, *, timeout: Optional[float] = None) -> bytes: - msg = await self.receive(timeout) - if msg.type is not WSMsgType.BINARY: - raise WSMessageTypeError( - f"Received message {msg.type}:{msg.data!r} is not WSMsgType.BINARY" - ) - return cast(bytes, msg.data) - - async def receive_json( - self, *, loads: JSONDecoder = json.loads, timeout: Optional[float] = None - ) -> Any: - data = await self.receive_str(timeout=timeout) - return loads(data) - - async def write(self, data: bytes) -> None: - raise RuntimeError("Cannot call .write() for websocket") - - def __aiter__(self) -> "WebSocketResponse": - return self - - async def __anext__(self) -> WSMessage: - msg = await self.receive() - if msg.type in (WSMsgType.CLOSE, WSMsgType.CLOSING, WSMsgType.CLOSED): - raise StopAsyncIteration - return msg - - def _cancel(self, exc: BaseException) -> None: - # web_protocol calls this from connection_lost - # or when the server is shutting down. - self._closing = True - self._cancel_heartbeat() - if self._reader is not None: - set_exception(self._reader, exc) diff --git a/venv/lib/python3.9/site-packages/aiohttp/worker.py b/venv/lib/python3.9/site-packages/aiohttp/worker.py deleted file mode 100644 index 00ec79c..0000000 --- a/venv/lib/python3.9/site-packages/aiohttp/worker.py +++ /dev/null @@ -1,262 +0,0 @@ -"""Async gunicorn worker for aiohttp.web""" - -import asyncio -import inspect -import os -import re -import signal -import sys -from types import FrameType -from typing import TYPE_CHECKING, Any, Optional - -from gunicorn.config import AccessLogFormat as GunicornAccessLogFormat -from gunicorn.workers import base - -from aiohttp import web - -from .helpers import set_result -from .web_app import Application -from .web_log import AccessLogger - -if TYPE_CHECKING: - import ssl - - SSLContext = ssl.SSLContext -else: - try: - import ssl - - SSLContext = ssl.SSLContext - except ImportError: # pragma: no cover - ssl = None # type: ignore[assignment] - SSLContext = object # type: ignore[misc,assignment] - - -__all__ = ("GunicornWebWorker", "GunicornUVLoopWebWorker") - - -class GunicornWebWorker(base.Worker): # type: ignore[misc,no-any-unimported] - DEFAULT_AIOHTTP_LOG_FORMAT = AccessLogger.LOG_FORMAT - DEFAULT_GUNICORN_LOG_FORMAT = GunicornAccessLogFormat.default - - def __init__(self, *args: Any, **kw: Any) -> None: # pragma: no cover - super().__init__(*args, **kw) - - self._task: Optional[asyncio.Task[None]] = None - self.exit_code = 0 - self._notify_waiter: Optional[asyncio.Future[bool]] = None - - def init_process(self) -> None: - # create new event_loop after fork - try: - asyncio.get_event_loop().close() - except RuntimeError: - # No loop was running - pass - - self.loop = asyncio.new_event_loop() - asyncio.set_event_loop(self.loop) - - super().init_process() - - def run(self) -> None: - self._task = self.loop.create_task(self._run()) - - try: # ignore all finalization problems - self.loop.run_until_complete(self._task) - except Exception: - self.log.exception("Exception in gunicorn worker") - self.loop.run_until_complete(self.loop.shutdown_asyncgens()) - self.loop.close() - - sys.exit(self.exit_code) - - async def _run(self) -> None: - runner = None - if isinstance(self.wsgi, Application): - app = self.wsgi - elif inspect.iscoroutinefunction(self.wsgi) or ( - sys.version_info < (3, 14) and asyncio.iscoroutinefunction(self.wsgi) - ): - wsgi = await self.wsgi() - if isinstance(wsgi, web.AppRunner): - runner = wsgi - app = runner.app - else: - app = wsgi - else: - raise RuntimeError( - "wsgi app should be either Application or " - "async function returning Application, got {}".format(self.wsgi) - ) - - if runner is None: - access_log = self.log.access_log if self.cfg.accesslog else None - runner = web.AppRunner( - app, - logger=self.log, - keepalive_timeout=self.cfg.keepalive, - access_log=access_log, - access_log_format=self._get_valid_log_format( - self.cfg.access_log_format - ), - shutdown_timeout=self.cfg.graceful_timeout / 100 * 95, - ) - await runner.setup() - - ctx = self._create_ssl_context(self.cfg) if self.cfg.is_ssl else None - - runner = runner - assert runner is not None - server = runner.server - assert server is not None - for sock in self.sockets: - site = web.SockSite( - runner, - sock, - ssl_context=ctx, - ) - await site.start() - - # If our parent changed then we shut down. - pid = os.getpid() - try: - while self.alive: # type: ignore[has-type] - self.notify() - - cnt = server.requests_count - if self.max_requests and cnt > self.max_requests: - self.alive = False - self.log.info("Max requests, shutting down: %s", self) - - elif pid == os.getpid() and self.ppid != os.getppid(): - self.alive = False - self.log.info("Parent changed, shutting down: %s", self) - else: - await self._wait_next_notify() - except BaseException: - pass - - await runner.cleanup() - - def _wait_next_notify(self) -> "asyncio.Future[bool]": - self._notify_waiter_done() - - loop = self.loop - assert loop is not None - self._notify_waiter = waiter = loop.create_future() - self.loop.call_later(1.0, self._notify_waiter_done, waiter) - - return waiter - - def _notify_waiter_done( - self, waiter: Optional["asyncio.Future[bool]"] = None - ) -> None: - if waiter is None: - waiter = self._notify_waiter - if waiter is not None: - set_result(waiter, True) - - if waiter is self._notify_waiter: - self._notify_waiter = None - - def init_signals(self) -> None: - # Set up signals through the event loop API. - - self.loop.add_signal_handler( - signal.SIGQUIT, self.handle_quit, signal.SIGQUIT, None - ) - - self.loop.add_signal_handler( - signal.SIGTERM, self.handle_exit, signal.SIGTERM, None - ) - - self.loop.add_signal_handler( - signal.SIGINT, self.handle_quit, signal.SIGINT, None - ) - - self.loop.add_signal_handler( - signal.SIGWINCH, self.handle_winch, signal.SIGWINCH, None - ) - - self.loop.add_signal_handler( - signal.SIGUSR1, self.handle_usr1, signal.SIGUSR1, None - ) - - self.loop.add_signal_handler( - signal.SIGABRT, self.handle_abort, signal.SIGABRT, None - ) - - # Don't let SIGTERM and SIGUSR1 disturb active requests - # by interrupting system calls - signal.siginterrupt(signal.SIGTERM, False) - signal.siginterrupt(signal.SIGUSR1, False) - # Reset signals so Gunicorn doesn't swallow subprocess return codes - # See: https://github.com/aio-libs/aiohttp/issues/6130 - - def handle_quit(self, sig: int, frame: Optional[FrameType]) -> None: - self.alive = False - - # worker_int callback - self.cfg.worker_int(self) - - # wakeup closing process - self._notify_waiter_done() - - def handle_abort(self, sig: int, frame: Optional[FrameType]) -> None: - self.alive = False - self.exit_code = 1 - self.cfg.worker_abort(self) - sys.exit(1) - - @staticmethod - def _create_ssl_context(cfg: Any) -> "SSLContext": - """Creates SSLContext instance for usage in asyncio.create_server. - - See ssl.SSLSocket.__init__ for more details. - """ - if ssl is None: # pragma: no cover - raise RuntimeError("SSL is not supported.") - - ctx = ssl.SSLContext(cfg.ssl_version) - ctx.load_cert_chain(cfg.certfile, cfg.keyfile) - ctx.verify_mode = cfg.cert_reqs - if cfg.ca_certs: - ctx.load_verify_locations(cfg.ca_certs) - if cfg.ciphers: - ctx.set_ciphers(cfg.ciphers) - return ctx - - def _get_valid_log_format(self, source_format: str) -> str: - if source_format == self.DEFAULT_GUNICORN_LOG_FORMAT: - return self.DEFAULT_AIOHTTP_LOG_FORMAT - elif re.search(r"%\([^\)]+\)", source_format): - raise ValueError( - "Gunicorn's style options in form of `%(name)s` are not " - "supported for the log formatting. Please use aiohttp's " - "format specification to configure access log formatting: " - "http://docs.aiohttp.org/en/stable/logging.html" - "#format-specification" - ) - else: - return source_format - - -class GunicornUVLoopWebWorker(GunicornWebWorker): - def init_process(self) -> None: - import uvloop - - # Close any existing event loop before setting a - # new policy. - try: - asyncio.get_event_loop().close() - except RuntimeError: - # No loop was running - pass - - # Setup uvloop policy, so that every - # asyncio.get_event_loop() will create an instance - # of uvloop event loop. - asyncio.set_event_loop_policy(uvloop.EventLoopPolicy()) - - super().init_process() diff --git a/venv/lib/python3.9/site-packages/aiosignal-1.4.0.dist-info/INSTALLER b/venv/lib/python3.9/site-packages/aiosignal-1.4.0.dist-info/INSTALLER deleted file mode 100644 index a1b589e..0000000 --- a/venv/lib/python3.9/site-packages/aiosignal-1.4.0.dist-info/INSTALLER +++ /dev/null @@ -1 +0,0 @@ -pip diff --git a/venv/lib/python3.9/site-packages/aiosignal-1.4.0.dist-info/METADATA b/venv/lib/python3.9/site-packages/aiosignal-1.4.0.dist-info/METADATA deleted file mode 100644 index 03a6f0f..0000000 --- a/venv/lib/python3.9/site-packages/aiosignal-1.4.0.dist-info/METADATA +++ /dev/null @@ -1,112 +0,0 @@ -Metadata-Version: 2.4 -Name: aiosignal -Version: 1.4.0 -Summary: aiosignal: a list of registered asynchronous callbacks -Home-page: https://github.com/aio-libs/aiosignal -Maintainer: aiohttp team -Maintainer-email: team@aiohttp.org -License: Apache 2.0 -Project-URL: Chat: Gitter, https://gitter.im/aio-libs/Lobby -Project-URL: CI: GitHub Actions, https://github.com/aio-libs/aiosignal/actions -Project-URL: Coverage: codecov, https://codecov.io/github/aio-libs/aiosignal -Project-URL: Docs: RTD, https://docs.aiosignal.org -Project-URL: GitHub: issues, https://github.com/aio-libs/aiosignal/issues -Project-URL: GitHub: repo, https://github.com/aio-libs/aiosignal -Classifier: License :: OSI Approved :: Apache Software License -Classifier: Intended Audience :: Developers -Classifier: Programming Language :: Python -Classifier: Programming Language :: Python :: 3 -Classifier: Programming Language :: Python :: 3 :: Only -Classifier: Development Status :: 5 - Production/Stable -Classifier: Operating System :: POSIX -Classifier: Operating System :: MacOS :: MacOS X -Classifier: Operating System :: Microsoft :: Windows -Classifier: Framework :: AsyncIO -Requires-Python: >=3.9 -Description-Content-Type: text/x-rst -License-File: LICENSE -Requires-Dist: frozenlist>=1.1.0 -Requires-Dist: typing-extensions>=4.2; python_version < "3.13" -Dynamic: license-file - -========= -aiosignal -========= - -.. image:: https://github.com/aio-libs/aiosignal/workflows/CI/badge.svg - :target: https://github.com/aio-libs/aiosignal/actions?query=workflow%3ACI - :alt: GitHub status for master branch - -.. image:: https://codecov.io/gh/aio-libs/aiosignal/branch/master/graph/badge.svg?flag=pytest - :target: https://codecov.io/gh/aio-libs/aiosignal?flags[0]=pytest - :alt: codecov.io status for master branch - -.. image:: https://badge.fury.io/py/aiosignal.svg - :target: https://pypi.org/project/aiosignal - :alt: Latest PyPI package version - -.. image:: https://readthedocs.org/projects/aiosignal/badge/?version=latest - :target: https://aiosignal.readthedocs.io/ - :alt: Latest Read The Docs - -.. image:: https://img.shields.io/discourse/topics?server=https%3A%2F%2Faio-libs.discourse.group%2F - :target: https://aio-libs.discourse.group/ - :alt: Discourse group for io-libs - -.. image:: https://badges.gitter.im/Join%20Chat.svg - :target: https://gitter.im/aio-libs/Lobby - :alt: Chat on Gitter - -Introduction -============ - -A project to manage callbacks in `asyncio` projects. - -``Signal`` is a list of registered asynchronous callbacks. - -The signal's life-cycle has two stages: after creation its content -could be filled by using standard list operations: ``sig.append()`` -etc. - -After you call ``sig.freeze()`` the signal is *frozen*: adding, removing -and dropping callbacks is forbidden. - -The only available operation is calling the previously registered -callbacks by using ``await sig.send(data)``. - -For concrete usage examples see the `Signals - -section of the `Web Server Advanced -` chapter of the `aiohttp -documentation`_. - - -Installation ------------- - -:: - - $ pip install aiosignal - - -Documentation -============= - -https://aiosignal.readthedocs.io/ - -License -======= - -``aiosignal`` is offered under the Apache 2 license. - -Source code -=========== - -The project is hosted on GitHub_ - -Please file an issue in the `bug tracker -`_ if you have found a bug -or have some suggestions to improve the library. - -.. _GitHub: https://github.com/aio-libs/aiosignal -.. _aiohttp documentation: https://docs.aiohttp.org/ diff --git a/venv/lib/python3.9/site-packages/aiosignal-1.4.0.dist-info/RECORD b/venv/lib/python3.9/site-packages/aiosignal-1.4.0.dist-info/RECORD deleted file mode 100644 index 816ef02..0000000 --- a/venv/lib/python3.9/site-packages/aiosignal-1.4.0.dist-info/RECORD +++ /dev/null @@ -1,9 +0,0 @@ -aiosignal-1.4.0.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 -aiosignal-1.4.0.dist-info/METADATA,sha256=CSR-8dqLxpZyjUcTDnAuQwf299EB1sSFv_nzpxznAI0,3662 -aiosignal-1.4.0.dist-info/RECORD,, -aiosignal-1.4.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91 -aiosignal-1.4.0.dist-info/licenses/LICENSE,sha256=b9UkPpLdf5jsacesN3co50kFcJ_1J6W_mNbQJjwE9bY,11332 -aiosignal-1.4.0.dist-info/top_level.txt,sha256=z45aNOKGDdrI1roqZY3BGXQ22kJFPHBmVdwtLYLtXC0,10 -aiosignal/__init__.py,sha256=TIkmUG9HTBt4dfq2nISYBiZiRB2xwvFtEZydLP0HPL4,1537 -aiosignal/__pycache__/__init__.cpython-39.pyc,, -aiosignal/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 diff --git a/venv/lib/python3.9/site-packages/aiosignal-1.4.0.dist-info/WHEEL b/venv/lib/python3.9/site-packages/aiosignal-1.4.0.dist-info/WHEEL deleted file mode 100644 index e7fa31b..0000000 --- a/venv/lib/python3.9/site-packages/aiosignal-1.4.0.dist-info/WHEEL +++ /dev/null @@ -1,5 +0,0 @@ -Wheel-Version: 1.0 -Generator: setuptools (80.9.0) -Root-Is-Purelib: true -Tag: py3-none-any - diff --git a/venv/lib/python3.9/site-packages/aiosignal-1.4.0.dist-info/licenses/LICENSE b/venv/lib/python3.9/site-packages/aiosignal-1.4.0.dist-info/licenses/LICENSE deleted file mode 100644 index 7082a2d..0000000 --- a/venv/lib/python3.9/site-packages/aiosignal-1.4.0.dist-info/licenses/LICENSE +++ /dev/null @@ -1,201 +0,0 @@ -Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "{}" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright 2013-2019 Nikolay Kim and Andrew Svetlov - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. diff --git a/venv/lib/python3.9/site-packages/aiosignal-1.4.0.dist-info/top_level.txt b/venv/lib/python3.9/site-packages/aiosignal-1.4.0.dist-info/top_level.txt deleted file mode 100644 index ac6df3a..0000000 --- a/venv/lib/python3.9/site-packages/aiosignal-1.4.0.dist-info/top_level.txt +++ /dev/null @@ -1 +0,0 @@ -aiosignal diff --git a/venv/lib/python3.9/site-packages/aiosignal/__init__.py b/venv/lib/python3.9/site-packages/aiosignal/__init__.py deleted file mode 100644 index 5ede009..0000000 --- a/venv/lib/python3.9/site-packages/aiosignal/__init__.py +++ /dev/null @@ -1,59 +0,0 @@ -import sys -from typing import Any, Awaitable, Callable, TypeVar - -from frozenlist import FrozenList - -if sys.version_info >= (3, 11): - from typing import Unpack -else: - from typing_extensions import Unpack - -if sys.version_info >= (3, 13): - from typing import TypeVarTuple -else: - from typing_extensions import TypeVarTuple - -_T = TypeVar("_T") -_Ts = TypeVarTuple("_Ts", default=Unpack[tuple[()]]) - -__version__ = "1.4.0" - -__all__ = ("Signal",) - - -class Signal(FrozenList[Callable[[Unpack[_Ts]], Awaitable[object]]]): - """Coroutine-based signal implementation. - - To connect a callback to a signal, use any list method. - - Signals are fired using the send() coroutine, which takes named - arguments. - """ - - __slots__ = ("_owner",) - - def __init__(self, owner: object): - super().__init__() - self._owner = owner - - def __repr__(self) -> str: - return "".format( - self._owner, self.frozen, list(self) - ) - - async def send(self, *args: Unpack[_Ts], **kwargs: Any) -> None: - """ - Sends data to all registered receivers. - """ - if not self.frozen: - raise RuntimeError("Cannot send non-frozen signal.") - - for receiver in self: - await receiver(*args, **kwargs) - - def __call__( - self, func: Callable[[Unpack[_Ts]], Awaitable[_T]] - ) -> Callable[[Unpack[_Ts]], Awaitable[_T]]: - """Decorator to add a function to this Signal.""" - self.append(func) - return func diff --git a/venv/lib/python3.9/site-packages/aiosignal/py.typed b/venv/lib/python3.9/site-packages/aiosignal/py.typed deleted file mode 100644 index e69de29..0000000 diff --git a/venv/lib/python3.9/site-packages/async_timeout-5.0.1.dist-info/INSTALLER b/venv/lib/python3.9/site-packages/async_timeout-5.0.1.dist-info/INSTALLER deleted file mode 100644 index a1b589e..0000000 --- a/venv/lib/python3.9/site-packages/async_timeout-5.0.1.dist-info/INSTALLER +++ /dev/null @@ -1 +0,0 @@ -pip diff --git a/venv/lib/python3.9/site-packages/async_timeout-5.0.1.dist-info/LICENSE b/venv/lib/python3.9/site-packages/async_timeout-5.0.1.dist-info/LICENSE deleted file mode 100644 index 033c86b..0000000 --- a/venv/lib/python3.9/site-packages/async_timeout-5.0.1.dist-info/LICENSE +++ /dev/null @@ -1,13 +0,0 @@ -Copyright 2016-2020 aio-libs collaboration. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. diff --git a/venv/lib/python3.9/site-packages/async_timeout-5.0.1.dist-info/METADATA b/venv/lib/python3.9/site-packages/async_timeout-5.0.1.dist-info/METADATA deleted file mode 100644 index 1eecd7d..0000000 --- a/venv/lib/python3.9/site-packages/async_timeout-5.0.1.dist-info/METADATA +++ /dev/null @@ -1,163 +0,0 @@ -Metadata-Version: 2.1 -Name: async-timeout -Version: 5.0.1 -Summary: Timeout context manager for asyncio programs -Home-page: https://github.com/aio-libs/async-timeout -Author: Andrew Svetlov -Author-email: andrew.svetlov@gmail.com -License: Apache 2 -Project-URL: Chat: Gitter, https://gitter.im/aio-libs/Lobby -Project-URL: CI: GitHub Actions, https://github.com/aio-libs/async-timeout/actions -Project-URL: Coverage: codecov, https://codecov.io/github/aio-libs/async-timeout -Project-URL: GitHub: issues, https://github.com/aio-libs/async-timeout/issues -Project-URL: GitHub: repo, https://github.com/aio-libs/async-timeout -Classifier: Development Status :: 5 - Production/Stable -Classifier: Topic :: Software Development :: Libraries -Classifier: Framework :: AsyncIO -Classifier: Intended Audience :: Developers -Classifier: License :: OSI Approved :: Apache Software License -Classifier: Programming Language :: Python -Classifier: Programming Language :: Python :: 3 -Classifier: Programming Language :: Python :: 3 :: Only -Requires-Python: >=3.8 -Description-Content-Type: text/x-rst -License-File: LICENSE - -async-timeout -============= -.. image:: https://travis-ci.com/aio-libs/async-timeout.svg?branch=master - :target: https://travis-ci.com/aio-libs/async-timeout -.. image:: https://codecov.io/gh/aio-libs/async-timeout/branch/master/graph/badge.svg - :target: https://codecov.io/gh/aio-libs/async-timeout -.. image:: https://img.shields.io/pypi/v/async-timeout.svg - :target: https://pypi.python.org/pypi/async-timeout -.. image:: https://badges.gitter.im/Join%20Chat.svg - :target: https://gitter.im/aio-libs/Lobby - :alt: Chat on Gitter - -asyncio-compatible timeout context manager. - - - -DEPRECATED ----------- - -This library has effectively been upstreamed into Python 3.11+. - -Therefore this library is considered deprecated and no longer actively supported. - -Version 5.0+ provides dual-mode when executed on Python 3.11+: -``asyncio_timeout.Timeout`` is fully compatible with ``asyncio.Timeout`` *and* old -versions of the library. - -Anyway, using upstream is highly recommended. ``asyncio_timeout`` exists only for the -sake of backward compatibility, easy supporting both old and new Python by the same -code, and easy misgration. - -If rescheduling API is not important and only ``async with timeout(...): ...`` functionality is required, -a user could apply conditional import:: - - if sys.version_info >= (3, 11): - from asyncio import timeout, timeout_at - else: - from async_timeout import timeout, timeout_at - - -Usage example -------------- - - -The context manager is useful in cases when you want to apply timeout -logic around block of code or in cases when ``asyncio.wait_for()`` is -not suitable. Also it's much faster than ``asyncio.wait_for()`` -because ``timeout`` doesn't create a new task. - -The ``timeout(delay, *, loop=None)`` call returns a context manager -that cancels a block on *timeout* expiring:: - - from async_timeout import timeout - async with timeout(1.5): - await inner() - -1. If ``inner()`` is executed faster than in ``1.5`` seconds nothing - happens. -2. Otherwise ``inner()`` is cancelled internally by sending - ``asyncio.CancelledError`` into but ``asyncio.TimeoutError`` is - raised outside of context manager scope. - -*timeout* parameter could be ``None`` for skipping timeout functionality. - - -Alternatively, ``timeout_at(when)`` can be used for scheduling -at the absolute time:: - - loop = asyncio.get_event_loop() - now = loop.time() - - async with timeout_at(now + 1.5): - await inner() - - -Please note: it is not POSIX time but a time with -undefined starting base, e.g. the time of the system power on. - - -Context manager has ``.expired()`` / ``.expired`` for check if timeout happens -exactly in context manager:: - - async with timeout(1.5) as cm: - await inner() - print(cm.expired()) # recommended api - print(cm.expired) # compatible api - -The property is ``True`` if ``inner()`` execution is cancelled by -timeout context manager. - -If ``inner()`` call explicitly raises ``TimeoutError`` ``cm.expired`` -is ``False``. - -The scheduled deadline time is available as ``.when()`` / ``.deadline``:: - - async with timeout(1.5) as cm: - cm.when() # recommended api - cm.deadline # compatible api - -Not finished yet timeout can be rescheduled by ``shift()`` -or ``update()`` methods:: - - async with timeout(1.5) as cm: - # recommended api - cm.reschedule(cm.when() + 1) # add another second on waiting - # compatible api - cm.shift(1) # add another second on waiting - cm.update(loop.time() + 5) # reschedule to now+5 seconds - -Rescheduling is forbidden if the timeout is expired or after exit from ``async with`` -code block. - - -Disable scheduled timeout:: - - async with timeout(1.5) as cm: - cm.reschedule(None) # recommended api - cm.reject() # compatible api - - - -Installation ------------- - -:: - - $ pip install async-timeout - -The library is Python 3 only! - - - -Authors and License -------------------- - -The module is written by Andrew Svetlov. - -It's *Apache 2* licensed and freely available. diff --git a/venv/lib/python3.9/site-packages/async_timeout-5.0.1.dist-info/RECORD b/venv/lib/python3.9/site-packages/async_timeout-5.0.1.dist-info/RECORD deleted file mode 100644 index 3dc7e73..0000000 --- a/venv/lib/python3.9/site-packages/async_timeout-5.0.1.dist-info/RECORD +++ /dev/null @@ -1,10 +0,0 @@ -async_timeout-5.0.1.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 -async_timeout-5.0.1.dist-info/LICENSE,sha256=4Y17uPUT4sRrtYXJS1hb0wcg3TzLId2weG9y0WZY-Sw,568 -async_timeout-5.0.1.dist-info/METADATA,sha256=RVDNEIPYIBJKPsjThJDaKRX1h79-4QYQNuBLSXPItU8,5131 -async_timeout-5.0.1.dist-info/RECORD,, -async_timeout-5.0.1.dist-info/WHEEL,sha256=P9jw-gEje8ByB7_hXoICnHtVCrEwMQh-630tKvQWehc,91 -async_timeout-5.0.1.dist-info/top_level.txt,sha256=9oM4e7Twq8iD_7_Q3Mz0E6GPIB6vJvRFo-UBwUQtBDU,14 -async_timeout-5.0.1.dist-info/zip-safe,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-YBdrKVGs,1 -async_timeout/__init__.py,sha256=QF0zpfX1vGmxib7kAqNPm9YehPV0oBVozxJ--Mxq9dI,9186 -async_timeout/__pycache__/__init__.cpython-39.pyc,, -async_timeout/py.typed,sha256=tyozzRT1fziXETDxokmuyt6jhOmtjUbnVNJdZcG7ik0,12 diff --git a/venv/lib/python3.9/site-packages/async_timeout-5.0.1.dist-info/WHEEL b/venv/lib/python3.9/site-packages/async_timeout-5.0.1.dist-info/WHEEL deleted file mode 100644 index 9b78c44..0000000 --- a/venv/lib/python3.9/site-packages/async_timeout-5.0.1.dist-info/WHEEL +++ /dev/null @@ -1,5 +0,0 @@ -Wheel-Version: 1.0 -Generator: setuptools (75.3.0) -Root-Is-Purelib: true -Tag: py3-none-any - diff --git a/venv/lib/python3.9/site-packages/async_timeout-5.0.1.dist-info/top_level.txt b/venv/lib/python3.9/site-packages/async_timeout-5.0.1.dist-info/top_level.txt deleted file mode 100644 index ad29955..0000000 --- a/venv/lib/python3.9/site-packages/async_timeout-5.0.1.dist-info/top_level.txt +++ /dev/null @@ -1 +0,0 @@ -async_timeout diff --git a/venv/lib/python3.9/site-packages/async_timeout-5.0.1.dist-info/zip-safe b/venv/lib/python3.9/site-packages/async_timeout-5.0.1.dist-info/zip-safe deleted file mode 100644 index 8b13789..0000000 --- a/venv/lib/python3.9/site-packages/async_timeout-5.0.1.dist-info/zip-safe +++ /dev/null @@ -1 +0,0 @@ - diff --git a/venv/lib/python3.9/site-packages/async_timeout/__init__.py b/venv/lib/python3.9/site-packages/async_timeout/__init__.py deleted file mode 100644 index fe4aa58..0000000 --- a/venv/lib/python3.9/site-packages/async_timeout/__init__.py +++ /dev/null @@ -1,276 +0,0 @@ -import asyncio -import enum -import sys -from types import TracebackType -from typing import Optional, Type, final - - -__version__ = "5.0.1" - - -__all__ = ("timeout", "timeout_at", "Timeout") - - -def timeout(delay: Optional[float]) -> "Timeout": - """timeout context manager. - - Useful in cases when you want to apply timeout logic around block - of code or in cases when asyncio.wait_for is not suitable. For example: - - >>> async with timeout(0.001): - ... async with aiohttp.get('https://github.com') as r: - ... await r.text() - - - delay - value in seconds or None to disable timeout logic - """ - loop = asyncio.get_running_loop() - if delay is not None: - deadline = loop.time() + delay # type: Optional[float] - else: - deadline = None - return Timeout(deadline, loop) - - -def timeout_at(deadline: Optional[float]) -> "Timeout": - """Schedule the timeout at absolute time. - - deadline argument points on the time in the same clock system - as loop.time(). - - Please note: it is not POSIX time but a time with - undefined starting base, e.g. the time of the system power on. - - >>> async with timeout_at(loop.time() + 10): - ... async with aiohttp.get('https://github.com') as r: - ... await r.text() - - - """ - loop = asyncio.get_running_loop() - return Timeout(deadline, loop) - - -class _State(enum.Enum): - INIT = "INIT" - ENTER = "ENTER" - TIMEOUT = "TIMEOUT" - EXIT = "EXIT" - - -if sys.version_info >= (3, 11): - - class _Expired: - __slots__ = ("_val",) - - def __init__(self, val: bool) -> None: - self._val = val - - def __call__(self) -> bool: - return self._val - - def __bool__(self) -> bool: - return self._val - - def __repr__(self) -> str: - return repr(self._val) - - def __str__(self) -> str: - return str(self._val) - - @final - class Timeout(asyncio.Timeout): # type: ignore[misc] - # Supports full asyncio.Timeout API. - # Also provides several asyncio_timeout specific methods - # for backward compatibility. - def __init__( - self, deadline: Optional[float], loop: asyncio.AbstractEventLoop - ) -> None: - super().__init__(deadline) - - @property - def expired(self) -> _Expired: - # a hacky property hat can provide both roles: - # timeout.expired() from asyncio - # timeout.expired from asyncio_timeout - return _Expired(super().expired()) - - @property - def deadline(self) -> Optional[float]: - return self.when() - - def reject(self) -> None: - """Reject scheduled timeout if any.""" - # cancel is maybe better name but - # task.cancel() raises CancelledError in asyncio world. - self.reschedule(None) - - def shift(self, delay: float) -> None: - """Advance timeout on delay seconds. - - The delay can be negative. - - Raise RuntimeError if shift is called when deadline is not scheduled - """ - deadline = self.when() - if deadline is None: - raise RuntimeError("cannot shift timeout if deadline is not scheduled") - self.reschedule(deadline + delay) - - def update(self, deadline: float) -> None: - """Set deadline to absolute value. - - deadline argument points on the time in the same clock system - as loop.time(). - - If new deadline is in the past the timeout is raised immediately. - - Please note: it is not POSIX time but a time with - undefined starting base, e.g. the time of the system power on. - """ - self.reschedule(deadline) - -else: - - @final - class Timeout: - # Internal class, please don't instantiate it directly - # Use timeout() and timeout_at() public factories instead. - # - # Implementation note: `async with timeout()` is preferred - # over `with timeout()`. - # While technically the Timeout class implementation - # doesn't need to be async at all, - # the `async with` statement explicitly points that - # the context manager should be used from async function context. - # - # This design allows to avoid many silly misusages. - # - # TimeoutError is raised immediately when scheduled - # if the deadline is passed. - # The purpose is to time out as soon as possible - # without waiting for the next await expression. - - __slots__ = ("_deadline", "_loop", "_state", "_timeout_handler", "_task") - - def __init__( - self, deadline: Optional[float], loop: asyncio.AbstractEventLoop - ) -> None: - self._loop = loop - self._state = _State.INIT - - self._task: Optional["asyncio.Task[object]"] = None - self._timeout_handler = None # type: Optional[asyncio.Handle] - if deadline is None: - self._deadline = None # type: Optional[float] - else: - self.update(deadline) - - async def __aenter__(self) -> "Timeout": - self._do_enter() - return self - - async def __aexit__( - self, - exc_type: Optional[Type[BaseException]], - exc_val: Optional[BaseException], - exc_tb: Optional[TracebackType], - ) -> Optional[bool]: - self._do_exit(exc_type) - return None - - @property - def expired(self) -> bool: - """Is timeout expired during execution?""" - return self._state == _State.TIMEOUT - - @property - def deadline(self) -> Optional[float]: - return self._deadline - - def reject(self) -> None: - """Reject scheduled timeout if any.""" - # cancel is maybe better name but - # task.cancel() raises CancelledError in asyncio world. - if self._state not in (_State.INIT, _State.ENTER): - raise RuntimeError(f"invalid state {self._state.value}") - self._reject() - - def _reject(self) -> None: - self._task = None - if self._timeout_handler is not None: - self._timeout_handler.cancel() - self._timeout_handler = None - - def shift(self, delay: float) -> None: - """Advance timeout on delay seconds. - - The delay can be negative. - - Raise RuntimeError if shift is called when deadline is not scheduled - """ - deadline = self._deadline - if deadline is None: - raise RuntimeError("cannot shift timeout if deadline is not scheduled") - self.update(deadline + delay) - - def update(self, deadline: float) -> None: - """Set deadline to absolute value. - - deadline argument points on the time in the same clock system - as loop.time(). - - If new deadline is in the past the timeout is raised immediately. - - Please note: it is not POSIX time but a time with - undefined starting base, e.g. the time of the system power on. - """ - if self._state == _State.EXIT: - raise RuntimeError("cannot reschedule after exit from context manager") - if self._state == _State.TIMEOUT: - raise RuntimeError("cannot reschedule expired timeout") - if self._timeout_handler is not None: - self._timeout_handler.cancel() - self._deadline = deadline - if self._state != _State.INIT: - self._reschedule() - - def _reschedule(self) -> None: - assert self._state == _State.ENTER - deadline = self._deadline - if deadline is None: - return - - now = self._loop.time() - if self._timeout_handler is not None: - self._timeout_handler.cancel() - - self._task = asyncio.current_task() - if deadline <= now: - self._timeout_handler = self._loop.call_soon(self._on_timeout) - else: - self._timeout_handler = self._loop.call_at(deadline, self._on_timeout) - - def _do_enter(self) -> None: - if self._state != _State.INIT: - raise RuntimeError(f"invalid state {self._state.value}") - self._state = _State.ENTER - self._reschedule() - - def _do_exit(self, exc_type: Optional[Type[BaseException]]) -> None: - if exc_type is asyncio.CancelledError and self._state == _State.TIMEOUT: - assert self._task is not None - self._timeout_handler = None - self._task = None - raise asyncio.TimeoutError - # timeout has not expired - self._state = _State.EXIT - self._reject() - return None - - def _on_timeout(self) -> None: - assert self._task is not None - self._task.cancel() - self._state = _State.TIMEOUT - # drop the reference early - self._timeout_handler = None diff --git a/venv/lib/python3.9/site-packages/async_timeout/py.typed b/venv/lib/python3.9/site-packages/async_timeout/py.typed deleted file mode 100644 index 3b94f91..0000000 --- a/venv/lib/python3.9/site-packages/async_timeout/py.typed +++ /dev/null @@ -1 +0,0 @@ -Placeholder diff --git a/venv/lib/python3.9/site-packages/attr/__init__.py b/venv/lib/python3.9/site-packages/attr/__init__.py deleted file mode 100644 index 5c6e065..0000000 --- a/venv/lib/python3.9/site-packages/attr/__init__.py +++ /dev/null @@ -1,104 +0,0 @@ -# SPDX-License-Identifier: MIT - -""" -Classes Without Boilerplate -""" - -from functools import partial -from typing import Callable, Literal, Protocol - -from . import converters, exceptions, filters, setters, validators -from ._cmp import cmp_using -from ._config import get_run_validators, set_run_validators -from ._funcs import asdict, assoc, astuple, has, resolve_types -from ._make import ( - NOTHING, - Attribute, - Converter, - Factory, - _Nothing, - attrib, - attrs, - evolve, - fields, - fields_dict, - make_class, - validate, -) -from ._next_gen import define, field, frozen, mutable -from ._version_info import VersionInfo - - -s = attributes = attrs -ib = attr = attrib -dataclass = partial(attrs, auto_attribs=True) # happy Easter ;) - - -class AttrsInstance(Protocol): - pass - - -NothingType = Literal[_Nothing.NOTHING] - -__all__ = [ - "NOTHING", - "Attribute", - "AttrsInstance", - "Converter", - "Factory", - "NothingType", - "asdict", - "assoc", - "astuple", - "attr", - "attrib", - "attributes", - "attrs", - "cmp_using", - "converters", - "define", - "evolve", - "exceptions", - "field", - "fields", - "fields_dict", - "filters", - "frozen", - "get_run_validators", - "has", - "ib", - "make_class", - "mutable", - "resolve_types", - "s", - "set_run_validators", - "setters", - "validate", - "validators", -] - - -def _make_getattr(mod_name: str) -> Callable: - """ - Create a metadata proxy for packaging information that uses *mod_name* in - its warnings and errors. - """ - - def __getattr__(name: str) -> str: - if name not in ("__version__", "__version_info__"): - msg = f"module {mod_name} has no attribute {name}" - raise AttributeError(msg) - - from importlib.metadata import metadata - - meta = metadata("attrs") - - if name == "__version_info__": - return VersionInfo._from_version_string(meta["version"]) - - return meta["version"] - - return __getattr__ - - -__getattr__ = _make_getattr(__name__) diff --git a/venv/lib/python3.9/site-packages/attr/__init__.pyi b/venv/lib/python3.9/site-packages/attr/__init__.pyi deleted file mode 100644 index 758decf..0000000 --- a/venv/lib/python3.9/site-packages/attr/__init__.pyi +++ /dev/null @@ -1,389 +0,0 @@ -import enum -import sys - -from typing import ( - Any, - Callable, - Generic, - Literal, - Mapping, - Protocol, - Sequence, - TypeVar, - overload, -) - -# `import X as X` is required to make these public -from . import converters as converters -from . import exceptions as exceptions -from . import filters as filters -from . import setters as setters -from . import validators as validators -from ._cmp import cmp_using as cmp_using -from ._typing_compat import AttrsInstance_ -from ._version_info import VersionInfo -from attrs import ( - define as define, - field as field, - mutable as mutable, - frozen as frozen, - _EqOrderType, - _ValidatorType, - _ConverterType, - _ReprArgType, - _OnSetAttrType, - _OnSetAttrArgType, - _FieldTransformer, - _ValidatorArgType, -) - -if sys.version_info >= (3, 10): - from typing import TypeGuard, TypeAlias -else: - from typing_extensions import TypeGuard, TypeAlias - -if sys.version_info >= (3, 11): - from typing import dataclass_transform -else: - from typing_extensions import dataclass_transform - -__version__: str -__version_info__: VersionInfo -__title__: str -__description__: str -__url__: str -__uri__: str -__author__: str -__email__: str -__license__: str -__copyright__: str - -_T = TypeVar("_T") -_C = TypeVar("_C", bound=type) - -_FilterType = Callable[["Attribute[_T]", _T], bool] - -# We subclass this here to keep the protocol's qualified name clean. -class AttrsInstance(AttrsInstance_, Protocol): - pass - -_A = TypeVar("_A", bound=type[AttrsInstance]) - -class _Nothing(enum.Enum): - NOTHING = enum.auto() - -NOTHING = _Nothing.NOTHING -NothingType: TypeAlias = Literal[_Nothing.NOTHING] - -# NOTE: Factory lies about its return type to make this possible: -# `x: List[int] # = Factory(list)` -# Work around mypy issue #4554 in the common case by using an overload. - -@overload -def Factory(factory: Callable[[], _T]) -> _T: ... -@overload -def Factory( - factory: Callable[[Any], _T], - takes_self: Literal[True], -) -> _T: ... -@overload -def Factory( - factory: Callable[[], _T], - takes_self: Literal[False], -) -> _T: ... - -In = TypeVar("In") -Out = TypeVar("Out") - -class Converter(Generic[In, Out]): - @overload - def __init__(self, converter: Callable[[In], Out]) -> None: ... - @overload - def __init__( - self, - converter: Callable[[In, AttrsInstance, Attribute], Out], - *, - takes_self: Literal[True], - takes_field: Literal[True], - ) -> None: ... - @overload - def __init__( - self, - converter: Callable[[In, Attribute], Out], - *, - takes_field: Literal[True], - ) -> None: ... - @overload - def __init__( - self, - converter: Callable[[In, AttrsInstance], Out], - *, - takes_self: Literal[True], - ) -> None: ... - -class Attribute(Generic[_T]): - name: str - default: _T | None - validator: _ValidatorType[_T] | None - repr: _ReprArgType - cmp: _EqOrderType - eq: _EqOrderType - order: _EqOrderType - hash: bool | None - init: bool - converter: Converter | None - metadata: dict[Any, Any] - type: type[_T] | None - kw_only: bool - on_setattr: _OnSetAttrType - alias: str | None - - def evolve(self, **changes: Any) -> "Attribute[Any]": ... - -# NOTE: We had several choices for the annotation to use for type arg: -# 1) Type[_T] -# - Pros: Handles simple cases correctly -# - Cons: Might produce less informative errors in the case of conflicting -# TypeVars e.g. `attr.ib(default='bad', type=int)` -# 2) Callable[..., _T] -# - Pros: Better error messages than #1 for conflicting TypeVars -# - Cons: Terrible error messages for validator checks. -# e.g. attr.ib(type=int, validator=validate_str) -# -> error: Cannot infer function type argument -# 3) type (and do all of the work in the mypy plugin) -# - Pros: Simple here, and we could customize the plugin with our own errors. -# - Cons: Would need to write mypy plugin code to handle all the cases. -# We chose option #1. - -# `attr` lies about its return type to make the following possible: -# attr() -> Any -# attr(8) -> int -# attr(validator=) -> Whatever the callable expects. -# This makes this type of assignments possible: -# x: int = attr(8) -# -# This form catches explicit None or no default but with no other arguments -# returns Any. -@overload -def attrib( - default: None = ..., - validator: None = ..., - repr: _ReprArgType = ..., - cmp: _EqOrderType | None = ..., - hash: bool | None = ..., - init: bool = ..., - metadata: Mapping[Any, Any] | None = ..., - type: None = ..., - converter: None = ..., - factory: None = ..., - kw_only: bool | None = ..., - eq: _EqOrderType | None = ..., - order: _EqOrderType | None = ..., - on_setattr: _OnSetAttrArgType | None = ..., - alias: str | None = ..., -) -> Any: ... - -# This form catches an explicit None or no default and infers the type from the -# other arguments. -@overload -def attrib( - default: None = ..., - validator: _ValidatorArgType[_T] | None = ..., - repr: _ReprArgType = ..., - cmp: _EqOrderType | None = ..., - hash: bool | None = ..., - init: bool = ..., - metadata: Mapping[Any, Any] | None = ..., - type: type[_T] | None = ..., - converter: _ConverterType - | list[_ConverterType] - | tuple[_ConverterType] - | None = ..., - factory: Callable[[], _T] | None = ..., - kw_only: bool | None = ..., - eq: _EqOrderType | None = ..., - order: _EqOrderType | None = ..., - on_setattr: _OnSetAttrArgType | None = ..., - alias: str | None = ..., -) -> _T: ... - -# This form catches an explicit default argument. -@overload -def attrib( - default: _T, - validator: _ValidatorArgType[_T] | None = ..., - repr: _ReprArgType = ..., - cmp: _EqOrderType | None = ..., - hash: bool | None = ..., - init: bool = ..., - metadata: Mapping[Any, Any] | None = ..., - type: type[_T] | None = ..., - converter: _ConverterType - | list[_ConverterType] - | tuple[_ConverterType] - | None = ..., - factory: Callable[[], _T] | None = ..., - kw_only: bool | None = ..., - eq: _EqOrderType | None = ..., - order: _EqOrderType | None = ..., - on_setattr: _OnSetAttrArgType | None = ..., - alias: str | None = ..., -) -> _T: ... - -# This form covers type=non-Type: e.g. forward references (str), Any -@overload -def attrib( - default: _T | None = ..., - validator: _ValidatorArgType[_T] | None = ..., - repr: _ReprArgType = ..., - cmp: _EqOrderType | None = ..., - hash: bool | None = ..., - init: bool = ..., - metadata: Mapping[Any, Any] | None = ..., - type: object = ..., - converter: _ConverterType - | list[_ConverterType] - | tuple[_ConverterType] - | None = ..., - factory: Callable[[], _T] | None = ..., - kw_only: bool | None = ..., - eq: _EqOrderType | None = ..., - order: _EqOrderType | None = ..., - on_setattr: _OnSetAttrArgType | None = ..., - alias: str | None = ..., -) -> Any: ... -@overload -@dataclass_transform(order_default=True, field_specifiers=(attrib, field)) -def attrs( - maybe_cls: _C, - these: dict[str, Any] | None = ..., - repr_ns: str | None = ..., - repr: bool = ..., - cmp: _EqOrderType | None = ..., - hash: bool | None = ..., - init: bool = ..., - slots: bool = ..., - frozen: bool = ..., - weakref_slot: bool = ..., - str: bool = ..., - auto_attribs: bool = ..., - kw_only: bool = ..., - cache_hash: bool = ..., - auto_exc: bool = ..., - eq: _EqOrderType | None = ..., - order: _EqOrderType | None = ..., - auto_detect: bool = ..., - collect_by_mro: bool = ..., - getstate_setstate: bool | None = ..., - on_setattr: _OnSetAttrArgType | None = ..., - field_transformer: _FieldTransformer | None = ..., - match_args: bool = ..., - unsafe_hash: bool | None = ..., -) -> _C: ... -@overload -@dataclass_transform(order_default=True, field_specifiers=(attrib, field)) -def attrs( - maybe_cls: None = ..., - these: dict[str, Any] | None = ..., - repr_ns: str | None = ..., - repr: bool = ..., - cmp: _EqOrderType | None = ..., - hash: bool | None = ..., - init: bool = ..., - slots: bool = ..., - frozen: bool = ..., - weakref_slot: bool = ..., - str: bool = ..., - auto_attribs: bool = ..., - kw_only: bool = ..., - cache_hash: bool = ..., - auto_exc: bool = ..., - eq: _EqOrderType | None = ..., - order: _EqOrderType | None = ..., - auto_detect: bool = ..., - collect_by_mro: bool = ..., - getstate_setstate: bool | None = ..., - on_setattr: _OnSetAttrArgType | None = ..., - field_transformer: _FieldTransformer | None = ..., - match_args: bool = ..., - unsafe_hash: bool | None = ..., -) -> Callable[[_C], _C]: ... -def fields(cls: type[AttrsInstance] | AttrsInstance) -> Any: ... -def fields_dict(cls: type[AttrsInstance]) -> dict[str, Attribute[Any]]: ... -def validate(inst: AttrsInstance) -> None: ... -def resolve_types( - cls: _A, - globalns: dict[str, Any] | None = ..., - localns: dict[str, Any] | None = ..., - attribs: list[Attribute[Any]] | None = ..., - include_extras: bool = ..., -) -> _A: ... - -# TODO: add support for returning a proper attrs class from the mypy plugin -# we use Any instead of _CountingAttr so that e.g. `make_class('Foo', -# [attr.ib()])` is valid -def make_class( - name: str, - attrs: list[str] | tuple[str, ...] | dict[str, Any], - bases: tuple[type, ...] = ..., - class_body: dict[str, Any] | None = ..., - repr_ns: str | None = ..., - repr: bool = ..., - cmp: _EqOrderType | None = ..., - hash: bool | None = ..., - init: bool = ..., - slots: bool = ..., - frozen: bool = ..., - weakref_slot: bool = ..., - str: bool = ..., - auto_attribs: bool = ..., - kw_only: bool = ..., - cache_hash: bool = ..., - auto_exc: bool = ..., - eq: _EqOrderType | None = ..., - order: _EqOrderType | None = ..., - collect_by_mro: bool = ..., - on_setattr: _OnSetAttrArgType | None = ..., - field_transformer: _FieldTransformer | None = ..., -) -> type: ... - -# _funcs -- - -# TODO: add support for returning TypedDict from the mypy plugin -# FIXME: asdict/astuple do not honor their factory args. Waiting on one of -# these: -# https://github.com/python/mypy/issues/4236 -# https://github.com/python/typing/issues/253 -# XXX: remember to fix attrs.asdict/astuple too! -def asdict( - inst: AttrsInstance, - recurse: bool = ..., - filter: _FilterType[Any] | None = ..., - dict_factory: type[Mapping[Any, Any]] = ..., - retain_collection_types: bool = ..., - value_serializer: Callable[[type, Attribute[Any], Any], Any] | None = ..., - tuple_keys: bool | None = ..., -) -> dict[str, Any]: ... - -# TODO: add support for returning NamedTuple from the mypy plugin -def astuple( - inst: AttrsInstance, - recurse: bool = ..., - filter: _FilterType[Any] | None = ..., - tuple_factory: type[Sequence[Any]] = ..., - retain_collection_types: bool = ..., -) -> tuple[Any, ...]: ... -def has(cls: type) -> TypeGuard[type[AttrsInstance]]: ... -def assoc(inst: _T, **changes: Any) -> _T: ... -def evolve(inst: _T, **changes: Any) -> _T: ... - -# _config -- - -def set_run_validators(run: bool) -> None: ... -def get_run_validators() -> bool: ... - -# aliases -- - -s = attributes = attrs -ib = attr = attrib -dataclass = attrs # Technically, partial(attrs, auto_attribs=True) ;) diff --git a/venv/lib/python3.9/site-packages/attr/_cmp.py b/venv/lib/python3.9/site-packages/attr/_cmp.py deleted file mode 100644 index 09bab49..0000000 --- a/venv/lib/python3.9/site-packages/attr/_cmp.py +++ /dev/null @@ -1,160 +0,0 @@ -# SPDX-License-Identifier: MIT - - -import functools -import types - -from ._make import __ne__ - - -_operation_names = {"eq": "==", "lt": "<", "le": "<=", "gt": ">", "ge": ">="} - - -def cmp_using( - eq=None, - lt=None, - le=None, - gt=None, - ge=None, - require_same_type=True, - class_name="Comparable", -): - """ - Create a class that can be passed into `attrs.field`'s ``eq``, ``order``, - and ``cmp`` arguments to customize field comparison. - - The resulting class will have a full set of ordering methods if at least - one of ``{lt, le, gt, ge}`` and ``eq`` are provided. - - Args: - eq (typing.Callable | None): - Callable used to evaluate equality of two objects. - - lt (typing.Callable | None): - Callable used to evaluate whether one object is less than another - object. - - le (typing.Callable | None): - Callable used to evaluate whether one object is less than or equal - to another object. - - gt (typing.Callable | None): - Callable used to evaluate whether one object is greater than - another object. - - ge (typing.Callable | None): - Callable used to evaluate whether one object is greater than or - equal to another object. - - require_same_type (bool): - When `True`, equality and ordering methods will return - `NotImplemented` if objects are not of the same type. - - class_name (str | None): Name of class. Defaults to "Comparable". - - See `comparison` for more details. - - .. versionadded:: 21.1.0 - """ - - body = { - "__slots__": ["value"], - "__init__": _make_init(), - "_requirements": [], - "_is_comparable_to": _is_comparable_to, - } - - # Add operations. - num_order_functions = 0 - has_eq_function = False - - if eq is not None: - has_eq_function = True - body["__eq__"] = _make_operator("eq", eq) - body["__ne__"] = __ne__ - - if lt is not None: - num_order_functions += 1 - body["__lt__"] = _make_operator("lt", lt) - - if le is not None: - num_order_functions += 1 - body["__le__"] = _make_operator("le", le) - - if gt is not None: - num_order_functions += 1 - body["__gt__"] = _make_operator("gt", gt) - - if ge is not None: - num_order_functions += 1 - body["__ge__"] = _make_operator("ge", ge) - - type_ = types.new_class( - class_name, (object,), {}, lambda ns: ns.update(body) - ) - - # Add same type requirement. - if require_same_type: - type_._requirements.append(_check_same_type) - - # Add total ordering if at least one operation was defined. - if 0 < num_order_functions < 4: - if not has_eq_function: - # functools.total_ordering requires __eq__ to be defined, - # so raise early error here to keep a nice stack. - msg = "eq must be define is order to complete ordering from lt, le, gt, ge." - raise ValueError(msg) - type_ = functools.total_ordering(type_) - - return type_ - - -def _make_init(): - """ - Create __init__ method. - """ - - def __init__(self, value): - """ - Initialize object with *value*. - """ - self.value = value - - return __init__ - - -def _make_operator(name, func): - """ - Create operator method. - """ - - def method(self, other): - if not self._is_comparable_to(other): - return NotImplemented - - result = func(self.value, other.value) - if result is NotImplemented: - return NotImplemented - - return result - - method.__name__ = f"__{name}__" - method.__doc__ = ( - f"Return a {_operation_names[name]} b. Computed by attrs." - ) - - return method - - -def _is_comparable_to(self, other): - """ - Check whether `other` is comparable to `self`. - """ - return all(func(self, other) for func in self._requirements) - - -def _check_same_type(self, other): - """ - Return True if *self* and *other* are of the same type, False otherwise. - """ - return other.value.__class__ is self.value.__class__ diff --git a/venv/lib/python3.9/site-packages/attr/_cmp.pyi b/venv/lib/python3.9/site-packages/attr/_cmp.pyi deleted file mode 100644 index cc7893b..0000000 --- a/venv/lib/python3.9/site-packages/attr/_cmp.pyi +++ /dev/null @@ -1,13 +0,0 @@ -from typing import Any, Callable - -_CompareWithType = Callable[[Any, Any], bool] - -def cmp_using( - eq: _CompareWithType | None = ..., - lt: _CompareWithType | None = ..., - le: _CompareWithType | None = ..., - gt: _CompareWithType | None = ..., - ge: _CompareWithType | None = ..., - require_same_type: bool = ..., - class_name: str = ..., -) -> type: ... diff --git a/venv/lib/python3.9/site-packages/attr/_compat.py b/venv/lib/python3.9/site-packages/attr/_compat.py deleted file mode 100644 index bc68ed9..0000000 --- a/venv/lib/python3.9/site-packages/attr/_compat.py +++ /dev/null @@ -1,99 +0,0 @@ -# SPDX-License-Identifier: MIT - -import inspect -import platform -import sys -import threading - -from collections.abc import Mapping, Sequence # noqa: F401 -from typing import _GenericAlias - - -PYPY = platform.python_implementation() == "PyPy" -PY_3_10_PLUS = sys.version_info[:2] >= (3, 10) -PY_3_11_PLUS = sys.version_info[:2] >= (3, 11) -PY_3_12_PLUS = sys.version_info[:2] >= (3, 12) -PY_3_13_PLUS = sys.version_info[:2] >= (3, 13) -PY_3_14_PLUS = sys.version_info[:2] >= (3, 14) - - -if PY_3_14_PLUS: - import annotationlib - - # We request forward-ref annotations to not break in the presence of - # forward references. - - def _get_annotations(cls): - return annotationlib.get_annotations( - cls, format=annotationlib.Format.FORWARDREF - ) - -else: - - def _get_annotations(cls): - """ - Get annotations for *cls*. - """ - return cls.__dict__.get("__annotations__", {}) - - -class _AnnotationExtractor: - """ - Extract type annotations from a callable, returning None whenever there - is none. - """ - - __slots__ = ["sig"] - - def __init__(self, callable): - try: - self.sig = inspect.signature(callable) - except (ValueError, TypeError): # inspect failed - self.sig = None - - def get_first_param_type(self): - """ - Return the type annotation of the first argument if it's not empty. - """ - if not self.sig: - return None - - params = list(self.sig.parameters.values()) - if params and params[0].annotation is not inspect.Parameter.empty: - return params[0].annotation - - return None - - def get_return_type(self): - """ - Return the return type if it's not empty. - """ - if ( - self.sig - and self.sig.return_annotation is not inspect.Signature.empty - ): - return self.sig.return_annotation - - return None - - -# Thread-local global to track attrs instances which are already being repr'd. -# This is needed because there is no other (thread-safe) way to pass info -# about the instances that are already being repr'd through the call stack -# in order to ensure we don't perform infinite recursion. -# -# For instance, if an instance contains a dict which contains that instance, -# we need to know that we're already repr'ing the outside instance from within -# the dict's repr() call. -# -# This lives here rather than in _make.py so that the functions in _make.py -# don't have a direct reference to the thread-local in their globals dict. -# If they have such a reference, it breaks cloudpickle. -repr_context = threading.local() - - -def get_generic_base(cl): - """If this is a generic class (A[str]), return the generic base for it.""" - if cl.__class__ is _GenericAlias: - return cl.__origin__ - return None diff --git a/venv/lib/python3.9/site-packages/attr/_config.py b/venv/lib/python3.9/site-packages/attr/_config.py deleted file mode 100644 index 4b25772..0000000 --- a/venv/lib/python3.9/site-packages/attr/_config.py +++ /dev/null @@ -1,31 +0,0 @@ -# SPDX-License-Identifier: MIT - -__all__ = ["get_run_validators", "set_run_validators"] - -_run_validators = True - - -def set_run_validators(run): - """ - Set whether or not validators are run. By default, they are run. - - .. deprecated:: 21.3.0 It will not be removed, but it also will not be - moved to new ``attrs`` namespace. Use `attrs.validators.set_disabled()` - instead. - """ - if not isinstance(run, bool): - msg = "'run' must be bool." - raise TypeError(msg) - global _run_validators - _run_validators = run - - -def get_run_validators(): - """ - Return whether or not validators are run. - - .. deprecated:: 21.3.0 It will not be removed, but it also will not be - moved to new ``attrs`` namespace. Use `attrs.validators.get_disabled()` - instead. - """ - return _run_validators diff --git a/venv/lib/python3.9/site-packages/attr/_funcs.py b/venv/lib/python3.9/site-packages/attr/_funcs.py deleted file mode 100644 index 1adb500..0000000 --- a/venv/lib/python3.9/site-packages/attr/_funcs.py +++ /dev/null @@ -1,497 +0,0 @@ -# SPDX-License-Identifier: MIT - - -import copy - -from ._compat import get_generic_base -from ._make import _OBJ_SETATTR, NOTHING, fields -from .exceptions import AttrsAttributeNotFoundError - - -_ATOMIC_TYPES = frozenset( - { - type(None), - bool, - int, - float, - str, - complex, - bytes, - type(...), - type, - range, - property, - } -) - - -def asdict( - inst, - recurse=True, - filter=None, - dict_factory=dict, - retain_collection_types=False, - value_serializer=None, -): - """ - Return the *attrs* attribute values of *inst* as a dict. - - Optionally recurse into other *attrs*-decorated classes. - - Args: - inst: Instance of an *attrs*-decorated class. - - recurse (bool): Recurse into classes that are also *attrs*-decorated. - - filter (~typing.Callable): - A callable whose return code determines whether an attribute or - element is included (`True`) or dropped (`False`). Is called with - the `attrs.Attribute` as the first argument and the value as the - second argument. - - dict_factory (~typing.Callable): - A callable to produce dictionaries from. For example, to produce - ordered dictionaries instead of normal Python dictionaries, pass in - ``collections.OrderedDict``. - - retain_collection_types (bool): - Do not convert to `list` when encountering an attribute whose type - is `tuple` or `set`. Only meaningful if *recurse* is `True`. - - value_serializer (typing.Callable | None): - A hook that is called for every attribute or dict key/value. It - receives the current instance, field and value and must return the - (updated) value. The hook is run *after* the optional *filter* has - been applied. - - Returns: - Return type of *dict_factory*. - - Raises: - attrs.exceptions.NotAnAttrsClassError: - If *cls* is not an *attrs* class. - - .. versionadded:: 16.0.0 *dict_factory* - .. versionadded:: 16.1.0 *retain_collection_types* - .. versionadded:: 20.3.0 *value_serializer* - .. versionadded:: 21.3.0 - If a dict has a collection for a key, it is serialized as a tuple. - """ - attrs = fields(inst.__class__) - rv = dict_factory() - for a in attrs: - v = getattr(inst, a.name) - if filter is not None and not filter(a, v): - continue - - if value_serializer is not None: - v = value_serializer(inst, a, v) - - if recurse is True: - value_type = type(v) - if value_type in _ATOMIC_TYPES: - rv[a.name] = v - elif has(value_type): - rv[a.name] = asdict( - v, - recurse=True, - filter=filter, - dict_factory=dict_factory, - retain_collection_types=retain_collection_types, - value_serializer=value_serializer, - ) - elif issubclass(value_type, (tuple, list, set, frozenset)): - cf = value_type if retain_collection_types is True else list - items = [ - _asdict_anything( - i, - is_key=False, - filter=filter, - dict_factory=dict_factory, - retain_collection_types=retain_collection_types, - value_serializer=value_serializer, - ) - for i in v - ] - try: - rv[a.name] = cf(items) - except TypeError: - if not issubclass(cf, tuple): - raise - # Workaround for TypeError: cf.__new__() missing 1 required - # positional argument (which appears, for a namedturle) - rv[a.name] = cf(*items) - elif issubclass(value_type, dict): - df = dict_factory - rv[a.name] = df( - ( - _asdict_anything( - kk, - is_key=True, - filter=filter, - dict_factory=df, - retain_collection_types=retain_collection_types, - value_serializer=value_serializer, - ), - _asdict_anything( - vv, - is_key=False, - filter=filter, - dict_factory=df, - retain_collection_types=retain_collection_types, - value_serializer=value_serializer, - ), - ) - for kk, vv in v.items() - ) - else: - rv[a.name] = v - else: - rv[a.name] = v - return rv - - -def _asdict_anything( - val, - is_key, - filter, - dict_factory, - retain_collection_types, - value_serializer, -): - """ - ``asdict`` only works on attrs instances, this works on anything. - """ - val_type = type(val) - if val_type in _ATOMIC_TYPES: - rv = val - if value_serializer is not None: - rv = value_serializer(None, None, rv) - elif getattr(val_type, "__attrs_attrs__", None) is not None: - # Attrs class. - rv = asdict( - val, - recurse=True, - filter=filter, - dict_factory=dict_factory, - retain_collection_types=retain_collection_types, - value_serializer=value_serializer, - ) - elif issubclass(val_type, (tuple, list, set, frozenset)): - if retain_collection_types is True: - cf = val.__class__ - elif is_key: - cf = tuple - else: - cf = list - - rv = cf( - [ - _asdict_anything( - i, - is_key=False, - filter=filter, - dict_factory=dict_factory, - retain_collection_types=retain_collection_types, - value_serializer=value_serializer, - ) - for i in val - ] - ) - elif issubclass(val_type, dict): - df = dict_factory - rv = df( - ( - _asdict_anything( - kk, - is_key=True, - filter=filter, - dict_factory=df, - retain_collection_types=retain_collection_types, - value_serializer=value_serializer, - ), - _asdict_anything( - vv, - is_key=False, - filter=filter, - dict_factory=df, - retain_collection_types=retain_collection_types, - value_serializer=value_serializer, - ), - ) - for kk, vv in val.items() - ) - else: - rv = val - if value_serializer is not None: - rv = value_serializer(None, None, rv) - - return rv - - -def astuple( - inst, - recurse=True, - filter=None, - tuple_factory=tuple, - retain_collection_types=False, -): - """ - Return the *attrs* attribute values of *inst* as a tuple. - - Optionally recurse into other *attrs*-decorated classes. - - Args: - inst: Instance of an *attrs*-decorated class. - - recurse (bool): - Recurse into classes that are also *attrs*-decorated. - - filter (~typing.Callable): - A callable whose return code determines whether an attribute or - element is included (`True`) or dropped (`False`). Is called with - the `attrs.Attribute` as the first argument and the value as the - second argument. - - tuple_factory (~typing.Callable): - A callable to produce tuples from. For example, to produce lists - instead of tuples. - - retain_collection_types (bool): - Do not convert to `list` or `dict` when encountering an attribute - which type is `tuple`, `dict` or `set`. Only meaningful if - *recurse* is `True`. - - Returns: - Return type of *tuple_factory* - - Raises: - attrs.exceptions.NotAnAttrsClassError: - If *cls* is not an *attrs* class. - - .. versionadded:: 16.2.0 - """ - attrs = fields(inst.__class__) - rv = [] - retain = retain_collection_types # Very long. :/ - for a in attrs: - v = getattr(inst, a.name) - if filter is not None and not filter(a, v): - continue - value_type = type(v) - if recurse is True: - if value_type in _ATOMIC_TYPES: - rv.append(v) - elif has(value_type): - rv.append( - astuple( - v, - recurse=True, - filter=filter, - tuple_factory=tuple_factory, - retain_collection_types=retain, - ) - ) - elif issubclass(value_type, (tuple, list, set, frozenset)): - cf = v.__class__ if retain is True else list - items = [ - ( - astuple( - j, - recurse=True, - filter=filter, - tuple_factory=tuple_factory, - retain_collection_types=retain, - ) - if has(j.__class__) - else j - ) - for j in v - ] - try: - rv.append(cf(items)) - except TypeError: - if not issubclass(cf, tuple): - raise - # Workaround for TypeError: cf.__new__() missing 1 required - # positional argument (which appears, for a namedturle) - rv.append(cf(*items)) - elif issubclass(value_type, dict): - df = value_type if retain is True else dict - rv.append( - df( - ( - ( - astuple( - kk, - tuple_factory=tuple_factory, - retain_collection_types=retain, - ) - if has(kk.__class__) - else kk - ), - ( - astuple( - vv, - tuple_factory=tuple_factory, - retain_collection_types=retain, - ) - if has(vv.__class__) - else vv - ), - ) - for kk, vv in v.items() - ) - ) - else: - rv.append(v) - else: - rv.append(v) - - return rv if tuple_factory is list else tuple_factory(rv) - - -def has(cls): - """ - Check whether *cls* is a class with *attrs* attributes. - - Args: - cls (type): Class to introspect. - - Raises: - TypeError: If *cls* is not a class. - - Returns: - bool: - """ - attrs = getattr(cls, "__attrs_attrs__", None) - if attrs is not None: - return True - - # No attrs, maybe it's a specialized generic (A[str])? - generic_base = get_generic_base(cls) - if generic_base is not None: - generic_attrs = getattr(generic_base, "__attrs_attrs__", None) - if generic_attrs is not None: - # Stick it on here for speed next time. - cls.__attrs_attrs__ = generic_attrs - return generic_attrs is not None - return False - - -def assoc(inst, **changes): - """ - Copy *inst* and apply *changes*. - - This is different from `evolve` that applies the changes to the arguments - that create the new instance. - - `evolve`'s behavior is preferable, but there are `edge cases`_ where it - doesn't work. Therefore `assoc` is deprecated, but will not be removed. - - .. _`edge cases`: https://github.com/python-attrs/attrs/issues/251 - - Args: - inst: Instance of a class with *attrs* attributes. - - changes: Keyword changes in the new copy. - - Returns: - A copy of inst with *changes* incorporated. - - Raises: - attrs.exceptions.AttrsAttributeNotFoundError: - If *attr_name* couldn't be found on *cls*. - - attrs.exceptions.NotAnAttrsClassError: - If *cls* is not an *attrs* class. - - .. deprecated:: 17.1.0 - Use `attrs.evolve` instead if you can. This function will not be - removed du to the slightly different approach compared to - `attrs.evolve`, though. - """ - new = copy.copy(inst) - attrs = fields(inst.__class__) - for k, v in changes.items(): - a = getattr(attrs, k, NOTHING) - if a is NOTHING: - msg = f"{k} is not an attrs attribute on {new.__class__}." - raise AttrsAttributeNotFoundError(msg) - _OBJ_SETATTR(new, k, v) - return new - - -def resolve_types( - cls, globalns=None, localns=None, attribs=None, include_extras=True -): - """ - Resolve any strings and forward annotations in type annotations. - - This is only required if you need concrete types in :class:`Attribute`'s - *type* field. In other words, you don't need to resolve your types if you - only use them for static type checking. - - With no arguments, names will be looked up in the module in which the class - was created. If this is not what you want, for example, if the name only - exists inside a method, you may pass *globalns* or *localns* to specify - other dictionaries in which to look up these names. See the docs of - `typing.get_type_hints` for more details. - - Args: - cls (type): Class to resolve. - - globalns (dict | None): Dictionary containing global variables. - - localns (dict | None): Dictionary containing local variables. - - attribs (list | None): - List of attribs for the given class. This is necessary when calling - from inside a ``field_transformer`` since *cls* is not an *attrs* - class yet. - - include_extras (bool): - Resolve more accurately, if possible. Pass ``include_extras`` to - ``typing.get_hints``, if supported by the typing module. On - supported Python versions (3.9+), this resolves the types more - accurately. - - Raises: - TypeError: If *cls* is not a class. - - attrs.exceptions.NotAnAttrsClassError: - If *cls* is not an *attrs* class and you didn't pass any attribs. - - NameError: If types cannot be resolved because of missing variables. - - Returns: - *cls* so you can use this function also as a class decorator. Please - note that you have to apply it **after** `attrs.define`. That means the - decorator has to come in the line **before** `attrs.define`. - - .. versionadded:: 20.1.0 - .. versionadded:: 21.1.0 *attribs* - .. versionadded:: 23.1.0 *include_extras* - """ - # Since calling get_type_hints is expensive we cache whether we've - # done it already. - if getattr(cls, "__attrs_types_resolved__", None) != cls: - import typing - - kwargs = { - "globalns": globalns, - "localns": localns, - "include_extras": include_extras, - } - - hints = typing.get_type_hints(cls, **kwargs) - for field in fields(cls) if attribs is None else attribs: - if field.name in hints: - # Since fields have been frozen we must work around it. - _OBJ_SETATTR(field, "type", hints[field.name]) - # We store the class we resolved so that subclasses know they haven't - # been resolved. - cls.__attrs_types_resolved__ = cls - - # Return the class so you can use it as a decorator too. - return cls diff --git a/venv/lib/python3.9/site-packages/attr/_make.py b/venv/lib/python3.9/site-packages/attr/_make.py deleted file mode 100644 index 4b32d6a..0000000 --- a/venv/lib/python3.9/site-packages/attr/_make.py +++ /dev/null @@ -1,3406 +0,0 @@ -# SPDX-License-Identifier: MIT - -from __future__ import annotations - -import abc -import contextlib -import copy -import enum -import inspect -import itertools -import linecache -import sys -import types -import unicodedata -import weakref - -from collections.abc import Callable, Mapping -from functools import cached_property -from typing import Any, NamedTuple, TypeVar - -# We need to import _compat itself in addition to the _compat members to avoid -# having the thread-local in the globals here. -from . import _compat, _config, setters -from ._compat import ( - PY_3_10_PLUS, - PY_3_11_PLUS, - PY_3_13_PLUS, - _AnnotationExtractor, - _get_annotations, - get_generic_base, -) -from .exceptions import ( - DefaultAlreadySetError, - FrozenInstanceError, - NotAnAttrsClassError, - UnannotatedAttributeError, -) - - -# This is used at least twice, so cache it here. -_OBJ_SETATTR = object.__setattr__ -_INIT_FACTORY_PAT = "__attr_factory_%s" -_CLASSVAR_PREFIXES = ( - "typing.ClassVar", - "t.ClassVar", - "ClassVar", - "typing_extensions.ClassVar", -) -# we don't use a double-underscore prefix because that triggers -# name mangling when trying to create a slot for the field -# (when slots=True) -_HASH_CACHE_FIELD = "_attrs_cached_hash" - -_EMPTY_METADATA_SINGLETON = types.MappingProxyType({}) - -# Unique object for unequivocal getattr() defaults. -_SENTINEL = object() - -_DEFAULT_ON_SETATTR = setters.pipe(setters.convert, setters.validate) - - -class _Nothing(enum.Enum): - """ - Sentinel to indicate the lack of a value when `None` is ambiguous. - - If extending attrs, you can use ``typing.Literal[NOTHING]`` to show - that a value may be ``NOTHING``. - - .. versionchanged:: 21.1.0 ``bool(NOTHING)`` is now False. - .. versionchanged:: 22.2.0 ``NOTHING`` is now an ``enum.Enum`` variant. - """ - - NOTHING = enum.auto() - - def __repr__(self): - return "NOTHING" - - def __bool__(self): - return False - - -NOTHING = _Nothing.NOTHING -""" -Sentinel to indicate the lack of a value when `None` is ambiguous. - -When using in 3rd party code, use `attrs.NothingType` for type annotations. -""" - - -class _CacheHashWrapper(int): - """ - An integer subclass that pickles / copies as None - - This is used for non-slots classes with ``cache_hash=True``, to avoid - serializing a potentially (even likely) invalid hash value. Since `None` - is the default value for uncalculated hashes, whenever this is copied, - the copy's value for the hash should automatically reset. - - See GH #613 for more details. - """ - - def __reduce__(self, _none_constructor=type(None), _args=()): # noqa: B008 - return _none_constructor, _args - - -def attrib( - default=NOTHING, - validator=None, - repr=True, - cmp=None, - hash=None, - init=True, - metadata=None, - type=None, - converter=None, - factory=None, - kw_only=None, - eq=None, - order=None, - on_setattr=None, - alias=None, -): - """ - Create a new field / attribute on a class. - - Identical to `attrs.field`, except it's not keyword-only. - - Consider using `attrs.field` in new code (``attr.ib`` will *never* go away, - though). - - .. warning:: - - Does **nothing** unless the class is also decorated with - `attr.s` (or similar)! - - - .. versionadded:: 15.2.0 *convert* - .. versionadded:: 16.3.0 *metadata* - .. versionchanged:: 17.1.0 *validator* can be a ``list`` now. - .. versionchanged:: 17.1.0 - *hash* is `None` and therefore mirrors *eq* by default. - .. versionadded:: 17.3.0 *type* - .. deprecated:: 17.4.0 *convert* - .. versionadded:: 17.4.0 - *converter* as a replacement for the deprecated *convert* to achieve - consistency with other noun-based arguments. - .. versionadded:: 18.1.0 - ``factory=f`` is syntactic sugar for ``default=attr.Factory(f)``. - .. versionadded:: 18.2.0 *kw_only* - .. versionchanged:: 19.2.0 *convert* keyword argument removed. - .. versionchanged:: 19.2.0 *repr* also accepts a custom callable. - .. deprecated:: 19.2.0 *cmp* Removal on or after 2021-06-01. - .. versionadded:: 19.2.0 *eq* and *order* - .. versionadded:: 20.1.0 *on_setattr* - .. versionchanged:: 20.3.0 *kw_only* backported to Python 2 - .. versionchanged:: 21.1.0 - *eq*, *order*, and *cmp* also accept a custom callable - .. versionchanged:: 21.1.0 *cmp* undeprecated - .. versionadded:: 22.2.0 *alias* - .. versionchanged:: 25.4.0 - *kw_only* can now be None, and its default is also changed from False to - None. - """ - eq, eq_key, order, order_key = _determine_attrib_eq_order( - cmp, eq, order, True - ) - - if hash is not None and hash is not True and hash is not False: - msg = "Invalid value for hash. Must be True, False, or None." - raise TypeError(msg) - - if factory is not None: - if default is not NOTHING: - msg = ( - "The `default` and `factory` arguments are mutually exclusive." - ) - raise ValueError(msg) - if not callable(factory): - msg = "The `factory` argument must be a callable." - raise ValueError(msg) - default = Factory(factory) - - if metadata is None: - metadata = {} - - # Apply syntactic sugar by auto-wrapping. - if isinstance(on_setattr, (list, tuple)): - on_setattr = setters.pipe(*on_setattr) - - if validator and isinstance(validator, (list, tuple)): - validator = and_(*validator) - - if converter and isinstance(converter, (list, tuple)): - converter = pipe(*converter) - - return _CountingAttr( - default=default, - validator=validator, - repr=repr, - cmp=None, - hash=hash, - init=init, - converter=converter, - metadata=metadata, - type=type, - kw_only=kw_only, - eq=eq, - eq_key=eq_key, - order=order, - order_key=order_key, - on_setattr=on_setattr, - alias=alias, - ) - - -def _compile_and_eval( - script: str, - globs: dict[str, Any] | None, - locs: Mapping[str, object] | None = None, - filename: str = "", -) -> None: - """ - Evaluate the script with the given global (globs) and local (locs) - variables. - """ - bytecode = compile(script, filename, "exec") - eval(bytecode, globs, locs) - - -def _linecache_and_compile( - script: str, - filename: str, - globs: dict[str, Any] | None, - locals: Mapping[str, object] | None = None, -) -> dict[str, Any]: - """ - Cache the script with _linecache_, compile it and return the _locals_. - """ - - locs = {} if locals is None else locals - - # In order of debuggers like PDB being able to step through the code, - # we add a fake linecache entry. - count = 1 - base_filename = filename - while True: - linecache_tuple = ( - len(script), - None, - script.splitlines(True), - filename, - ) - old_val = linecache.cache.setdefault(filename, linecache_tuple) - if old_val == linecache_tuple: - break - - filename = f"{base_filename[:-1]}-{count}>" - count += 1 - - _compile_and_eval(script, globs, locs, filename) - - return locs - - -def _make_attr_tuple_class(cls_name: str, attr_names: list[str]) -> type: - """ - Create a tuple subclass to hold `Attribute`s for an `attrs` class. - - The subclass is a bare tuple with properties for names. - - class MyClassAttributes(tuple): - __slots__ = () - x = property(itemgetter(0)) - """ - attr_class_name = f"{cls_name}Attributes" - body = {} - for i, attr_name in enumerate(attr_names): - - def getter(self, i=i): - return self[i] - - body[attr_name] = property(getter) - return type(attr_class_name, (tuple,), body) - - -# Tuple class for extracted attributes from a class definition. -# `base_attrs` is a subset of `attrs`. -class _Attributes(NamedTuple): - attrs: type - base_attrs: list[Attribute] - base_attrs_map: dict[str, type] - - -def _is_class_var(annot): - """ - Check whether *annot* is a typing.ClassVar. - - The string comparison hack is used to avoid evaluating all string - annotations which would put attrs-based classes at a performance - disadvantage compared to plain old classes. - """ - annot = str(annot) - - # Annotation can be quoted. - if annot.startswith(("'", '"')) and annot.endswith(("'", '"')): - annot = annot[1:-1] - - return annot.startswith(_CLASSVAR_PREFIXES) - - -def _has_own_attribute(cls, attrib_name): - """ - Check whether *cls* defines *attrib_name* (and doesn't just inherit it). - """ - return attrib_name in cls.__dict__ - - -def _collect_base_attrs( - cls, taken_attr_names -) -> tuple[list[Attribute], dict[str, type]]: - """ - Collect attr.ibs from base classes of *cls*, except *taken_attr_names*. - """ - base_attrs = [] - base_attr_map = {} # A dictionary of base attrs to their classes. - - # Traverse the MRO and collect attributes. - for base_cls in reversed(cls.__mro__[1:-1]): - for a in getattr(base_cls, "__attrs_attrs__", []): - if a.inherited or a.name in taken_attr_names: - continue - - a = a.evolve(inherited=True) # noqa: PLW2901 - base_attrs.append(a) - base_attr_map[a.name] = base_cls - - # For each name, only keep the freshest definition i.e. the furthest at the - # back. base_attr_map is fine because it gets overwritten with every new - # instance. - filtered = [] - seen = set() - for a in reversed(base_attrs): - if a.name in seen: - continue - filtered.insert(0, a) - seen.add(a.name) - - return filtered, base_attr_map - - -def _collect_base_attrs_broken(cls, taken_attr_names): - """ - Collect attr.ibs from base classes of *cls*, except *taken_attr_names*. - - N.B. *taken_attr_names* will be mutated. - - Adhere to the old incorrect behavior. - - Notably it collects from the front and considers inherited attributes which - leads to the buggy behavior reported in #428. - """ - base_attrs = [] - base_attr_map = {} # A dictionary of base attrs to their classes. - - # Traverse the MRO and collect attributes. - for base_cls in cls.__mro__[1:-1]: - for a in getattr(base_cls, "__attrs_attrs__", []): - if a.name in taken_attr_names: - continue - - a = a.evolve(inherited=True) # noqa: PLW2901 - taken_attr_names.add(a.name) - base_attrs.append(a) - base_attr_map[a.name] = base_cls - - return base_attrs, base_attr_map - - -def _transform_attrs( - cls, - these, - auto_attribs, - kw_only, - collect_by_mro, - field_transformer, -) -> _Attributes: - """ - Transform all `_CountingAttr`s on a class into `Attribute`s. - - If *these* is passed, use that and don't look for them on the class. - - If *collect_by_mro* is True, collect them in the correct MRO order, - otherwise use the old -- incorrect -- order. See #428. - - Return an `_Attributes`. - """ - cd = cls.__dict__ - anns = _get_annotations(cls) - - if these is not None: - ca_list = list(these.items()) - elif auto_attribs is True: - ca_names = { - name - for name, attr in cd.items() - if attr.__class__ is _CountingAttr - } - ca_list = [] - annot_names = set() - for attr_name, type in anns.items(): - if _is_class_var(type): - continue - annot_names.add(attr_name) - a = cd.get(attr_name, NOTHING) - - if a.__class__ is not _CountingAttr: - a = attrib(a) - ca_list.append((attr_name, a)) - - unannotated = ca_names - annot_names - if unannotated: - raise UnannotatedAttributeError( - "The following `attr.ib`s lack a type annotation: " - + ", ".join( - sorted(unannotated, key=lambda n: cd.get(n).counter) - ) - + "." - ) - else: - ca_list = sorted( - ( - (name, attr) - for name, attr in cd.items() - if attr.__class__ is _CountingAttr - ), - key=lambda e: e[1].counter, - ) - - fca = Attribute.from_counting_attr - no = ClassProps.KeywordOnly.NO - own_attrs = [ - fca( - attr_name, - ca, - kw_only is not no, - anns.get(attr_name), - ) - for attr_name, ca in ca_list - ] - - if collect_by_mro: - base_attrs, base_attr_map = _collect_base_attrs( - cls, {a.name for a in own_attrs} - ) - else: - base_attrs, base_attr_map = _collect_base_attrs_broken( - cls, {a.name for a in own_attrs} - ) - - if kw_only is ClassProps.KeywordOnly.FORCE: - own_attrs = [a.evolve(kw_only=True) for a in own_attrs] - base_attrs = [a.evolve(kw_only=True) for a in base_attrs] - - attrs = base_attrs + own_attrs - - # Resolve default field alias before executing field_transformer, so that - # the transformer receives fully populated Attribute objects with usable - # alias values. - for a in attrs: - if not a.alias: - # Evolve is very slow, so we hold our nose and do it dirty. - _OBJ_SETATTR.__get__(a)("alias", _default_init_alias_for(a.name)) - _OBJ_SETATTR.__get__(a)("alias_is_default", True) - - if field_transformer is not None: - attrs = tuple(field_transformer(cls, attrs)) - - # Check attr order after executing the field_transformer. - # Mandatory vs non-mandatory attr order only matters when they are part of - # the __init__ signature and when they aren't kw_only (which are moved to - # the end and can be mandatory or non-mandatory in any order, as they will - # be specified as keyword args anyway). Check the order of those attrs: - had_default = False - for a in (a for a in attrs if a.init is not False and a.kw_only is False): - if had_default is True and a.default is NOTHING: - msg = f"No mandatory attributes allowed after an attribute with a default value or factory. Attribute in question: {a!r}" - raise ValueError(msg) - - if had_default is False and a.default is not NOTHING: - had_default = True - - # Resolve default field alias for any new attributes that the - # field_transformer may have added without setting an alias. - for a in attrs: - if not a.alias: - _OBJ_SETATTR.__get__(a)("alias", _default_init_alias_for(a.name)) - _OBJ_SETATTR.__get__(a)("alias_is_default", True) - - # Create AttrsClass *after* applying the field_transformer since it may - # add or remove attributes! - attr_names = [a.name for a in attrs] - AttrsClass = _make_attr_tuple_class(cls.__name__, attr_names) - - return _Attributes(AttrsClass(attrs), base_attrs, base_attr_map) - - -def _make_cached_property_getattr(cached_properties, original_getattr, cls): - lines = [ - # Wrapped to get `__class__` into closure cell for super() - # (It will be replaced with the newly constructed class after construction). - "def wrapper(_cls):", - " __class__ = _cls", - " def __getattr__(self, item, cached_properties=cached_properties, original_getattr=original_getattr, _cached_setattr_get=_cached_setattr_get):", - " func = cached_properties.get(item)", - " if func is not None:", - " result = func(self)", - " _setter = _cached_setattr_get(self)", - " _setter(item, result)", - " return result", - ] - if original_getattr is not None: - lines.append( - " return original_getattr(self, item)", - ) - else: - lines.extend( - [ - " try:", - " return super().__getattribute__(item)", - " except AttributeError:", - " if not hasattr(super(), '__getattr__'):", - " raise", - " return super().__getattr__(item)", - " original_error = f\"'{self.__class__.__name__}' object has no attribute '{item}'\"", - " raise AttributeError(original_error)", - ] - ) - - lines.extend( - [ - " return __getattr__", - "__getattr__ = wrapper(_cls)", - ] - ) - - unique_filename = _generate_unique_filename(cls, "getattr") - - glob = { - "cached_properties": cached_properties, - "_cached_setattr_get": _OBJ_SETATTR.__get__, - "original_getattr": original_getattr, - } - - return _linecache_and_compile( - "\n".join(lines), unique_filename, glob, locals={"_cls": cls} - )["__getattr__"] - - -def _frozen_setattrs(self, name, value): - """ - Attached to frozen classes as __setattr__. - """ - if isinstance(self, BaseException) and name in ( - "__cause__", - "__context__", - "__traceback__", - "__suppress_context__", - "__notes__", - ): - BaseException.__setattr__(self, name, value) - return - - raise FrozenInstanceError - - -def _frozen_delattrs(self, name): - """ - Attached to frozen classes as __delattr__. - """ - if isinstance(self, BaseException) and name == "__notes__": - BaseException.__delattr__(self, name) - return - - raise FrozenInstanceError - - -def evolve(*args, **changes): - """ - Create a new instance, based on the first positional argument with - *changes* applied. - - .. tip:: - - On Python 3.13 and later, you can also use `copy.replace` instead. - - Args: - - inst: - Instance of a class with *attrs* attributes. *inst* must be passed - as a positional argument. - - changes: - Keyword changes in the new copy. - - Returns: - A copy of inst with *changes* incorporated. - - Raises: - TypeError: - If *attr_name* couldn't be found in the class ``__init__``. - - attrs.exceptions.NotAnAttrsClassError: - If *cls* is not an *attrs* class. - - .. versionadded:: 17.1.0 - .. deprecated:: 23.1.0 - It is now deprecated to pass the instance using the keyword argument - *inst*. It will raise a warning until at least April 2024, after which - it will become an error. Always pass the instance as a positional - argument. - .. versionchanged:: 24.1.0 - *inst* can't be passed as a keyword argument anymore. - """ - try: - (inst,) = args - except ValueError: - msg = ( - f"evolve() takes 1 positional argument, but {len(args)} were given" - ) - raise TypeError(msg) from None - - cls = inst.__class__ - attrs = fields(cls) - for a in attrs: - if not a.init: - continue - attr_name = a.name # To deal with private attributes. - init_name = a.alias - if init_name not in changes: - changes[init_name] = getattr(inst, attr_name) - - return cls(**changes) - - -class _ClassBuilder: - """ - Iteratively build *one* class. - """ - - __slots__ = ( - "_add_method_dunders", - "_attr_names", - "_attrs", - "_base_attr_map", - "_base_names", - "_cache_hash", - "_cls", - "_cls_dict", - "_delete_attribs", - "_frozen", - "_has_custom_setattr", - "_has_post_init", - "_has_pre_init", - "_is_exc", - "_on_setattr", - "_pre_init_has_args", - "_repr_added", - "_script_snippets", - "_slots", - "_weakref_slot", - "_wrote_own_setattr", - ) - - def __init__( - self, - cls: type, - these, - auto_attribs: bool, - props: ClassProps, - has_custom_setattr: bool, - ): - attrs, base_attrs, base_map = _transform_attrs( - cls, - these, - auto_attribs, - props.kw_only, - props.collected_fields_by_mro, - props.field_transformer, - ) - - self._cls = cls - self._cls_dict = dict(cls.__dict__) if props.is_slotted else {} - self._attrs = attrs - self._base_names = {a.name for a in base_attrs} - self._base_attr_map = base_map - self._attr_names = tuple(a.name for a in attrs) - self._slots = props.is_slotted - self._frozen = props.is_frozen - self._weakref_slot = props.has_weakref_slot - self._cache_hash = ( - props.hashability is ClassProps.Hashability.HASHABLE_CACHED - ) - self._has_pre_init = bool(getattr(cls, "__attrs_pre_init__", False)) - self._pre_init_has_args = False - if self._has_pre_init: - # Check if the pre init method has more arguments than just `self` - # We want to pass arguments if pre init expects arguments - pre_init_func = cls.__attrs_pre_init__ - pre_init_signature = inspect.signature(pre_init_func) - self._pre_init_has_args = len(pre_init_signature.parameters) > 1 - self._has_post_init = bool(getattr(cls, "__attrs_post_init__", False)) - self._delete_attribs = not bool(these) - self._is_exc = props.is_exception - self._on_setattr = props.on_setattr_hook - - self._has_custom_setattr = has_custom_setattr - self._wrote_own_setattr = False - - self._cls_dict["__attrs_attrs__"] = self._attrs - self._cls_dict["__attrs_props__"] = props - - if props.is_frozen: - self._cls_dict["__setattr__"] = _frozen_setattrs - self._cls_dict["__delattr__"] = _frozen_delattrs - - self._wrote_own_setattr = True - elif self._on_setattr in ( - _DEFAULT_ON_SETATTR, - setters.validate, - setters.convert, - ): - has_validator = has_converter = False - for a in attrs: - if a.validator is not None: - has_validator = True - if a.converter is not None: - has_converter = True - - if has_validator and has_converter: - break - if ( - ( - self._on_setattr == _DEFAULT_ON_SETATTR - and not (has_validator or has_converter) - ) - or (self._on_setattr == setters.validate and not has_validator) - or (self._on_setattr == setters.convert and not has_converter) - ): - # If class-level on_setattr is set to convert + validate, but - # there's no field to convert or validate, pretend like there's - # no on_setattr. - self._on_setattr = None - - if props.added_pickling: - ( - self._cls_dict["__getstate__"], - self._cls_dict["__setstate__"], - ) = self._make_getstate_setstate() - - # tuples of script, globs, hook - self._script_snippets: list[ - tuple[str, dict, Callable[[dict, dict], Any]] - ] = [] - self._repr_added = False - - # We want to only do this check once; in 99.9% of cases these - # exist. - if not hasattr(self._cls, "__module__") or not hasattr( - self._cls, "__qualname__" - ): - self._add_method_dunders = self._add_method_dunders_safe - else: - self._add_method_dunders = self._add_method_dunders_unsafe - - def __repr__(self): - return f"<_ClassBuilder(cls={self._cls.__name__})>" - - def _eval_snippets(self) -> None: - """ - Evaluate any registered snippets in one go. - """ - script = "\n".join([snippet[0] for snippet in self._script_snippets]) - globs = {} - for _, snippet_globs, _ in self._script_snippets: - globs.update(snippet_globs) - - locs = _linecache_and_compile( - script, - _generate_unique_filename(self._cls, "methods"), - globs, - ) - - for _, _, hook in self._script_snippets: - hook(self._cls_dict, locs) - - def build_class(self): - """ - Finalize class based on the accumulated configuration. - - Builder cannot be used after calling this method. - """ - self._eval_snippets() - if self._slots is True: - cls = self._create_slots_class() - self._cls.__attrs_base_of_slotted__ = weakref.ref(cls) - else: - cls = self._patch_original_class() - if PY_3_10_PLUS: - cls = abc.update_abstractmethods(cls) - - # The method gets only called if it's not inherited from a base class. - # _has_own_attribute does NOT work properly for classmethods. - if ( - getattr(cls, "__attrs_init_subclass__", None) - and "__attrs_init_subclass__" not in cls.__dict__ - ): - cls.__attrs_init_subclass__() - - return cls - - def _patch_original_class(self): - """ - Apply accumulated methods and return the class. - """ - cls = self._cls - base_names = self._base_names - - # Clean class of attribute definitions (`attr.ib()`s). - if self._delete_attribs: - for name in self._attr_names: - if ( - name not in base_names - and getattr(cls, name, _SENTINEL) is not _SENTINEL - ): - # An AttributeError can happen if a base class defines a - # class variable and we want to set an attribute with the - # same name by using only a type annotation. - with contextlib.suppress(AttributeError): - delattr(cls, name) - - # Attach our dunder methods. - for name, value in self._cls_dict.items(): - setattr(cls, name, value) - - # If we've inherited an attrs __setattr__ and don't write our own, - # reset it to object's. - if not self._wrote_own_setattr and getattr( - cls, "__attrs_own_setattr__", False - ): - cls.__attrs_own_setattr__ = False - - if not self._has_custom_setattr: - cls.__setattr__ = _OBJ_SETATTR - - return cls - - def _create_slots_class(self): - """ - Build and return a new class with a `__slots__` attribute. - """ - cd = { - k: v - for k, v in self._cls_dict.items() - if k not in (*tuple(self._attr_names), "__dict__", "__weakref__") - } - - # 3.14.0rc2+ - if hasattr(sys, "_clear_type_descriptors"): - sys._clear_type_descriptors(self._cls) - - # If our class doesn't have its own implementation of __setattr__ - # (either from the user or by us), check the bases, if one of them has - # an attrs-made __setattr__, that needs to be reset. We don't walk the - # MRO because we only care about our immediate base classes. - # XXX: This can be confused by subclassing a slotted attrs class with - # XXX: a non-attrs class and subclass the resulting class with an attrs - # XXX: class. See `test_slotted_confused` for details. For now that's - # XXX: OK with us. - if not self._wrote_own_setattr: - cd["__attrs_own_setattr__"] = False - - if not self._has_custom_setattr: - for base_cls in self._cls.__bases__: - if base_cls.__dict__.get("__attrs_own_setattr__", False): - cd["__setattr__"] = _OBJ_SETATTR - break - - # Traverse the MRO to collect existing slots - # and check for an existing __weakref__. - existing_slots = {} - weakref_inherited = False - for base_cls in self._cls.__mro__[1:-1]: - if base_cls.__dict__.get("__weakref__", None) is not None: - weakref_inherited = True - existing_slots.update( - { - name: getattr(base_cls, name) - for name in getattr(base_cls, "__slots__", []) - } - ) - - base_names = set(self._base_names) - - names = self._attr_names - if ( - self._weakref_slot - and "__weakref__" not in getattr(self._cls, "__slots__", ()) - and "__weakref__" not in names - and not weakref_inherited - ): - names += ("__weakref__",) - - cached_properties = { - name: cached_prop.func - for name, cached_prop in cd.items() - if isinstance(cached_prop, cached_property) - } - - # Collect methods with a `__class__` reference that are shadowed in the new class. - # To know to update them. - additional_closure_functions_to_update = [] - if cached_properties: - class_annotations = _get_annotations(self._cls) - for name, func in cached_properties.items(): - # Add cached properties to names for slotting. - names += (name,) - # Clear out function from class to avoid clashing. - del cd[name] - additional_closure_functions_to_update.append(func) - annotation = inspect.signature(func).return_annotation - if annotation is not inspect.Parameter.empty: - class_annotations[name] = annotation - - original_getattr = cd.get("__getattr__") - if original_getattr is not None: - additional_closure_functions_to_update.append(original_getattr) - - cd["__getattr__"] = _make_cached_property_getattr( - cached_properties, original_getattr, self._cls - ) - - # We only add the names of attributes that aren't inherited. - # Setting __slots__ to inherited attributes wastes memory. - slot_names = [name for name in names if name not in base_names] - - # There are slots for attributes from current class - # that are defined in parent classes. - # As their descriptors may be overridden by a child class, - # we collect them here and update the class dict - reused_slots = { - slot: slot_descriptor - for slot, slot_descriptor in existing_slots.items() - if slot in slot_names - } - slot_names = [name for name in slot_names if name not in reused_slots] - cd.update(reused_slots) - if self._cache_hash: - slot_names.append(_HASH_CACHE_FIELD) - - cd["__slots__"] = tuple(slot_names) - - cd["__qualname__"] = self._cls.__qualname__ - - # Create new class based on old class and our methods. - cls = type(self._cls)(self._cls.__name__, self._cls.__bases__, cd) - - # The following is a fix for - # . - # If a method mentions `__class__` or uses the no-arg super(), the - # compiler will bake a reference to the class in the method itself - # as `method.__closure__`. Since we replace the class with a - # clone, we rewrite these references so it keeps working. - for item in itertools.chain( - cls.__dict__.values(), additional_closure_functions_to_update - ): - if isinstance(item, (classmethod, staticmethod)): - # Class- and staticmethods hide their functions inside. - # These might need to be rewritten as well. - closure_cells = getattr(item.__func__, "__closure__", None) - elif isinstance(item, property): - # Workaround for property `super()` shortcut (PY3-only). - # There is no universal way for other descriptors. - closure_cells = getattr(item.fget, "__closure__", None) - else: - closure_cells = getattr(item, "__closure__", None) - - if not closure_cells: # Catch None or the empty list. - continue - for cell in closure_cells: - try: - match = cell.cell_contents is self._cls - except ValueError: # noqa: PERF203 - # ValueError: Cell is empty - pass - else: - if match: - cell.cell_contents = cls - return cls - - def add_repr(self, ns): - script, globs = _make_repr_script(self._attrs, ns) - - def _attach_repr(cls_dict, globs): - cls_dict["__repr__"] = self._add_method_dunders(globs["__repr__"]) - - self._script_snippets.append((script, globs, _attach_repr)) - self._repr_added = True - return self - - def add_str(self): - if not self._repr_added: - msg = "__str__ can only be generated if a __repr__ exists." - raise ValueError(msg) - - def __str__(self): - return self.__repr__() - - self._cls_dict["__str__"] = self._add_method_dunders(__str__) - return self - - def _make_getstate_setstate(self): - """ - Create custom __setstate__ and __getstate__ methods. - """ - # __weakref__ is not writable. - state_attr_names = tuple( - an for an in self._attr_names if an != "__weakref__" - ) - - def slots_getstate(self): - """ - Automatically created by attrs. - """ - return {name: getattr(self, name) for name in state_attr_names} - - hash_caching_enabled = self._cache_hash - - def slots_setstate(self, state): - """ - Automatically created by attrs. - """ - __bound_setattr = _OBJ_SETATTR.__get__(self) - if isinstance(state, tuple): - # Backward compatibility with attrs instances pickled with - # attrs versions before v22.2.0 which stored tuples. - for name, value in zip(state_attr_names, state): - __bound_setattr(name, value) - else: - for name in state_attr_names: - if name in state: - __bound_setattr(name, state[name]) - - # The hash code cache is not included when the object is - # serialized, but it still needs to be initialized to None to - # indicate that the first call to __hash__ should be a cache - # miss. - if hash_caching_enabled: - __bound_setattr(_HASH_CACHE_FIELD, None) - - return slots_getstate, slots_setstate - - def make_unhashable(self): - self._cls_dict["__hash__"] = None - return self - - def add_hash(self): - script, globs = _make_hash_script( - self._cls, - self._attrs, - frozen=self._frozen, - cache_hash=self._cache_hash, - ) - - def attach_hash(cls_dict: dict, locs: dict) -> None: - cls_dict["__hash__"] = self._add_method_dunders(locs["__hash__"]) - - self._script_snippets.append((script, globs, attach_hash)) - - return self - - def add_init(self): - script, globs, annotations = _make_init_script( - self._cls, - self._attrs, - self._has_pre_init, - self._pre_init_has_args, - self._has_post_init, - self._frozen, - self._slots, - self._cache_hash, - self._base_attr_map, - self._is_exc, - self._on_setattr, - attrs_init=False, - ) - - def _attach_init(cls_dict, globs): - init = globs["__init__"] - init.__annotations__ = annotations - cls_dict["__init__"] = self._add_method_dunders(init) - - self._script_snippets.append((script, globs, _attach_init)) - - return self - - def add_replace(self): - self._cls_dict["__replace__"] = self._add_method_dunders(evolve) - return self - - def add_match_args(self): - self._cls_dict["__match_args__"] = tuple( - field.name - for field in self._attrs - if field.init and not field.kw_only - ) - - def add_attrs_init(self): - script, globs, annotations = _make_init_script( - self._cls, - self._attrs, - self._has_pre_init, - self._pre_init_has_args, - self._has_post_init, - self._frozen, - self._slots, - self._cache_hash, - self._base_attr_map, - self._is_exc, - self._on_setattr, - attrs_init=True, - ) - - def _attach_attrs_init(cls_dict, globs): - init = globs["__attrs_init__"] - init.__annotations__ = annotations - cls_dict["__attrs_init__"] = self._add_method_dunders(init) - - self._script_snippets.append((script, globs, _attach_attrs_init)) - - return self - - def add_eq(self): - cd = self._cls_dict - - script, globs = _make_eq_script(self._attrs) - - def _attach_eq(cls_dict, globs): - cls_dict["__eq__"] = self._add_method_dunders(globs["__eq__"]) - - self._script_snippets.append((script, globs, _attach_eq)) - - cd["__ne__"] = __ne__ - - return self - - def add_order(self): - cd = self._cls_dict - - cd["__lt__"], cd["__le__"], cd["__gt__"], cd["__ge__"] = ( - self._add_method_dunders(meth) - for meth in _make_order(self._cls, self._attrs) - ) - - return self - - def add_setattr(self): - sa_attrs = {} - for a in self._attrs: - on_setattr = a.on_setattr or self._on_setattr - if on_setattr and on_setattr is not setters.NO_OP: - sa_attrs[a.name] = a, on_setattr - - if not sa_attrs: - return self - - if self._has_custom_setattr: - # We need to write a __setattr__ but there already is one! - msg = "Can't combine custom __setattr__ with on_setattr hooks." - raise ValueError(msg) - - # docstring comes from _add_method_dunders - def __setattr__(self, name, val): - try: - a, hook = sa_attrs[name] - except KeyError: - nval = val - else: - nval = hook(self, a, val) - - _OBJ_SETATTR(self, name, nval) - - self._cls_dict["__attrs_own_setattr__"] = True - self._cls_dict["__setattr__"] = self._add_method_dunders(__setattr__) - self._wrote_own_setattr = True - - return self - - def _add_method_dunders_unsafe(self, method: Callable) -> Callable: - """ - Add __module__ and __qualname__ to a *method*. - """ - method.__module__ = self._cls.__module__ - - method.__qualname__ = f"{self._cls.__qualname__}.{method.__name__}" - - method.__doc__ = ( - f"Method generated by attrs for class {self._cls.__qualname__}." - ) - - return method - - def _add_method_dunders_safe(self, method: Callable) -> Callable: - """ - Add __module__ and __qualname__ to a *method* if possible. - """ - with contextlib.suppress(AttributeError): - method.__module__ = self._cls.__module__ - - with contextlib.suppress(AttributeError): - method.__qualname__ = f"{self._cls.__qualname__}.{method.__name__}" - - with contextlib.suppress(AttributeError): - method.__doc__ = f"Method generated by attrs for class {self._cls.__qualname__}." - - return method - - -def _determine_attrs_eq_order(cmp, eq, order, default_eq): - """ - Validate the combination of *cmp*, *eq*, and *order*. Derive the effective - values of eq and order. If *eq* is None, set it to *default_eq*. - """ - if cmp is not None and any((eq is not None, order is not None)): - msg = "Don't mix `cmp` with `eq' and `order`." - raise ValueError(msg) - - # cmp takes precedence due to bw-compatibility. - if cmp is not None: - return cmp, cmp - - # If left None, equality is set to the specified default and ordering - # mirrors equality. - if eq is None: - eq = default_eq - - if order is None: - order = eq - - if eq is False and order is True: - msg = "`order` can only be True if `eq` is True too." - raise ValueError(msg) - - return eq, order - - -def _determine_attrib_eq_order(cmp, eq, order, default_eq): - """ - Validate the combination of *cmp*, *eq*, and *order*. Derive the effective - values of eq and order. If *eq* is None, set it to *default_eq*. - """ - if cmp is not None and any((eq is not None, order is not None)): - msg = "Don't mix `cmp` with `eq' and `order`." - raise ValueError(msg) - - def decide_callable_or_boolean(value): - """ - Decide whether a key function is used. - """ - if callable(value): - value, key = True, value - else: - key = None - return value, key - - # cmp takes precedence due to bw-compatibility. - if cmp is not None: - cmp, cmp_key = decide_callable_or_boolean(cmp) - return cmp, cmp_key, cmp, cmp_key - - # If left None, equality is set to the specified default and ordering - # mirrors equality. - if eq is None: - eq, eq_key = default_eq, None - else: - eq, eq_key = decide_callable_or_boolean(eq) - - if order is None: - order, order_key = eq, eq_key - else: - order, order_key = decide_callable_or_boolean(order) - - if eq is False and order is True: - msg = "`order` can only be True if `eq` is True too." - raise ValueError(msg) - - return eq, eq_key, order, order_key - - -def _determine_whether_to_implement( - cls, flag, auto_detect, dunders, default=True -): - """ - Check whether we should implement a set of methods for *cls*. - - *flag* is the argument passed into @attr.s like 'init', *auto_detect* the - same as passed into @attr.s and *dunders* is a tuple of attribute names - whose presence signal that the user has implemented it themselves. - - Return *default* if no reason for either for or against is found. - """ - if flag is True or flag is False: - return flag - - if flag is None and auto_detect is False: - return default - - # Logically, flag is None and auto_detect is True here. - for dunder in dunders: - if _has_own_attribute(cls, dunder): - return False - - return default - - -def attrs( - maybe_cls=None, - these=None, - repr_ns=None, - repr=None, - cmp=None, - hash=None, - init=None, - slots=False, - frozen=False, - weakref_slot=True, - str=False, - auto_attribs=False, - kw_only=False, - cache_hash=False, - auto_exc=False, - eq=None, - order=None, - auto_detect=False, - collect_by_mro=False, - getstate_setstate=None, - on_setattr=None, - field_transformer=None, - match_args=True, - unsafe_hash=None, - force_kw_only=True, -): - r""" - A class decorator that adds :term:`dunder methods` according to the - specified attributes using `attr.ib` or the *these* argument. - - Consider using `attrs.define` / `attrs.frozen` in new code (``attr.s`` will - *never* go away, though). - - Args: - repr_ns (str): - When using nested classes, there was no way in Python 2 to - automatically detect that. This argument allows to set a custom - name for a more meaningful ``repr`` output. This argument is - pointless in Python 3 and is therefore deprecated. - - .. caution:: - Refer to `attrs.define` for the rest of the parameters, but note that they - can have different defaults. - - Notably, leaving *on_setattr* as `None` will **not** add any hooks. - - .. versionadded:: 16.0.0 *slots* - .. versionadded:: 16.1.0 *frozen* - .. versionadded:: 16.3.0 *str* - .. versionadded:: 16.3.0 Support for ``__attrs_post_init__``. - .. versionchanged:: 17.1.0 - *hash* supports `None` as value which is also the default now. - .. versionadded:: 17.3.0 *auto_attribs* - .. versionchanged:: 18.1.0 - If *these* is passed, no attributes are deleted from the class body. - .. versionchanged:: 18.1.0 If *these* is ordered, the order is retained. - .. versionadded:: 18.2.0 *weakref_slot* - .. deprecated:: 18.2.0 - ``__lt__``, ``__le__``, ``__gt__``, and ``__ge__`` now raise a - `DeprecationWarning` if the classes compared are subclasses of - each other. ``__eq`` and ``__ne__`` never tried to compared subclasses - to each other. - .. versionchanged:: 19.2.0 - ``__lt__``, ``__le__``, ``__gt__``, and ``__ge__`` now do not consider - subclasses comparable anymore. - .. versionadded:: 18.2.0 *kw_only* - .. versionadded:: 18.2.0 *cache_hash* - .. versionadded:: 19.1.0 *auto_exc* - .. deprecated:: 19.2.0 *cmp* Removal on or after 2021-06-01. - .. versionadded:: 19.2.0 *eq* and *order* - .. versionadded:: 20.1.0 *auto_detect* - .. versionadded:: 20.1.0 *collect_by_mro* - .. versionadded:: 20.1.0 *getstate_setstate* - .. versionadded:: 20.1.0 *on_setattr* - .. versionadded:: 20.3.0 *field_transformer* - .. versionchanged:: 21.1.0 - ``init=False`` injects ``__attrs_init__`` - .. versionchanged:: 21.1.0 Support for ``__attrs_pre_init__`` - .. versionchanged:: 21.1.0 *cmp* undeprecated - .. versionadded:: 21.3.0 *match_args* - .. versionadded:: 22.2.0 - *unsafe_hash* as an alias for *hash* (for :pep:`681` compliance). - .. deprecated:: 24.1.0 *repr_ns* - .. versionchanged:: 24.1.0 - Instances are not compared as tuples of attributes anymore, but using a - big ``and`` condition. This is faster and has more correct behavior for - uncomparable values like `math.nan`. - .. versionadded:: 24.1.0 - If a class has an *inherited* classmethod called - ``__attrs_init_subclass__``, it is executed after the class is created. - .. deprecated:: 24.1.0 *hash* is deprecated in favor of *unsafe_hash*. - .. versionchanged:: 25.4.0 - *kw_only* now only applies to attributes defined in the current class, - and respects attribute-level ``kw_only=False`` settings. - .. versionadded:: 25.4.0 *force_kw_only* - """ - if repr_ns is not None: - import warnings - - warnings.warn( - DeprecationWarning( - "The `repr_ns` argument is deprecated and will be removed in or after August 2025." - ), - stacklevel=2, - ) - - eq_, order_ = _determine_attrs_eq_order(cmp, eq, order, None) - - # unsafe_hash takes precedence due to PEP 681. - if unsafe_hash is not None: - hash = unsafe_hash - - if isinstance(on_setattr, (list, tuple)): - on_setattr = setters.pipe(*on_setattr) - - def wrap(cls): - nonlocal hash - is_frozen = frozen or _has_frozen_base_class(cls) - is_exc = auto_exc is True and issubclass(cls, BaseException) - has_own_setattr = auto_detect and _has_own_attribute( - cls, "__setattr__" - ) - - if has_own_setattr and is_frozen: - msg = "Can't freeze a class with a custom __setattr__." - raise ValueError(msg) - - eq = not is_exc and _determine_whether_to_implement( - cls, eq_, auto_detect, ("__eq__", "__ne__") - ) - - Hashability = ClassProps.Hashability - - if is_exc: - hashability = Hashability.LEAVE_ALONE - elif hash is True: - hashability = ( - Hashability.HASHABLE_CACHED - if cache_hash - else Hashability.HASHABLE - ) - elif hash is False: - hashability = Hashability.LEAVE_ALONE - elif hash is None: - if auto_detect is True and _has_own_attribute(cls, "__hash__"): - hashability = Hashability.LEAVE_ALONE - elif eq is True and is_frozen is True: - hashability = ( - Hashability.HASHABLE_CACHED - if cache_hash - else Hashability.HASHABLE - ) - elif eq is False: - hashability = Hashability.LEAVE_ALONE - else: - hashability = Hashability.UNHASHABLE - else: - msg = "Invalid value for hash. Must be True, False, or None." - raise TypeError(msg) - - KeywordOnly = ClassProps.KeywordOnly - if kw_only: - kwo = KeywordOnly.FORCE if force_kw_only else KeywordOnly.YES - else: - kwo = KeywordOnly.NO - - props = ClassProps( - is_exception=is_exc, - is_frozen=is_frozen, - is_slotted=slots, - collected_fields_by_mro=collect_by_mro, - added_init=_determine_whether_to_implement( - cls, init, auto_detect, ("__init__",) - ), - added_repr=_determine_whether_to_implement( - cls, repr, auto_detect, ("__repr__",) - ), - added_eq=eq, - added_ordering=not is_exc - and _determine_whether_to_implement( - cls, - order_, - auto_detect, - ("__lt__", "__le__", "__gt__", "__ge__"), - ), - hashability=hashability, - added_match_args=match_args, - kw_only=kwo, - has_weakref_slot=weakref_slot, - added_str=str, - added_pickling=_determine_whether_to_implement( - cls, - getstate_setstate, - auto_detect, - ("__getstate__", "__setstate__"), - default=slots, - ), - on_setattr_hook=on_setattr, - field_transformer=field_transformer, - ) - - if not props.is_hashable and cache_hash: - msg = "Invalid value for cache_hash. To use hash caching, hashing must be either explicitly or implicitly enabled." - raise TypeError(msg) - - builder = _ClassBuilder( - cls, - these, - auto_attribs=auto_attribs, - props=props, - has_custom_setattr=has_own_setattr, - ) - - if props.added_repr: - builder.add_repr(repr_ns) - - if props.added_str: - builder.add_str() - - if props.added_eq: - builder.add_eq() - if props.added_ordering: - builder.add_order() - - if not frozen: - builder.add_setattr() - - if props.is_hashable: - builder.add_hash() - elif props.hashability is Hashability.UNHASHABLE: - builder.make_unhashable() - - if props.added_init: - builder.add_init() - else: - builder.add_attrs_init() - if cache_hash: - msg = "Invalid value for cache_hash. To use hash caching, init must be True." - raise TypeError(msg) - - if PY_3_13_PLUS and not _has_own_attribute(cls, "__replace__"): - builder.add_replace() - - if ( - PY_3_10_PLUS - and match_args - and not _has_own_attribute(cls, "__match_args__") - ): - builder.add_match_args() - - return builder.build_class() - - # maybe_cls's type depends on the usage of the decorator. It's a class - # if it's used as `@attrs` but `None` if used as `@attrs()`. - if maybe_cls is None: - return wrap - - return wrap(maybe_cls) - - -_attrs = attrs -""" -Internal alias so we can use it in functions that take an argument called -*attrs*. -""" - - -def _has_frozen_base_class(cls): - """ - Check whether *cls* has a frozen ancestor by looking at its - __setattr__. - """ - return cls.__setattr__ is _frozen_setattrs - - -def _generate_unique_filename(cls: type, func_name: str) -> str: - """ - Create a "filename" suitable for a function being generated. - """ - return ( - f"" - ) - - -def _make_hash_script( - cls: type, attrs: list[Attribute], frozen: bool, cache_hash: bool -) -> tuple[str, dict]: - attrs = tuple( - a for a in attrs if a.hash is True or (a.hash is None and a.eq is True) - ) - - tab = " " - - type_hash = hash(_generate_unique_filename(cls, "hash")) - # If eq is custom generated, we need to include the functions in globs - globs = {} - - hash_def = "def __hash__(self" - hash_func = "hash((" - closing_braces = "))" - if not cache_hash: - hash_def += "):" - else: - hash_def += ", *" - - hash_def += ", _cache_wrapper=__import__('attr._make')._make._CacheHashWrapper):" - hash_func = "_cache_wrapper(" + hash_func - closing_braces += ")" - - method_lines = [hash_def] - - def append_hash_computation_lines(prefix, indent): - """ - Generate the code for actually computing the hash code. - Below this will either be returned directly or used to compute - a value which is then cached, depending on the value of cache_hash - """ - - method_lines.extend( - [ - indent + prefix + hash_func, - indent + f" {type_hash},", - ] - ) - - for a in attrs: - if a.eq_key: - cmp_name = f"_{a.name}_key" - globs[cmp_name] = a.eq_key - method_lines.append( - indent + f" {cmp_name}(self.{a.name})," - ) - else: - method_lines.append(indent + f" self.{a.name},") - - method_lines.append(indent + " " + closing_braces) - - if cache_hash: - method_lines.append(tab + f"if self.{_HASH_CACHE_FIELD} is None:") - if frozen: - append_hash_computation_lines( - f"object.__setattr__(self, '{_HASH_CACHE_FIELD}', ", tab * 2 - ) - method_lines.append(tab * 2 + ")") # close __setattr__ - else: - append_hash_computation_lines( - f"self.{_HASH_CACHE_FIELD} = ", tab * 2 - ) - method_lines.append(tab + f"return self.{_HASH_CACHE_FIELD}") - else: - append_hash_computation_lines("return ", tab) - - script = "\n".join(method_lines) - return script, globs - - -def _add_hash(cls: type, attrs: list[Attribute]): - """ - Add a hash method to *cls*. - """ - script, globs = _make_hash_script( - cls, attrs, frozen=False, cache_hash=False - ) - _compile_and_eval( - script, globs, filename=_generate_unique_filename(cls, "__hash__") - ) - cls.__hash__ = globs["__hash__"] - return cls - - -def __ne__(self, other): - """ - Check equality and either forward a NotImplemented or - return the result negated. - """ - result = self.__eq__(other) - if result is NotImplemented: - return NotImplemented - - return not result - - -def _make_eq_script(attrs: list) -> tuple[str, dict]: - """ - Create __eq__ method for *cls* with *attrs*. - """ - attrs = [a for a in attrs if a.eq] - - lines = [ - "def __eq__(self, other):", - " if other.__class__ is not self.__class__:", - " return NotImplemented", - ] - - globs = {} - if attrs: - lines.append(" return (") - for a in attrs: - if a.eq_key: - cmp_name = f"_{a.name}_key" - # Add the key function to the global namespace - # of the evaluated function. - globs[cmp_name] = a.eq_key - lines.append( - f" {cmp_name}(self.{a.name}) == {cmp_name}(other.{a.name})" - ) - else: - lines.append(f" self.{a.name} == other.{a.name}") - if a is not attrs[-1]: - lines[-1] = f"{lines[-1]} and" - lines.append(" )") - else: - lines.append(" return True") - - script = "\n".join(lines) - - return script, globs - - -def _make_order(cls, attrs): - """ - Create ordering methods for *cls* with *attrs*. - """ - attrs = [a for a in attrs if a.order] - - def attrs_to_tuple(obj): - """ - Save us some typing. - """ - return tuple( - key(value) if key else value - for value, key in ( - (getattr(obj, a.name), a.order_key) for a in attrs - ) - ) - - def __lt__(self, other): - """ - Automatically created by attrs. - """ - if other.__class__ is self.__class__: - return attrs_to_tuple(self) < attrs_to_tuple(other) - - return NotImplemented - - def __le__(self, other): - """ - Automatically created by attrs. - """ - if other.__class__ is self.__class__: - return attrs_to_tuple(self) <= attrs_to_tuple(other) - - return NotImplemented - - def __gt__(self, other): - """ - Automatically created by attrs. - """ - if other.__class__ is self.__class__: - return attrs_to_tuple(self) > attrs_to_tuple(other) - - return NotImplemented - - def __ge__(self, other): - """ - Automatically created by attrs. - """ - if other.__class__ is self.__class__: - return attrs_to_tuple(self) >= attrs_to_tuple(other) - - return NotImplemented - - return __lt__, __le__, __gt__, __ge__ - - -def _add_eq(cls, attrs=None): - """ - Add equality methods to *cls* with *attrs*. - """ - if attrs is None: - attrs = cls.__attrs_attrs__ - - script, globs = _make_eq_script(attrs) - _compile_and_eval( - script, globs, filename=_generate_unique_filename(cls, "__eq__") - ) - cls.__eq__ = globs["__eq__"] - cls.__ne__ = __ne__ - - return cls - - -def _make_repr_script(attrs, ns) -> tuple[str, dict]: - """ - Create the source and globs for a __repr__ and return it. - """ - # Figure out which attributes to include, and which function to use to - # format them. The a.repr value can be either bool or a custom - # callable. - attr_names_with_reprs = tuple( - (a.name, (repr if a.repr is True else a.repr), a.init) - for a in attrs - if a.repr is not False - ) - globs = { - name + "_repr": r for name, r, _ in attr_names_with_reprs if r != repr - } - globs["_compat"] = _compat - globs["AttributeError"] = AttributeError - globs["NOTHING"] = NOTHING - attribute_fragments = [] - for name, r, i in attr_names_with_reprs: - accessor = ( - "self." + name if i else 'getattr(self, "' + name + '", NOTHING)' - ) - fragment = ( - "%s={%s!r}" % (name, accessor) - if r == repr - else "%s={%s_repr(%s)}" % (name, name, accessor) - ) - attribute_fragments.append(fragment) - repr_fragment = ", ".join(attribute_fragments) - - if ns is None: - cls_name_fragment = '{self.__class__.__qualname__.rsplit(">.", 1)[-1]}' - else: - cls_name_fragment = ns + ".{self.__class__.__name__}" - - lines = [ - "def __repr__(self):", - " try:", - " already_repring = _compat.repr_context.already_repring", - " except AttributeError:", - " already_repring = {id(self),}", - " _compat.repr_context.already_repring = already_repring", - " else:", - " if id(self) in already_repring:", - " return '...'", - " else:", - " already_repring.add(id(self))", - " try:", - f" return f'{cls_name_fragment}({repr_fragment})'", - " finally:", - " already_repring.remove(id(self))", - ] - - return "\n".join(lines), globs - - -def _add_repr(cls, ns=None, attrs=None): - """ - Add a repr method to *cls*. - """ - if attrs is None: - attrs = cls.__attrs_attrs__ - - script, globs = _make_repr_script(attrs, ns) - _compile_and_eval( - script, globs, filename=_generate_unique_filename(cls, "__repr__") - ) - cls.__repr__ = globs["__repr__"] - return cls - - -def fields(cls): - """ - Return the tuple of *attrs* attributes for a class or instance. - - The tuple also allows accessing the fields by their names (see below for - examples). - - Args: - cls (type): Class or instance to introspect. - - Raises: - TypeError: If *cls* is neither a class nor an *attrs* instance. - - attrs.exceptions.NotAnAttrsClassError: - If *cls* is not an *attrs* class. - - Returns: - tuple (with name accessors) of `attrs.Attribute` - - .. versionchanged:: 16.2.0 Returned tuple allows accessing the fields - by name. - .. versionchanged:: 23.1.0 Add support for generic classes. - .. versionchanged:: 26.1.0 Add support for instances. - """ - generic_base = get_generic_base(cls) - - if generic_base is None and not isinstance(cls, type): - type_ = type(cls) - if getattr(type_, "__attrs_attrs__", None) is None: - msg = "Passed object must be a class or attrs instance." - raise TypeError(msg) - - return fields(type_) - - attrs = getattr(cls, "__attrs_attrs__", None) - - if attrs is None: - if generic_base is not None: - attrs = getattr(generic_base, "__attrs_attrs__", None) - if attrs is not None: - # Even though this is global state, stick it on here to speed - # it up. We rely on `cls` being cached for this to be - # efficient. - cls.__attrs_attrs__ = attrs - return attrs - msg = f"{cls!r} is not an attrs-decorated class." - raise NotAnAttrsClassError(msg) - - return attrs - - -def fields_dict(cls): - """ - Return an ordered dictionary of *attrs* attributes for a class, whose keys - are the attribute names. - - Args: - cls (type): Class to introspect. - - Raises: - TypeError: If *cls* is not a class. - - attrs.exceptions.NotAnAttrsClassError: - If *cls* is not an *attrs* class. - - Returns: - dict[str, attrs.Attribute]: Dict of attribute name to definition - - .. versionadded:: 18.1.0 - """ - if not isinstance(cls, type): - msg = "Passed object must be a class." - raise TypeError(msg) - attrs = getattr(cls, "__attrs_attrs__", None) - if attrs is None: - msg = f"{cls!r} is not an attrs-decorated class." - raise NotAnAttrsClassError(msg) - return {a.name: a for a in attrs} - - -def validate(inst): - """ - Validate all attributes on *inst* that have a validator. - - Leaves all exceptions through. - - Args: - inst: Instance of a class with *attrs* attributes. - """ - if _config._run_validators is False: - return - - for a in fields(inst.__class__): - v = a.validator - if v is not None: - v(inst, a, getattr(inst, a.name)) - - -def _is_slot_attr(a_name, base_attr_map): - """ - Check if the attribute name comes from a slot class. - """ - cls = base_attr_map.get(a_name) - return cls and "__slots__" in cls.__dict__ - - -def _make_init_script( - cls, - attrs, - pre_init, - pre_init_has_args, - post_init, - frozen, - slots, - cache_hash, - base_attr_map, - is_exc, - cls_on_setattr, - attrs_init, -) -> tuple[str, dict, dict]: - has_cls_on_setattr = ( - cls_on_setattr is not None and cls_on_setattr is not setters.NO_OP - ) - - if frozen and has_cls_on_setattr: - msg = "Frozen classes can't use on_setattr." - raise ValueError(msg) - - needs_cached_setattr = cache_hash or frozen - filtered_attrs = [] - attr_dict = {} - for a in attrs: - if not a.init and a.default is NOTHING: - continue - - filtered_attrs.append(a) - attr_dict[a.name] = a - - if a.on_setattr is not None: - if frozen is True and a.on_setattr is not setters.NO_OP: - msg = "Frozen classes can't use on_setattr." - raise ValueError(msg) - - needs_cached_setattr = True - elif has_cls_on_setattr and a.on_setattr is not setters.NO_OP: - needs_cached_setattr = True - - script, globs, annotations = _attrs_to_init_script( - filtered_attrs, - frozen, - slots, - pre_init, - pre_init_has_args, - post_init, - cache_hash, - base_attr_map, - is_exc, - needs_cached_setattr, - has_cls_on_setattr, - "__attrs_init__" if attrs_init else "__init__", - ) - if cls.__module__ in sys.modules: - # This makes typing.get_type_hints(CLS.__init__) resolve string types. - globs.update(sys.modules[cls.__module__].__dict__) - - globs.update({"NOTHING": NOTHING, "attr_dict": attr_dict}) - - if needs_cached_setattr: - # Save the lookup overhead in __init__ if we need to circumvent - # setattr hooks. - globs["_cached_setattr_get"] = _OBJ_SETATTR.__get__ - - return script, globs, annotations - - -def _setattr(attr_name: str, value_var: str, has_on_setattr: bool) -> str: - """ - Use the cached object.setattr to set *attr_name* to *value_var*. - """ - return f"_setattr('{attr_name}', {value_var})" - - -def _setattr_with_converter( - attr_name: str, value_var: str, has_on_setattr: bool, converter: Converter -) -> str: - """ - Use the cached object.setattr to set *attr_name* to *value_var*, but run - its converter first. - """ - return f"_setattr('{attr_name}', {converter._fmt_converter_call(attr_name, value_var)})" - - -def _assign(attr_name: str, value: str, has_on_setattr: bool) -> str: - """ - Unless *attr_name* has an on_setattr hook, use normal assignment. Otherwise - relegate to _setattr. - """ - if has_on_setattr: - return _setattr(attr_name, value, True) - - return f"self.{attr_name} = {value}" - - -def _assign_with_converter( - attr_name: str, value_var: str, has_on_setattr: bool, converter: Converter -) -> str: - """ - Unless *attr_name* has an on_setattr hook, use normal assignment after - conversion. Otherwise relegate to _setattr_with_converter. - """ - if has_on_setattr: - return _setattr_with_converter(attr_name, value_var, True, converter) - - return f"self.{attr_name} = {converter._fmt_converter_call(attr_name, value_var)}" - - -def _determine_setters( - frozen: bool, slots: bool, base_attr_map: dict[str, type] -): - """ - Determine the correct setter functions based on whether a class is frozen - and/or slotted. - """ - if frozen is True: - if slots is True: - return (), _setattr, _setattr_with_converter - - # Dict frozen classes assign directly to __dict__. - # But only if the attribute doesn't come from an ancestor slot - # class. - # Note _inst_dict will be used again below if cache_hash is True - - def fmt_setter( - attr_name: str, value_var: str, has_on_setattr: bool - ) -> str: - if _is_slot_attr(attr_name, base_attr_map): - return _setattr(attr_name, value_var, has_on_setattr) - - return f"_inst_dict['{attr_name}'] = {value_var}" - - def fmt_setter_with_converter( - attr_name: str, - value_var: str, - has_on_setattr: bool, - converter: Converter, - ) -> str: - if has_on_setattr or _is_slot_attr(attr_name, base_attr_map): - return _setattr_with_converter( - attr_name, value_var, has_on_setattr, converter - ) - - return f"_inst_dict['{attr_name}'] = {converter._fmt_converter_call(attr_name, value_var)}" - - return ( - ("_inst_dict = self.__dict__",), - fmt_setter, - fmt_setter_with_converter, - ) - - # Not frozen -- we can just assign directly. - return (), _assign, _assign_with_converter - - -def _attrs_to_init_script( - attrs: list[Attribute], - is_frozen: bool, - is_slotted: bool, - call_pre_init: bool, - pre_init_has_args: bool, - call_post_init: bool, - does_cache_hash: bool, - base_attr_map: dict[str, type], - is_exc: bool, - needs_cached_setattr: bool, - has_cls_on_setattr: bool, - method_name: str, -) -> tuple[str, dict, dict]: - """ - Return a script of an initializer for *attrs*, a dict of globals, and - annotations for the initializer. - - The globals are required by the generated script. - """ - lines = ["self.__attrs_pre_init__()"] if call_pre_init else [] - - if needs_cached_setattr: - lines.append( - # Circumvent the __setattr__ descriptor to save one lookup per - # assignment. Note _setattr will be used again below if - # does_cache_hash is True. - "_setattr = _cached_setattr_get(self)" - ) - - extra_lines, fmt_setter, fmt_setter_with_converter = _determine_setters( - is_frozen, is_slotted, base_attr_map - ) - lines.extend(extra_lines) - - args = [] # Parameters in the definition of __init__ - pre_init_args = [] # Parameters in the call to __attrs_pre_init__ - kw_only_args = [] # Used for both 'args' and 'pre_init_args' above - attrs_to_validate = [] - - # This is a dictionary of names to validator and converter callables. - # Injecting this into __init__ globals lets us avoid lookups. - names_for_globals = {} - annotations = {"return": None} - - for a in attrs: - if a.validator: - attrs_to_validate.append(a) - - attr_name = a.name - has_on_setattr = a.on_setattr is not None or ( - a.on_setattr is not setters.NO_OP and has_cls_on_setattr - ) - # a.alias is set to maybe-mangled attr_name in _ClassBuilder if not - # explicitly provided - arg_name = a.alias - - has_factory = isinstance(a.default, Factory) - maybe_self = "self" if has_factory and a.default.takes_self else "" - - if a.converter is not None and not isinstance(a.converter, Converter): - converter = Converter(a.converter) - else: - converter = a.converter - - if a.init is False: - if has_factory: - init_factory_name = _INIT_FACTORY_PAT % (a.name,) - if converter is not None: - lines.append( - fmt_setter_with_converter( - attr_name, - init_factory_name + f"({maybe_self})", - has_on_setattr, - converter, - ) - ) - names_for_globals[converter._get_global_name(a.name)] = ( - converter.converter - ) - else: - lines.append( - fmt_setter( - attr_name, - init_factory_name + f"({maybe_self})", - has_on_setattr, - ) - ) - names_for_globals[init_factory_name] = a.default.factory - elif converter is not None: - lines.append( - fmt_setter_with_converter( - attr_name, - f"attr_dict['{attr_name}'].default", - has_on_setattr, - converter, - ) - ) - names_for_globals[converter._get_global_name(a.name)] = ( - converter.converter - ) - else: - lines.append( - fmt_setter( - attr_name, - f"attr_dict['{attr_name}'].default", - has_on_setattr, - ) - ) - elif a.default is not NOTHING and not has_factory: - arg = f"{arg_name}=attr_dict['{attr_name}'].default" - if a.kw_only: - kw_only_args.append(arg) - else: - args.append(arg) - pre_init_args.append(arg_name) - - if converter is not None: - lines.append( - fmt_setter_with_converter( - attr_name, arg_name, has_on_setattr, converter - ) - ) - names_for_globals[converter._get_global_name(a.name)] = ( - converter.converter - ) - else: - lines.append(fmt_setter(attr_name, arg_name, has_on_setattr)) - - elif has_factory: - arg = f"{arg_name}=NOTHING" - if a.kw_only: - kw_only_args.append(arg) - else: - args.append(arg) - pre_init_args.append(arg_name) - lines.append(f"if {arg_name} is not NOTHING:") - - init_factory_name = _INIT_FACTORY_PAT % (a.name,) - if converter is not None: - lines.append( - " " - + fmt_setter_with_converter( - attr_name, arg_name, has_on_setattr, converter - ) - ) - lines.append("else:") - lines.append( - " " - + fmt_setter_with_converter( - attr_name, - init_factory_name + "(" + maybe_self + ")", - has_on_setattr, - converter, - ) - ) - names_for_globals[converter._get_global_name(a.name)] = ( - converter.converter - ) - else: - lines.append( - " " + fmt_setter(attr_name, arg_name, has_on_setattr) - ) - lines.append("else:") - lines.append( - " " - + fmt_setter( - attr_name, - init_factory_name + "(" + maybe_self + ")", - has_on_setattr, - ) - ) - names_for_globals[init_factory_name] = a.default.factory - else: - if a.kw_only: - kw_only_args.append(arg_name) - else: - args.append(arg_name) - pre_init_args.append(arg_name) - - if converter is not None: - lines.append( - fmt_setter_with_converter( - attr_name, arg_name, has_on_setattr, converter - ) - ) - names_for_globals[converter._get_global_name(a.name)] = ( - converter.converter - ) - else: - lines.append(fmt_setter(attr_name, arg_name, has_on_setattr)) - - if a.init is True: - if a.type is not None and converter is None: - annotations[arg_name] = a.type - elif converter is not None and converter._first_param_type: - # Use the type from the converter if present. - annotations[arg_name] = converter._first_param_type - - if attrs_to_validate: # we can skip this if there are no validators. - names_for_globals["_config"] = _config - lines.append("if _config._run_validators is True:") - for a in attrs_to_validate: - val_name = "__attr_validator_" + a.name - attr_name = "__attr_" + a.name - lines.append(f" {val_name}(self, {attr_name}, self.{a.name})") - names_for_globals[val_name] = a.validator - names_for_globals[attr_name] = a - - if call_post_init: - lines.append("self.__attrs_post_init__()") - - # Because this is set only after __attrs_post_init__ is called, a crash - # will result if post-init tries to access the hash code. This seemed - # preferable to setting this beforehand, in which case alteration to field - # values during post-init combined with post-init accessing the hash code - # would result in silent bugs. - if does_cache_hash: - if is_frozen: - if is_slotted: - init_hash_cache = f"_setattr('{_HASH_CACHE_FIELD}', None)" - else: - init_hash_cache = f"_inst_dict['{_HASH_CACHE_FIELD}'] = None" - else: - init_hash_cache = f"self.{_HASH_CACHE_FIELD} = None" - lines.append(init_hash_cache) - - # For exceptions we rely on BaseException.__init__ for proper - # initialization. - if is_exc: - vals = ",".join(f"self.{a.name}" for a in attrs if a.init) - - lines.append(f"BaseException.__init__(self, {vals})") - - args = ", ".join(args) - pre_init_args = ", ".join(pre_init_args) - if kw_only_args: - # leading comma & kw_only args - args += f"{', ' if args else ''}*, {', '.join(kw_only_args)}" - pre_init_kw_only_args = ", ".join( - [ - f"{kw_arg_name}={kw_arg_name}" - # We need to remove the defaults from the kw_only_args. - for kw_arg_name in (kwa.split("=")[0] for kwa in kw_only_args) - ] - ) - pre_init_args += ", " if pre_init_args else "" - pre_init_args += pre_init_kw_only_args - - if call_pre_init and pre_init_has_args: - # If pre init method has arguments, pass the values given to __init__. - lines[0] = f"self.__attrs_pre_init__({pre_init_args})" - - # Python <3.12 doesn't allow backslashes in f-strings. - NL = "\n " - return ( - f"""def {method_name}(self, {args}): - {NL.join(lines) if lines else "pass"} -""", - names_for_globals, - annotations, - ) - - -def _default_init_alias_for(name: str) -> str: - """ - The default __init__ parameter name for a field. - - This performs private-name adjustment via leading-unscore stripping, - and is the default value of Attribute.alias if not provided. - """ - - return name.lstrip("_") - - -class Attribute: - """ - *Read-only* representation of an attribute. - - .. warning:: - - You should never instantiate this class yourself. - - The class has *all* arguments of `attr.ib` (except for ``factory`` which is - only syntactic sugar for ``default=Factory(...)`` plus the following: - - - ``name`` (`str`): The name of the attribute. - - ``alias`` (`str`): The __init__ parameter name of the attribute, after - any explicit overrides and default private-attribute-name handling. - - ``alias_is_default`` (`bool`): Whether the ``alias`` was automatically - generated (``True``) or explicitly provided by the user (``False``). - - ``inherited`` (`bool`): Whether or not that attribute has been inherited - from a base class. - - ``eq_key`` and ``order_key`` (`typing.Callable` or `None`): The - callables that are used for comparing and ordering objects by this - attribute, respectively. These are set by passing a callable to - `attr.ib`'s ``eq``, ``order``, or ``cmp`` arguments. See also - :ref:`comparison customization `. - - Instances of this class are frequently used for introspection purposes - like: - - - `fields` returns a tuple of them. - - Validators get them passed as the first argument. - - The :ref:`field transformer ` hook receives a list of - them. - - The ``alias`` property exposes the __init__ parameter name of the field, - with any overrides and default private-attribute handling applied. - - - .. versionadded:: 20.1.0 *inherited* - .. versionadded:: 20.1.0 *on_setattr* - .. versionchanged:: 20.2.0 *inherited* is not taken into account for - equality checks and hashing anymore. - .. versionadded:: 21.1.0 *eq_key* and *order_key* - .. versionadded:: 22.2.0 *alias* - .. versionadded:: 26.1.0 *alias_is_default* - - For the full version history of the fields, see `attr.ib`. - """ - - # These slots must NOT be reordered because we use them later for - # instantiation. - __slots__ = ( # noqa: RUF023 - "name", - "default", - "validator", - "repr", - "eq", - "eq_key", - "order", - "order_key", - "hash", - "init", - "metadata", - "type", - "converter", - "kw_only", - "inherited", - "on_setattr", - "alias", - "alias_is_default", - ) - - def __init__( - self, - name, - default, - validator, - repr, - cmp, # XXX: unused, remove along with other cmp code. - hash, - init, - inherited, - metadata=None, - type=None, - converter=None, - kw_only=False, - eq=None, - eq_key=None, - order=None, - order_key=None, - on_setattr=None, - alias=None, - alias_is_default=None, - ): - eq, eq_key, order, order_key = _determine_attrib_eq_order( - cmp, eq_key or eq, order_key or order, True - ) - - # Cache this descriptor here to speed things up later. - bound_setattr = _OBJ_SETATTR.__get__(self) - - # Despite the big red warning, people *do* instantiate `Attribute` - # themselves. - bound_setattr("name", name) - bound_setattr("default", default) - bound_setattr("validator", validator) - bound_setattr("repr", repr) - bound_setattr("eq", eq) - bound_setattr("eq_key", eq_key) - bound_setattr("order", order) - bound_setattr("order_key", order_key) - bound_setattr("hash", hash) - bound_setattr("init", init) - bound_setattr("converter", converter) - bound_setattr( - "metadata", - ( - types.MappingProxyType(dict(metadata)) # Shallow copy - if metadata - else _EMPTY_METADATA_SINGLETON - ), - ) - bound_setattr("type", type) - bound_setattr("kw_only", kw_only) - bound_setattr("inherited", inherited) - bound_setattr("on_setattr", on_setattr) - bound_setattr("alias", alias) - bound_setattr( - "alias_is_default", - alias is None if alias_is_default is None else alias_is_default, - ) - - def __setattr__(self, name, value): - raise FrozenInstanceError - - @classmethod - def from_counting_attr( - cls, name: str, ca: _CountingAttr, kw_only: bool, type=None - ): - # The 'kw_only' argument is the class-level setting, and is used if the - # attribute itself does not explicitly set 'kw_only'. - # type holds the annotated value. deal with conflicts: - if type is None: - type = ca.type - elif ca.type is not None: - msg = f"Type annotation and type argument cannot both be present for '{name}'." - raise ValueError(msg) - return cls( - name, - ca._default, - ca._validator, - ca.repr, - None, - ca.hash, - ca.init, - False, - ca.metadata, - type, - ca.converter, - kw_only if ca.kw_only is None else ca.kw_only, - ca.eq, - ca.eq_key, - ca.order, - ca.order_key, - ca.on_setattr, - ca.alias, - ca.alias is None, - ) - - # Don't use attrs.evolve since fields(Attribute) doesn't work - def evolve(self, **changes): - """ - Copy *self* and apply *changes*. - - This works similarly to `attrs.evolve` but that function does not work - with :class:`attrs.Attribute`. - - It is mainly meant to be used for `transform-fields`. - - .. versionadded:: 20.3.0 - """ - new = copy.copy(self) - - new._setattrs(changes.items()) - - if "alias" in changes and "alias_is_default" not in changes: - # Explicit alias provided -- no longer the default. - _OBJ_SETATTR.__get__(new)("alias_is_default", False) - elif ( - "name" in changes - and "alias" not in changes - # Don't auto-generate alias if the user picked picked the old one. - and self.alias_is_default - ): - # Name changed, alias was auto-generated -- update it. - _OBJ_SETATTR.__get__(new)( - "alias", _default_init_alias_for(new.name) - ) - - return new - - # Don't use _add_pickle since fields(Attribute) doesn't work - def __getstate__(self): - """ - Play nice with pickle. - """ - return tuple( - getattr(self, name) if name != "metadata" else dict(self.metadata) - for name in self.__slots__ - ) - - def __setstate__(self, state): - """ - Play nice with pickle. - """ - if len(state) < len(self.__slots__): - # Pre-26.1.0 pickle without alias_is_default -- infer it - # heuristically. - state_dict = dict(zip(self.__slots__, state)) - alias_is_default = state_dict.get( - "alias" - ) is None or state_dict.get("alias") == _default_init_alias_for( - state_dict["name"] - ) - state = (*state, alias_is_default) - - self._setattrs(zip(self.__slots__, state)) - - def _setattrs(self, name_values_pairs): - bound_setattr = _OBJ_SETATTR.__get__(self) - for name, value in name_values_pairs: - if name != "metadata": - bound_setattr(name, value) - else: - bound_setattr( - name, - ( - types.MappingProxyType(dict(value)) - if value - else _EMPTY_METADATA_SINGLETON - ), - ) - - -_a = [ - Attribute( - name=name, - default=NOTHING, - validator=None, - repr=(name != "alias_is_default"), - cmp=None, - eq=True, - order=False, - hash=(name != "metadata"), - init=True, - inherited=False, - alias=_default_init_alias_for(name), - ) - for name in Attribute.__slots__ -] - -Attribute = _add_hash( - _add_eq( - _add_repr(Attribute, attrs=_a), - attrs=[a for a in _a if a.name != "inherited"], - ), - attrs=[a for a in _a if a.hash and a.name != "inherited"], -) - - -class _CountingAttr: - """ - Intermediate representation of attributes that uses a counter to preserve - the order in which the attributes have been defined. - - *Internal* data structure of the attrs library. Running into is most - likely the result of a bug like a forgotten `@attr.s` decorator. - """ - - __slots__ = ( - "_default", - "_validator", - "alias", - "converter", - "counter", - "eq", - "eq_key", - "hash", - "init", - "kw_only", - "metadata", - "on_setattr", - "order", - "order_key", - "repr", - "type", - ) - __attrs_attrs__ = ( - *tuple( - Attribute( - name=name, - alias=_default_init_alias_for(name), - default=NOTHING, - validator=None, - repr=True, - cmp=None, - hash=True, - init=True, - kw_only=False, - eq=True, - eq_key=None, - order=False, - order_key=None, - inherited=False, - on_setattr=None, - ) - for name in ( - "counter", - "_default", - "repr", - "eq", - "order", - "hash", - "init", - "on_setattr", - "alias", - ) - ), - Attribute( - name="metadata", - alias="metadata", - default=None, - validator=None, - repr=True, - cmp=None, - hash=False, - init=True, - kw_only=False, - eq=True, - eq_key=None, - order=False, - order_key=None, - inherited=False, - on_setattr=None, - ), - ) - cls_counter = 0 - - def __init__( - self, - default, - validator, - repr, - cmp, - hash, - init, - converter, - metadata, - type, - kw_only, - eq, - eq_key, - order, - order_key, - on_setattr, - alias, - ): - _CountingAttr.cls_counter += 1 - self.counter = _CountingAttr.cls_counter - self._default = default - self._validator = validator - self.converter = converter - self.repr = repr - self.eq = eq - self.eq_key = eq_key - self.order = order - self.order_key = order_key - self.hash = hash - self.init = init - self.metadata = metadata - self.type = type - self.kw_only = kw_only - self.on_setattr = on_setattr - self.alias = alias - - def validator(self, meth): - """ - Decorator that adds *meth* to the list of validators. - - Returns *meth* unchanged. - - .. versionadded:: 17.1.0 - """ - if self._validator is None: - self._validator = meth - else: - self._validator = and_(self._validator, meth) - return meth - - def default(self, meth): - """ - Decorator that allows to set the default for an attribute. - - Returns *meth* unchanged. - - Raises: - DefaultAlreadySetError: If default has been set before. - - .. versionadded:: 17.1.0 - """ - if self._default is not NOTHING: - raise DefaultAlreadySetError - - self._default = Factory(meth, takes_self=True) - - return meth - - -_CountingAttr = _add_eq(_add_repr(_CountingAttr)) - - -class ClassProps: - """ - Effective class properties as derived from parameters to `attr.s()` or - `define()` decorators. - - This is the same data structure that *attrs* uses internally to decide how - to construct the final class. - - Warning: - - This feature is currently **experimental** and is not covered by our - strict backwards-compatibility guarantees. - - - Attributes: - is_exception (bool): - Whether the class is treated as an exception class. - - is_slotted (bool): - Whether the class is `slotted `. - - has_weakref_slot (bool): - Whether the class has a slot for weak references. - - is_frozen (bool): - Whether the class is frozen. - - kw_only (KeywordOnly): - Whether / how the class enforces keyword-only arguments on the - ``__init__`` method. - - collected_fields_by_mro (bool): - Whether the class fields were collected by method resolution order. - That is, correctly but unlike `dataclasses`. - - added_init (bool): - Whether the class has an *attrs*-generated ``__init__`` method. - - added_repr (bool): - Whether the class has an *attrs*-generated ``__repr__`` method. - - added_eq (bool): - Whether the class has *attrs*-generated equality methods. - - added_ordering (bool): - Whether the class has *attrs*-generated ordering methods. - - hashability (Hashability): How `hashable ` the class is. - - added_match_args (bool): - Whether the class supports positional `match ` over its - fields. - - added_str (bool): - Whether the class has an *attrs*-generated ``__str__`` method. - - added_pickling (bool): - Whether the class has *attrs*-generated ``__getstate__`` and - ``__setstate__`` methods for `pickle`. - - on_setattr_hook (Callable[[Any, Attribute[Any], Any], Any] | None): - The class's ``__setattr__`` hook. - - field_transformer (Callable[[Attribute[Any]], Attribute[Any]] | None): - The class's `field transformers `. - - .. versionadded:: 25.4.0 - """ - - class Hashability(enum.Enum): - """ - The hashability of a class. - - .. versionadded:: 25.4.0 - """ - - HASHABLE = "hashable" - """Write a ``__hash__``.""" - HASHABLE_CACHED = "hashable_cache" - """Write a ``__hash__`` and cache the hash.""" - UNHASHABLE = "unhashable" - """Set ``__hash__`` to ``None``.""" - LEAVE_ALONE = "leave_alone" - """Don't touch ``__hash__``.""" - - class KeywordOnly(enum.Enum): - """ - How attributes should be treated regarding keyword-only parameters. - - .. versionadded:: 25.4.0 - """ - - NO = "no" - """Attributes are not keyword-only.""" - YES = "yes" - """Attributes in current class without kw_only=False are keyword-only.""" - FORCE = "force" - """All attributes are keyword-only.""" - - __slots__ = ( # noqa: RUF023 -- order matters for __init__ - "is_exception", - "is_slotted", - "has_weakref_slot", - "is_frozen", - "kw_only", - "collected_fields_by_mro", - "added_init", - "added_repr", - "added_eq", - "added_ordering", - "hashability", - "added_match_args", - "added_str", - "added_pickling", - "on_setattr_hook", - "field_transformer", - ) - - def __init__( - self, - is_exception, - is_slotted, - has_weakref_slot, - is_frozen, - kw_only, - collected_fields_by_mro, - added_init, - added_repr, - added_eq, - added_ordering, - hashability, - added_match_args, - added_str, - added_pickling, - on_setattr_hook, - field_transformer, - ): - self.is_exception = is_exception - self.is_slotted = is_slotted - self.has_weakref_slot = has_weakref_slot - self.is_frozen = is_frozen - self.kw_only = kw_only - self.collected_fields_by_mro = collected_fields_by_mro - self.added_init = added_init - self.added_repr = added_repr - self.added_eq = added_eq - self.added_ordering = added_ordering - self.hashability = hashability - self.added_match_args = added_match_args - self.added_str = added_str - self.added_pickling = added_pickling - self.on_setattr_hook = on_setattr_hook - self.field_transformer = field_transformer - - @property - def is_hashable(self): - return ( - self.hashability is ClassProps.Hashability.HASHABLE - or self.hashability is ClassProps.Hashability.HASHABLE_CACHED - ) - - -_cas = [ - Attribute( - name=name, - default=NOTHING, - validator=None, - repr=True, - cmp=None, - eq=True, - order=False, - hash=True, - init=True, - inherited=False, - alias=_default_init_alias_for(name), - ) - for name in ClassProps.__slots__ -] - -ClassProps = _add_eq(_add_repr(ClassProps, attrs=_cas), attrs=_cas) - - -class Factory: - """ - Stores a factory callable. - - If passed as the default value to `attrs.field`, the factory is used to - generate a new value. - - Args: - factory (typing.Callable): - A callable that takes either none or exactly one mandatory - positional argument depending on *takes_self*. - - takes_self (bool): - Pass the partially initialized instance that is being initialized - as a positional argument. - - .. versionadded:: 17.1.0 *takes_self* - """ - - __slots__ = ("factory", "takes_self") - - def __init__(self, factory, takes_self=False): - self.factory = factory - self.takes_self = takes_self - - def __getstate__(self): - """ - Play nice with pickle. - """ - return tuple(getattr(self, name) for name in self.__slots__) - - def __setstate__(self, state): - """ - Play nice with pickle. - """ - for name, value in zip(self.__slots__, state): - setattr(self, name, value) - - -_f = [ - Attribute( - name=name, - default=NOTHING, - validator=None, - repr=True, - cmp=None, - eq=True, - order=False, - hash=True, - init=True, - inherited=False, - ) - for name in Factory.__slots__ -] - -Factory = _add_hash(_add_eq(_add_repr(Factory, attrs=_f), attrs=_f), attrs=_f) - - -class Converter: - """ - Stores a converter callable. - - Allows for the wrapped converter to take additional arguments. The - arguments are passed in the order they are documented. - - Args: - converter (Callable): A callable that converts the passed value. - - takes_self (bool): - Pass the partially initialized instance that is being initialized - as a positional argument. (default: `False`) - - takes_field (bool): - Pass the field definition (an :class:`Attribute`) into the - converter as a positional argument. (default: `False`) - - .. versionadded:: 24.1.0 - """ - - __slots__ = ( - "__call__", - "_first_param_type", - "_global_name", - "converter", - "takes_field", - "takes_self", - ) - - def __init__(self, converter, *, takes_self=False, takes_field=False): - self.converter = converter - self.takes_self = takes_self - self.takes_field = takes_field - - ex = _AnnotationExtractor(converter) - self._first_param_type = ex.get_first_param_type() - - if not (self.takes_self or self.takes_field): - self.__call__ = lambda value, _, __: self.converter(value) - elif self.takes_self and not self.takes_field: - self.__call__ = lambda value, instance, __: self.converter( - value, instance - ) - elif not self.takes_self and self.takes_field: - self.__call__ = lambda value, __, field: self.converter( - value, field - ) - else: - self.__call__ = self.converter - - rt = ex.get_return_type() - if rt is not None: - self.__call__.__annotations__["return"] = rt - - @staticmethod - def _get_global_name(attr_name: str) -> str: - """ - Return the name that a converter for an attribute name *attr_name* - would have. - """ - return f"__attr_converter_{attr_name}" - - def _fmt_converter_call(self, attr_name: str, value_var: str) -> str: - """ - Return a string that calls the converter for an attribute name - *attr_name* and the value in variable named *value_var* according to - `self.takes_self` and `self.takes_field`. - """ - if not (self.takes_self or self.takes_field): - return f"{self._get_global_name(attr_name)}({value_var})" - - if self.takes_self and self.takes_field: - return f"{self._get_global_name(attr_name)}({value_var}, self, attr_dict['{attr_name}'])" - - if self.takes_self: - return f"{self._get_global_name(attr_name)}({value_var}, self)" - - return f"{self._get_global_name(attr_name)}({value_var}, attr_dict['{attr_name}'])" - - def __getstate__(self): - """ - Return a dict containing only converter and takes_self -- the rest gets - computed when loading. - """ - return { - "converter": self.converter, - "takes_self": self.takes_self, - "takes_field": self.takes_field, - } - - def __setstate__(self, state): - """ - Load instance from state. - """ - self.__init__(**state) - - -_f = [ - Attribute( - name=name, - default=NOTHING, - validator=None, - repr=True, - cmp=None, - eq=True, - order=False, - hash=True, - init=True, - inherited=False, - ) - for name in ("converter", "takes_self", "takes_field") -] - -Converter = _add_hash( - _add_eq(_add_repr(Converter, attrs=_f), attrs=_f), attrs=_f -) - - -def make_class( - name, attrs, bases=(object,), class_body=None, **attributes_arguments -): - r""" - A quick way to create a new class called *name* with *attrs*. - - .. note:: - - ``make_class()`` is a thin wrapper around `attr.s`, not `attrs.define` - which means that it doesn't come with some of the improved defaults. - - For example, if you want the same ``on_setattr`` behavior as in - `attrs.define`, you have to pass the hooks yourself: ``make_class(..., - on_setattr=setters.pipe(setters.convert, setters.validate)`` - - .. warning:: - - It is *your* duty to ensure that the class name and the attribute names - are valid identifiers. ``make_class()`` will *not* validate them for - you. - - Args: - name (str): The name for the new class. - - attrs (list | dict): - A list of names or a dictionary of mappings of names to `attr.ib`\ - s / `attrs.field`\ s. - - The order is deduced from the order of the names or attributes - inside *attrs*. Otherwise the order of the definition of the - attributes is used. - - bases (tuple[type, ...]): Classes that the new class will subclass. - - class_body (dict): - An optional dictionary of class attributes for the new class. - - attributes_arguments: Passed unmodified to `attr.s`. - - Returns: - type: A new class with *attrs*. - - .. versionadded:: 17.1.0 *bases* - .. versionchanged:: 18.1.0 If *attrs* is ordered, the order is retained. - .. versionchanged:: 23.2.0 *class_body* - .. versionchanged:: 25.2.0 Class names can now be unicode. - """ - # Class identifiers are converted into the normal form NFKC while parsing - name = unicodedata.normalize("NFKC", name) - - if isinstance(attrs, dict): - cls_dict = attrs - elif isinstance(attrs, (list, tuple)): - cls_dict = {a: attrib() for a in attrs} - else: - msg = "attrs argument must be a dict or a list." - raise TypeError(msg) - - pre_init = cls_dict.pop("__attrs_pre_init__", None) - post_init = cls_dict.pop("__attrs_post_init__", None) - user_init = cls_dict.pop("__init__", None) - - body = {} - if class_body is not None: - body.update(class_body) - if pre_init is not None: - body["__attrs_pre_init__"] = pre_init - if post_init is not None: - body["__attrs_post_init__"] = post_init - if user_init is not None: - body["__init__"] = user_init - - type_ = types.new_class(name, bases, {}, lambda ns: ns.update(body)) - - # For pickling to work, the __module__ variable needs to be set to the - # frame where the class is created. Bypass this step in environments where - # sys._getframe is not defined (Jython for example) or sys._getframe is not - # defined for arguments greater than 0 (IronPython). - with contextlib.suppress(AttributeError, ValueError): - type_.__module__ = sys._getframe(1).f_globals.get( - "__name__", "__main__" - ) - - # We do it here for proper warnings with meaningful stacklevel. - cmp = attributes_arguments.pop("cmp", None) - ( - attributes_arguments["eq"], - attributes_arguments["order"], - ) = _determine_attrs_eq_order( - cmp, - attributes_arguments.get("eq"), - attributes_arguments.get("order"), - True, - ) - - cls = _attrs(these=cls_dict, **attributes_arguments)(type_) - # Only add type annotations now or "_attrs()" will complain: - cls.__annotations__ = { - k: v.type for k, v in cls_dict.items() if v.type is not None - } - return cls - - -# These are required by within this module so we define them here and merely -# import into .validators / .converters. - - -@attrs(slots=True, unsafe_hash=True) -class _AndValidator: - """ - Compose many validators to a single one. - """ - - _validators = attrib() - - def __call__(self, inst, attr, value): - for v in self._validators: - v(inst, attr, value) - - -def and_(*validators): - """ - A validator that composes multiple validators into one. - - When called on a value, it runs all wrapped validators. - - Args: - validators (~collections.abc.Iterable[typing.Callable]): - Arbitrary number of validators. - - .. versionadded:: 17.1.0 - """ - vals = [] - for validator in validators: - vals.extend( - validator._validators - if isinstance(validator, _AndValidator) - else [validator] - ) - - return _AndValidator(tuple(vals)) - - -def pipe(*converters): - """ - A converter that composes multiple converters into one. - - When called on a value, it runs all wrapped converters, returning the - *last* value. - - Type annotations will be inferred from the wrapped converters', if they - have any. - - converters (~collections.abc.Iterable[typing.Callable]): - Arbitrary number of converters. - - .. versionadded:: 20.1.0 - """ - - return_instance = any(isinstance(c, Converter) for c in converters) - - if return_instance: - - def pipe_converter(val, inst, field): - for c in converters: - val = ( - c(val, inst, field) if isinstance(c, Converter) else c(val) - ) - - return val - - else: - - def pipe_converter(val): - for c in converters: - val = c(val) - - return val - - if not converters: - # If the converter list is empty, pipe_converter is the identity. - A = TypeVar("A") - pipe_converter.__annotations__.update({"val": A, "return": A}) - else: - # Get parameter type from first converter. - t = _AnnotationExtractor(converters[0]).get_first_param_type() - if t: - pipe_converter.__annotations__["val"] = t - - last = converters[-1] - if not PY_3_11_PLUS and isinstance(last, Converter): - last = last.__call__ - - # Get return type from last converter. - rt = _AnnotationExtractor(last).get_return_type() - if rt: - pipe_converter.__annotations__["return"] = rt - - if return_instance: - return Converter(pipe_converter, takes_self=True, takes_field=True) - return pipe_converter diff --git a/venv/lib/python3.9/site-packages/attr/_next_gen.py b/venv/lib/python3.9/site-packages/attr/_next_gen.py deleted file mode 100644 index 4ccd0da..0000000 --- a/venv/lib/python3.9/site-packages/attr/_next_gen.py +++ /dev/null @@ -1,674 +0,0 @@ -# SPDX-License-Identifier: MIT - -""" -These are keyword-only APIs that call `attr.s` and `attr.ib` with different -default values. -""" - -from functools import partial - -from . import setters -from ._funcs import asdict as _asdict -from ._funcs import astuple as _astuple -from ._make import ( - _DEFAULT_ON_SETATTR, - NOTHING, - _frozen_setattrs, - attrib, - attrs, -) -from .exceptions import NotAnAttrsClassError, UnannotatedAttributeError - - -def define( - maybe_cls=None, - *, - these=None, - repr=None, - unsafe_hash=None, - hash=None, - init=None, - slots=True, - frozen=False, - weakref_slot=True, - str=False, - auto_attribs=None, - kw_only=False, - cache_hash=False, - auto_exc=True, - eq=None, - order=False, - auto_detect=True, - getstate_setstate=None, - on_setattr=None, - field_transformer=None, - match_args=True, - force_kw_only=False, -): - r""" - A class decorator that adds :term:`dunder methods` according to - :term:`fields ` specified using :doc:`type annotations `, - `field()` calls, or the *these* argument. - - Since *attrs* patches or replaces an existing class, you cannot use - `object.__init_subclass__` with *attrs* classes, because it runs too early. - As a replacement, you can define ``__attrs_init_subclass__`` on your class. - It will be called by *attrs* classes that subclass it after they're - created. See also :ref:`init-subclass`. - - Args: - slots (bool): - Create a :term:`slotted class ` that's more - memory-efficient. Slotted classes are generally superior to the - default dict classes, but have some gotchas you should know about, - so we encourage you to read the :term:`glossary entry `. - - auto_detect (bool): - Instead of setting the *init*, *repr*, *eq*, and *hash* arguments - explicitly, assume they are set to True **unless any** of the - involved methods for one of the arguments is implemented in the - *current* class (meaning, it is *not* inherited from some base - class). - - So, for example by implementing ``__eq__`` on a class yourself, - *attrs* will deduce ``eq=False`` and will create *neither* - ``__eq__`` *nor* ``__ne__`` (but Python classes come with a - sensible ``__ne__`` by default, so it *should* be enough to only - implement ``__eq__`` in most cases). - - Passing :data:`True` or :data:`False` to *init*, *repr*, *eq*, or *hash* - overrides whatever *auto_detect* would determine. - - auto_exc (bool): - If the class subclasses `BaseException` (which implicitly includes - any subclass of any exception), the following happens to behave - like a well-behaved Python exception class: - - - the values for *eq*, *order*, and *hash* are ignored and the - instances compare and hash by the instance's ids [#]_ , - - all attributes that are either passed into ``__init__`` or have a - default value are additionally available as a tuple in the - ``args`` attribute, - - the value of *str* is ignored leaving ``__str__`` to base - classes. - - .. [#] - Note that *attrs* will *not* remove existing implementations of - ``__hash__`` or the equality methods. It just won't add own - ones. - - on_setattr (~typing.Callable | list[~typing.Callable] | None | ~typing.Literal[attrs.setters.NO_OP]): - A callable that is run whenever the user attempts to set an - attribute (either by assignment like ``i.x = 42`` or by using - `setattr` like ``setattr(i, "x", 42)``). It receives the same - arguments as validators: the instance, the attribute that is being - modified, and the new value. - - If no exception is raised, the attribute is set to the return value - of the callable. - - If a list of callables is passed, they're automatically wrapped in - an `attrs.setters.pipe`. - - If left None, the default behavior is to run converters and - validators whenever an attribute is set. - - init (bool): - Create a ``__init__`` method that initializes the *attrs* - attributes. Leading underscores are stripped for the argument name, - unless an alias is set on the attribute. - - .. seealso:: - `init` shows advanced ways to customize the generated - ``__init__`` method, including executing code before and after. - - repr(bool): - Create a ``__repr__`` method with a human readable representation - of *attrs* attributes. - - str (bool): - Create a ``__str__`` method that is identical to ``__repr__``. This - is usually not necessary except for `Exception`\ s. - - eq (bool | None): - If True or None (default), add ``__eq__`` and ``__ne__`` methods - that check two instances for equality. - - .. seealso:: - `comparison` describes how to customize the comparison behavior - going as far comparing NumPy arrays. - - order (bool | None): - If True, add ``__lt__``, ``__le__``, ``__gt__``, and ``__ge__`` - methods that behave like *eq* above and allow instances to be - ordered. - - They compare the instances as if they were tuples of their *attrs* - attributes if and only if the types of both classes are - *identical*. - - If `None` mirror value of *eq*. - - .. seealso:: `comparison` - - unsafe_hash (bool | None): - If None (default), the ``__hash__`` method is generated according - how *eq* and *frozen* are set. - - 1. If *both* are True, *attrs* will generate a ``__hash__`` for - you. - 2. If *eq* is True and *frozen* is False, ``__hash__`` will be set - to None, marking it unhashable (which it is). - 3. If *eq* is False, ``__hash__`` will be left untouched meaning - the ``__hash__`` method of the base class will be used. If the - base class is `object`, this means it will fall back to id-based - hashing. - - Although not recommended, you can decide for yourself and force - *attrs* to create one (for example, if the class is immutable even - though you didn't freeze it programmatically) by passing True or - not. Both of these cases are rather special and should be used - carefully. - - .. seealso:: - - - Our documentation on `hashing`, - - Python's documentation on `object.__hash__`, - - and the `GitHub issue that led to the default \ behavior - `_ for more - details. - - hash (bool | None): - Deprecated alias for *unsafe_hash*. *unsafe_hash* takes precedence. - - cache_hash (bool): - Ensure that the object's hash code is computed only once and stored - on the object. If this is set to True, hashing must be either - explicitly or implicitly enabled for this class. If the hash code - is cached, avoid any reassignments of fields involved in hash code - computation or mutations of the objects those fields point to after - object creation. If such changes occur, the behavior of the - object's hash code is undefined. - - frozen (bool): - Make instances immutable after initialization. If someone attempts - to modify a frozen instance, `attrs.exceptions.FrozenInstanceError` - is raised. - - .. note:: - - 1. This is achieved by installing a custom ``__setattr__`` - method on your class, so you can't implement your own. - - 2. True immutability is impossible in Python. - - 3. This *does* have a minor a runtime performance `impact - ` when initializing new instances. In other - words: ``__init__`` is slightly slower with ``frozen=True``. - - 4. If a class is frozen, you cannot modify ``self`` in - ``__attrs_post_init__`` or a self-written ``__init__``. You - can circumvent that limitation by using - ``object.__setattr__(self, "attribute_name", value)``. - - 5. Subclasses of a frozen class are frozen too. - - kw_only (bool): - Make attributes keyword-only in the generated ``__init__`` (if - *init* is False, this parameter is ignored). Attributes that - explicitly set ``kw_only=False`` are not affected; base class - attributes are also not affected. - - Also see *force_kw_only*. - - weakref_slot (bool): - Make instances weak-referenceable. This has no effect unless - *slots* is True. - - field_transformer (~typing.Callable | None): - A function that is called with the original class object and all - fields right before *attrs* finalizes the class. You can use this, - for example, to automatically add converters or validators to - fields based on their types. - - .. seealso:: `transform-fields` - - match_args (bool): - If True (default), set ``__match_args__`` on the class to support - :pep:`634` (*Structural Pattern Matching*). It is a tuple of all - non-keyword-only ``__init__`` parameter names on Python 3.10 and - later. Ignored on older Python versions. - - collect_by_mro (bool): - If True, *attrs* collects attributes from base classes correctly - according to the `method resolution order - `_. If False, *attrs* - will mimic the (wrong) behavior of `dataclasses` and :pep:`681`. - - See also `issue #428 - `_. - - force_kw_only (bool): - A back-compat flag for restoring pre-25.4.0 behavior. If True and - ``kw_only=True``, all attributes are made keyword-only, including - base class attributes, and those set to ``kw_only=False`` at the - attribute level. Defaults to False. - - See also `issue #980 - `_. - - getstate_setstate (bool | None): - .. note:: - - This is usually only interesting for slotted classes and you - should probably just set *auto_detect* to True. - - If True, ``__getstate__`` and ``__setstate__`` are generated and - attached to the class. This is necessary for slotted classes to be - pickleable. If left None, it's True by default for slotted classes - and False for dict classes. - - If *auto_detect* is True, and *getstate_setstate* is left None, and - **either** ``__getstate__`` or ``__setstate__`` is detected - directly on the class (meaning: not inherited), it is set to False - (this is usually what you want). - - auto_attribs (bool | None): - If True, look at type annotations to determine which attributes to - use, like `dataclasses`. If False, it will only look for explicit - :func:`field` class attributes, like classic *attrs*. - - If left None, it will guess: - - 1. If any attributes are annotated and no unannotated - `attrs.field`\ s are found, it assumes *auto_attribs=True*. - 2. Otherwise it assumes *auto_attribs=False* and tries to collect - `attrs.field`\ s. - - If *attrs* decides to look at type annotations, **all** fields - **must** be annotated. If *attrs* encounters a field that is set to - a :func:`field` / `attr.ib` but lacks a type annotation, an - `attrs.exceptions.UnannotatedAttributeError` is raised. Use - ``field_name: typing.Any = field(...)`` if you don't want to set a - type. - - .. warning:: - - For features that use the attribute name to create decorators - (for example, :ref:`validators `), you still *must* - assign :func:`field` / `attr.ib` to them. Otherwise Python will - either not find the name or try to use the default value to - call, for example, ``validator`` on it. - - Attributes annotated as `typing.ClassVar`, and attributes that are - neither annotated nor set to an `field()` are **ignored**. - - these (dict[str, object]): - A dictionary of name to the (private) return value of `field()` - mappings. This is useful to avoid the definition of your attributes - within the class body because you can't (for example, if you want - to add ``__repr__`` methods to Django models) or don't want to. - - If *these* is not `None`, *attrs* will *not* search the class body - for attributes and will *not* remove any attributes from it. - - The order is deduced from the order of the attributes inside - *these*. - - Arguably, this is a rather obscure feature. - - .. versionadded:: 20.1.0 - .. versionchanged:: 21.3.0 Converters are also run ``on_setattr``. - .. versionadded:: 22.2.0 - *unsafe_hash* as an alias for *hash* (for :pep:`681` compliance). - .. versionchanged:: 24.1.0 - Instances are not compared as tuples of attributes anymore, but using a - big ``and`` condition. This is faster and has more correct behavior for - uncomparable values like `math.nan`. - .. versionadded:: 24.1.0 - If a class has an *inherited* classmethod called - ``__attrs_init_subclass__``, it is executed after the class is created. - .. deprecated:: 24.1.0 *hash* is deprecated in favor of *unsafe_hash*. - .. versionadded:: 24.3.0 - Unless already present, a ``__replace__`` method is automatically - created for `copy.replace` (Python 3.13+ only). - .. versionchanged:: 25.4.0 - *kw_only* now only applies to attributes defined in the current class, - and respects attribute-level ``kw_only=False`` settings. - .. versionadded:: 25.4.0 - Added *force_kw_only* to go back to the previous *kw_only* behavior. - - .. note:: - - The main differences to the classic `attr.s` are: - - - Automatically detect whether or not *auto_attribs* should be `True` - (c.f. *auto_attribs* parameter). - - Converters and validators run when attributes are set by default -- - if *frozen* is `False`. - - *slots=True* - - Usually, this has only upsides and few visible effects in everyday - programming. But it *can* lead to some surprising behaviors, so - please make sure to read :term:`slotted classes`. - - - *auto_exc=True* - - *auto_detect=True* - - *order=False* - - *force_kw_only=False* - - Some options that were only relevant on Python 2 or were kept around - for backwards-compatibility have been removed. - - """ - - def do_it(cls, auto_attribs): - return attrs( - maybe_cls=cls, - these=these, - repr=repr, - hash=hash, - unsafe_hash=unsafe_hash, - init=init, - slots=slots, - frozen=frozen, - weakref_slot=weakref_slot, - str=str, - auto_attribs=auto_attribs, - kw_only=kw_only, - cache_hash=cache_hash, - auto_exc=auto_exc, - eq=eq, - order=order, - auto_detect=auto_detect, - collect_by_mro=True, - getstate_setstate=getstate_setstate, - on_setattr=on_setattr, - field_transformer=field_transformer, - match_args=match_args, - force_kw_only=force_kw_only, - ) - - def wrap(cls): - """ - Making this a wrapper ensures this code runs during class creation. - - We also ensure that frozen-ness of classes is inherited. - """ - nonlocal frozen, on_setattr - - had_on_setattr = on_setattr not in (None, setters.NO_OP) - - # By default, mutable classes convert & validate on setattr. - if frozen is False and on_setattr is None: - on_setattr = _DEFAULT_ON_SETATTR - - # However, if we subclass a frozen class, we inherit the immutability - # and disable on_setattr. - for base_cls in cls.__bases__: - if base_cls.__setattr__ is _frozen_setattrs: - if had_on_setattr: - msg = "Frozen classes can't use on_setattr (frozen-ness was inherited)." - raise ValueError(msg) - - on_setattr = setters.NO_OP - break - - if auto_attribs is not None: - return do_it(cls, auto_attribs) - - try: - return do_it(cls, True) - except UnannotatedAttributeError: - return do_it(cls, False) - - # maybe_cls's type depends on the usage of the decorator. It's a class - # if it's used as `@attrs` but `None` if used as `@attrs()`. - if maybe_cls is None: - return wrap - - return wrap(maybe_cls) - - -mutable = define -frozen = partial(define, frozen=True, on_setattr=None) - - -def field( - *, - default=NOTHING, - validator=None, - repr=True, - hash=None, - init=True, - metadata=None, - type=None, - converter=None, - factory=None, - kw_only=None, - eq=None, - order=None, - on_setattr=None, - alias=None, -): - """ - Create a new :term:`field` / :term:`attribute` on a class. - - .. warning:: - - Does **nothing** unless the class is also decorated with - `attrs.define` (or similar)! - - Args: - default: - A value that is used if an *attrs*-generated ``__init__`` is used - and no value is passed while instantiating or the attribute is - excluded using ``init=False``. - - If the value is an instance of `attrs.Factory`, its callable will - be used to construct a new value (useful for mutable data types - like lists or dicts). - - If a default is not set (or set manually to `attrs.NOTHING`), a - value *must* be supplied when instantiating; otherwise a - `TypeError` will be raised. - - .. seealso:: `defaults` - - factory (~typing.Callable): - Syntactic sugar for ``default=attr.Factory(factory)``. - - validator (~typing.Callable | list[~typing.Callable]): - Callable that is called by *attrs*-generated ``__init__`` methods - after the instance has been initialized. They receive the - initialized instance, the :func:`~attrs.Attribute`, and the passed - value. - - The return value is *not* inspected so the validator has to throw - an exception itself. - - If a `list` is passed, its items are treated as validators and must - all pass. - - Validators can be globally disabled and re-enabled using - `attrs.validators.get_disabled` / `attrs.validators.set_disabled`. - - The validator can also be set using decorator notation as shown - below. - - .. seealso:: :ref:`validators` - - repr (bool | ~typing.Callable): - Include this attribute in the generated ``__repr__`` method. If - True, include the attribute; if False, omit it. By default, the - built-in ``repr()`` function is used. To override how the attribute - value is formatted, pass a ``callable`` that takes a single value - and returns a string. Note that the resulting string is used as-is, - which means it will be used directly *instead* of calling - ``repr()`` (the default). - - eq (bool | ~typing.Callable): - If True (default), include this attribute in the generated - ``__eq__`` and ``__ne__`` methods that check two instances for - equality. To override how the attribute value is compared, pass a - callable that takes a single value and returns the value to be - compared. - - .. seealso:: `comparison` - - order (bool | ~typing.Callable): - If True (default), include this attributes in the generated - ``__lt__``, ``__le__``, ``__gt__`` and ``__ge__`` methods. To - override how the attribute value is ordered, pass a callable that - takes a single value and returns the value to be ordered. - - .. seealso:: `comparison` - - hash (bool | None): - Include this attribute in the generated ``__hash__`` method. If - None (default), mirror *eq*'s value. This is the correct behavior - according the Python spec. Setting this value to anything else - than None is *discouraged*. - - .. seealso:: `hashing` - - init (bool): - Include this attribute in the generated ``__init__`` method. - - It is possible to set this to False and set a default value. In - that case this attributed is unconditionally initialized with the - specified default value or factory. - - .. seealso:: `init` - - converter (typing.Callable | Converter): - A callable that is called by *attrs*-generated ``__init__`` methods - to convert attribute's value to the desired format. - - If a vanilla callable is passed, it is given the passed-in value as - the only positional argument. It is possible to receive additional - arguments by wrapping the callable in a `Converter`. - - Either way, the returned value will be used as the new value of the - attribute. The value is converted before being passed to the - validator, if any. - - .. seealso:: :ref:`converters` - - metadata (dict | None): - An arbitrary mapping, to be used by third-party code. - - .. seealso:: `extending-metadata`. - - type (type): - The type of the attribute. Nowadays, the preferred method to - specify the type is using a variable annotation (see :pep:`526`). - This argument is provided for backwards-compatibility and for usage - with `make_class`. Regardless of the approach used, the type will - be stored on ``Attribute.type``. - - Please note that *attrs* doesn't do anything with this metadata by - itself. You can use it as part of your own code or for `static type - checking `. - - kw_only (bool | None): - Make this attribute keyword-only in the generated ``__init__`` (if - *init* is False, this parameter is ignored). If None (default), - mirror the setting from `attrs.define`. - - on_setattr (~typing.Callable | list[~typing.Callable] | None | ~typing.Literal[attrs.setters.NO_OP]): - Allows to overwrite the *on_setattr* setting from `attr.s`. If left - None, the *on_setattr* value from `attr.s` is used. Set to - `attrs.setters.NO_OP` to run **no** `setattr` hooks for this - attribute -- regardless of the setting in `define()`. - - alias (str | None): - Override this attribute's parameter name in the generated - ``__init__`` method. If left None, default to ``name`` stripped - of leading underscores. See `private-attributes`. - - .. versionadded:: 20.1.0 - .. versionchanged:: 21.1.0 - *eq*, *order*, and *cmp* also accept a custom callable - .. versionadded:: 22.2.0 *alias* - .. versionadded:: 23.1.0 - The *type* parameter has been re-added; mostly for `attrs.make_class`. - Please note that type checkers ignore this metadata. - .. versionchanged:: 25.4.0 - *kw_only* can now be None, and its default is also changed from False to - None. - - .. seealso:: - - `attr.ib` - """ - return attrib( - default=default, - validator=validator, - repr=repr, - hash=hash, - init=init, - metadata=metadata, - type=type, - converter=converter, - factory=factory, - kw_only=kw_only, - eq=eq, - order=order, - on_setattr=on_setattr, - alias=alias, - ) - - -def asdict(inst, *, recurse=True, filter=None, value_serializer=None): - """ - Same as `attr.asdict`, except that collections types are always retained - and dict is always used as *dict_factory*. - - .. versionadded:: 21.3.0 - """ - return _asdict( - inst=inst, - recurse=recurse, - filter=filter, - value_serializer=value_serializer, - retain_collection_types=True, - ) - - -def astuple(inst, *, recurse=True, filter=None): - """ - Same as `attr.astuple`, except that collections types are always retained - and `tuple` is always used as the *tuple_factory*. - - .. versionadded:: 21.3.0 - """ - return _astuple( - inst=inst, recurse=recurse, filter=filter, retain_collection_types=True - ) - - -def inspect(cls): - """ - Inspect the class and return its effective build parameters. - - Warning: - This feature is currently **experimental** and is not covered by our - strict backwards-compatibility guarantees. - - Args: - cls: The *attrs*-decorated class to inspect. - - Returns: - The effective build parameters of the class. - - Raises: - NotAnAttrsClassError: If the class is not an *attrs*-decorated class. - - .. versionadded:: 25.4.0 - """ - try: - return cls.__dict__["__attrs_props__"] - except KeyError: - msg = f"{cls!r} is not an attrs-decorated class." - raise NotAnAttrsClassError(msg) from None diff --git a/venv/lib/python3.9/site-packages/attr/_typing_compat.pyi b/venv/lib/python3.9/site-packages/attr/_typing_compat.pyi deleted file mode 100644 index ca7b71e..0000000 --- a/venv/lib/python3.9/site-packages/attr/_typing_compat.pyi +++ /dev/null @@ -1,15 +0,0 @@ -from typing import Any, ClassVar, Protocol - -# MYPY is a special constant in mypy which works the same way as `TYPE_CHECKING`. -MYPY = False - -if MYPY: - # A protocol to be able to statically accept an attrs class. - class AttrsInstance_(Protocol): - __attrs_attrs__: ClassVar[Any] - -else: - # For type checkers without plug-in support use an empty protocol that - # will (hopefully) be combined into a union. - class AttrsInstance_(Protocol): - pass diff --git a/venv/lib/python3.9/site-packages/attr/_version_info.py b/venv/lib/python3.9/site-packages/attr/_version_info.py deleted file mode 100644 index 27f1888..0000000 --- a/venv/lib/python3.9/site-packages/attr/_version_info.py +++ /dev/null @@ -1,89 +0,0 @@ -# SPDX-License-Identifier: MIT - - -from functools import total_ordering - -from ._funcs import astuple -from ._make import attrib, attrs - - -@total_ordering -@attrs(eq=False, order=False, slots=True, frozen=True) -class VersionInfo: - """ - A version object that can be compared to tuple of length 1--4: - - >>> attr.VersionInfo(19, 1, 0, "final") <= (19, 2) - True - >>> attr.VersionInfo(19, 1, 0, "final") < (19, 1, 1) - True - >>> vi = attr.VersionInfo(19, 2, 0, "final") - >>> vi < (19, 1, 1) - False - >>> vi < (19,) - False - >>> vi == (19, 2,) - True - >>> vi == (19, 2, 1) - False - - .. versionadded:: 19.2 - """ - - year = attrib(type=int) - minor = attrib(type=int) - micro = attrib(type=int) - releaselevel = attrib(type=str) - - @classmethod - def _from_version_string(cls, s): - """ - Parse *s* and return a _VersionInfo. - """ - v = s.split(".") - if len(v) == 3: - v.append("final") - - return cls( - year=int(v[0]), minor=int(v[1]), micro=int(v[2]), releaselevel=v[3] - ) - - def _ensure_tuple(self, other): - """ - Ensure *other* is a tuple of a valid length. - - Returns a possibly transformed *other* and ourselves as a tuple of - the same length as *other*. - """ - - if self.__class__ is other.__class__: - other = astuple(other) - - if not isinstance(other, tuple): - raise NotImplementedError - - if not (1 <= len(other) <= 4): - raise NotImplementedError - - return astuple(self)[: len(other)], other - - def __eq__(self, other): - try: - us, them = self._ensure_tuple(other) - except NotImplementedError: - return NotImplemented - - return us == them - - def __lt__(self, other): - try: - us, them = self._ensure_tuple(other) - except NotImplementedError: - return NotImplemented - - # Since alphabetically "dev0" < "final" < "post1" < "post2", we don't - # have to do anything special with releaselevel for now. - return us < them - - def __hash__(self): - return hash((self.year, self.minor, self.micro, self.releaselevel)) diff --git a/venv/lib/python3.9/site-packages/attr/_version_info.pyi b/venv/lib/python3.9/site-packages/attr/_version_info.pyi deleted file mode 100644 index 45ced08..0000000 --- a/venv/lib/python3.9/site-packages/attr/_version_info.pyi +++ /dev/null @@ -1,9 +0,0 @@ -class VersionInfo: - @property - def year(self) -> int: ... - @property - def minor(self) -> int: ... - @property - def micro(self) -> int: ... - @property - def releaselevel(self) -> str: ... diff --git a/venv/lib/python3.9/site-packages/attr/converters.py b/venv/lib/python3.9/site-packages/attr/converters.py deleted file mode 100644 index 0a79dee..0000000 --- a/venv/lib/python3.9/site-packages/attr/converters.py +++ /dev/null @@ -1,162 +0,0 @@ -# SPDX-License-Identifier: MIT - -""" -Commonly useful converters. -""" - -import typing - -from ._compat import _AnnotationExtractor -from ._make import NOTHING, Converter, Factory, pipe - - -__all__ = [ - "default_if_none", - "optional", - "pipe", - "to_bool", -] - - -def optional(converter): - """ - A converter that allows an attribute to be optional. An optional attribute - is one which can be set to `None`. - - Type annotations will be inferred from the wrapped converter's, if it has - any. - - Args: - converter (typing.Callable): - the converter that is used for non-`None` values. - - .. versionadded:: 17.1.0 - """ - - if isinstance(converter, Converter): - - def optional_converter(val, inst, field): - if val is None: - return None - return converter(val, inst, field) - - else: - - def optional_converter(val): - if val is None: - return None - return converter(val) - - xtr = _AnnotationExtractor(converter) - - t = xtr.get_first_param_type() - if t: - optional_converter.__annotations__["val"] = typing.Optional[t] - - rt = xtr.get_return_type() - if rt: - optional_converter.__annotations__["return"] = typing.Optional[rt] - - if isinstance(converter, Converter): - return Converter(optional_converter, takes_self=True, takes_field=True) - - return optional_converter - - -def default_if_none(default=NOTHING, factory=None): - """ - A converter that allows to replace `None` values by *default* or the result - of *factory*. - - Args: - default: - Value to be used if `None` is passed. Passing an instance of - `attrs.Factory` is supported, however the ``takes_self`` option is - *not*. - - factory (typing.Callable): - A callable that takes no parameters whose result is used if `None` - is passed. - - Raises: - TypeError: If **neither** *default* or *factory* is passed. - - TypeError: If **both** *default* and *factory* are passed. - - ValueError: - If an instance of `attrs.Factory` is passed with - ``takes_self=True``. - - .. versionadded:: 18.2.0 - """ - if default is NOTHING and factory is None: - msg = "Must pass either `default` or `factory`." - raise TypeError(msg) - - if default is not NOTHING and factory is not None: - msg = "Must pass either `default` or `factory` but not both." - raise TypeError(msg) - - if factory is not None: - default = Factory(factory) - - if isinstance(default, Factory): - if default.takes_self: - msg = "`takes_self` is not supported by default_if_none." - raise ValueError(msg) - - def default_if_none_converter(val): - if val is not None: - return val - - return default.factory() - - else: - - def default_if_none_converter(val): - if val is not None: - return val - - return default - - return default_if_none_converter - - -def to_bool(val): - """ - Convert "boolean" strings (for example, from environment variables) to real - booleans. - - Values mapping to `True`: - - - ``True`` - - ``"true"`` / ``"t"`` - - ``"yes"`` / ``"y"`` - - ``"on"`` - - ``"1"`` - - ``1`` - - Values mapping to `False`: - - - ``False`` - - ``"false"`` / ``"f"`` - - ``"no"`` / ``"n"`` - - ``"off"`` - - ``"0"`` - - ``0`` - - Raises: - ValueError: For any other value. - - .. versionadded:: 21.3.0 - """ - if isinstance(val, str): - val = val.lower() - - if val in (True, "true", "t", "yes", "y", "on", "1", 1): - return True - if val in (False, "false", "f", "no", "n", "off", "0", 0): - return False - - msg = f"Cannot convert value to bool: {val!r}" - raise ValueError(msg) diff --git a/venv/lib/python3.9/site-packages/attr/converters.pyi b/venv/lib/python3.9/site-packages/attr/converters.pyi deleted file mode 100644 index 12bd0c4..0000000 --- a/venv/lib/python3.9/site-packages/attr/converters.pyi +++ /dev/null @@ -1,19 +0,0 @@ -from typing import Callable, Any, overload - -from attrs import _ConverterType, _CallableConverterType - -@overload -def pipe(*validators: _CallableConverterType) -> _CallableConverterType: ... -@overload -def pipe(*validators: _ConverterType) -> _ConverterType: ... -@overload -def optional(converter: _CallableConverterType) -> _CallableConverterType: ... -@overload -def optional(converter: _ConverterType) -> _ConverterType: ... -@overload -def default_if_none(default: Any) -> _CallableConverterType: ... -@overload -def default_if_none( - *, factory: Callable[[], Any] -) -> _CallableConverterType: ... -def to_bool(val: str | int | bool) -> bool: ... diff --git a/venv/lib/python3.9/site-packages/attr/exceptions.py b/venv/lib/python3.9/site-packages/attr/exceptions.py deleted file mode 100644 index a207df4..0000000 --- a/venv/lib/python3.9/site-packages/attr/exceptions.py +++ /dev/null @@ -1,95 +0,0 @@ -# SPDX-License-Identifier: MIT - -from __future__ import annotations - - -class FrozenError(AttributeError): - """ - A frozen/immutable instance or attribute have been attempted to be - modified. - - It mirrors the behavior of ``namedtuples`` by using the same error message - and subclassing `AttributeError`. - - .. versionadded:: 20.1.0 - """ - - def __init__(self): - msg = "can't set attribute" - super().__init__(msg) - self.msg = msg - - -class FrozenInstanceError(FrozenError): - """ - A frozen instance has been attempted to be modified. - - .. versionadded:: 16.1.0 - """ - - -class FrozenAttributeError(FrozenError): - """ - A frozen attribute has been attempted to be modified. - - .. versionadded:: 20.1.0 - """ - - -class AttrsAttributeNotFoundError(ValueError): - """ - An *attrs* function couldn't find an attribute that the user asked for. - - .. versionadded:: 16.2.0 - """ - - -class NotAnAttrsClassError(ValueError): - """ - A non-*attrs* class has been passed into an *attrs* function. - - .. versionadded:: 16.2.0 - """ - - -class DefaultAlreadySetError(RuntimeError): - """ - A default has been set when defining the field and is attempted to be reset - using the decorator. - - .. versionadded:: 17.1.0 - """ - - -class UnannotatedAttributeError(RuntimeError): - """ - A class with ``auto_attribs=True`` has a field without a type annotation. - - .. versionadded:: 17.3.0 - """ - - -class PythonTooOldError(RuntimeError): - """ - It was attempted to use an *attrs* feature that requires a newer Python - version. - - .. versionadded:: 18.2.0 - """ - - -class NotCallableError(TypeError): - """ - A field requiring a callable has been set with a value that is not - callable. - - .. versionadded:: 19.2.0 - """ - - def __init__(self, msg, value): - super(TypeError, self).__init__(msg, value) - self.msg = msg - self.value = value - - def __str__(self): - return str(self.msg) diff --git a/venv/lib/python3.9/site-packages/attr/exceptions.pyi b/venv/lib/python3.9/site-packages/attr/exceptions.pyi deleted file mode 100644 index f268011..0000000 --- a/venv/lib/python3.9/site-packages/attr/exceptions.pyi +++ /dev/null @@ -1,17 +0,0 @@ -from typing import Any - -class FrozenError(AttributeError): - msg: str = ... - -class FrozenInstanceError(FrozenError): ... -class FrozenAttributeError(FrozenError): ... -class AttrsAttributeNotFoundError(ValueError): ... -class NotAnAttrsClassError(ValueError): ... -class DefaultAlreadySetError(RuntimeError): ... -class UnannotatedAttributeError(RuntimeError): ... -class PythonTooOldError(RuntimeError): ... - -class NotCallableError(TypeError): - msg: str = ... - value: Any = ... - def __init__(self, msg: str, value: Any) -> None: ... diff --git a/venv/lib/python3.9/site-packages/attr/filters.py b/venv/lib/python3.9/site-packages/attr/filters.py deleted file mode 100644 index 689b170..0000000 --- a/venv/lib/python3.9/site-packages/attr/filters.py +++ /dev/null @@ -1,72 +0,0 @@ -# SPDX-License-Identifier: MIT - -""" -Commonly useful filters for `attrs.asdict` and `attrs.astuple`. -""" - -from ._make import Attribute - - -def _split_what(what): - """ - Returns a tuple of `frozenset`s of classes and attributes. - """ - return ( - frozenset(cls for cls in what if isinstance(cls, type)), - frozenset(cls for cls in what if isinstance(cls, str)), - frozenset(cls for cls in what if isinstance(cls, Attribute)), - ) - - -def include(*what): - """ - Create a filter that only allows *what*. - - Args: - what (list[type, str, attrs.Attribute]): - What to include. Can be a type, a name, or an attribute. - - Returns: - Callable: - A callable that can be passed to `attrs.asdict`'s and - `attrs.astuple`'s *filter* argument. - - .. versionchanged:: 23.1.0 Accept strings with field names. - """ - cls, names, attrs = _split_what(what) - - def include_(attribute, value): - return ( - value.__class__ in cls - or attribute.name in names - or attribute in attrs - ) - - return include_ - - -def exclude(*what): - """ - Create a filter that does **not** allow *what*. - - Args: - what (list[type, str, attrs.Attribute]): - What to exclude. Can be a type, a name, or an attribute. - - Returns: - Callable: - A callable that can be passed to `attrs.asdict`'s and - `attrs.astuple`'s *filter* argument. - - .. versionchanged:: 23.3.0 Accept field name string as input argument - """ - cls, names, attrs = _split_what(what) - - def exclude_(attribute, value): - return not ( - value.__class__ in cls - or attribute.name in names - or attribute in attrs - ) - - return exclude_ diff --git a/venv/lib/python3.9/site-packages/attr/filters.pyi b/venv/lib/python3.9/site-packages/attr/filters.pyi deleted file mode 100644 index 974abdc..0000000 --- a/venv/lib/python3.9/site-packages/attr/filters.pyi +++ /dev/null @@ -1,6 +0,0 @@ -from typing import Any - -from . import Attribute, _FilterType - -def include(*what: type | str | Attribute[Any]) -> _FilterType[Any]: ... -def exclude(*what: type | str | Attribute[Any]) -> _FilterType[Any]: ... diff --git a/venv/lib/python3.9/site-packages/attr/py.typed b/venv/lib/python3.9/site-packages/attr/py.typed deleted file mode 100644 index e69de29..0000000 diff --git a/venv/lib/python3.9/site-packages/attr/setters.py b/venv/lib/python3.9/site-packages/attr/setters.py deleted file mode 100644 index 78b0839..0000000 --- a/venv/lib/python3.9/site-packages/attr/setters.py +++ /dev/null @@ -1,79 +0,0 @@ -# SPDX-License-Identifier: MIT - -""" -Commonly used hooks for on_setattr. -""" - -from . import _config -from .exceptions import FrozenAttributeError - - -def pipe(*setters): - """ - Run all *setters* and return the return value of the last one. - - .. versionadded:: 20.1.0 - """ - - def wrapped_pipe(instance, attrib, new_value): - rv = new_value - - for setter in setters: - rv = setter(instance, attrib, rv) - - return rv - - return wrapped_pipe - - -def frozen(_, __, ___): - """ - Prevent an attribute to be modified. - - .. versionadded:: 20.1.0 - """ - raise FrozenAttributeError - - -def validate(instance, attrib, new_value): - """ - Run *attrib*'s validator on *new_value* if it has one. - - .. versionadded:: 20.1.0 - """ - if _config._run_validators is False: - return new_value - - v = attrib.validator - if not v: - return new_value - - v(instance, attrib, new_value) - - return new_value - - -def convert(instance, attrib, new_value): - """ - Run *attrib*'s converter -- if it has one -- on *new_value* and return the - result. - - .. versionadded:: 20.1.0 - """ - c = attrib.converter - if c: - # This can be removed once we drop 3.8 and use attrs.Converter instead. - from ._make import Converter - - if not isinstance(c, Converter): - return c(new_value) - - return c(new_value, instance, attrib) - - return new_value - - -# Sentinel for disabling class-wide *on_setattr* hooks for certain attributes. -# Sphinx's autodata stopped working, so the docstring is inlined in the API -# docs. -NO_OP = object() diff --git a/venv/lib/python3.9/site-packages/attr/setters.pyi b/venv/lib/python3.9/site-packages/attr/setters.pyi deleted file mode 100644 index 73abf36..0000000 --- a/venv/lib/python3.9/site-packages/attr/setters.pyi +++ /dev/null @@ -1,20 +0,0 @@ -from typing import Any, NewType, NoReturn, TypeVar - -from . import Attribute -from attrs import _OnSetAttrType - -_T = TypeVar("_T") - -def frozen( - instance: Any, attribute: Attribute[Any], new_value: Any -) -> NoReturn: ... -def pipe(*setters: _OnSetAttrType) -> _OnSetAttrType: ... -def validate(instance: Any, attribute: Attribute[_T], new_value: _T) -> _T: ... - -# convert is allowed to return Any, because they can be chained using pipe. -def convert( - instance: Any, attribute: Attribute[Any], new_value: Any -) -> Any: ... - -_NoOpType = NewType("_NoOpType", object) -NO_OP: _NoOpType diff --git a/venv/lib/python3.9/site-packages/attr/validators.py b/venv/lib/python3.9/site-packages/attr/validators.py deleted file mode 100644 index 0b1a294..0000000 --- a/venv/lib/python3.9/site-packages/attr/validators.py +++ /dev/null @@ -1,750 +0,0 @@ -# SPDX-License-Identifier: MIT - -""" -Commonly useful validators. -""" - -import operator -import re - -from contextlib import contextmanager -from re import Pattern - -from ._config import get_run_validators, set_run_validators -from ._make import _AndValidator, and_, attrib, attrs -from .converters import default_if_none -from .exceptions import NotCallableError - - -__all__ = [ - "and_", - "deep_iterable", - "deep_mapping", - "disabled", - "ge", - "get_disabled", - "gt", - "in_", - "instance_of", - "is_callable", - "le", - "lt", - "matches_re", - "max_len", - "min_len", - "not_", - "optional", - "or_", - "set_disabled", -] - - -def set_disabled(disabled): - """ - Globally disable or enable running validators. - - By default, they are run. - - Args: - disabled (bool): If `True`, disable running all validators. - - .. warning:: - - This function is not thread-safe! - - .. versionadded:: 21.3.0 - """ - set_run_validators(not disabled) - - -def get_disabled(): - """ - Return a bool indicating whether validators are currently disabled or not. - - Returns: - bool:`True` if validators are currently disabled. - - .. versionadded:: 21.3.0 - """ - return not get_run_validators() - - -@contextmanager -def disabled(): - """ - Context manager that disables running validators within its context. - - .. warning:: - - This context manager is not thread-safe! - - .. versionadded:: 21.3.0 - .. versionchanged:: 26.1.0 The contextmanager is nestable. - """ - prev = get_run_validators() - set_run_validators(False) - try: - yield - finally: - set_run_validators(prev) - - -@attrs(repr=False, slots=True, unsafe_hash=True) -class _InstanceOfValidator: - type = attrib() - - def __call__(self, inst, attr, value): - """ - We use a callable class to be able to change the ``__repr__``. - """ - if not isinstance(value, self.type): - msg = f"'{attr.name}' must be {self.type!r} (got {value!r} that is a {value.__class__!r})." - raise TypeError( - msg, - attr, - self.type, - value, - ) - - def __repr__(self): - return f"" - - -def instance_of(type): - """ - A validator that raises a `TypeError` if the initializer is called with a - wrong type for this particular attribute (checks are performed using - `isinstance` therefore it's also valid to pass a tuple of types). - - Args: - type (type | tuple[type]): The type to check for. - - Raises: - TypeError: - With a human readable error message, the attribute (of type - `attrs.Attribute`), the expected type, and the value it got. - """ - return _InstanceOfValidator(type) - - -@attrs(repr=False, frozen=True, slots=True) -class _MatchesReValidator: - pattern = attrib() - match_func = attrib() - - def __call__(self, inst, attr, value): - """ - We use a callable class to be able to change the ``__repr__``. - """ - if not self.match_func(value): - msg = f"'{attr.name}' must match regex {self.pattern.pattern!r} ({value!r} doesn't)" - raise ValueError( - msg, - attr, - self.pattern, - value, - ) - - def __repr__(self): - return f"" - - -def matches_re(regex, flags=0, func=None): - r""" - A validator that raises `ValueError` if the initializer is called with a - string that doesn't match *regex*. - - Args: - regex (str, re.Pattern): - A regex string or precompiled pattern to match against - - flags (int): - Flags that will be passed to the underlying re function (default 0) - - func (typing.Callable): - Which underlying `re` function to call. Valid options are - `re.fullmatch`, `re.search`, and `re.match`; the default `None` - means `re.fullmatch`. For performance reasons, the pattern is - always precompiled using `re.compile`. - - .. versionadded:: 19.2.0 - .. versionchanged:: 21.3.0 *regex* can be a pre-compiled pattern. - """ - valid_funcs = (re.fullmatch, None, re.search, re.match) - if func not in valid_funcs: - msg = "'func' must be one of {}.".format( - ", ".join( - sorted((e and e.__name__) or "None" for e in set(valid_funcs)) - ) - ) - raise ValueError(msg) - - if isinstance(regex, Pattern): - if flags: - msg = "'flags' can only be used with a string pattern; pass flags to re.compile() instead" - raise TypeError(msg) - pattern = regex - else: - pattern = re.compile(regex, flags) - - if func is re.match: - match_func = pattern.match - elif func is re.search: - match_func = pattern.search - else: - match_func = pattern.fullmatch - - return _MatchesReValidator(pattern, match_func) - - -@attrs(repr=False, slots=True, unsafe_hash=True) -class _OptionalValidator: - validator = attrib() - - def __call__(self, inst, attr, value): - if value is None: - return - - self.validator(inst, attr, value) - - def __repr__(self): - return f"" - - -def optional(validator): - """ - A validator that makes an attribute optional. An optional attribute is one - which can be set to `None` in addition to satisfying the requirements of - the sub-validator. - - Args: - validator - (typing.Callable | tuple[typing.Callable] | list[typing.Callable]): - A validator (or validators) that is used for non-`None` values. - - .. versionadded:: 15.1.0 - .. versionchanged:: 17.1.0 *validator* can be a list of validators. - .. versionchanged:: 23.1.0 *validator* can also be a tuple of validators. - """ - if isinstance(validator, (list, tuple)): - return _OptionalValidator(_AndValidator(validator)) - - return _OptionalValidator(validator) - - -@attrs(repr=False, slots=True, unsafe_hash=True) -class _InValidator: - options = attrib() - _original_options = attrib(hash=False) - - def __call__(self, inst, attr, value): - try: - in_options = value in self.options - except TypeError: # e.g. `1 in "abc"` - in_options = False - - if not in_options: - msg = f"'{attr.name}' must be in {self._original_options!r} (got {value!r})" - raise ValueError( - msg, - attr, - self._original_options, - value, - ) - - def __repr__(self): - return f"" - - -def in_(options): - """ - A validator that raises a `ValueError` if the initializer is called with a - value that does not belong in the *options* provided. - - The check is performed using ``value in options``, so *options* has to - support that operation. - - To keep the validator hashable, dicts, lists, and sets are transparently - transformed into a `tuple`. - - Args: - options: Allowed options. - - Raises: - ValueError: - With a human readable error message, the attribute (of type - `attrs.Attribute`), the expected options, and the value it got. - - .. versionadded:: 17.1.0 - .. versionchanged:: 22.1.0 - The ValueError was incomplete until now and only contained the human - readable error message. Now it contains all the information that has - been promised since 17.1.0. - .. versionchanged:: 24.1.0 - *options* that are a list, dict, or a set are now transformed into a - tuple to keep the validator hashable. - """ - repr_options = options - if isinstance(options, (list, dict, set)): - options = tuple(options) - - return _InValidator(options, repr_options) - - -@attrs(repr=False, slots=False, unsafe_hash=True) -class _IsCallableValidator: - def __call__(self, inst, attr, value): - """ - We use a callable class to be able to change the ``__repr__``. - """ - if not callable(value): - message = ( - "'{name}' must be callable " - "(got {value!r} that is a {actual!r})." - ) - raise NotCallableError( - msg=message.format( - name=attr.name, value=value, actual=value.__class__ - ), - value=value, - ) - - def __repr__(self): - return "" - - -def is_callable(): - """ - A validator that raises a `attrs.exceptions.NotCallableError` if the - initializer is called with a value for this particular attribute that is - not callable. - - .. versionadded:: 19.1.0 - - Raises: - attrs.exceptions.NotCallableError: - With a human readable error message containing the attribute - (`attrs.Attribute`) name, and the value it got. - """ - return _IsCallableValidator() - - -@attrs(repr=False, slots=True, unsafe_hash=True) -class _DeepIterable: - member_validator = attrib(validator=is_callable()) - iterable_validator = attrib( - default=None, validator=optional(is_callable()) - ) - - def __call__(self, inst, attr, value): - """ - We use a callable class to be able to change the ``__repr__``. - """ - if self.iterable_validator is not None: - self.iterable_validator(inst, attr, value) - - for member in value: - self.member_validator(inst, attr, member) - - def __repr__(self): - iterable_identifier = ( - "" - if self.iterable_validator is None - else f" {self.iterable_validator!r}" - ) - return ( - f"" - ) - - -def deep_iterable(member_validator, iterable_validator=None): - """ - A validator that performs deep validation of an iterable. - - Args: - member_validator: Validator(s) to apply to iterable members. - - iterable_validator: - Validator(s) to apply to iterable itself (optional). - - Raises - TypeError: if any sub-validators fail - - .. versionadded:: 19.1.0 - - .. versionchanged:: 25.4.0 - *member_validator* and *iterable_validator* can now be a list or tuple - of validators. - """ - if isinstance(member_validator, (list, tuple)): - member_validator = and_(*member_validator) - if isinstance(iterable_validator, (list, tuple)): - iterable_validator = and_(*iterable_validator) - return _DeepIterable(member_validator, iterable_validator) - - -@attrs(repr=False, slots=True, unsafe_hash=True) -class _DeepMapping: - key_validator = attrib(validator=optional(is_callable())) - value_validator = attrib(validator=optional(is_callable())) - mapping_validator = attrib(validator=optional(is_callable())) - - def __call__(self, inst, attr, value): - """ - We use a callable class to be able to change the ``__repr__``. - """ - if self.mapping_validator is not None: - self.mapping_validator(inst, attr, value) - - for key in value: - if self.key_validator is not None: - self.key_validator(inst, attr, key) - if self.value_validator is not None: - self.value_validator(inst, attr, value[key]) - - def __repr__(self): - return f"" - - -def deep_mapping( - key_validator=None, value_validator=None, mapping_validator=None -): - """ - A validator that performs deep validation of a dictionary. - - All validators are optional, but at least one of *key_validator* or - *value_validator* must be provided. - - Args: - key_validator: Validator(s) to apply to dictionary keys. - - value_validator: Validator(s) to apply to dictionary values. - - mapping_validator: - Validator(s) to apply to top-level mapping attribute. - - .. versionadded:: 19.1.0 - - .. versionchanged:: 25.4.0 - *key_validator* and *value_validator* are now optional, but at least one - of them must be provided. - - .. versionchanged:: 25.4.0 - *key_validator*, *value_validator*, and *mapping_validator* can now be a - list or tuple of validators. - - Raises: - TypeError: If any sub-validator fails on validation. - - ValueError: - If neither *key_validator* nor *value_validator* is provided on - instantiation. - """ - if key_validator is None and value_validator is None: - msg = ( - "At least one of key_validator or value_validator must be provided" - ) - raise ValueError(msg) - - if isinstance(key_validator, (list, tuple)): - key_validator = and_(*key_validator) - if isinstance(value_validator, (list, tuple)): - value_validator = and_(*value_validator) - if isinstance(mapping_validator, (list, tuple)): - mapping_validator = and_(*mapping_validator) - - return _DeepMapping(key_validator, value_validator, mapping_validator) - - -@attrs(repr=False, frozen=True, slots=True) -class _NumberValidator: - bound = attrib() - compare_op = attrib() - compare_func = attrib() - - def __call__(self, inst, attr, value): - """ - We use a callable class to be able to change the ``__repr__``. - """ - if not self.compare_func(value, self.bound): - msg = f"'{attr.name}' must be {self.compare_op} {self.bound}: {value}" - raise ValueError(msg) - - def __repr__(self): - return f"" - - -def lt(val): - """ - A validator that raises `ValueError` if the initializer is called with a - number larger or equal to *val*. - - The validator uses `operator.lt` to compare the values. - - Args: - val: Exclusive upper bound for values. - - .. versionadded:: 21.3.0 - """ - return _NumberValidator(val, "<", operator.lt) - - -def le(val): - """ - A validator that raises `ValueError` if the initializer is called with a - number greater than *val*. - - The validator uses `operator.le` to compare the values. - - Args: - val: Inclusive upper bound for values. - - .. versionadded:: 21.3.0 - """ - return _NumberValidator(val, "<=", operator.le) - - -def ge(val): - """ - A validator that raises `ValueError` if the initializer is called with a - number smaller than *val*. - - The validator uses `operator.ge` to compare the values. - - Args: - val: Inclusive lower bound for values - - .. versionadded:: 21.3.0 - """ - return _NumberValidator(val, ">=", operator.ge) - - -def gt(val): - """ - A validator that raises `ValueError` if the initializer is called with a - number smaller or equal to *val*. - - The validator uses `operator.gt` to compare the values. - - Args: - val: Exclusive lower bound for values - - .. versionadded:: 21.3.0 - """ - return _NumberValidator(val, ">", operator.gt) - - -@attrs(repr=False, frozen=True, slots=True) -class _MaxLengthValidator: - max_length = attrib() - - def __call__(self, inst, attr, value): - """ - We use a callable class to be able to change the ``__repr__``. - """ - if len(value) > self.max_length: - msg = f"Length of '{attr.name}' must be <= {self.max_length}: {len(value)}" - raise ValueError(msg) - - def __repr__(self): - return f"" - - -def max_len(length): - """ - A validator that raises `ValueError` if the initializer is called - with a string or iterable that is longer than *length*. - - Args: - length (int): Maximum length of the string or iterable - - .. versionadded:: 21.3.0 - """ - return _MaxLengthValidator(length) - - -@attrs(repr=False, frozen=True, slots=True) -class _MinLengthValidator: - min_length = attrib() - - def __call__(self, inst, attr, value): - """ - We use a callable class to be able to change the ``__repr__``. - """ - if len(value) < self.min_length: - msg = f"Length of '{attr.name}' must be >= {self.min_length}: {len(value)}" - raise ValueError(msg) - - def __repr__(self): - return f"" - - -def min_len(length): - """ - A validator that raises `ValueError` if the initializer is called - with a string or iterable that is shorter than *length*. - - Args: - length (int): Minimum length of the string or iterable - - .. versionadded:: 22.1.0 - """ - return _MinLengthValidator(length) - - -@attrs(repr=False, slots=True, unsafe_hash=True) -class _SubclassOfValidator: - type = attrib() - - def __call__(self, inst, attr, value): - """ - We use a callable class to be able to change the ``__repr__``. - """ - if not issubclass(value, self.type): - msg = f"'{attr.name}' must be a subclass of {self.type!r} (got {value!r})." - raise TypeError( - msg, - attr, - self.type, - value, - ) - - def __repr__(self): - return f"" - - -def _subclass_of(type): - """ - A validator that raises a `TypeError` if the initializer is called with a - wrong type for this particular attribute (checks are performed using - `issubclass` therefore it's also valid to pass a tuple of types). - - Args: - type (type | tuple[type, ...]): The type(s) to check for. - - Raises: - TypeError: - With a human readable error message, the attribute (of type - `attrs.Attribute`), the expected type, and the value it got. - """ - return _SubclassOfValidator(type) - - -@attrs(repr=False, slots=True, unsafe_hash=True) -class _NotValidator: - validator = attrib() - msg = attrib( - converter=default_if_none( - "not_ validator child '{validator!r}' " - "did not raise a captured error" - ) - ) - exc_types = attrib( - validator=deep_iterable( - member_validator=_subclass_of(Exception), - iterable_validator=instance_of(tuple), - ), - ) - - def __call__(self, inst, attr, value): - try: - self.validator(inst, attr, value) - except self.exc_types: - pass # suppress error to invert validity - else: - raise ValueError( - self.msg.format( - validator=self.validator, - exc_types=self.exc_types, - ), - attr, - self.validator, - value, - self.exc_types, - ) - - def __repr__(self): - return f"" - - -def not_(validator, *, msg=None, exc_types=(ValueError, TypeError)): - """ - A validator that wraps and logically 'inverts' the validator passed to it. - It will raise a `ValueError` if the provided validator *doesn't* raise a - `ValueError` or `TypeError` (by default), and will suppress the exception - if the provided validator *does*. - - Intended to be used with existing validators to compose logic without - needing to create inverted variants, for example, ``not_(in_(...))``. - - Args: - validator: A validator to be logically inverted. - - msg (str): - Message to raise if validator fails. Formatted with keys - ``exc_types`` and ``validator``. - - exc_types (tuple[type, ...]): - Exception type(s) to capture. Other types raised by child - validators will not be intercepted and pass through. - - Raises: - ValueError: - With a human readable error message, the attribute (of type - `attrs.Attribute`), the validator that failed to raise an - exception, the value it got, and the expected exception types. - - .. versionadded:: 22.2.0 - """ - try: - exc_types = tuple(exc_types) - except TypeError: - exc_types = (exc_types,) - return _NotValidator(validator, msg, exc_types) - - -@attrs(repr=False, slots=True, unsafe_hash=True) -class _OrValidator: - validators = attrib() - - def __call__(self, inst, attr, value): - for v in self.validators: - try: - v(inst, attr, value) - except Exception: # noqa: BLE001, PERF203, S112 - continue - else: - return - - msg = f"None of {self.validators!r} satisfied for value {value!r}" - raise ValueError(msg) - - def __repr__(self): - return f"" - - -def or_(*validators): - """ - A validator that composes multiple validators into one. - - When called on a value, it runs all wrapped validators until one of them is - satisfied. - - Args: - validators (~collections.abc.Iterable[typing.Callable]): - Arbitrary number of validators. - - Raises: - ValueError: - If no validator is satisfied. Raised with a human-readable error - message listing all the wrapped validators and the value that - failed all of them. - - .. versionadded:: 24.1.0 - """ - vals = [] - for v in validators: - vals.extend(v.validators if isinstance(v, _OrValidator) else [v]) - - return _OrValidator(tuple(vals)) diff --git a/venv/lib/python3.9/site-packages/attr/validators.pyi b/venv/lib/python3.9/site-packages/attr/validators.pyi deleted file mode 100644 index 18fb112..0000000 --- a/venv/lib/python3.9/site-packages/attr/validators.pyi +++ /dev/null @@ -1,140 +0,0 @@ -from types import UnionType -from typing import ( - Any, - AnyStr, - Callable, - Container, - ContextManager, - Iterable, - Mapping, - Match, - Pattern, - TypeVar, - overload, -) - -from attrs import _ValidatorType -from attrs import _ValidatorArgType - -_T = TypeVar("_T") -_T1 = TypeVar("_T1") -_T2 = TypeVar("_T2") -_T3 = TypeVar("_T3") -_T4 = TypeVar("_T4") -_T5 = TypeVar("_T5") -_T6 = TypeVar("_T6") -_I = TypeVar("_I", bound=Iterable) -_K = TypeVar("_K") -_V = TypeVar("_V") -_M = TypeVar("_M", bound=Mapping) - -def set_disabled(run: bool) -> None: ... -def get_disabled() -> bool: ... -def disabled() -> ContextManager[None]: ... - -# To be more precise on instance_of use some overloads. -# If there are more than 3 items in the tuple then we fall back to Any -@overload -def instance_of(type: type[_T]) -> _ValidatorType[_T]: ... -@overload -def instance_of(type: tuple[type[_T]]) -> _ValidatorType[_T]: ... -@overload -def instance_of( - type: tuple[type[_T1], type[_T2]], -) -> _ValidatorType[_T1 | _T2]: ... -@overload -def instance_of( - type: tuple[type[_T1], type[_T2], type[_T3]], -) -> _ValidatorType[_T1 | _T2 | _T3]: ... -@overload -def instance_of(type: tuple[type, ...]) -> _ValidatorType[Any]: ... -@overload -def instance_of(type: UnionType) -> _ValidatorType[Any]: ... -def optional( - validator: ( - _ValidatorType[_T] - | list[_ValidatorType[_T]] - | tuple[_ValidatorType[_T], ...] - ), -) -> _ValidatorType[_T | None]: ... -def in_(options: Container[_T]) -> _ValidatorType[_T]: ... -def and_(*validators: _ValidatorType[_T]) -> _ValidatorType[_T]: ... -def matches_re( - regex: Pattern[AnyStr] | AnyStr, - flags: int = ..., - func: Callable[[AnyStr, AnyStr, int], Match[AnyStr] | None] | None = ..., -) -> _ValidatorType[AnyStr]: ... -def deep_iterable( - member_validator: _ValidatorArgType[_T], - iterable_validator: _ValidatorArgType[_I] | None = ..., -) -> _ValidatorType[_I]: ... -@overload -def deep_mapping( - key_validator: _ValidatorArgType[_K], - value_validator: _ValidatorArgType[_V] | None = ..., - mapping_validator: _ValidatorArgType[_M] | None = ..., -) -> _ValidatorType[_M]: ... -@overload -def deep_mapping( - key_validator: _ValidatorArgType[_K] | None = ..., - value_validator: _ValidatorArgType[_V] = ..., - mapping_validator: _ValidatorArgType[_M] | None = ..., -) -> _ValidatorType[_M]: ... -def is_callable() -> _ValidatorType[_T]: ... -def lt(val: _T) -> _ValidatorType[_T]: ... -def le(val: _T) -> _ValidatorType[_T]: ... -def ge(val: _T) -> _ValidatorType[_T]: ... -def gt(val: _T) -> _ValidatorType[_T]: ... -def max_len(length: int) -> _ValidatorType[_T]: ... -def min_len(length: int) -> _ValidatorType[_T]: ... -def not_( - validator: _ValidatorType[_T], - *, - msg: str | None = None, - exc_types: type[Exception] | Iterable[type[Exception]] = ..., -) -> _ValidatorType[_T]: ... -@overload -def or_( - __v1: _ValidatorType[_T1], - __v2: _ValidatorType[_T2], -) -> _ValidatorType[_T1 | _T2]: ... -@overload -def or_( - __v1: _ValidatorType[_T1], - __v2: _ValidatorType[_T2], - __v3: _ValidatorType[_T3], -) -> _ValidatorType[_T1 | _T2 | _T3]: ... -@overload -def or_( - __v1: _ValidatorType[_T1], - __v2: _ValidatorType[_T2], - __v3: _ValidatorType[_T3], - __v4: _ValidatorType[_T4], -) -> _ValidatorType[_T1 | _T2 | _T3 | _T4]: ... -@overload -def or_( - __v1: _ValidatorType[_T1], - __v2: _ValidatorType[_T2], - __v3: _ValidatorType[_T3], - __v4: _ValidatorType[_T4], - __v5: _ValidatorType[_T5], -) -> _ValidatorType[_T1 | _T2 | _T3 | _T4 | _T5]: ... -@overload -def or_( - __v1: _ValidatorType[_T1], - __v2: _ValidatorType[_T2], - __v3: _ValidatorType[_T3], - __v4: _ValidatorType[_T4], - __v5: _ValidatorType[_T5], - __v6: _ValidatorType[_T6], -) -> _ValidatorType[_T1 | _T2 | _T3 | _T4 | _T5 | _T6]: ... -@overload -def or_( - __v1: _ValidatorType[Any], - __v2: _ValidatorType[Any], - __v3: _ValidatorType[Any], - __v4: _ValidatorType[Any], - __v5: _ValidatorType[Any], - __v6: _ValidatorType[Any], - *validators: _ValidatorType[Any], -) -> _ValidatorType[Any]: ... diff --git a/venv/lib/python3.9/site-packages/attrs-26.1.0.dist-info/INSTALLER b/venv/lib/python3.9/site-packages/attrs-26.1.0.dist-info/INSTALLER deleted file mode 100644 index a1b589e..0000000 --- a/venv/lib/python3.9/site-packages/attrs-26.1.0.dist-info/INSTALLER +++ /dev/null @@ -1 +0,0 @@ -pip diff --git a/venv/lib/python3.9/site-packages/attrs-26.1.0.dist-info/METADATA b/venv/lib/python3.9/site-packages/attrs-26.1.0.dist-info/METADATA deleted file mode 100644 index 5cf16a0..0000000 --- a/venv/lib/python3.9/site-packages/attrs-26.1.0.dist-info/METADATA +++ /dev/null @@ -1,199 +0,0 @@ -Metadata-Version: 2.4 -Name: attrs -Version: 26.1.0 -Summary: Classes Without Boilerplate -Project-URL: Documentation, https://www.attrs.org/ -Project-URL: Changelog, https://www.attrs.org/en/stable/changelog.html -Project-URL: GitHub, https://github.com/python-attrs/attrs -Project-URL: Funding, https://github.com/sponsors/hynek -Project-URL: Tidelift, https://tidelift.com/subscription/pkg/pypi-attrs?utm_source=pypi-attrs&utm_medium=pypi -Author-email: Hynek Schlawack -License-Expression: MIT -License-File: LICENSE -Keywords: attribute,boilerplate,class -Classifier: Development Status :: 5 - Production/Stable -Classifier: Programming Language :: Python :: 3.9 -Classifier: Programming Language :: Python :: 3.10 -Classifier: Programming Language :: Python :: 3.11 -Classifier: Programming Language :: Python :: 3.12 -Classifier: Programming Language :: Python :: 3.13 -Classifier: Programming Language :: Python :: 3.14 -Classifier: Programming Language :: Python :: Implementation :: CPython -Classifier: Programming Language :: Python :: Implementation :: PyPy -Classifier: Typing :: Typed -Requires-Python: >=3.9 -Description-Content-Type: text/markdown - -

    - - attrs - -

    - - -*attrs* is the Python package that will bring back the **joy** of **writing classes** by relieving you from the drudgery of implementing object protocols (aka [dunder methods](https://www.attrs.org/en/latest/glossary.html#term-dunder-methods)). -Trusted by NASA for [Mars missions since 2020](https://github.com/readme/featured/nasa-ingenuity-helicopter)! - -Its main goal is to help you to write **concise** and **correct** software without slowing down your code. - - -## Sponsors - -*attrs* would not be possible without our [amazing sponsors](https://github.com/sponsors/hynek). -Especially those generously supporting us at the *The Organization* tier and higher: - - - -

    - - - - - - - - - - - -

    - - - -

    - Please consider joining them to help make attrs’s maintenance more sustainable! -

    - - - -## Example - -*attrs* gives you a class decorator and a way to declaratively define the attributes on that class: - - - -```pycon ->>> from attrs import asdict, define, make_class, Factory - ->>> @define -... class SomeClass: -... a_number: int = 42 -... list_of_numbers: list[int] = Factory(list) -... -... def hard_math(self, another_number): -... return self.a_number + sum(self.list_of_numbers) * another_number - - ->>> sc = SomeClass(1, [1, 2, 3]) ->>> sc -SomeClass(a_number=1, list_of_numbers=[1, 2, 3]) - ->>> sc.hard_math(3) -19 ->>> sc == SomeClass(1, [1, 2, 3]) -True ->>> sc != SomeClass(2, [3, 2, 1]) -True - ->>> asdict(sc) -{'a_number': 1, 'list_of_numbers': [1, 2, 3]} - ->>> SomeClass() -SomeClass(a_number=42, list_of_numbers=[]) - ->>> C = make_class("C", ["a", "b"]) ->>> C("foo", "bar") -C(a='foo', b='bar') -``` - -After *declaring* your attributes, *attrs* gives you: - -- a concise and explicit overview of the class's attributes, -- a nice human-readable `__repr__`, -- equality-checking methods, -- an initializer, -- and much more, - -*without* writing dull boilerplate code again and again and *without* runtime performance penalties. - ---- - -This example uses *attrs*'s modern APIs that have been introduced in version 20.1.0, and the *attrs* package import name that has been added in version 21.3.0. -The classic APIs (`@attr.s`, `attr.ib`, plus their serious-business aliases) and the `attr` package import name will remain **indefinitely**. - -Check out [*On The Core API Names*](https://www.attrs.org/en/latest/names.html) for an in-depth explanation! - - -### Hate Type Annotations!? - -No problem! -Types are entirely **optional** with *attrs*. -Simply assign `attrs.field()` to the attributes instead of annotating them with types: - -```python -from attrs import define, field - -@define -class SomeClass: - a_number = field(default=42) - list_of_numbers = field(factory=list) -``` - - -## Data Classes - -On the tin, *attrs* might remind you of `dataclasses` (and indeed, `dataclasses` [are a descendant](https://hynek.me/articles/import-attrs/) of *attrs*). -In practice it does a lot more and is more flexible. -For instance, it allows you to define [special handling of NumPy arrays for equality checks](https://www.attrs.org/en/stable/comparison.html#customization), allows more ways to [plug into the initialization process](https://www.attrs.org/en/stable/init.html#hooking-yourself-into-initialization), has a replacement for `__init_subclass__`, and allows for stepping through the generated methods using a debugger. - -For more details, please refer to our [comparison page](https://www.attrs.org/en/stable/why.html#data-classes), but generally speaking, we are more likely to commit crimes against nature to make things work that one would expect to work, but that are quite complicated in practice. - - -## Project Information - -- [**Changelog**](https://www.attrs.org/en/stable/changelog.html) -- [**Documentation**](https://www.attrs.org/) -- [**PyPI**](https://pypi.org/project/attrs/) -- [**Source Code**](https://github.com/python-attrs/attrs) -- [**Contributing**](https://github.com/python-attrs/attrs/blob/main/.github/CONTRIBUTING.md) -- [**Third-party Extensions**](https://github.com/python-attrs/attrs/wiki/Extensions-to-attrs) -- **Get Help**: use the `python-attrs` tag on [Stack Overflow](https://stackoverflow.com/questions/tagged/python-attrs) - - -### *attrs* for Enterprise - -Available as part of the [Tidelift Subscription](https://tidelift.com/?utm_source=lifter&utm_medium=referral&utm_campaign=hynek). - -The maintainers of *attrs* and thousands of other packages are working with Tidelift to deliver commercial support and maintenance for the open source packages you use to build your applications. -Save time, reduce risk, and improve code health, while paying the maintainers of the exact packages you use. - -## Release Information - -### Backwards-incompatible Changes - -- Field aliases are now resolved *before* calling `field_transformer`, so transformers receive fully populated `Attribute` objects with usable `alias` values instead of `None`. - The new `Attribute.alias_is_default` flag indicates whether the alias was auto-generated (`True`) or explicitly set by the user (`False`). - [#1509](https://github.com/python-attrs/attrs/issues/1509) - - -### Changes - -- Fix type annotations for `attrs.validators.optional()`, so it no longer rejects tuples with more than one validator. - [#1496](https://github.com/python-attrs/attrs/issues/1496) -- The `attrs.validators.disabled()` contextmanager can now be nested. - [#1513](https://github.com/python-attrs/attrs/issues/1513) -- Frozen classes can set `on_setattr=attrs.setters.NO_OP` in addition to `None`. - [#1515](https://github.com/python-attrs/attrs/issues/1515) -- It's now possible to pass *attrs* **instances** in addition to *attrs* **classes** to `attrs.fields()`. - [#1529](https://github.com/python-attrs/attrs/issues/1529) - - - ---- - -[Full changelog →](https://www.attrs.org/en/stable/changelog.html) diff --git a/venv/lib/python3.9/site-packages/attrs-26.1.0.dist-info/RECORD b/venv/lib/python3.9/site-packages/attrs-26.1.0.dist-info/RECORD deleted file mode 100644 index 585c7ee..0000000 --- a/venv/lib/python3.9/site-packages/attrs-26.1.0.dist-info/RECORD +++ /dev/null @@ -1,55 +0,0 @@ -attr/__init__.py,sha256=fOYIvt1eGSqQre4uCS3sJWKZ0mwAuC8UD6qba5OS9_U,2057 -attr/__init__.pyi,sha256=pVGImAUVovq2_TYl_r_HIYnGlyOaoCuEhxo-EvsnnSc,11325 -attr/__pycache__/__init__.cpython-39.pyc,, -attr/__pycache__/_cmp.cpython-39.pyc,, -attr/__pycache__/_compat.cpython-39.pyc,, -attr/__pycache__/_config.cpython-39.pyc,, -attr/__pycache__/_funcs.cpython-39.pyc,, -attr/__pycache__/_make.cpython-39.pyc,, -attr/__pycache__/_next_gen.cpython-39.pyc,, -attr/__pycache__/_version_info.cpython-39.pyc,, -attr/__pycache__/converters.cpython-39.pyc,, -attr/__pycache__/exceptions.cpython-39.pyc,, -attr/__pycache__/filters.cpython-39.pyc,, -attr/__pycache__/setters.cpython-39.pyc,, -attr/__pycache__/validators.cpython-39.pyc,, -attr/_cmp.py,sha256=3Nn1TjxllUYiX_nJoVnEkXoDk0hM1DYKj5DE7GZe4i0,4117 -attr/_cmp.pyi,sha256=U-_RU_UZOyPUEQzXE6RMYQQcjkZRY25wTH99sN0s7MM,368 -attr/_compat.py,sha256=x0g7iEUOnBVJC72zyFCgb1eKqyxS-7f2LGnNyZ_r95s,2829 -attr/_config.py,sha256=dGq3xR6fgZEF6UBt_L0T-eUHIB4i43kRmH0P28sJVw8,843 -attr/_funcs.py,sha256=Ix5IETTfz5F01F-12MF_CSFomIn2h8b67EVVz2gCtBE,16479 -attr/_make.py,sha256=H7OH2eWS5CnBzLUjNFE1WymfPrmF1r8fv2RPdt9MuYA,106129 -attr/_next_gen.py,sha256=BQtCUlzwg2gWHTYXBQvrEYBnzBUrDvO57u0Py6UCPhc,26274 -attr/_typing_compat.pyi,sha256=XDP54TUn-ZKhD62TOQebmzrwFyomhUCoGRpclb6alRA,469 -attr/_version_info.py,sha256=w4R-FYC3NK_kMkGUWJlYP4cVAlH9HRaC-um3fcjYkHM,2222 -attr/_version_info.pyi,sha256=x_M3L3WuB7r_ULXAWjx959udKQ4HLB8l-hsc1FDGNvk,209 -attr/converters.py,sha256=GlDeOzPeTFgeBBLbj9G57Ez5lAk68uhSALRYJ_exe84,3861 -attr/converters.pyi,sha256=orU2bff-VjQa2kMDyvnMQV73oJT2WRyQuw4ZR1ym1bE,643 -attr/exceptions.py,sha256=b4vMbnoQ3VpwWZhqrYi_ssXVCK8o2c4HQSS09cSUM9o,1990 -attr/exceptions.pyi,sha256=zZq8bCUnKAy9mDtBEw42ZhPhAUIHoTKedDQInJD883M,539 -attr/filters.py,sha256=ZBiKWLp3R0LfCZsq7X11pn9WX8NslS2wXM4jsnLOGc8,1795 -attr/filters.pyi,sha256=3J5BG-dTxltBk1_-RuNRUHrv2qu1v8v4aDNAQ7_mifA,208 -attr/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 -attr/setters.py,sha256=5-dcT63GQK35ONEzSgfXCkbB7pPkaR-qv15mm4PVSzQ,1617 -attr/setters.pyi,sha256=NnVkaFU1BB4JB8E4JuXyrzTUgvtMpj8p3wBdJY7uix4,584 -attr/validators.py,sha256=m3QRzZTANr4f2C4eVdUoFg11NgXWak8Wat4qQTGhvcs,21553 -attr/validators.pyi,sha256=gM1ZmHaBckyYWI2EirpRNzqm3B19cw5Iq6B4Kno9YCM,4087 -attrs-26.1.0.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 -attrs-26.1.0.dist-info/METADATA,sha256=TNQOaQ8jvzfLytNO_WdY4GLfHfB8hoM_fjzpW_H6OMw,8754 -attrs-26.1.0.dist-info/RECORD,, -attrs-26.1.0.dist-info/WHEEL,sha256=QccIxa26bgl1E6uMy58deGWi-0aeIkkangHcxk2kWfw,87 -attrs-26.1.0.dist-info/licenses/LICENSE,sha256=iCEVyV38KvHutnFPjsbVy8q_Znyv-HKfQkINpj9xTp8,1109 -attrs/__init__.py,sha256=RxaAZNwYiEh-fcvHLZNpQ_DWKni73M_jxEPEftiq1Zc,1183 -attrs/__init__.pyi,sha256=2gV79g9UxJppGSM48hAZJ6h_MHb70dZoJL31ZNJeZYI,9416 -attrs/__pycache__/__init__.cpython-39.pyc,, -attrs/__pycache__/converters.cpython-39.pyc,, -attrs/__pycache__/exceptions.cpython-39.pyc,, -attrs/__pycache__/filters.cpython-39.pyc,, -attrs/__pycache__/setters.cpython-39.pyc,, -attrs/__pycache__/validators.cpython-39.pyc,, -attrs/converters.py,sha256=8kQljrVwfSTRu8INwEk8SI0eGrzmWftsT7rM0EqyohM,76 -attrs/exceptions.py,sha256=ACCCmg19-vDFaDPY9vFl199SPXCQMN_bENs4DALjzms,76 -attrs/filters.py,sha256=VOUMZug9uEU6dUuA0dF1jInUK0PL3fLgP0VBS5d-CDE,73 -attrs/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 -attrs/setters.py,sha256=eL1YidYQV3T2h9_SYIZSZR1FAcHGb1TuCTy0E0Lv2SU,73 -attrs/validators.py,sha256=xcy6wD5TtTkdCG1f4XWbocPSO0faBjk5IfVJfP6SUj0,76 diff --git a/venv/lib/python3.9/site-packages/attrs-26.1.0.dist-info/WHEEL b/venv/lib/python3.9/site-packages/attrs-26.1.0.dist-info/WHEEL deleted file mode 100644 index b1b94fd..0000000 --- a/venv/lib/python3.9/site-packages/attrs-26.1.0.dist-info/WHEEL +++ /dev/null @@ -1,4 +0,0 @@ -Wheel-Version: 1.0 -Generator: hatchling 1.29.0 -Root-Is-Purelib: true -Tag: py3-none-any diff --git a/venv/lib/python3.9/site-packages/attrs-26.1.0.dist-info/licenses/LICENSE b/venv/lib/python3.9/site-packages/attrs-26.1.0.dist-info/licenses/LICENSE deleted file mode 100644 index 2bd6453..0000000 --- a/venv/lib/python3.9/site-packages/attrs-26.1.0.dist-info/licenses/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -The MIT License (MIT) - -Copyright (c) 2015 Hynek Schlawack and the attrs contributors - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/venv/lib/python3.9/site-packages/attrs/__init__.py b/venv/lib/python3.9/site-packages/attrs/__init__.py deleted file mode 100644 index dc1ce4b..0000000 --- a/venv/lib/python3.9/site-packages/attrs/__init__.py +++ /dev/null @@ -1,72 +0,0 @@ -# SPDX-License-Identifier: MIT - -from attr import ( - NOTHING, - Attribute, - AttrsInstance, - Converter, - Factory, - NothingType, - _make_getattr, - assoc, - cmp_using, - define, - evolve, - field, - fields, - fields_dict, - frozen, - has, - make_class, - mutable, - resolve_types, - validate, -) -from attr._make import ClassProps -from attr._next_gen import asdict, astuple, inspect - -from . import converters, exceptions, filters, setters, validators - - -__all__ = [ - "NOTHING", - "Attribute", - "AttrsInstance", - "ClassProps", - "Converter", - "Factory", - "NothingType", - "__author__", - "__copyright__", - "__description__", - "__doc__", - "__email__", - "__license__", - "__title__", - "__url__", - "__version__", - "__version_info__", - "asdict", - "assoc", - "astuple", - "cmp_using", - "converters", - "define", - "evolve", - "exceptions", - "field", - "fields", - "fields_dict", - "filters", - "frozen", - "has", - "inspect", - "make_class", - "mutable", - "resolve_types", - "setters", - "validate", - "validators", -] - -__getattr__ = _make_getattr(__name__) diff --git a/venv/lib/python3.9/site-packages/attrs/__init__.pyi b/venv/lib/python3.9/site-packages/attrs/__init__.pyi deleted file mode 100644 index 6364bac..0000000 --- a/venv/lib/python3.9/site-packages/attrs/__init__.pyi +++ /dev/null @@ -1,314 +0,0 @@ -import sys - -from typing import ( - Any, - Callable, - Mapping, - Sequence, - overload, - TypeVar, -) - -# Because we need to type our own stuff, we have to make everything from -# attr explicitly public too. -from attr import __author__ as __author__ -from attr import __copyright__ as __copyright__ -from attr import __description__ as __description__ -from attr import __email__ as __email__ -from attr import __license__ as __license__ -from attr import __title__ as __title__ -from attr import __url__ as __url__ -from attr import __version__ as __version__ -from attr import __version_info__ as __version_info__ -from attr import assoc as assoc -from attr import Attribute as Attribute -from attr import AttrsInstance as AttrsInstance -from attr import cmp_using as cmp_using -from attr import converters as converters -from attr import Converter as Converter -from attr import evolve as evolve -from attr import exceptions as exceptions -from attr import Factory as Factory -from attr import fields as fields -from attr import fields_dict as fields_dict -from attr import filters as filters -from attr import has as has -from attr import make_class as make_class -from attr import NOTHING as NOTHING -from attr import resolve_types as resolve_types -from attr import setters as setters -from attr import validate as validate -from attr import validators as validators -from attr import attrib, asdict as asdict, astuple as astuple -from attr import NothingType as NothingType - -if sys.version_info >= (3, 11): - from typing import dataclass_transform -else: - from typing_extensions import dataclass_transform - -_T = TypeVar("_T") -_C = TypeVar("_C", bound=type) - -_EqOrderType = bool | Callable[[Any], Any] -_ValidatorType = Callable[[Any, "Attribute[_T]", _T], Any] -_CallableConverterType = Callable[[Any], Any] -_ConverterType = _CallableConverterType | Converter[Any, Any] -_ReprType = Callable[[Any], str] -_ReprArgType = bool | _ReprType -_OnSetAttrType = Callable[[Any, "Attribute[Any]", Any], Any] -_OnSetAttrArgType = _OnSetAttrType | list[_OnSetAttrType] | setters._NoOpType -_FieldTransformer = Callable[ - [type, list["Attribute[Any]"]], list["Attribute[Any]"] -] -# FIXME: in reality, if multiple validators are passed they must be in a list -# or tuple, but those are invariant and so would prevent subtypes of -# _ValidatorType from working when passed in a list or tuple. -_ValidatorArgType = _ValidatorType[_T] | Sequence[_ValidatorType[_T]] - -@overload -def field( - *, - default: None = ..., - validator: None = ..., - repr: _ReprArgType = ..., - hash: bool | None = ..., - init: bool = ..., - metadata: Mapping[Any, Any] | None = ..., - converter: None = ..., - factory: None = ..., - kw_only: bool | None = ..., - eq: bool | None = ..., - order: bool | None = ..., - on_setattr: _OnSetAttrArgType | None = ..., - alias: str | None = ..., - type: type | None = ..., -) -> Any: ... - -# This form catches an explicit None or no default and infers the type from the -# other arguments. -@overload -def field( - *, - default: None = ..., - validator: _ValidatorArgType[_T] | None = ..., - repr: _ReprArgType = ..., - hash: bool | None = ..., - init: bool = ..., - metadata: Mapping[Any, Any] | None = ..., - converter: _ConverterType - | list[_ConverterType] - | tuple[_ConverterType, ...] - | None = ..., - factory: Callable[[], _T] | None = ..., - kw_only: bool | None = ..., - eq: _EqOrderType | None = ..., - order: _EqOrderType | None = ..., - on_setattr: _OnSetAttrArgType | None = ..., - alias: str | None = ..., - type: type | None = ..., -) -> _T: ... - -# This form catches an explicit default argument. -@overload -def field( - *, - default: _T, - validator: _ValidatorArgType[_T] | None = ..., - repr: _ReprArgType = ..., - hash: bool | None = ..., - init: bool = ..., - metadata: Mapping[Any, Any] | None = ..., - converter: _ConverterType - | list[_ConverterType] - | tuple[_ConverterType, ...] - | None = ..., - factory: Callable[[], _T] | None = ..., - kw_only: bool | None = ..., - eq: _EqOrderType | None = ..., - order: _EqOrderType | None = ..., - on_setattr: _OnSetAttrArgType | None = ..., - alias: str | None = ..., - type: type | None = ..., -) -> _T: ... - -# This form covers type=non-Type: e.g. forward references (str), Any -@overload -def field( - *, - default: _T | None = ..., - validator: _ValidatorArgType[_T] | None = ..., - repr: _ReprArgType = ..., - hash: bool | None = ..., - init: bool = ..., - metadata: Mapping[Any, Any] | None = ..., - converter: _ConverterType - | list[_ConverterType] - | tuple[_ConverterType, ...] - | None = ..., - factory: Callable[[], _T] | None = ..., - kw_only: bool | None = ..., - eq: _EqOrderType | None = ..., - order: _EqOrderType | None = ..., - on_setattr: _OnSetAttrArgType | None = ..., - alias: str | None = ..., - type: type | None = ..., -) -> Any: ... -@overload -@dataclass_transform(field_specifiers=(attrib, field)) -def define( - maybe_cls: _C, - *, - these: dict[str, Any] | None = ..., - repr: bool = ..., - unsafe_hash: bool | None = ..., - hash: bool | None = ..., - init: bool = ..., - slots: bool = ..., - frozen: bool = ..., - weakref_slot: bool = ..., - str: bool = ..., - auto_attribs: bool = ..., - kw_only: bool = ..., - cache_hash: bool = ..., - auto_exc: bool = ..., - eq: bool | None = ..., - order: bool | None = ..., - auto_detect: bool = ..., - getstate_setstate: bool | None = ..., - on_setattr: _OnSetAttrArgType | None = ..., - field_transformer: _FieldTransformer | None = ..., - match_args: bool = ..., -) -> _C: ... -@overload -@dataclass_transform(field_specifiers=(attrib, field)) -def define( - maybe_cls: None = ..., - *, - these: dict[str, Any] | None = ..., - repr: bool = ..., - unsafe_hash: bool | None = ..., - hash: bool | None = ..., - init: bool = ..., - slots: bool = ..., - frozen: bool = ..., - weakref_slot: bool = ..., - str: bool = ..., - auto_attribs: bool = ..., - kw_only: bool = ..., - cache_hash: bool = ..., - auto_exc: bool = ..., - eq: bool | None = ..., - order: bool | None = ..., - auto_detect: bool = ..., - getstate_setstate: bool | None = ..., - on_setattr: _OnSetAttrArgType | None = ..., - field_transformer: _FieldTransformer | None = ..., - match_args: bool = ..., -) -> Callable[[_C], _C]: ... - -mutable = define - -@overload -@dataclass_transform(frozen_default=True, field_specifiers=(attrib, field)) -def frozen( - maybe_cls: _C, - *, - these: dict[str, Any] | None = ..., - repr: bool = ..., - unsafe_hash: bool | None = ..., - hash: bool | None = ..., - init: bool = ..., - slots: bool = ..., - frozen: bool = ..., - weakref_slot: bool = ..., - str: bool = ..., - auto_attribs: bool = ..., - kw_only: bool = ..., - cache_hash: bool = ..., - auto_exc: bool = ..., - eq: bool | None = ..., - order: bool | None = ..., - auto_detect: bool = ..., - getstate_setstate: bool | None = ..., - on_setattr: _OnSetAttrArgType | None = ..., - field_transformer: _FieldTransformer | None = ..., - match_args: bool = ..., -) -> _C: ... -@overload -@dataclass_transform(frozen_default=True, field_specifiers=(attrib, field)) -def frozen( - maybe_cls: None = ..., - *, - these: dict[str, Any] | None = ..., - repr: bool = ..., - unsafe_hash: bool | None = ..., - hash: bool | None = ..., - init: bool = ..., - slots: bool = ..., - frozen: bool = ..., - weakref_slot: bool = ..., - str: bool = ..., - auto_attribs: bool = ..., - kw_only: bool = ..., - cache_hash: bool = ..., - auto_exc: bool = ..., - eq: bool | None = ..., - order: bool | None = ..., - auto_detect: bool = ..., - getstate_setstate: bool | None = ..., - on_setattr: _OnSetAttrArgType | None = ..., - field_transformer: _FieldTransformer | None = ..., - match_args: bool = ..., -) -> Callable[[_C], _C]: ... - -class ClassProps: - # XXX: somehow when defining/using enums Mypy starts looking at our own - # (untyped) code and causes tons of errors. - Hashability: Any - KeywordOnly: Any - - is_exception: bool - is_slotted: bool - has_weakref_slot: bool - is_frozen: bool - # kw_only: ClassProps.KeywordOnly - kw_only: Any - collected_fields_by_mro: bool - added_init: bool - added_repr: bool - added_eq: bool - added_ordering: bool - # hashability: ClassProps.Hashability - hashability: Any - added_match_args: bool - added_str: bool - added_pickling: bool - on_setattr_hook: _OnSetAttrType | None - field_transformer: Callable[[Attribute[Any]], Attribute[Any]] | None - - def __init__( - self, - is_exception: bool, - is_slotted: bool, - has_weakref_slot: bool, - is_frozen: bool, - # kw_only: ClassProps.KeywordOnly - kw_only: Any, - collected_fields_by_mro: bool, - added_init: bool, - added_repr: bool, - added_eq: bool, - added_ordering: bool, - # hashability: ClassProps.Hashability - hashability: Any, - added_match_args: bool, - added_str: bool, - added_pickling: bool, - on_setattr_hook: _OnSetAttrType, - field_transformer: Callable[[Attribute[Any]], Attribute[Any]], - ) -> None: ... - @property - def is_hashable(self) -> bool: ... - -def inspect(cls: type) -> ClassProps: ... diff --git a/venv/lib/python3.9/site-packages/attrs/converters.py b/venv/lib/python3.9/site-packages/attrs/converters.py deleted file mode 100644 index 7821f6c..0000000 --- a/venv/lib/python3.9/site-packages/attrs/converters.py +++ /dev/null @@ -1,3 +0,0 @@ -# SPDX-License-Identifier: MIT - -from attr.converters import * # noqa: F403 diff --git a/venv/lib/python3.9/site-packages/attrs/exceptions.py b/venv/lib/python3.9/site-packages/attrs/exceptions.py deleted file mode 100644 index 3323f9d..0000000 --- a/venv/lib/python3.9/site-packages/attrs/exceptions.py +++ /dev/null @@ -1,3 +0,0 @@ -# SPDX-License-Identifier: MIT - -from attr.exceptions import * # noqa: F403 diff --git a/venv/lib/python3.9/site-packages/attrs/filters.py b/venv/lib/python3.9/site-packages/attrs/filters.py deleted file mode 100644 index 3080f48..0000000 --- a/venv/lib/python3.9/site-packages/attrs/filters.py +++ /dev/null @@ -1,3 +0,0 @@ -# SPDX-License-Identifier: MIT - -from attr.filters import * # noqa: F403 diff --git a/venv/lib/python3.9/site-packages/attrs/py.typed b/venv/lib/python3.9/site-packages/attrs/py.typed deleted file mode 100644 index e69de29..0000000 diff --git a/venv/lib/python3.9/site-packages/attrs/setters.py b/venv/lib/python3.9/site-packages/attrs/setters.py deleted file mode 100644 index f3d73bb..0000000 --- a/venv/lib/python3.9/site-packages/attrs/setters.py +++ /dev/null @@ -1,3 +0,0 @@ -# SPDX-License-Identifier: MIT - -from attr.setters import * # noqa: F403 diff --git a/venv/lib/python3.9/site-packages/attrs/validators.py b/venv/lib/python3.9/site-packages/attrs/validators.py deleted file mode 100644 index 037e124..0000000 --- a/venv/lib/python3.9/site-packages/attrs/validators.py +++ /dev/null @@ -1,3 +0,0 @@ -# SPDX-License-Identifier: MIT - -from attr.validators import * # noqa: F403 diff --git a/venv/lib/python3.9/site-packages/bidict-0.23.1.dist-info/INSTALLER b/venv/lib/python3.9/site-packages/bidict-0.23.1.dist-info/INSTALLER deleted file mode 100644 index a1b589e..0000000 --- a/venv/lib/python3.9/site-packages/bidict-0.23.1.dist-info/INSTALLER +++ /dev/null @@ -1 +0,0 @@ -pip diff --git a/venv/lib/python3.9/site-packages/bidict-0.23.1.dist-info/LICENSE b/venv/lib/python3.9/site-packages/bidict-0.23.1.dist-info/LICENSE deleted file mode 100644 index d1cc6f8..0000000 --- a/venv/lib/python3.9/site-packages/bidict-0.23.1.dist-info/LICENSE +++ /dev/null @@ -1,376 +0,0 @@ -Mozilla Public License Version 2.0 -================================== - -Copyright 2009-2024 Joshua Bronson. All rights reserved. - - -1. Definitions --------------- - -1.1. "Contributor" - means each individual or legal entity that creates, contributes to - the creation of, or owns Covered Software. - -1.2. "Contributor Version" - means the combination of the Contributions of others (if any) used - by a Contributor and that particular Contributor's Contribution. - -1.3. "Contribution" - means Covered Software of a particular Contributor. - -1.4. "Covered Software" - means Source Code Form to which the initial Contributor has attached - the notice in Exhibit A, the Executable Form of such Source Code - Form, and Modifications of such Source Code Form, in each case - including portions thereof. - -1.5. "Incompatible With Secondary Licenses" - means - - (a) that the initial Contributor has attached the notice described - in Exhibit B to the Covered Software; or - - (b) that the Covered Software was made available under the terms of - version 1.1 or earlier of the License, but not also under the - terms of a Secondary License. - -1.6. "Executable Form" - means any form of the work other than Source Code Form. - -1.7. "Larger Work" - means a work that combines Covered Software with other material, in - a separate file or files, that is not Covered Software. - -1.8. "License" - means this document. - -1.9. "Licensable" - means having the right to grant, to the maximum extent possible, - whether at the time of the initial grant or subsequently, any and - all of the rights conveyed by this License. - -1.10. "Modifications" - means any of the following: - - (a) any file in Source Code Form that results from an addition to, - deletion from, or modification of the contents of Covered - Software; or - - (b) any new file in Source Code Form that contains any Covered - Software. - -1.11. "Patent Claims" of a Contributor - means any patent claim(s), including without limitation, method, - process, and apparatus claims, in any patent Licensable by such - Contributor that would be infringed, but for the grant of the - License, by the making, using, selling, offering for sale, having - made, import, or transfer of either its Contributions or its - Contributor Version. - -1.12. "Secondary License" - means either the GNU General Public License, Version 2.0, the GNU - Lesser General Public License, Version 2.1, the GNU Affero General - Public License, Version 3.0, or any later versions of those - licenses. - -1.13. "Source Code Form" - means the form of the work preferred for making modifications. - -1.14. "You" (or "Your") - means an individual or a legal entity exercising rights under this - License. For legal entities, "You" includes any entity that - controls, is controlled by, or is under common control with You. For - purposes of this definition, "control" means (a) the power, direct - or indirect, to cause the direction or management of such entity, - whether by contract or otherwise, or (b) ownership of more than - fifty percent (50%) of the outstanding shares or beneficial - ownership of such entity. - -2. License Grants and Conditions --------------------------------- - -2.1. Grants - -Each Contributor hereby grants You a world-wide, royalty-free, -non-exclusive license: - -(a) under intellectual property rights (other than patent or trademark) - Licensable by such Contributor to use, reproduce, make available, - modify, display, perform, distribute, and otherwise exploit its - Contributions, either on an unmodified basis, with Modifications, or - as part of a Larger Work; and - -(b) under Patent Claims of such Contributor to make, use, sell, offer - for sale, have made, import, and otherwise transfer either its - Contributions or its Contributor Version. - -2.2. Effective Date - -The licenses granted in Section 2.1 with respect to any Contribution -become effective for each Contribution on the date the Contributor first -distributes such Contribution. - -2.3. Limitations on Grant Scope - -The licenses granted in this Section 2 are the only rights granted under -this License. No additional rights or licenses will be implied from the -distribution or licensing of Covered Software under this License. -Notwithstanding Section 2.1(b) above, no patent license is granted by a -Contributor: - -(a) for any code that a Contributor has removed from Covered Software; - or - -(b) for infringements caused by: (i) Your and any other third party's - modifications of Covered Software, or (ii) the combination of its - Contributions with other software (except as part of its Contributor - Version); or - -(c) under Patent Claims infringed by Covered Software in the absence of - its Contributions. - -This License does not grant any rights in the trademarks, service marks, -or logos of any Contributor (except as may be necessary to comply with -the notice requirements in Section 3.4). - -2.4. Subsequent Licenses - -No Contributor makes additional grants as a result of Your choice to -distribute the Covered Software under a subsequent version of this -License (see Section 10.2) or under the terms of a Secondary License (if -permitted under the terms of Section 3.3). - -2.5. Representation - -Each Contributor represents that the Contributor believes its -Contributions are its original creation(s) or it has sufficient rights -to grant the rights to its Contributions conveyed by this License. - -2.6. Fair Use - -This License is not intended to limit any rights You have under -applicable copyright doctrines of fair use, fair dealing, or other -equivalents. - -2.7. Conditions - -Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted -in Section 2.1. - -3. Responsibilities -------------------- - -3.1. Distribution of Source Form - -All distribution of Covered Software in Source Code Form, including any -Modifications that You create or to which You contribute, must be under -the terms of this License. You must inform recipients that the Source -Code Form of the Covered Software is governed by the terms of this -License, and how they can obtain a copy of this License. You may not -attempt to alter or restrict the recipients' rights in the Source Code -Form. - -3.2. Distribution of Executable Form - -If You distribute Covered Software in Executable Form then: - -(a) such Covered Software must also be made available in Source Code - Form, as described in Section 3.1, and You must inform recipients of - the Executable Form how they can obtain a copy of such Source Code - Form by reasonable means in a timely manner, at a charge no more - than the cost of distribution to the recipient; and - -(b) You may distribute such Executable Form under the terms of this - License, or sublicense it under different terms, provided that the - license for the Executable Form does not attempt to limit or alter - the recipients' rights in the Source Code Form under this License. - -3.3. Distribution of a Larger Work - -You may create and distribute a Larger Work under terms of Your choice, -provided that You also comply with the requirements of this License for -the Covered Software. If the Larger Work is a combination of Covered -Software with a work governed by one or more Secondary Licenses, and the -Covered Software is not Incompatible With Secondary Licenses, this -License permits You to additionally distribute such Covered Software -under the terms of such Secondary License(s), so that the recipient of -the Larger Work may, at their option, further distribute the Covered -Software under the terms of either this License or such Secondary -License(s). - -3.4. Notices - -You may not remove or alter the substance of any license notices -(including copyright notices, patent notices, disclaimers of warranty, -or limitations of liability) contained within the Source Code Form of -the Covered Software, except that You may alter any license notices to -the extent required to remedy known factual inaccuracies. - -3.5. Application of Additional Terms - -You may choose to offer, and to charge a fee for, warranty, support, -indemnity or liability obligations to one or more recipients of Covered -Software. However, You may do so only on Your own behalf, and not on -behalf of any Contributor. You must make it absolutely clear that any -such warranty, support, indemnity, or liability obligation is offered by -You alone, and You hereby agree to indemnify every Contributor for any -liability incurred by such Contributor as a result of warranty, support, -indemnity or liability terms You offer. You may include additional -disclaimers of warranty and limitations of liability specific to any -jurisdiction. - -4. Inability to Comply Due to Statute or Regulation ---------------------------------------------------- - -If it is impossible for You to comply with any of the terms of this -License with respect to some or all of the Covered Software due to -statute, judicial order, or regulation then You must: (a) comply with -the terms of this License to the maximum extent possible; and (b) -describe the limitations and the code they affect. Such description must -be placed in a text file included with all distributions of the Covered -Software under this License. Except to the extent prohibited by statute -or regulation, such description must be sufficiently detailed for a -recipient of ordinary skill to be able to understand it. - -5. Termination --------------- - -5.1. The rights granted under this License will terminate automatically -if You fail to comply with any of its terms. However, if You become -compliant, then the rights granted under this License from a particular -Contributor are reinstated (a) provisionally, unless and until such -Contributor explicitly and finally terminates Your grants, and (b) on an -ongoing basis, if such Contributor fails to notify You of the -non-compliance by some reasonable means prior to 60 days after You have -come back into compliance. Moreover, Your grants from a particular -Contributor are reinstated on an ongoing basis if such Contributor -notifies You of the non-compliance by some reasonable means, this is the -first time You have received notice of non-compliance with this License -from such Contributor, and You become compliant prior to 30 days after -Your receipt of the notice. - -5.2. If You initiate litigation against any entity by asserting a patent -infringement claim (excluding declaratory judgment actions, -counter-claims, and cross-claims) alleging that a Contributor Version -directly or indirectly infringes any patent, then the rights granted to -You by any and all Contributors for the Covered Software under Section -2.1 of this License shall terminate. - -5.3. In the event of termination under Sections 5.1 or 5.2 above, all -end user license agreements (excluding distributors and resellers) which -have been validly granted by You or Your distributors under this License -prior to termination shall survive termination. - -************************************************************************ -* * -* 6. Disclaimer of Warranty * -* ------------------------- * -* * -* Covered Software is provided under this License on an "as is" * -* basis, without warranty of any kind, either expressed, implied, or * -* statutory, including, without limitation, warranties that the * -* Covered Software is free of defects, merchantable, fit for a * -* particular purpose or non-infringing. The entire risk as to the * -* quality and performance of the Covered Software is with You. * -* Should any Covered Software prove defective in any respect, You * -* (not any Contributor) assume the cost of any necessary servicing, * -* repair, or correction. This disclaimer of warranty constitutes an * -* essential part of this License. No use of any Covered Software is * -* authorized under this License except under this disclaimer. * -* * -************************************************************************ - -************************************************************************ -* * -* 7. Limitation of Liability * -* -------------------------- * -* * -* Under no circumstances and under no legal theory, whether tort * -* (including negligence), contract, or otherwise, shall any * -* Contributor, or anyone who distributes Covered Software as * -* permitted above, be liable to You for any direct, indirect, * -* special, incidental, or consequential damages of any character * -* including, without limitation, damages for lost profits, loss of * -* goodwill, work stoppage, computer failure or malfunction, or any * -* and all other commercial damages or losses, even if such party * -* shall have been informed of the possibility of such damages. This * -* limitation of liability shall not apply to liability for death or * -* personal injury resulting from such party's negligence to the * -* extent applicable law prohibits such limitation. Some * -* jurisdictions do not allow the exclusion or limitation of * -* incidental or consequential damages, so this exclusion and * -* limitation may not apply to You. * -* * -************************************************************************ - -8. Litigation -------------- - -Any litigation relating to this License may be brought only in the -courts of a jurisdiction where the defendant maintains its principal -place of business and such litigation shall be governed by laws of that -jurisdiction, without reference to its conflict-of-law provisions. -Nothing in this Section shall prevent a party's ability to bring -cross-claims or counter-claims. - -9. Miscellaneous ----------------- - -This License represents the complete agreement concerning the subject -matter hereof. If any provision of this License is held to be -unenforceable, such provision shall be reformed only to the extent -necessary to make it enforceable. Any law or regulation which provides -that the language of a contract shall be construed against the drafter -shall not be used to construe this License against a Contributor. - -10. Versions of the License ---------------------------- - -10.1. New Versions - -Mozilla Foundation is the license steward. Except as provided in Section -10.3, no one other than the license steward has the right to modify or -publish new versions of this License. Each version will be given a -distinguishing version number. - -10.2. Effect of New Versions - -You may distribute the Covered Software under the terms of the version -of the License under which You originally received the Covered Software, -or under the terms of any subsequent version published by the license -steward. - -10.3. Modified Versions - -If you create software not governed by this License, and you want to -create a new license for such software, you may create and use a -modified version of this License if you rename the license and remove -any references to the name of the license steward (except to note that -such modified license differs from this License). - -10.4. Distributing Source Code Form that is Incompatible With Secondary -Licenses - -If You choose to distribute Source Code Form that is Incompatible With -Secondary Licenses under the terms of this version of the License, the -notice described in Exhibit B of this License must be attached. - -Exhibit A - Source Code Form License Notice -------------------------------------------- - - This Source Code Form is subject to the terms of the Mozilla Public - License, v. 2.0. If a copy of the MPL was not distributed with this - file, You can obtain one at http://mozilla.org/MPL/2.0/. - -If it is not possible or desirable to put the notice in a particular -file, then You may include the notice in a location (such as a LICENSE -file in a relevant directory) where a recipient would be likely to look -for such a notice. - -You may add additional accurate notices of copyright ownership. - -Exhibit B - "Incompatible With Secondary Licenses" Notice ---------------------------------------------------------- - - This Source Code Form is "Incompatible With Secondary Licenses", as - defined by the Mozilla Public License, v. 2.0. diff --git a/venv/lib/python3.9/site-packages/bidict-0.23.1.dist-info/METADATA b/venv/lib/python3.9/site-packages/bidict-0.23.1.dist-info/METADATA deleted file mode 100644 index 5356d23..0000000 --- a/venv/lib/python3.9/site-packages/bidict-0.23.1.dist-info/METADATA +++ /dev/null @@ -1,260 +0,0 @@ -Metadata-Version: 2.1 -Name: bidict -Version: 0.23.1 -Summary: The bidirectional mapping library for Python. -Author-email: Joshua Bronson -License: MPL 2.0 -Project-URL: Changelog, https://bidict.readthedocs.io/changelog.html -Project-URL: Documentation, https://bidict.readthedocs.io -Project-URL: Funding, https://bidict.readthedocs.io/#sponsoring -Project-URL: Repository, https://github.com/jab/bidict -Keywords: bidict,bimap,bidirectional,dict,dictionary,mapping,collections -Classifier: License :: OSI Approved :: Mozilla Public License 2.0 (MPL 2.0) -Classifier: Operating System :: OS Independent -Classifier: Programming Language :: Python :: Implementation :: CPython -Classifier: Programming Language :: Python :: Implementation :: PyPy -Classifier: Typing :: Typed -Requires-Python: >=3.8 -Description-Content-Type: text/x-rst -License-File: LICENSE - -.. role:: doc -.. (Forward declaration for the "doc" role that Sphinx defines for interop with renderers that - are often used to show this doc and that are unaware of Sphinx (GitHub.com, PyPI.org, etc.). - Use :doc: rather than :ref: here for better interop as well.) - - -bidict -====== - -*The bidirectional mapping library for Python.* - - -Status ------- - -.. image:: https://img.shields.io/pypi/v/bidict.svg - :target: https://pypi.org/project/bidict - :alt: Latest release - -.. image:: https://img.shields.io/readthedocs/bidict/main.svg - :target: https://bidict.readthedocs.io/en/main/ - :alt: Documentation - -.. image:: https://github.com/jab/bidict/actions/workflows/test.yml/badge.svg - :target: https://github.com/jab/bidict/actions/workflows/test.yml?query=branch%3Amain - :alt: GitHub Actions CI status - -.. image:: https://img.shields.io/pypi/l/bidict.svg - :target: https://raw.githubusercontent.com/jab/bidict/main/LICENSE - :alt: License - -.. image:: https://static.pepy.tech/badge/bidict - :target: https://pepy.tech/project/bidict - :alt: PyPI Downloads - -.. image:: https://img.shields.io/badge/GitHub-sponsor-ff69b4 - :target: https://github.com/sponsors/jab - :alt: Sponsor - - -Features --------- - -- Mature: Depended on by - Google, Venmo, CERN, Baidu, Tencent, - and teams across the world since 2009 - -- Familiar, Pythonic APIs - that are carefully designed for - safety, simplicity, flexibility, and ergonomics - -- Lightweight, with no runtime dependencies - outside Python's standard library - -- Implemented in - concise, well-factored, fully type-hinted Python code - that is optimized for running efficiently - as well as for long-term maintenance and stability - (as well as `joy <#learning-from-bidict>`__) - -- Extensively `documented `__ - -- 100% test coverage - running continuously across all supported Python versions - (including property-based tests and benchmarks) - - -Installation ------------- - -``pip install bidict`` - - -Quick Start ------------ - -.. code:: python - - >>> from bidict import bidict - >>> element_by_symbol = bidict({'H': 'hydrogen'}) - >>> element_by_symbol['H'] - 'hydrogen' - >>> element_by_symbol.inverse['hydrogen'] - 'H' - - -For more usage documentation, -head to the :doc:`intro` [#fn-intro]_ -and proceed from there. - - -Enterprise Support ------------------- - -Enterprise-level support for bidict can be obtained via the -`Tidelift subscription `__ -or by `contacting me directly `__. - -I have a US-based LLC set up for invoicing, -and I have 15+ years of professional experience -delivering software and support to companies successfully. - -You can also sponsor my work through several platforms, including GitHub Sponsors. -See the `Sponsoring <#sponsoring>`__ section below for details, -including rationale and examples of companies -supporting the open source projects they depend on. - - -Voluntary Community Support ---------------------------- - -Please search through already-asked questions and answers -in `GitHub Discussions `__ -and the `issue tracker `__ -in case your question has already been addressed. - -Otherwise, please feel free to -`start a new discussion `__ -or `create a new issue `__ on GitHub -for voluntary community support. - - -Notice of Usage ---------------- - -If you use bidict, -and especially if your usage or your organization is significant in some way, -please let me know in any of the following ways: - -- `star bidict on GitHub `__ -- post in `GitHub Discussions `__ -- `email me `__ - - -Changelog ---------- - -For bidict release notes, see the :doc:`changelog`. [#fn-changelog]_ - - -Release Notifications ---------------------- - -.. duplicated in CHANGELOG.rst: - (Would use `.. include::` but GitHub's renderer doesn't support it.) - -Watch `bidict releases on GitHub `__ -to be notified when new versions of bidict are published. -Click the "Watch" dropdown, choose "Custom", and then choose "Releases". - - -Learning from bidict --------------------- - -One of the best things about bidict -is that it touches a surprising number of -interesting Python corners, -especially given its small size and scope. - -Check out :doc:`learning-from-bidict` [#fn-learning]_ -if you're interested in learning more. - - -Contributing ------------- - -I have been bidict's sole maintainer -and `active contributor `__ -since I started the project ~15 years ago. - -Your help would be most welcome! -See the :doc:`contributors-guide` [#fn-contributing]_ -for more information. - - -Sponsoring ----------- - -.. duplicated in CONTRIBUTING.rst - (Would use `.. include::` but GitHub's renderer doesn't support it.) - -.. image:: https://img.shields.io/badge/GitHub-sponsor-ff69b4 - :target: https://github.com/sponsors/jab - :alt: Sponsor through GitHub - -Bidict is the product of thousands of hours of my unpaid work -over the 15+ years that I've been the sole maintainer. - -If bidict has helped you or your company accomplish your work, -please sponsor my work through one of the following, -and/or ask your company to do the same: - -- `GitHub `__ -- `PayPal `__ -- `Tidelift `__ -- `thanks.dev `__ -- `Gumroad `__ -- `a support engagement with my LLC <#enterprise-support>`__ - -If you're not sure which to use, GitHub is an easy option, -especially if you already have a GitHub account. -Just choose a monthly or one-time amount, and GitHub handles everything else. -Your bidict sponsorship on GitHub will automatically go -on the same regular bill as any other GitHub charges you pay for. -PayPal is another easy option for one-time contributions. - -See the following for rationale and examples of companies -supporting the open source projects they depend on -in this manner: - -- ``__ -- ``__ -- ``__ - -.. - ``__ -.. - ``__ -.. - ``__ - - -Finding Documentation ---------------------- - -If you're viewing this on ``__, -note that multiple versions of the documentation are available, -and you can choose a different version using the popup menu at the bottom-right. -Please make sure you're viewing the version of the documentation -that corresponds to the version of bidict you'd like to use. - -If you're viewing this on GitHub, PyPI, or some other place -that can't render and link this documentation properly -and are seeing broken links, -try these alternate links instead: - -.. [#fn-intro] ``__ | ``__ - -.. [#fn-changelog] ``__ | ``__ - -.. [#fn-learning] ``__ | ``__ - -.. [#fn-contributing] ``__ | ``__ diff --git a/venv/lib/python3.9/site-packages/bidict-0.23.1.dist-info/RECORD b/venv/lib/python3.9/site-packages/bidict-0.23.1.dist-info/RECORD deleted file mode 100644 index 840671d..0000000 --- a/venv/lib/python3.9/site-packages/bidict-0.23.1.dist-info/RECORD +++ /dev/null @@ -1,31 +0,0 @@ -bidict-0.23.1.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 -bidict-0.23.1.dist-info/LICENSE,sha256=8_U63OyqSNc6ZuI4-lupBstBh2eDtF0ooTRrMULuvZo,16784 -bidict-0.23.1.dist-info/METADATA,sha256=2ovIRm6Df8gdwAMekGqkeBSF5TWj2mv1jpmh4W4ks7o,8704 -bidict-0.23.1.dist-info/RECORD,, -bidict-0.23.1.dist-info/WHEEL,sha256=oiQVh_5PnQM0E3gPdiz09WCNmwiHDMaGer_elqB3coM,92 -bidict-0.23.1.dist-info/top_level.txt,sha256=WuQO02jp0ODioS7sJoaHg3JJ5_3h6Sxo9RITvNGPYmc,7 -bidict/__init__.py,sha256=pL87KsrDpBsl3AG09LQk1t1TSFt0hIJVYa2POMdErN8,4398 -bidict/__pycache__/__init__.cpython-39.pyc,, -bidict/__pycache__/_abc.cpython-39.pyc,, -bidict/__pycache__/_base.cpython-39.pyc,, -bidict/__pycache__/_bidict.cpython-39.pyc,, -bidict/__pycache__/_dup.cpython-39.pyc,, -bidict/__pycache__/_exc.cpython-39.pyc,, -bidict/__pycache__/_frozen.cpython-39.pyc,, -bidict/__pycache__/_iter.cpython-39.pyc,, -bidict/__pycache__/_orderedbase.cpython-39.pyc,, -bidict/__pycache__/_orderedbidict.cpython-39.pyc,, -bidict/__pycache__/_typing.cpython-39.pyc,, -bidict/__pycache__/metadata.cpython-39.pyc,, -bidict/_abc.py,sha256=SMCNdCsmqSWg0OGnMZtnnXY8edjXcyZup5tva4HBm_c,3172 -bidict/_base.py,sha256=YiauA0aj52fNB6cfZ4gBt6OV-CRQoZm7WVhuw1nT-Cg,24439 -bidict/_bidict.py,sha256=Sr-RoEzWOaxpnDRbDJ7ngaGRIsyGnqZgzvR-NyT4jl4,6923 -bidict/_dup.py,sha256=YAn5gWA6lwMBA5A6ebVF19UTZyambGS8WxmbK4TN1Ww,2079 -bidict/_exc.py,sha256=HnD_WgteI5PrXa3zBx9RUiGlgnZTO6CF4nIU9p3-njk,1066 -bidict/_frozen.py,sha256=p4TaRHKeyTs0KmlpwSnZiTlN_CR4J97kAgBpNdZHQMs,1771 -bidict/_iter.py,sha256=zVUx-hJ1M4YuJROoFWRjPKlcaFnyo1AAuRpOaKAFhOQ,1530 -bidict/_orderedbase.py,sha256=M7v5rHa7vrym9Z3DxQBFQDxjnrr39Z8p26V0c1PggoE,8942 -bidict/_orderedbidict.py,sha256=pPnmC19mIISrj8_yjnb-4r_ti1B74tD5eTd08DETNuI,7080 -bidict/_typing.py,sha256=AylMZpBhEFTQegfziPSxfKkKLk7oUsH6o3awDIg2z_k,1289 -bidict/metadata.py,sha256=BMIKu6fBY_OKeV_q48EpumE7MdmFw8rFcdaUz8kcIYk,573 -bidict/py.typed,sha256=RJao5SVFYIp8IfbxhL_SpZkBQYe3XXzPlobSRdh4B_c,16 diff --git a/venv/lib/python3.9/site-packages/bidict-0.23.1.dist-info/WHEEL b/venv/lib/python3.9/site-packages/bidict-0.23.1.dist-info/WHEEL deleted file mode 100644 index 98c0d20..0000000 --- a/venv/lib/python3.9/site-packages/bidict-0.23.1.dist-info/WHEEL +++ /dev/null @@ -1,5 +0,0 @@ -Wheel-Version: 1.0 -Generator: bdist_wheel (0.42.0) -Root-Is-Purelib: true -Tag: py3-none-any - diff --git a/venv/lib/python3.9/site-packages/bidict-0.23.1.dist-info/top_level.txt b/venv/lib/python3.9/site-packages/bidict-0.23.1.dist-info/top_level.txt deleted file mode 100644 index 6ff5b04..0000000 --- a/venv/lib/python3.9/site-packages/bidict-0.23.1.dist-info/top_level.txt +++ /dev/null @@ -1 +0,0 @@ -bidict diff --git a/venv/lib/python3.9/site-packages/bidict/__init__.py b/venv/lib/python3.9/site-packages/bidict/__init__.py deleted file mode 100644 index 07e5ba5..0000000 --- a/venv/lib/python3.9/site-packages/bidict/__init__.py +++ /dev/null @@ -1,103 +0,0 @@ -# Copyright 2009-2024 Joshua Bronson. All rights reserved. -# -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at http://mozilla.org/MPL/2.0/. - - -# ============================================================================ -# * Welcome to the bidict source code * -# ============================================================================ - -# Reading through the code? You'll find a "Code review nav" comment like the one -# below at the top and bottom of the key source files. Follow these cues to take -# a path through the code that's optimized for familiarizing yourself with it. -# -# If you're not reading this on https://github.com/jab/bidict already, go there -# to ensure you have the latest version of the code. While there, you can also -# star the project, watch it for updates, fork the code, and submit an issue or -# pull request with any proposed changes. More information can be found linked -# from README.rst, which is also shown on https://github.com/jab/bidict. - -# * Code review nav * -# ============================================================================ -# Current: __init__.py Next: _abc.py → -# ============================================================================ - - -"""The bidirectional mapping library for Python. - ----- - -bidict by example: - -.. code-block:: python - - >>> from bidict import bidict - >>> element_by_symbol = bidict({'H': 'hydrogen'}) - >>> element_by_symbol['H'] - 'hydrogen' - >>> element_by_symbol.inverse['hydrogen'] - 'H' - - -Please see https://github.com/jab/bidict for the most up-to-date code and -https://bidict.readthedocs.io for the most up-to-date documentation -if you are reading this elsewhere. - ----- - -.. :copyright: (c) 2009-2024 Joshua Bronson. -.. :license: MPLv2. See LICENSE for details. -""" - -# Use private aliases to not re-export these publicly (for Sphinx automodule with imported-members). -from __future__ import annotations as _annotations - -from contextlib import suppress as _suppress - -from ._abc import BidirectionalMapping as BidirectionalMapping -from ._abc import MutableBidirectionalMapping as MutableBidirectionalMapping -from ._base import BidictBase as BidictBase -from ._base import BidictKeysView as BidictKeysView -from ._base import GeneratedBidictInverse as GeneratedBidictInverse -from ._bidict import MutableBidict as MutableBidict -from ._bidict import bidict as bidict -from ._dup import DROP_NEW as DROP_NEW -from ._dup import DROP_OLD as DROP_OLD -from ._dup import ON_DUP_DEFAULT as ON_DUP_DEFAULT -from ._dup import ON_DUP_DROP_OLD as ON_DUP_DROP_OLD -from ._dup import ON_DUP_RAISE as ON_DUP_RAISE -from ._dup import RAISE as RAISE -from ._dup import OnDup as OnDup -from ._dup import OnDupAction as OnDupAction -from ._exc import BidictException as BidictException -from ._exc import DuplicationError as DuplicationError -from ._exc import KeyAndValueDuplicationError as KeyAndValueDuplicationError -from ._exc import KeyDuplicationError as KeyDuplicationError -from ._exc import ValueDuplicationError as ValueDuplicationError -from ._frozen import frozenbidict as frozenbidict -from ._iter import inverted as inverted -from ._orderedbase import OrderedBidictBase as OrderedBidictBase -from ._orderedbidict import OrderedBidict as OrderedBidict -from .metadata import __author__ as __author__ -from .metadata import __copyright__ as __copyright__ -from .metadata import __description__ as __description__ -from .metadata import __license__ as __license__ -from .metadata import __url__ as __url__ -from .metadata import __version__ as __version__ - - -# Set __module__ of re-exported classes to the 'bidict' top-level module, so that e.g. -# 'bidict.bidict' shows up as 'bidict.bidict` rather than 'bidict._bidict.bidict'. -for _obj in tuple(locals().values()): # pragma: no cover - if not getattr(_obj, '__module__', '').startswith('bidict.'): - continue - with _suppress(AttributeError): - _obj.__module__ = 'bidict' - - -# * Code review nav * -# ============================================================================ -# Current: __init__.py Next: _abc.py → -# ============================================================================ diff --git a/venv/lib/python3.9/site-packages/bidict/_abc.py b/venv/lib/python3.9/site-packages/bidict/_abc.py deleted file mode 100644 index d4a30aa..0000000 --- a/venv/lib/python3.9/site-packages/bidict/_abc.py +++ /dev/null @@ -1,79 +0,0 @@ -# Copyright 2009-2024 Joshua Bronson. All rights reserved. -# -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at http://mozilla.org/MPL/2.0/. - - -# * Code review nav * -# (see comments in __init__.py) -# ============================================================================ -# ← Prev: __init__.py Current: _abc.py Next: _base.py → -# ============================================================================ - - -"""Provide the :class:`BidirectionalMapping` abstract base class.""" - -from __future__ import annotations - -import typing as t -from abc import abstractmethod - -from ._typing import KT -from ._typing import VT - - -class BidirectionalMapping(t.Mapping[KT, VT]): - """Abstract base class for bidirectional mapping types. - - Extends :class:`collections.abc.Mapping` primarily by adding the - (abstract) :attr:`inverse` property, - which implementers of :class:`BidirectionalMapping` - should override to return a reference to the inverse - :class:`BidirectionalMapping` instance. - """ - - __slots__ = () - - @property - @abstractmethod - def inverse(self) -> BidirectionalMapping[VT, KT]: - """The inverse of this bidirectional mapping instance. - - *See also* :attr:`bidict.BidictBase.inverse`, :attr:`bidict.BidictBase.inv` - - :raises NotImplementedError: Meant to be overridden in subclasses. - """ - # The @abstractmethod decorator prevents subclasses from being instantiated unless they - # override this method. But an overriding implementation may merely return super().inverse, - # in which case this implementation is used. Raise NotImplementedError to indicate that - # subclasses must actually provide their own implementation. - raise NotImplementedError - - def __inverted__(self) -> t.Iterator[tuple[VT, KT]]: - """Get an iterator over the items in :attr:`inverse`. - - This is functionally equivalent to iterating over the items in the - forward mapping and inverting each one on the fly, but this provides a - more efficient implementation: Assuming the already-inverted items - are stored in :attr:`inverse`, just return an iterator over them directly. - - Providing this default implementation enables external functions, - particularly :func:`~bidict.inverted`, to use this optimized - implementation when available, instead of having to invert on the fly. - - *See also* :func:`bidict.inverted` - """ - return iter(self.inverse.items()) - - -class MutableBidirectionalMapping(BidirectionalMapping[KT, VT], t.MutableMapping[KT, VT]): - """Abstract base class for mutable bidirectional mapping types.""" - - __slots__ = () - - -# * Code review nav * -# ============================================================================ -# ← Prev: __init__.py Current: _abc.py Next: _base.py → -# ============================================================================ diff --git a/venv/lib/python3.9/site-packages/bidict/_base.py b/venv/lib/python3.9/site-packages/bidict/_base.py deleted file mode 100644 index 848a376..0000000 --- a/venv/lib/python3.9/site-packages/bidict/_base.py +++ /dev/null @@ -1,556 +0,0 @@ -# Copyright 2009-2024 Joshua Bronson. All rights reserved. -# -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at http://mozilla.org/MPL/2.0/. - - -# * Code review nav * -# (see comments in __init__.py) -# ============================================================================ -# ← Prev: _abc.py Current: _base.py Next: _frozen.py → -# ============================================================================ - - -"""Provide :class:`BidictBase`.""" - -from __future__ import annotations - -import typing as t -import weakref -from itertools import starmap -from operator import eq -from types import MappingProxyType - -from ._abc import BidirectionalMapping -from ._dup import DROP_NEW -from ._dup import DROP_OLD -from ._dup import ON_DUP_DEFAULT -from ._dup import RAISE -from ._dup import OnDup -from ._exc import DuplicationError -from ._exc import KeyAndValueDuplicationError -from ._exc import KeyDuplicationError -from ._exc import ValueDuplicationError -from ._iter import inverted -from ._iter import iteritems -from ._typing import KT -from ._typing import MISSING -from ._typing import OKT -from ._typing import OVT -from ._typing import VT -from ._typing import Maplike -from ._typing import MapOrItems - - -OldKV = t.Tuple[OKT[KT], OVT[VT]] -DedupResult = t.Optional[OldKV[KT, VT]] -Unwrites = t.List[t.Tuple[t.Any, ...]] -BT = t.TypeVar('BT', bound='BidictBase[t.Any, t.Any]') - - -class BidictKeysView(t.KeysView[KT], t.ValuesView[KT]): - """Since the keys of a bidict are the values of its inverse (and vice versa), - the :class:`~collections.abc.ValuesView` result of calling *bi.values()* - is also a :class:`~collections.abc.KeysView` of *bi.inverse*. - """ - - -class BidictBase(BidirectionalMapping[KT, VT]): - """Base class implementing :class:`BidirectionalMapping`.""" - - #: The default :class:`~bidict.OnDup` - #: that governs behavior when a provided item - #: duplicates the key or value of other item(s). - #: - #: *See also* - #: :ref:`basic-usage:Values Must Be Unique` (https://bidict.rtfd.io/basic-usage.html#values-must-be-unique), - #: :doc:`extending` (https://bidict.rtfd.io/extending.html) - on_dup = ON_DUP_DEFAULT - - _fwdm: t.MutableMapping[KT, VT] #: the backing forward mapping (*key* → *val*) - _invm: t.MutableMapping[VT, KT] #: the backing inverse mapping (*val* → *key*) - - # Use Any rather than KT/VT in the following to avoid "ClassVar cannot contain type variables" errors: - _fwdm_cls: t.ClassVar[type[t.MutableMapping[t.Any, t.Any]]] = dict #: class of the backing forward mapping - _invm_cls: t.ClassVar[type[t.MutableMapping[t.Any, t.Any]]] = dict #: class of the backing inverse mapping - - #: The class of the inverse bidict instance. - _inv_cls: t.ClassVar[type[BidictBase[t.Any, t.Any]]] - - def __init_subclass__(cls) -> None: - super().__init_subclass__() - cls._init_class() - - @classmethod - def _init_class(cls) -> None: - cls._ensure_inv_cls() - cls._set_reversed() - - __reversed__: t.ClassVar[t.Any] - - @classmethod - def _set_reversed(cls) -> None: - """Set __reversed__ for subclasses that do not set it explicitly - according to whether backing mappings are reversible. - """ - if cls is not BidictBase: - resolved = cls.__reversed__ - overridden = resolved is not BidictBase.__reversed__ - if overridden: # E.g. OrderedBidictBase, OrderedBidict - return - backing_reversible = all(issubclass(i, t.Reversible) for i in (cls._fwdm_cls, cls._invm_cls)) - cls.__reversed__ = _fwdm_reversed if backing_reversible else None - - @classmethod - def _ensure_inv_cls(cls) -> None: - """Ensure :attr:`_inv_cls` is set, computing it dynamically if necessary. - - All subclasses provided in :mod:`bidict` are their own inverse classes, - i.e., their backing forward and inverse mappings are both the same type, - but users may define subclasses where this is not the case. - This method ensures that the inverse class is computed correctly regardless. - - See: :ref:`extending:Dynamic Inverse Class Generation` - (https://bidict.rtfd.io/extending.html#dynamic-inverse-class-generation) - """ - # This _ensure_inv_cls() method is (indirectly) corecursive with _make_inv_cls() below - # in the case that we need to dynamically generate the inverse class: - # 1. _ensure_inv_cls() calls cls._make_inv_cls() - # 2. cls._make_inv_cls() calls type(..., (cls, ...), ...) to dynamically generate inv_cls - # 3. Our __init_subclass__ hook (see above) is automatically called on inv_cls - # 4. inv_cls.__init_subclass__() calls inv_cls._ensure_inv_cls() - # 5. inv_cls._ensure_inv_cls() resolves to this implementation - # (inv_cls deliberately does not override this), so we're back where we started. - # But since the _make_inv_cls() call will have set inv_cls.__dict__._inv_cls, - # just check if it's already set before calling _make_inv_cls() to prevent infinite recursion. - if getattr(cls, '__dict__', {}).get('_inv_cls'): # Don't assume cls.__dict__ (e.g. mypyc native class) - return - cls._inv_cls = cls._make_inv_cls() - - @classmethod - def _make_inv_cls(cls: type[BT]) -> type[BT]: - diff = cls._inv_cls_dict_diff() - cls_is_own_inv = all(getattr(cls, k, MISSING) == v for (k, v) in diff.items()) - if cls_is_own_inv: - return cls - # Suppress auto-calculation of _inv_cls's _inv_cls since we know it already. - # Works with the guard in BidictBase._ensure_inv_cls() to prevent infinite recursion. - diff['_inv_cls'] = cls - inv_cls = type(f'{cls.__name__}Inv', (cls, GeneratedBidictInverse), diff) - inv_cls.__module__ = cls.__module__ - return t.cast(t.Type[BT], inv_cls) - - @classmethod - def _inv_cls_dict_diff(cls) -> dict[str, t.Any]: - return { - '_fwdm_cls': cls._invm_cls, - '_invm_cls': cls._fwdm_cls, - } - - def __init__(self, arg: MapOrItems[KT, VT] = (), /, **kw: VT) -> None: - """Make a new bidirectional mapping. - The signature behaves like that of :class:`dict`. - ktems passed via positional arg are processed first, - followed by any items passed via keyword argument. - Any duplication encountered along the way - is handled as per :attr:`on_dup`. - """ - self._fwdm = self._fwdm_cls() - self._invm = self._invm_cls() - self._update(arg, kw, rollback=False) - - # If Python ever adds support for higher-kinded types, `inverse` could use them, e.g. - # def inverse(self: BT[KT, VT]) -> BT[VT, KT]: - # Ref: https://github.com/python/typing/issues/548#issuecomment-621571821 - @property - def inverse(self) -> BidictBase[VT, KT]: - """The inverse of this bidirectional mapping instance.""" - # When `bi.inverse` is called for the first time, this method - # computes the inverse instance, stores it for subsequent use, and then - # returns it. It also stores a reference on `bi.inverse` back to `bi`, - # but uses a weakref to avoid creating a reference cycle. Strong references - # to inverse instances are stored in ._inv, and weak references are stored - # in ._invweak. - - # First check if a strong reference is already stored. - inv: BidictBase[VT, KT] | None = getattr(self, '_inv', None) - if inv is not None: - return inv - # Next check if a weak reference is already stored. - invweak = getattr(self, '_invweak', None) - if invweak is not None: - inv = invweak() # Try to resolve a strong reference and return it. - if inv is not None: - return inv - # No luck. Compute the inverse reference and store it for subsequent use. - inv = self._make_inverse() - self._inv: BidictBase[VT, KT] | None = inv - self._invweak: weakref.ReferenceType[BidictBase[VT, KT]] | None = None - # Also store a weak reference back to `instance` on its inverse instance, so that - # the second `.inverse` access in `bi.inverse.inverse` hits the cached weakref. - inv._inv = None - inv._invweak = weakref.ref(self) - # In e.g. `bidict().inverse.inverse`, this design ensures that a strong reference - # back to the original instance is retained before its refcount drops to zero, - # avoiding an unintended potential deallocation. - return inv - - def _make_inverse(self) -> BidictBase[VT, KT]: - inv: BidictBase[VT, KT] = self._inv_cls() - inv._fwdm = self._invm - inv._invm = self._fwdm - return inv - - @property - def inv(self) -> BidictBase[VT, KT]: - """Alias for :attr:`inverse`.""" - return self.inverse - - def __repr__(self) -> str: - """See :func:`repr`.""" - clsname = self.__class__.__name__ - items = dict(self.items()) if self else '' - return f'{clsname}({items})' - - def values(self) -> BidictKeysView[VT]: - """A set-like object providing a view on the contained values. - - Since the values of a bidict are equivalent to the keys of its inverse, - this method returns a set-like object for this bidict's values - rather than just a collections.abc.ValuesView. - This object supports set operations like union and difference, - and constant- rather than linear-time containment checks, - and is no more expensive to provide than the less capable - collections.abc.ValuesView would be. - - See :meth:`keys` for more information. - """ - return t.cast(BidictKeysView[VT], self.inverse.keys()) - - def keys(self) -> t.KeysView[KT]: - """A set-like object providing a view on the contained keys. - - When *b._fwdm* is a :class:`dict`, *b.keys()* returns a - *dict_keys* object that behaves exactly the same as - *collections.abc.KeysView(b)*, except for - - - offering better performance - - - being reversible on Python 3.8+ - - - having a .mapping attribute in Python 3.10+ - that exposes a mappingproxy to *b._fwdm*. - """ - fwdm, fwdm_cls = self._fwdm, self._fwdm_cls - return fwdm.keys() if fwdm_cls is dict else BidictKeysView(self) - - def items(self) -> t.ItemsView[KT, VT]: - """A set-like object providing a view on the contained items. - - When *b._fwdm* is a :class:`dict`, *b.items()* returns a - *dict_items* object that behaves exactly the same as - *collections.abc.ItemsView(b)*, except for: - - - offering better performance - - - being reversible on Python 3.8+ - - - having a .mapping attribute in Python 3.10+ - that exposes a mappingproxy to *b._fwdm*. - """ - return self._fwdm.items() if self._fwdm_cls is dict else super().items() - - # The inherited collections.abc.Mapping.__contains__() method is implemented by doing a `try` - # `except KeyError` around `self[key]`. The following implementation is much faster, - # especially in the missing case. - def __contains__(self, key: t.Any) -> bool: - """True if the mapping contains the specified key, else False.""" - return key in self._fwdm - - # The inherited collections.abc.Mapping.__eq__() method is implemented in terms of an inefficient - # `dict(self.items()) == dict(other.items())` comparison, so override it with a - # more efficient implementation. - def __eq__(self, other: object) -> bool: - """*x.__eq__(other) ⟺ x == other* - - Equivalent to *dict(x.items()) == dict(other.items())* - but more efficient. - - Note that :meth:`bidict's __eq__() ` implementation - is inherited by subclasses, - in particular by the ordered bidict subclasses, - so even with ordered bidicts, - :ref:`== comparison is order-insensitive ` - (https://bidict.rtfd.io/other-bidict-types.html#eq-is-order-insensitive). - - *See also* :meth:`equals_order_sensitive` - """ - if isinstance(other, t.Mapping): - return self._fwdm.items() == other.items() - # Ref: https://docs.python.org/3/library/constants.html#NotImplemented - return NotImplemented - - def equals_order_sensitive(self, other: object) -> bool: - """Order-sensitive equality check. - - *See also* :ref:`eq-order-insensitive` - (https://bidict.rtfd.io/other-bidict-types.html#eq-is-order-insensitive) - """ - if not isinstance(other, t.Mapping) or len(self) != len(other): - return False - return all(starmap(eq, zip(self.items(), other.items()))) - - def _dedup(self, key: KT, val: VT, on_dup: OnDup) -> DedupResult[KT, VT]: - """Check *key* and *val* for any duplication in self. - - Handle any duplication as per the passed in *on_dup*. - - If (key, val) is already present, return None - since writing (key, val) would be a no-op. - - If duplication is found and the corresponding :class:`~bidict.OnDupAction` is - :attr:`~bidict.DROP_NEW`, return None. - - If duplication is found and the corresponding :class:`~bidict.OnDupAction` is - :attr:`~bidict.RAISE`, raise the appropriate exception. - - If duplication is found and the corresponding :class:`~bidict.OnDupAction` is - :attr:`~bidict.DROP_OLD`, or if no duplication is found, - return *(oldkey, oldval)*. - """ - fwdm, invm = self._fwdm, self._invm - oldval: OVT[VT] = fwdm.get(key, MISSING) - oldkey: OKT[KT] = invm.get(val, MISSING) - isdupkey, isdupval = oldval is not MISSING, oldkey is not MISSING - if isdupkey and isdupval: - if key == oldkey: - assert val == oldval - # (key, val) duplicates an existing item -> no-op. - return None - # key and val each duplicate a different existing item. - if on_dup.val is RAISE: - raise KeyAndValueDuplicationError(key, val) - if on_dup.val is DROP_NEW: - return None - assert on_dup.val is DROP_OLD - # Fall through to the return statement on the last line. - elif isdupkey: - if on_dup.key is RAISE: - raise KeyDuplicationError(key) - if on_dup.key is DROP_NEW: - return None - assert on_dup.key is DROP_OLD - # Fall through to the return statement on the last line. - elif isdupval: - if on_dup.val is RAISE: - raise ValueDuplicationError(val) - if on_dup.val is DROP_NEW: - return None - assert on_dup.val is DROP_OLD - # Fall through to the return statement on the last line. - # else neither isdupkey nor isdupval. - return oldkey, oldval - - def _write(self, newkey: KT, newval: VT, oldkey: OKT[KT], oldval: OVT[VT], unwrites: Unwrites | None) -> None: - """Insert (newkey, newval), extending *unwrites* with associated inverse operations if provided. - - *oldkey* and *oldval* are as returned by :meth:`_dedup`. - - If *unwrites* is not None, it is extended with the inverse operations necessary to undo the write. - This design allows :meth:`_update` to roll back a partially applied update that fails part-way through - when necessary. - - This design also allows subclasses that require additional operations to easily extend this implementation. - For example, :class:`bidict.OrderedBidictBase` calls this inherited implementation, and then extends *unwrites* - with additional operations needed to keep its internal linked list nodes consistent with its items' order - as changes are made. - """ - fwdm, invm = self._fwdm, self._invm - fwdm_set, invm_set = fwdm.__setitem__, invm.__setitem__ - fwdm_del, invm_del = fwdm.__delitem__, invm.__delitem__ - # Always perform the following writes regardless of duplication. - fwdm_set(newkey, newval) - invm_set(newval, newkey) - if oldval is MISSING and oldkey is MISSING: # no key or value duplication - # {0: 1, 2: 3} | {4: 5} => {0: 1, 2: 3, 4: 5} - if unwrites is not None: - unwrites.extend(( - (fwdm_del, newkey), - (invm_del, newval), - )) - elif oldval is not MISSING and oldkey is not MISSING: # key and value duplication across two different items - # {0: 1, 2: 3} | {0: 3} => {0: 3} - fwdm_del(oldkey) - invm_del(oldval) - if unwrites is not None: - unwrites.extend(( - (fwdm_set, newkey, oldval), - (invm_set, oldval, newkey), - (fwdm_set, oldkey, newval), - (invm_set, newval, oldkey), - )) - elif oldval is not MISSING: # just key duplication - # {0: 1, 2: 3} | {2: 4} => {0: 1, 2: 4} - invm_del(oldval) - if unwrites is not None: - unwrites.extend(( - (fwdm_set, newkey, oldval), - (invm_set, oldval, newkey), - (invm_del, newval), - )) - else: - assert oldkey is not MISSING # just value duplication - # {0: 1, 2: 3} | {4: 3} => {0: 1, 4: 3} - fwdm_del(oldkey) - if unwrites is not None: - unwrites.extend(( - (fwdm_set, oldkey, newval), - (invm_set, newval, oldkey), - (fwdm_del, newkey), - )) - - def _update( - self, - arg: MapOrItems[KT, VT], - kw: t.Mapping[str, VT] = MappingProxyType({}), - *, - rollback: bool | None = None, - on_dup: OnDup | None = None, - ) -> None: - """Update with the items from *arg* and *kw*, maybe failing and rolling back as per *on_dup* and *rollback*.""" - # Note: We must process input in a single pass, since arg may be a generator. - if not isinstance(arg, (t.Iterable, Maplike)): - raise TypeError(f"'{arg.__class__.__name__}' object is not iterable") - if not arg and not kw: - return - if on_dup is None: - on_dup = self.on_dup - if rollback is None: - rollback = RAISE in on_dup - - # Fast path when we're empty and updating only from another bidict (i.e. no dup vals in new items). - if not self and not kw and isinstance(arg, BidictBase): - self._init_from(arg) - return - - # Fast path when we're adding more items than we contain already and rollback is enabled: - # Update a copy of self with rollback disabled. Fail if that fails, otherwise become the copy. - if rollback and isinstance(arg, t.Sized) and len(arg) + len(kw) > len(self): - tmp = self.copy() - tmp._update(arg, kw, rollback=False, on_dup=on_dup) - self._init_from(tmp) - return - - # In all other cases, benchmarking has indicated that the update is best implemented as follows: - # For each new item, perform a dup check (raising if necessary), and apply the associated writes we need to - # perform on our backing _fwdm and _invm mappings. If rollback is enabled, also compute the associated unwrites - # as we go. If the update results in a DuplicationError and rollback is enabled, apply the accumulated unwrites - # before raising, to ensure that we fail clean. - write = self._write - unwrites: Unwrites | None = [] if rollback else None - for key, val in iteritems(arg, **kw): - try: - dedup_result = self._dedup(key, val, on_dup) - except DuplicationError: - if unwrites is not None: - for fn, *args in reversed(unwrites): - fn(*args) - raise - if dedup_result is not None: - write(key, val, *dedup_result, unwrites=unwrites) - - def __copy__(self: BT) -> BT: - """Used for the copy protocol. See the :mod:`copy` module.""" - return self.copy() - - def copy(self: BT) -> BT: - """Make a (shallow) copy of this bidict.""" - # Could just `return self.__class__(self)` here, but the below is faster. The former - # would copy this bidict's items into a new instance one at a time (checking for duplication - # for each item), whereas the below copies from the backing mappings all at once, and foregoes - # item-by-item duplication checking since the backing mappings have been checked already. - return self._from_other(self.__class__, self) - - @staticmethod - def _from_other(bt: type[BT], other: MapOrItems[KT, VT], inv: bool = False) -> BT: - """Fast, private constructor based on :meth:`_init_from`. - - If *inv* is true, return the inverse of the instance instead of the instance itself. - (Useful for pickling with dynamically-generated inverse classes -- see :meth:`__reduce__`.) - """ - inst = bt() - inst._init_from(other) - return t.cast(BT, inst.inverse) if inv else inst - - def _init_from(self, other: MapOrItems[KT, VT]) -> None: - """Fast init from *other*, bypassing item-by-item duplication checking.""" - self._fwdm.clear() - self._invm.clear() - self._fwdm.update(other) - # If other is a bidict, use its existing backing inverse mapping, otherwise - # other could be a generator that's now exhausted, so invert self._fwdm on the fly. - inv = other.inverse if isinstance(other, BidictBase) else inverted(self._fwdm) - self._invm.update(inv) - - # other's type is Mapping rather than Maplike since bidict() | SupportsKeysAndGetItem({}) - # raises a TypeError, just like dict() | SupportsKeysAndGetItem({}) does. - def __or__(self: BT, other: t.Mapping[KT, VT]) -> BT: - """Return self|other.""" - if not isinstance(other, t.Mapping): - return NotImplemented - new = self.copy() - new._update(other, rollback=False) - return new - - def __ror__(self: BT, other: t.Mapping[KT, VT]) -> BT: - """Return other|self.""" - if not isinstance(other, t.Mapping): - return NotImplemented - new = self.__class__(other) - new._update(self, rollback=False) - return new - - def __len__(self) -> int: - """The number of contained items.""" - return len(self._fwdm) - - def __iter__(self) -> t.Iterator[KT]: - """Iterator over the contained keys.""" - return iter(self._fwdm) - - def __getitem__(self, key: KT) -> VT: - """*x.__getitem__(key) ⟺ x[key]*""" - return self._fwdm[key] - - def __reduce__(self) -> tuple[t.Any, ...]: - """Return state information for pickling.""" - cls = self.__class__ - inst: t.Mapping[t.Any, t.Any] = self - # If this bidict's class is dynamically generated, pickle the inverse instead, whose (presumably not - # dynamically generated) class the caller is more likely to have a reference to somewhere in sys.modules - # that pickle can discover. - if should_invert := isinstance(self, GeneratedBidictInverse): - cls = self._inv_cls - inst = self.inverse - return self._from_other, (cls, dict(inst), should_invert) - - -# See BidictBase._set_reversed() above. -def _fwdm_reversed(self: BidictBase[KT, t.Any]) -> t.Iterator[KT]: - """Iterator over the contained keys in reverse order.""" - assert isinstance(self._fwdm, t.Reversible) - return reversed(self._fwdm) - - -BidictBase._init_class() - - -class GeneratedBidictInverse: - """Base class for dynamically-generated inverse bidict classes.""" - - -# * Code review nav * -# ============================================================================ -# ← Prev: _abc.py Current: _base.py Next: _frozen.py → -# ============================================================================ diff --git a/venv/lib/python3.9/site-packages/bidict/_bidict.py b/venv/lib/python3.9/site-packages/bidict/_bidict.py deleted file mode 100644 index 94dd3db..0000000 --- a/venv/lib/python3.9/site-packages/bidict/_bidict.py +++ /dev/null @@ -1,194 +0,0 @@ -# Copyright 2009-2024 Joshua Bronson. All rights reserved. -# -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at http://mozilla.org/MPL/2.0/. - - -# * Code review nav * -# (see comments in __init__.py) -# ============================================================================ -# ← Prev: _frozen.py Current: _bidict.py Next: _orderedbase.py → -# ============================================================================ - - -"""Provide :class:`MutableBidict` and :class:`bidict`.""" - -from __future__ import annotations - -import typing as t - -from ._abc import MutableBidirectionalMapping -from ._base import BidictBase -from ._dup import ON_DUP_DROP_OLD -from ._dup import ON_DUP_RAISE -from ._dup import OnDup -from ._typing import DT -from ._typing import KT -from ._typing import MISSING -from ._typing import ODT -from ._typing import VT -from ._typing import MapOrItems - - -class MutableBidict(BidictBase[KT, VT], MutableBidirectionalMapping[KT, VT]): - """Base class for mutable bidirectional mappings.""" - - if t.TYPE_CHECKING: - - @property - def inverse(self) -> MutableBidict[VT, KT]: ... - - @property - def inv(self) -> MutableBidict[VT, KT]: ... - - def _pop(self, key: KT) -> VT: - val = self._fwdm.pop(key) - del self._invm[val] - return val - - def __delitem__(self, key: KT) -> None: - """*x.__delitem__(y) ⟺ del x[y]*""" - self._pop(key) - - def __setitem__(self, key: KT, val: VT) -> None: - """Set the value for *key* to *val*. - - If *key* is already associated with *val*, this is a no-op. - - If *key* is already associated with a different value, - the old value will be replaced with *val*, - as with dict's :meth:`__setitem__`. - - If *val* is already associated with a different key, - an exception is raised - to protect against accidental removal of the key - that's currently associated with *val*. - - Use :meth:`put` instead if you want to specify different behavior in - the case that the provided key or value duplicates an existing one. - Or use :meth:`forceput` to unconditionally associate *key* with *val*, - replacing any existing items as necessary to preserve uniqueness. - - :raises bidict.ValueDuplicationError: if *val* duplicates that of an - existing item. - - :raises bidict.KeyAndValueDuplicationError: if *key* duplicates the key of an - existing item and *val* duplicates the value of a different - existing item. - """ - self.put(key, val, on_dup=self.on_dup) - - def put(self, key: KT, val: VT, on_dup: OnDup = ON_DUP_RAISE) -> None: - """Associate *key* with *val*, honoring the :class:`OnDup` given in *on_dup*. - - For example, if *on_dup* is :attr:`~bidict.ON_DUP_RAISE`, - then *key* will be associated with *val* if and only if - *key* is not already associated with an existing value and - *val* is not already associated with an existing key, - otherwise an exception will be raised. - - If *key* is already associated with *val*, this is a no-op. - - :raises bidict.KeyDuplicationError: if attempting to insert an item - whose key only duplicates an existing item's, and *on_dup.key* is - :attr:`~bidict.RAISE`. - - :raises bidict.ValueDuplicationError: if attempting to insert an item - whose value only duplicates an existing item's, and *on_dup.val* is - :attr:`~bidict.RAISE`. - - :raises bidict.KeyAndValueDuplicationError: if attempting to insert an - item whose key duplicates one existing item's, and whose value - duplicates another existing item's, and *on_dup.val* is - :attr:`~bidict.RAISE`. - """ - self._update(((key, val),), on_dup=on_dup) - - def forceput(self, key: KT, val: VT) -> None: - """Associate *key* with *val* unconditionally. - - Replace any existing mappings containing key *key* or value *val* - as necessary to preserve uniqueness. - """ - self.put(key, val, on_dup=ON_DUP_DROP_OLD) - - def clear(self) -> None: - """Remove all items.""" - self._fwdm.clear() - self._invm.clear() - - @t.overload - def pop(self, key: KT, /) -> VT: ... - @t.overload - def pop(self, key: KT, default: DT = ..., /) -> VT | DT: ... - - def pop(self, key: KT, default: ODT[DT] = MISSING, /) -> VT | DT: - """*x.pop(k[, d]) → v* - - Remove specified key and return the corresponding value. - - :raises KeyError: if *key* is not found and no *default* is provided. - """ - try: - return self._pop(key) - except KeyError: - if default is MISSING: - raise - return default - - def popitem(self) -> tuple[KT, VT]: - """*x.popitem() → (k, v)* - - Remove and return some item as a (key, value) pair. - - :raises KeyError: if *x* is empty. - """ - key, val = self._fwdm.popitem() - del self._invm[val] - return key, val - - def update(self, arg: MapOrItems[KT, VT] = (), /, **kw: VT) -> None: - """Like calling :meth:`putall` with *self.on_dup* passed for *on_dup*.""" - self._update(arg, kw=kw) - - def forceupdate(self, arg: MapOrItems[KT, VT] = (), /, **kw: VT) -> None: - """Like a bulk :meth:`forceput`.""" - self._update(arg, kw=kw, on_dup=ON_DUP_DROP_OLD) - - def putall(self, items: MapOrItems[KT, VT], on_dup: OnDup = ON_DUP_RAISE) -> None: - """Like a bulk :meth:`put`. - - If one of the given items causes an exception to be raised, - none of the items is inserted. - """ - self._update(items, on_dup=on_dup) - - # other's type is Mapping rather than Maplike since bidict() |= SupportsKeysAndGetItem({}) - # raises a TypeError, just like dict() |= SupportsKeysAndGetItem({}) does. - def __ior__(self, other: t.Mapping[KT, VT]) -> MutableBidict[KT, VT]: - """Return self|=other.""" - self.update(other) - return self - - -class bidict(MutableBidict[KT, VT]): - """The main bidirectional mapping type. - - See :ref:`intro:Introduction` and :ref:`basic-usage:Basic Usage` - to get started (also available at https://bidict.rtfd.io). - """ - - if t.TYPE_CHECKING: - - @property - def inverse(self) -> bidict[VT, KT]: ... - - @property - def inv(self) -> bidict[VT, KT]: ... - - -# * Code review nav * -# ============================================================================ -# ← Prev: _frozen.py Current: _bidict.py Next: _orderedbase.py → -# ============================================================================ diff --git a/venv/lib/python3.9/site-packages/bidict/_dup.py b/venv/lib/python3.9/site-packages/bidict/_dup.py deleted file mode 100644 index fd25b61..0000000 --- a/venv/lib/python3.9/site-packages/bidict/_dup.py +++ /dev/null @@ -1,61 +0,0 @@ -# Copyright 2009-2024 Joshua Bronson. All rights reserved. -# -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at http://mozilla.org/MPL/2.0/. - - -"""Provide :class:`OnDup` and related functionality.""" - -from __future__ import annotations - -import typing as t -from enum import Enum - - -class OnDupAction(Enum): - """An action to take to prevent duplication from occurring.""" - - #: Raise a :class:`~bidict.DuplicationError`. - RAISE = 'RAISE' - #: Overwrite existing items with new items. - DROP_OLD = 'DROP_OLD' - #: Keep existing items and drop new items. - DROP_NEW = 'DROP_NEW' - - def __repr__(self) -> str: - return f'{self.__class__.__name__}.{self.name}' - - -RAISE: t.Final[OnDupAction] = OnDupAction.RAISE -DROP_OLD: t.Final[OnDupAction] = OnDupAction.DROP_OLD -DROP_NEW: t.Final[OnDupAction] = OnDupAction.DROP_NEW - - -class OnDup(t.NamedTuple): - r"""A combination of :class:`~bidict.OnDupAction`\s specifying how to handle various types of duplication. - - The :attr:`~OnDup.key` field specifies what action to take when a duplicate key is encountered. - - The :attr:`~OnDup.val` field specifies what action to take when a duplicate value is encountered. - - In the case of both key and value duplication across two different items, - only :attr:`~OnDup.val` is used. - - *See also* :ref:`basic-usage:Values Must Be Unique` - (https://bidict.rtfd.io/basic-usage.html#values-must-be-unique) - """ - - key: OnDupAction = DROP_OLD - val: OnDupAction = RAISE - - -#: Default :class:`OnDup` used for the -#: :meth:`~bidict.bidict.__init__`, -#: :meth:`~bidict.bidict.__setitem__`, and -#: :meth:`~bidict.bidict.update` methods. -ON_DUP_DEFAULT: t.Final[OnDup] = OnDup(key=DROP_OLD, val=RAISE) -#: An :class:`OnDup` whose members are all :obj:`RAISE`. -ON_DUP_RAISE: t.Final[OnDup] = OnDup(key=RAISE, val=RAISE) -#: An :class:`OnDup` whose members are all :obj:`DROP_OLD`. -ON_DUP_DROP_OLD: t.Final[OnDup] = OnDup(key=DROP_OLD, val=DROP_OLD) diff --git a/venv/lib/python3.9/site-packages/bidict/_exc.py b/venv/lib/python3.9/site-packages/bidict/_exc.py deleted file mode 100644 index e2a96f3..0000000 --- a/venv/lib/python3.9/site-packages/bidict/_exc.py +++ /dev/null @@ -1,36 +0,0 @@ -# Copyright 2009-2024 Joshua Bronson. All rights reserved. -# -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at http://mozilla.org/MPL/2.0/. - - -"""Provide all bidict exceptions.""" - -from __future__ import annotations - - -class BidictException(Exception): - """Base class for bidict exceptions.""" - - -class DuplicationError(BidictException): - """Base class for exceptions raised when uniqueness is violated - as per the :attr:`~bidict.RAISE` :class:`~bidict.OnDupAction`. - """ - - -class KeyDuplicationError(DuplicationError): - """Raised when a given key is not unique.""" - - -class ValueDuplicationError(DuplicationError): - """Raised when a given value is not unique.""" - - -class KeyAndValueDuplicationError(KeyDuplicationError, ValueDuplicationError): - """Raised when a given item's key and value are not unique. - - That is, its key duplicates that of another item, - and its value duplicates that of a different other item. - """ diff --git a/venv/lib/python3.9/site-packages/bidict/_frozen.py b/venv/lib/python3.9/site-packages/bidict/_frozen.py deleted file mode 100644 index e2f789d..0000000 --- a/venv/lib/python3.9/site-packages/bidict/_frozen.py +++ /dev/null @@ -1,50 +0,0 @@ -# Copyright 2009-2024 Joshua Bronson. All rights reserved. -# -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at http://mozilla.org/MPL/2.0/. - - -# * Code review nav * -# (see comments in __init__.py) -# ============================================================================ -# ← Prev: _base.py Current: _frozen.py Next: _bidict.py → -# ============================================================================ - -"""Provide :class:`frozenbidict`, an immutable, hashable bidirectional mapping type.""" - -from __future__ import annotations - -import typing as t - -from ._base import BidictBase -from ._typing import KT -from ._typing import VT - - -class frozenbidict(BidictBase[KT, VT]): - """Immutable, hashable bidict type.""" - - _hash: int - - if t.TYPE_CHECKING: - - @property - def inverse(self) -> frozenbidict[VT, KT]: ... - - @property - def inv(self) -> frozenbidict[VT, KT]: ... - - def __hash__(self) -> int: - """The hash of this bidict as determined by its items.""" - if getattr(self, '_hash', None) is None: - # The following is like hash(frozenset(self.items())) - # but more memory efficient. See also: https://bugs.python.org/issue46684 - self._hash = t.ItemsView(self)._hash() - return self._hash - - -# * Code review nav * -# ============================================================================ -# ← Prev: _base.py Current: _frozen.py Next: _bidict.py → -# ============================================================================ diff --git a/venv/lib/python3.9/site-packages/bidict/_iter.py b/venv/lib/python3.9/site-packages/bidict/_iter.py deleted file mode 100644 index 53ad25d..0000000 --- a/venv/lib/python3.9/site-packages/bidict/_iter.py +++ /dev/null @@ -1,51 +0,0 @@ -# Copyright 2009-2024 Joshua Bronson. All rights reserved. -# -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at http://mozilla.org/MPL/2.0/. - - -"""Functions for iterating over items in a mapping.""" - -from __future__ import annotations - -import typing as t -from operator import itemgetter - -from ._typing import KT -from ._typing import VT -from ._typing import ItemsIter -from ._typing import Maplike -from ._typing import MapOrItems - - -def iteritems(arg: MapOrItems[KT, VT] = (), /, **kw: VT) -> ItemsIter[KT, VT]: - """Yield the items from *arg* and *kw* in the order given.""" - if isinstance(arg, t.Mapping): - yield from arg.items() - elif isinstance(arg, Maplike): - yield from ((k, arg[k]) for k in arg.keys()) - else: - yield from arg - yield from t.cast(ItemsIter[KT, VT], kw.items()) - - -swap: t.Final = itemgetter(1, 0) - - -def inverted(arg: MapOrItems[KT, VT]) -> ItemsIter[VT, KT]: - """Yield the inverse items of the provided object. - - If *arg* has a :func:`callable` ``__inverted__`` attribute, - return the result of calling it. - - Otherwise, return an iterator over the items in `arg`, - inverting each item on the fly. - - *See also* :attr:`bidict.BidirectionalMapping.__inverted__` - """ - invattr = getattr(arg, '__inverted__', None) - if callable(invattr): - inv: ItemsIter[VT, KT] = invattr() - return inv - return map(swap, iteritems(arg)) diff --git a/venv/lib/python3.9/site-packages/bidict/_orderedbase.py b/venv/lib/python3.9/site-packages/bidict/_orderedbase.py deleted file mode 100644 index 92f2633..0000000 --- a/venv/lib/python3.9/site-packages/bidict/_orderedbase.py +++ /dev/null @@ -1,238 +0,0 @@ -# Copyright 2009-2024 Joshua Bronson. All rights reserved. -# -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at http://mozilla.org/MPL/2.0/. - - -# * Code review nav * -# (see comments in __init__.py) -# ============================================================================ -# ← Prev: _bidict.py Current: _orderedbase.py Next: _orderedbidict.py → -# ============================================================================ - - -"""Provide :class:`OrderedBidictBase`.""" - -from __future__ import annotations - -import typing as t -from weakref import ref as weakref - -from ._base import BidictBase -from ._base import Unwrites -from ._bidict import bidict -from ._iter import iteritems -from ._typing import KT -from ._typing import MISSING -from ._typing import OKT -from ._typing import OVT -from ._typing import VT -from ._typing import MapOrItems - - -AT = t.TypeVar('AT') # attr type - - -class WeakAttr(t.Generic[AT]): - """Descriptor to automatically manage (de)referencing the given slot as a weakref. - - See https://docs.python.org/3/howto/descriptor.html#managed-attributes - for an intro to using descriptors like this for managed attributes. - """ - - def __init__(self, *, slot: str) -> None: - self.slot = slot - - def __set__(self, instance: t.Any, value: AT) -> None: - setattr(instance, self.slot, weakref(value)) - - def __get__(self, instance: t.Any, __owner: t.Any = None) -> AT: - return t.cast(AT, getattr(instance, self.slot)()) - - -class Node: - """A node in a circular doubly-linked list - used to encode the order of items in an ordered bidict. - - A weak reference to the previous node is stored - to avoid creating strong reference cycles. - Referencing/dereferencing the weakref is handled automatically by :class:`WeakAttr`. - """ - - prv: WeakAttr[Node] = WeakAttr(slot='_prv_weak') - __slots__ = ('__weakref__', '_prv_weak', 'nxt') - - nxt: Node | WeakAttr[Node] # Allow subclasses to use a WeakAttr for nxt too (see SentinelNode) - - def __init__(self, prv: Node, nxt: Node) -> None: - self.prv = prv - self.nxt = nxt - - def unlink(self) -> None: - """Remove self from in between prv and nxt. - Self's references to prv and nxt are retained so it can be relinked (see below). - """ - self.prv.nxt = self.nxt - self.nxt.prv = self.prv - - def relink(self) -> None: - """Restore self between prv and nxt after unlinking (see above).""" - self.prv.nxt = self.nxt.prv = self - - -class SentinelNode(Node): - """Special node in a circular doubly-linked list - that links the first node with the last node. - When its next and previous references point back to itself - it represents an empty list. - """ - - nxt: WeakAttr[Node] = WeakAttr(slot='_nxt_weak') - __slots__ = ('_nxt_weak',) - - def __init__(self) -> None: - super().__init__(self, self) - - def iternodes(self, *, reverse: bool = False) -> t.Iterator[Node]: - """Iterator yielding nodes in the requested order.""" - attr = 'prv' if reverse else 'nxt' - node = getattr(self, attr) - while node is not self: - yield node - node = getattr(node, attr) - - def new_last_node(self) -> Node: - """Create and return a new terminal node.""" - old_last = self.prv - new_last = Node(old_last, self) - old_last.nxt = self.prv = new_last - return new_last - - -class OrderedBidictBase(BidictBase[KT, VT]): - """Base class implementing an ordered :class:`BidirectionalMapping`.""" - - _node_by_korv: bidict[t.Any, Node] - _bykey: bool - - def __init__(self, arg: MapOrItems[KT, VT] = (), /, **kw: VT) -> None: - """Make a new ordered bidirectional mapping. - The signature behaves like that of :class:`dict`. - Items passed in are added in the order they are passed, - respecting the :attr:`~bidict.BidictBase.on_dup` - class attribute in the process. - - The order in which items are inserted is remembered, - similar to :class:`collections.OrderedDict`. - """ - self._sntl = SentinelNode() - self._node_by_korv = bidict() - self._bykey = True - super().__init__(arg, **kw) - - if t.TYPE_CHECKING: - - @property - def inverse(self) -> OrderedBidictBase[VT, KT]: ... - - @property - def inv(self) -> OrderedBidictBase[VT, KT]: ... - - def _make_inverse(self) -> OrderedBidictBase[VT, KT]: - inv = t.cast(OrderedBidictBase[VT, KT], super()._make_inverse()) - inv._sntl = self._sntl - inv._node_by_korv = self._node_by_korv - inv._bykey = not self._bykey - return inv - - def _assoc_node(self, node: Node, key: KT, val: VT) -> None: - korv = key if self._bykey else val - self._node_by_korv.forceput(korv, node) - - def _dissoc_node(self, node: Node) -> None: - del self._node_by_korv.inverse[node] - node.unlink() - - def _init_from(self, other: MapOrItems[KT, VT]) -> None: - """See :meth:`BidictBase._init_from`.""" - super()._init_from(other) - bykey = self._bykey - korv_by_node = self._node_by_korv.inverse - korv_by_node.clear() - korv_by_node_set = korv_by_node.__setitem__ - self._sntl.nxt = self._sntl.prv = self._sntl - new_node = self._sntl.new_last_node - for k, v in iteritems(other): - korv_by_node_set(new_node(), k if bykey else v) - - def _write(self, newkey: KT, newval: VT, oldkey: OKT[KT], oldval: OVT[VT], unwrites: Unwrites | None) -> None: - """See :meth:`bidict.BidictBase._spec_write`.""" - super()._write(newkey, newval, oldkey, oldval, unwrites) - assoc, dissoc = self._assoc_node, self._dissoc_node - node_by_korv, bykey = self._node_by_korv, self._bykey - if oldval is MISSING and oldkey is MISSING: # no key or value duplication - # {0: 1, 2: 3} | {4: 5} => {0: 1, 2: 3, 4: 5} - newnode = self._sntl.new_last_node() - assoc(newnode, newkey, newval) - if unwrites is not None: - unwrites.append((dissoc, newnode)) - elif oldval is not MISSING and oldkey is not MISSING: # key and value duplication across two different items - # {0: 1, 2: 3} | {0: 3} => {0: 3} - # n1, n2 => n1 (collapse n1 and n2 into n1) - # oldkey: 2, oldval: 1, oldnode: n2, newkey: 0, newval: 3, newnode: n1 - if bykey: - oldnode = node_by_korv[oldkey] - newnode = node_by_korv[newkey] - else: - oldnode = node_by_korv[newval] - newnode = node_by_korv[oldval] - dissoc(oldnode) - assoc(newnode, newkey, newval) - if unwrites is not None: - unwrites.extend(( - (assoc, newnode, newkey, oldval), - (assoc, oldnode, oldkey, newval), - (oldnode.relink,), - )) - elif oldval is not MISSING: # just key duplication - # {0: 1, 2: 3} | {2: 4} => {0: 1, 2: 4} - # oldkey: MISSING, oldval: 3, newkey: 2, newval: 4 - node = node_by_korv[newkey if bykey else oldval] - assoc(node, newkey, newval) - if unwrites is not None: - unwrites.append((assoc, node, newkey, oldval)) - else: - assert oldkey is not MISSING # just value duplication - # {0: 1, 2: 3} | {4: 3} => {0: 1, 4: 3} - # oldkey: 2, oldval: MISSING, newkey: 4, newval: 3 - node = node_by_korv[oldkey if bykey else newval] - assoc(node, newkey, newval) - if unwrites is not None: - unwrites.append((assoc, node, oldkey, newval)) - - def __iter__(self) -> t.Iterator[KT]: - """Iterator over the contained keys in insertion order.""" - return self._iter(reverse=False) - - def __reversed__(self) -> t.Iterator[KT]: - """Iterator over the contained keys in reverse insertion order.""" - return self._iter(reverse=True) - - def _iter(self, *, reverse: bool = False) -> t.Iterator[KT]: - nodes = self._sntl.iternodes(reverse=reverse) - korv_by_node = self._node_by_korv.inverse - if self._bykey: - for node in nodes: - yield korv_by_node[node] - else: - key_by_val = self._invm - for node in nodes: - val = korv_by_node[node] - yield key_by_val[val] - - -# * Code review nav * -# ============================================================================ -# ← Prev: _bidict.py Current: _orderedbase.py Next: _orderedbidict.py → -# ============================================================================ diff --git a/venv/lib/python3.9/site-packages/bidict/_orderedbidict.py b/venv/lib/python3.9/site-packages/bidict/_orderedbidict.py deleted file mode 100644 index 2fb1757..0000000 --- a/venv/lib/python3.9/site-packages/bidict/_orderedbidict.py +++ /dev/null @@ -1,172 +0,0 @@ -# Copyright 2009-2024 Joshua Bronson. All rights reserved. -# -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at http://mozilla.org/MPL/2.0/. - - -# * Code review nav * -# (see comments in __init__.py) -# ============================================================================ -# ← Prev: _orderedbase.py Current: _orderedbidict.py -# ============================================================================ - - -"""Provide :class:`OrderedBidict`.""" - -from __future__ import annotations - -import typing as t -from collections.abc import Set - -from ._base import BidictKeysView -from ._bidict import MutableBidict -from ._orderedbase import OrderedBidictBase -from ._typing import KT -from ._typing import VT - - -class OrderedBidict(OrderedBidictBase[KT, VT], MutableBidict[KT, VT]): - """Mutable bidict type that maintains items in insertion order.""" - - if t.TYPE_CHECKING: - - @property - def inverse(self) -> OrderedBidict[VT, KT]: ... - - @property - def inv(self) -> OrderedBidict[VT, KT]: ... - - def clear(self) -> None: - """Remove all items.""" - super().clear() - self._node_by_korv.clear() - self._sntl.nxt = self._sntl.prv = self._sntl - - def _pop(self, key: KT) -> VT: - val = super()._pop(key) - node = self._node_by_korv[key if self._bykey else val] - self._dissoc_node(node) - return val - - def popitem(self, last: bool = True) -> tuple[KT, VT]: - """*b.popitem() → (k, v)* - - If *last* is true, - remove and return the most recently added item as a (key, value) pair. - Otherwise, remove and return the least recently added item. - - :raises KeyError: if *b* is empty. - """ - if not self: - raise KeyError('OrderedBidict is empty') - node = getattr(self._sntl, 'prv' if last else 'nxt') - korv = self._node_by_korv.inverse[node] - if self._bykey: - return korv, self._pop(korv) - return self.inverse._pop(korv), korv - - def move_to_end(self, key: KT, last: bool = True) -> None: - """Move the item with the given key to the end if *last* is true, else to the beginning. - - :raises KeyError: if *key* is missing - """ - korv = key if self._bykey else self._fwdm[key] - node = self._node_by_korv[korv] - node.prv.nxt = node.nxt - node.nxt.prv = node.prv - sntl = self._sntl - if last: - lastnode = sntl.prv - node.prv = lastnode - node.nxt = sntl - sntl.prv = lastnode.nxt = node - else: - firstnode = sntl.nxt - node.prv = sntl - node.nxt = firstnode - sntl.nxt = firstnode.prv = node - - # Override the keys() and items() implementations inherited from BidictBase, - # which may delegate to the backing _fwdm dict, since this is a mutable ordered bidict, - # and therefore the ordering of items can get out of sync with the backing mappings - # after mutation. (Need not override values() because it delegates to .inverse.keys().) - def keys(self) -> t.KeysView[KT]: - """A set-like object providing a view on the contained keys.""" - return _OrderedBidictKeysView(self) - - def items(self) -> t.ItemsView[KT, VT]: - """A set-like object providing a view on the contained items.""" - return _OrderedBidictItemsView(self) - - -# The following MappingView implementations use the __iter__ implementations -# inherited from their superclass counterparts in collections.abc, so they -# continue to yield items in the correct order even after an OrderedBidict -# is mutated. They also provide a __reversed__ implementation, which is not -# provided by the collections.abc superclasses. -class _OrderedBidictKeysView(BidictKeysView[KT]): - _mapping: OrderedBidict[KT, t.Any] - - def __reversed__(self) -> t.Iterator[KT]: - return reversed(self._mapping) - - -class _OrderedBidictItemsView(t.ItemsView[KT, VT]): - _mapping: OrderedBidict[KT, VT] - - def __reversed__(self) -> t.Iterator[tuple[KT, VT]]: - ob = self._mapping - for key in reversed(ob): - yield key, ob[key] - - -# For better performance, make _OrderedBidictKeysView and _OrderedBidictItemsView delegate -# to backing dicts for the methods they inherit from collections.abc.Set. (Cannot delegate -# for __iter__ and __reversed__ since they are order-sensitive.) See also: https://bugs.python.org/issue46713 -_OView = t.Union[t.Type[_OrderedBidictKeysView[KT]], t.Type[_OrderedBidictItemsView[KT, t.Any]]] -_setmethodnames: t.Iterable[str] = ( - '__lt__ __le__ __gt__ __ge__ __eq__ __ne__ __sub__ __rsub__ ' - '__or__ __ror__ __xor__ __rxor__ __and__ __rand__ isdisjoint' -).split() - - -def _override_set_methods_to_use_backing_dict(cls: _OView[KT], viewname: str) -> None: - def make_proxy_method(methodname: str) -> t.Any: - def method(self: _OrderedBidictKeysView[KT] | _OrderedBidictItemsView[KT, t.Any], *args: t.Any) -> t.Any: - fwdm = self._mapping._fwdm - if not isinstance(fwdm, dict): # dict view speedup not available, fall back to Set's implementation. - return getattr(Set, methodname)(self, *args) - fwdm_dict_view = getattr(fwdm, viewname)() - fwdm_dict_view_method = getattr(fwdm_dict_view, methodname) - if ( - len(args) != 1 - or not isinstance((arg := args[0]), self.__class__) - or not isinstance(arg._mapping._fwdm, dict) - ): - return fwdm_dict_view_method(*args) - # self and arg are both _OrderedBidictKeysViews or _OrderedBidictItemsViews whose bidicts are backed by - # a dict. Use arg's backing dict's corresponding view instead of arg. Otherwise, e.g. `ob1.keys() - # < ob2.keys()` would give "TypeError: '<' not supported between instances of '_OrderedBidictKeysView' and - # '_OrderedBidictKeysView'", because both `dict_keys(ob1).__lt__(ob2.keys()) is NotImplemented` and - # `dict_keys(ob2).__gt__(ob1.keys()) is NotImplemented`. - arg_dict = arg._mapping._fwdm - arg_dict_view = getattr(arg_dict, viewname)() - return fwdm_dict_view_method(arg_dict_view) - - method.__name__ = methodname - method.__qualname__ = f'{cls.__qualname__}.{methodname}' - return method - - for name in _setmethodnames: - setattr(cls, name, make_proxy_method(name)) - - -_override_set_methods_to_use_backing_dict(_OrderedBidictKeysView, 'keys') -_override_set_methods_to_use_backing_dict(_OrderedBidictItemsView, 'items') - - -# * Code review nav * -# ============================================================================ -# ← Prev: _orderedbase.py Current: _orderedbidict.py -# ============================================================================ diff --git a/venv/lib/python3.9/site-packages/bidict/_typing.py b/venv/lib/python3.9/site-packages/bidict/_typing.py deleted file mode 100644 index ce95053..0000000 --- a/venv/lib/python3.9/site-packages/bidict/_typing.py +++ /dev/null @@ -1,49 +0,0 @@ -# Copyright 2009-2024 Joshua Bronson. All rights reserved. -# -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at http://mozilla.org/MPL/2.0/. - - -"""Provide typing-related objects.""" - -from __future__ import annotations - -import typing as t -from enum import Enum - - -KT = t.TypeVar('KT') -VT = t.TypeVar('VT') -VT_co = t.TypeVar('VT_co', covariant=True) - - -Items = t.Iterable[t.Tuple[KT, VT]] - - -@t.runtime_checkable -class Maplike(t.Protocol[KT, VT_co]): - """Like typeshed's SupportsKeysAndGetItem, but usable at runtime.""" - - def keys(self) -> t.Iterable[KT]: ... - - def __getitem__(self, __key: KT) -> VT_co: ... - - -MapOrItems = t.Union[Maplike[KT, VT], Items[KT, VT]] -MappOrItems = t.Union[t.Mapping[KT, VT], Items[KT, VT]] -ItemsIter = t.Iterator[t.Tuple[KT, VT]] - - -class MissingT(Enum): - """Sentinel used to represent none/missing when None itself can't be used.""" - - MISSING = 'MISSING' - - -MISSING: t.Final[t.Literal[MissingT.MISSING]] = MissingT.MISSING -OKT = t.Union[KT, MissingT] #: optional key type -OVT = t.Union[VT, MissingT] #: optional value type - -DT = t.TypeVar('DT') #: for default arguments -ODT = t.Union[DT, MissingT] #: optional default arg type diff --git a/venv/lib/python3.9/site-packages/bidict/metadata.py b/venv/lib/python3.9/site-packages/bidict/metadata.py deleted file mode 100644 index 30ad836..0000000 --- a/venv/lib/python3.9/site-packages/bidict/metadata.py +++ /dev/null @@ -1,14 +0,0 @@ -# Copyright 2009-2024 Joshua Bronson. All rights reserved. -# -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at http://mozilla.org/MPL/2.0/. - -"""Define bidict package metadata.""" - -__version__ = '0.23.1' -__author__ = {'name': 'Joshua Bronson', 'email': 'jabronson@gmail.com'} -__copyright__ = '© 2009-2024 Joshua Bronson' -__description__ = 'The bidirectional mapping library for Python.' -__license__ = 'MPL 2.0' -__url__ = 'https://bidict.readthedocs.io' diff --git a/venv/lib/python3.9/site-packages/bidict/py.typed b/venv/lib/python3.9/site-packages/bidict/py.typed deleted file mode 100644 index 342ea76..0000000 --- a/venv/lib/python3.9/site-packages/bidict/py.typed +++ /dev/null @@ -1 +0,0 @@ -PEP-561 marker. diff --git a/venv/lib/python3.9/site-packages/blinker-1.9.0.dist-info/INSTALLER b/venv/lib/python3.9/site-packages/blinker-1.9.0.dist-info/INSTALLER deleted file mode 100644 index a1b589e..0000000 --- a/venv/lib/python3.9/site-packages/blinker-1.9.0.dist-info/INSTALLER +++ /dev/null @@ -1 +0,0 @@ -pip diff --git a/venv/lib/python3.9/site-packages/blinker-1.9.0.dist-info/LICENSE.txt b/venv/lib/python3.9/site-packages/blinker-1.9.0.dist-info/LICENSE.txt deleted file mode 100644 index 79c9825..0000000 --- a/venv/lib/python3.9/site-packages/blinker-1.9.0.dist-info/LICENSE.txt +++ /dev/null @@ -1,20 +0,0 @@ -Copyright 2010 Jason Kirtland - -Permission is hereby granted, free of charge, to any person obtaining a -copy of this software and associated documentation files (the -"Software"), to deal in the Software without restriction, including -without limitation the rights to use, copy, modify, merge, publish, -distribute, sublicense, and/or sell copies of the Software, and to -permit persons to whom the Software is furnished to do so, subject to -the following conditions: - -The above copyright notice and this permission notice shall be included -in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY -CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, -TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE -SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/venv/lib/python3.9/site-packages/blinker-1.9.0.dist-info/METADATA b/venv/lib/python3.9/site-packages/blinker-1.9.0.dist-info/METADATA deleted file mode 100644 index 6d343f5..0000000 --- a/venv/lib/python3.9/site-packages/blinker-1.9.0.dist-info/METADATA +++ /dev/null @@ -1,60 +0,0 @@ -Metadata-Version: 2.3 -Name: blinker -Version: 1.9.0 -Summary: Fast, simple object-to-object and broadcast signaling -Author: Jason Kirtland -Maintainer-email: Pallets Ecosystem -Requires-Python: >=3.9 -Description-Content-Type: text/markdown -Classifier: Development Status :: 5 - Production/Stable -Classifier: License :: OSI Approved :: MIT License -Classifier: Programming Language :: Python -Classifier: Typing :: Typed -Project-URL: Chat, https://discord.gg/pallets -Project-URL: Documentation, https://blinker.readthedocs.io -Project-URL: Source, https://github.com/pallets-eco/blinker/ - -# Blinker - -Blinker provides a fast dispatching system that allows any number of -interested parties to subscribe to events, or "signals". - - -## Pallets Community Ecosystem - -> [!IMPORTANT]\ -> This project is part of the Pallets Community Ecosystem. Pallets is the open -> source organization that maintains Flask; Pallets-Eco enables community -> maintenance of related projects. If you are interested in helping maintain -> this project, please reach out on [the Pallets Discord server][discord]. -> -> [discord]: https://discord.gg/pallets - - -## Example - -Signal receivers can subscribe to specific senders or receive signals -sent by any sender. - -```pycon ->>> from blinker import signal ->>> started = signal('round-started') ->>> def each(round): -... print(f"Round {round}") -... ->>> started.connect(each) - ->>> def round_two(round): -... print("This is round two.") -... ->>> started.connect(round_two, sender=2) - ->>> for round in range(1, 4): -... started.send(round) -... -Round 1! -Round 2! -This is round two. -Round 3! -``` - diff --git a/venv/lib/python3.9/site-packages/blinker-1.9.0.dist-info/RECORD b/venv/lib/python3.9/site-packages/blinker-1.9.0.dist-info/RECORD deleted file mode 100644 index 40109c3..0000000 --- a/venv/lib/python3.9/site-packages/blinker-1.9.0.dist-info/RECORD +++ /dev/null @@ -1,12 +0,0 @@ -blinker-1.9.0.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 -blinker-1.9.0.dist-info/LICENSE.txt,sha256=nrc6HzhZekqhcCXSrhvjg5Ykx5XphdTw6Xac4p-spGc,1054 -blinker-1.9.0.dist-info/METADATA,sha256=uIRiM8wjjbHkCtbCyTvctU37IAZk0kEe5kxAld1dvzA,1633 -blinker-1.9.0.dist-info/RECORD,, -blinker-1.9.0.dist-info/WHEEL,sha256=CpUCUxeHQbRN5UGRQHYRJorO5Af-Qy_fHMctcQ8DSGI,82 -blinker/__init__.py,sha256=I2EdZqpy4LyjX17Hn1yzJGWCjeLaVaPzsMgHkLfj_cQ,317 -blinker/__pycache__/__init__.cpython-39.pyc,, -blinker/__pycache__/_utilities.cpython-39.pyc,, -blinker/__pycache__/base.cpython-39.pyc,, -blinker/_utilities.py,sha256=0J7eeXXTUx0Ivf8asfpx0ycVkp0Eqfqnj117x2mYX9E,1675 -blinker/base.py,sha256=QpDuvXXcwJF49lUBcH5BiST46Rz9wSG7VW_p7N_027M,19132 -blinker/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 diff --git a/venv/lib/python3.9/site-packages/blinker-1.9.0.dist-info/WHEEL b/venv/lib/python3.9/site-packages/blinker-1.9.0.dist-info/WHEEL deleted file mode 100644 index e3c6fee..0000000 --- a/venv/lib/python3.9/site-packages/blinker-1.9.0.dist-info/WHEEL +++ /dev/null @@ -1,4 +0,0 @@ -Wheel-Version: 1.0 -Generator: flit 3.10.1 -Root-Is-Purelib: true -Tag: py3-none-any diff --git a/venv/lib/python3.9/site-packages/blinker/__init__.py b/venv/lib/python3.9/site-packages/blinker/__init__.py deleted file mode 100644 index 1772fa4..0000000 --- a/venv/lib/python3.9/site-packages/blinker/__init__.py +++ /dev/null @@ -1,17 +0,0 @@ -from __future__ import annotations - -from .base import ANY -from .base import default_namespace -from .base import NamedSignal -from .base import Namespace -from .base import Signal -from .base import signal - -__all__ = [ - "ANY", - "default_namespace", - "NamedSignal", - "Namespace", - "Signal", - "signal", -] diff --git a/venv/lib/python3.9/site-packages/blinker/_utilities.py b/venv/lib/python3.9/site-packages/blinker/_utilities.py deleted file mode 100644 index 000c902..0000000 --- a/venv/lib/python3.9/site-packages/blinker/_utilities.py +++ /dev/null @@ -1,64 +0,0 @@ -from __future__ import annotations - -import collections.abc as c -import inspect -import typing as t -from weakref import ref -from weakref import WeakMethod - -T = t.TypeVar("T") - - -class Symbol: - """A constant symbol, nicer than ``object()``. Repeated calls return the - same instance. - - >>> Symbol('foo') is Symbol('foo') - True - >>> Symbol('foo') - foo - """ - - symbols: t.ClassVar[dict[str, Symbol]] = {} - - def __new__(cls, name: str) -> Symbol: - if name in cls.symbols: - return cls.symbols[name] - - obj = super().__new__(cls) - cls.symbols[name] = obj - return obj - - def __init__(self, name: str) -> None: - self.name = name - - def __repr__(self) -> str: - return self.name - - def __getnewargs__(self) -> tuple[t.Any, ...]: - return (self.name,) - - -def make_id(obj: object) -> c.Hashable: - """Get a stable identifier for a receiver or sender, to be used as a dict - key or in a set. - """ - if inspect.ismethod(obj): - # The id of a bound method is not stable, but the id of the unbound - # function and instance are. - return id(obj.__func__), id(obj.__self__) - - if isinstance(obj, (str, int)): - # Instances with the same value always compare equal and have the same - # hash, even if the id may change. - return obj - - # Assume other types are not hashable but will always be the same instance. - return id(obj) - - -def make_ref(obj: T, callback: c.Callable[[ref[T]], None] | None = None) -> ref[T]: - if inspect.ismethod(obj): - return WeakMethod(obj, callback) # type: ignore[arg-type, return-value] - - return ref(obj, callback) diff --git a/venv/lib/python3.9/site-packages/blinker/base.py b/venv/lib/python3.9/site-packages/blinker/base.py deleted file mode 100644 index d051b94..0000000 --- a/venv/lib/python3.9/site-packages/blinker/base.py +++ /dev/null @@ -1,512 +0,0 @@ -from __future__ import annotations - -import collections.abc as c -import sys -import typing as t -import weakref -from collections import defaultdict -from contextlib import contextmanager -from functools import cached_property -from inspect import iscoroutinefunction - -from ._utilities import make_id -from ._utilities import make_ref -from ._utilities import Symbol - -F = t.TypeVar("F", bound=c.Callable[..., t.Any]) - -ANY = Symbol("ANY") -"""Symbol for "any sender".""" - -ANY_ID = 0 - - -class Signal: - """A notification emitter. - - :param doc: The docstring for the signal. - """ - - ANY = ANY - """An alias for the :data:`~blinker.ANY` sender symbol.""" - - set_class: type[set[t.Any]] = set - """The set class to use for tracking connected receivers and senders. - Python's ``set`` is unordered. If receivers must be dispatched in the order - they were connected, an ordered set implementation can be used. - - .. versionadded:: 1.7 - """ - - @cached_property - def receiver_connected(self) -> Signal: - """Emitted at the end of each :meth:`connect` call. - - The signal sender is the signal instance, and the :meth:`connect` - arguments are passed through: ``receiver``, ``sender``, and ``weak``. - - .. versionadded:: 1.2 - """ - return Signal(doc="Emitted after a receiver connects.") - - @cached_property - def receiver_disconnected(self) -> Signal: - """Emitted at the end of each :meth:`disconnect` call. - - The sender is the signal instance, and the :meth:`disconnect` arguments - are passed through: ``receiver`` and ``sender``. - - This signal is emitted **only** when :meth:`disconnect` is called - explicitly. This signal cannot be emitted by an automatic disconnect - when a weakly referenced receiver or sender goes out of scope, as the - instance is no longer be available to be used as the sender for this - signal. - - An alternative approach is available by subscribing to - :attr:`receiver_connected` and setting up a custom weakref cleanup - callback on weak receivers and senders. - - .. versionadded:: 1.2 - """ - return Signal(doc="Emitted after a receiver disconnects.") - - def __init__(self, doc: str | None = None) -> None: - if doc: - self.__doc__ = doc - - self.receivers: dict[ - t.Any, weakref.ref[c.Callable[..., t.Any]] | c.Callable[..., t.Any] - ] = {} - """The map of connected receivers. Useful to quickly check if any - receivers are connected to the signal: ``if s.receivers:``. The - structure and data is not part of the public API, but checking its - boolean value is. - """ - - self.is_muted: bool = False - self._by_receiver: dict[t.Any, set[t.Any]] = defaultdict(self.set_class) - self._by_sender: dict[t.Any, set[t.Any]] = defaultdict(self.set_class) - self._weak_senders: dict[t.Any, weakref.ref[t.Any]] = {} - - def connect(self, receiver: F, sender: t.Any = ANY, weak: bool = True) -> F: - """Connect ``receiver`` to be called when the signal is sent by - ``sender``. - - :param receiver: The callable to call when :meth:`send` is called with - the given ``sender``, passing ``sender`` as a positional argument - along with any extra keyword arguments. - :param sender: Any object or :data:`ANY`. ``receiver`` will only be - called when :meth:`send` is called with this sender. If ``ANY``, the - receiver will be called for any sender. A receiver may be connected - to multiple senders by calling :meth:`connect` multiple times. - :param weak: Track the receiver with a :mod:`weakref`. The receiver will - be automatically disconnected when it is garbage collected. When - connecting a receiver defined within a function, set to ``False``, - otherwise it will be disconnected when the function scope ends. - """ - receiver_id = make_id(receiver) - sender_id = ANY_ID if sender is ANY else make_id(sender) - - if weak: - self.receivers[receiver_id] = make_ref( - receiver, self._make_cleanup_receiver(receiver_id) - ) - else: - self.receivers[receiver_id] = receiver - - self._by_sender[sender_id].add(receiver_id) - self._by_receiver[receiver_id].add(sender_id) - - if sender is not ANY and sender_id not in self._weak_senders: - # store a cleanup for weakref-able senders - try: - self._weak_senders[sender_id] = make_ref( - sender, self._make_cleanup_sender(sender_id) - ) - except TypeError: - pass - - if "receiver_connected" in self.__dict__ and self.receiver_connected.receivers: - try: - self.receiver_connected.send( - self, receiver=receiver, sender=sender, weak=weak - ) - except TypeError: - # TODO no explanation or test for this - self.disconnect(receiver, sender) - raise - - return receiver - - def connect_via(self, sender: t.Any, weak: bool = False) -> c.Callable[[F], F]: - """Connect the decorated function to be called when the signal is sent - by ``sender``. - - The decorated function will be called when :meth:`send` is called with - the given ``sender``, passing ``sender`` as a positional argument along - with any extra keyword arguments. - - :param sender: Any object or :data:`ANY`. ``receiver`` will only be - called when :meth:`send` is called with this sender. If ``ANY``, the - receiver will be called for any sender. A receiver may be connected - to multiple senders by calling :meth:`connect` multiple times. - :param weak: Track the receiver with a :mod:`weakref`. The receiver will - be automatically disconnected when it is garbage collected. When - connecting a receiver defined within a function, set to ``False``, - otherwise it will be disconnected when the function scope ends.= - - .. versionadded:: 1.1 - """ - - def decorator(fn: F) -> F: - self.connect(fn, sender, weak) - return fn - - return decorator - - @contextmanager - def connected_to( - self, receiver: c.Callable[..., t.Any], sender: t.Any = ANY - ) -> c.Generator[None, None, None]: - """A context manager that temporarily connects ``receiver`` to the - signal while a ``with`` block executes. When the block exits, the - receiver is disconnected. Useful for tests. - - :param receiver: The callable to call when :meth:`send` is called with - the given ``sender``, passing ``sender`` as a positional argument - along with any extra keyword arguments. - :param sender: Any object or :data:`ANY`. ``receiver`` will only be - called when :meth:`send` is called with this sender. If ``ANY``, the - receiver will be called for any sender. - - .. versionadded:: 1.1 - """ - self.connect(receiver, sender=sender, weak=False) - - try: - yield None - finally: - self.disconnect(receiver) - - @contextmanager - def muted(self) -> c.Generator[None, None, None]: - """A context manager that temporarily disables the signal. No receivers - will be called if the signal is sent, until the ``with`` block exits. - Useful for tests. - """ - self.is_muted = True - - try: - yield None - finally: - self.is_muted = False - - def send( - self, - sender: t.Any | None = None, - /, - *, - _async_wrapper: c.Callable[ - [c.Callable[..., c.Coroutine[t.Any, t.Any, t.Any]]], c.Callable[..., t.Any] - ] - | None = None, - **kwargs: t.Any, - ) -> list[tuple[c.Callable[..., t.Any], t.Any]]: - """Call all receivers that are connected to the given ``sender`` - or :data:`ANY`. Each receiver is called with ``sender`` as a positional - argument along with any extra keyword arguments. Return a list of - ``(receiver, return value)`` tuples. - - The order receivers are called is undefined, but can be influenced by - setting :attr:`set_class`. - - If a receiver raises an exception, that exception will propagate up. - This makes debugging straightforward, with an assumption that correctly - implemented receivers will not raise. - - :param sender: Call receivers connected to this sender, in addition to - those connected to :data:`ANY`. - :param _async_wrapper: Will be called on any receivers that are async - coroutines to turn them into sync callables. For example, could run - the receiver with an event loop. - :param kwargs: Extra keyword arguments to pass to each receiver. - - .. versionchanged:: 1.7 - Added the ``_async_wrapper`` argument. - """ - if self.is_muted: - return [] - - results = [] - - for receiver in self.receivers_for(sender): - if iscoroutinefunction(receiver): - if _async_wrapper is None: - raise RuntimeError("Cannot send to a coroutine function.") - - result = _async_wrapper(receiver)(sender, **kwargs) - else: - result = receiver(sender, **kwargs) - - results.append((receiver, result)) - - return results - - async def send_async( - self, - sender: t.Any | None = None, - /, - *, - _sync_wrapper: c.Callable[ - [c.Callable[..., t.Any]], c.Callable[..., c.Coroutine[t.Any, t.Any, t.Any]] - ] - | None = None, - **kwargs: t.Any, - ) -> list[tuple[c.Callable[..., t.Any], t.Any]]: - """Await all receivers that are connected to the given ``sender`` - or :data:`ANY`. Each receiver is called with ``sender`` as a positional - argument along with any extra keyword arguments. Return a list of - ``(receiver, return value)`` tuples. - - The order receivers are called is undefined, but can be influenced by - setting :attr:`set_class`. - - If a receiver raises an exception, that exception will propagate up. - This makes debugging straightforward, with an assumption that correctly - implemented receivers will not raise. - - :param sender: Call receivers connected to this sender, in addition to - those connected to :data:`ANY`. - :param _sync_wrapper: Will be called on any receivers that are sync - callables to turn them into async coroutines. For example, - could call the receiver in a thread. - :param kwargs: Extra keyword arguments to pass to each receiver. - - .. versionadded:: 1.7 - """ - if self.is_muted: - return [] - - results = [] - - for receiver in self.receivers_for(sender): - if not iscoroutinefunction(receiver): - if _sync_wrapper is None: - raise RuntimeError("Cannot send to a non-coroutine function.") - - result = await _sync_wrapper(receiver)(sender, **kwargs) - else: - result = await receiver(sender, **kwargs) - - results.append((receiver, result)) - - return results - - def has_receivers_for(self, sender: t.Any) -> bool: - """Check if there is at least one receiver that will be called with the - given ``sender``. A receiver connected to :data:`ANY` will always be - called, regardless of sender. Does not check if weakly referenced - receivers are still live. See :meth:`receivers_for` for a stronger - search. - - :param sender: Check for receivers connected to this sender, in addition - to those connected to :data:`ANY`. - """ - if not self.receivers: - return False - - if self._by_sender[ANY_ID]: - return True - - if sender is ANY: - return False - - return make_id(sender) in self._by_sender - - def receivers_for( - self, sender: t.Any - ) -> c.Generator[c.Callable[..., t.Any], None, None]: - """Yield each receiver to be called for ``sender``, in addition to those - to be called for :data:`ANY`. Weakly referenced receivers that are not - live will be disconnected and skipped. - - :param sender: Yield receivers connected to this sender, in addition - to those connected to :data:`ANY`. - """ - # TODO: test receivers_for(ANY) - if not self.receivers: - return - - sender_id = make_id(sender) - - if sender_id in self._by_sender: - ids = self._by_sender[ANY_ID] | self._by_sender[sender_id] - else: - ids = self._by_sender[ANY_ID].copy() - - for receiver_id in ids: - receiver = self.receivers.get(receiver_id) - - if receiver is None: - continue - - if isinstance(receiver, weakref.ref): - strong = receiver() - - if strong is None: - self._disconnect(receiver_id, ANY_ID) - continue - - yield strong - else: - yield receiver - - def disconnect(self, receiver: c.Callable[..., t.Any], sender: t.Any = ANY) -> None: - """Disconnect ``receiver`` from being called when the signal is sent by - ``sender``. - - :param receiver: A connected receiver callable. - :param sender: Disconnect from only this sender. By default, disconnect - from all senders. - """ - sender_id: c.Hashable - - if sender is ANY: - sender_id = ANY_ID - else: - sender_id = make_id(sender) - - receiver_id = make_id(receiver) - self._disconnect(receiver_id, sender_id) - - if ( - "receiver_disconnected" in self.__dict__ - and self.receiver_disconnected.receivers - ): - self.receiver_disconnected.send(self, receiver=receiver, sender=sender) - - def _disconnect(self, receiver_id: c.Hashable, sender_id: c.Hashable) -> None: - if sender_id == ANY_ID: - if self._by_receiver.pop(receiver_id, None) is not None: - for bucket in self._by_sender.values(): - bucket.discard(receiver_id) - - self.receivers.pop(receiver_id, None) - else: - self._by_sender[sender_id].discard(receiver_id) - self._by_receiver[receiver_id].discard(sender_id) - - def _make_cleanup_receiver( - self, receiver_id: c.Hashable - ) -> c.Callable[[weakref.ref[c.Callable[..., t.Any]]], None]: - """Create a callback function to disconnect a weakly referenced - receiver when it is garbage collected. - """ - - def cleanup(ref: weakref.ref[c.Callable[..., t.Any]]) -> None: - # If the interpreter is shutting down, disconnecting can result in a - # weird ignored exception. Don't call it in that case. - if not sys.is_finalizing(): - self._disconnect(receiver_id, ANY_ID) - - return cleanup - - def _make_cleanup_sender( - self, sender_id: c.Hashable - ) -> c.Callable[[weakref.ref[t.Any]], None]: - """Create a callback function to disconnect all receivers for a weakly - referenced sender when it is garbage collected. - """ - assert sender_id != ANY_ID - - def cleanup(ref: weakref.ref[t.Any]) -> None: - self._weak_senders.pop(sender_id, None) - - for receiver_id in self._by_sender.pop(sender_id, ()): - self._by_receiver[receiver_id].discard(sender_id) - - return cleanup - - def _cleanup_bookkeeping(self) -> None: - """Prune unused sender/receiver bookkeeping. Not threadsafe. - - Connecting & disconnecting leaves behind a small amount of bookkeeping - data. Typical workloads using Blinker, for example in most web apps, - Flask, CLI scripts, etc., are not adversely affected by this - bookkeeping. - - With a long-running process performing dynamic signal routing with high - volume, e.g. connecting to function closures, senders are all unique - object instances. Doing all of this over and over may cause memory usage - to grow due to extraneous bookkeeping. (An empty ``set`` for each stale - sender/receiver pair.) - - This method will prune that bookkeeping away, with the caveat that such - pruning is not threadsafe. The risk is that cleanup of a fully - disconnected receiver/sender pair occurs while another thread is - connecting that same pair. If you are in the highly dynamic, unique - receiver/sender situation that has lead you to this method, that failure - mode is perhaps not a big deal for you. - """ - for mapping in (self._by_sender, self._by_receiver): - for ident, bucket in list(mapping.items()): - if not bucket: - mapping.pop(ident, None) - - def _clear_state(self) -> None: - """Disconnect all receivers and senders. Useful for tests.""" - self._weak_senders.clear() - self.receivers.clear() - self._by_sender.clear() - self._by_receiver.clear() - - -class NamedSignal(Signal): - """A named generic notification emitter. The name is not used by the signal - itself, but matches the key in the :class:`Namespace` that it belongs to. - - :param name: The name of the signal within the namespace. - :param doc: The docstring for the signal. - """ - - def __init__(self, name: str, doc: str | None = None) -> None: - super().__init__(doc) - - #: The name of this signal. - self.name: str = name - - def __repr__(self) -> str: - base = super().__repr__() - return f"{base[:-1]}; {self.name!r}>" # noqa: E702 - - -class Namespace(dict[str, NamedSignal]): - """A dict mapping names to signals.""" - - def signal(self, name: str, doc: str | None = None) -> NamedSignal: - """Return the :class:`NamedSignal` for the given ``name``, creating it - if required. Repeated calls with the same name return the same signal. - - :param name: The name of the signal. - :param doc: The docstring of the signal. - """ - if name not in self: - self[name] = NamedSignal(name, doc) - - return self[name] - - -class _PNamespaceSignal(t.Protocol): - def __call__(self, name: str, doc: str | None = None) -> NamedSignal: ... - - -default_namespace: Namespace = Namespace() -"""A default :class:`Namespace` for creating named signals. :func:`signal` -creates a :class:`NamedSignal` in this namespace. -""" - -signal: _PNamespaceSignal = default_namespace.signal -"""Return a :class:`NamedSignal` in :data:`default_namespace` with the given -``name``, creating it if required. Repeated calls with the same name return the -same signal. -""" diff --git a/venv/lib/python3.9/site-packages/blinker/py.typed b/venv/lib/python3.9/site-packages/blinker/py.typed deleted file mode 100644 index e69de29..0000000 diff --git a/venv/lib/python3.9/site-packages/certifi-2026.4.22.dist-info/INSTALLER b/venv/lib/python3.9/site-packages/certifi-2026.4.22.dist-info/INSTALLER deleted file mode 100644 index a1b589e..0000000 --- a/venv/lib/python3.9/site-packages/certifi-2026.4.22.dist-info/INSTALLER +++ /dev/null @@ -1 +0,0 @@ -pip diff --git a/venv/lib/python3.9/site-packages/certifi-2026.4.22.dist-info/METADATA b/venv/lib/python3.9/site-packages/certifi-2026.4.22.dist-info/METADATA deleted file mode 100644 index 3816cc9..0000000 --- a/venv/lib/python3.9/site-packages/certifi-2026.4.22.dist-info/METADATA +++ /dev/null @@ -1,78 +0,0 @@ -Metadata-Version: 2.4 -Name: certifi -Version: 2026.4.22 -Summary: Python package for providing Mozilla's CA Bundle. -Home-page: https://github.com/certifi/python-certifi -Author: Kenneth Reitz -Author-email: me@kennethreitz.com -License: MPL-2.0 -Project-URL: Source, https://github.com/certifi/python-certifi -Classifier: Development Status :: 5 - Production/Stable -Classifier: Intended Audience :: Developers -Classifier: License :: OSI Approved :: Mozilla Public License 2.0 (MPL 2.0) -Classifier: Natural Language :: English -Classifier: Programming Language :: Python -Classifier: Programming Language :: Python :: 3 -Classifier: Programming Language :: Python :: 3 :: Only -Classifier: Programming Language :: Python :: 3.7 -Classifier: Programming Language :: Python :: 3.8 -Classifier: Programming Language :: Python :: 3.9 -Classifier: Programming Language :: Python :: 3.10 -Classifier: Programming Language :: Python :: 3.11 -Classifier: Programming Language :: Python :: 3.12 -Classifier: Programming Language :: Python :: 3.13 -Classifier: Programming Language :: Python :: 3.14 -Requires-Python: >=3.7 -License-File: LICENSE -Dynamic: author -Dynamic: author-email -Dynamic: classifier -Dynamic: description -Dynamic: home-page -Dynamic: license -Dynamic: license-file -Dynamic: project-url -Dynamic: requires-python -Dynamic: summary - -Certifi: Python SSL Certificates -================================ - -Certifi provides Mozilla's carefully curated collection of Root Certificates for -validating the trustworthiness of SSL certificates while verifying the identity -of TLS hosts. It has been extracted from the `Requests`_ project. - -Installation ------------- - -``certifi`` is available on PyPI. Simply install it with ``pip``:: - - $ pip install certifi - -Usage ------ - -To reference the installed certificate authority (CA) bundle, you can use the -built-in function:: - - >>> import certifi - - >>> certifi.where() - '/usr/local/lib/python3.7/site-packages/certifi/cacert.pem' - -Or from the command line:: - - $ python -m certifi - /usr/local/lib/python3.7/site-packages/certifi/cacert.pem - -Enjoy! - -.. _`Requests`: https://requests.readthedocs.io/en/master/ - -Addition/Removal of Certificates --------------------------------- - -Certifi does not support any addition/removal or other modification of the -CA trust store content. This project is intended to provide a reliable and -highly portable root of trust to python deployments. Look to upstream projects -for methods to use alternate trust. diff --git a/venv/lib/python3.9/site-packages/certifi-2026.4.22.dist-info/RECORD b/venv/lib/python3.9/site-packages/certifi-2026.4.22.dist-info/RECORD deleted file mode 100644 index ffb4372..0000000 --- a/venv/lib/python3.9/site-packages/certifi-2026.4.22.dist-info/RECORD +++ /dev/null @@ -1,14 +0,0 @@ -certifi-2026.4.22.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 -certifi-2026.4.22.dist-info/METADATA,sha256=Ttb_6cy-0FBGq3v_ICTNPKcXKVs2i-0f4gpz42W8QVo,2474 -certifi-2026.4.22.dist-info/RECORD,, -certifi-2026.4.22.dist-info/WHEEL,sha256=aeYiig01lYGDzBgS8HxWXOg3uV61G9ijOsup-k9o1sk,91 -certifi-2026.4.22.dist-info/licenses/LICENSE,sha256=6TcW2mucDVpKHfYP5pWzcPBpVgPSH2-D8FPkLPwQyvc,989 -certifi-2026.4.22.dist-info/top_level.txt,sha256=KMu4vUCfsjLrkPbSNdgdekS-pVJzBAJFO__nI8NF6-U,8 -certifi/__init__.py,sha256=iBJYWtxRGHMaO1S73pWYpFn962WQ4ldof2GkfMSREJM,94 -certifi/__main__.py,sha256=xBBoj905TUWBLRGANOcf7oi6e-3dMP4cEoG9OyMs11g,243 -certifi/__pycache__/__init__.cpython-39.pyc,, -certifi/__pycache__/__main__.cpython-39.pyc,, -certifi/__pycache__/core.cpython-39.pyc,, -certifi/cacert.pem,sha256=Fr4_b-sVQIGV3P46oade-dty9ka5brvv3Gj1YlX3mfg,238641 -certifi/core.py,sha256=XFXycndG5pf37ayeF8N32HUuDafsyhkVMbO4BAPWHa0,3394 -certifi/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 diff --git a/venv/lib/python3.9/site-packages/certifi-2026.4.22.dist-info/WHEEL b/venv/lib/python3.9/site-packages/certifi-2026.4.22.dist-info/WHEEL deleted file mode 100644 index 14a883f..0000000 --- a/venv/lib/python3.9/site-packages/certifi-2026.4.22.dist-info/WHEEL +++ /dev/null @@ -1,5 +0,0 @@ -Wheel-Version: 1.0 -Generator: setuptools (82.0.1) -Root-Is-Purelib: true -Tag: py3-none-any - diff --git a/venv/lib/python3.9/site-packages/certifi-2026.4.22.dist-info/licenses/LICENSE b/venv/lib/python3.9/site-packages/certifi-2026.4.22.dist-info/licenses/LICENSE deleted file mode 100644 index 62b076c..0000000 --- a/venv/lib/python3.9/site-packages/certifi-2026.4.22.dist-info/licenses/LICENSE +++ /dev/null @@ -1,20 +0,0 @@ -This package contains a modified version of ca-bundle.crt: - -ca-bundle.crt -- Bundle of CA Root Certificates - -This is a bundle of X.509 certificates of public Certificate Authorities -(CA). These were automatically extracted from Mozilla's root certificates -file (certdata.txt). This file can be found in the mozilla source tree: -https://hg.mozilla.org/mozilla-central/file/tip/security/nss/lib/ckfw/builtins/certdata.txt -It contains the certificates in PEM format and therefore -can be directly used with curl / libcurl / php_curl, or with -an Apache+mod_ssl webserver for SSL client authentication. -Just configure this file as the SSLCACertificateFile.# - -***** BEGIN LICENSE BLOCK ***** -This Source Code Form is subject to the terms of the Mozilla Public License, -v. 2.0. If a copy of the MPL was not distributed with this file, You can obtain -one at http://mozilla.org/MPL/2.0/. - -***** END LICENSE BLOCK ***** -@(#) $RCSfile: certdata.txt,v $ $Revision: 1.80 $ $Date: 2011/11/03 15:11:58 $ diff --git a/venv/lib/python3.9/site-packages/certifi-2026.4.22.dist-info/top_level.txt b/venv/lib/python3.9/site-packages/certifi-2026.4.22.dist-info/top_level.txt deleted file mode 100644 index 963eac5..0000000 --- a/venv/lib/python3.9/site-packages/certifi-2026.4.22.dist-info/top_level.txt +++ /dev/null @@ -1 +0,0 @@ -certifi diff --git a/venv/lib/python3.9/site-packages/certifi/__init__.py b/venv/lib/python3.9/site-packages/certifi/__init__.py deleted file mode 100644 index 9d711f4..0000000 --- a/venv/lib/python3.9/site-packages/certifi/__init__.py +++ /dev/null @@ -1,4 +0,0 @@ -from .core import contents, where - -__all__ = ["contents", "where"] -__version__ = "2026.04.22" diff --git a/venv/lib/python3.9/site-packages/certifi/__main__.py b/venv/lib/python3.9/site-packages/certifi/__main__.py deleted file mode 100644 index 8945b5d..0000000 --- a/venv/lib/python3.9/site-packages/certifi/__main__.py +++ /dev/null @@ -1,12 +0,0 @@ -import argparse - -from certifi import contents, where - -parser = argparse.ArgumentParser() -parser.add_argument("-c", "--contents", action="store_true") -args = parser.parse_args() - -if args.contents: - print(contents()) -else: - print(where()) diff --git a/venv/lib/python3.9/site-packages/certifi/cacert.pem b/venv/lib/python3.9/site-packages/certifi/cacert.pem deleted file mode 100644 index 27132f5..0000000 --- a/venv/lib/python3.9/site-packages/certifi/cacert.pem +++ /dev/null @@ -1,3933 +0,0 @@ - -# Issuer: CN=COMODO ECC Certification Authority O=COMODO CA Limited -# Subject: CN=COMODO ECC Certification Authority O=COMODO CA Limited -# Label: "COMODO ECC Certification Authority" -# Serial: 41578283867086692638256921589707938090 -# MD5 Fingerprint: 7c:62:ff:74:9d:31:53:5e:68:4a:d5:78:aa:1e:bf:23 -# SHA1 Fingerprint: 9f:74:4e:9f:2b:4d:ba:ec:0f:31:2c:50:b6:56:3b:8e:2d:93:c3:11 -# SHA256 Fingerprint: 17:93:92:7a:06:14:54:97:89:ad:ce:2f:8f:34:f7:f0:b6:6d:0f:3a:e3:a3:b8:4d:21:ec:15:db:ba:4f:ad:c7 ------BEGIN CERTIFICATE----- -MIICiTCCAg+gAwIBAgIQH0evqmIAcFBUTAGem2OZKjAKBggqhkjOPQQDAzCBhTEL -MAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UE -BxMHU2FsZm9yZDEaMBgGA1UEChMRQ09NT0RPIENBIExpbWl0ZWQxKzApBgNVBAMT -IkNPTU9ETyBFQ0MgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMDgwMzA2MDAw -MDAwWhcNMzgwMTE4MjM1OTU5WjCBhTELMAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdy -ZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEaMBgGA1UEChMRQ09N -T0RPIENBIExpbWl0ZWQxKzApBgNVBAMTIkNPTU9ETyBFQ0MgQ2VydGlmaWNhdGlv -biBBdXRob3JpdHkwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAAQDR3svdcmCFYX7deSR -FtSrYpn1PlILBs5BAH+X4QokPB0BBO490o0JlwzgdeT6+3eKKvUDYEs2ixYjFq0J -cfRK9ChQtP6IHG4/bC8vCVlbpVsLM5niwz2J+Wos77LTBumjQjBAMB0GA1UdDgQW -BBR1cacZSBm8nZ3qQUfflMRId5nTeTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/ -BAUwAwEB/zAKBggqhkjOPQQDAwNoADBlAjEA7wNbeqy3eApyt4jf/7VGFAkK+qDm -fQjGGoe9GKhzvSbKYAydzpmfz1wPMOG+FDHqAjAU9JM8SaczepBGR7NjfRObTrdv -GDeAU/7dIOA1mjbRxwG55tzd8/8dLDoWV9mSOdY= ------END CERTIFICATE----- - -# Issuer: O=Chunghwa Telecom Co., Ltd. OU=ePKI Root Certification Authority -# Subject: O=Chunghwa Telecom Co., Ltd. OU=ePKI Root Certification Authority -# Label: "ePKI Root Certification Authority" -# Serial: 28956088682735189655030529057352760477 -# MD5 Fingerprint: 1b:2e:00:ca:26:06:90:3d:ad:fe:6f:15:68:d3:6b:b3 -# SHA1 Fingerprint: 67:65:0d:f1:7e:8e:7e:5b:82:40:a4:f4:56:4b:cf:e2:3d:69:c6:f0 -# SHA256 Fingerprint: c0:a6:f4:dc:63:a2:4b:fd:cf:54:ef:2a:6a:08:2a:0a:72:de:35:80:3e:2f:f5:ff:52:7a:e5:d8:72:06:df:d5 ------BEGIN CERTIFICATE----- -MIIFsDCCA5igAwIBAgIQFci9ZUdcr7iXAF7kBtK8nTANBgkqhkiG9w0BAQUFADBe -MQswCQYDVQQGEwJUVzEjMCEGA1UECgwaQ2h1bmdod2EgVGVsZWNvbSBDby4sIEx0 -ZC4xKjAoBgNVBAsMIWVQS0kgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAe -Fw0wNDEyMjAwMjMxMjdaFw0zNDEyMjAwMjMxMjdaMF4xCzAJBgNVBAYTAlRXMSMw -IQYDVQQKDBpDaHVuZ2h3YSBUZWxlY29tIENvLiwgTHRkLjEqMCgGA1UECwwhZVBL -SSBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIICIjANBgkqhkiG9w0BAQEF -AAOCAg8AMIICCgKCAgEA4SUP7o3biDN1Z82tH306Tm2d0y8U82N0ywEhajfqhFAH -SyZbCUNsIZ5qyNUD9WBpj8zwIuQf5/dqIjG3LBXy4P4AakP/h2XGtRrBp0xtInAh -ijHyl3SJCRImHJ7K2RKilTza6We/CKBk49ZCt0Xvl/T29de1ShUCWH2YWEtgvM3X -DZoTM1PRYfl61dd4s5oz9wCGzh1NlDivqOx4UXCKXBCDUSH3ET00hl7lSM2XgYI1 -TBnsZfZrxQWh7kcT1rMhJ5QQCtkkO7q+RBNGMD+XPNjX12ruOzjjK9SXDrkb5wdJ -fzcq+Xd4z1TtW0ado4AOkUPB1ltfFLqfpo0kR0BZv3I4sjZsN/+Z0V0OWQqraffA -sgRFelQArr5T9rXn4fg8ozHSqf4hUmTFpmfwdQcGlBSBVcYn5AGPF8Fqcde+S/uU -WH1+ETOxQvdibBjWzwloPn9s9h6PYq2lY9sJpx8iQkEeb5mKPtf5P0B6ebClAZLS -nT0IFaUQAS2zMnaolQ2zepr7BxB4EW/hj8e6DyUadCrlHJhBmd8hh+iVBmoKs2pH -dmX2Os+PYhcZewoozRrSgx4hxyy/vv9haLdnG7t4TY3OZ+XkwY63I2binZB1NJip -NiuKmpS5nezMirH4JYlcWrYvjB9teSSnUmjDhDXiZo1jDiVN1Rmy5nk3pyKdVDEC -AwEAAaNqMGgwHQYDVR0OBBYEFB4M97Zn8uGSJglFwFU5Lnc/QkqiMAwGA1UdEwQF -MAMBAf8wOQYEZyoHAAQxMC8wLQIBADAJBgUrDgMCGgUAMAcGBWcqAwAABBRFsMLH -ClZ87lt4DJX5GFPBphzYEDANBgkqhkiG9w0BAQUFAAOCAgEACbODU1kBPpVJufGB -uvl2ICO1J2B01GqZNF5sAFPZn/KmsSQHRGoqxqWOeBLoR9lYGxMqXnmbnwoqZ6Yl -PwZpVnPDimZI+ymBV3QGypzqKOg4ZyYr8dW1P2WT+DZdjo2NQCCHGervJ8A9tDkP -JXtoUHRVnAxZfVo9QZQlUgjgRywVMRnVvwdVxrsStZf0X4OFunHB2WyBEXYKCrC/ -gpf36j36+uwtqSiUO1bd0lEursC9CBWMd1I0ltabrNMdjmEPNXubrjlpC2JgQCA2 -j6/7Nu4tCEoduL+bXPjqpRugc6bY+G7gMwRfaKonh+3ZwZCc7b3jajWvY9+rGNm6 -5ulK6lCKD2GTHuItGeIwlDWSXQ62B68ZgI9HkFFLLk3dheLSClIKF5r8GrBQAuUB -o2M3IUxExJtRmREOc5wGj1QupyheRDmHVi03vYVElOEMSyycw5KFNGHLD7ibSkNS -/jQ6fbjpKdx2qcgw+BRxgMYeNkh0IkFch4LoGHGLQYlE535YW6i4jRPpp2zDR+2z -Gp1iro2C6pSe3VkQw63d4k3jMdXH7OjysP6SHhYKGvzZ8/gntsm+HbRsZJB/9OTE -W9c3rkIO3aQab3yIVMUWbuF6aC74Or8NpDyJO3inTmODBCEIZ43ygknQW/2xzQ+D -hNQ+IIX3Sj0rnP0qCglN6oH4EZw= ------END CERTIFICATE----- - -# Issuer: CN=NetLock Arany (Class Gold) F\u0151tan\xfas\xedtv\xe1ny O=NetLock Kft. OU=Tan\xfas\xedtv\xe1nykiad\xf3k (Certification Services) -# Subject: CN=NetLock Arany (Class Gold) F\u0151tan\xfas\xedtv\xe1ny O=NetLock Kft. OU=Tan\xfas\xedtv\xe1nykiad\xf3k (Certification Services) -# Label: "NetLock Arany (Class Gold) F\u0151tan\xfas\xedtv\xe1ny" -# Serial: 80544274841616 -# MD5 Fingerprint: c5:a1:b7:ff:73:dd:d6:d7:34:32:18:df:fc:3c:ad:88 -# SHA1 Fingerprint: 06:08:3f:59:3f:15:a1:04:a0:69:a4:6b:a9:03:d0:06:b7:97:09:91 -# SHA256 Fingerprint: 6c:61:da:c3:a2:de:f0:31:50:6b:e0:36:d2:a6:fe:40:19:94:fb:d1:3d:f9:c8:d4:66:59:92:74:c4:46:ec:98 ------BEGIN CERTIFICATE----- -MIIEFTCCAv2gAwIBAgIGSUEs5AAQMA0GCSqGSIb3DQEBCwUAMIGnMQswCQYDVQQG -EwJIVTERMA8GA1UEBwwIQnVkYXBlc3QxFTATBgNVBAoMDE5ldExvY2sgS2Z0LjE3 -MDUGA1UECwwuVGFuw7pzw610dsOhbnlraWFkw7NrIChDZXJ0aWZpY2F0aW9uIFNl -cnZpY2VzKTE1MDMGA1UEAwwsTmV0TG9jayBBcmFueSAoQ2xhc3MgR29sZCkgRsWR -dGFuw7pzw610dsOhbnkwHhcNMDgxMjExMTUwODIxWhcNMjgxMjA2MTUwODIxWjCB -pzELMAkGA1UEBhMCSFUxETAPBgNVBAcMCEJ1ZGFwZXN0MRUwEwYDVQQKDAxOZXRM -b2NrIEtmdC4xNzA1BgNVBAsMLlRhbsO6c8OtdHbDoW55a2lhZMOzayAoQ2VydGlm -aWNhdGlvbiBTZXJ2aWNlcykxNTAzBgNVBAMMLE5ldExvY2sgQXJhbnkgKENsYXNz -IEdvbGQpIEbFkXRhbsO6c8OtdHbDoW55MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A -MIIBCgKCAQEAxCRec75LbRTDofTjl5Bu0jBFHjzuZ9lk4BqKf8owyoPjIMHj9DrT -lF8afFttvzBPhCf2nx9JvMaZCpDyD/V/Q4Q3Y1GLeqVw/HpYzY6b7cNGbIRwXdrz -AZAj/E4wqX7hJ2Pn7WQ8oLjJM2P+FpD/sLj916jAwJRDC7bVWaaeVtAkH3B5r9s5 -VA1lddkVQZQBr17s9o3x/61k/iCa11zr/qYfCGSji3ZVrR47KGAuhyXoqq8fxmRG -ILdwfzzeSNuWU7c5d+Qa4scWhHaXWy+7GRWF+GmF9ZmnqfI0p6m2pgP8b4Y9VHx2 -BJtr+UBdADTHLpl1neWIA6pN+APSQnbAGwIDAKiLo0UwQzASBgNVHRMBAf8ECDAG -AQH/AgEEMA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUzPpnk/C2uNClwB7zU/2M -U9+D15YwDQYJKoZIhvcNAQELBQADggEBAKt/7hwWqZw8UQCgwBEIBaeZ5m8BiFRh -bvG5GK1Krf6BQCOUL/t1fC8oS2IkgYIL9WHxHG64YTjrgfpioTtaYtOUZcTh5m2C -+C8lcLIhJsFyUR+MLMOEkMNaj7rP9KdlpeuY0fsFskZ1FSNqb4VjMIDw1Z4fKRzC -bLBQWV2QWzuoDTDPv31/zvGdg73JRm4gpvlhUbohL3u+pRVjodSVh/GeufOJ8z2F -uLjbvrW5KfnaNwUASZQDhETnv0Mxz3WLJdH0pmT1kvarBes96aULNmLazAZfNou2 -XjG4Kvte9nHfRCaexOYNkbQudZWAUWpLMKawYqGT8ZvYzsRjdT9ZR7E= ------END CERTIFICATE----- - -# Issuer: CN=Microsec e-Szigno Root CA 2009 O=Microsec Ltd. -# Subject: CN=Microsec e-Szigno Root CA 2009 O=Microsec Ltd. -# Label: "Microsec e-Szigno Root CA 2009" -# Serial: 14014712776195784473 -# MD5 Fingerprint: f8:49:f4:03:bc:44:2d:83:be:48:69:7d:29:64:fc:b1 -# SHA1 Fingerprint: 89:df:74:fe:5c:f4:0f:4a:80:f9:e3:37:7d:54:da:91:e1:01:31:8e -# SHA256 Fingerprint: 3c:5f:81:fe:a5:fa:b8:2c:64:bf:a2:ea:ec:af:cd:e8:e0:77:fc:86:20:a7:ca:e5:37:16:3d:f3:6e:db:f3:78 ------BEGIN CERTIFICATE----- -MIIECjCCAvKgAwIBAgIJAMJ+QwRORz8ZMA0GCSqGSIb3DQEBCwUAMIGCMQswCQYD -VQQGEwJIVTERMA8GA1UEBwwIQnVkYXBlc3QxFjAUBgNVBAoMDU1pY3Jvc2VjIEx0 -ZC4xJzAlBgNVBAMMHk1pY3Jvc2VjIGUtU3ppZ25vIFJvb3QgQ0EgMjAwOTEfMB0G -CSqGSIb3DQEJARYQaW5mb0BlLXN6aWduby5odTAeFw0wOTA2MTYxMTMwMThaFw0y -OTEyMzAxMTMwMThaMIGCMQswCQYDVQQGEwJIVTERMA8GA1UEBwwIQnVkYXBlc3Qx -FjAUBgNVBAoMDU1pY3Jvc2VjIEx0ZC4xJzAlBgNVBAMMHk1pY3Jvc2VjIGUtU3pp -Z25vIFJvb3QgQ0EgMjAwOTEfMB0GCSqGSIb3DQEJARYQaW5mb0BlLXN6aWduby5o -dTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAOn4j/NjrdqG2KfgQvvP -kd6mJviZpWNwrZuuyjNAfW2WbqEORO7hE52UQlKavXWFdCyoDh2Tthi3jCyoz/tc -cbna7P7ofo/kLx2yqHWH2Leh5TvPmUpG0IMZfcChEhyVbUr02MelTTMuhTlAdX4U -fIASmFDHQWe4oIBhVKZsTh/gnQ4H6cm6M+f+wFUoLAKApxn1ntxVUwOXewdI/5n7 -N4okxFnMUBBjjqqpGrCEGob5X7uxUG6k0QrM1XF+H6cbfPVTbiJfyyvm1HxdrtbC -xkzlBQHZ7Vf8wSN5/PrIJIOV87VqUQHQd9bpEqH5GoP7ghu5sJf0dgYzQ0mg/wu1 -+rUCAwEAAaOBgDB+MA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0G -A1UdDgQWBBTLD8bfQkPMPcu1SCOhGnqmKrs0aDAfBgNVHSMEGDAWgBTLD8bfQkPM -Pcu1SCOhGnqmKrs0aDAbBgNVHREEFDASgRBpbmZvQGUtc3ppZ25vLmh1MA0GCSqG -SIb3DQEBCwUAA4IBAQDJ0Q5eLtXMs3w+y/w9/w0olZMEyL/azXm4Q5DwpL7v8u8h -mLzU1F0G9u5C7DBsoKqpyvGvivo/C3NqPuouQH4frlRheesuCDfXI/OMn74dseGk -ddug4lQUsbocKaQY9hK6ohQU4zE1yED/t+AFdlfBHFny+L/k7SViXITwfn4fs775 -tyERzAMBVnCnEJIeGzSBHq2cGsMEPO0CYdYeBvNfOofyK/FFh+U9rNHHV4S9a67c -2Pm2G2JwCz02yULyMtd6YebS2z3PyKnJm9zbWETXbzivf3jTo60adbocwTZ8jx5t -HMN1Rq41Bab2XD0h7lbwyYIiLXpUq3DDfSJlgnCW ------END CERTIFICATE----- - -# Issuer: CN=GlobalSign O=GlobalSign OU=GlobalSign Root CA - R3 -# Subject: CN=GlobalSign O=GlobalSign OU=GlobalSign Root CA - R3 -# Label: "GlobalSign Root CA - R3" -# Serial: 4835703278459759426209954 -# MD5 Fingerprint: c5:df:b8:49:ca:05:13:55:ee:2d:ba:1a:c3:3e:b0:28 -# SHA1 Fingerprint: d6:9b:56:11:48:f0:1c:77:c5:45:78:c1:09:26:df:5b:85:69:76:ad -# SHA256 Fingerprint: cb:b5:22:d7:b7:f1:27:ad:6a:01:13:86:5b:df:1c:d4:10:2e:7d:07:59:af:63:5a:7c:f4:72:0d:c9:63:c5:3b ------BEGIN CERTIFICATE----- -MIIDXzCCAkegAwIBAgILBAAAAAABIVhTCKIwDQYJKoZIhvcNAQELBQAwTDEgMB4G -A1UECxMXR2xvYmFsU2lnbiBSb290IENBIC0gUjMxEzARBgNVBAoTCkdsb2JhbFNp -Z24xEzARBgNVBAMTCkdsb2JhbFNpZ24wHhcNMDkwMzE4MTAwMDAwWhcNMjkwMzE4 -MTAwMDAwWjBMMSAwHgYDVQQLExdHbG9iYWxTaWduIFJvb3QgQ0EgLSBSMzETMBEG -A1UEChMKR2xvYmFsU2lnbjETMBEGA1UEAxMKR2xvYmFsU2lnbjCCASIwDQYJKoZI -hvcNAQEBBQADggEPADCCAQoCggEBAMwldpB5BngiFvXAg7aEyiie/QV2EcWtiHL8 -RgJDx7KKnQRfJMsuS+FggkbhUqsMgUdwbN1k0ev1LKMPgj0MK66X17YUhhB5uzsT -gHeMCOFJ0mpiLx9e+pZo34knlTifBtc+ycsmWQ1z3rDI6SYOgxXG71uL0gRgykmm -KPZpO/bLyCiR5Z2KYVc3rHQU3HTgOu5yLy6c+9C7v/U9AOEGM+iCK65TpjoWc4zd -QQ4gOsC0p6Hpsk+QLjJg6VfLuQSSaGjlOCZgdbKfd/+RFO+uIEn8rUAVSNECMWEZ -XriX7613t2Saer9fwRPvm2L7DWzgVGkWqQPabumDk3F2xmmFghcCAwEAAaNCMEAw -DgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFI/wS3+o -LkUkrk1Q+mOai97i3Ru8MA0GCSqGSIb3DQEBCwUAA4IBAQBLQNvAUKr+yAzv95ZU -RUm7lgAJQayzE4aGKAczymvmdLm6AC2upArT9fHxD4q/c2dKg8dEe3jgr25sbwMp -jjM5RcOO5LlXbKr8EpbsU8Yt5CRsuZRj+9xTaGdWPoO4zzUhw8lo/s7awlOqzJCK -6fBdRoyV3XpYKBovHd7NADdBj+1EbddTKJd+82cEHhXXipa0095MJ6RMG3NzdvQX -mcIfeg7jLQitChws/zyrVQ4PkX4268NXSb7hLi18YIvDQVETI53O9zJrlAGomecs -Mx86OyXShkDOOyyGeMlhLxS67ttVb9+E7gUJTb0o2HLO02JQZR7rkpeDMdmztcpH -WD9f ------END CERTIFICATE----- - -# Issuer: CN=Izenpe.com O=IZENPE S.A. -# Subject: CN=Izenpe.com O=IZENPE S.A. -# Label: "Izenpe.com" -# Serial: 917563065490389241595536686991402621 -# MD5 Fingerprint: a6:b0:cd:85:80:da:5c:50:34:a3:39:90:2f:55:67:73 -# SHA1 Fingerprint: 2f:78:3d:25:52:18:a7:4a:65:39:71:b5:2c:a2:9c:45:15:6f:e9:19 -# SHA256 Fingerprint: 25:30:cc:8e:98:32:15:02:ba:d9:6f:9b:1f:ba:1b:09:9e:2d:29:9e:0f:45:48:bb:91:4f:36:3b:c0:d4:53:1f ------BEGIN CERTIFICATE----- -MIIF8TCCA9mgAwIBAgIQALC3WhZIX7/hy/WL1xnmfTANBgkqhkiG9w0BAQsFADA4 -MQswCQYDVQQGEwJFUzEUMBIGA1UECgwLSVpFTlBFIFMuQS4xEzARBgNVBAMMCkl6 -ZW5wZS5jb20wHhcNMDcxMjEzMTMwODI4WhcNMzcxMjEzMDgyNzI1WjA4MQswCQYD -VQQGEwJFUzEUMBIGA1UECgwLSVpFTlBFIFMuQS4xEzARBgNVBAMMCkl6ZW5wZS5j -b20wggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDJ03rKDx6sp4boFmVq -scIbRTJxldn+EFvMr+eleQGPicPK8lVx93e+d5TzcqQsRNiekpsUOqHnJJAKClaO -xdgmlOHZSOEtPtoKct2jmRXagaKH9HtuJneJWK3W6wyyQXpzbm3benhB6QiIEn6H -LmYRY2xU+zydcsC8Lv/Ct90NduM61/e0aL6i9eOBbsFGb12N4E3GVFWJGjMxCrFX -uaOKmMPsOzTFlUFpfnXCPCDFYbpRR6AgkJOhkEvzTnyFRVSa0QUmQbC1TR0zvsQD -yCV8wXDbO/QJLVQnSKwv4cSsPsjLkkxTOTcj7NMB+eAJRE1NZMDhDVqHIrytG6P+ -JrUV86f8hBnp7KGItERphIPzidF0BqnMC9bC3ieFUCbKF7jJeodWLBoBHmy+E60Q -rLUk9TiRodZL2vG70t5HtfG8gfZZa88ZU+mNFctKy6lvROUbQc/hhqfK0GqfvEyN -BjNaooXlkDWgYlwWTvDjovoDGrQscbNYLN57C9saD+veIR8GdwYDsMnvmfzAuU8L -hij+0rnq49qlw0dpEuDb8PYZi+17cNcC1u2HGCgsBCRMd+RIihrGO5rUD8r6ddIB -QFqNeb+Lz0vPqhbBleStTIo+F5HUsWLlguWABKQDfo2/2n+iD5dPDNMN+9fR5XJ+ -HMh3/1uaD7euBUbl8agW7EekFwIDAQABo4H2MIHzMIGwBgNVHREEgagwgaWBD2lu -Zm9AaXplbnBlLmNvbaSBkTCBjjFHMEUGA1UECgw+SVpFTlBFIFMuQS4gLSBDSUYg -QTAxMzM3MjYwLVJNZXJjLlZpdG9yaWEtR2FzdGVpeiBUMTA1NSBGNjIgUzgxQzBB -BgNVBAkMOkF2ZGEgZGVsIE1lZGl0ZXJyYW5lbyBFdG9yYmlkZWEgMTQgLSAwMTAx -MCBWaXRvcmlhLUdhc3RlaXowDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMC -AQYwHQYDVR0OBBYEFB0cZQ6o8iV7tJHP5LGx5r1VdGwFMA0GCSqGSIb3DQEBCwUA -A4ICAQB4pgwWSp9MiDrAyw6lFn2fuUhfGI8NYjb2zRlrrKvV9pF9rnHzP7MOeIWb -laQnIUdCSnxIOvVFfLMMjlF4rJUT3sb9fbgakEyrkgPH7UIBzg/YsfqikuFgba56 -awmqxinuaElnMIAkejEWOVt+8Rwu3WwJrfIxwYJOubv5vr8qhT/AQKM6WfxZSzwo -JNu0FXWuDYi6LnPAvViH5ULy617uHjAimcs30cQhbIHsvm0m5hzkQiCeR7Csg1lw -LDXWrzY0tM07+DKo7+N4ifuNRSzanLh+QBxh5z6ikixL8s36mLYp//Pye6kfLqCT -VyvehQP5aTfLnnhqBbTFMXiJ7HqnheG5ezzevh55hM6fcA5ZwjUukCox2eRFekGk -LhObNA5me0mrZJfQRsN5nXJQY6aYWwa9SG3YOYNw6DXwBdGqvOPbyALqfP2C2sJb -UjWumDqtujWTI6cfSN01RpiyEGjkpTHCClguGYEQyVB1/OpaFs4R1+7vUIgtYf8/ -QnMFlEPVjjxOAToZpR9GTnfQXeWBIiGH/pR9hNiTrdZoQ0iy2+tzJOeRf1SktoA+ -naM8THLCV8Sg1Mw4J87VBp6iSNnpn86CcDaTmjvfliHjWbcM2pE38P1ZWrOZyGls -QyYBNWNgVYkDOnXYukrZVP/u3oDYLdE41V4tC5h9Pmzb/CaIxw== ------END CERTIFICATE----- - -# Issuer: CN=Go Daddy Root Certificate Authority - G2 O=GoDaddy.com, Inc. -# Subject: CN=Go Daddy Root Certificate Authority - G2 O=GoDaddy.com, Inc. -# Label: "Go Daddy Root Certificate Authority - G2" -# Serial: 0 -# MD5 Fingerprint: 80:3a:bc:22:c1:e6:fb:8d:9b:3b:27:4a:32:1b:9a:01 -# SHA1 Fingerprint: 47:be:ab:c9:22:ea:e8:0e:78:78:34:62:a7:9f:45:c2:54:fd:e6:8b -# SHA256 Fingerprint: 45:14:0b:32:47:eb:9c:c8:c5:b4:f0:d7:b5:30:91:f7:32:92:08:9e:6e:5a:63:e2:74:9d:d3:ac:a9:19:8e:da ------BEGIN CERTIFICATE----- -MIIDxTCCAq2gAwIBAgIBADANBgkqhkiG9w0BAQsFADCBgzELMAkGA1UEBhMCVVMx -EDAOBgNVBAgTB0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxGjAYBgNVBAoT -EUdvRGFkZHkuY29tLCBJbmMuMTEwLwYDVQQDEyhHbyBEYWRkeSBSb290IENlcnRp -ZmljYXRlIEF1dGhvcml0eSAtIEcyMB4XDTA5MDkwMTAwMDAwMFoXDTM3MTIzMTIz -NTk1OVowgYMxCzAJBgNVBAYTAlVTMRAwDgYDVQQIEwdBcml6b25hMRMwEQYDVQQH -EwpTY290dHNkYWxlMRowGAYDVQQKExFHb0RhZGR5LmNvbSwgSW5jLjExMC8GA1UE -AxMoR28gRGFkZHkgUm9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkgLSBHMjCCASIw -DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAL9xYgjx+lk09xvJGKP3gElY6SKD -E6bFIEMBO4Tx5oVJnyfq9oQbTqC023CYxzIBsQU+B07u9PpPL1kwIuerGVZr4oAH -/PMWdYA5UXvl+TW2dE6pjYIT5LY/qQOD+qK+ihVqf94Lw7YZFAXK6sOoBJQ7Rnwy -DfMAZiLIjWltNowRGLfTshxgtDj6AozO091GB94KPutdfMh8+7ArU6SSYmlRJQVh -GkSBjCypQ5Yj36w6gZoOKcUcqeldHraenjAKOc7xiID7S13MMuyFYkMlNAJWJwGR -tDtwKj9useiciAF9n9T521NtYJ2/LOdYq7hfRvzOxBsDPAnrSTFcaUaz4EcCAwEA -AaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYE -FDqahQcQZyi27/a9BUFuIMGU2g/eMA0GCSqGSIb3DQEBCwUAA4IBAQCZ21151fmX -WWcDYfF+OwYxdS2hII5PZYe096acvNjpL9DbWu7PdIxztDhC2gV7+AJ1uP2lsdeu -9tfeE8tTEH6KRtGX+rcuKxGrkLAngPnon1rpN5+r5N9ss4UXnT3ZJE95kTXWXwTr -gIOrmgIttRD02JDHBHNA7XIloKmf7J6raBKZV8aPEjoJpL1E/QYVN8Gb5DKj7Tjo -2GTzLH4U/ALqn83/B2gX2yKQOC16jdFU8WnjXzPKej17CuPKf1855eJ1usV2GDPO -LPAvTK33sefOT6jEm0pUBsV/fdUID+Ic/n4XuKxe9tQWskMJDE32p2u0mYRlynqI -4uJEvlz36hz1 ------END CERTIFICATE----- - -# Issuer: CN=Starfield Root Certificate Authority - G2 O=Starfield Technologies, Inc. -# Subject: CN=Starfield Root Certificate Authority - G2 O=Starfield Technologies, Inc. -# Label: "Starfield Root Certificate Authority - G2" -# Serial: 0 -# MD5 Fingerprint: d6:39:81:c6:52:7e:96:69:fc:fc:ca:66:ed:05:f2:96 -# SHA1 Fingerprint: b5:1c:06:7c:ee:2b:0c:3d:f8:55:ab:2d:92:f4:fe:39:d4:e7:0f:0e -# SHA256 Fingerprint: 2c:e1:cb:0b:f9:d2:f9:e1:02:99:3f:be:21:51:52:c3:b2:dd:0c:ab:de:1c:68:e5:31:9b:83:91:54:db:b7:f5 ------BEGIN CERTIFICATE----- -MIID3TCCAsWgAwIBAgIBADANBgkqhkiG9w0BAQsFADCBjzELMAkGA1UEBhMCVVMx -EDAOBgNVBAgTB0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxJTAjBgNVBAoT -HFN0YXJmaWVsZCBUZWNobm9sb2dpZXMsIEluYy4xMjAwBgNVBAMTKVN0YXJmaWVs -ZCBSb290IENlcnRpZmljYXRlIEF1dGhvcml0eSAtIEcyMB4XDTA5MDkwMTAwMDAw -MFoXDTM3MTIzMTIzNTk1OVowgY8xCzAJBgNVBAYTAlVTMRAwDgYDVQQIEwdBcml6 -b25hMRMwEQYDVQQHEwpTY290dHNkYWxlMSUwIwYDVQQKExxTdGFyZmllbGQgVGVj -aG5vbG9naWVzLCBJbmMuMTIwMAYDVQQDEylTdGFyZmllbGQgUm9vdCBDZXJ0aWZp -Y2F0ZSBBdXRob3JpdHkgLSBHMjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC -ggEBAL3twQP89o/8ArFvW59I2Z154qK3A2FWGMNHttfKPTUuiUP3oWmb3ooa/RMg -nLRJdzIpVv257IzdIvpy3Cdhl+72WoTsbhm5iSzchFvVdPtrX8WJpRBSiUZV9Lh1 -HOZ/5FSuS/hVclcCGfgXcVnrHigHdMWdSL5stPSksPNkN3mSwOxGXn/hbVNMYq/N -Hwtjuzqd+/x5AJhhdM8mgkBj87JyahkNmcrUDnXMN/uLicFZ8WJ/X7NfZTD4p7dN -dloedl40wOiWVpmKs/B/pM293DIxfJHP4F8R+GuqSVzRmZTRouNjWwl2tVZi4Ut0 -HZbUJtQIBFnQmA4O5t78w+wfkPECAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAO -BgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFHwMMh+n2TB/xH1oo2Kooc6rB1snMA0G -CSqGSIb3DQEBCwUAA4IBAQARWfolTwNvlJk7mh+ChTnUdgWUXuEok21iXQnCoKjU -sHU48TRqneSfioYmUeYs0cYtbpUgSpIB7LiKZ3sx4mcujJUDJi5DnUox9g61DLu3 -4jd/IroAow57UvtruzvE03lRTs2Q9GcHGcg8RnoNAX3FWOdt5oUwF5okxBDgBPfg -8n/Uqgr/Qh037ZTlZFkSIHc40zI+OIF1lnP6aI+xy84fxez6nH7PfrHxBy22/L/K -pL/QlwVKvOoYKAKQvVR4CSFx09F9HdkWsKlhPdAKACL8x3vLCWRFCztAgfd9fDL1 -mMpYjn0q7pBZc2T5NnReJaH1ZgUufzkVqSr7UIuOhWn0 ------END CERTIFICATE----- - -# Issuer: CN=Starfield Services Root Certificate Authority - G2 O=Starfield Technologies, Inc. -# Subject: CN=Starfield Services Root Certificate Authority - G2 O=Starfield Technologies, Inc. -# Label: "Starfield Services Root Certificate Authority - G2" -# Serial: 0 -# MD5 Fingerprint: 17:35:74:af:7b:61:1c:eb:f4:f9:3c:e2:ee:40:f9:a2 -# SHA1 Fingerprint: 92:5a:8f:8d:2c:6d:04:e0:66:5f:59:6a:ff:22:d8:63:e8:25:6f:3f -# SHA256 Fingerprint: 56:8d:69:05:a2:c8:87:08:a4:b3:02:51:90:ed:cf:ed:b1:97:4a:60:6a:13:c6:e5:29:0f:cb:2a:e6:3e:da:b5 ------BEGIN CERTIFICATE----- -MIID7zCCAtegAwIBAgIBADANBgkqhkiG9w0BAQsFADCBmDELMAkGA1UEBhMCVVMx -EDAOBgNVBAgTB0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxJTAjBgNVBAoT -HFN0YXJmaWVsZCBUZWNobm9sb2dpZXMsIEluYy4xOzA5BgNVBAMTMlN0YXJmaWVs -ZCBTZXJ2aWNlcyBSb290IENlcnRpZmljYXRlIEF1dGhvcml0eSAtIEcyMB4XDTA5 -MDkwMTAwMDAwMFoXDTM3MTIzMTIzNTk1OVowgZgxCzAJBgNVBAYTAlVTMRAwDgYD -VQQIEwdBcml6b25hMRMwEQYDVQQHEwpTY290dHNkYWxlMSUwIwYDVQQKExxTdGFy -ZmllbGQgVGVjaG5vbG9naWVzLCBJbmMuMTswOQYDVQQDEzJTdGFyZmllbGQgU2Vy -dmljZXMgUm9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkgLSBHMjCCASIwDQYJKoZI -hvcNAQEBBQADggEPADCCAQoCggEBANUMOsQq+U7i9b4Zl1+OiFOxHz/Lz58gE20p -OsgPfTz3a3Y4Y9k2YKibXlwAgLIvWX/2h/klQ4bnaRtSmpDhcePYLQ1Ob/bISdm2 -8xpWriu2dBTrz/sm4xq6HZYuajtYlIlHVv8loJNwU4PahHQUw2eeBGg6345AWh1K -Ts9DkTvnVtYAcMtS7nt9rjrnvDH5RfbCYM8TWQIrgMw0R9+53pBlbQLPLJGmpufe -hRhJfGZOozptqbXuNC66DQO4M99H67FrjSXZm86B0UVGMpZwh94CDklDhbZsc7tk -6mFBrMnUVN+HL8cisibMn1lUaJ/8viovxFUcdUBgF4UCVTmLfwUCAwEAAaNCMEAw -DwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFJxfAN+q -AdcwKziIorhtSpzyEZGDMA0GCSqGSIb3DQEBCwUAA4IBAQBLNqaEd2ndOxmfZyMI -bw5hyf2E3F/YNoHN2BtBLZ9g3ccaaNnRbobhiCPPE95Dz+I0swSdHynVv/heyNXB -ve6SbzJ08pGCL72CQnqtKrcgfU28elUSwhXqvfdqlS5sdJ/PHLTyxQGjhdByPq1z -qwubdQxtRbeOlKyWN7Wg0I8VRw7j6IPdj/3vQQF3zCepYoUz8jcI73HPdwbeyBkd -iEDPfUYd/x7H4c7/I9vG+o1VTqkC50cRRj70/b17KSa7qWFiNyi2LSr2EIZkyXCn -0q23KXB56jzaYyWf/Wi3MOxw+3WKt21gZ7IeyLnp2KhvAotnDU0mV3HaIPzBSlCN -sSi6 ------END CERTIFICATE----- - -# Issuer: CN=Certum Trusted Network CA O=Unizeto Technologies S.A. OU=Certum Certification Authority -# Subject: CN=Certum Trusted Network CA O=Unizeto Technologies S.A. OU=Certum Certification Authority -# Label: "Certum Trusted Network CA" -# Serial: 279744 -# MD5 Fingerprint: d5:e9:81:40:c5:18:69:fc:46:2c:89:75:62:0f:aa:78 -# SHA1 Fingerprint: 07:e0:32:e0:20:b7:2c:3f:19:2f:06:28:a2:59:3a:19:a7:0f:06:9e -# SHA256 Fingerprint: 5c:58:46:8d:55:f5:8e:49:7e:74:39:82:d2:b5:00:10:b6:d1:65:37:4a:cf:83:a7:d4:a3:2d:b7:68:c4:40:8e ------BEGIN CERTIFICATE----- -MIIDuzCCAqOgAwIBAgIDBETAMA0GCSqGSIb3DQEBBQUAMH4xCzAJBgNVBAYTAlBM -MSIwIAYDVQQKExlVbml6ZXRvIFRlY2hub2xvZ2llcyBTLkEuMScwJQYDVQQLEx5D -ZXJ0dW0gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxIjAgBgNVBAMTGUNlcnR1bSBU -cnVzdGVkIE5ldHdvcmsgQ0EwHhcNMDgxMDIyMTIwNzM3WhcNMjkxMjMxMTIwNzM3 -WjB+MQswCQYDVQQGEwJQTDEiMCAGA1UEChMZVW5pemV0byBUZWNobm9sb2dpZXMg -Uy5BLjEnMCUGA1UECxMeQ2VydHVtIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MSIw -IAYDVQQDExlDZXJ0dW0gVHJ1c3RlZCBOZXR3b3JrIENBMIIBIjANBgkqhkiG9w0B -AQEFAAOCAQ8AMIIBCgKCAQEA4/t9o3K6wvDJFIf1awFO4W5AB7ptJ11/91sts1rH -UV+rpDKmYYe2bg+G0jACl/jXaVehGDldamR5xgFZrDwxSjh80gTSSyjoIF87B6LM -TXPb865Px1bVWqeWifrzq2jUI4ZZJ88JJ7ysbnKDHDBy3+Ci6dLhdHUZvSqeexVU -BBvXQzmtVSjF4hq79MDkrjhJM8x2hZ85RdKknvISjFH4fOQtf/WsX+sWn7Et0brM -kUJ3TCXJkDhv2/DM+44el1k+1WBO5gUo7Ul5E0u6SNsv+XLTOcr+H9g0cvW0QM8x -AcPs3hEtF10fuFDRXhmnad4HMyjKUJX5p1TLVIZQRan5SQIDAQABo0IwQDAPBgNV -HRMBAf8EBTADAQH/MB0GA1UdDgQWBBQIds3LB/8k9sXN7buQvOKEN0Z19zAOBgNV -HQ8BAf8EBAMCAQYwDQYJKoZIhvcNAQEFBQADggEBAKaorSLOAT2mo/9i0Eidi15y -sHhE49wcrwn9I0j6vSrEuVUEtRCjjSfeC4Jj0O7eDDd5QVsisrCaQVymcODU0HfL -I9MA4GxWL+FpDQ3Zqr8hgVDZBqWo/5U30Kr+4rP1mS1FhIrlQgnXdAIv94nYmem8 -J9RHjboNRhx3zxSkHLmkMcScKHQDNP8zGSal6Q10tz6XxnboJ5ajZt3hrvJBW8qY -VoNzcOSGGtIxQbovvi0TWnZvTuhOgQ4/WwMioBK+ZlgRSssDxLQqKi2WF+A5VLxI -03YnnZotBqbJ7DnSq9ufmgsnAjUpsUCV5/nonFWIGUbWtzT1fs45mtk48VH3Tyw= ------END CERTIFICATE----- - -# Issuer: CN=TWCA Root Certification Authority O=TAIWAN-CA OU=Root CA -# Subject: CN=TWCA Root Certification Authority O=TAIWAN-CA OU=Root CA -# Label: "TWCA Root Certification Authority" -# Serial: 1 -# MD5 Fingerprint: aa:08:8f:f6:f9:7b:b7:f2:b1:a7:1e:9b:ea:ea:bd:79 -# SHA1 Fingerprint: cf:9e:87:6d:d3:eb:fc:42:26:97:a3:b5:a3:7a:a0:76:a9:06:23:48 -# SHA256 Fingerprint: bf:d8:8f:e1:10:1c:41:ae:3e:80:1b:f8:be:56:35:0e:e9:ba:d1:a6:b9:bd:51:5e:dc:5c:6d:5b:87:11:ac:44 ------BEGIN CERTIFICATE----- -MIIDezCCAmOgAwIBAgIBATANBgkqhkiG9w0BAQUFADBfMQswCQYDVQQGEwJUVzES -MBAGA1UECgwJVEFJV0FOLUNBMRAwDgYDVQQLDAdSb290IENBMSowKAYDVQQDDCFU -V0NBIFJvb3QgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMDgwODI4MDcyNDMz -WhcNMzAxMjMxMTU1OTU5WjBfMQswCQYDVQQGEwJUVzESMBAGA1UECgwJVEFJV0FO -LUNBMRAwDgYDVQQLDAdSb290IENBMSowKAYDVQQDDCFUV0NBIFJvb3QgQ2VydGlm -aWNhdGlvbiBBdXRob3JpdHkwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIB -AQCwfnK4pAOU5qfeCTiRShFAh6d8WWQUe7UREN3+v9XAu1bihSX0NXIP+FPQQeFE -AcK0HMMxQhZHhTMidrIKbw/lJVBPhYa+v5guEGcevhEFhgWQxFnQfHgQsIBct+HH -K3XLfJ+utdGdIzdjp9xCoi2SBBtQwXu4PhvJVgSLL1KbralW6cH/ralYhzC2gfeX -RfwZVzsrb+RH9JlF/h3x+JejiB03HFyP4HYlmlD4oFT/RJB2I9IyxsOrBr/8+7/z -rX2SYgJbKdM1o5OaQ2RgXbL6Mv87BK9NQGr5x+PvI/1ry+UPizgN7gr8/g+YnzAx -3WxSZfmLgb4i4RxYA7qRG4kHAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNV -HRMBAf8EBTADAQH/MB0GA1UdDgQWBBRqOFsmjd6LWvJPelSDGRjjCDWmujANBgkq -hkiG9w0BAQUFAAOCAQEAPNV3PdrfibqHDAhUaiBQkr6wQT25JmSDCi/oQMCXKCeC -MErJk/9q56YAf4lCmtYR5VPOL8zy2gXE/uJQxDqGfczafhAJO5I1KlOy/usrBdls -XebQ79NqZp4VKIV66IIArB6nCWlWQtNoURi+VJq/REG6Sb4gumlc7rh3zc5sH62D -lhh9DrUUOYTxKOkto557HnpyWoOzeW/vtPzQCqVYT0bf+215WfKEIlKuD8z7fDvn -aspHYcN6+NOSBB+4IIThNlQWx0DeO4pz3N/GCUzf7Nr/1FNCocnyYh0igzyXxfkZ -YiesZSLX0zzG5Y6yU8xJzrww/nsOM5D77dIUkR8Hrw== ------END CERTIFICATE----- - -# Issuer: O=SECOM Trust Systems CO.,LTD. OU=Security Communication RootCA2 -# Subject: O=SECOM Trust Systems CO.,LTD. OU=Security Communication RootCA2 -# Label: "Security Communication RootCA2" -# Serial: 0 -# MD5 Fingerprint: 6c:39:7d:a4:0e:55:59:b2:3f:d6:41:b1:12:50:de:43 -# SHA1 Fingerprint: 5f:3b:8c:f2:f8:10:b3:7d:78:b4:ce:ec:19:19:c3:73:34:b9:c7:74 -# SHA256 Fingerprint: 51:3b:2c:ec:b8:10:d4:cd:e5:dd:85:39:1a:df:c6:c2:dd:60:d8:7b:b7:36:d2:b5:21:48:4a:a4:7a:0e:be:f6 ------BEGIN CERTIFICATE----- -MIIDdzCCAl+gAwIBAgIBADANBgkqhkiG9w0BAQsFADBdMQswCQYDVQQGEwJKUDEl -MCMGA1UEChMcU0VDT00gVHJ1c3QgU3lzdGVtcyBDTy4sTFRELjEnMCUGA1UECxMe -U2VjdXJpdHkgQ29tbXVuaWNhdGlvbiBSb290Q0EyMB4XDTA5MDUyOTA1MDAzOVoX -DTI5MDUyOTA1MDAzOVowXTELMAkGA1UEBhMCSlAxJTAjBgNVBAoTHFNFQ09NIFRy -dXN0IFN5c3RlbXMgQ08uLExURC4xJzAlBgNVBAsTHlNlY3VyaXR5IENvbW11bmlj -YXRpb24gUm9vdENBMjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANAV -OVKxUrO6xVmCxF1SrjpDZYBLx/KWvNs2l9amZIyoXvDjChz335c9S672XewhtUGr -zbl+dp+++T42NKA7wfYxEUV0kz1XgMX5iZnK5atq1LXaQZAQwdbWQonCv/Q4EpVM -VAX3NuRFg3sUZdbcDE3R3n4MqzvEFb46VqZab3ZpUql6ucjrappdUtAtCms1FgkQ -hNBqyjoGADdH5H5XTz+L62e4iKrFvlNVspHEfbmwhRkGeC7bYRr6hfVKkaHnFtWO -ojnflLhwHyg/i/xAXmODPIMqGplrz95Zajv8bxbXH/1KEOtOghY6rCcMU/Gt1SSw -awNQwS08Ft1ENCcadfsCAwEAAaNCMEAwHQYDVR0OBBYEFAqFqXdlBZh8QIH4D5cs -OPEK7DzPMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3 -DQEBCwUAA4IBAQBMOqNErLlFsceTfsgLCkLfZOoc7llsCLqJX2rKSpWeeo8HxdpF -coJxDjrSzG+ntKEju/Ykn8sX/oymzsLS28yN/HH8AynBbF0zX2S2ZTuJbxh2ePXc -okgfGT+Ok+vx+hfuzU7jBBJV1uXk3fs+BXziHV7Gp7yXT2g69ekuCkO2r1dcYmh8 -t/2jioSgrGK+KwmHNPBqAbubKVY8/gA3zyNs8U6qtnRGEmyR7jTV7JqR50S+kDFy -1UkC9gLl9B/rfNmWVan/7Ir5mUf/NVoCqgTLiluHcSmRvaS0eg29mvVXIwAHIRc/ -SjnRBUkLp7Y3gaVdjKozXoEofKd9J+sAro03 ------END CERTIFICATE----- - -# Issuer: CN=Actalis Authentication Root CA O=Actalis S.p.A./03358520967 -# Subject: CN=Actalis Authentication Root CA O=Actalis S.p.A./03358520967 -# Label: "Actalis Authentication Root CA" -# Serial: 6271844772424770508 -# MD5 Fingerprint: 69:c1:0d:4f:07:a3:1b:c3:fe:56:3d:04:bc:11:f6:a6 -# SHA1 Fingerprint: f3:73:b3:87:06:5a:28:84:8a:f2:f3:4a:ce:19:2b:dd:c7:8e:9c:ac -# SHA256 Fingerprint: 55:92:60:84:ec:96:3a:64:b9:6e:2a:be:01:ce:0b:a8:6a:64:fb:fe:bc:c7:aa:b5:af:c1:55:b3:7f:d7:60:66 ------BEGIN CERTIFICATE----- -MIIFuzCCA6OgAwIBAgIIVwoRl0LE48wwDQYJKoZIhvcNAQELBQAwazELMAkGA1UE -BhMCSVQxDjAMBgNVBAcMBU1pbGFuMSMwIQYDVQQKDBpBY3RhbGlzIFMucC5BLi8w -MzM1ODUyMDk2NzEnMCUGA1UEAwweQWN0YWxpcyBBdXRoZW50aWNhdGlvbiBSb290 -IENBMB4XDTExMDkyMjExMjIwMloXDTMwMDkyMjExMjIwMlowazELMAkGA1UEBhMC -SVQxDjAMBgNVBAcMBU1pbGFuMSMwIQYDVQQKDBpBY3RhbGlzIFMucC5BLi8wMzM1 -ODUyMDk2NzEnMCUGA1UEAwweQWN0YWxpcyBBdXRoZW50aWNhdGlvbiBSb290IENB -MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAp8bEpSmkLO/lGMWwUKNv -UTufClrJwkg4CsIcoBh/kbWHuUA/3R1oHwiD1S0eiKD4j1aPbZkCkpAW1V8IbInX -4ay8IMKx4INRimlNAJZaby/ARH6jDuSRzVju3PvHHkVH3Se5CAGfpiEd9UEtL0z9 -KK3giq0itFZljoZUj5NDKd45RnijMCO6zfB9E1fAXdKDa0hMxKufgFpbOr3JpyI/ -gCczWw63igxdBzcIy2zSekciRDXFzMwujt0q7bd9Zg1fYVEiVRvjRuPjPdA1Yprb -rxTIW6HMiRvhMCb8oJsfgadHHwTrozmSBp+Z07/T6k9QnBn+locePGX2oxgkg4YQ -51Q+qDp2JE+BIcXjDwL4k5RHILv+1A7TaLndxHqEguNTVHnd25zS8gebLra8Pu2F -be8lEfKXGkJh90qX6IuxEAf6ZYGyojnP9zz/GPvG8VqLWeICrHuS0E4UT1lF9gxe -KF+w6D9Fz8+vm2/7hNN3WpVvrJSEnu68wEqPSpP4RCHiMUVhUE4Q2OM1fEwZtN4F -v6MGn8i1zeQf1xcGDXqVdFUNaBr8EBtiZJ1t4JWgw5QHVw0U5r0F+7if5t+L4sbn -fpb2U8WANFAoWPASUHEXMLrmeGO89LKtmyuy/uE5jF66CyCU3nuDuP/jVo23Eek7 -jPKxwV2dpAtMK9myGPW1n0sCAwEAAaNjMGEwHQYDVR0OBBYEFFLYiDrIn3hm7Ynz -ezhwlMkCAjbQMA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAUUtiIOsifeGbt -ifN7OHCUyQICNtAwDgYDVR0PAQH/BAQDAgEGMA0GCSqGSIb3DQEBCwUAA4ICAQAL -e3KHwGCmSUyIWOYdiPcUZEim2FgKDk8TNd81HdTtBjHIgT5q1d07GjLukD0R0i70 -jsNjLiNmsGe+b7bAEzlgqqI0JZN1Ut6nna0Oh4lScWoWPBkdg/iaKWW+9D+a2fDz -WochcYBNy+A4mz+7+uAwTc+G02UQGRjRlwKxK3JCaKygvU5a2hi/a5iB0P2avl4V -SM0RFbnAKVy06Ij3Pjaut2L9HmLecHgQHEhb2rykOLpn7VU+Xlff1ANATIGk0k9j -pwlCCRT8AKnCgHNPLsBA2RF7SOp6AsDT6ygBJlh0wcBzIm2Tlf05fbsq4/aC4yyX -X04fkZT6/iyj2HYauE2yOE+b+h1IYHkm4vP9qdCa6HCPSXrW5b0KDtst842/6+Ok -fcvHlXHo2qN8xcL4dJIEG4aspCJTQLas/kx2z/uUMsA1n3Y/buWQbqCmJqK4LL7R -K4X9p2jIugErsWx0Hbhzlefut8cl8ABMALJ+tguLHPPAUJ4lueAI3jZm/zel0btU -ZCzJJ7VLkn5l/9Mt4blOvH+kQSGQQXemOR/qnuOf0GZvBeyqdn6/axag67XH/JJU -LysRJyU3eExRarDzzFhdFPFqSBX/wge2sY0PjlxQRrM9vwGYT7JZVEc+NHt4bVaT -LnPqZih4zR0Uv6CPLy64Lo7yFIrM6bV8+2ydDKXhlg== ------END CERTIFICATE----- - -# Issuer: CN=Buypass Class 2 Root CA O=Buypass AS-983163327 -# Subject: CN=Buypass Class 2 Root CA O=Buypass AS-983163327 -# Label: "Buypass Class 2 Root CA" -# Serial: 2 -# MD5 Fingerprint: 46:a7:d2:fe:45:fb:64:5a:a8:59:90:9b:78:44:9b:29 -# SHA1 Fingerprint: 49:0a:75:74:de:87:0a:47:fe:58:ee:f6:c7:6b:eb:c6:0b:12:40:99 -# SHA256 Fingerprint: 9a:11:40:25:19:7c:5b:b9:5d:94:e6:3d:55:cd:43:79:08:47:b6:46:b2:3c:df:11:ad:a4:a0:0e:ff:15:fb:48 ------BEGIN CERTIFICATE----- -MIIFWTCCA0GgAwIBAgIBAjANBgkqhkiG9w0BAQsFADBOMQswCQYDVQQGEwJOTzEd -MBsGA1UECgwUQnV5cGFzcyBBUy05ODMxNjMzMjcxIDAeBgNVBAMMF0J1eXBhc3Mg -Q2xhc3MgMiBSb290IENBMB4XDTEwMTAyNjA4MzgwM1oXDTQwMTAyNjA4MzgwM1ow -TjELMAkGA1UEBhMCTk8xHTAbBgNVBAoMFEJ1eXBhc3MgQVMtOTgzMTYzMzI3MSAw -HgYDVQQDDBdCdXlwYXNzIENsYXNzIDIgUm9vdCBDQTCCAiIwDQYJKoZIhvcNAQEB -BQADggIPADCCAgoCggIBANfHXvfBB9R3+0Mh9PT1aeTuMgHbo4Yf5FkNuud1g1Lr -6hxhFUi7HQfKjK6w3Jad6sNgkoaCKHOcVgb/S2TwDCo3SbXlzwx87vFKu3MwZfPV -L4O2fuPn9Z6rYPnT8Z2SdIrkHJasW4DptfQxh6NR/Md+oW+OU3fUl8FVM5I+GC91 -1K2GScuVr1QGbNgGE41b/+EmGVnAJLqBcXmQRFBoJJRfuLMR8SlBYaNByyM21cHx -MlAQTn/0hpPshNOOvEu/XAFOBz3cFIqUCqTqc/sLUegTBxj6DvEr0VQVfTzh97QZ -QmdiXnfgolXsttlpF9U6r0TtSsWe5HonfOV116rLJeffawrbD02TTqigzXsu8lkB -arcNuAeBfos4GzjmCleZPe4h6KP1DBbdi+w0jpwqHAAVF41og9JwnxgIzRFo1clr -Us3ERo/ctfPYV3Me6ZQ5BL/T3jjetFPsaRyifsSP5BtwrfKi+fv3FmRmaZ9JUaLi -FRhnBkp/1Wy1TbMz4GHrXb7pmA8y1x1LPC5aAVKRCfLf6o3YBkBjqhHk/sM3nhRS -P/TizPJhk9H9Z2vXUq6/aKtAQ6BXNVN48FP4YUIHZMbXb5tMOA1jrGKvNouicwoN -9SG9dKpN6nIDSdvHXx1iY8f93ZHsM+71bbRuMGjeyNYmsHVee7QHIJihdjK4TWxP -AgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFMmAd+BikoL1Rpzz -uvdMw964o605MA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQsFAAOCAgEAU18h -9bqwOlI5LJKwbADJ784g7wbylp7ppHR/ehb8t/W2+xUbP6umwHJdELFx7rxP462s -A20ucS6vxOOto70MEae0/0qyexAQH6dXQbLArvQsWdZHEIjzIVEpMMpghq9Gqx3t -OluwlN5E40EIosHsHdb9T7bWR9AUC8rmyrV7d35BH16Dx7aMOZawP5aBQW9gkOLo -+fsicdl9sz1Gv7SEr5AcD48Saq/v7h56rgJKihcrdv6sVIkkLE8/trKnToyokZf7 -KcZ7XC25y2a2t6hbElGFtQl+Ynhw/qlqYLYdDnkM/crqJIByw5c/8nerQyIKx+u2 -DISCLIBrQYoIwOula9+ZEsuK1V6ADJHgJgg2SMX6OBE1/yWDLfJ6v9r9jv6ly0Us -H8SIU653DtmadsWOLB2jutXsMq7Aqqz30XpN69QH4kj3Io6wpJ9qzo6ysmD0oyLQ -I+uUWnpp3Q+/QFesa1lQ2aOZ4W7+jQF5JyMV3pKdewlNWudLSDBaGOYKbeaP4NK7 -5t98biGCwWg5TbSYWGZizEqQXsP6JwSxeRV0mcy+rSDeJmAc61ZRpqPq5KM/p/9h -3PFaTWwyI0PurKju7koSCTxdccK+efrCh2gdC/1cacwG0Jp9VJkqyTkaGa9LKkPz -Y11aWOIv4x3kqdbQCtCev9eBCfHJxyYNrJgWVqA= ------END CERTIFICATE----- - -# Issuer: CN=Buypass Class 3 Root CA O=Buypass AS-983163327 -# Subject: CN=Buypass Class 3 Root CA O=Buypass AS-983163327 -# Label: "Buypass Class 3 Root CA" -# Serial: 2 -# MD5 Fingerprint: 3d:3b:18:9e:2c:64:5a:e8:d5:88:ce:0e:f9:37:c2:ec -# SHA1 Fingerprint: da:fa:f7:fa:66:84:ec:06:8f:14:50:bd:c7:c2:81:a5:bc:a9:64:57 -# SHA256 Fingerprint: ed:f7:eb:bc:a2:7a:2a:38:4d:38:7b:7d:40:10:c6:66:e2:ed:b4:84:3e:4c:29:b4:ae:1d:5b:93:32:e6:b2:4d ------BEGIN CERTIFICATE----- -MIIFWTCCA0GgAwIBAgIBAjANBgkqhkiG9w0BAQsFADBOMQswCQYDVQQGEwJOTzEd -MBsGA1UECgwUQnV5cGFzcyBBUy05ODMxNjMzMjcxIDAeBgNVBAMMF0J1eXBhc3Mg -Q2xhc3MgMyBSb290IENBMB4XDTEwMTAyNjA4Mjg1OFoXDTQwMTAyNjA4Mjg1OFow -TjELMAkGA1UEBhMCTk8xHTAbBgNVBAoMFEJ1eXBhc3MgQVMtOTgzMTYzMzI3MSAw -HgYDVQQDDBdCdXlwYXNzIENsYXNzIDMgUm9vdCBDQTCCAiIwDQYJKoZIhvcNAQEB -BQADggIPADCCAgoCggIBAKXaCpUWUOOV8l6ddjEGMnqb8RB2uACatVI2zSRHsJ8Y -ZLya9vrVediQYkwiL944PdbgqOkcLNt4EemOaFEVcsfzM4fkoF0LXOBXByow9c3E -N3coTRiR5r/VUv1xLXA+58bEiuPwKAv0dpihi4dVsjoT/Lc+JzeOIuOoTyrvYLs9 -tznDDgFHmV0ST9tD+leh7fmdvhFHJlsTmKtdFoqwNxxXnUX/iJY2v7vKB3tvh2PX -0DJq1l1sDPGzbjniazEuOQAnFN44wOwZZoYS6J1yFhNkUsepNxz9gjDthBgd9K5c -/3ATAOux9TN6S9ZV+AWNS2mw9bMoNlwUxFFzTWsL8TQH2xc519woe2v1n/MuwU8X -KhDzzMro6/1rqy6any2CbgTUUgGTLT2G/H783+9CHaZr77kgxve9oKeV/afmiSTY -zIw0bOIjL9kSGiG5VZFvC5F5GQytQIgLcOJ60g7YaEi7ghM5EFjp2CoHxhLbWNvS -O1UQRwUVZ2J+GGOmRj8JDlQyXr8NYnon74Do29lLBlo3WiXQCBJ31G8JUJc9yB3D -34xFMFbG02SrZvPAXpacw8Tvw3xrizp5f7NJzz3iiZ+gMEuFuZyUJHmPfWupRWgP -K9Dx2hzLabjKSWJtyNBjYt1gD1iqj6G8BaVmos8bdrKEZLFMOVLAMLrwjEsCsLa3 -AgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFEe4zf/lb+74suwv -Tg75JbCOPGvDMA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQsFAAOCAgEAACAj -QTUEkMJAYmDv4jVM1z+s4jSQuKFvdvoWFqRINyzpkMLyPPgKn9iB5btb2iUspKdV -cSQy9sgL8rxq+JOssgfCX5/bzMiKqr5qb+FJEMwx14C7u8jYog5kV+qi9cKpMRXS -IGrs/CIBKM+GuIAeqcwRpTzyFrNHnfzSgCHEy9BHcEGhyoMZCCxt8l13nIoUE9Q2 -HJLw5QY33KbmkJs4j1xrG0aGQ0JfPgEHU1RdZX33inOhmlRaHylDFCfChQ+1iHsa -O5S3HWCntZznKWlXWpuTekMwGwPXYshApqr8ZORK15FTAaggiG6cX0S5y2CBNOxv -033aSF/rtJC8LakcC6wc1aJoIIAE1vyxjy+7SjENSoYc6+I2KSb12tjE8nVhz36u -dmNKekBlk4f4HoCMhuWG1o8O/FMsYOgWYRqiPkN7zTlgVGr18okmAWiDSKIz6MkE -kbIRNBE+6tBDGR8Dk5AM/1E9V/RBbuHLoL7ryWPNbczk+DaqaJ3tvV2XcEQNtg41 -3OEMXbugUZTLfhbrES+jkkXITHHZvMmZUldGL1DPvTVp9D0VzgalLA8+9oG6lLvD -u79leNKGef9JOxqDDPDeeOzI8k1MGt6CKfjBWtrt7uYnXuhF0J0cUahoq0Tj0Itq -4/g7u9xN12TyUb7mqqta6THuBrxzvxNiCp/HuZc= ------END CERTIFICATE----- - -# Issuer: CN=T-TeleSec GlobalRoot Class 3 O=T-Systems Enterprise Services GmbH OU=T-Systems Trust Center -# Subject: CN=T-TeleSec GlobalRoot Class 3 O=T-Systems Enterprise Services GmbH OU=T-Systems Trust Center -# Label: "T-TeleSec GlobalRoot Class 3" -# Serial: 1 -# MD5 Fingerprint: ca:fb:40:a8:4e:39:92:8a:1d:fe:8e:2f:c4:27:ea:ef -# SHA1 Fingerprint: 55:a6:72:3e:cb:f2:ec:cd:c3:23:74:70:19:9d:2a:be:11:e3:81:d1 -# SHA256 Fingerprint: fd:73:da:d3:1c:64:4f:f1:b4:3b:ef:0c:cd:da:96:71:0b:9c:d9:87:5e:ca:7e:31:70:7a:f3:e9:6d:52:2b:bd ------BEGIN CERTIFICATE----- -MIIDwzCCAqugAwIBAgIBATANBgkqhkiG9w0BAQsFADCBgjELMAkGA1UEBhMCREUx -KzApBgNVBAoMIlQtU3lzdGVtcyBFbnRlcnByaXNlIFNlcnZpY2VzIEdtYkgxHzAd -BgNVBAsMFlQtU3lzdGVtcyBUcnVzdCBDZW50ZXIxJTAjBgNVBAMMHFQtVGVsZVNl -YyBHbG9iYWxSb290IENsYXNzIDMwHhcNMDgxMDAxMTAyOTU2WhcNMzMxMDAxMjM1 -OTU5WjCBgjELMAkGA1UEBhMCREUxKzApBgNVBAoMIlQtU3lzdGVtcyBFbnRlcnBy -aXNlIFNlcnZpY2VzIEdtYkgxHzAdBgNVBAsMFlQtU3lzdGVtcyBUcnVzdCBDZW50 -ZXIxJTAjBgNVBAMMHFQtVGVsZVNlYyBHbG9iYWxSb290IENsYXNzIDMwggEiMA0G -CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC9dZPwYiJvJK7genasfb3ZJNW4t/zN -8ELg63iIVl6bmlQdTQyK9tPPcPRStdiTBONGhnFBSivwKixVA9ZIw+A5OO3yXDw/ -RLyTPWGrTs0NvvAgJ1gORH8EGoel15YUNpDQSXuhdfsaa3Ox+M6pCSzyU9XDFES4 -hqX2iys52qMzVNn6chr3IhUciJFrf2blw2qAsCTz34ZFiP0Zf3WHHx+xGwpzJFu5 -ZeAsVMhg02YXP+HMVDNzkQI6pn97djmiH5a2OK61yJN0HZ65tOVgnS9W0eDrXltM -EnAMbEQgqxHY9Bn20pxSN+f6tsIxO0rUFJmtxxr1XV/6B7h8DR/Wgx6zAgMBAAGj -QjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBS1 -A/d2O2GCahKqGFPrAyGUv/7OyjANBgkqhkiG9w0BAQsFAAOCAQEAVj3vlNW92nOy -WL6ukK2YJ5f+AbGwUgC4TeQbIXQbfsDuXmkqJa9c1h3a0nnJ85cp4IaH3gRZD/FZ -1GSFS5mvJQQeyUapl96Cshtwn5z2r3Ex3XsFpSzTucpH9sry9uetuUg/vBa3wW30 -6gmv7PO15wWeph6KU1HWk4HMdJP2udqmJQV0eVp+QD6CSyYRMG7hP0HHRwA11fXT -91Q+gT3aSWqas+8QPebrb9HIIkfLzM8BMZLZGOMivgkeGj5asuRrDFR6fUNOuIml -e9eiPZaGzPImNC1qkp2aGtAw4l1OBLBfiyB+d8E9lYLRRpo7PHi4b6HQDWSieB4p -TpPDpFQUWw== ------END CERTIFICATE----- - -# Issuer: CN=D-TRUST Root Class 3 CA 2 2009 O=D-Trust GmbH -# Subject: CN=D-TRUST Root Class 3 CA 2 2009 O=D-Trust GmbH -# Label: "D-TRUST Root Class 3 CA 2 2009" -# Serial: 623603 -# MD5 Fingerprint: cd:e0:25:69:8d:47:ac:9c:89:35:90:f7:fd:51:3d:2f -# SHA1 Fingerprint: 58:e8:ab:b0:36:15:33:fb:80:f7:9b:1b:6d:29:d3:ff:8d:5f:00:f0 -# SHA256 Fingerprint: 49:e7:a4:42:ac:f0:ea:62:87:05:00:54:b5:25:64:b6:50:e4:f4:9e:42:e3:48:d6:aa:38:e0:39:e9:57:b1:c1 ------BEGIN CERTIFICATE----- -MIIEMzCCAxugAwIBAgIDCYPzMA0GCSqGSIb3DQEBCwUAME0xCzAJBgNVBAYTAkRF -MRUwEwYDVQQKDAxELVRydXN0IEdtYkgxJzAlBgNVBAMMHkQtVFJVU1QgUm9vdCBD -bGFzcyAzIENBIDIgMjAwOTAeFw0wOTExMDUwODM1NThaFw0yOTExMDUwODM1NTha -ME0xCzAJBgNVBAYTAkRFMRUwEwYDVQQKDAxELVRydXN0IEdtYkgxJzAlBgNVBAMM -HkQtVFJVU1QgUm9vdCBDbGFzcyAzIENBIDIgMjAwOTCCASIwDQYJKoZIhvcNAQEB -BQADggEPADCCAQoCggEBANOySs96R+91myP6Oi/WUEWJNTrGa9v+2wBoqOADER03 -UAifTUpolDWzU9GUY6cgVq/eUXjsKj3zSEhQPgrfRlWLJ23DEE0NkVJD2IfgXU42 -tSHKXzlABF9bfsyjxiupQB7ZNoTWSPOSHjRGICTBpFGOShrvUD9pXRl/RcPHAY9R -ySPocq60vFYJfxLLHLGvKZAKyVXMD9O0Gu1HNVpK7ZxzBCHQqr0ME7UAyiZsxGsM -lFqVlNpQmvH/pStmMaTJOKDfHR+4CS7zp+hnUquVH+BGPtikw8paxTGA6Eian5Rp -/hnd2HN8gcqW3o7tszIFZYQ05ub9VxC1X3a/L7AQDcUCAwEAAaOCARowggEWMA8G -A1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFP3aFMSfMN4hvR5COfyrYyNJ4PGEMA4G -A1UdDwEB/wQEAwIBBjCB0wYDVR0fBIHLMIHIMIGAoH6gfIZ6bGRhcDovL2RpcmVj -dG9yeS5kLXRydXN0Lm5ldC9DTj1ELVRSVVNUJTIwUm9vdCUyMENsYXNzJTIwMyUy -MENBJTIwMiUyMDIwMDksTz1ELVRydXN0JTIwR21iSCxDPURFP2NlcnRpZmljYXRl -cmV2b2NhdGlvbmxpc3QwQ6BBoD+GPWh0dHA6Ly93d3cuZC10cnVzdC5uZXQvY3Js -L2QtdHJ1c3Rfcm9vdF9jbGFzc18zX2NhXzJfMjAwOS5jcmwwDQYJKoZIhvcNAQEL -BQADggEBAH+X2zDI36ScfSF6gHDOFBJpiBSVYEQBrLLpME+bUMJm2H6NMLVwMeni -acfzcNsgFYbQDfC+rAF1hM5+n02/t2A7nPPKHeJeaNijnZflQGDSNiH+0LS4F9p0 -o3/U37CYAqxva2ssJSRyoWXuJVrl5jLn8t+rSfrzkGkj2wTZ51xY/GXUl77M/C4K -zCUqNQT4YJEVdT1B/yMfGchs64JTBKbkTCJNjYy6zltz7GRUUG3RnFX7acM2w4y8 -PIWmawomDeCTmGCufsYkl4phX5GOZpIJhzbNi5stPvZR1FDUWSi9g/LMKHtThm3Y -Johw1+qRzT65ysCQblrGXnRl11z+o+I= ------END CERTIFICATE----- - -# Issuer: CN=D-TRUST Root Class 3 CA 2 EV 2009 O=D-Trust GmbH -# Subject: CN=D-TRUST Root Class 3 CA 2 EV 2009 O=D-Trust GmbH -# Label: "D-TRUST Root Class 3 CA 2 EV 2009" -# Serial: 623604 -# MD5 Fingerprint: aa:c6:43:2c:5e:2d:cd:c4:34:c0:50:4f:11:02:4f:b6 -# SHA1 Fingerprint: 96:c9:1b:0b:95:b4:10:98:42:fa:d0:d8:22:79:fe:60:fa:b9:16:83 -# SHA256 Fingerprint: ee:c5:49:6b:98:8c:e9:86:25:b9:34:09:2e:ec:29:08:be:d0:b0:f3:16:c2:d4:73:0c:84:ea:f1:f3:d3:48:81 ------BEGIN CERTIFICATE----- -MIIEQzCCAyugAwIBAgIDCYP0MA0GCSqGSIb3DQEBCwUAMFAxCzAJBgNVBAYTAkRF -MRUwEwYDVQQKDAxELVRydXN0IEdtYkgxKjAoBgNVBAMMIUQtVFJVU1QgUm9vdCBD -bGFzcyAzIENBIDIgRVYgMjAwOTAeFw0wOTExMDUwODUwNDZaFw0yOTExMDUwODUw -NDZaMFAxCzAJBgNVBAYTAkRFMRUwEwYDVQQKDAxELVRydXN0IEdtYkgxKjAoBgNV -BAMMIUQtVFJVU1QgUm9vdCBDbGFzcyAzIENBIDIgRVYgMjAwOTCCASIwDQYJKoZI -hvcNAQEBBQADggEPADCCAQoCggEBAJnxhDRwui+3MKCOvXwEz75ivJn9gpfSegpn -ljgJ9hBOlSJzmY3aFS3nBfwZcyK3jpgAvDw9rKFs+9Z5JUut8Mxk2og+KbgPCdM0 -3TP1YtHhzRnp7hhPTFiu4h7WDFsVWtg6uMQYZB7jM7K1iXdODL/ZlGsTl28So/6Z -qQTMFexgaDbtCHu39b+T7WYxg4zGcTSHThfqr4uRjRxWQa4iN1438h3Z0S0NL2lR -p75mpoo6Kr3HGrHhFPC+Oh25z1uxav60sUYgovseO3Dvk5h9jHOW8sXvhXCtKSb8 -HgQ+HKDYD8tSg2J87otTlZCpV6LqYQXY+U3EJ/pure3511H3a6UCAwEAAaOCASQw -ggEgMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFNOUikxiEyoZLsyvcop9Ntea -HNxnMA4GA1UdDwEB/wQEAwIBBjCB3QYDVR0fBIHVMIHSMIGHoIGEoIGBhn9sZGFw -Oi8vZGlyZWN0b3J5LmQtdHJ1c3QubmV0L0NOPUQtVFJVU1QlMjBSb290JTIwQ2xh -c3MlMjAzJTIwQ0ElMjAyJTIwRVYlMjAyMDA5LE89RC1UcnVzdCUyMEdtYkgsQz1E -RT9jZXJ0aWZpY2F0ZXJldm9jYXRpb25saXN0MEagRKBChkBodHRwOi8vd3d3LmQt -dHJ1c3QubmV0L2NybC9kLXRydXN0X3Jvb3RfY2xhc3NfM19jYV8yX2V2XzIwMDku -Y3JsMA0GCSqGSIb3DQEBCwUAA4IBAQA07XtaPKSUiO8aEXUHL7P+PPoeUSbrh/Yp -3uDx1MYkCenBz1UbtDDZzhr+BlGmFaQt77JLvyAoJUnRpjZ3NOhk31KxEcdzes05 -nsKtjHEh8lprr988TlWvsoRlFIm5d8sqMb7Po23Pb0iUMkZv53GMoKaEGTcH8gNF -CSuGdXzfX2lXANtu2KZyIktQ1HWYVt+3GP9DQ1CuekR78HlR10M9p9OB0/DJT7na -xpeG0ILD5EJt/rDiZE4OJudANCa1CInXCGNjOCd1HjPqbqjdn5lPdE2BiYBL3ZqX -KVwvvoFBuYz/6n1gBp7N1z3TLqMVvKjmJuVvw9y4AyHqnxbxLFS1 ------END CERTIFICATE----- - -# Issuer: CN=CA Disig Root R2 O=Disig a.s. -# Subject: CN=CA Disig Root R2 O=Disig a.s. -# Label: "CA Disig Root R2" -# Serial: 10572350602393338211 -# MD5 Fingerprint: 26:01:fb:d8:27:a7:17:9a:45:54:38:1a:43:01:3b:03 -# SHA1 Fingerprint: b5:61:eb:ea:a4:de:e4:25:4b:69:1a:98:a5:57:47:c2:34:c7:d9:71 -# SHA256 Fingerprint: e2:3d:4a:03:6d:7b:70:e9:f5:95:b1:42:20:79:d2:b9:1e:df:bb:1f:b6:51:a0:63:3e:aa:8a:9d:c5:f8:07:03 ------BEGIN CERTIFICATE----- -MIIFaTCCA1GgAwIBAgIJAJK4iNuwisFjMA0GCSqGSIb3DQEBCwUAMFIxCzAJBgNV -BAYTAlNLMRMwEQYDVQQHEwpCcmF0aXNsYXZhMRMwEQYDVQQKEwpEaXNpZyBhLnMu -MRkwFwYDVQQDExBDQSBEaXNpZyBSb290IFIyMB4XDTEyMDcxOTA5MTUzMFoXDTQy -MDcxOTA5MTUzMFowUjELMAkGA1UEBhMCU0sxEzARBgNVBAcTCkJyYXRpc2xhdmEx -EzARBgNVBAoTCkRpc2lnIGEucy4xGTAXBgNVBAMTEENBIERpc2lnIFJvb3QgUjIw -ggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCio8QACdaFXS1tFPbCw3Oe -NcJxVX6B+6tGUODBfEl45qt5WDza/3wcn9iXAng+a0EE6UG9vgMsRfYvZNSrXaNH -PWSb6WiaxswbP7q+sos0Ai6YVRn8jG+qX9pMzk0DIaPY0jSTVpbLTAwAFjxfGs3I -x2ymrdMxp7zo5eFm1tL7A7RBZckQrg4FY8aAamkw/dLukO8NJ9+flXP04SXabBbe -QTg06ov80egEFGEtQX6sx3dOy1FU+16SGBsEWmjGycT6txOgmLcRK7fWV8x8nhfR -yyX+hk4kLlYMeE2eARKmK6cBZW58Yh2EhN/qwGu1pSqVg8NTEQxzHQuyRpDRQjrO -QG6Vrf/GlK1ul4SOfW+eioANSW1z4nuSHsPzwfPrLgVv2RvPN3YEyLRa5Beny912 -H9AZdugsBbPWnDTYltxhh5EF5EQIM8HauQhl1K6yNg3ruji6DOWbnuuNZt2Zz9aJ -QfYEkoopKW1rOhzndX0CcQ7zwOe9yxndnWCywmZgtrEE7snmhrmaZkCo5xHtgUUD -i/ZnWejBBhG93c+AAk9lQHhcR1DIm+YfgXvkRKhbhZri3lrVx/k6RGZL5DJUfORs -nLMOPReisjQS1n6yqEm70XooQL6iFh/f5DcfEXP7kAplQ6INfPgGAVUzfbANuPT1 -rqVCV3w2EYx7XsQDnYx5nQIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1Ud -DwEB/wQEAwIBBjAdBgNVHQ4EFgQUtZn4r7CU9eMg1gqtzk5WpC5uQu0wDQYJKoZI -hvcNAQELBQADggIBACYGXnDnZTPIgm7ZnBc6G3pmsgH2eDtpXi/q/075KMOYKmFM -tCQSin1tERT3nLXK5ryeJ45MGcipvXrA1zYObYVybqjGom32+nNjf7xueQgcnYqf -GopTpti72TVVsRHFqQOzVju5hJMiXn7B9hJSi+osZ7z+Nkz1uM/Rs0mSO9MpDpkb -lvdhuDvEK7Z4bLQjb/D907JedR+Zlais9trhxTF7+9FGs9K8Z7RiVLoJ92Owk6Ka -+elSLotgEqv89WBW7xBci8QaQtyDW2QOy7W81k/BfDxujRNt+3vrMNDcTa/F1bal -TFtxyegxvug4BkihGuLq0t4SOVga/4AOgnXmt8kHbA7v/zjxmHHEt38OFdAlab0i -nSvtBfZGR6ztwPDUO+Ls7pZbkBNOHlY667DvlruWIxG68kOGdGSVyCh13x01utI3 -gzhTODY7z2zp+WsO0PsE6E9312UBeIYMej4hYvF/Y3EMyZ9E26gnonW+boE+18Dr -G5gPcFw0sorMwIUY6256s/daoQe/qUKS82Ail+QUoQebTnbAjn39pCXHR+3/H3Os -zMOl6W8KjptlwlCFtaOgUxLMVYdh84GuEEZhvUQhuMI9dM9+JDX6HAcOmz0iyu8x -L4ysEr3vQCj8KWefshNPZiTEUxnpHikV7+ZtsH8tZ/3zbBt1RqPlShfppNcL ------END CERTIFICATE----- - -# Issuer: CN=ACCVRAIZ1 O=ACCV OU=PKIACCV -# Subject: CN=ACCVRAIZ1 O=ACCV OU=PKIACCV -# Label: "ACCVRAIZ1" -# Serial: 6828503384748696800 -# MD5 Fingerprint: d0:a0:5a:ee:05:b6:09:94:21:a1:7d:f1:b2:29:82:02 -# SHA1 Fingerprint: 93:05:7a:88:15:c6:4f:ce:88:2f:fa:91:16:52:28:78:bc:53:64:17 -# SHA256 Fingerprint: 9a:6e:c0:12:e1:a7:da:9d:be:34:19:4d:47:8a:d7:c0:db:18:22:fb:07:1d:f1:29:81:49:6e:d1:04:38:41:13 ------BEGIN CERTIFICATE----- -MIIH0zCCBbugAwIBAgIIXsO3pkN/pOAwDQYJKoZIhvcNAQEFBQAwQjESMBAGA1UE -AwwJQUNDVlJBSVoxMRAwDgYDVQQLDAdQS0lBQ0NWMQ0wCwYDVQQKDARBQ0NWMQsw -CQYDVQQGEwJFUzAeFw0xMTA1MDUwOTM3MzdaFw0zMDEyMzEwOTM3MzdaMEIxEjAQ -BgNVBAMMCUFDQ1ZSQUlaMTEQMA4GA1UECwwHUEtJQUNDVjENMAsGA1UECgwEQUND -VjELMAkGA1UEBhMCRVMwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCb -qau/YUqXry+XZpp0X9DZlv3P4uRm7x8fRzPCRKPfmt4ftVTdFXxpNRFvu8gMjmoY -HtiP2Ra8EEg2XPBjs5BaXCQ316PWywlxufEBcoSwfdtNgM3802/J+Nq2DoLSRYWo -G2ioPej0RGy9ocLLA76MPhMAhN9KSMDjIgro6TenGEyxCQ0jVn8ETdkXhBilyNpA -lHPrzg5XPAOBOp0KoVdDaaxXbXmQeOW1tDvYvEyNKKGno6e6Ak4l0Squ7a4DIrhr -IA8wKFSVf+DuzgpmndFALW4ir50awQUZ0m/A8p/4e7MCQvtQqR0tkw8jq8bBD5L/ -0KIV9VMJcRz/RROE5iZe+OCIHAr8Fraocwa48GOEAqDGWuzndN9wrqODJerWx5eH -k6fGioozl2A3ED6XPm4pFdahD9GILBKfb6qkxkLrQaLjlUPTAYVtjrs78yM2x/47 -4KElB0iryYl0/wiPgL/AlmXz7uxLaL2diMMxs0Dx6M/2OLuc5NF/1OVYm3z61PMO -m3WR5LpSLhl+0fXNWhn8ugb2+1KoS5kE3fj5tItQo05iifCHJPqDQsGH+tUtKSpa -cXpkatcnYGMN285J9Y0fkIkyF/hzQ7jSWpOGYdbhdQrqeWZ2iE9x6wQl1gpaepPl -uUsXQA+xtrn13k/c4LOsOxFwYIRKQ26ZIMApcQrAZQIDAQABo4ICyzCCAscwfQYI -KwYBBQUHAQEEcTBvMEwGCCsGAQUFBzAChkBodHRwOi8vd3d3LmFjY3YuZXMvZmls -ZWFkbWluL0FyY2hpdm9zL2NlcnRpZmljYWRvcy9yYWl6YWNjdjEuY3J0MB8GCCsG -AQUFBzABhhNodHRwOi8vb2NzcC5hY2N2LmVzMB0GA1UdDgQWBBTSh7Tj3zcnk1X2 -VuqB5TbMjB4/vTAPBgNVHRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFNKHtOPfNyeT -VfZW6oHlNsyMHj+9MIIBcwYDVR0gBIIBajCCAWYwggFiBgRVHSAAMIIBWDCCASIG -CCsGAQUFBwICMIIBFB6CARAAQQB1AHQAbwByAGkAZABhAGQAIABkAGUAIABDAGUA -cgB0AGkAZgBpAGMAYQBjAGkA8wBuACAAUgBhAO0AegAgAGQAZQAgAGwAYQAgAEEA -QwBDAFYAIAAoAEEAZwBlAG4AYwBpAGEAIABkAGUAIABUAGUAYwBuAG8AbABvAGcA -7QBhACAAeQAgAEMAZQByAHQAaQBmAGkAYwBhAGMAaQDzAG4AIABFAGwAZQBjAHQA -cgDzAG4AaQBjAGEALAAgAEMASQBGACAAUQA0ADYAMAAxADEANQA2AEUAKQAuACAA -QwBQAFMAIABlAG4AIABoAHQAdABwADoALwAvAHcAdwB3AC4AYQBjAGMAdgAuAGUA -czAwBggrBgEFBQcCARYkaHR0cDovL3d3dy5hY2N2LmVzL2xlZ2lzbGFjaW9uX2Mu -aHRtMFUGA1UdHwROMEwwSqBIoEaGRGh0dHA6Ly93d3cuYWNjdi5lcy9maWxlYWRt -aW4vQXJjaGl2b3MvY2VydGlmaWNhZG9zL3JhaXphY2N2MV9kZXIuY3JsMA4GA1Ud -DwEB/wQEAwIBBjAXBgNVHREEEDAOgQxhY2N2QGFjY3YuZXMwDQYJKoZIhvcNAQEF -BQADggIBAJcxAp/n/UNnSEQU5CmH7UwoZtCPNdpNYbdKl02125DgBS4OxnnQ8pdp -D70ER9m+27Up2pvZrqmZ1dM8MJP1jaGo/AaNRPTKFpV8M9xii6g3+CfYCS0b78gU -JyCpZET/LtZ1qmxNYEAZSUNUY9rizLpm5U9EelvZaoErQNV/+QEnWCzI7UiRfD+m -AM/EKXMRNt6GGT6d7hmKG9Ww7Y49nCrADdg9ZuM8Db3VlFzi4qc1GwQA9j9ajepD -vV+JHanBsMyZ4k0ACtrJJ1vnE5Bc5PUzolVt3OAJTS+xJlsndQAJxGJ3KQhfnlms -tn6tn1QwIgPBHnFk/vk4CpYY3QIUrCPLBhwepH2NDd4nQeit2hW3sCPdK6jT2iWH -7ehVRE2I9DZ+hJp4rPcOVkkO1jMl1oRQQmwgEh0q1b688nCBpHBgvgW1m54ERL5h -I6zppSSMEYCUWqKiuUnSwdzRp+0xESyeGabu4VXhwOrPDYTkF7eifKXeVSUG7szA -h1xA2syVP1XgNce4hL60Xc16gwFy7ofmXx2utYXGJt/mwZrpHgJHnyqobalbz+xF -d3+YJ5oyXSrjhO7FmGYvliAd3djDJ9ew+f7Zfc3Qn48LFFhRny+Lwzgt3uiP1o2H -pPVWQxaZLPSkVrQ0uGE3ycJYgBugl6H8WY3pEfbRD0tVNEYqi4Y7 ------END CERTIFICATE----- - -# Issuer: CN=TWCA Global Root CA O=TAIWAN-CA OU=Root CA -# Subject: CN=TWCA Global Root CA O=TAIWAN-CA OU=Root CA -# Label: "TWCA Global Root CA" -# Serial: 3262 -# MD5 Fingerprint: f9:03:7e:cf:e6:9e:3c:73:7a:2a:90:07:69:ff:2b:96 -# SHA1 Fingerprint: 9c:bb:48:53:f6:a4:f6:d3:52:a4:e8:32:52:55:60:13:f5:ad:af:65 -# SHA256 Fingerprint: 59:76:90:07:f7:68:5d:0f:cd:50:87:2f:9f:95:d5:75:5a:5b:2b:45:7d:81:f3:69:2b:61:0a:98:67:2f:0e:1b ------BEGIN CERTIFICATE----- -MIIFQTCCAymgAwIBAgICDL4wDQYJKoZIhvcNAQELBQAwUTELMAkGA1UEBhMCVFcx -EjAQBgNVBAoTCVRBSVdBTi1DQTEQMA4GA1UECxMHUm9vdCBDQTEcMBoGA1UEAxMT -VFdDQSBHbG9iYWwgUm9vdCBDQTAeFw0xMjA2MjcwNjI4MzNaFw0zMDEyMzExNTU5 -NTlaMFExCzAJBgNVBAYTAlRXMRIwEAYDVQQKEwlUQUlXQU4tQ0ExEDAOBgNVBAsT -B1Jvb3QgQ0ExHDAaBgNVBAMTE1RXQ0EgR2xvYmFsIFJvb3QgQ0EwggIiMA0GCSqG -SIb3DQEBAQUAA4ICDwAwggIKAoICAQCwBdvI64zEbooh745NnHEKH1Jw7W2CnJfF -10xORUnLQEK1EjRsGcJ0pDFfhQKX7EMzClPSnIyOt7h52yvVavKOZsTuKwEHktSz -0ALfUPZVr2YOy+BHYC8rMjk1Ujoog/h7FsYYuGLWRyWRzvAZEk2tY/XTP3VfKfCh -MBwqoJimFb3u/Rk28OKRQ4/6ytYQJ0lM793B8YVwm8rqqFpD/G2Gb3PpN0Wp8DbH -zIh1HrtsBv+baz4X7GGqcXzGHaL3SekVtTzWoWH1EfcFbx39Eb7QMAfCKbAJTibc -46KokWofwpFFiFzlmLhxpRUZyXx1EcxwdE8tmx2RRP1WKKD+u4ZqyPpcC1jcxkt2 -yKsi2XMPpfRaAok/T54igu6idFMqPVMnaR1sjjIsZAAmY2E2TqNGtz99sy2sbZCi -laLOz9qC5wc0GZbpuCGqKX6mOL6OKUohZnkfs8O1CWfe1tQHRvMq2uYiN2DLgbYP -oA/pyJV/v1WRBXrPPRXAb94JlAGD1zQbzECl8LibZ9WYkTunhHiVJqRaCPgrdLQA -BDzfuBSO6N+pjWxnkjMdwLfS7JLIvgm/LCkFbwJrnu+8vyq8W8BQj0FwcYeyTbcE -qYSjMq+u7msXi7Kx/mzhkIyIqJdIzshNy/MGz19qCkKxHh53L46g5pIOBvwFItIm -4TFRfTLcDwIDAQABoyMwITAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB -/zANBgkqhkiG9w0BAQsFAAOCAgEAXzSBdu+WHdXltdkCY4QWwa6gcFGn90xHNcgL -1yg9iXHZqjNB6hQbbCEAwGxCGX6faVsgQt+i0trEfJdLjbDorMjupWkEmQqSpqsn -LhpNgb+E1HAerUf+/UqdM+DyucRFCCEK2mlpc3INvjT+lIutwx4116KD7+U4x6WF -H6vPNOw/KP4M8VeGTslV9xzU2KV9Bnpv1d8Q34FOIWWxtuEXeZVFBs5fzNxGiWNo -RI2T9GRwoD2dKAXDOXC4Ynsg/eTb6QihuJ49CcdP+yz4k3ZB3lLg4VfSnQO8d57+ -nile98FRYB/e2guyLXW3Q0iT5/Z5xoRdgFlglPx4mI88k1HtQJAH32RjJMtOcQWh -15QaiDLxInQirqWm2BJpTGCjAu4r7NRjkgtevi92a6O2JryPA9gK8kxkRr05YuWW -6zRjESjMlfGt7+/cgFhI6Uu46mWs6fyAtbXIRfmswZ/ZuepiiI7E8UuDEq3mi4TW -nsLrgxifarsbJGAzcMzs9zLzXNl5fe+epP7JI8Mk7hWSsT2RTyaGvWZzJBPqpK5j -wa19hAM8EHiGG3njxPPyBJUgriOCxLM6AGK/5jYk4Ve6xx6QddVfP5VhK8E7zeWz -aGHQRiapIVJpLesux+t3zqY6tQMzT3bR51xUAV3LePTJDL/PEo4XLSNolOer/qmy -KwbQBM0= ------END CERTIFICATE----- - -# Issuer: CN=T-TeleSec GlobalRoot Class 2 O=T-Systems Enterprise Services GmbH OU=T-Systems Trust Center -# Subject: CN=T-TeleSec GlobalRoot Class 2 O=T-Systems Enterprise Services GmbH OU=T-Systems Trust Center -# Label: "T-TeleSec GlobalRoot Class 2" -# Serial: 1 -# MD5 Fingerprint: 2b:9b:9e:e4:7b:6c:1f:00:72:1a:cc:c1:77:79:df:6a -# SHA1 Fingerprint: 59:0d:2d:7d:88:4f:40:2e:61:7e:a5:62:32:17:65:cf:17:d8:94:e9 -# SHA256 Fingerprint: 91:e2:f5:78:8d:58:10:eb:a7:ba:58:73:7d:e1:54:8a:8e:ca:cd:01:45:98:bc:0b:14:3e:04:1b:17:05:25:52 ------BEGIN CERTIFICATE----- -MIIDwzCCAqugAwIBAgIBATANBgkqhkiG9w0BAQsFADCBgjELMAkGA1UEBhMCREUx -KzApBgNVBAoMIlQtU3lzdGVtcyBFbnRlcnByaXNlIFNlcnZpY2VzIEdtYkgxHzAd -BgNVBAsMFlQtU3lzdGVtcyBUcnVzdCBDZW50ZXIxJTAjBgNVBAMMHFQtVGVsZVNl -YyBHbG9iYWxSb290IENsYXNzIDIwHhcNMDgxMDAxMTA0MDE0WhcNMzMxMDAxMjM1 -OTU5WjCBgjELMAkGA1UEBhMCREUxKzApBgNVBAoMIlQtU3lzdGVtcyBFbnRlcnBy -aXNlIFNlcnZpY2VzIEdtYkgxHzAdBgNVBAsMFlQtU3lzdGVtcyBUcnVzdCBDZW50 -ZXIxJTAjBgNVBAMMHFQtVGVsZVNlYyBHbG9iYWxSb290IENsYXNzIDIwggEiMA0G -CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCqX9obX+hzkeXaXPSi5kfl82hVYAUd -AqSzm1nzHoqvNK38DcLZSBnuaY/JIPwhqgcZ7bBcrGXHX+0CfHt8LRvWurmAwhiC -FoT6ZrAIxlQjgeTNuUk/9k9uN0goOA/FvudocP05l03Sx5iRUKrERLMjfTlH6VJi -1hKTXrcxlkIF+3anHqP1wvzpesVsqXFP6st4vGCvx9702cu+fjOlbpSD8DT6Iavq -jnKgP6TeMFvvhk1qlVtDRKgQFRzlAVfFmPHmBiiRqiDFt1MmUUOyCxGVWOHAD3bZ -wI18gfNycJ5v/hqO2V81xrJvNHy+SE/iWjnX2J14np+GPgNeGYtEotXHAgMBAAGj -QjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBS/ -WSA2AHmgoCJrjNXyYdK4LMuCSjANBgkqhkiG9w0BAQsFAAOCAQEAMQOiYQsfdOhy -NsZt+U2e+iKo4YFWz827n+qrkRk4r6p8FU3ztqONpfSO9kSpp+ghla0+AGIWiPAC -uvxhI+YzmzB6azZie60EI4RYZeLbK4rnJVM3YlNfvNoBYimipidx5joifsFvHZVw -IEoHNN/q/xWA5brXethbdXwFeilHfkCoMRN3zUA7tFFHei4R40cR3p1m0IvVVGb6 -g1XqfMIpiRvpb7PO4gWEyS8+eIVibslfwXhjdFjASBgMmTnrpMwatXlajRWc2BQN -9noHV8cigwUtPJslJj0Ys6lDfMjIq2SPDqO/nBudMNva0Bkuqjzx+zOAduTNrRlP -BSeOE6Fuwg== ------END CERTIFICATE----- - -# Issuer: CN=Atos TrustedRoot 2011 O=Atos -# Subject: CN=Atos TrustedRoot 2011 O=Atos -# Label: "Atos TrustedRoot 2011" -# Serial: 6643877497813316402 -# MD5 Fingerprint: ae:b9:c4:32:4b:ac:7f:5d:66:cc:77:94:bb:2a:77:56 -# SHA1 Fingerprint: 2b:b1:f5:3e:55:0c:1d:c5:f1:d4:e6:b7:6a:46:4b:55:06:02:ac:21 -# SHA256 Fingerprint: f3:56:be:a2:44:b7:a9:1e:b3:5d:53:ca:9a:d7:86:4a:ce:01:8e:2d:35:d5:f8:f9:6d:df:68:a6:f4:1a:a4:74 ------BEGIN CERTIFICATE----- -MIIDdzCCAl+gAwIBAgIIXDPLYixfszIwDQYJKoZIhvcNAQELBQAwPDEeMBwGA1UE -AwwVQXRvcyBUcnVzdGVkUm9vdCAyMDExMQ0wCwYDVQQKDARBdG9zMQswCQYDVQQG -EwJERTAeFw0xMTA3MDcxNDU4MzBaFw0zMDEyMzEyMzU5NTlaMDwxHjAcBgNVBAMM -FUF0b3MgVHJ1c3RlZFJvb3QgMjAxMTENMAsGA1UECgwEQXRvczELMAkGA1UEBhMC -REUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCVhTuXbyo7LjvPpvMp -Nb7PGKw+qtn4TaA+Gke5vJrf8v7MPkfoepbCJI419KkM/IL9bcFyYie96mvr54rM -VD6QUM+A1JX76LWC1BTFtqlVJVfbsVD2sGBkWXppzwO3bw2+yj5vdHLqqjAqc2K+ -SZFhyBH+DgMq92og3AIVDV4VavzjgsG1xZ1kCWyjWZgHJ8cblithdHFsQ/H3NYkQ -4J7sVaE3IqKHBAUsR320HLliKWYoyrfhk/WklAOZuXCFteZI6o1Q/NnezG8HDt0L -cp2AMBYHlT8oDv3FdU9T1nSatCQujgKRz3bFmx5VdJx4IbHwLfELn8LVlhgf8FQi -eowHAgMBAAGjfTB7MB0GA1UdDgQWBBSnpQaxLKYJYO7Rl+lwrrw7GWzbITAPBgNV -HRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFKelBrEspglg7tGX6XCuvDsZbNshMBgG -A1UdIAQRMA8wDQYLKwYBBAGwLQMEAQEwDgYDVR0PAQH/BAQDAgGGMA0GCSqGSIb3 -DQEBCwUAA4IBAQAmdzTblEiGKkGdLD4GkGDEjKwLVLgfuXvTBznk+j57sj1O7Z8j -vZfza1zv7v1Apt+hk6EKhqzvINB5Ab149xnYJDE0BAGmuhWawyfc2E8PzBhj/5kP -DpFrdRbhIfzYJsdHt6bPWHJxfrrhTZVHO8mvbaG0weyJ9rQPOLXiZNwlz6bb65pc -maHFCN795trV1lpFDMS3wrUU77QR/w4VtfX128a961qn8FYiqTxlVMYVqL2Gns2D -lmh6cYGJ4Qvh6hEbaAjMaZ7snkGeRDImeuKHCnE96+RapNLbxc3G3mB/ufNPRJLv -KrcYPqcZ2Qt9sTdBQrC6YB3y/gkRsPCHe6ed ------END CERTIFICATE----- - -# Issuer: CN=QuoVadis Root CA 1 G3 O=QuoVadis Limited -# Subject: CN=QuoVadis Root CA 1 G3 O=QuoVadis Limited -# Label: "QuoVadis Root CA 1 G3" -# Serial: 687049649626669250736271037606554624078720034195 -# MD5 Fingerprint: a4:bc:5b:3f:fe:37:9a:fa:64:f0:e2:fa:05:3d:0b:ab -# SHA1 Fingerprint: 1b:8e:ea:57:96:29:1a:c9:39:ea:b8:0a:81:1a:73:73:c0:93:79:67 -# SHA256 Fingerprint: 8a:86:6f:d1:b2:76:b5:7e:57:8e:92:1c:65:82:8a:2b:ed:58:e9:f2:f2:88:05:41:34:b7:f1:f4:bf:c9:cc:74 ------BEGIN CERTIFICATE----- -MIIFYDCCA0igAwIBAgIUeFhfLq0sGUvjNwc1NBMotZbUZZMwDQYJKoZIhvcNAQEL -BQAwSDELMAkGA1UEBhMCQk0xGTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxHjAc -BgNVBAMTFVF1b1ZhZGlzIFJvb3QgQ0EgMSBHMzAeFw0xMjAxMTIxNzI3NDRaFw00 -MjAxMTIxNzI3NDRaMEgxCzAJBgNVBAYTAkJNMRkwFwYDVQQKExBRdW9WYWRpcyBM -aW1pdGVkMR4wHAYDVQQDExVRdW9WYWRpcyBSb290IENBIDEgRzMwggIiMA0GCSqG -SIb3DQEBAQUAA4ICDwAwggIKAoICAQCgvlAQjunybEC0BJyFuTHK3C3kEakEPBtV -wedYMB0ktMPvhd6MLOHBPd+C5k+tR4ds7FtJwUrVu4/sh6x/gpqG7D0DmVIB0jWe -rNrwU8lmPNSsAgHaJNM7qAJGr6Qc4/hzWHa39g6QDbXwz8z6+cZM5cOGMAqNF341 -68Xfuw6cwI2H44g4hWf6Pser4BOcBRiYz5P1sZK0/CPTz9XEJ0ngnjybCKOLXSoh -4Pw5qlPafX7PGglTvF0FBM+hSo+LdoINofjSxxR3W5A2B4GbPgb6Ul5jxaYA/qXp -UhtStZI5cgMJYr2wYBZupt0lwgNm3fME0UDiTouG9G/lg6AnhF4EwfWQvTA9xO+o -abw4m6SkltFi2mnAAZauy8RRNOoMqv8hjlmPSlzkYZqn0ukqeI1RPToV7qJZjqlc -3sX5kCLliEVx3ZGZbHqfPT2YfF72vhZooF6uCyP8Wg+qInYtyaEQHeTTRCOQiJ/G -KubX9ZqzWB4vMIkIG1SitZgj7Ah3HJVdYdHLiZxfokqRmu8hqkkWCKi9YSgxyXSt -hfbZxbGL0eUQMk1fiyA6PEkfM4VZDdvLCXVDaXP7a3F98N/ETH3Goy7IlXnLc6KO -Tk0k+17kBL5yG6YnLUlamXrXXAkgt3+UuU/xDRxeiEIbEbfnkduebPRq34wGmAOt -zCjvpUfzUwIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIB -BjAdBgNVHQ4EFgQUo5fW816iEOGrRZ88F2Q87gFwnMwwDQYJKoZIhvcNAQELBQAD -ggIBABj6W3X8PnrHX3fHyt/PX8MSxEBd1DKquGrX1RUVRpgjpeaQWxiZTOOtQqOC -MTaIzen7xASWSIsBx40Bz1szBpZGZnQdT+3Btrm0DWHMY37XLneMlhwqI2hrhVd2 -cDMT/uFPpiN3GPoajOi9ZcnPP/TJF9zrx7zABC4tRi9pZsMbj/7sPtPKlL92CiUN -qXsCHKnQO18LwIE6PWThv6ctTr1NxNgpxiIY0MWscgKCP6o6ojoilzHdCGPDdRS5 -YCgtW2jgFqlmgiNR9etT2DGbe+m3nUvriBbP+V04ikkwj+3x6xn0dxoxGE1nVGwv -b2X52z3sIexe9PSLymBlVNFxZPT5pqOBMzYzcfCkeF9OrYMh3jRJjehZrJ3ydlo2 -8hP0r+AJx2EqbPfgna67hkooby7utHnNkDPDs3b69fBsnQGQ+p6Q9pxyz0fawx/k -NSBT8lTR32GDpgLiJTjehTItXnOQUl1CxM49S+H5GYQd1aJQzEH7QRTDvdbJWqNj -ZgKAvQU6O0ec7AAmTPWIUb+oI38YB7AL7YsmoWTTYUrrXJ/es69nA7Mf3W1daWhp -q1467HxpvMc7hU6eFbm0FU/DlXpY18ls6Wy58yljXrQs8C097Vpl4KlbQMJImYFt -nh8GKjwStIsPm6Ik8KaN1nrgS7ZklmOVhMJKzRwuJIczYOXD ------END CERTIFICATE----- - -# Issuer: CN=QuoVadis Root CA 2 G3 O=QuoVadis Limited -# Subject: CN=QuoVadis Root CA 2 G3 O=QuoVadis Limited -# Label: "QuoVadis Root CA 2 G3" -# Serial: 390156079458959257446133169266079962026824725800 -# MD5 Fingerprint: af:0c:86:6e:bf:40:2d:7f:0b:3e:12:50:ba:12:3d:06 -# SHA1 Fingerprint: 09:3c:61:f3:8b:8b:dc:7d:55:df:75:38:02:05:00:e1:25:f5:c8:36 -# SHA256 Fingerprint: 8f:e4:fb:0a:f9:3a:4d:0d:67:db:0b:eb:b2:3e:37:c7:1b:f3:25:dc:bc:dd:24:0e:a0:4d:af:58:b4:7e:18:40 ------BEGIN CERTIFICATE----- -MIIFYDCCA0igAwIBAgIURFc0JFuBiZs18s64KztbpybwdSgwDQYJKoZIhvcNAQEL -BQAwSDELMAkGA1UEBhMCQk0xGTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxHjAc -BgNVBAMTFVF1b1ZhZGlzIFJvb3QgQ0EgMiBHMzAeFw0xMjAxMTIxODU5MzJaFw00 -MjAxMTIxODU5MzJaMEgxCzAJBgNVBAYTAkJNMRkwFwYDVQQKExBRdW9WYWRpcyBM -aW1pdGVkMR4wHAYDVQQDExVRdW9WYWRpcyBSb290IENBIDIgRzMwggIiMA0GCSqG -SIb3DQEBAQUAA4ICDwAwggIKAoICAQChriWyARjcV4g/Ruv5r+LrI3HimtFhZiFf -qq8nUeVuGxbULX1QsFN3vXg6YOJkApt8hpvWGo6t/x8Vf9WVHhLL5hSEBMHfNrMW -n4rjyduYNM7YMxcoRvynyfDStNVNCXJJ+fKH46nafaF9a7I6JaltUkSs+L5u+9ym -c5GQYaYDFCDy54ejiK2toIz/pgslUiXnFgHVy7g1gQyjO/Dh4fxaXc6AcW34Sas+ -O7q414AB+6XrW7PFXmAqMaCvN+ggOp+oMiwMzAkd056OXbxMmO7FGmh77FOm6RQ1 -o9/NgJ8MSPsc9PG/Srj61YxxSscfrf5BmrODXfKEVu+lV0POKa2Mq1W/xPtbAd0j -IaFYAI7D0GoT7RPjEiuA3GfmlbLNHiJuKvhB1PLKFAeNilUSxmn1uIZoL1NesNKq -IcGY5jDjZ1XHm26sGahVpkUG0CM62+tlXSoREfA7T8pt9DTEceT/AFr2XK4jYIVz -8eQQsSWu1ZK7E8EM4DnatDlXtas1qnIhO4M15zHfeiFuuDIIfR0ykRVKYnLP43eh -vNURG3YBZwjgQQvD6xVu+KQZ2aKrr+InUlYrAoosFCT5v0ICvybIxo/gbjh9Uy3l -7ZizlWNof/k19N+IxWA1ksB8aRxhlRbQ694Lrz4EEEVlWFA4r0jyWbYW8jwNkALG -cC4BrTwV1wIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIB -BjAdBgNVHQ4EFgQU7edvdlq/YOxJW8ald7tyFnGbxD0wDQYJKoZIhvcNAQELBQAD -ggIBAJHfgD9DCX5xwvfrs4iP4VGyvD11+ShdyLyZm3tdquXK4Qr36LLTn91nMX66 -AarHakE7kNQIXLJgapDwyM4DYvmL7ftuKtwGTTwpD4kWilhMSA/ohGHqPHKmd+RC -roijQ1h5fq7KpVMNqT1wvSAZYaRsOPxDMuHBR//47PERIjKWnML2W2mWeyAMQ0Ga -W/ZZGYjeVYg3UQt4XAoeo0L9x52ID8DyeAIkVJOviYeIyUqAHerQbj5hLja7NQ4n -lv1mNDthcnPxFlxHBlRJAHpYErAK74X9sbgzdWqTHBLmYF5vHX/JHyPLhGGfHoJE -+V+tYlUkmlKY7VHnoX6XOuYvHxHaU4AshZ6rNRDbIl9qxV6XU/IyAgkwo1jwDQHV -csaxfGl7w/U2Rcxhbl5MlMVerugOXou/983g7aEOGzPuVBj+D77vfoRrQ+NwmNtd -dbINWQeFFSM51vHfqSYP1kjHs6Yi9TM3WpVHn3u6GBVv/9YUZINJ0gpnIdsPNWNg -KCLjsZWDzYWm3S8P52dSbrsvhXz1SnPnxT7AvSESBT/8twNJAlvIJebiVDj1eYeM -HVOyToV7BjjHLPj4sHKNJeV3UvQDHEimUF+IIDBu8oJDqz2XhOdT+yHBTw8imoa4 -WSr2Rz0ZiC3oheGe7IUIarFsNMkd7EgrO3jtZsSOeWmD3n+M ------END CERTIFICATE----- - -# Issuer: CN=QuoVadis Root CA 3 G3 O=QuoVadis Limited -# Subject: CN=QuoVadis Root CA 3 G3 O=QuoVadis Limited -# Label: "QuoVadis Root CA 3 G3" -# Serial: 268090761170461462463995952157327242137089239581 -# MD5 Fingerprint: df:7d:b9:ad:54:6f:68:a1:df:89:57:03:97:43:b0:d7 -# SHA1 Fingerprint: 48:12:bd:92:3c:a8:c4:39:06:e7:30:6d:27:96:e6:a4:cf:22:2e:7d -# SHA256 Fingerprint: 88:ef:81:de:20:2e:b0:18:45:2e:43:f8:64:72:5c:ea:5f:bd:1f:c2:d9:d2:05:73:07:09:c5:d8:b8:69:0f:46 ------BEGIN CERTIFICATE----- -MIIFYDCCA0igAwIBAgIULvWbAiin23r/1aOp7r0DoM8Sah0wDQYJKoZIhvcNAQEL -BQAwSDELMAkGA1UEBhMCQk0xGTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxHjAc -BgNVBAMTFVF1b1ZhZGlzIFJvb3QgQ0EgMyBHMzAeFw0xMjAxMTIyMDI2MzJaFw00 -MjAxMTIyMDI2MzJaMEgxCzAJBgNVBAYTAkJNMRkwFwYDVQQKExBRdW9WYWRpcyBM -aW1pdGVkMR4wHAYDVQQDExVRdW9WYWRpcyBSb290IENBIDMgRzMwggIiMA0GCSqG -SIb3DQEBAQUAA4ICDwAwggIKAoICAQCzyw4QZ47qFJenMioKVjZ/aEzHs286IxSR -/xl/pcqs7rN2nXrpixurazHb+gtTTK/FpRp5PIpM/6zfJd5O2YIyC0TeytuMrKNu -FoM7pmRLMon7FhY4futD4tN0SsJiCnMK3UmzV9KwCoWdcTzeo8vAMvMBOSBDGzXR -U7Ox7sWTaYI+FrUoRqHe6okJ7UO4BUaKhvVZR74bbwEhELn9qdIoyhA5CcoTNs+c -ra1AdHkrAj80//ogaX3T7mH1urPnMNA3I4ZyYUUpSFlob3emLoG+B01vr87ERROR -FHAGjx+f+IdpsQ7vw4kZ6+ocYfx6bIrc1gMLnia6Et3UVDmrJqMz6nWB2i3ND0/k -A9HvFZcba5DFApCTZgIhsUfei5pKgLlVj7WiL8DWM2fafsSntARE60f75li59wzw -eyuxwHApw0BiLTtIadwjPEjrewl5qW3aqDCYz4ByA4imW0aucnl8CAMhZa634Ryl -sSqiMd5mBPfAdOhx3v89WcyWJhKLhZVXGqtrdQtEPREoPHtht+KPZ0/l7DxMYIBp -VzgeAVuNVejH38DMdyM0SXV89pgR6y3e7UEuFAUCf+D+IOs15xGsIs5XPd7JMG0Q -A4XN8f+MFrXBsj6IbGB/kE+V9/YtrQE5BwT6dYB9v0lQ7e/JxHwc64B+27bQ3RP+ -ydOc17KXqQIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIB -BjAdBgNVHQ4EFgQUxhfQvKjqAkPyGwaZXSuQILnXnOQwDQYJKoZIhvcNAQELBQAD -ggIBADRh2Va1EodVTd2jNTFGu6QHcrxfYWLopfsLN7E8trP6KZ1/AvWkyaiTt3px -KGmPc+FSkNrVvjrlt3ZqVoAh313m6Tqe5T72omnHKgqwGEfcIHB9UqM+WXzBusnI -FUBhynLWcKzSt/Ac5IYp8M7vaGPQtSCKFWGafoaYtMnCdvvMujAWzKNhxnQT5Wvv -oxXqA/4Ti2Tk08HS6IT7SdEQTXlm66r99I0xHnAUrdzeZxNMgRVhvLfZkXdxGYFg -u/BYpbWcC/ePIlUnwEsBbTuZDdQdm2NnL9DuDcpmvJRPpq3t/O5jrFc/ZSXPsoaP -0Aj/uHYUbt7lJ+yreLVTubY/6CD50qi+YUbKh4yE8/nxoGibIh6BJpsQBJFxwAYf -3KDTuVan45gtf4Od34wrnDKOMpTwATwiKp9Dwi7DmDkHOHv8XgBCH/MyJnmDhPbl -8MFREsALHgQjDFSlTC9JxUrRtm5gDWv8a4uFJGS3iQ6rJUdbPM9+Sb3H6QrG2vd+ -DhcI00iX0HGS8A85PjRqHH3Y8iKuu2n0M7SmSFXRDw4m6Oy2Cy2nhTXN/VnIn9HN -PlopNLk9hM6xZdRZkZFWdSHBd575euFgndOtBBj0fOtek49TSiIp+EgrPk2GrFt/ -ywaZWWDYWGWVjUTR939+J399roD1B0y2PpxxVJkES/1Y+Zj0 ------END CERTIFICATE----- - -# Issuer: CN=DigiCert Assured ID Root G2 O=DigiCert Inc OU=www.digicert.com -# Subject: CN=DigiCert Assured ID Root G2 O=DigiCert Inc OU=www.digicert.com -# Label: "DigiCert Assured ID Root G2" -# Serial: 15385348160840213938643033620894905419 -# MD5 Fingerprint: 92:38:b9:f8:63:24:82:65:2c:57:33:e6:fe:81:8f:9d -# SHA1 Fingerprint: a1:4b:48:d9:43:ee:0a:0e:40:90:4f:3c:e0:a4:c0:91:93:51:5d:3f -# SHA256 Fingerprint: 7d:05:eb:b6:82:33:9f:8c:94:51:ee:09:4e:eb:fe:fa:79:53:a1:14:ed:b2:f4:49:49:45:2f:ab:7d:2f:c1:85 ------BEGIN CERTIFICATE----- -MIIDljCCAn6gAwIBAgIQC5McOtY5Z+pnI7/Dr5r0SzANBgkqhkiG9w0BAQsFADBl -MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 -d3cuZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJv -b3QgRzIwHhcNMTMwODAxMTIwMDAwWhcNMzgwMTE1MTIwMDAwWjBlMQswCQYDVQQG -EwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNl -cnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgRzIwggEi -MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDZ5ygvUj82ckmIkzTz+GoeMVSA -n61UQbVH35ao1K+ALbkKz3X9iaV9JPrjIgwrvJUXCzO/GU1BBpAAvQxNEP4Htecc -biJVMWWXvdMX0h5i89vqbFCMP4QMls+3ywPgym2hFEwbid3tALBSfK+RbLE4E9Hp -EgjAALAcKxHad3A2m67OeYfcgnDmCXRwVWmvo2ifv922ebPynXApVfSr/5Vh88lA -bx3RvpO704gqu52/clpWcTs/1PPRCv4o76Pu2ZmvA9OPYLfykqGxvYmJHzDNw6Yu -YjOuFgJ3RFrngQo8p0Quebg/BLxcoIfhG69Rjs3sLPr4/m3wOnyqi+RnlTGNAgMB -AAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgGGMB0GA1UdDgQW -BBTOw0q5mVXyuNtgv6l+vVa1lzan1jANBgkqhkiG9w0BAQsFAAOCAQEAyqVVjOPI -QW5pJ6d1Ee88hjZv0p3GeDgdaZaikmkuOGybfQTUiaWxMTeKySHMq2zNixya1r9I -0jJmwYrA8y8678Dj1JGG0VDjA9tzd29KOVPt3ibHtX2vK0LRdWLjSisCx1BL4Gni -lmwORGYQRI+tBev4eaymG+g3NJ1TyWGqolKvSnAWhsI6yLETcDbYz+70CjTVW0z9 -B5yiutkBclzzTcHdDrEcDcRjvq30FPuJ7KJBDkzMyFdA0G4Dqs0MjomZmWzwPDCv -ON9vvKO+KSAnq3T/EyJ43pdSVR6DtVQgA+6uwE9W3jfMw3+qBCe703e4YtsXfJwo -IhNzbM8m9Yop5w== ------END CERTIFICATE----- - -# Issuer: CN=DigiCert Assured ID Root G3 O=DigiCert Inc OU=www.digicert.com -# Subject: CN=DigiCert Assured ID Root G3 O=DigiCert Inc OU=www.digicert.com -# Label: "DigiCert Assured ID Root G3" -# Serial: 15459312981008553731928384953135426796 -# MD5 Fingerprint: 7c:7f:65:31:0c:81:df:8d:ba:3e:99:e2:5c:ad:6e:fb -# SHA1 Fingerprint: f5:17:a2:4f:9a:48:c6:c9:f8:a2:00:26:9f:dc:0f:48:2c:ab:30:89 -# SHA256 Fingerprint: 7e:37:cb:8b:4c:47:09:0c:ab:36:55:1b:a6:f4:5d:b8:40:68:0f:ba:16:6a:95:2d:b1:00:71:7f:43:05:3f:c2 ------BEGIN CERTIFICATE----- -MIICRjCCAc2gAwIBAgIQC6Fa+h3foLVJRK/NJKBs7DAKBggqhkjOPQQDAzBlMQsw -CQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cu -ZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3Qg -RzMwHhcNMTMwODAxMTIwMDAwWhcNMzgwMTE1MTIwMDAwWjBlMQswCQYDVQQGEwJV -UzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQu -Y29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgRzMwdjAQBgcq -hkjOPQIBBgUrgQQAIgNiAAQZ57ysRGXtzbg/WPuNsVepRC0FFfLvC/8QdJ+1YlJf -Zn4f5dwbRXkLzMZTCp2NXQLZqVneAlr2lSoOjThKiknGvMYDOAdfVdp+CW7if17Q -RSAPWXYQ1qAk8C3eNvJsKTmjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/ -BAQDAgGGMB0GA1UdDgQWBBTL0L2p4ZgFUaFNN6KDec6NHSrkhDAKBggqhkjOPQQD -AwNnADBkAjAlpIFFAmsSS3V0T8gj43DydXLefInwz5FyYZ5eEJJZVrmDxxDnOOlY -JjZ91eQ0hjkCMHw2U/Aw5WJjOpnitqM7mzT6HtoQknFekROn3aRukswy1vUhZscv -6pZjamVFkpUBtA== ------END CERTIFICATE----- - -# Issuer: CN=DigiCert Global Root G2 O=DigiCert Inc OU=www.digicert.com -# Subject: CN=DigiCert Global Root G2 O=DigiCert Inc OU=www.digicert.com -# Label: "DigiCert Global Root G2" -# Serial: 4293743540046975378534879503202253541 -# MD5 Fingerprint: e4:a6:8a:c8:54:ac:52:42:46:0a:fd:72:48:1b:2a:44 -# SHA1 Fingerprint: df:3c:24:f9:bf:d6:66:76:1b:26:80:73:fe:06:d1:cc:8d:4f:82:a4 -# SHA256 Fingerprint: cb:3c:cb:b7:60:31:e5:e0:13:8f:8d:d3:9a:23:f9:de:47:ff:c3:5e:43:c1:14:4c:ea:27:d4:6a:5a:b1:cb:5f ------BEGIN CERTIFICATE----- -MIIDjjCCAnagAwIBAgIQAzrx5qcRqaC7KGSxHQn65TANBgkqhkiG9w0BAQsFADBh -MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 -d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBH -MjAeFw0xMzA4MDExMjAwMDBaFw0zODAxMTUxMjAwMDBaMGExCzAJBgNVBAYTAlVT -MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5j -b20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IEcyMIIBIjANBgkqhkiG -9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuzfNNNx7a8myaJCtSnX/RrohCgiN9RlUyfuI -2/Ou8jqJkTx65qsGGmvPrC3oXgkkRLpimn7Wo6h+4FR1IAWsULecYxpsMNzaHxmx -1x7e/dfgy5SDN67sH0NO3Xss0r0upS/kqbitOtSZpLYl6ZtrAGCSYP9PIUkY92eQ -q2EGnI/yuum06ZIya7XzV+hdG82MHauVBJVJ8zUtluNJbd134/tJS7SsVQepj5Wz -tCO7TG1F8PapspUwtP1MVYwnSlcUfIKdzXOS0xZKBgyMUNGPHgm+F6HmIcr9g+UQ -vIOlCsRnKPZzFBQ9RnbDhxSJITRNrw9FDKZJobq7nMWxM4MphQIDAQABo0IwQDAP -BgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBhjAdBgNVHQ4EFgQUTiJUIBiV -5uNu5g/6+rkS7QYXjzkwDQYJKoZIhvcNAQELBQADggEBAGBnKJRvDkhj6zHd6mcY -1Yl9PMWLSn/pvtsrF9+wX3N3KjITOYFnQoQj8kVnNeyIv/iPsGEMNKSuIEyExtv4 -NeF22d+mQrvHRAiGfzZ0JFrabA0UWTW98kndth/Jsw1HKj2ZL7tcu7XUIOGZX1NG -Fdtom/DzMNU+MeKNhJ7jitralj41E6Vf8PlwUHBHQRFXGU7Aj64GxJUTFy8bJZ91 -8rGOmaFvE7FBcf6IKshPECBV1/MUReXgRPTqh5Uykw7+U0b6LJ3/iyK5S9kJRaTe -pLiaWN0bfVKfjllDiIGknibVb63dDcY3fe0Dkhvld1927jyNxF1WW6LZZm6zNTfl -MrY= ------END CERTIFICATE----- - -# Issuer: CN=DigiCert Global Root G3 O=DigiCert Inc OU=www.digicert.com -# Subject: CN=DigiCert Global Root G3 O=DigiCert Inc OU=www.digicert.com -# Label: "DigiCert Global Root G3" -# Serial: 7089244469030293291760083333884364146 -# MD5 Fingerprint: f5:5d:a4:50:a5:fb:28:7e:1e:0f:0d:cc:96:57:56:ca -# SHA1 Fingerprint: 7e:04:de:89:6a:3e:66:6d:00:e6:87:d3:3f:fa:d9:3b:e8:3d:34:9e -# SHA256 Fingerprint: 31:ad:66:48:f8:10:41:38:c7:38:f3:9e:a4:32:01:33:39:3e:3a:18:cc:02:29:6e:f9:7c:2a:c9:ef:67:31:d0 ------BEGIN CERTIFICATE----- -MIICPzCCAcWgAwIBAgIQBVVWvPJepDU1w6QP1atFcjAKBggqhkjOPQQDAzBhMQsw -CQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cu -ZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBHMzAe -Fw0xMzA4MDExMjAwMDBaFw0zODAxMTUxMjAwMDBaMGExCzAJBgNVBAYTAlVTMRUw -EwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20x -IDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IEczMHYwEAYHKoZIzj0CAQYF -K4EEACIDYgAE3afZu4q4C/sLfyHS8L6+c/MzXRq8NOrexpu80JX28MzQC7phW1FG -fp4tn+6OYwwX7Adw9c+ELkCDnOg/QW07rdOkFFk2eJ0DQ+4QE2xy3q6Ip6FrtUPO -Z9wj/wMco+I+o0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBhjAd -BgNVHQ4EFgQUs9tIpPmhxdiuNkHMEWNpYim8S8YwCgYIKoZIzj0EAwMDaAAwZQIx -AK288mw/EkrRLTnDCgmXc/SINoyIJ7vmiI1Qhadj+Z4y3maTD/HMsQmP3Wyr+mt/ -oAIwOWZbwmSNuJ5Q3KjVSaLtx9zRSX8XAbjIho9OjIgrqJqpisXRAL34VOKa5Vt8 -sycX ------END CERTIFICATE----- - -# Issuer: CN=DigiCert Trusted Root G4 O=DigiCert Inc OU=www.digicert.com -# Subject: CN=DigiCert Trusted Root G4 O=DigiCert Inc OU=www.digicert.com -# Label: "DigiCert Trusted Root G4" -# Serial: 7451500558977370777930084869016614236 -# MD5 Fingerprint: 78:f2:fc:aa:60:1f:2f:b4:eb:c9:37:ba:53:2e:75:49 -# SHA1 Fingerprint: dd:fb:16:cd:49:31:c9:73:a2:03:7d:3f:c8:3a:4d:7d:77:5d:05:e4 -# SHA256 Fingerprint: 55:2f:7b:dc:f1:a7:af:9e:6c:e6:72:01:7f:4f:12:ab:f7:72:40:c7:8e:76:1a:c2:03:d1:d9:d2:0a:c8:99:88 ------BEGIN CERTIFICATE----- -MIIFkDCCA3igAwIBAgIQBZsbV56OITLiOQe9p3d1XDANBgkqhkiG9w0BAQwFADBi -MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 -d3cuZGlnaWNlcnQuY29tMSEwHwYDVQQDExhEaWdpQ2VydCBUcnVzdGVkIFJvb3Qg -RzQwHhcNMTMwODAxMTIwMDAwWhcNMzgwMTE1MTIwMDAwWjBiMQswCQYDVQQGEwJV -UzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQu -Y29tMSEwHwYDVQQDExhEaWdpQ2VydCBUcnVzdGVkIFJvb3QgRzQwggIiMA0GCSqG -SIb3DQEBAQUAA4ICDwAwggIKAoICAQC/5pBzaN675F1KPDAiMGkz7MKnJS7JIT3y -ithZwuEppz1Yq3aaza57G4QNxDAf8xukOBbrVsaXbR2rsnnyyhHS5F/WBTxSD1If -xp4VpX6+n6lXFllVcq9ok3DCsrp1mWpzMpTREEQQLt+C8weE5nQ7bXHiLQwb7iDV -ySAdYyktzuxeTsiT+CFhmzTrBcZe7FsavOvJz82sNEBfsXpm7nfISKhmV1efVFiO -DCu3T6cw2Vbuyntd463JT17lNecxy9qTXtyOj4DatpGYQJB5w3jHtrHEtWoYOAMQ -jdjUN6QuBX2I9YI+EJFwq1WCQTLX2wRzKm6RAXwhTNS8rhsDdV14Ztk6MUSaM0C/ -CNdaSaTC5qmgZ92kJ7yhTzm1EVgX9yRcRo9k98FpiHaYdj1ZXUJ2h4mXaXpI8OCi -EhtmmnTK3kse5w5jrubU75KSOp493ADkRSWJtppEGSt+wJS00mFt6zPZxd9LBADM -fRyVw4/3IbKyEbe7f/LVjHAsQWCqsWMYRJUadmJ+9oCw++hkpjPRiQfhvbfmQ6QY -uKZ3AeEPlAwhHbJUKSWJbOUOUlFHdL4mrLZBdd56rF+NP8m800ERElvlEFDrMcXK -chYiCd98THU/Y+whX8QgUWtvsauGi0/C1kVfnSD8oR7FwI+isX4KJpn15GkvmB0t -9dmpsh3lGwIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIB -hjAdBgNVHQ4EFgQU7NfjgtJxXWRM3y5nP+e6mK4cD08wDQYJKoZIhvcNAQEMBQAD -ggIBALth2X2pbL4XxJEbw6GiAI3jZGgPVs93rnD5/ZpKmbnJeFwMDF/k5hQpVgs2 -SV1EY+CtnJYYZhsjDT156W1r1lT40jzBQ0CuHVD1UvyQO7uYmWlrx8GnqGikJ9yd -+SeuMIW59mdNOj6PWTkiU0TryF0Dyu1Qen1iIQqAyHNm0aAFYF/opbSnr6j3bTWc -fFqK1qI4mfN4i/RN0iAL3gTujJtHgXINwBQy7zBZLq7gcfJW5GqXb5JQbZaNaHqa -sjYUegbyJLkJEVDXCLG4iXqEI2FCKeWjzaIgQdfRnGTZ6iahixTXTBmyUEFxPT9N -cCOGDErcgdLMMpSEDQgJlxxPwO5rIHQw0uA5NBCFIRUBCOhVMt5xSdkoF1BN5r5N -0XWs0Mr7QbhDparTwwVETyw2m+L64kW4I1NsBm9nVX9GtUw/bihaeSbSpKhil9Ie -4u1Ki7wb/UdKDd9nZn6yW0HQO+T0O/QEY+nvwlQAUaCKKsnOeMzV6ocEGLPOr0mI -r/OSmbaz5mEP0oUA51Aa5BuVnRmhuZyxm7EAHu/QD09CbMkKvO5D+jpxpchNJqU1 -/YldvIViHTLSoCtU7ZpXwdv6EM8Zt4tKG48BtieVU+i2iW1bvGjUI+iLUaJW+fCm -gKDWHrO8Dw9TdSmq6hN35N6MgSGtBxBHEa2HPQfRdbzP82Z+ ------END CERTIFICATE----- - -# Issuer: CN=COMODO RSA Certification Authority O=COMODO CA Limited -# Subject: CN=COMODO RSA Certification Authority O=COMODO CA Limited -# Label: "COMODO RSA Certification Authority" -# Serial: 101909084537582093308941363524873193117 -# MD5 Fingerprint: 1b:31:b0:71:40:36:cc:14:36:91:ad:c4:3e:fd:ec:18 -# SHA1 Fingerprint: af:e5:d2:44:a8:d1:19:42:30:ff:47:9f:e2:f8:97:bb:cd:7a:8c:b4 -# SHA256 Fingerprint: 52:f0:e1:c4:e5:8e:c6:29:29:1b:60:31:7f:07:46:71:b8:5d:7e:a8:0d:5b:07:27:34:63:53:4b:32:b4:02:34 ------BEGIN CERTIFICATE----- -MIIF2DCCA8CgAwIBAgIQTKr5yttjb+Af907YWwOGnTANBgkqhkiG9w0BAQwFADCB -hTELMAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4G -A1UEBxMHU2FsZm9yZDEaMBgGA1UEChMRQ09NT0RPIENBIExpbWl0ZWQxKzApBgNV -BAMTIkNPTU9ETyBSU0EgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMTAwMTE5 -MDAwMDAwWhcNMzgwMTE4MjM1OTU5WjCBhTELMAkGA1UEBhMCR0IxGzAZBgNVBAgT -EkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEaMBgGA1UEChMR -Q09NT0RPIENBIExpbWl0ZWQxKzApBgNVBAMTIkNPTU9ETyBSU0EgQ2VydGlmaWNh -dGlvbiBBdXRob3JpdHkwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCR -6FSS0gpWsawNJN3Fz0RndJkrN6N9I3AAcbxT38T6KhKPS38QVr2fcHK3YX/JSw8X -pz3jsARh7v8Rl8f0hj4K+j5c+ZPmNHrZFGvnnLOFoIJ6dq9xkNfs/Q36nGz637CC -9BR++b7Epi9Pf5l/tfxnQ3K9DADWietrLNPtj5gcFKt+5eNu/Nio5JIk2kNrYrhV -/erBvGy2i/MOjZrkm2xpmfh4SDBF1a3hDTxFYPwyllEnvGfDyi62a+pGx8cgoLEf -Zd5ICLqkTqnyg0Y3hOvozIFIQ2dOciqbXL1MGyiKXCJ7tKuY2e7gUYPDCUZObT6Z -+pUX2nwzV0E8jVHtC7ZcryxjGt9XyD+86V3Em69FmeKjWiS0uqlWPc9vqv9JWL7w -qP/0uK3pN/u6uPQLOvnoQ0IeidiEyxPx2bvhiWC4jChWrBQdnArncevPDt09qZah -SL0896+1DSJMwBGB7FY79tOi4lu3sgQiUpWAk2nojkxl8ZEDLXB0AuqLZxUpaVIC -u9ffUGpVRr+goyhhf3DQw6KqLCGqR84onAZFdr+CGCe01a60y1Dma/RMhnEw6abf -Fobg2P9A3fvQQoh/ozM6LlweQRGBY84YcWsr7KaKtzFcOmpH4MN5WdYgGq/yapiq -crxXStJLnbsQ/LBMQeXtHT1eKJ2czL+zUdqnR+WEUwIDAQABo0IwQDAdBgNVHQ4E -FgQUu69+Aj36pvE8hI6t7jiY7NkyMtQwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB -/wQFMAMBAf8wDQYJKoZIhvcNAQEMBQADggIBAArx1UaEt65Ru2yyTUEUAJNMnMvl -wFTPoCWOAvn9sKIN9SCYPBMtrFaisNZ+EZLpLrqeLppysb0ZRGxhNaKatBYSaVqM -4dc+pBroLwP0rmEdEBsqpIt6xf4FpuHA1sj+nq6PK7o9mfjYcwlYRm6mnPTXJ9OV -2jeDchzTc+CiR5kDOF3VSXkAKRzH7JsgHAckaVd4sjn8OoSgtZx8jb8uk2Intzna -FxiuvTwJaP+EmzzV1gsD41eeFPfR60/IvYcjt7ZJQ3mFXLrrkguhxuhoqEwWsRqZ -CuhTLJK7oQkYdQxlqHvLI7cawiiFwxv/0Cti76R7CZGYZ4wUAc1oBmpjIXUDgIiK -boHGhfKppC3n9KUkEEeDys30jXlYsQab5xoq2Z0B15R97QNKyvDb6KkBPvVWmcke -jkk9u+UJueBPSZI9FoJAzMxZxuY67RIuaTxslbH9qh17f4a+Hg4yRvv7E491f0yL -S0Zj/gA0QHDBw7mh3aZw4gSzQbzpgJHqZJx64SIDqZxubw5lT2yHh17zbqD5daWb -QOhTsiedSrnAdyGN/4fy3ryM7xfft0kL0fJuMAsaDk527RH89elWsn2/x20Kk4yl -0MC2Hb46TpSi125sC8KKfPog88Tk5c0NqMuRkrF8hey1FGlmDoLnzc7ILaZRfyHB -NVOFBkpdn627G190 ------END CERTIFICATE----- - -# Issuer: CN=USERTrust RSA Certification Authority O=The USERTRUST Network -# Subject: CN=USERTrust RSA Certification Authority O=The USERTRUST Network -# Label: "USERTrust RSA Certification Authority" -# Serial: 2645093764781058787591871645665788717 -# MD5 Fingerprint: 1b:fe:69:d1:91:b7:19:33:a3:72:a8:0f:e1:55:e5:b5 -# SHA1 Fingerprint: 2b:8f:1b:57:33:0d:bb:a2:d0:7a:6c:51:f7:0e:e9:0d:da:b9:ad:8e -# SHA256 Fingerprint: e7:93:c9:b0:2f:d8:aa:13:e2:1c:31:22:8a:cc:b0:81:19:64:3b:74:9c:89:89:64:b1:74:6d:46:c3:d4:cb:d2 ------BEGIN CERTIFICATE----- -MIIF3jCCA8agAwIBAgIQAf1tMPyjylGoG7xkDjUDLTANBgkqhkiG9w0BAQwFADCB -iDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0pl -cnNleSBDaXR5MR4wHAYDVQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNV -BAMTJVVTRVJUcnVzdCBSU0EgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMTAw -MjAxMDAwMDAwWhcNMzgwMTE4MjM1OTU5WjCBiDELMAkGA1UEBhMCVVMxEzARBgNV -BAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0plcnNleSBDaXR5MR4wHAYDVQQKExVU -aGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNVBAMTJVVTRVJUcnVzdCBSU0EgQ2Vy -dGlmaWNhdGlvbiBBdXRob3JpdHkwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIK -AoICAQCAEmUXNg7D2wiz0KxXDXbtzSfTTK1Qg2HiqiBNCS1kCdzOiZ/MPans9s/B -3PHTsdZ7NygRK0faOca8Ohm0X6a9fZ2jY0K2dvKpOyuR+OJv0OwWIJAJPuLodMkY -tJHUYmTbf6MG8YgYapAiPLz+E/CHFHv25B+O1ORRxhFnRghRy4YUVD+8M/5+bJz/ -Fp0YvVGONaanZshyZ9shZrHUm3gDwFA66Mzw3LyeTP6vBZY1H1dat//O+T23LLb2 -VN3I5xI6Ta5MirdcmrS3ID3KfyI0rn47aGYBROcBTkZTmzNg95S+UzeQc0PzMsNT -79uq/nROacdrjGCT3sTHDN/hMq7MkztReJVni+49Vv4M0GkPGw/zJSZrM233bkf6 -c0Plfg6lZrEpfDKEY1WJxA3Bk1QwGROs0303p+tdOmw1XNtB1xLaqUkL39iAigmT -Yo61Zs8liM2EuLE/pDkP2QKe6xJMlXzzawWpXhaDzLhn4ugTncxbgtNMs+1b/97l -c6wjOy0AvzVVdAlJ2ElYGn+SNuZRkg7zJn0cTRe8yexDJtC/QV9AqURE9JnnV4ee -UB9XVKg+/XRjL7FQZQnmWEIuQxpMtPAlR1n6BB6T1CZGSlCBst6+eLf8ZxXhyVeE -Hg9j1uliutZfVS7qXMYoCAQlObgOK6nyTJccBz8NUvXt7y+CDwIDAQABo0IwQDAd -BgNVHQ4EFgQUU3m/WqorSs9UgOHYm8Cd8rIDZsswDgYDVR0PAQH/BAQDAgEGMA8G -A1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEMBQADggIBAFzUfA3P9wF9QZllDHPF -Up/L+M+ZBn8b2kMVn54CVVeWFPFSPCeHlCjtHzoBN6J2/FNQwISbxmtOuowhT6KO -VWKR82kV2LyI48SqC/3vqOlLVSoGIG1VeCkZ7l8wXEskEVX/JJpuXior7gtNn3/3 -ATiUFJVDBwn7YKnuHKsSjKCaXqeYalltiz8I+8jRRa8YFWSQEg9zKC7F4iRO/Fjs -8PRF/iKz6y+O0tlFYQXBl2+odnKPi4w2r78NBc5xjeambx9spnFixdjQg3IM8WcR -iQycE0xyNN+81XHfqnHd4blsjDwSXWXavVcStkNr/+XeTWYRUc+ZruwXtuhxkYze -Sf7dNXGiFSeUHM9h4ya7b6NnJSFd5t0dCy5oGzuCr+yDZ4XUmFF0sbmZgIn/f3gZ -XHlKYC6SQK5MNyosycdiyA5d9zZbyuAlJQG03RoHnHcAP9Dc1ew91Pq7P8yF1m9/ -qS3fuQL39ZeatTXaw2ewh0qpKJ4jjv9cJ2vhsE/zB+4ALtRZh8tSQZXq9EfX7mRB -VXyNWQKV3WKdwrnuWih0hKWbt5DHDAff9Yk2dDLWKMGwsAvgnEzDHNb842m1R0aB -L6KCq9NjRHDEjf8tM7qtj3u1cIiuPhnPQCjY/MiQu12ZIvVS5ljFH4gxQ+6IHdfG -jjxDah2nGN59PRbxYvnKkKj9 ------END CERTIFICATE----- - -# Issuer: CN=USERTrust ECC Certification Authority O=The USERTRUST Network -# Subject: CN=USERTrust ECC Certification Authority O=The USERTRUST Network -# Label: "USERTrust ECC Certification Authority" -# Serial: 123013823720199481456569720443997572134 -# MD5 Fingerprint: fa:68:bc:d9:b5:7f:ad:fd:c9:1d:06:83:28:cc:24:c1 -# SHA1 Fingerprint: d1:cb:ca:5d:b2:d5:2a:7f:69:3b:67:4d:e5:f0:5a:1d:0c:95:7d:f0 -# SHA256 Fingerprint: 4f:f4:60:d5:4b:9c:86:da:bf:bc:fc:57:12:e0:40:0d:2b:ed:3f:bc:4d:4f:bd:aa:86:e0:6a:dc:d2:a9:ad:7a ------BEGIN CERTIFICATE----- -MIICjzCCAhWgAwIBAgIQXIuZxVqUxdJxVt7NiYDMJjAKBggqhkjOPQQDAzCBiDEL -MAkGA1UEBhMCVVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0plcnNl -eSBDaXR5MR4wHAYDVQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNVBAMT -JVVTRVJUcnVzdCBFQ0MgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMTAwMjAx -MDAwMDAwWhcNMzgwMTE4MjM1OTU5WjCBiDELMAkGA1UEBhMCVVMxEzARBgNVBAgT -Ck5ldyBKZXJzZXkxFDASBgNVBAcTC0plcnNleSBDaXR5MR4wHAYDVQQKExVUaGUg -VVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNVBAMTJVVTRVJUcnVzdCBFQ0MgQ2VydGlm -aWNhdGlvbiBBdXRob3JpdHkwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAAQarFRaqflo -I+d61SRvU8Za2EurxtW20eZzca7dnNYMYf3boIkDuAUU7FfO7l0/4iGzzvfUinng -o4N+LZfQYcTxmdwlkWOrfzCjtHDix6EznPO/LlxTsV+zfTJ/ijTjeXmjQjBAMB0G -A1UdDgQWBBQ64QmG1M8ZwpZ2dEl23OA1xmNjmjAOBgNVHQ8BAf8EBAMCAQYwDwYD -VR0TAQH/BAUwAwEB/zAKBggqhkjOPQQDAwNoADBlAjA2Z6EWCNzklwBBHU6+4WMB -zzuqQhFkoJ2UOQIReVx7Hfpkue4WQrO/isIJxOzksU0CMQDpKmFHjFJKS04YcPbW -RNZu9YO6bVi9JNlWSOrvxKJGgYhqOkbRqZtNyWHa0V1Xahg= ------END CERTIFICATE----- - -# Issuer: CN=GlobalSign O=GlobalSign OU=GlobalSign ECC Root CA - R5 -# Subject: CN=GlobalSign O=GlobalSign OU=GlobalSign ECC Root CA - R5 -# Label: "GlobalSign ECC Root CA - R5" -# Serial: 32785792099990507226680698011560947931244 -# MD5 Fingerprint: 9f:ad:3b:1c:02:1e:8a:ba:17:74:38:81:0c:a2:bc:08 -# SHA1 Fingerprint: 1f:24:c6:30:cd:a4:18:ef:20:69:ff:ad:4f:dd:5f:46:3a:1b:69:aa -# SHA256 Fingerprint: 17:9f:bc:14:8a:3d:d0:0f:d2:4e:a1:34:58:cc:43:bf:a7:f5:9c:81:82:d7:83:a5:13:f6:eb:ec:10:0c:89:24 ------BEGIN CERTIFICATE----- -MIICHjCCAaSgAwIBAgIRYFlJ4CYuu1X5CneKcflK2GwwCgYIKoZIzj0EAwMwUDEk -MCIGA1UECxMbR2xvYmFsU2lnbiBFQ0MgUm9vdCBDQSAtIFI1MRMwEQYDVQQKEwpH -bG9iYWxTaWduMRMwEQYDVQQDEwpHbG9iYWxTaWduMB4XDTEyMTExMzAwMDAwMFoX -DTM4MDExOTAzMTQwN1owUDEkMCIGA1UECxMbR2xvYmFsU2lnbiBFQ0MgUm9vdCBD -QSAtIFI1MRMwEQYDVQQKEwpHbG9iYWxTaWduMRMwEQYDVQQDEwpHbG9iYWxTaWdu -MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAER0UOlvt9Xb/pOdEh+J8LttV7HpI6SFkc -8GIxLcB6KP4ap1yztsyX50XUWPrRd21DosCHZTQKH3rd6zwzocWdTaRvQZU4f8ke -hOvRnkmSh5SHDDqFSmafnVmTTZdhBoZKo0IwQDAOBgNVHQ8BAf8EBAMCAQYwDwYD -VR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUPeYpSJvqB8ohREom3m7e0oPQn1kwCgYI -KoZIzj0EAwMDaAAwZQIxAOVpEslu28YxuglB4Zf4+/2a4n0Sye18ZNPLBSWLVtmg -515dTguDnFt2KaAJJiFqYgIwcdK1j1zqO+F4CYWodZI7yFz9SO8NdCKoCOJuxUnO -xwy8p2Fp8fc74SrL+SvzZpA3 ------END CERTIFICATE----- - -# Issuer: CN=IdenTrust Commercial Root CA 1 O=IdenTrust -# Subject: CN=IdenTrust Commercial Root CA 1 O=IdenTrust -# Label: "IdenTrust Commercial Root CA 1" -# Serial: 13298821034946342390520003877796839426 -# MD5 Fingerprint: b3:3e:77:73:75:ee:a0:d3:e3:7e:49:63:49:59:bb:c7 -# SHA1 Fingerprint: df:71:7e:aa:4a:d9:4e:c9:55:84:99:60:2d:48:de:5f:bc:f0:3a:25 -# SHA256 Fingerprint: 5d:56:49:9b:e4:d2:e0:8b:cf:ca:d0:8a:3e:38:72:3d:50:50:3b:de:70:69:48:e4:2f:55:60:30:19:e5:28:ae ------BEGIN CERTIFICATE----- -MIIFYDCCA0igAwIBAgIQCgFCgAAAAUUjyES1AAAAAjANBgkqhkiG9w0BAQsFADBK -MQswCQYDVQQGEwJVUzESMBAGA1UEChMJSWRlblRydXN0MScwJQYDVQQDEx5JZGVu -VHJ1c3QgQ29tbWVyY2lhbCBSb290IENBIDEwHhcNMTQwMTE2MTgxMjIzWhcNMzQw -MTE2MTgxMjIzWjBKMQswCQYDVQQGEwJVUzESMBAGA1UEChMJSWRlblRydXN0MScw -JQYDVQQDEx5JZGVuVHJ1c3QgQ29tbWVyY2lhbCBSb290IENBIDEwggIiMA0GCSqG -SIb3DQEBAQUAA4ICDwAwggIKAoICAQCnUBneP5k91DNG8W9RYYKyqU+PZ4ldhNlT -3Qwo2dfw/66VQ3KZ+bVdfIrBQuExUHTRgQ18zZshq0PirK1ehm7zCYofWjK9ouuU -+ehcCuz/mNKvcbO0U59Oh++SvL3sTzIwiEsXXlfEU8L2ApeN2WIrvyQfYo3fw7gp -S0l4PJNgiCL8mdo2yMKi1CxUAGc1bnO/AljwpN3lsKImesrgNqUZFvX9t++uP0D1 -bVoE/c40yiTcdCMbXTMTEl3EASX2MN0CXZ/g1Ue9tOsbobtJSdifWwLziuQkkORi -T0/Br4sOdBeo0XKIanoBScy0RnnGF7HamB4HWfp1IYVl3ZBWzvurpWCdxJ35UrCL -vYf5jysjCiN2O/cz4ckA82n5S6LgTrx+kzmEB/dEcH7+B1rlsazRGMzyNeVJSQjK -Vsk9+w8YfYs7wRPCTY/JTw436R+hDmrfYi7LNQZReSzIJTj0+kuniVyc0uMNOYZK -dHzVWYfCP04MXFL0PfdSgvHqo6z9STQaKPNBiDoT7uje/5kdX7rL6B7yuVBgwDHT -c+XvvqDtMwt0viAgxGds8AgDelWAf0ZOlqf0Hj7h9tgJ4TNkK2PXMl6f+cB7D3hv -l7yTmvmcEpB4eoCHFddydJxVdHixuuFucAS6T6C6aMN7/zHwcz09lCqxC0EOoP5N -iGVreTO01wIDAQABo0IwQDAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB -/zAdBgNVHQ4EFgQU7UQZwNPwBovupHu+QucmVMiONnYwDQYJKoZIhvcNAQELBQAD -ggIBAA2ukDL2pkt8RHYZYR4nKM1eVO8lvOMIkPkp165oCOGUAFjvLi5+U1KMtlwH -6oi6mYtQlNeCgN9hCQCTrQ0U5s7B8jeUeLBfnLOic7iPBZM4zY0+sLj7wM+x8uwt -LRvM7Kqas6pgghstO8OEPVeKlh6cdbjTMM1gCIOQ045U8U1mwF10A0Cj7oV+wh93 -nAbowacYXVKV7cndJZ5t+qntozo00Fl72u1Q8zW/7esUTTHHYPTa8Yec4kjixsU3 -+wYQ+nVZZjFHKdp2mhzpgq7vmrlR94gjmmmVYjzlVYA211QC//G5Xc7UI2/YRYRK -W2XviQzdFKcgyxilJbQN+QHwotL0AMh0jqEqSI5l2xPE4iUXfeu+h1sXIFRRk0pT -AwvsXcoz7WL9RccvW9xYoIA55vrX/hMUpu09lEpCdNTDd1lzzY9GvlU47/rokTLq -l1gEIt44w8y8bckzOmoKaT+gyOpyj4xjhiO9bTyWnpXgSUyqorkqG5w2gXjtw+hG -4iZZRHUe2XWJUc0QhJ1hYMtd+ZciTY6Y5uN/9lu7rs3KSoFrXgvzUeF0K+l+J6fZ -mUlO+KWA2yUPHGNiiskzZ2s8EIPGrd6ozRaOjfAHN3Gf8qv8QfXBi+wAN10J5U6A -7/qxXDgGpRtK4dw4LTzcqx+QGtVKnO7RcGzM7vRX+Bi6hG6H ------END CERTIFICATE----- - -# Issuer: CN=IdenTrust Public Sector Root CA 1 O=IdenTrust -# Subject: CN=IdenTrust Public Sector Root CA 1 O=IdenTrust -# Label: "IdenTrust Public Sector Root CA 1" -# Serial: 13298821034946342390521976156843933698 -# MD5 Fingerprint: 37:06:a5:b0:fc:89:9d:ba:f4:6b:8c:1a:64:cd:d5:ba -# SHA1 Fingerprint: ba:29:41:60:77:98:3f:f4:f3:ef:f2:31:05:3b:2e:ea:6d:4d:45:fd -# SHA256 Fingerprint: 30:d0:89:5a:9a:44:8a:26:20:91:63:55:22:d1:f5:20:10:b5:86:7a:ca:e1:2c:78:ef:95:8f:d4:f4:38:9f:2f ------BEGIN CERTIFICATE----- -MIIFZjCCA06gAwIBAgIQCgFCgAAAAUUjz0Z8AAAAAjANBgkqhkiG9w0BAQsFADBN -MQswCQYDVQQGEwJVUzESMBAGA1UEChMJSWRlblRydXN0MSowKAYDVQQDEyFJZGVu -VHJ1c3QgUHVibGljIFNlY3RvciBSb290IENBIDEwHhcNMTQwMTE2MTc1MzMyWhcN -MzQwMTE2MTc1MzMyWjBNMQswCQYDVQQGEwJVUzESMBAGA1UEChMJSWRlblRydXN0 -MSowKAYDVQQDEyFJZGVuVHJ1c3QgUHVibGljIFNlY3RvciBSb290IENBIDEwggIi -MA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC2IpT8pEiv6EdrCvsnduTyP4o7 -ekosMSqMjbCpwzFrqHd2hCa2rIFCDQjrVVi7evi8ZX3yoG2LqEfpYnYeEe4IFNGy -RBb06tD6Hi9e28tzQa68ALBKK0CyrOE7S8ItneShm+waOh7wCLPQ5CQ1B5+ctMlS -bdsHyo+1W/CD80/HLaXIrcuVIKQxKFdYWuSNG5qrng0M8gozOSI5Cpcu81N3uURF -/YTLNiCBWS2ab21ISGHKTN9T0a9SvESfqy9rg3LvdYDaBjMbXcjaY8ZNzaxmMc3R -3j6HEDbhuaR672BQssvKplbgN6+rNBM5Jeg5ZuSYeqoSmJxZZoY+rfGwyj4GD3vw -EUs3oERte8uojHH01bWRNszwFcYr3lEXsZdMUD2xlVl8BX0tIdUAvwFnol57plzy -9yLxkA2T26pEUWbMfXYD62qoKjgZl3YNa4ph+bz27nb9cCvdKTz4Ch5bQhyLVi9V -GxyhLrXHFub4qjySjmm2AcG1hp2JDws4lFTo6tyePSW8Uybt1as5qsVATFSrsrTZ -2fjXctscvG29ZV/viDUqZi/u9rNl8DONfJhBaUYPQxxp+pu10GFqzcpL2UyQRqsV -WaFHVCkugyhfHMKiq3IXAAaOReyL4jM9f9oZRORicsPfIsbyVtTdX5Vy7W1f90gD -W/3FKqD2cyOEEBsB5wIDAQABo0IwQDAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/ -BAUwAwEB/zAdBgNVHQ4EFgQU43HgntinQtnbcZFrlJPrw6PRFKMwDQYJKoZIhvcN -AQELBQADggIBAEf63QqwEZE4rU1d9+UOl1QZgkiHVIyqZJnYWv6IAcVYpZmxI1Qj -t2odIFflAWJBF9MJ23XLblSQdf4an4EKwt3X9wnQW3IV5B4Jaj0z8yGa5hV+rVHV -DRDtfULAj+7AmgjVQdZcDiFpboBhDhXAuM/FSRJSzL46zNQuOAXeNf0fb7iAaJg9 -TaDKQGXSc3z1i9kKlT/YPyNtGtEqJBnZhbMX73huqVjRI9PHE+1yJX9dsXNw0H8G -lwmEKYBhHfpe/3OsoOOJuBxxFcbeMX8S3OFtm6/n6J91eEyrRjuazr8FGF1NFTwW -mhlQBJqymm9li1JfPFgEKCXAZmExfrngdbkaqIHWchezxQMxNRF4eKLg6TCMf4Df -WN88uieW4oA0beOY02QnrEh+KHdcxiVhJfiFDGX6xDIvpZgF5PgLZxYWxoK4Mhn5 -+bl53B/N66+rDt0b20XkeucC4pVd/GnwU2lhlXV5C15V5jgclKlZM57IcXR5f1GJ -tshquDDIajjDbp7hNxbqBWJMWxJH7ae0s1hWx0nzfxJoCTFx8G34Tkf71oXuxVhA -GaQdp/lLQzfcaFpPz+vCZHTetBXZ9FRUGi8c15dxVJCO2SCdUyt/q4/i6jC8UDfv -8Ue1fXwsBOxonbRJRBD0ckscZOf85muQ3Wl9af0AVqW3rLatt8o+Ae+c ------END CERTIFICATE----- - -# Issuer: CN=CFCA EV ROOT O=China Financial Certification Authority -# Subject: CN=CFCA EV ROOT O=China Financial Certification Authority -# Label: "CFCA EV ROOT" -# Serial: 407555286 -# MD5 Fingerprint: 74:e1:b6:ed:26:7a:7a:44:30:33:94:ab:7b:27:81:30 -# SHA1 Fingerprint: e2:b8:29:4b:55:84:ab:6b:58:c2:90:46:6c:ac:3f:b8:39:8f:84:83 -# SHA256 Fingerprint: 5c:c3:d7:8e:4e:1d:5e:45:54:7a:04:e6:87:3e:64:f9:0c:f9:53:6d:1c:cc:2e:f8:00:f3:55:c4:c5:fd:70:fd ------BEGIN CERTIFICATE----- -MIIFjTCCA3WgAwIBAgIEGErM1jANBgkqhkiG9w0BAQsFADBWMQswCQYDVQQGEwJD -TjEwMC4GA1UECgwnQ2hpbmEgRmluYW5jaWFsIENlcnRpZmljYXRpb24gQXV0aG9y -aXR5MRUwEwYDVQQDDAxDRkNBIEVWIFJPT1QwHhcNMTIwODA4MDMwNzAxWhcNMjkx -MjMxMDMwNzAxWjBWMQswCQYDVQQGEwJDTjEwMC4GA1UECgwnQ2hpbmEgRmluYW5j -aWFsIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MRUwEwYDVQQDDAxDRkNBIEVWIFJP -T1QwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDXXWvNED8fBVnVBU03 -sQ7smCuOFR36k0sXgiFxEFLXUWRwFsJVaU2OFW2fvwwbwuCjZ9YMrM8irq93VCpL -TIpTUnrD7i7es3ElweldPe6hL6P3KjzJIx1qqx2hp/Hz7KDVRM8Vz3IvHWOX6Jn5 -/ZOkVIBMUtRSqy5J35DNuF++P96hyk0g1CXohClTt7GIH//62pCfCqktQT+x8Rgp -7hZZLDRJGqgG16iI0gNyejLi6mhNbiyWZXvKWfry4t3uMCz7zEasxGPrb382KzRz -EpR/38wmnvFyXVBlWY9ps4deMm/DGIq1lY+wejfeWkU7xzbh72fROdOXW3NiGUgt -hxwG+3SYIElz8AXSG7Ggo7cbcNOIabla1jj0Ytwli3i/+Oh+uFzJlU9fpy25IGvP -a931DfSCt/SyZi4QKPaXWnuWFo8BGS1sbn85WAZkgwGDg8NNkt0yxoekN+kWzqot -aK8KgWU6cMGbrU1tVMoqLUuFG7OA5nBFDWteNfB/O7ic5ARwiRIlk9oKmSJgamNg -TnYGmE69g60dWIolhdLHZR4tjsbftsbhf4oEIRUpdPA+nJCdDC7xij5aqgwJHsfV -PKPtl8MeNPo4+QgO48BdK4PRVmrJtqhUUy54Mmc9gn900PvhtgVguXDbjgv5E1hv -cWAQUhC5wUEJ73IfZzF4/5YFjQIDAQABo2MwYTAfBgNVHSMEGDAWgBTj/i39KNAL -tbq2osS/BqoFjJP7LzAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAd -BgNVHQ4EFgQU4/4t/SjQC7W6tqLEvwaqBYyT+y8wDQYJKoZIhvcNAQELBQADggIB -ACXGumvrh8vegjmWPfBEp2uEcwPenStPuiB/vHiyz5ewG5zz13ku9Ui20vsXiObT -ej/tUxPQ4i9qecsAIyjmHjdXNYmEwnZPNDatZ8POQQaIxffu2Bq41gt/UP+TqhdL -jOztUmCypAbqTuv0axn96/Ua4CUqmtzHQTb3yHQFhDmVOdYLO6Qn+gjYXB74BGBS -ESgoA//vU2YApUo0FmZ8/Qmkrp5nGm9BC2sGE5uPhnEFtC+NiWYzKXZUmhH4J/qy -P5Hgzg0b8zAarb8iXRvTvyUFTeGSGn+ZnzxEk8rUQElsgIfXBDrDMlI1Dlb4pd19 -xIsNER9Tyx6yF7Zod1rg1MvIB671Oi6ON7fQAUtDKXeMOZePglr4UeWJoBjnaH9d -Ci77o0cOPaYjesYBx4/IXr9tgFa+iiS6M+qf4TIRnvHST4D2G0CvOJ4RUHlzEhLN -5mydLIhyPDCBBpEi6lmt2hkuIsKNuYyH4Ga8cyNfIWRjgEj1oDwYPZTISEEdQLpe -/v5WOaHIz16eGWRGENoXkbcFgKyLmZJ956LYBws2J+dIeWCKw9cTXPhyQN9Ky8+Z -AAoACxGV2lZFA4gKn2fQ1XmxqI1AbQ3CekD6819kR5LLU7m7Wc5P/dAVUwHY3+vZ -5nbv0CO7O6l5s9UCKc2Jo5YPSjXnTkLAdc0Hz+Ys63su ------END CERTIFICATE----- - -# Issuer: CN=OISTE WISeKey Global Root GB CA O=WISeKey OU=OISTE Foundation Endorsed -# Subject: CN=OISTE WISeKey Global Root GB CA O=WISeKey OU=OISTE Foundation Endorsed -# Label: "OISTE WISeKey Global Root GB CA" -# Serial: 157768595616588414422159278966750757568 -# MD5 Fingerprint: a4:eb:b9:61:28:2e:b7:2f:98:b0:35:26:90:99:51:1d -# SHA1 Fingerprint: 0f:f9:40:76:18:d3:d7:6a:4b:98:f0:a8:35:9e:0c:fd:27:ac:cc:ed -# SHA256 Fingerprint: 6b:9c:08:e8:6e:b0:f7:67:cf:ad:65:cd:98:b6:21:49:e5:49:4a:67:f5:84:5e:7b:d1:ed:01:9f:27:b8:6b:d6 ------BEGIN CERTIFICATE----- -MIIDtTCCAp2gAwIBAgIQdrEgUnTwhYdGs/gjGvbCwDANBgkqhkiG9w0BAQsFADBt -MQswCQYDVQQGEwJDSDEQMA4GA1UEChMHV0lTZUtleTEiMCAGA1UECxMZT0lTVEUg -Rm91bmRhdGlvbiBFbmRvcnNlZDEoMCYGA1UEAxMfT0lTVEUgV0lTZUtleSBHbG9i -YWwgUm9vdCBHQiBDQTAeFw0xNDEyMDExNTAwMzJaFw0zOTEyMDExNTEwMzFaMG0x -CzAJBgNVBAYTAkNIMRAwDgYDVQQKEwdXSVNlS2V5MSIwIAYDVQQLExlPSVNURSBG -b3VuZGF0aW9uIEVuZG9yc2VkMSgwJgYDVQQDEx9PSVNURSBXSVNlS2V5IEdsb2Jh -bCBSb290IEdCIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA2Be3 -HEokKtaXscriHvt9OO+Y9bI5mE4nuBFde9IllIiCFSZqGzG7qFshISvYD06fWvGx -WuR51jIjK+FTzJlFXHtPrby/h0oLS5daqPZI7H17Dc0hBt+eFf1Biki3IPShehtX -1F1Q/7pn2COZH8g/497/b1t3sWtuuMlk9+HKQUYOKXHQuSP8yYFfTvdv37+ErXNk -u7dCjmn21HYdfp2nuFeKUWdy19SouJVUQHMD9ur06/4oQnc/nSMbsrY9gBQHTC5P -99UKFg29ZkM3fiNDecNAhvVMKdqOmq0NpQSHiB6F4+lT1ZvIiwNjeOvgGUpuuy9r -M2RYk61pv48b74JIxwIDAQABo1EwTzALBgNVHQ8EBAMCAYYwDwYDVR0TAQH/BAUw -AwEB/zAdBgNVHQ4EFgQUNQ/INmNe4qPs+TtmFc5RUuORmj0wEAYJKwYBBAGCNxUB -BAMCAQAwDQYJKoZIhvcNAQELBQADggEBAEBM+4eymYGQfp3FsLAmzYh7KzKNbrgh -cViXfa43FK8+5/ea4n32cZiZBKpDdHij40lhPnOMTZTg+XHEthYOU3gf1qKHLwI5 -gSk8rxWYITD+KJAAjNHhy/peyP34EEY7onhCkRd0VQreUGdNZtGn//3ZwLWoo4rO -ZvUPQ82nK1d7Y0Zqqi5S2PTt4W2tKZB4SLrhI6qjiey1q5bAtEuiHZeeevJuQHHf -aPFlTc58Bd9TZaml8LGXBHAVRgOY1NK/VLSgWH1Sb9pWJmLU2NuJMW8c8CLC02Ic -Nc1MaRVUGpCY3useX8p3x8uOPUNpnJpY0CQ73xtAln41rYHHTnG6iBM= ------END CERTIFICATE----- - -# Issuer: CN=SZAFIR ROOT CA2 O=Krajowa Izba Rozliczeniowa S.A. -# Subject: CN=SZAFIR ROOT CA2 O=Krajowa Izba Rozliczeniowa S.A. -# Label: "SZAFIR ROOT CA2" -# Serial: 357043034767186914217277344587386743377558296292 -# MD5 Fingerprint: 11:64:c1:89:b0:24:b1:8c:b1:07:7e:89:9e:51:9e:99 -# SHA1 Fingerprint: e2:52:fa:95:3f:ed:db:24:60:bd:6e:28:f3:9c:cc:cf:5e:b3:3f:de -# SHA256 Fingerprint: a1:33:9d:33:28:1a:0b:56:e5:57:d3:d3:2b:1c:e7:f9:36:7e:b0:94:bd:5f:a7:2a:7e:50:04:c8:de:d7:ca:fe ------BEGIN CERTIFICATE----- -MIIDcjCCAlqgAwIBAgIUPopdB+xV0jLVt+O2XwHrLdzk1uQwDQYJKoZIhvcNAQEL -BQAwUTELMAkGA1UEBhMCUEwxKDAmBgNVBAoMH0tyYWpvd2EgSXpiYSBSb3psaWN6 -ZW5pb3dhIFMuQS4xGDAWBgNVBAMMD1NaQUZJUiBST09UIENBMjAeFw0xNTEwMTkw -NzQzMzBaFw0zNTEwMTkwNzQzMzBaMFExCzAJBgNVBAYTAlBMMSgwJgYDVQQKDB9L -cmFqb3dhIEl6YmEgUm96bGljemVuaW93YSBTLkEuMRgwFgYDVQQDDA9TWkFGSVIg -Uk9PVCBDQTIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC3vD5QqEvN -QLXOYeeWyrSh2gwisPq1e3YAd4wLz32ohswmUeQgPYUM1ljj5/QqGJ3a0a4m7utT -3PSQ1hNKDJA8w/Ta0o4NkjrcsbH/ON7Dui1fgLkCvUqdGw+0w8LBZwPd3BucPbOw -3gAeqDRHu5rr/gsUvTaE2g0gv/pby6kWIK05YO4vdbbnl5z5Pv1+TW9NL++IDWr6 -3fE9biCloBK0TXC5ztdyO4mTp4CEHCdJckm1/zuVnsHMyAHs6A6KCpbns6aH5db5 -BSsNl0BwPLqsdVqc1U2dAgrSS5tmS0YHF2Wtn2yIANwiieDhZNRnvDF5YTy7ykHN -XGoAyDw4jlivAgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQD -AgEGMB0GA1UdDgQWBBQuFqlKGLXLzPVvUPMjX/hd56zwyDANBgkqhkiG9w0BAQsF -AAOCAQEAtXP4A9xZWx126aMqe5Aosk3AM0+qmrHUuOQn/6mWmc5G4G18TKI4pAZw -8PRBEew/R40/cof5O/2kbytTAOD/OblqBw7rHRz2onKQy4I9EYKL0rufKq8h5mOG -nXkZ7/e7DDWQw4rtTw/1zBLZpD67oPwglV9PJi8RI4NOdQcPv5vRtB3pEAT+ymCP -oky4rc/hkA/NrgrHXXu3UNLUYfrVFdvXn4dRVOul4+vJhaAlIDf7js4MNIThPIGy -d05DpYhfhmehPea0XGG2Ptv+tyjFogeutcrKjSoS75ftwjCkySp6+/NNIxuZMzSg -LvWpCz/UXeHPhJ/iGcJfitYgHuNztw== ------END CERTIFICATE----- - -# Issuer: CN=Certum Trusted Network CA 2 O=Unizeto Technologies S.A. OU=Certum Certification Authority -# Subject: CN=Certum Trusted Network CA 2 O=Unizeto Technologies S.A. OU=Certum Certification Authority -# Label: "Certum Trusted Network CA 2" -# Serial: 44979900017204383099463764357512596969 -# MD5 Fingerprint: 6d:46:9e:d9:25:6d:08:23:5b:5e:74:7d:1e:27:db:f2 -# SHA1 Fingerprint: d3:dd:48:3e:2b:bf:4c:05:e8:af:10:f5:fa:76:26:cf:d3:dc:30:92 -# SHA256 Fingerprint: b6:76:f2:ed:da:e8:77:5c:d3:6c:b0:f6:3c:d1:d4:60:39:61:f4:9e:62:65:ba:01:3a:2f:03:07:b6:d0:b8:04 ------BEGIN CERTIFICATE----- -MIIF0jCCA7qgAwIBAgIQIdbQSk8lD8kyN/yqXhKN6TANBgkqhkiG9w0BAQ0FADCB -gDELMAkGA1UEBhMCUEwxIjAgBgNVBAoTGVVuaXpldG8gVGVjaG5vbG9naWVzIFMu -QS4xJzAlBgNVBAsTHkNlcnR1bSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTEkMCIG -A1UEAxMbQ2VydHVtIFRydXN0ZWQgTmV0d29yayBDQSAyMCIYDzIwMTExMDA2MDgz -OTU2WhgPMjA0NjEwMDYwODM5NTZaMIGAMQswCQYDVQQGEwJQTDEiMCAGA1UEChMZ -VW5pemV0byBUZWNobm9sb2dpZXMgUy5BLjEnMCUGA1UECxMeQ2VydHVtIENlcnRp -ZmljYXRpb24gQXV0aG9yaXR5MSQwIgYDVQQDExtDZXJ0dW0gVHJ1c3RlZCBOZXR3 -b3JrIENBIDIwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC9+Xj45tWA -DGSdhhuWZGc/IjoedQF97/tcZ4zJzFxrqZHmuULlIEub2pt7uZld2ZuAS9eEQCsn -0+i6MLs+CRqnSZXvK0AkwpfHp+6bJe+oCgCXhVqqndwpyeI1B+twTUrWwbNWuKFB -OJvR+zF/j+Bf4bE/D44WSWDXBo0Y+aomEKsq09DRZ40bRr5HMNUuctHFY9rnY3lE -fktjJImGLjQ/KUxSiyqnwOKRKIm5wFv5HdnnJ63/mgKXwcZQkpsCLL2puTRZCr+E -Sv/f/rOf69me4Jgj7KZrdxYq28ytOxykh9xGc14ZYmhFV+SQgkK7QtbwYeDBoz1m -o130GO6IyY0XRSmZMnUCMe4pJshrAua1YkV/NxVaI2iJ1D7eTiew8EAMvE0Xy02i -sx7QBlrd9pPPV3WZ9fqGGmd4s7+W/jTcvedSVuWz5XV710GRBdxdaeOVDUO5/IOW -OZV7bIBaTxNyxtd9KXpEulKkKtVBRgkg/iKgtlswjbyJDNXXcPiHUv3a76xRLgez -Tv7QCdpw75j6VuZt27VXS9zlLCUVyJ4ueE742pyehizKV/Ma5ciSixqClnrDvFAS -adgOWkaLOusm+iPJtrCBvkIApPjW/jAux9JG9uWOdf3yzLnQh1vMBhBgu4M1t15n -3kfsmUjxpKEV/q2MYo45VU85FrmxY53/twIDAQABo0IwQDAPBgNVHRMBAf8EBTAD -AQH/MB0GA1UdDgQWBBS2oVQ5AsOgP46KvPrU+Bym0ToO/TAOBgNVHQ8BAf8EBAMC -AQYwDQYJKoZIhvcNAQENBQADggIBAHGlDs7k6b8/ONWJWsQCYftMxRQXLYtPU2sQ -F/xlhMcQSZDe28cmk4gmb3DWAl45oPePq5a1pRNcgRRtDoGCERuKTsZPpd1iHkTf -CVn0W3cLN+mLIMb4Ck4uWBzrM9DPhmDJ2vuAL55MYIR4PSFk1vtBHxgP58l1cb29 -XN40hz5BsA72udY/CROWFC/emh1auVbONTqwX3BNXuMp8SMoclm2q8KMZiYcdywm -djWLKKdpoPk79SPdhRB0yZADVpHnr7pH1BKXESLjokmUbOe3lEu6LaTaM4tMpkT/ -WjzGHWTYtTHkpjx6qFcL2+1hGsvxznN3Y6SHb0xRONbkX8eftoEq5IVIeVheO/jb -AoJnwTnbw3RLPTYe+SmTiGhbqEQZIfCn6IENLOiTNrQ3ssqwGyZ6miUfmpqAnksq -P/ujmv5zMnHCnsZy4YpoJ/HkD7TETKVhk/iXEAcqMCWpuchxuO9ozC1+9eB+D4Ko -b7a6bINDd82Kkhehnlt4Fj1F4jNy3eFmypnTycUm/Q1oBEauttmbjL4ZvrHG8hnj -XALKLNhvSgfZyTXaQHXyxKcZb55CEJh15pWLYLztxRLXis7VmFxWlgPF7ncGNf/P -5O4/E2Hu29othfDNrp2yGAlFw5Khchf8R7agCyzxxN5DaAhqXzvwdmP7zAYspsbi -DrW5viSP ------END CERTIFICATE----- - -# Issuer: CN=Hellenic Academic and Research Institutions RootCA 2015 O=Hellenic Academic and Research Institutions Cert. Authority -# Subject: CN=Hellenic Academic and Research Institutions RootCA 2015 O=Hellenic Academic and Research Institutions Cert. Authority -# Label: "Hellenic Academic and Research Institutions RootCA 2015" -# Serial: 0 -# MD5 Fingerprint: ca:ff:e2:db:03:d9:cb:4b:e9:0f:ad:84:fd:7b:18:ce -# SHA1 Fingerprint: 01:0c:06:95:a6:98:19:14:ff:bf:5f:c6:b0:b6:95:ea:29:e9:12:a6 -# SHA256 Fingerprint: a0:40:92:9a:02:ce:53:b4:ac:f4:f2:ff:c6:98:1c:e4:49:6f:75:5e:6d:45:fe:0b:2a:69:2b:cd:52:52:3f:36 ------BEGIN CERTIFICATE----- -MIIGCzCCA/OgAwIBAgIBADANBgkqhkiG9w0BAQsFADCBpjELMAkGA1UEBhMCR1Ix -DzANBgNVBAcTBkF0aGVuczFEMEIGA1UEChM7SGVsbGVuaWMgQWNhZGVtaWMgYW5k -IFJlc2VhcmNoIEluc3RpdHV0aW9ucyBDZXJ0LiBBdXRob3JpdHkxQDA+BgNVBAMT -N0hlbGxlbmljIEFjYWRlbWljIGFuZCBSZXNlYXJjaCBJbnN0aXR1dGlvbnMgUm9v -dENBIDIwMTUwHhcNMTUwNzA3MTAxMTIxWhcNNDAwNjMwMTAxMTIxWjCBpjELMAkG -A1UEBhMCR1IxDzANBgNVBAcTBkF0aGVuczFEMEIGA1UEChM7SGVsbGVuaWMgQWNh -ZGVtaWMgYW5kIFJlc2VhcmNoIEluc3RpdHV0aW9ucyBDZXJ0LiBBdXRob3JpdHkx -QDA+BgNVBAMTN0hlbGxlbmljIEFjYWRlbWljIGFuZCBSZXNlYXJjaCBJbnN0aXR1 -dGlvbnMgUm9vdENBIDIwMTUwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoIC -AQDC+Kk/G4n8PDwEXT2QNrCROnk8ZlrvbTkBSRq0t89/TSNTt5AA4xMqKKYx8ZEA -4yjsriFBzh/a/X0SWwGDD7mwX5nh8hKDgE0GPt+sr+ehiGsxr/CL0BgzuNtFajT0 -AoAkKAoCFZVedioNmToUW/bLy1O8E00BiDeUJRtCvCLYjqOWXjrZMts+6PAQZe10 -4S+nfK8nNLspfZu2zwnI5dMK/IhlZXQK3HMcXM1AsRzUtoSMTFDPaI6oWa7CJ06C -ojXdFPQf/7J31Ycvqm59JCfnxssm5uX+Zwdj2EUN3TpZZTlYepKZcj2chF6IIbjV -9Cz82XBST3i4vTwri5WY9bPRaM8gFH5MXF/ni+X1NYEZN9cRCLdmvtNKzoNXADrD -gfgXy5I2XdGj2HUb4Ysn6npIQf1FGQatJ5lOwXBH3bWfgVMS5bGMSF0xQxfjjMZ6 -Y5ZLKTBOhE5iGV48zpeQpX8B653g+IuJ3SWYPZK2fu/Z8VFRfS0myGlZYeCsargq -NhEEelC9MoS+L9xy1dcdFkfkR2YgP/SWxa+OAXqlD3pk9Q0Yh9muiNX6hME6wGko -LfINaFGq46V3xqSQDqE3izEjR8EJCOtu93ib14L8hCCZSRm2Ekax+0VVFqmjZayc -Bw/qa9wfLgZy7IaIEuQt218FL+TwA9MmM+eAws1CoRc0CwIDAQABo0IwQDAPBgNV -HRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUcRVnyMjJvXVd -ctA4GGqd83EkVAswDQYJKoZIhvcNAQELBQADggIBAHW7bVRLqhBYRjTyYtcWNl0I -XtVsyIe9tC5G8jH4fOpCtZMWVdyhDBKg2mF+D1hYc2Ryx+hFjtyp8iY/xnmMsVMI -M4GwVhO+5lFc2JsKT0ucVlMC6U/2DWDqTUJV6HwbISHTGzrMd/K4kPFox/la/vot -9L/J9UUbzjgQKjeKeaO04wlshYaT/4mWJ3iBj2fjRnRUjtkNaeJK9E10A/+yd+2V -Z5fkscWrv2oj6NSU4kQoYsRL4vDY4ilrGnB+JGGTe08DMiUNRSQrlrRGar9KC/ea -j8GsGsVn82800vpzY4zvFrCopEYq+OsS7HK07/grfoxSwIuEVPkvPuNVqNxmsdnh -X9izjFk0WaSrT2y7HxjbdavYy5LNlDhhDgcGH0tGEPEVvo2FXDtKK4F5D7Rpn0lQ -l033DlZdwJVqwjbDG2jJ9SrcR5q+ss7FJej6A7na+RZukYT1HCjI/CbM1xyQVqdf -bzoEvM14iQuODy+jqk+iGxI9FghAD/FGTNeqewjBCvVtJ94Cj8rDtSvK6evIIVM4 -pcw72Hc3MKJP2W/R8kCtQXoXxdZKNYm3QdV8hn9VTYNKpXMgwDqvkPGaJI7ZjnHK -e7iG2rKPmT4dEw0SEe7Uq/DpFXYC5ODfqiAeW2GFZECpkJcNrVPSWh2HagCXZWK0 -vm9qp/UsQu0yrbYhnr68 ------END CERTIFICATE----- - -# Issuer: CN=Hellenic Academic and Research Institutions ECC RootCA 2015 O=Hellenic Academic and Research Institutions Cert. Authority -# Subject: CN=Hellenic Academic and Research Institutions ECC RootCA 2015 O=Hellenic Academic and Research Institutions Cert. Authority -# Label: "Hellenic Academic and Research Institutions ECC RootCA 2015" -# Serial: 0 -# MD5 Fingerprint: 81:e5:b4:17:eb:c2:f5:e1:4b:0d:41:7b:49:92:fe:ef -# SHA1 Fingerprint: 9f:f1:71:8d:92:d5:9a:f3:7d:74:97:b4:bc:6f:84:68:0b:ba:b6:66 -# SHA256 Fingerprint: 44:b5:45:aa:8a:25:e6:5a:73:ca:15:dc:27:fc:36:d2:4c:1c:b9:95:3a:06:65:39:b1:15:82:dc:48:7b:48:33 ------BEGIN CERTIFICATE----- -MIICwzCCAkqgAwIBAgIBADAKBggqhkjOPQQDAjCBqjELMAkGA1UEBhMCR1IxDzAN -BgNVBAcTBkF0aGVuczFEMEIGA1UEChM7SGVsbGVuaWMgQWNhZGVtaWMgYW5kIFJl -c2VhcmNoIEluc3RpdHV0aW9ucyBDZXJ0LiBBdXRob3JpdHkxRDBCBgNVBAMTO0hl -bGxlbmljIEFjYWRlbWljIGFuZCBSZXNlYXJjaCBJbnN0aXR1dGlvbnMgRUNDIFJv -b3RDQSAyMDE1MB4XDTE1MDcwNzEwMzcxMloXDTQwMDYzMDEwMzcxMlowgaoxCzAJ -BgNVBAYTAkdSMQ8wDQYDVQQHEwZBdGhlbnMxRDBCBgNVBAoTO0hlbGxlbmljIEFj -YWRlbWljIGFuZCBSZXNlYXJjaCBJbnN0aXR1dGlvbnMgQ2VydC4gQXV0aG9yaXR5 -MUQwQgYDVQQDEztIZWxsZW5pYyBBY2FkZW1pYyBhbmQgUmVzZWFyY2ggSW5zdGl0 -dXRpb25zIEVDQyBSb290Q0EgMjAxNTB2MBAGByqGSM49AgEGBSuBBAAiA2IABJKg -QehLgoRc4vgxEZmGZE4JJS+dQS8KrjVPdJWyUWRrjWvmP3CV8AVER6ZyOFB2lQJa -jq4onvktTpnvLEhvTCUp6NFxW98dwXU3tNf6e3pCnGoKVlp8aQuqgAkkbH7BRqNC -MEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFLQi -C4KZJAEOnLvkDv2/+5cgk5kqMAoGCCqGSM49BAMCA2cAMGQCMGfOFmI4oqxiRaep -lSTAGiecMjvAwNW6qef4BENThe5SId6d9SWDPp5YSy/XZxMOIQIwBeF1Ad5o7Sof -TUwJCA3sS61kFyjndc5FZXIhF8siQQ6ME5g4mlRtm8rifOoCWCKR ------END CERTIFICATE----- - -# Issuer: CN=ISRG Root X1 O=Internet Security Research Group -# Subject: CN=ISRG Root X1 O=Internet Security Research Group -# Label: "ISRG Root X1" -# Serial: 172886928669790476064670243504169061120 -# MD5 Fingerprint: 0c:d2:f9:e0:da:17:73:e9:ed:86:4d:a5:e3:70:e7:4e -# SHA1 Fingerprint: ca:bd:2a:79:a1:07:6a:31:f2:1d:25:36:35:cb:03:9d:43:29:a5:e8 -# SHA256 Fingerprint: 96:bc:ec:06:26:49:76:f3:74:60:77:9a:cf:28:c5:a7:cf:e8:a3:c0:aa:e1:1a:8f:fc:ee:05:c0:bd:df:08:c6 ------BEGIN CERTIFICATE----- -MIIFazCCA1OgAwIBAgIRAIIQz7DSQONZRGPgu2OCiwAwDQYJKoZIhvcNAQELBQAw -TzELMAkGA1UEBhMCVVMxKTAnBgNVBAoTIEludGVybmV0IFNlY3VyaXR5IFJlc2Vh -cmNoIEdyb3VwMRUwEwYDVQQDEwxJU1JHIFJvb3QgWDEwHhcNMTUwNjA0MTEwNDM4 -WhcNMzUwNjA0MTEwNDM4WjBPMQswCQYDVQQGEwJVUzEpMCcGA1UEChMgSW50ZXJu -ZXQgU2VjdXJpdHkgUmVzZWFyY2ggR3JvdXAxFTATBgNVBAMTDElTUkcgUm9vdCBY -MTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAK3oJHP0FDfzm54rVygc -h77ct984kIxuPOZXoHj3dcKi/vVqbvYATyjb3miGbESTtrFj/RQSa78f0uoxmyF+ -0TM8ukj13Xnfs7j/EvEhmkvBioZxaUpmZmyPfjxwv60pIgbz5MDmgK7iS4+3mX6U -A5/TR5d8mUgjU+g4rk8Kb4Mu0UlXjIB0ttov0DiNewNwIRt18jA8+o+u3dpjq+sW -T8KOEUt+zwvo/7V3LvSye0rgTBIlDHCNAymg4VMk7BPZ7hm/ELNKjD+Jo2FR3qyH -B5T0Y3HsLuJvW5iB4YlcNHlsdu87kGJ55tukmi8mxdAQ4Q7e2RCOFvu396j3x+UC -B5iPNgiV5+I3lg02dZ77DnKxHZu8A/lJBdiB3QW0KtZB6awBdpUKD9jf1b0SHzUv -KBds0pjBqAlkd25HN7rOrFleaJ1/ctaJxQZBKT5ZPt0m9STJEadao0xAH0ahmbWn -OlFuhjuefXKnEgV4We0+UXgVCwOPjdAvBbI+e0ocS3MFEvzG6uBQE3xDk3SzynTn -jh8BCNAw1FtxNrQHusEwMFxIt4I7mKZ9YIqioymCzLq9gwQbooMDQaHWBfEbwrbw -qHyGO0aoSCqI3Haadr8faqU9GY/rOPNk3sgrDQoo//fb4hVC1CLQJ13hef4Y53CI -rU7m2Ys6xt0nUW7/vGT1M0NPAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNV -HRMBAf8EBTADAQH/MB0GA1UdDgQWBBR5tFnme7bl5AFzgAiIyBpY9umbbjANBgkq -hkiG9w0BAQsFAAOCAgEAVR9YqbyyqFDQDLHYGmkgJykIrGF1XIpu+ILlaS/V9lZL -ubhzEFnTIZd+50xx+7LSYK05qAvqFyFWhfFQDlnrzuBZ6brJFe+GnY+EgPbk6ZGQ -3BebYhtF8GaV0nxvwuo77x/Py9auJ/GpsMiu/X1+mvoiBOv/2X/qkSsisRcOj/KK -NFtY2PwByVS5uCbMiogziUwthDyC3+6WVwW6LLv3xLfHTjuCvjHIInNzktHCgKQ5 -ORAzI4JMPJ+GslWYHb4phowim57iaztXOoJwTdwJx4nLCgdNbOhdjsnvzqvHu7Ur -TkXWStAmzOVyyghqpZXjFaH3pO3JLF+l+/+sKAIuvtd7u+Nxe5AW0wdeRlN8NwdC -jNPElpzVmbUq4JUagEiuTDkHzsxHpFKVK7q4+63SM1N95R1NbdWhscdCb+ZAJzVc -oyi3B43njTOQ5yOf+1CceWxG1bQVs5ZufpsMljq4Ui0/1lvh+wjChP4kqKOJ2qxq -4RgqsahDYVvTH9w7jXbyLeiNdd8XM2w9U/t7y0Ff/9yi0GE44Za4rF2LN9d11TPA -mRGunUHBcnWEvgJBQl9nJEiU0Zsnvgc/ubhPgXRR4Xq37Z0j4r7g1SgEEzwxA57d -emyPxgcYxn/eR44/KJ4EBs+lVDR3veyJm+kXQ99b21/+jh5Xos1AnX5iItreGCc= ------END CERTIFICATE----- - -# Issuer: O=FNMT-RCM OU=AC RAIZ FNMT-RCM -# Subject: O=FNMT-RCM OU=AC RAIZ FNMT-RCM -# Label: "AC RAIZ FNMT-RCM" -# Serial: 485876308206448804701554682760554759 -# MD5 Fingerprint: e2:09:04:b4:d3:bd:d1:a0:14:fd:1a:d2:47:c4:57:1d -# SHA1 Fingerprint: ec:50:35:07:b2:15:c4:95:62:19:e2:a8:9a:5b:42:99:2c:4c:2c:20 -# SHA256 Fingerprint: eb:c5:57:0c:29:01:8c:4d:67:b1:aa:12:7b:af:12:f7:03:b4:61:1e:bc:17:b7:da:b5:57:38:94:17:9b:93:fa ------BEGIN CERTIFICATE----- -MIIFgzCCA2ugAwIBAgIPXZONMGc2yAYdGsdUhGkHMA0GCSqGSIb3DQEBCwUAMDsx -CzAJBgNVBAYTAkVTMREwDwYDVQQKDAhGTk1ULVJDTTEZMBcGA1UECwwQQUMgUkFJ -WiBGTk1ULVJDTTAeFw0wODEwMjkxNTU5NTZaFw0zMDAxMDEwMDAwMDBaMDsxCzAJ -BgNVBAYTAkVTMREwDwYDVQQKDAhGTk1ULVJDTTEZMBcGA1UECwwQQUMgUkFJWiBG -Tk1ULVJDTTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBALpxgHpMhm5/ -yBNtwMZ9HACXjywMI7sQmkCpGreHiPibVmr75nuOi5KOpyVdWRHbNi63URcfqQgf -BBckWKo3Shjf5TnUV/3XwSyRAZHiItQDwFj8d0fsjz50Q7qsNI1NOHZnjrDIbzAz -WHFctPVrbtQBULgTfmxKo0nRIBnuvMApGGWn3v7v3QqQIecaZ5JCEJhfTzC8PhxF -tBDXaEAUwED653cXeuYLj2VbPNmaUtu1vZ5Gzz3rkQUCwJaydkxNEJY7kvqcfw+Z -374jNUUeAlz+taibmSXaXvMiwzn15Cou08YfxGyqxRxqAQVKL9LFwag0Jl1mpdIC -IfkYtwb1TplvqKtMUejPUBjFd8g5CSxJkjKZqLsXF3mwWsXmo8RZZUc1g16p6DUL -mbvkzSDGm0oGObVo/CK67lWMK07q87Hj/LaZmtVC+nFNCM+HHmpxffnTtOmlcYF7 -wk5HlqX2doWjKI/pgG6BU6VtX7hI+cL5NqYuSf+4lsKMB7ObiFj86xsc3i1w4peS -MKGJ47xVqCfWS+2QrYv6YyVZLag13cqXM7zlzced0ezvXg5KkAYmY6252TUtB7p2 -ZSysV4999AeU14ECll2jB0nVetBX+RvnU0Z1qrB5QstocQjpYL05ac70r8NWQMet -UqIJ5G+GR4of6ygnXYMgrwTJbFaai0b1AgMBAAGjgYMwgYAwDwYDVR0TAQH/BAUw -AwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFPd9xf3E6Jobd2Sn9R2gzL+H -YJptMD4GA1UdIAQ3MDUwMwYEVR0gADArMCkGCCsGAQUFBwIBFh1odHRwOi8vd3d3 -LmNlcnQuZm5tdC5lcy9kcGNzLzANBgkqhkiG9w0BAQsFAAOCAgEAB5BK3/MjTvDD -nFFlm5wioooMhfNzKWtN/gHiqQxjAb8EZ6WdmF/9ARP67Jpi6Yb+tmLSbkyU+8B1 -RXxlDPiyN8+sD8+Nb/kZ94/sHvJwnvDKuO+3/3Y3dlv2bojzr2IyIpMNOmqOFGYM -LVN0V2Ue1bLdI4E7pWYjJ2cJj+F3qkPNZVEI7VFY/uY5+ctHhKQV8Xa7pO6kO8Rf -77IzlhEYt8llvhjho6Tc+hj507wTmzl6NLrTQfv6MooqtyuGC2mDOL7Nii4LcK2N -JpLuHvUBKwrZ1pebbuCoGRw6IYsMHkCtA+fdZn71uSANA+iW+YJF1DngoABd15jm -fZ5nc8OaKveri6E6FO80vFIOiZiaBECEHX5FaZNXzuvO+FB8TxxuBEOb+dY7Ixjp -6o7RTUaN8Tvkasq6+yO3m/qZASlaWFot4/nUbQ4mrcFuNLwy+AwF+mWj2zs3gyLp -1txyM/1d8iC9djwj2ij3+RvrWWTV3F9yfiD8zYm1kGdNYno/Tq0dwzn+evQoFt9B -9kiABdcPUXmsEKvU7ANm5mqwujGSQkBqvjrTcuFqN1W8rB2Vt2lh8kORdOag0wok -RqEIr9baRRmW1FMdW4R58MD3R++Lj8UGrp1MYp3/RgT408m2ECVAdf4WqslKYIYv -uu8wd+RU4riEmViAqhOLUTpPSPaLtrM= ------END CERTIFICATE----- - -# Issuer: CN=Amazon Root CA 1 O=Amazon -# Subject: CN=Amazon Root CA 1 O=Amazon -# Label: "Amazon Root CA 1" -# Serial: 143266978916655856878034712317230054538369994 -# MD5 Fingerprint: 43:c6:bf:ae:ec:fe:ad:2f:18:c6:88:68:30:fc:c8:e6 -# SHA1 Fingerprint: 8d:a7:f9:65:ec:5e:fc:37:91:0f:1c:6e:59:fd:c1:cc:6a:6e:de:16 -# SHA256 Fingerprint: 8e:cd:e6:88:4f:3d:87:b1:12:5b:a3:1a:c3:fc:b1:3d:70:16:de:7f:57:cc:90:4f:e1:cb:97:c6:ae:98:19:6e ------BEGIN CERTIFICATE----- -MIIDQTCCAimgAwIBAgITBmyfz5m/jAo54vB4ikPmljZbyjANBgkqhkiG9w0BAQsF -ADA5MQswCQYDVQQGEwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6 -b24gUm9vdCBDQSAxMB4XDTE1MDUyNjAwMDAwMFoXDTM4MDExNzAwMDAwMFowOTEL -MAkGA1UEBhMCVVMxDzANBgNVBAoTBkFtYXpvbjEZMBcGA1UEAxMQQW1hem9uIFJv -b3QgQ0EgMTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALJ4gHHKeNXj -ca9HgFB0fW7Y14h29Jlo91ghYPl0hAEvrAIthtOgQ3pOsqTQNroBvo3bSMgHFzZM -9O6II8c+6zf1tRn4SWiw3te5djgdYZ6k/oI2peVKVuRF4fn9tBb6dNqcmzU5L/qw -IFAGbHrQgLKm+a/sRxmPUDgH3KKHOVj4utWp+UhnMJbulHheb4mjUcAwhmahRWa6 -VOujw5H5SNz/0egwLX0tdHA114gk957EWW67c4cX8jJGKLhD+rcdqsq08p8kDi1L -93FcXmn/6pUCyziKrlA4b9v7LWIbxcceVOF34GfID5yHI9Y/QCB/IIDEgEw+OyQm -jgSubJrIqg0CAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMC -AYYwHQYDVR0OBBYEFIQYzIU07LwMlJQuCFmcx7IQTgoIMA0GCSqGSIb3DQEBCwUA -A4IBAQCY8jdaQZChGsV2USggNiMOruYou6r4lK5IpDB/G/wkjUu0yKGX9rbxenDI -U5PMCCjjmCXPI6T53iHTfIUJrU6adTrCC2qJeHZERxhlbI1Bjjt/msv0tadQ1wUs -N+gDS63pYaACbvXy8MWy7Vu33PqUXHeeE6V/Uq2V8viTO96LXFvKWlJbYK8U90vv -o/ufQJVtMVT8QtPHRh8jrdkPSHCa2XV4cdFyQzR1bldZwgJcJmApzyMZFo6IQ6XU -5MsI+yMRQ+hDKXJioaldXgjUkK642M4UwtBV8ob2xJNDd2ZhwLnoQdeXeGADbkpy -rqXRfboQnoZsG4q5WTP468SQvvG5 ------END CERTIFICATE----- - -# Issuer: CN=Amazon Root CA 2 O=Amazon -# Subject: CN=Amazon Root CA 2 O=Amazon -# Label: "Amazon Root CA 2" -# Serial: 143266982885963551818349160658925006970653239 -# MD5 Fingerprint: c8:e5:8d:ce:a8:42:e2:7a:c0:2a:5c:7c:9e:26:bf:66 -# SHA1 Fingerprint: 5a:8c:ef:45:d7:a6:98:59:76:7a:8c:8b:44:96:b5:78:cf:47:4b:1a -# SHA256 Fingerprint: 1b:a5:b2:aa:8c:65:40:1a:82:96:01:18:f8:0b:ec:4f:62:30:4d:83:ce:c4:71:3a:19:c3:9c:01:1e:a4:6d:b4 ------BEGIN CERTIFICATE----- -MIIFQTCCAymgAwIBAgITBmyf0pY1hp8KD+WGePhbJruKNzANBgkqhkiG9w0BAQwF -ADA5MQswCQYDVQQGEwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6 -b24gUm9vdCBDQSAyMB4XDTE1MDUyNjAwMDAwMFoXDTQwMDUyNjAwMDAwMFowOTEL -MAkGA1UEBhMCVVMxDzANBgNVBAoTBkFtYXpvbjEZMBcGA1UEAxMQQW1hem9uIFJv -b3QgQ0EgMjCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAK2Wny2cSkxK -gXlRmeyKy2tgURO8TW0G/LAIjd0ZEGrHJgw12MBvIITplLGbhQPDW9tK6Mj4kHbZ -W0/jTOgGNk3Mmqw9DJArktQGGWCsN0R5hYGCrVo34A3MnaZMUnbqQ523BNFQ9lXg -1dKmSYXpN+nKfq5clU1Imj+uIFptiJXZNLhSGkOQsL9sBbm2eLfq0OQ6PBJTYv9K -8nu+NQWpEjTj82R0Yiw9AElaKP4yRLuH3WUnAnE72kr3H9rN9yFVkE8P7K6C4Z9r -2UXTu/Bfh+08LDmG2j/e7HJV63mjrdvdfLC6HM783k81ds8P+HgfajZRRidhW+me -z/CiVX18JYpvL7TFz4QuK/0NURBs+18bvBt+xa47mAExkv8LV/SasrlX6avvDXbR -8O70zoan4G7ptGmh32n2M8ZpLpcTnqWHsFcQgTfJU7O7f/aS0ZzQGPSSbtqDT6Zj -mUyl+17vIWR6IF9sZIUVyzfpYgwLKhbcAS4y2j5L9Z469hdAlO+ekQiG+r5jqFoz -7Mt0Q5X5bGlSNscpb/xVA1wf+5+9R+vnSUeVC06JIglJ4PVhHvG/LopyboBZ/1c6 -+XUyo05f7O0oYtlNc/LMgRdg7c3r3NunysV+Ar3yVAhU/bQtCSwXVEqY0VThUWcI -0u1ufm8/0i2BWSlmy5A5lREedCf+3euvAgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMB -Af8wDgYDVR0PAQH/BAQDAgGGMB0GA1UdDgQWBBSwDPBMMPQFWAJI/TPlUq9LhONm -UjANBgkqhkiG9w0BAQwFAAOCAgEAqqiAjw54o+Ci1M3m9Zh6O+oAA7CXDpO8Wqj2 -LIxyh6mx/H9z/WNxeKWHWc8w4Q0QshNabYL1auaAn6AFC2jkR2vHat+2/XcycuUY -+gn0oJMsXdKMdYV2ZZAMA3m3MSNjrXiDCYZohMr/+c8mmpJ5581LxedhpxfL86kS -k5Nrp+gvU5LEYFiwzAJRGFuFjWJZY7attN6a+yb3ACfAXVU3dJnJUH/jWS5E4ywl -7uxMMne0nxrpS10gxdr9HIcWxkPo1LsmmkVwXqkLN1PiRnsn/eBG8om3zEK2yygm -btmlyTrIQRNg91CMFa6ybRoVGld45pIq2WWQgj9sAq+uEjonljYE1x2igGOpm/Hl -urR8FLBOybEfdF849lHqm/osohHUqS0nGkWxr7JOcQ3AWEbWaQbLU8uz/mtBzUF+ -fUwPfHJ5elnNXkoOrJupmHN5fLT0zLm4BwyydFy4x2+IoZCn9Kr5v2c69BoVYh63 -n749sSmvZ6ES8lgQGVMDMBu4Gon2nL2XA46jCfMdiyHxtN/kHNGfZQIG6lzWE7OE -76KlXIx3KadowGuuQNKotOrN8I1LOJwZmhsoVLiJkO/KdYE+HvJkJMcYr07/R54H -9jVlpNMKVv/1F2Rs76giJUmTtt8AF9pYfl3uxRuw0dFfIRDH+fO6AgonB8Xx1sfT -4PsJYGw= ------END CERTIFICATE----- - -# Issuer: CN=Amazon Root CA 3 O=Amazon -# Subject: CN=Amazon Root CA 3 O=Amazon -# Label: "Amazon Root CA 3" -# Serial: 143266986699090766294700635381230934788665930 -# MD5 Fingerprint: a0:d4:ef:0b:f7:b5:d8:49:95:2a:ec:f5:c4:fc:81:87 -# SHA1 Fingerprint: 0d:44:dd:8c:3c:8c:1a:1a:58:75:64:81:e9:0f:2e:2a:ff:b3:d2:6e -# SHA256 Fingerprint: 18:ce:6c:fe:7b:f1:4e:60:b2:e3:47:b8:df:e8:68:cb:31:d0:2e:bb:3a:da:27:15:69:f5:03:43:b4:6d:b3:a4 ------BEGIN CERTIFICATE----- -MIIBtjCCAVugAwIBAgITBmyf1XSXNmY/Owua2eiedgPySjAKBggqhkjOPQQDAjA5 -MQswCQYDVQQGEwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6b24g -Um9vdCBDQSAzMB4XDTE1MDUyNjAwMDAwMFoXDTQwMDUyNjAwMDAwMFowOTELMAkG -A1UEBhMCVVMxDzANBgNVBAoTBkFtYXpvbjEZMBcGA1UEAxMQQW1hem9uIFJvb3Qg -Q0EgMzBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABCmXp8ZBf8ANm+gBG1bG8lKl -ui2yEujSLtf6ycXYqm0fc4E7O5hrOXwzpcVOho6AF2hiRVd9RFgdszflZwjrZt6j -QjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgGGMB0GA1UdDgQWBBSr -ttvXBp43rDCGB5Fwx5zEGbF4wDAKBggqhkjOPQQDAgNJADBGAiEA4IWSoxe3jfkr -BqWTrBqYaGFy+uGh0PsceGCmQ5nFuMQCIQCcAu/xlJyzlvnrxir4tiz+OpAUFteM -YyRIHN8wfdVoOw== ------END CERTIFICATE----- - -# Issuer: CN=Amazon Root CA 4 O=Amazon -# Subject: CN=Amazon Root CA 4 O=Amazon -# Label: "Amazon Root CA 4" -# Serial: 143266989758080763974105200630763877849284878 -# MD5 Fingerprint: 89:bc:27:d5:eb:17:8d:06:6a:69:d5:fd:89:47:b4:cd -# SHA1 Fingerprint: f6:10:84:07:d6:f8:bb:67:98:0c:c2:e2:44:c2:eb:ae:1c:ef:63:be -# SHA256 Fingerprint: e3:5d:28:41:9e:d0:20:25:cf:a6:90:38:cd:62:39:62:45:8d:a5:c6:95:fb:de:a3:c2:2b:0b:fb:25:89:70:92 ------BEGIN CERTIFICATE----- -MIIB8jCCAXigAwIBAgITBmyf18G7EEwpQ+Vxe3ssyBrBDjAKBggqhkjOPQQDAzA5 -MQswCQYDVQQGEwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6b24g -Um9vdCBDQSA0MB4XDTE1MDUyNjAwMDAwMFoXDTQwMDUyNjAwMDAwMFowOTELMAkG -A1UEBhMCVVMxDzANBgNVBAoTBkFtYXpvbjEZMBcGA1UEAxMQQW1hem9uIFJvb3Qg -Q0EgNDB2MBAGByqGSM49AgEGBSuBBAAiA2IABNKrijdPo1MN/sGKe0uoe0ZLY7Bi -9i0b2whxIdIA6GO9mif78DluXeo9pcmBqqNbIJhFXRbb/egQbeOc4OO9X4Ri83Bk -M6DLJC9wuoihKqB1+IGuYgbEgds5bimwHvouXKNCMEAwDwYDVR0TAQH/BAUwAwEB -/zAOBgNVHQ8BAf8EBAMCAYYwHQYDVR0OBBYEFNPsxzplbszh2naaVvuc84ZtV+WB -MAoGCCqGSM49BAMDA2gAMGUCMDqLIfG9fhGt0O9Yli/W651+kI0rz2ZVwyzjKKlw -CkcO8DdZEv8tmZQoTipPNU0zWgIxAOp1AE47xDqUEpHJWEadIRNyp4iciuRMStuW -1KyLa2tJElMzrdfkviT8tQp21KW8EA== ------END CERTIFICATE----- - -# Issuer: CN=TUBITAK Kamu SM SSL Kok Sertifikasi - Surum 1 O=Turkiye Bilimsel ve Teknolojik Arastirma Kurumu - TUBITAK OU=Kamu Sertifikasyon Merkezi - Kamu SM -# Subject: CN=TUBITAK Kamu SM SSL Kok Sertifikasi - Surum 1 O=Turkiye Bilimsel ve Teknolojik Arastirma Kurumu - TUBITAK OU=Kamu Sertifikasyon Merkezi - Kamu SM -# Label: "TUBITAK Kamu SM SSL Kok Sertifikasi - Surum 1" -# Serial: 1 -# MD5 Fingerprint: dc:00:81:dc:69:2f:3e:2f:b0:3b:f6:3d:5a:91:8e:49 -# SHA1 Fingerprint: 31:43:64:9b:ec:ce:27:ec:ed:3a:3f:0b:8f:0d:e4:e8:91:dd:ee:ca -# SHA256 Fingerprint: 46:ed:c3:68:90:46:d5:3a:45:3f:b3:10:4a:b8:0d:ca:ec:65:8b:26:60:ea:16:29:dd:7e:86:79:90:64:87:16 ------BEGIN CERTIFICATE----- -MIIEYzCCA0ugAwIBAgIBATANBgkqhkiG9w0BAQsFADCB0jELMAkGA1UEBhMCVFIx -GDAWBgNVBAcTD0dlYnplIC0gS29jYWVsaTFCMEAGA1UEChM5VHVya2l5ZSBCaWxp -bXNlbCB2ZSBUZWtub2xvamlrIEFyYXN0aXJtYSBLdXJ1bXUgLSBUVUJJVEFLMS0w -KwYDVQQLEyRLYW11IFNlcnRpZmlrYXN5b24gTWVya2V6aSAtIEthbXUgU00xNjA0 -BgNVBAMTLVRVQklUQUsgS2FtdSBTTSBTU0wgS29rIFNlcnRpZmlrYXNpIC0gU3Vy -dW0gMTAeFw0xMzExMjUwODI1NTVaFw00MzEwMjUwODI1NTVaMIHSMQswCQYDVQQG -EwJUUjEYMBYGA1UEBxMPR2ViemUgLSBLb2NhZWxpMUIwQAYDVQQKEzlUdXJraXll -IEJpbGltc2VsIHZlIFRla25vbG9qaWsgQXJhc3Rpcm1hIEt1cnVtdSAtIFRVQklU -QUsxLTArBgNVBAsTJEthbXUgU2VydGlmaWthc3lvbiBNZXJrZXppIC0gS2FtdSBT -TTE2MDQGA1UEAxMtVFVCSVRBSyBLYW11IFNNIFNTTCBLb2sgU2VydGlmaWthc2kg -LSBTdXJ1bSAxMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAr3UwM6q7 -a9OZLBI3hNmNe5eA027n/5tQlT6QlVZC1xl8JoSNkvoBHToP4mQ4t4y86Ij5iySr -LqP1N+RAjhgleYN1Hzv/bKjFxlb4tO2KRKOrbEz8HdDc72i9z+SqzvBV96I01INr -N3wcwv61A+xXzry0tcXtAA9TNypN9E8Mg/uGz8v+jE69h/mniyFXnHrfA2eJLJ2X -YacQuFWQfw4tJzh03+f92k4S400VIgLI4OD8D62K18lUUMw7D8oWgITQUVbDjlZ/ -iSIzL+aFCr2lqBs23tPcLG07xxO9WSMs5uWk99gL7eqQQESolbuT1dCANLZGeA4f -AJNG4e7p+exPFwIDAQABo0IwQDAdBgNVHQ4EFgQUZT/HiobGPN08VFw1+DrtUgxH -V8gwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEL -BQADggEBACo/4fEyjq7hmFxLXs9rHmoJ0iKpEsdeV31zVmSAhHqT5Am5EM2fKifh -AHe+SMg1qIGf5LgsyX8OsNJLN13qudULXjS99HMpw+0mFZx+CFOKWI3QSyjfwbPf -IPP54+M638yclNhOT8NrF7f3cuitZjO1JVOr4PhMqZ398g26rrnZqsZr+ZO7rqu4 -lzwDGrpDxpa5RXI4s6ehlj2Re37AIVNMh+3yC1SVUZPVIqUNivGTDj5UDrDYyU7c -8jEyVupk+eq1nRZmQnLzf9OxMUP8pI4X8W0jq5Rm+K37DwhuJi1/FwcJsoz7UMCf -lo3Ptv0AnVoUmr8CRPXBwp8iXqIPoeM= ------END CERTIFICATE----- - -# Issuer: CN=GDCA TrustAUTH R5 ROOT O=GUANG DONG CERTIFICATE AUTHORITY CO.,LTD. -# Subject: CN=GDCA TrustAUTH R5 ROOT O=GUANG DONG CERTIFICATE AUTHORITY CO.,LTD. -# Label: "GDCA TrustAUTH R5 ROOT" -# Serial: 9009899650740120186 -# MD5 Fingerprint: 63:cc:d9:3d:34:35:5c:6f:53:a3:e2:08:70:48:1f:b4 -# SHA1 Fingerprint: 0f:36:38:5b:81:1a:25:c3:9b:31:4e:83:ca:e9:34:66:70:cc:74:b4 -# SHA256 Fingerprint: bf:ff:8f:d0:44:33:48:7d:6a:8a:a6:0c:1a:29:76:7a:9f:c2:bb:b0:5e:42:0f:71:3a:13:b9:92:89:1d:38:93 ------BEGIN CERTIFICATE----- -MIIFiDCCA3CgAwIBAgIIfQmX/vBH6nowDQYJKoZIhvcNAQELBQAwYjELMAkGA1UE -BhMCQ04xMjAwBgNVBAoMKUdVQU5HIERPTkcgQ0VSVElGSUNBVEUgQVVUSE9SSVRZ -IENPLixMVEQuMR8wHQYDVQQDDBZHRENBIFRydXN0QVVUSCBSNSBST09UMB4XDTE0 -MTEyNjA1MTMxNVoXDTQwMTIzMTE1NTk1OVowYjELMAkGA1UEBhMCQ04xMjAwBgNV -BAoMKUdVQU5HIERPTkcgQ0VSVElGSUNBVEUgQVVUSE9SSVRZIENPLixMVEQuMR8w -HQYDVQQDDBZHRENBIFRydXN0QVVUSCBSNSBST09UMIICIjANBgkqhkiG9w0BAQEF -AAOCAg8AMIICCgKCAgEA2aMW8Mh0dHeb7zMNOwZ+Vfy1YI92hhJCfVZmPoiC7XJj -Dp6L3TQsAlFRwxn9WVSEyfFrs0yw6ehGXTjGoqcuEVe6ghWinI9tsJlKCvLriXBj -TnnEt1u9ol2x8kECK62pOqPseQrsXzrj/e+APK00mxqriCZ7VqKChh/rNYmDf1+u -KU49tm7srsHwJ5uu4/Ts765/94Y9cnrrpftZTqfrlYwiOXnhLQiPzLyRuEH3FMEj -qcOtmkVEs7LXLM3GKeJQEK5cy4KOFxg2fZfmiJqwTTQJ9Cy5WmYqsBebnh52nUpm -MUHfP/vFBu8btn4aRjb3ZGM74zkYI+dndRTVdVeSN72+ahsmUPI2JgaQxXABZG12 -ZuGR224HwGGALrIuL4xwp9E7PLOR5G62xDtw8mySlwnNR30YwPO7ng/Wi64HtloP -zgsMR6flPri9fcebNaBhlzpBdRfMK5Z3KpIhHtmVdiBnaM8Nvd/WHwlqmuLMc3Gk -L30SgLdTMEZeS1SZD2fJpcjyIMGC7J0R38IC+xo70e0gmu9lZJIQDSri3nDxGGeC -jGHeuLzRL5z7D9Ar7Rt2ueQ5Vfj4oR24qoAATILnsn8JuLwwoC8N9VKejveSswoA -HQBUlwbgsQfZxw9cZX08bVlX5O2ljelAU58VS6Bx9hoh49pwBiFYFIeFd3mqgnkC -AwEAAaNCMEAwHQYDVR0OBBYEFOLJQJ9NzuiaoXzPDj9lxSmIahlRMA8GA1UdEwEB -/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgGGMA0GCSqGSIb3DQEBCwUAA4ICAQDRSVfg -p8xoWLoBDysZzY2wYUWsEe1jUGn4H3++Fo/9nesLqjJHdtJnJO29fDMylyrHBYZm -DRd9FBUb1Ov9H5r2XpdptxolpAqzkT9fNqyL7FeoPueBihhXOYV0GkLH6VsTX4/5 -COmSdI31R9KrO9b7eGZONn356ZLpBN79SWP8bfsUcZNnL0dKt7n/HipzcEYwv1ry -L3ml4Y0M2fmyYzeMN2WFcGpcWwlyua1jPLHd+PwyvzeG5LuOmCd+uh8W4XAR8gPf -JWIyJyYYMoSf/wA6E7qaTfRPuBRwIrHKK5DOKcFw9C+df/KQHtZa37dG/OaG+svg -IHZ6uqbL9XzeYqWxi+7egmaKTjowHz+Ay60nugxe19CxVsp3cbK1daFQqUBDF8Io -2c9Si1vIY9RCPqAzekYu9wogRlR+ak8x8YF+QnQ4ZXMn7sZ8uI7XpTrXmKGcjBBV -09tL7ECQ8s1uV9JiDnxXk7Gnbc2dg7sq5+W2O3FYrf3RRbxake5TFW/TRQl1brqQ -XR4EzzffHqhmsYzmIGrv/EhOdJhCrylvLmrH+33RZjEizIYAfmaDDEL0vTSSwxrq -T8p+ck0LcIymSLumoRT2+1hEmRSuqguTaaApJUqlyyvdimYHFngVV3Eb7PVHhPOe -MTd61X8kreS8/f3MboPoDKi3QWwH3b08hpcv0g== ------END CERTIFICATE----- - -# Issuer: CN=SSL.com Root Certification Authority RSA O=SSL Corporation -# Subject: CN=SSL.com Root Certification Authority RSA O=SSL Corporation -# Label: "SSL.com Root Certification Authority RSA" -# Serial: 8875640296558310041 -# MD5 Fingerprint: 86:69:12:c0:70:f1:ec:ac:ac:c2:d5:bc:a5:5b:a1:29 -# SHA1 Fingerprint: b7:ab:33:08:d1:ea:44:77:ba:14:80:12:5a:6f:bd:a9:36:49:0c:bb -# SHA256 Fingerprint: 85:66:6a:56:2e:e0:be:5c:e9:25:c1:d8:89:0a:6f:76:a8:7e:c1:6d:4d:7d:5f:29:ea:74:19:cf:20:12:3b:69 ------BEGIN CERTIFICATE----- -MIIF3TCCA8WgAwIBAgIIeyyb0xaAMpkwDQYJKoZIhvcNAQELBQAwfDELMAkGA1UE -BhMCVVMxDjAMBgNVBAgMBVRleGFzMRAwDgYDVQQHDAdIb3VzdG9uMRgwFgYDVQQK -DA9TU0wgQ29ycG9yYXRpb24xMTAvBgNVBAMMKFNTTC5jb20gUm9vdCBDZXJ0aWZp -Y2F0aW9uIEF1dGhvcml0eSBSU0EwHhcNMTYwMjEyMTczOTM5WhcNNDEwMjEyMTcz -OTM5WjB8MQswCQYDVQQGEwJVUzEOMAwGA1UECAwFVGV4YXMxEDAOBgNVBAcMB0hv -dXN0b24xGDAWBgNVBAoMD1NTTCBDb3Jwb3JhdGlvbjExMC8GA1UEAwwoU1NMLmNv -bSBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IFJTQTCCAiIwDQYJKoZIhvcN -AQEBBQADggIPADCCAgoCggIBAPkP3aMrfcvQKv7sZ4Wm5y4bunfh4/WvpOz6Sl2R -xFdHaxh3a3by/ZPkPQ/CFp4LZsNWlJ4Xg4XOVu/yFv0AYvUiCVToZRdOQbngT0aX -qhvIuG5iXmmxX9sqAn78bMrzQdjt0Oj8P2FI7bADFB0QDksZ4LtO7IZl/zbzXmcC -C52GVWH9ejjt/uIZALdvoVBidXQ8oPrIJZK0bnoix/geoeOy3ZExqysdBP+lSgQ3 -6YWkMyv94tZVNHwZpEpox7Ko07fKoZOI68GXvIz5HdkihCR0xwQ9aqkpk8zruFvh -/l8lqjRYyMEjVJ0bmBHDOJx+PYZspQ9AhnwC9FwCTyjLrnGfDzrIM/4RJTXq/LrF -YD3ZfBjVsqnTdXgDciLKOsMf7yzlLqn6niy2UUb9rwPW6mBo6oUWNmuF6R7As93E -JNyAKoFBbZQ+yODJgUEAnl6/f8UImKIYLEJAs/lvOCdLToD0PYFH4Ih86hzOtXVc -US4cK38acijnALXRdMbX5J+tB5O2UzU1/Dfkw/ZdFr4hc96SCvigY2q8lpJqPvi8 -ZVWb3vUNiSYE/CUapiVpy8JtynziWV+XrOvvLsi81xtZPCvM8hnIk2snYxnP/Okm -+Mpxm3+T/jRnhE6Z6/yzeAkzcLpmpnbtG3PrGqUNxCITIJRWCk4sbE6x/c+cCbqi -M+2HAgMBAAGjYzBhMB0GA1UdDgQWBBTdBAkHovV6fVJTEpKV7jiAJQ2mWTAPBgNV -HRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFN0ECQei9Xp9UlMSkpXuOIAlDaZZMA4G -A1UdDwEB/wQEAwIBhjANBgkqhkiG9w0BAQsFAAOCAgEAIBgRlCn7Jp0cHh5wYfGV -cpNxJK1ok1iOMq8bs3AD/CUrdIWQPXhq9LmLpZc7tRiRux6n+UBbkflVma8eEdBc -Hadm47GUBwwyOabqG7B52B2ccETjit3E+ZUfijhDPwGFpUenPUayvOUiaPd7nNgs -PgohyC0zrL/FgZkxdMF1ccW+sfAjRfSda/wZY52jvATGGAslu1OJD7OAUN5F7kR/ -q5R4ZJjT9ijdh9hwZXT7DrkT66cPYakylszeu+1jTBi7qUD3oFRuIIhxdRjqerQ0 -cuAjJ3dctpDqhiVAq+8zD8ufgr6iIPv2tS0a5sKFsXQP+8hlAqRSAUfdSSLBv9jr -a6x+3uxjMxW3IwiPxg+NQVrdjsW5j+VFP3jbutIbQLH+cU0/4IGiul607BXgk90I -H37hVZkLId6Tngr75qNJvTYw/ud3sqB1l7UtgYgXZSD32pAAn8lSzDLKNXz1PQ/Y -K9f1JmzJBjSWFupwWRoyeXkLtoh/D1JIPb9s2KJELtFOt3JY04kTlf5Eq/jXixtu -nLwsoFvVagCvXzfh1foQC5ichucmj87w7G6KVwuA406ywKBjYZC6VWg3dGq2ktuf -oYYitmUnDuy2n0Jg5GfCtdpBC8TTi2EbvPofkSvXRAdeuims2cXp71NIWuuA8ShY -Ic2wBlX7Jz9TkHCpBB5XJ7k= ------END CERTIFICATE----- - -# Issuer: CN=SSL.com Root Certification Authority ECC O=SSL Corporation -# Subject: CN=SSL.com Root Certification Authority ECC O=SSL Corporation -# Label: "SSL.com Root Certification Authority ECC" -# Serial: 8495723813297216424 -# MD5 Fingerprint: 2e:da:e4:39:7f:9c:8f:37:d1:70:9f:26:17:51:3a:8e -# SHA1 Fingerprint: c3:19:7c:39:24:e6:54:af:1b:c4:ab:20:95:7a:e2:c3:0e:13:02:6a -# SHA256 Fingerprint: 34:17:bb:06:cc:60:07:da:1b:96:1c:92:0b:8a:b4:ce:3f:ad:82:0e:4a:a3:0b:9a:cb:c4:a7:4e:bd:ce:bc:65 ------BEGIN CERTIFICATE----- -MIICjTCCAhSgAwIBAgIIdebfy8FoW6gwCgYIKoZIzj0EAwIwfDELMAkGA1UEBhMC -VVMxDjAMBgNVBAgMBVRleGFzMRAwDgYDVQQHDAdIb3VzdG9uMRgwFgYDVQQKDA9T -U0wgQ29ycG9yYXRpb24xMTAvBgNVBAMMKFNTTC5jb20gUm9vdCBDZXJ0aWZpY2F0 -aW9uIEF1dGhvcml0eSBFQ0MwHhcNMTYwMjEyMTgxNDAzWhcNNDEwMjEyMTgxNDAz -WjB8MQswCQYDVQQGEwJVUzEOMAwGA1UECAwFVGV4YXMxEDAOBgNVBAcMB0hvdXN0 -b24xGDAWBgNVBAoMD1NTTCBDb3Jwb3JhdGlvbjExMC8GA1UEAwwoU1NMLmNvbSBS -b290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IEVDQzB2MBAGByqGSM49AgEGBSuB -BAAiA2IABEVuqVDEpiM2nl8ojRfLliJkP9x6jh3MCLOicSS6jkm5BBtHllirLZXI -7Z4INcgn64mMU1jrYor+8FsPazFSY0E7ic3s7LaNGdM0B9y7xgZ/wkWV7Mt/qCPg -CemB+vNH06NjMGEwHQYDVR0OBBYEFILRhXMw5zUE044CkvvlpNHEIejNMA8GA1Ud -EwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAUgtGFczDnNQTTjgKS++Wk0cQh6M0wDgYD -VR0PAQH/BAQDAgGGMAoGCCqGSM49BAMCA2cAMGQCMG/n61kRpGDPYbCWe+0F+S8T -kdzt5fxQaxFGRrMcIQBiu77D5+jNB5n5DQtdcj7EqgIwH7y6C+IwJPt8bYBVCpk+ -gA0z5Wajs6O7pdWLjwkspl1+4vAHCGht0nxpbl/f5Wpl ------END CERTIFICATE----- - -# Issuer: CN=SSL.com EV Root Certification Authority RSA R2 O=SSL Corporation -# Subject: CN=SSL.com EV Root Certification Authority RSA R2 O=SSL Corporation -# Label: "SSL.com EV Root Certification Authority RSA R2" -# Serial: 6248227494352943350 -# MD5 Fingerprint: e1:1e:31:58:1a:ae:54:53:02:f6:17:6a:11:7b:4d:95 -# SHA1 Fingerprint: 74:3a:f0:52:9b:d0:32:a0:f4:4a:83:cd:d4:ba:a9:7b:7c:2e:c4:9a -# SHA256 Fingerprint: 2e:7b:f1:6c:c2:24:85:a7:bb:e2:aa:86:96:75:07:61:b0:ae:39:be:3b:2f:e9:d0:cc:6d:4e:f7:34:91:42:5c ------BEGIN CERTIFICATE----- -MIIF6zCCA9OgAwIBAgIIVrYpzTS8ePYwDQYJKoZIhvcNAQELBQAwgYIxCzAJBgNV -BAYTAlVTMQ4wDAYDVQQIDAVUZXhhczEQMA4GA1UEBwwHSG91c3RvbjEYMBYGA1UE -CgwPU1NMIENvcnBvcmF0aW9uMTcwNQYDVQQDDC5TU0wuY29tIEVWIFJvb3QgQ2Vy -dGlmaWNhdGlvbiBBdXRob3JpdHkgUlNBIFIyMB4XDTE3MDUzMTE4MTQzN1oXDTQy -MDUzMDE4MTQzN1owgYIxCzAJBgNVBAYTAlVTMQ4wDAYDVQQIDAVUZXhhczEQMA4G -A1UEBwwHSG91c3RvbjEYMBYGA1UECgwPU1NMIENvcnBvcmF0aW9uMTcwNQYDVQQD -DC5TU0wuY29tIEVWIFJvb3QgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgUlNBIFIy -MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAjzZlQOHWTcDXtOlG2mvq -M0fNTPl9fb69LT3w23jhhqXZuglXaO1XPqDQCEGD5yhBJB/jchXQARr7XnAjssuf -OePPxU7Gkm0mxnu7s9onnQqG6YE3Bf7wcXHswxzpY6IXFJ3vG2fThVUCAtZJycxa -4bH3bzKfydQ7iEGonL3Lq9ttewkfokxykNorCPzPPFTOZw+oz12WGQvE43LrrdF9 -HSfvkusQv1vrO6/PgN3B0pYEW3p+pKk8OHakYo6gOV7qd89dAFmPZiw+B6KjBSYR -aZfqhbcPlgtLyEDhULouisv3D5oi53+aNxPN8k0TayHRwMwi8qFG9kRpnMphNQcA -b9ZhCBHqurj26bNg5U257J8UZslXWNvNh2n4ioYSA0e/ZhN2rHd9NCSFg83XqpyQ -Gp8hLH94t2S42Oim9HizVcuE0jLEeK6jj2HdzghTreyI/BXkmg3mnxp3zkyPuBQV -PWKchjgGAGYS5Fl2WlPAApiiECtoRHuOec4zSnaqW4EWG7WK2NAAe15itAnWhmMO -pgWVSbooi4iTsjQc2KRVbrcc0N6ZVTsj9CLg+SlmJuwgUHfbSguPvuUCYHBBXtSu -UDkiFCbLsjtzdFVHB3mBOagwE0TlBIqulhMlQg+5U8Sb/M3kHN48+qvWBkofZ6aY -MBzdLNvcGJVXZsb/XItW9XcCAwEAAaNjMGEwDwYDVR0TAQH/BAUwAwEB/zAfBgNV -HSMEGDAWgBT5YLvU49U09rj1BoAlp3PbRmmonjAdBgNVHQ4EFgQU+WC71OPVNPa4 -9QaAJadz20ZpqJ4wDgYDVR0PAQH/BAQDAgGGMA0GCSqGSIb3DQEBCwUAA4ICAQBW -s47LCp1Jjr+kxJG7ZhcFUZh1++VQLHqe8RT6q9OKPv+RKY9ji9i0qVQBDb6Thi/5 -Sm3HXvVX+cpVHBK+Rw82xd9qt9t1wkclf7nxY/hoLVUE0fKNsKTPvDxeH3jnpaAg -cLAExbf3cqfeIg29MyVGjGSSJuM+LmOW2puMPfgYCdcDzH2GguDKBAdRUNf/ktUM -79qGn5nX67evaOI5JpS6aLe/g9Pqemc9YmeuJeVy6OLk7K4S9ksrPJ/psEDzOFSz -/bdoyNrGj1E8svuR3Bznm53htw1yj+KkxKl4+esUrMZDBcJlOSgYAsOCsp0FvmXt -ll9ldDz7CTUue5wT/RsPXcdtgTpWD8w74a8CLyKsRspGPKAcTNZEtF4uXBVmCeEm -Kf7GUmG6sXP/wwyc5WxqlD8UykAWlYTzWamsX0xhk23RO8yilQwipmdnRC652dKK -QbNmC1r7fSOl8hqw/96bg5Qu0T/fkreRrwU7ZcegbLHNYhLDkBvjJc40vG93drEQ -w/cFGsDWr3RiSBd3kmmQYRzelYB0VI8YHMPzA9C/pEN1hlMYegouCRw2n5H9gooi -S9EOUCXdywMMF8mDAAhONU2Ki+3wApRmLER/y5UnlhetCTCstnEXbosX9hwJ1C07 -mKVx01QT2WDz9UtmT/rx7iASjbSsV7FFY6GsdqnC+w== ------END CERTIFICATE----- - -# Issuer: CN=SSL.com EV Root Certification Authority ECC O=SSL Corporation -# Subject: CN=SSL.com EV Root Certification Authority ECC O=SSL Corporation -# Label: "SSL.com EV Root Certification Authority ECC" -# Serial: 3182246526754555285 -# MD5 Fingerprint: 59:53:22:65:83:42:01:54:c0:ce:42:b9:5a:7c:f2:90 -# SHA1 Fingerprint: 4c:dd:51:a3:d1:f5:20:32:14:b0:c6:c5:32:23:03:91:c7:46:42:6d -# SHA256 Fingerprint: 22:a2:c1:f7:bd:ed:70:4c:c1:e7:01:b5:f4:08:c3:10:88:0f:e9:56:b5:de:2a:4a:44:f9:9c:87:3a:25:a7:c8 ------BEGIN CERTIFICATE----- -MIIClDCCAhqgAwIBAgIILCmcWxbtBZUwCgYIKoZIzj0EAwIwfzELMAkGA1UEBhMC -VVMxDjAMBgNVBAgMBVRleGFzMRAwDgYDVQQHDAdIb3VzdG9uMRgwFgYDVQQKDA9T -U0wgQ29ycG9yYXRpb24xNDAyBgNVBAMMK1NTTC5jb20gRVYgUm9vdCBDZXJ0aWZp -Y2F0aW9uIEF1dGhvcml0eSBFQ0MwHhcNMTYwMjEyMTgxNTIzWhcNNDEwMjEyMTgx -NTIzWjB/MQswCQYDVQQGEwJVUzEOMAwGA1UECAwFVGV4YXMxEDAOBgNVBAcMB0hv -dXN0b24xGDAWBgNVBAoMD1NTTCBDb3Jwb3JhdGlvbjE0MDIGA1UEAwwrU1NMLmNv -bSBFViBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IEVDQzB2MBAGByqGSM49 -AgEGBSuBBAAiA2IABKoSR5CYG/vvw0AHgyBO8TCCogbR8pKGYfL2IWjKAMTH6kMA -VIbc/R/fALhBYlzccBYy3h+Z1MzFB8gIH2EWB1E9fVwHU+M1OIzfzZ/ZLg1Kthku -WnBaBu2+8KGwytAJKaNjMGEwHQYDVR0OBBYEFFvKXuXe0oGqzagtZFG22XKbl+ZP -MA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAUW8pe5d7SgarNqC1kUbbZcpuX -5k8wDgYDVR0PAQH/BAQDAgGGMAoGCCqGSM49BAMCA2gAMGUCMQCK5kCJN+vp1RPZ -ytRrJPOwPYdGWBrssd9v+1a6cGvHOMzosYxPD/fxZ3YOg9AeUY8CMD32IygmTMZg -h5Mmm7I1HrrW9zzRHM76JTymGoEVW/MSD2zuZYrJh6j5B+BimoxcSg== ------END CERTIFICATE----- - -# Issuer: CN=GlobalSign O=GlobalSign OU=GlobalSign Root CA - R6 -# Subject: CN=GlobalSign O=GlobalSign OU=GlobalSign Root CA - R6 -# Label: "GlobalSign Root CA - R6" -# Serial: 1417766617973444989252670301619537 -# MD5 Fingerprint: 4f:dd:07:e4:d4:22:64:39:1e:0c:37:42:ea:d1:c6:ae -# SHA1 Fingerprint: 80:94:64:0e:b5:a7:a1:ca:11:9c:1f:dd:d5:9f:81:02:63:a7:fb:d1 -# SHA256 Fingerprint: 2c:ab:ea:fe:37:d0:6c:a2:2a:ba:73:91:c0:03:3d:25:98:29:52:c4:53:64:73:49:76:3a:3a:b5:ad:6c:cf:69 ------BEGIN CERTIFICATE----- -MIIFgzCCA2ugAwIBAgIORea7A4Mzw4VlSOb/RVEwDQYJKoZIhvcNAQEMBQAwTDEg -MB4GA1UECxMXR2xvYmFsU2lnbiBSb290IENBIC0gUjYxEzARBgNVBAoTCkdsb2Jh -bFNpZ24xEzARBgNVBAMTCkdsb2JhbFNpZ24wHhcNMTQxMjEwMDAwMDAwWhcNMzQx -MjEwMDAwMDAwWjBMMSAwHgYDVQQLExdHbG9iYWxTaWduIFJvb3QgQ0EgLSBSNjET -MBEGA1UEChMKR2xvYmFsU2lnbjETMBEGA1UEAxMKR2xvYmFsU2lnbjCCAiIwDQYJ -KoZIhvcNAQEBBQADggIPADCCAgoCggIBAJUH6HPKZvnsFMp7PPcNCPG0RQssgrRI -xutbPK6DuEGSMxSkb3/pKszGsIhrxbaJ0cay/xTOURQh7ErdG1rG1ofuTToVBu1k -ZguSgMpE3nOUTvOniX9PeGMIyBJQbUJmL025eShNUhqKGoC3GYEOfsSKvGRMIRxD -aNc9PIrFsmbVkJq3MQbFvuJtMgamHvm566qjuL++gmNQ0PAYid/kD3n16qIfKtJw -LnvnvJO7bVPiSHyMEAc4/2ayd2F+4OqMPKq0pPbzlUoSB239jLKJz9CgYXfIWHSw -1CM69106yqLbnQneXUQtkPGBzVeS+n68UARjNN9rkxi+azayOeSsJDa38O+2HBNX -k7besvjihbdzorg1qkXy4J02oW9UivFyVm4uiMVRQkQVlO6jxTiWm05OWgtH8wY2 -SXcwvHE35absIQh1/OZhFj931dmRl4QKbNQCTXTAFO39OfuD8l4UoQSwC+n+7o/h -bguyCLNhZglqsQY6ZZZZwPA1/cnaKI0aEYdwgQqomnUdnjqGBQCe24DWJfncBZ4n -WUx2OVvq+aWh2IMP0f/fMBH5hc8zSPXKbWQULHpYT9NLCEnFlWQaYw55PfWzjMpY -rZxCRXluDocZXFSxZba/jJvcE+kNb7gu3GduyYsRtYQUigAZcIN5kZeR1Bonvzce -MgfYFGM8KEyvAgMBAAGjYzBhMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTAD -AQH/MB0GA1UdDgQWBBSubAWjkxPioufi1xzWx/B/yGdToDAfBgNVHSMEGDAWgBSu -bAWjkxPioufi1xzWx/B/yGdToDANBgkqhkiG9w0BAQwFAAOCAgEAgyXt6NH9lVLN -nsAEoJFp5lzQhN7craJP6Ed41mWYqVuoPId8AorRbrcWc+ZfwFSY1XS+wc3iEZGt -Ixg93eFyRJa0lV7Ae46ZeBZDE1ZXs6KzO7V33EByrKPrmzU+sQghoefEQzd5Mr61 -55wsTLxDKZmOMNOsIeDjHfrYBzN2VAAiKrlNIC5waNrlU/yDXNOd8v9EDERm8tLj -vUYAGm0CuiVdjaExUd1URhxN25mW7xocBFymFe944Hn+Xds+qkxV/ZoVqW/hpvvf -cDDpw+5CRu3CkwWJ+n1jez/QcYF8AOiYrg54NMMl+68KnyBr3TsTjxKM4kEaSHpz -oHdpx7Zcf4LIHv5YGygrqGytXm3ABdJ7t+uA/iU3/gKbaKxCXcPu9czc8FB10jZp -nOZ7BN9uBmm23goJSFmH63sUYHpkqmlD75HHTOwY3WzvUy2MmeFe8nI+z1TIvWfs -pA9MRf/TuTAjB0yPEL+GltmZWrSZVxykzLsViVO6LAUP5MSeGbEYNNVMnbrt9x+v -JJUEeKgDu+6B5dpffItKoZB0JaezPkvILFa9x8jvOOJckvB595yEunQtYQEgfn7R -8k8HWV+LLUNS60YMlOH1Zkd5d9VUWx+tJDfLRVpOoERIyNiwmcUVhAn21klJwGW4 -5hpxbqCo8YLoRT5s1gLXCmeDBVrJpBA= ------END CERTIFICATE----- - -# Issuer: CN=OISTE WISeKey Global Root GC CA O=WISeKey OU=OISTE Foundation Endorsed -# Subject: CN=OISTE WISeKey Global Root GC CA O=WISeKey OU=OISTE Foundation Endorsed -# Label: "OISTE WISeKey Global Root GC CA" -# Serial: 44084345621038548146064804565436152554 -# MD5 Fingerprint: a9:d6:b9:2d:2f:93:64:f8:a5:69:ca:91:e9:68:07:23 -# SHA1 Fingerprint: e0:11:84:5e:34:de:be:88:81:b9:9c:f6:16:26:d1:96:1f:c3:b9:31 -# SHA256 Fingerprint: 85:60:f9:1c:36:24:da:ba:95:70:b5:fe:a0:db:e3:6f:f1:1a:83:23:be:94:86:85:4f:b3:f3:4a:55:71:19:8d ------BEGIN CERTIFICATE----- -MIICaTCCAe+gAwIBAgIQISpWDK7aDKtARb8roi066jAKBggqhkjOPQQDAzBtMQsw -CQYDVQQGEwJDSDEQMA4GA1UEChMHV0lTZUtleTEiMCAGA1UECxMZT0lTVEUgRm91 -bmRhdGlvbiBFbmRvcnNlZDEoMCYGA1UEAxMfT0lTVEUgV0lTZUtleSBHbG9iYWwg -Um9vdCBHQyBDQTAeFw0xNzA1MDkwOTQ4MzRaFw00MjA1MDkwOTU4MzNaMG0xCzAJ -BgNVBAYTAkNIMRAwDgYDVQQKEwdXSVNlS2V5MSIwIAYDVQQLExlPSVNURSBGb3Vu -ZGF0aW9uIEVuZG9yc2VkMSgwJgYDVQQDEx9PSVNURSBXSVNlS2V5IEdsb2JhbCBS -b290IEdDIENBMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAETOlQwMYPchi82PG6s4ni -eUqjFqdrVCTbUf/q9Akkwwsin8tqJ4KBDdLArzHkdIJuyiXZjHWd8dvQmqJLIX4W -p2OQ0jnUsYd4XxiWD1AbNTcPasbc2RNNpI6QN+a9WzGRo1QwUjAOBgNVHQ8BAf8E -BAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUSIcUrOPDnpBgOtfKie7T -rYy0UGYwEAYJKwYBBAGCNxUBBAMCAQAwCgYIKoZIzj0EAwMDaAAwZQIwJsdpW9zV -57LnyAyMjMPdeYwbY9XJUpROTYJKcx6ygISpJcBMWm1JKWB4E+J+SOtkAjEA2zQg -Mgj/mkkCtojeFK9dbJlxjRo/i9fgojaGHAeCOnZT/cKi7e97sIBPWA9LUzm9 ------END CERTIFICATE----- - -# Issuer: CN=UCA Global G2 Root O=UniTrust -# Subject: CN=UCA Global G2 Root O=UniTrust -# Label: "UCA Global G2 Root" -# Serial: 124779693093741543919145257850076631279 -# MD5 Fingerprint: 80:fe:f0:c4:4a:f0:5c:62:32:9f:1c:ba:78:a9:50:f8 -# SHA1 Fingerprint: 28:f9:78:16:19:7a:ff:18:25:18:aa:44:fe:c1:a0:ce:5c:b6:4c:8a -# SHA256 Fingerprint: 9b:ea:11:c9:76:fe:01:47:64:c1:be:56:a6:f9:14:b5:a5:60:31:7a:bd:99:88:39:33:82:e5:16:1a:a0:49:3c ------BEGIN CERTIFICATE----- -MIIFRjCCAy6gAwIBAgIQXd+x2lqj7V2+WmUgZQOQ7zANBgkqhkiG9w0BAQsFADA9 -MQswCQYDVQQGEwJDTjERMA8GA1UECgwIVW5pVHJ1c3QxGzAZBgNVBAMMElVDQSBH -bG9iYWwgRzIgUm9vdDAeFw0xNjAzMTEwMDAwMDBaFw00MDEyMzEwMDAwMDBaMD0x -CzAJBgNVBAYTAkNOMREwDwYDVQQKDAhVbmlUcnVzdDEbMBkGA1UEAwwSVUNBIEds -b2JhbCBHMiBSb290MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAxeYr -b3zvJgUno4Ek2m/LAfmZmqkywiKHYUGRO8vDaBsGxUypK8FnFyIdK+35KYmToni9 -kmugow2ifsqTs6bRjDXVdfkX9s9FxeV67HeToI8jrg4aA3++1NDtLnurRiNb/yzm -VHqUwCoV8MmNsHo7JOHXaOIxPAYzRrZUEaalLyJUKlgNAQLx+hVRZ2zA+te2G3/R -VogvGjqNO7uCEeBHANBSh6v7hn4PJGtAnTRnvI3HLYZveT6OqTwXS3+wmeOwcWDc -C/Vkw85DvG1xudLeJ1uK6NjGruFZfc8oLTW4lVYa8bJYS7cSN8h8s+1LgOGN+jIj -tm+3SJUIsUROhYw6AlQgL9+/V087OpAh18EmNVQg7Mc/R+zvWr9LesGtOxdQXGLY -D0tK3Cv6brxzks3sx1DoQZbXqX5t2Okdj4q1uViSukqSKwxW/YDrCPBeKW4bHAyv -j5OJrdu9o54hyokZ7N+1wxrrFv54NkzWbtA+FxyQF2smuvt6L78RHBgOLXMDj6Dl -NaBa4kx1HXHhOThTeEDMg5PXCp6dW4+K5OXgSORIskfNTip1KnvyIvbJvgmRlld6 -iIis7nCs+dwp4wwcOxJORNanTrAmyPPZGpeRaOrvjUYG0lZFWJo8DA+DuAUlwznP -O6Q0ibd5Ei9Hxeepl2n8pndntd978XplFeRhVmUCAwEAAaNCMEAwDgYDVR0PAQH/ -BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFIHEjMz15DD/pQwIX4wV -ZyF0Ad/fMA0GCSqGSIb3DQEBCwUAA4ICAQATZSL1jiutROTL/7lo5sOASD0Ee/oj -L3rtNtqyzm325p7lX1iPyzcyochltq44PTUbPrw7tgTQvPlJ9Zv3hcU2tsu8+Mg5 -1eRfB70VVJd0ysrtT7q6ZHafgbiERUlMjW+i67HM0cOU2kTC5uLqGOiiHycFutfl -1qnN3e92mI0ADs0b+gO3joBYDic/UvuUospeZcnWhNq5NXHzJsBPd+aBJ9J3O5oU -b3n09tDh05S60FdRvScFDcH9yBIw7m+NESsIndTUv4BFFJqIRNow6rSn4+7vW4LV -PtateJLbXDzz2K36uGt/xDYotgIVilQsnLAXc47QN6MUPJiVAAwpBVueSUmxX8fj -y88nZY41F7dXyDDZQVu5FLbowg+UMaeUmMxq67XhJ/UQqAHojhJi6IjMtX9Gl8Cb -EGY4GjZGXyJoPd/JxhMnq1MGrKI8hgZlb7F+sSlEmqO6SWkoaY/X5V+tBIZkbxqg -DMUIYs6Ao9Dz7GjevjPHF1t/gMRMTLGmhIrDO7gJzRSBuhjjVFc2/tsvfEehOjPI -+Vg7RE+xygKJBJYoaMVLuCaJu9YzL1DV/pqJuhgyklTGW+Cd+V7lDSKb9triyCGy -YiGqhkCyLmTTX8jjfhFnRR8F/uOi77Oos/N9j/gMHyIfLXC0uAE0djAA5SN4p1bX -UB+K+wb1whnw0A== ------END CERTIFICATE----- - -# Issuer: CN=UCA Extended Validation Root O=UniTrust -# Subject: CN=UCA Extended Validation Root O=UniTrust -# Label: "UCA Extended Validation Root" -# Serial: 106100277556486529736699587978573607008 -# MD5 Fingerprint: a1:f3:5f:43:c6:34:9b:da:bf:8c:7e:05:53:ad:96:e2 -# SHA1 Fingerprint: a3:a1:b0:6f:24:61:23:4a:e3:36:a5:c2:37:fc:a6:ff:dd:f0:d7:3a -# SHA256 Fingerprint: d4:3a:f9:b3:54:73:75:5c:96:84:fc:06:d7:d8:cb:70:ee:5c:28:e7:73:fb:29:4e:b4:1e:e7:17:22:92:4d:24 ------BEGIN CERTIFICATE----- -MIIFWjCCA0KgAwIBAgIQT9Irj/VkyDOeTzRYZiNwYDANBgkqhkiG9w0BAQsFADBH -MQswCQYDVQQGEwJDTjERMA8GA1UECgwIVW5pVHJ1c3QxJTAjBgNVBAMMHFVDQSBF -eHRlbmRlZCBWYWxpZGF0aW9uIFJvb3QwHhcNMTUwMzEzMDAwMDAwWhcNMzgxMjMx -MDAwMDAwWjBHMQswCQYDVQQGEwJDTjERMA8GA1UECgwIVW5pVHJ1c3QxJTAjBgNV -BAMMHFVDQSBFeHRlbmRlZCBWYWxpZGF0aW9uIFJvb3QwggIiMA0GCSqGSIb3DQEB -AQUAA4ICDwAwggIKAoICAQCpCQcoEwKwmeBkqh5DFnpzsZGgdT6o+uM4AHrsiWog -D4vFsJszA1qGxliG1cGFu0/GnEBNyr7uaZa4rYEwmnySBesFK5pI0Lh2PpbIILvS -sPGP2KxFRv+qZ2C0d35qHzwaUnoEPQc8hQ2E0B92CvdqFN9y4zR8V05WAT558aop -O2z6+I9tTcg1367r3CTueUWnhbYFiN6IXSV8l2RnCdm/WhUFhvMJHuxYMjMR83dk -sHYf5BA1FxvyDrFspCqjc/wJHx4yGVMR59mzLC52LqGj3n5qiAno8geK+LLNEOfi -c0CTuwjRP+H8C5SzJe98ptfRr5//lpr1kXuYC3fUfugH0mK1lTnj8/FtDw5lhIpj -VMWAtuCeS31HJqcBCF3RiJ7XwzJE+oJKCmhUfzhTA8ykADNkUVkLo4KRel7sFsLz -KuZi2irbWWIQJUoqgQtHB0MGcIfS+pMRKXpITeuUx3BNr2fVUbGAIAEBtHoIppB/ -TuDvB0GHr2qlXov7z1CymlSvw4m6WC31MJixNnI5fkkE/SmnTHnkBVfblLkWU41G -sx2VYVdWf6/wFlthWG82UBEL2KwrlRYaDh8IzTY0ZRBiZtWAXxQgXy0MoHgKaNYs -1+lvK9JKBZP8nm9rZ/+I8U6laUpSNwXqxhaN0sSZ0YIrO7o1dfdRUVjzyAfd5LQD -fwIDAQABo0IwQDAdBgNVHQ4EFgQU2XQ65DA9DfcS3H5aBZ8eNJr34RQwDwYDVR0T -AQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAYYwDQYJKoZIhvcNAQELBQADggIBADaN -l8xCFWQpN5smLNb7rhVpLGsaGvdftvkHTFnq88nIua7Mui563MD1sC3AO6+fcAUR -ap8lTwEpcOPlDOHqWnzcSbvBHiqB9RZLcpHIojG5qtr8nR/zXUACE/xOHAbKsxSQ -VBcZEhrxH9cMaVr2cXj0lH2RC47skFSOvG+hTKv8dGT9cZr4QQehzZHkPJrgmzI5 -c6sq1WnIeJEmMX3ixzDx/BR4dxIOE/TdFpS/S2d7cFOFyrC78zhNLJA5wA3CXWvp -4uXViI3WLL+rG761KIcSF3Ru/H38j9CHJrAb+7lsq+KePRXBOy5nAliRn+/4Qh8s -t2j1da3Ptfb/EX3C8CSlrdP6oDyp+l3cpaDvRKS+1ujl5BOWF3sGPjLtx7dCvHaj -2GU4Kzg1USEODm8uNBNA4StnDG1KQTAYI1oyVZnJF+A83vbsea0rWBmirSwiGpWO -vpaQXUJXxPkUAzUrHC1RVwinOt4/5Mi0A3PCwSaAuwtCH60NryZy2sy+s6ODWA2C -xR9GUeOcGMyNm43sSet1UNWMKFnKdDTajAshqx7qG+XH/RU+wBeq+yNuJkbL+vmx -cmtpzyKEC2IPrNkZAJSidjzULZrtBJ4tBmIQN1IchXIbJ+XMxjHsN+xjWZsLHXbM -fjKaiJUINlK73nZfdklJrX+9ZSCyycErdhh2n1ax ------END CERTIFICATE----- - -# Issuer: CN=Certigna Root CA O=Dhimyotis OU=0002 48146308100036 -# Subject: CN=Certigna Root CA O=Dhimyotis OU=0002 48146308100036 -# Label: "Certigna Root CA" -# Serial: 269714418870597844693661054334862075617 -# MD5 Fingerprint: 0e:5c:30:62:27:eb:5b:bc:d7:ae:62:ba:e9:d5:df:77 -# SHA1 Fingerprint: 2d:0d:52:14:ff:9e:ad:99:24:01:74:20:47:6e:6c:85:27:27:f5:43 -# SHA256 Fingerprint: d4:8d:3d:23:ee:db:50:a4:59:e5:51:97:60:1c:27:77:4b:9d:7b:18:c9:4d:5a:05:95:11:a1:02:50:b9:31:68 ------BEGIN CERTIFICATE----- -MIIGWzCCBEOgAwIBAgIRAMrpG4nxVQMNo+ZBbcTjpuEwDQYJKoZIhvcNAQELBQAw -WjELMAkGA1UEBhMCRlIxEjAQBgNVBAoMCURoaW15b3RpczEcMBoGA1UECwwTMDAw -MiA0ODE0NjMwODEwMDAzNjEZMBcGA1UEAwwQQ2VydGlnbmEgUm9vdCBDQTAeFw0x -MzEwMDEwODMyMjdaFw0zMzEwMDEwODMyMjdaMFoxCzAJBgNVBAYTAkZSMRIwEAYD -VQQKDAlEaGlteW90aXMxHDAaBgNVBAsMEzAwMDIgNDgxNDYzMDgxMDAwMzYxGTAX -BgNVBAMMEENlcnRpZ25hIFJvb3QgQ0EwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAw -ggIKAoICAQDNGDllGlmx6mQWDoyUJJV8g9PFOSbcDO8WV43X2KyjQn+Cyu3NW9sO -ty3tRQgXstmzy9YXUnIo245Onoq2C/mehJpNdt4iKVzSs9IGPjA5qXSjklYcoW9M -CiBtnyN6tMbaLOQdLNyzKNAT8kxOAkmhVECe5uUFoC2EyP+YbNDrihqECB63aCPu -I9Vwzm1RaRDuoXrC0SIxwoKF0vJVdlB8JXrJhFwLrN1CTivngqIkicuQstDuI7pm -TLtipPlTWmR7fJj6o0ieD5Wupxj0auwuA0Wv8HT4Ks16XdG+RCYyKfHx9WzMfgIh -C59vpD++nVPiz32pLHxYGpfhPTc3GGYo0kDFUYqMwy3OU4gkWGQwFsWq4NYKpkDf -ePb1BHxpE4S80dGnBs8B92jAqFe7OmGtBIyT46388NtEbVncSVmurJqZNjBBe3Yz -IoejwpKGbvlw7q6Hh5UbxHq9MfPU0uWZ/75I7HX1eBYdpnDBfzwboZL7z8g81sWT -Co/1VTp2lc5ZmIoJlXcymoO6LAQ6l73UL77XbJuiyn1tJslV1c/DeVIICZkHJC1k -JWumIWmbat10TWuXekG9qxf5kBdIjzb5LdXF2+6qhUVB+s06RbFo5jZMm5BX7CO5 -hwjCxAnxl4YqKE3idMDaxIzb3+KhF1nOJFl0Mdp//TBt2dzhauH8XwIDAQABo4IB -GjCCARYwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYE -FBiHVuBud+4kNTxOc5of1uHieX4rMB8GA1UdIwQYMBaAFBiHVuBud+4kNTxOc5of -1uHieX4rMEQGA1UdIAQ9MDswOQYEVR0gADAxMC8GCCsGAQUFBwIBFiNodHRwczov -L3d3d3cuY2VydGlnbmEuZnIvYXV0b3JpdGVzLzBtBgNVHR8EZjBkMC+gLaArhilo -dHRwOi8vY3JsLmNlcnRpZ25hLmZyL2NlcnRpZ25hcm9vdGNhLmNybDAxoC+gLYYr -aHR0cDovL2NybC5kaGlteW90aXMuY29tL2NlcnRpZ25hcm9vdGNhLmNybDANBgkq -hkiG9w0BAQsFAAOCAgEAlLieT/DjlQgi581oQfccVdV8AOItOoldaDgvUSILSo3L -6btdPrtcPbEo/uRTVRPPoZAbAh1fZkYJMyjhDSSXcNMQH+pkV5a7XdrnxIxPTGRG -HVyH41neQtGbqH6mid2PHMkwgu07nM3A6RngatgCdTer9zQoKJHyBApPNeNgJgH6 -0BGM+RFq7q89w1DTj18zeTyGqHNFkIwgtnJzFyO+B2XleJINugHA64wcZr+shncB -lA2c5uk5jR+mUYyZDDl34bSb+hxnV29qao6pK0xXeXpXIs/NX2NGjVxZOob4Mkdi -o2cNGJHc+6Zr9UhhcyNZjgKnvETq9Emd8VRY+WCv2hikLyhF3HqgiIZd8zvn/yk1 -gPxkQ5Tm4xxvvq0OKmOZK8l+hfZx6AYDlf7ej0gcWtSS6Cvu5zHbugRqh5jnxV/v -faci9wHYTfmJ0A6aBVmknpjZbyvKcL5kwlWj9Omvw5Ip3IgWJJk8jSaYtlu3zM63 -Nwf9JtmYhST/WSMDmu2dnajkXjjO11INb9I/bbEFa0nOipFGc/T2L/Coc3cOZayh -jWZSaX5LaAzHHjcng6WMxwLkFM1JAbBzs/3GkDpv0mztO+7skb6iQ12LAEpmJURw -3kAP+HwV96LOPNdeE4yBFxgX0b3xdxA61GU5wSesVywlVP+i2k+KYTlerj1KjL0= ------END CERTIFICATE----- - -# Issuer: CN=emSign Root CA - G1 O=eMudhra Technologies Limited OU=emSign PKI -# Subject: CN=emSign Root CA - G1 O=eMudhra Technologies Limited OU=emSign PKI -# Label: "emSign Root CA - G1" -# Serial: 235931866688319308814040 -# MD5 Fingerprint: 9c:42:84:57:dd:cb:0b:a7:2e:95:ad:b6:f3:da:bc:ac -# SHA1 Fingerprint: 8a:c7:ad:8f:73:ac:4e:c1:b5:75:4d:a5:40:f4:fc:cf:7c:b5:8e:8c -# SHA256 Fingerprint: 40:f6:af:03:46:a9:9a:a1:cd:1d:55:5a:4e:9c:ce:62:c7:f9:63:46:03:ee:40:66:15:83:3d:c8:c8:d0:03:67 ------BEGIN CERTIFICATE----- -MIIDlDCCAnygAwIBAgIKMfXkYgxsWO3W2DANBgkqhkiG9w0BAQsFADBnMQswCQYD -VQQGEwJJTjETMBEGA1UECxMKZW1TaWduIFBLSTElMCMGA1UEChMcZU11ZGhyYSBU -ZWNobm9sb2dpZXMgTGltaXRlZDEcMBoGA1UEAxMTZW1TaWduIFJvb3QgQ0EgLSBH -MTAeFw0xODAyMTgxODMwMDBaFw00MzAyMTgxODMwMDBaMGcxCzAJBgNVBAYTAklO -MRMwEQYDVQQLEwplbVNpZ24gUEtJMSUwIwYDVQQKExxlTXVkaHJhIFRlY2hub2xv -Z2llcyBMaW1pdGVkMRwwGgYDVQQDExNlbVNpZ24gUm9vdCBDQSAtIEcxMIIBIjAN -BgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAk0u76WaK7p1b1TST0Bsew+eeuGQz -f2N4aLTNLnF115sgxk0pvLZoYIr3IZpWNVrzdr3YzZr/k1ZLpVkGoZM0Kd0WNHVO -8oG0x5ZOrRkVUkr+PHB1cM2vK6sVmjM8qrOLqs1D/fXqcP/tzxE7lM5OMhbTI0Aq -d7OvPAEsbO2ZLIvZTmmYsvePQbAyeGHWDV/D+qJAkh1cF+ZwPjXnorfCYuKrpDhM -tTk1b+oDafo6VGiFbdbyL0NVHpENDtjVaqSW0RM8LHhQ6DqS0hdW5TUaQBw+jSzt -Od9C4INBdN+jzcKGYEho42kLVACL5HZpIQ15TjQIXhTCzLG3rdd8cIrHhQIDAQAB -o0IwQDAdBgNVHQ4EFgQU++8Nhp6w492pufEhF38+/PB3KxowDgYDVR0PAQH/BAQD -AgEGMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBAFn/8oz1h31x -PaOfG1vR2vjTnGs2vZupYeveFix0PZ7mddrXuqe8QhfnPZHr5X3dPpzxz5KsbEjM -wiI/aTvFthUvozXGaCocV685743QNcMYDHsAVhzNixl03r4PEuDQqqE/AjSxcM6d -GNYIAwlG7mDgfrbESQRRfXBgvKqy/3lyeqYdPV8q+Mri/Tm3R7nrft8EI6/6nAYH -6ftjk4BAtcZsCjEozgyfz7MjNYBBjWzEN3uBL4ChQEKF6dk4jeihU80Bv2noWgby -RQuQ+q7hv53yrlc8pa6yVvSLZUDp/TGBLPQ5Cdjua6e0ph0VpZj3AYHYhX3zUVxx -iN66zB+Afko= ------END CERTIFICATE----- - -# Issuer: CN=emSign ECC Root CA - G3 O=eMudhra Technologies Limited OU=emSign PKI -# Subject: CN=emSign ECC Root CA - G3 O=eMudhra Technologies Limited OU=emSign PKI -# Label: "emSign ECC Root CA - G3" -# Serial: 287880440101571086945156 -# MD5 Fingerprint: ce:0b:72:d1:9f:88:8e:d0:50:03:e8:e3:b8:8b:67:40 -# SHA1 Fingerprint: 30:43:fa:4f:f2:57:dc:a0:c3:80:ee:2e:58:ea:78:b2:3f:e6:bb:c1 -# SHA256 Fingerprint: 86:a1:ec:ba:08:9c:4a:8d:3b:be:27:34:c6:12:ba:34:1d:81:3e:04:3c:f9:e8:a8:62:cd:5c:57:a3:6b:be:6b ------BEGIN CERTIFICATE----- -MIICTjCCAdOgAwIBAgIKPPYHqWhwDtqLhDAKBggqhkjOPQQDAzBrMQswCQYDVQQG -EwJJTjETMBEGA1UECxMKZW1TaWduIFBLSTElMCMGA1UEChMcZU11ZGhyYSBUZWNo -bm9sb2dpZXMgTGltaXRlZDEgMB4GA1UEAxMXZW1TaWduIEVDQyBSb290IENBIC0g -RzMwHhcNMTgwMjE4MTgzMDAwWhcNNDMwMjE4MTgzMDAwWjBrMQswCQYDVQQGEwJJ -TjETMBEGA1UECxMKZW1TaWduIFBLSTElMCMGA1UEChMcZU11ZGhyYSBUZWNobm9s -b2dpZXMgTGltaXRlZDEgMB4GA1UEAxMXZW1TaWduIEVDQyBSb290IENBIC0gRzMw -djAQBgcqhkjOPQIBBgUrgQQAIgNiAAQjpQy4LRL1KPOxst3iAhKAnjlfSU2fySU0 -WXTsuwYc58Byr+iuL+FBVIcUqEqy6HyC5ltqtdyzdc6LBtCGI79G1Y4PPwT01xyS -fvalY8L1X44uT6EYGQIrMgqCZH0Wk9GjQjBAMB0GA1UdDgQWBBR8XQKEE9TMipuB -zhccLikenEhjQjAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAKBggq -hkjOPQQDAwNpADBmAjEAvvNhzwIQHWSVB7gYboiFBS+DCBeQyh+KTOgNG3qxrdWB -CUfvO6wIBHxcmbHtRwfSAjEAnbpV/KlK6O3t5nYBQnvI+GDZjVGLVTv7jHvrZQnD -+JbNR6iC8hZVdyR+EhCVBCyj ------END CERTIFICATE----- - -# Issuer: CN=emSign Root CA - C1 O=eMudhra Inc OU=emSign PKI -# Subject: CN=emSign Root CA - C1 O=eMudhra Inc OU=emSign PKI -# Label: "emSign Root CA - C1" -# Serial: 825510296613316004955058 -# MD5 Fingerprint: d8:e3:5d:01:21:fa:78:5a:b0:df:ba:d2:ee:2a:5f:68 -# SHA1 Fingerprint: e7:2e:f1:df:fc:b2:09:28:cf:5d:d4:d5:67:37:b1:51:cb:86:4f:01 -# SHA256 Fingerprint: 12:56:09:aa:30:1d:a0:a2:49:b9:7a:82:39:cb:6a:34:21:6f:44:dc:ac:9f:39:54:b1:42:92:f2:e8:c8:60:8f ------BEGIN CERTIFICATE----- -MIIDczCCAlugAwIBAgILAK7PALrEzzL4Q7IwDQYJKoZIhvcNAQELBQAwVjELMAkG -A1UEBhMCVVMxEzARBgNVBAsTCmVtU2lnbiBQS0kxFDASBgNVBAoTC2VNdWRocmEg -SW5jMRwwGgYDVQQDExNlbVNpZ24gUm9vdCBDQSAtIEMxMB4XDTE4MDIxODE4MzAw -MFoXDTQzMDIxODE4MzAwMFowVjELMAkGA1UEBhMCVVMxEzARBgNVBAsTCmVtU2ln -biBQS0kxFDASBgNVBAoTC2VNdWRocmEgSW5jMRwwGgYDVQQDExNlbVNpZ24gUm9v -dCBDQSAtIEMxMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAz+upufGZ -BczYKCFK83M0UYRWEPWgTywS4/oTmifQz/l5GnRfHXk5/Fv4cI7gklL35CX5VIPZ -HdPIWoU/Xse2B+4+wM6ar6xWQio5JXDWv7V7Nq2s9nPczdcdioOl+yuQFTdrHCZH -3DspVpNqs8FqOp099cGXOFgFixwR4+S0uF2FHYP+eF8LRWgYSKVGczQ7/g/IdrvH -GPMF0Ybzhe3nudkyrVWIzqa2kbBPrH4VI5b2P/AgNBbeCsbEBEV5f6f9vtKppa+c -xSMq9zwhbL2vj07FOrLzNBL834AaSaTUqZX3noleoomslMuoaJuvimUnzYnu3Yy1 -aylwQ6BpC+S5DwIDAQABo0IwQDAdBgNVHQ4EFgQU/qHgcB4qAzlSWkK+XJGFehiq -TbUwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEL -BQADggEBAMJKVvoVIXsoounlHfv4LcQ5lkFMOycsxGwYFYDGrK9HWS8mC+M2sO87 -/kOXSTKZEhVb3xEp/6tT+LvBeA+snFOvV71ojD1pM/CjoCNjO2RnIkSt1XHLVip4 -kqNPEjE2NuLe/gDEo2APJ62gsIq1NnpSob0n9CAnYuhNlCQT5AoE6TyrLshDCUrG -YQTlSTR+08TI9Q/Aqum6VF7zYytPT1DU/rl7mYw9wC68AivTxEDkigcxHpvOJpkT -+xHqmiIMERnHXhuBUDDIlhJu58tBf5E7oke3VIAb3ADMmpDqw8NQBmIMMMAVSKeo -WXzhriKi4gp6D/piq1JM4fHfyr6DDUI= ------END CERTIFICATE----- - -# Issuer: CN=emSign ECC Root CA - C3 O=eMudhra Inc OU=emSign PKI -# Subject: CN=emSign ECC Root CA - C3 O=eMudhra Inc OU=emSign PKI -# Label: "emSign ECC Root CA - C3" -# Serial: 582948710642506000014504 -# MD5 Fingerprint: 3e:53:b3:a3:81:ee:d7:10:f8:d3:b0:1d:17:92:f5:d5 -# SHA1 Fingerprint: b6:af:43:c2:9b:81:53:7d:f6:ef:6b:c3:1f:1f:60:15:0c:ee:48:66 -# SHA256 Fingerprint: bc:4d:80:9b:15:18:9d:78:db:3e:1d:8c:f4:f9:72:6a:79:5d:a1:64:3c:a5:f1:35:8e:1d:db:0e:dc:0d:7e:b3 ------BEGIN CERTIFICATE----- -MIICKzCCAbGgAwIBAgIKe3G2gla4EnycqDAKBggqhkjOPQQDAzBaMQswCQYDVQQG -EwJVUzETMBEGA1UECxMKZW1TaWduIFBLSTEUMBIGA1UEChMLZU11ZGhyYSBJbmMx -IDAeBgNVBAMTF2VtU2lnbiBFQ0MgUm9vdCBDQSAtIEMzMB4XDTE4MDIxODE4MzAw -MFoXDTQzMDIxODE4MzAwMFowWjELMAkGA1UEBhMCVVMxEzARBgNVBAsTCmVtU2ln -biBQS0kxFDASBgNVBAoTC2VNdWRocmEgSW5jMSAwHgYDVQQDExdlbVNpZ24gRUND -IFJvb3QgQ0EgLSBDMzB2MBAGByqGSM49AgEGBSuBBAAiA2IABP2lYa57JhAd6bci -MK4G9IGzsUJxlTm801Ljr6/58pc1kjZGDoeVjbk5Wum739D+yAdBPLtVb4Ojavti -sIGJAnB9SMVK4+kiVCJNk7tCDK93nCOmfddhEc5lx/h//vXyqaNCMEAwHQYDVR0O -BBYEFPtaSNCAIEDyqOkAB2kZd6fmw/TPMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMB -Af8EBTADAQH/MAoGCCqGSM49BAMDA2gAMGUCMQC02C8Cif22TGK6Q04ThHK1rt0c -3ta13FaPWEBaLd4gTCKDypOofu4SQMfWh0/434UCMBwUZOR8loMRnLDRWmFLpg9J -0wD8ofzkpf9/rdcw0Md3f76BB1UwUCAU9Vc4CqgxUQ== ------END CERTIFICATE----- - -# Issuer: CN=Hongkong Post Root CA 3 O=Hongkong Post -# Subject: CN=Hongkong Post Root CA 3 O=Hongkong Post -# Label: "Hongkong Post Root CA 3" -# Serial: 46170865288971385588281144162979347873371282084 -# MD5 Fingerprint: 11:fc:9f:bd:73:30:02:8a:fd:3f:f3:58:b9:cb:20:f0 -# SHA1 Fingerprint: 58:a2:d0:ec:20:52:81:5b:c1:f3:f8:64:02:24:4e:c2:8e:02:4b:02 -# SHA256 Fingerprint: 5a:2f:c0:3f:0c:83:b0:90:bb:fa:40:60:4b:09:88:44:6c:76:36:18:3d:f9:84:6e:17:10:1a:44:7f:b8:ef:d6 ------BEGIN CERTIFICATE----- -MIIFzzCCA7egAwIBAgIUCBZfikyl7ADJk0DfxMauI7gcWqQwDQYJKoZIhvcNAQEL -BQAwbzELMAkGA1UEBhMCSEsxEjAQBgNVBAgTCUhvbmcgS29uZzESMBAGA1UEBxMJ -SG9uZyBLb25nMRYwFAYDVQQKEw1Ib25na29uZyBQb3N0MSAwHgYDVQQDExdIb25n -a29uZyBQb3N0IFJvb3QgQ0EgMzAeFw0xNzA2MDMwMjI5NDZaFw00MjA2MDMwMjI5 -NDZaMG8xCzAJBgNVBAYTAkhLMRIwEAYDVQQIEwlIb25nIEtvbmcxEjAQBgNVBAcT -CUhvbmcgS29uZzEWMBQGA1UEChMNSG9uZ2tvbmcgUG9zdDEgMB4GA1UEAxMXSG9u -Z2tvbmcgUG9zdCBSb290IENBIDMwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIK -AoICAQCziNfqzg8gTr7m1gNt7ln8wlffKWihgw4+aMdoWJwcYEuJQwy51BWy7sFO -dem1p+/l6TWZ5Mwc50tfjTMwIDNT2aa71T4Tjukfh0mtUC1Qyhi+AViiE3CWu4mI -VoBc+L0sPOFMV4i707mV78vH9toxdCim5lSJ9UExyuUmGs2C4HDaOym71QP1mbpV -9WTRYA6ziUm4ii8F0oRFKHyPaFASePwLtVPLwpgchKOesL4jpNrcyCse2m5FHomY -2vkALgbpDDtw1VAliJnLzXNg99X/NWfFobxeq81KuEXryGgeDQ0URhLj0mRiikKY -vLTGCAj4/ahMZJx2Ab0vqWwzD9g/KLg8aQFChn5pwckGyuV6RmXpwtZQQS4/t+Tt -bNe/JgERohYpSms0BpDsE9K2+2p20jzt8NYt3eEV7KObLyzJPivkaTv/ciWxNoZb -x39ri1UbSsUgYT2uy1DhCDq+sI9jQVMwCFk8mB13umOResoQUGC/8Ne8lYePl8X+ -l2oBlKN8W4UdKjk60FSh0Tlxnf0h+bV78OLgAo9uliQlLKAeLKjEiafv7ZkGL7YK -TE/bosw3Gq9HhS2KX8Q0NEwA/RiTZxPRN+ZItIsGxVd7GYYKecsAyVKvQv83j+Gj -Hno9UKtjBucVtT+2RTeUN7F+8kjDf8V1/peNRY8apxpyKBpADwIDAQABo2MwYTAP -BgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAfBgNVHSMEGDAWgBQXnc0e -i9Y5K3DTXNSguB+wAPzFYTAdBgNVHQ4EFgQUF53NHovWOStw01zUoLgfsAD8xWEw -DQYJKoZIhvcNAQELBQADggIBAFbVe27mIgHSQpsY1Q7XZiNc4/6gx5LS6ZStS6LG -7BJ8dNVI0lkUmcDrudHr9EgwW62nV3OZqdPlt9EuWSRY3GguLmLYauRwCy0gUCCk -MpXRAJi70/33MvJJrsZ64Ee+bs7Lo3I6LWldy8joRTnU+kLBEUx3XZL7av9YROXr -gZ6voJmtvqkBZss4HTzfQx/0TW60uhdG/H39h4F5ag0zD/ov+BS5gLNdTaqX4fnk -GMX41TiMJjz98iji7lpJiCzfeT2OnpA8vUFKOt1b9pq0zj8lMH8yfaIDlNDceqFS -3m6TjRgm/VWsvY+b0s+v54Ysyx8Jb6NvqYTUc79NoXQbTiNg8swOqn+knEwlqLJm -Ozj/2ZQw9nKEvmhVEA/GcywWaZMH/rFF7buiVWqw2rVKAiUnhde3t4ZEFolsgCs+ -l6mc1X5VTMbeRRAc6uk7nwNT7u56AQIWeNTowr5GdogTPyK7SBIdUgC0An4hGh6c -JfTzPV4e0hz5sy229zdcxsshTrD3mUcYhcErulWuBurQB7Lcq9CClnXO0lD+mefP -L5/ndtFhKvshuzHQqp9HpLIiyhY6UFfEW0NnxWViA0kB60PZ2Pierc+xYw5F9KBa -LJstxabArahH9CdMOA0uG0k7UvToiIMrVCjU8jVStDKDYmlkDJGcn5fqdBb9HxEG -mpv0 ------END CERTIFICATE----- - -# Issuer: CN=Microsoft ECC Root Certificate Authority 2017 O=Microsoft Corporation -# Subject: CN=Microsoft ECC Root Certificate Authority 2017 O=Microsoft Corporation -# Label: "Microsoft ECC Root Certificate Authority 2017" -# Serial: 136839042543790627607696632466672567020 -# MD5 Fingerprint: dd:a1:03:e6:4a:93:10:d1:bf:f0:19:42:cb:fe:ed:67 -# SHA1 Fingerprint: 99:9a:64:c3:7f:f4:7d:9f:ab:95:f1:47:69:89:14:60:ee:c4:c3:c5 -# SHA256 Fingerprint: 35:8d:f3:9d:76:4a:f9:e1:b7:66:e9:c9:72:df:35:2e:e1:5c:fa:c2:27:af:6a:d1:d7:0e:8e:4a:6e:dc:ba:02 ------BEGIN CERTIFICATE----- -MIICWTCCAd+gAwIBAgIQZvI9r4fei7FK6gxXMQHC7DAKBggqhkjOPQQDAzBlMQsw -CQYDVQQGEwJVUzEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMTYwNAYD -VQQDEy1NaWNyb3NvZnQgRUNDIFJvb3QgQ2VydGlmaWNhdGUgQXV0aG9yaXR5IDIw -MTcwHhcNMTkxMjE4MjMwNjQ1WhcNNDIwNzE4MjMxNjA0WjBlMQswCQYDVQQGEwJV -UzEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMTYwNAYDVQQDEy1NaWNy -b3NvZnQgRUNDIFJvb3QgQ2VydGlmaWNhdGUgQXV0aG9yaXR5IDIwMTcwdjAQBgcq -hkjOPQIBBgUrgQQAIgNiAATUvD0CQnVBEyPNgASGAlEvaqiBYgtlzPbKnR5vSmZR -ogPZnZH6thaxjG7efM3beaYvzrvOcS/lpaso7GMEZpn4+vKTEAXhgShC48Zo9OYb -hGBKia/teQ87zvH2RPUBeMCjVDBSMA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8E -BTADAQH/MB0GA1UdDgQWBBTIy5lycFIM+Oa+sgRXKSrPQhDtNTAQBgkrBgEEAYI3 -FQEEAwIBADAKBggqhkjOPQQDAwNoADBlAjBY8k3qDPlfXu5gKcs68tvWMoQZP3zV -L8KxzJOuULsJMsbG7X7JNpQS5GiFBqIb0C8CMQCZ6Ra0DvpWSNSkMBaReNtUjGUB -iudQZsIxtzm6uBoiB078a1QWIP8rtedMDE2mT3M= ------END CERTIFICATE----- - -# Issuer: CN=Microsoft RSA Root Certificate Authority 2017 O=Microsoft Corporation -# Subject: CN=Microsoft RSA Root Certificate Authority 2017 O=Microsoft Corporation -# Label: "Microsoft RSA Root Certificate Authority 2017" -# Serial: 40975477897264996090493496164228220339 -# MD5 Fingerprint: 10:ff:00:ff:cf:c9:f8:c7:7a:c0:ee:35:8e:c9:0f:47 -# SHA1 Fingerprint: 73:a5:e6:4a:3b:ff:83:16:ff:0e:dc:cc:61:8a:90:6e:4e:ae:4d:74 -# SHA256 Fingerprint: c7:41:f7:0f:4b:2a:8d:88:bf:2e:71:c1:41:22:ef:53:ef:10:eb:a0:cf:a5:e6:4c:fa:20:f4:18:85:30:73:e0 ------BEGIN CERTIFICATE----- -MIIFqDCCA5CgAwIBAgIQHtOXCV/YtLNHcB6qvn9FszANBgkqhkiG9w0BAQwFADBl -MQswCQYDVQQGEwJVUzEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMTYw -NAYDVQQDEy1NaWNyb3NvZnQgUlNBIFJvb3QgQ2VydGlmaWNhdGUgQXV0aG9yaXR5 -IDIwMTcwHhcNMTkxMjE4MjI1MTIyWhcNNDIwNzE4MjMwMDIzWjBlMQswCQYDVQQG -EwJVUzEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMTYwNAYDVQQDEy1N -aWNyb3NvZnQgUlNBIFJvb3QgQ2VydGlmaWNhdGUgQXV0aG9yaXR5IDIwMTcwggIi -MA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDKW76UM4wplZEWCpW9R2LBifOZ -Nt9GkMml7Xhqb0eRaPgnZ1AzHaGm++DlQ6OEAlcBXZxIQIJTELy/xztokLaCLeX0 -ZdDMbRnMlfl7rEqUrQ7eS0MdhweSE5CAg2Q1OQT85elss7YfUJQ4ZVBcF0a5toW1 -HLUX6NZFndiyJrDKxHBKrmCk3bPZ7Pw71VdyvD/IybLeS2v4I2wDwAW9lcfNcztm -gGTjGqwu+UcF8ga2m3P1eDNbx6H7JyqhtJqRjJHTOoI+dkC0zVJhUXAoP8XFWvLJ -jEm7FFtNyP9nTUwSlq31/niol4fX/V4ggNyhSyL71Imtus5Hl0dVe49FyGcohJUc -aDDv70ngNXtk55iwlNpNhTs+VcQor1fznhPbRiefHqJeRIOkpcrVE7NLP8TjwuaG -YaRSMLl6IE9vDzhTyzMMEyuP1pq9KsgtsRx9S1HKR9FIJ3Jdh+vVReZIZZ2vUpC6 -W6IYZVcSn2i51BVrlMRpIpj0M+Dt+VGOQVDJNE92kKz8OMHY4Xu54+OU4UZpyw4K -UGsTuqwPN1q3ErWQgR5WrlcihtnJ0tHXUeOrO8ZV/R4O03QK0dqq6mm4lyiPSMQH -+FJDOvTKVTUssKZqwJz58oHhEmrARdlns87/I6KJClTUFLkqqNfs+avNJVgyeY+Q -W5g5xAgGwax/Dj0ApQIDAQABo1QwUjAOBgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/ -BAUwAwEB/zAdBgNVHQ4EFgQUCctZf4aycI8awznjwNnpv7tNsiMwEAYJKwYBBAGC -NxUBBAMCAQAwDQYJKoZIhvcNAQEMBQADggIBAKyvPl3CEZaJjqPnktaXFbgToqZC -LgLNFgVZJ8og6Lq46BrsTaiXVq5lQ7GPAJtSzVXNUzltYkyLDVt8LkS/gxCP81OC -gMNPOsduET/m4xaRhPtthH80dK2Jp86519efhGSSvpWhrQlTM93uCupKUY5vVau6 -tZRGrox/2KJQJWVggEbbMwSubLWYdFQl3JPk+ONVFT24bcMKpBLBaYVu32TxU5nh -SnUgnZUP5NbcA/FZGOhHibJXWpS2qdgXKxdJ5XbLwVaZOjex/2kskZGT4d9Mozd2 -TaGf+G0eHdP67Pv0RR0Tbc/3WeUiJ3IrhvNXuzDtJE3cfVa7o7P4NHmJweDyAmH3 -pvwPuxwXC65B2Xy9J6P9LjrRk5Sxcx0ki69bIImtt2dmefU6xqaWM/5TkshGsRGR -xpl/j8nWZjEgQRCHLQzWwa80mMpkg/sTV9HB8Dx6jKXB/ZUhoHHBk2dxEuqPiApp -GWSZI1b7rCoucL5mxAyE7+WL85MB+GqQk2dLsmijtWKP6T+MejteD+eMuMZ87zf9 -dOLITzNy4ZQ5bb0Sr74MTnB8G2+NszKTc0QWbej09+CVgI+WXTik9KveCjCHk9hN -AHFiRSdLOkKEW39lt2c0Ui2cFmuqqNh7o0JMcccMyj6D5KbvtwEwXlGjefVwaaZB -RA+GsCyRxj3qrg+E ------END CERTIFICATE----- - -# Issuer: CN=e-Szigno Root CA 2017 O=Microsec Ltd. -# Subject: CN=e-Szigno Root CA 2017 O=Microsec Ltd. -# Label: "e-Szigno Root CA 2017" -# Serial: 411379200276854331539784714 -# MD5 Fingerprint: de:1f:f6:9e:84:ae:a7:b4:21:ce:1e:58:7d:d1:84:98 -# SHA1 Fingerprint: 89:d4:83:03:4f:9e:9a:48:80:5f:72:37:d4:a9:a6:ef:cb:7c:1f:d1 -# SHA256 Fingerprint: be:b0:0b:30:83:9b:9b:c3:2c:32:e4:44:79:05:95:06:41:f2:64:21:b1:5e:d0:89:19:8b:51:8a:e2:ea:1b:99 ------BEGIN CERTIFICATE----- -MIICQDCCAeWgAwIBAgIMAVRI7yH9l1kN9QQKMAoGCCqGSM49BAMCMHExCzAJBgNV -BAYTAkhVMREwDwYDVQQHDAhCdWRhcGVzdDEWMBQGA1UECgwNTWljcm9zZWMgTHRk -LjEXMBUGA1UEYQwOVkFUSFUtMjM1ODQ0OTcxHjAcBgNVBAMMFWUtU3ppZ25vIFJv -b3QgQ0EgMjAxNzAeFw0xNzA4MjIxMjA3MDZaFw00MjA4MjIxMjA3MDZaMHExCzAJ -BgNVBAYTAkhVMREwDwYDVQQHDAhCdWRhcGVzdDEWMBQGA1UECgwNTWljcm9zZWMg -THRkLjEXMBUGA1UEYQwOVkFUSFUtMjM1ODQ0OTcxHjAcBgNVBAMMFWUtU3ppZ25v -IFJvb3QgQ0EgMjAxNzBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABJbcPYrYsHtv -xie+RJCxs1YVe45DJH0ahFnuY2iyxl6H0BVIHqiQrb1TotreOpCmYF9oMrWGQd+H -Wyx7xf58etqjYzBhMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0G -A1UdDgQWBBSHERUI0arBeAyxr87GyZDvvzAEwDAfBgNVHSMEGDAWgBSHERUI0arB -eAyxr87GyZDvvzAEwDAKBggqhkjOPQQDAgNJADBGAiEAtVfd14pVCzbhhkT61Nlo -jbjcI4qKDdQvfepz7L9NbKgCIQDLpbQS+ue16M9+k/zzNY9vTlp8tLxOsvxyqltZ -+efcMQ== ------END CERTIFICATE----- - -# Issuer: O=CERTSIGN SA OU=certSIGN ROOT CA G2 -# Subject: O=CERTSIGN SA OU=certSIGN ROOT CA G2 -# Label: "certSIGN Root CA G2" -# Serial: 313609486401300475190 -# MD5 Fingerprint: 8c:f1:75:8a:c6:19:cf:94:b7:f7:65:20:87:c3:97:c7 -# SHA1 Fingerprint: 26:f9:93:b4:ed:3d:28:27:b0:b9:4b:a7:e9:15:1d:a3:8d:92:e5:32 -# SHA256 Fingerprint: 65:7c:fe:2f:a7:3f:aa:38:46:25:71:f3:32:a2:36:3a:46:fc:e7:02:09:51:71:07:02:cd:fb:b6:ee:da:33:05 ------BEGIN CERTIFICATE----- -MIIFRzCCAy+gAwIBAgIJEQA0tk7GNi02MA0GCSqGSIb3DQEBCwUAMEExCzAJBgNV -BAYTAlJPMRQwEgYDVQQKEwtDRVJUU0lHTiBTQTEcMBoGA1UECxMTY2VydFNJR04g -Uk9PVCBDQSBHMjAeFw0xNzAyMDYwOTI3MzVaFw00MjAyMDYwOTI3MzVaMEExCzAJ -BgNVBAYTAlJPMRQwEgYDVQQKEwtDRVJUU0lHTiBTQTEcMBoGA1UECxMTY2VydFNJ -R04gUk9PVCBDQSBHMjCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMDF -dRmRfUR0dIf+DjuW3NgBFszuY5HnC2/OOwppGnzC46+CjobXXo9X69MhWf05N0Iw -vlDqtg+piNguLWkh59E3GE59kdUWX2tbAMI5Qw02hVK5U2UPHULlj88F0+7cDBrZ -uIt4ImfkabBoxTzkbFpG583H+u/E7Eu9aqSs/cwoUe+StCmrqzWaTOTECMYmzPhp -n+Sc8CnTXPnGFiWeI8MgwT0PPzhAsP6CRDiqWhqKa2NYOLQV07YRaXseVO6MGiKs -cpc/I1mbySKEwQdPzH/iV8oScLumZfNpdWO9lfsbl83kqK/20U6o2YpxJM02PbyW -xPFsqa7lzw1uKA2wDrXKUXt4FMMgL3/7FFXhEZn91QqhngLjYl/rNUssuHLoPj1P -rCy7Lobio3aP5ZMqz6WryFyNSwb/EkaseMsUBzXgqd+L6a8VTxaJW732jcZZroiF -DsGJ6x9nxUWO/203Nit4ZoORUSs9/1F3dmKh7Gc+PoGD4FapUB8fepmrY7+EF3fx -DTvf95xhszWYijqy7DwaNz9+j5LP2RIUZNoQAhVB/0/E6xyjyfqZ90bp4RjZsbgy -LcsUDFDYg2WD7rlcz8sFWkz6GZdr1l0T08JcVLwyc6B49fFtHsufpaafItzRUZ6C -eWRgKRM+o/1Pcmqr4tTluCRVLERLiohEnMqE0yo7AgMBAAGjQjBAMA8GA1UdEwEB -/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBSCIS1mxteg4BXrzkwJ -d8RgnlRuAzANBgkqhkiG9w0BAQsFAAOCAgEAYN4auOfyYILVAzOBywaK8SJJ6ejq -kX/GM15oGQOGO0MBzwdw5AgeZYWR5hEit/UCI46uuR59H35s5r0l1ZUa8gWmr4UC -b6741jH/JclKyMeKqdmfS0mbEVeZkkMR3rYzpMzXjWR91M08KCy0mpbqTfXERMQl -qiCA2ClV9+BB/AYm/7k29UMUA2Z44RGx2iBfRgB4ACGlHgAoYXhvqAEBj500mv/0 -OJD7uNGzcgbJceaBxXntC6Z58hMLnPddDnskk7RI24Zf3lCGeOdA5jGokHZwYa+c -NywRtYK3qq4kNFtyDGkNzVmf9nGvnAvRCjj5BiKDUyUM/FHE5r7iOZULJK2v0ZXk -ltd0ZGtxTgI8qoXzIKNDOXZbbFD+mpwUHmUUihW9o4JFWklWatKcsWMy5WHgUyIO -pwpJ6st+H6jiYoD2EEVSmAYY3qXNL3+q1Ok+CHLsIwMCPKaq2LxndD0UF/tUSxfj -03k9bWtJySgOLnRQvwzZRjoQhsmnP+mg7H/rpXdYaXHmgwo38oZJar55CJD2AhZk -PuXaTH4MNMn5X7azKFGnpyuqSfqNZSlO42sTp5SjLVFteAxEy9/eCG/Oo2Sr05WE -1LlSVHJ7liXMvGnjSG4N0MedJ5qq+BOS3R7fY581qRY27Iy4g/Q9iY/NtBde17MX -QRBdJ3NghVdJIgc= ------END CERTIFICATE----- - -# Issuer: CN=NAVER Global Root Certification Authority O=NAVER BUSINESS PLATFORM Corp. -# Subject: CN=NAVER Global Root Certification Authority O=NAVER BUSINESS PLATFORM Corp. -# Label: "NAVER Global Root Certification Authority" -# Serial: 9013692873798656336226253319739695165984492813 -# MD5 Fingerprint: c8:7e:41:f6:25:3b:f5:09:b3:17:e8:46:3d:bf:d0:9b -# SHA1 Fingerprint: 8f:6b:f2:a9:27:4a:da:14:a0:c4:f4:8e:61:27:f9:c0:1e:78:5d:d1 -# SHA256 Fingerprint: 88:f4:38:dc:f8:ff:d1:fa:8f:42:91:15:ff:e5:f8:2a:e1:e0:6e:0c:70:c3:75:fa:ad:71:7b:34:a4:9e:72:65 ------BEGIN CERTIFICATE----- -MIIFojCCA4qgAwIBAgIUAZQwHqIL3fXFMyqxQ0Rx+NZQTQ0wDQYJKoZIhvcNAQEM -BQAwaTELMAkGA1UEBhMCS1IxJjAkBgNVBAoMHU5BVkVSIEJVU0lORVNTIFBMQVRG -T1JNIENvcnAuMTIwMAYDVQQDDClOQVZFUiBHbG9iYWwgUm9vdCBDZXJ0aWZpY2F0 -aW9uIEF1dGhvcml0eTAeFw0xNzA4MTgwODU4NDJaFw0zNzA4MTgyMzU5NTlaMGkx -CzAJBgNVBAYTAktSMSYwJAYDVQQKDB1OQVZFUiBCVVNJTkVTUyBQTEFURk9STSBD -b3JwLjEyMDAGA1UEAwwpTkFWRVIgR2xvYmFsIFJvb3QgQ2VydGlmaWNhdGlvbiBB -dXRob3JpdHkwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC21PGTXLVA -iQqrDZBbUGOukJR0F0Vy1ntlWilLp1agS7gvQnXp2XskWjFlqxcX0TM62RHcQDaH -38dq6SZeWYp34+hInDEW+j6RscrJo+KfziFTowI2MMtSAuXaMl3Dxeb57hHHi8lE -HoSTGEq0n+USZGnQJoViAbbJAh2+g1G7XNr4rRVqmfeSVPc0W+m/6imBEtRTkZaz -kVrd/pBzKPswRrXKCAfHcXLJZtM0l/aM9BhK4dA9WkW2aacp+yPOiNgSnABIqKYP -szuSjXEOdMWLyEz59JuOuDxp7W87UC9Y7cSw0BwbagzivESq2M0UXZR4Yb8Obtoq -vC8MC3GmsxY/nOb5zJ9TNeIDoKAYv7vxvvTWjIcNQvcGufFt7QSUqP620wbGQGHf -nZ3zVHbOUzoBppJB7ASjjw2i1QnK1sua8e9DXcCrpUHPXFNwcMmIpi3Ua2FzUCaG -YQ5fG8Ir4ozVu53BA0K6lNpfqbDKzE0K70dpAy8i+/Eozr9dUGWokG2zdLAIx6yo -0es+nPxdGoMuK8u180SdOqcXYZaicdNwlhVNt0xz7hlcxVs+Qf6sdWA7G2POAN3a -CJBitOUt7kinaxeZVL6HSuOpXgRM6xBtVNbv8ejyYhbLgGvtPe31HzClrkvJE+2K -AQHJuFFYwGY6sWZLxNUxAmLpdIQM201GLQIDAQABo0IwQDAdBgNVHQ4EFgQU0p+I -36HNLL3s9TsBAZMzJ7LrYEswDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMB -Af8wDQYJKoZIhvcNAQEMBQADggIBADLKgLOdPVQG3dLSLvCkASELZ0jKbY7gyKoN -qo0hV4/GPnrK21HUUrPUloSlWGB/5QuOH/XcChWB5Tu2tyIvCZwTFrFsDDUIbatj -cu3cvuzHV+YwIHHW1xDBE1UBjCpD5EHxzzp6U5LOogMFDTjfArsQLtk70pt6wKGm -+LUx5vR1yblTmXVHIloUFcd4G7ad6Qz4G3bxhYTeodoS76TiEJd6eN4MUZeoIUCL -hr0N8F5OSza7OyAfikJW4Qsav3vQIkMsRIz75Sq0bBwcupTgE34h5prCy8VCZLQe -lHsIJchxzIdFV4XTnyliIoNRlwAYl3dqmJLJfGBs32x9SuRwTMKeuB330DTHD8z7 -p/8Dvq1wkNoL3chtl1+afwkyQf3NosxabUzyqkn+Zvjp2DXrDige7kgvOtB5CTh8 -piKCk5XQA76+AqAF3SAi428diDRgxuYKuQl1C/AH6GmWNcf7I4GOODm4RStDeKLR -LBT/DShycpWbXgnbiUSYqqFJu3FS8r/2/yehNq+4tneI3TqkbZs0kNwUXTC/t+sX -5Ie3cdCh13cV1ELX8vMxmV2b3RZtP+oGI/hGoiLtk/bdmuYqh7GYVPEi92tF4+KO -dh2ajcQGjTa3FPOdVGm3jjzVpG2Tgbet9r1ke8LJaDmgkpzNNIaRkPpkUZ3+/uul -9XXeifdy ------END CERTIFICATE----- - -# Issuer: CN=AC RAIZ FNMT-RCM SERVIDORES SEGUROS O=FNMT-RCM OU=Ceres -# Subject: CN=AC RAIZ FNMT-RCM SERVIDORES SEGUROS O=FNMT-RCM OU=Ceres -# Label: "AC RAIZ FNMT-RCM SERVIDORES SEGUROS" -# Serial: 131542671362353147877283741781055151509 -# MD5 Fingerprint: 19:36:9c:52:03:2f:d2:d1:bb:23:cc:dd:1e:12:55:bb -# SHA1 Fingerprint: 62:ff:d9:9e:c0:65:0d:03:ce:75:93:d2:ed:3f:2d:32:c9:e3:e5:4a -# SHA256 Fingerprint: 55:41:53:b1:3d:2c:f9:dd:b7:53:bf:be:1a:4e:0a:e0:8d:0a:a4:18:70:58:fe:60:a2:b8:62:b2:e4:b8:7b:cb ------BEGIN CERTIFICATE----- -MIICbjCCAfOgAwIBAgIQYvYybOXE42hcG2LdnC6dlTAKBggqhkjOPQQDAzB4MQsw -CQYDVQQGEwJFUzERMA8GA1UECgwIRk5NVC1SQ00xDjAMBgNVBAsMBUNlcmVzMRgw -FgYDVQRhDA9WQVRFUy1RMjgyNjAwNEoxLDAqBgNVBAMMI0FDIFJBSVogRk5NVC1S -Q00gU0VSVklET1JFUyBTRUdVUk9TMB4XDTE4MTIyMDA5MzczM1oXDTQzMTIyMDA5 -MzczM1oweDELMAkGA1UEBhMCRVMxETAPBgNVBAoMCEZOTVQtUkNNMQ4wDAYDVQQL -DAVDZXJlczEYMBYGA1UEYQwPVkFURVMtUTI4MjYwMDRKMSwwKgYDVQQDDCNBQyBS -QUlaIEZOTVQtUkNNIFNFUlZJRE9SRVMgU0VHVVJPUzB2MBAGByqGSM49AgEGBSuB -BAAiA2IABPa6V1PIyqvfNkpSIeSX0oNnnvBlUdBeh8dHsVnyV0ebAAKTRBdp20LH -sbI6GA60XYyzZl2hNPk2LEnb80b8s0RpRBNm/dfF/a82Tc4DTQdxz69qBdKiQ1oK -Um8BA06Oi6NCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYD -VR0OBBYEFAG5L++/EYZg8k/QQW6rcx/n0m5JMAoGCCqGSM49BAMDA2kAMGYCMQCu -SuMrQMN0EfKVrRYj3k4MGuZdpSRea0R7/DjiT8ucRRcRTBQnJlU5dUoDzBOQn5IC -MQD6SmxgiHPz7riYYqnOK8LZiqZwMR2vsJRM60/G49HzYqc8/5MuB1xJAWdpEgJy -v+c= ------END CERTIFICATE----- - -# Issuer: CN=GlobalSign Root R46 O=GlobalSign nv-sa -# Subject: CN=GlobalSign Root R46 O=GlobalSign nv-sa -# Label: "GlobalSign Root R46" -# Serial: 1552617688466950547958867513931858518042577 -# MD5 Fingerprint: c4:14:30:e4:fa:66:43:94:2a:6a:1b:24:5f:19:d0:ef -# SHA1 Fingerprint: 53:a2:b0:4b:ca:6b:d6:45:e6:39:8a:8e:c4:0d:d2:bf:77:c3:a2:90 -# SHA256 Fingerprint: 4f:a3:12:6d:8d:3a:11:d1:c4:85:5a:4f:80:7c:ba:d6:cf:91:9d:3a:5a:88:b0:3b:ea:2c:63:72:d9:3c:40:c9 ------BEGIN CERTIFICATE----- -MIIFWjCCA0KgAwIBAgISEdK7udcjGJ5AXwqdLdDfJWfRMA0GCSqGSIb3DQEBDAUA -MEYxCzAJBgNVBAYTAkJFMRkwFwYDVQQKExBHbG9iYWxTaWduIG52LXNhMRwwGgYD -VQQDExNHbG9iYWxTaWduIFJvb3QgUjQ2MB4XDTE5MDMyMDAwMDAwMFoXDTQ2MDMy -MDAwMDAwMFowRjELMAkGA1UEBhMCQkUxGTAXBgNVBAoTEEdsb2JhbFNpZ24gbnYt -c2ExHDAaBgNVBAMTE0dsb2JhbFNpZ24gUm9vdCBSNDYwggIiMA0GCSqGSIb3DQEB -AQUAA4ICDwAwggIKAoICAQCsrHQy6LNl5brtQyYdpokNRbopiLKkHWPd08EsCVeJ -OaFV6Wc0dwxu5FUdUiXSE2te4R2pt32JMl8Nnp8semNgQB+msLZ4j5lUlghYruQG -vGIFAha/r6gjA7aUD7xubMLL1aa7DOn2wQL7Id5m3RerdELv8HQvJfTqa1VbkNud -316HCkD7rRlr+/fKYIje2sGP1q7Vf9Q8g+7XFkyDRTNrJ9CG0Bwta/OrffGFqfUo -0q3v84RLHIf8E6M6cqJaESvWJ3En7YEtbWaBkoe0G1h6zD8K+kZPTXhc+CtI4wSE -y132tGqzZfxCnlEmIyDLPRT5ge1lFgBPGmSXZgjPjHvjK8Cd+RTyG/FWaha/LIWF -zXg4mutCagI0GIMXTpRW+LaCtfOW3T3zvn8gdz57GSNrLNRyc0NXfeD412lPFzYE -+cCQYDdF3uYM2HSNrpyibXRdQr4G9dlkbgIQrImwTDsHTUB+JMWKmIJ5jqSngiCN -I/onccnfxkF0oE32kRbcRoxfKWMxWXEM2G/CtjJ9++ZdU6Z+Ffy7dXxd7Pj2Fxzs -x2sZy/N78CsHpdlseVR2bJ0cpm4O6XkMqCNqo98bMDGfsVR7/mrLZqrcZdCinkqa -ByFrgY/bxFn63iLABJzjqls2k+g9vXqhnQt2sQvHnf3PmKgGwvgqo6GDoLclcqUC -4wIDAQABo0IwQDAOBgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNV -HQ4EFgQUA1yrc4GHqMywptWU4jaWSf8FmSwwDQYJKoZIhvcNAQEMBQADggIBAHx4 -7PYCLLtbfpIrXTncvtgdokIzTfnvpCo7RGkerNlFo048p9gkUbJUHJNOxO97k4Vg -JuoJSOD1u8fpaNK7ajFxzHmuEajwmf3lH7wvqMxX63bEIaZHU1VNaL8FpO7XJqti -2kM3S+LGteWygxk6x9PbTZ4IevPuzz5i+6zoYMzRx6Fcg0XERczzF2sUyQQCPtIk -pnnpHs6i58FZFZ8d4kuaPp92CC1r2LpXFNqD6v6MVenQTqnMdzGxRBF6XLE+0xRF -FRhiJBPSy03OXIPBNvIQtQ6IbbjhVp+J3pZmOUdkLG5NrmJ7v2B0GbhWrJKsFjLt -rWhV/pi60zTe9Mlhww6G9kuEYO4Ne7UyWHmRVSyBQ7N0H3qqJZ4d16GLuc1CLgSk -ZoNNiTW2bKg2SnkheCLQQrzRQDGQob4Ez8pn7fXwgNNgyYMqIgXQBztSvwyeqiv5 -u+YfjyW6hY0XHgL+XVAEV8/+LbzvXMAaq7afJMbfc2hIkCwU9D9SGuTSyxTDYWnP -4vkYxboznxSjBF25cfe1lNj2M8FawTSLfJvdkzrnE6JwYZ+vj+vYxXX4M2bUdGc6 -N3ec592kD3ZDZopD8p/7DEJ4Y9HiD2971KE9dJeFt0g5QdYg/NA6s/rob8SKunE3 -vouXsXgxT7PntgMTzlSdriVZzH81Xwj3QEUxeCp6 ------END CERTIFICATE----- - -# Issuer: CN=GlobalSign Root E46 O=GlobalSign nv-sa -# Subject: CN=GlobalSign Root E46 O=GlobalSign nv-sa -# Label: "GlobalSign Root E46" -# Serial: 1552617690338932563915843282459653771421763 -# MD5 Fingerprint: b5:b8:66:ed:de:08:83:e3:c9:e2:01:34:06:ac:51:6f -# SHA1 Fingerprint: 39:b4:6c:d5:fe:80:06:eb:e2:2f:4a:bb:08:33:a0:af:db:b9:dd:84 -# SHA256 Fingerprint: cb:b9:c4:4d:84:b8:04:3e:10:50:ea:31:a6:9f:51:49:55:d7:bf:d2:e2:c6:b4:93:01:01:9a:d6:1d:9f:50:58 ------BEGIN CERTIFICATE----- -MIICCzCCAZGgAwIBAgISEdK7ujNu1LzmJGjFDYQdmOhDMAoGCCqGSM49BAMDMEYx -CzAJBgNVBAYTAkJFMRkwFwYDVQQKExBHbG9iYWxTaWduIG52LXNhMRwwGgYDVQQD -ExNHbG9iYWxTaWduIFJvb3QgRTQ2MB4XDTE5MDMyMDAwMDAwMFoXDTQ2MDMyMDAw -MDAwMFowRjELMAkGA1UEBhMCQkUxGTAXBgNVBAoTEEdsb2JhbFNpZ24gbnYtc2Ex -HDAaBgNVBAMTE0dsb2JhbFNpZ24gUm9vdCBFNDYwdjAQBgcqhkjOPQIBBgUrgQQA -IgNiAAScDrHPt+ieUnd1NPqlRqetMhkytAepJ8qUuwzSChDH2omwlwxwEwkBjtjq -R+q+soArzfwoDdusvKSGN+1wCAB16pMLey5SnCNoIwZD7JIvU4Tb+0cUB+hflGdd -yXqBPCCjQjBAMA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8EBTADAQH/MB0GA1Ud -DgQWBBQxCpCPtsad0kRLgLWi5h+xEk8blTAKBggqhkjOPQQDAwNoADBlAjEA31SQ -7Zvvi5QCkxeCmb6zniz2C5GMn0oUsfZkvLtoURMMA/cVi4RguYv/Uo7njLwcAjA8 -+RHUjE7AwWHCFUyqqx0LMV87HOIAl0Qx5v5zli/altP+CAezNIm8BZ/3Hobui3A= ------END CERTIFICATE----- - -# Issuer: CN=ANF Secure Server Root CA O=ANF Autoridad de Certificacion OU=ANF CA Raiz -# Subject: CN=ANF Secure Server Root CA O=ANF Autoridad de Certificacion OU=ANF CA Raiz -# Label: "ANF Secure Server Root CA" -# Serial: 996390341000653745 -# MD5 Fingerprint: 26:a6:44:5a:d9:af:4e:2f:b2:1d:b6:65:b0:4e:e8:96 -# SHA1 Fingerprint: 5b:6e:68:d0:cc:15:b6:a0:5f:1e:c1:5f:ae:02:fc:6b:2f:5d:6f:74 -# SHA256 Fingerprint: fb:8f:ec:75:91:69:b9:10:6b:1e:51:16:44:c6:18:c5:13:04:37:3f:6c:06:43:08:8d:8b:ef:fd:1b:99:75:99 ------BEGIN CERTIFICATE----- -MIIF7zCCA9egAwIBAgIIDdPjvGz5a7EwDQYJKoZIhvcNAQELBQAwgYQxEjAQBgNV -BAUTCUc2MzI4NzUxMDELMAkGA1UEBhMCRVMxJzAlBgNVBAoTHkFORiBBdXRvcmlk -YWQgZGUgQ2VydGlmaWNhY2lvbjEUMBIGA1UECxMLQU5GIENBIFJhaXoxIjAgBgNV -BAMTGUFORiBTZWN1cmUgU2VydmVyIFJvb3QgQ0EwHhcNMTkwOTA0MTAwMDM4WhcN -MzkwODMwMTAwMDM4WjCBhDESMBAGA1UEBRMJRzYzMjg3NTEwMQswCQYDVQQGEwJF -UzEnMCUGA1UEChMeQU5GIEF1dG9yaWRhZCBkZSBDZXJ0aWZpY2FjaW9uMRQwEgYD -VQQLEwtBTkYgQ0EgUmFpejEiMCAGA1UEAxMZQU5GIFNlY3VyZSBTZXJ2ZXIgUm9v -dCBDQTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBANvrayvmZFSVgpCj -cqQZAZ2cC4Ffc0m6p6zzBE57lgvsEeBbphzOG9INgxwruJ4dfkUyYA8H6XdYfp9q -yGFOtibBTI3/TO80sh9l2Ll49a2pcbnvT1gdpd50IJeh7WhM3pIXS7yr/2WanvtH -2Vdy8wmhrnZEE26cLUQ5vPnHO6RYPUG9tMJJo8gN0pcvB2VSAKduyK9o7PQUlrZX -H1bDOZ8rbeTzPvY1ZNoMHKGESy9LS+IsJJ1tk0DrtSOOMspvRdOoiXsezx76W0OL -zc2oD2rKDF65nkeP8Nm2CgtYZRczuSPkdxl9y0oukntPLxB3sY0vaJxizOBQ+OyR -p1RMVwnVdmPF6GUe7m1qzwmd+nxPrWAI/VaZDxUse6mAq4xhj0oHdkLePfTdsiQz -W7i1o0TJrH93PB0j7IKppuLIBkwC/qxcmZkLLxCKpvR/1Yd0DVlJRfbwcVw5Kda/ -SiOL9V8BY9KHcyi1Swr1+KuCLH5zJTIdC2MKF4EA/7Z2Xue0sUDKIbvVgFHlSFJn -LNJhiQcND85Cd8BEc5xEUKDbEAotlRyBr+Qc5RQe8TZBAQIvfXOn3kLMTOmJDVb3 -n5HUA8ZsyY/b2BzgQJhdZpmYgG4t/wHFzstGH6wCxkPmrqKEPMVOHj1tyRRM4y5B -u8o5vzY8KhmqQYdOpc5LMnndkEl/AgMBAAGjYzBhMB8GA1UdIwQYMBaAFJxf0Gxj -o1+TypOYCK2Mh6UsXME3MB0GA1UdDgQWBBScX9BsY6Nfk8qTmAitjIelLFzBNzAO -BgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOC -AgEATh65isagmD9uw2nAalxJUqzLK114OMHVVISfk/CHGT0sZonrDUL8zPB1hT+L -9IBdeeUXZ701guLyPI59WzbLWoAAKfLOKyzxj6ptBZNscsdW699QIyjlRRA96Gej -rw5VD5AJYu9LWaL2U/HANeQvwSS9eS9OICI7/RogsKQOLHDtdD+4E5UGUcjohybK -pFtqFiGS3XNgnhAY3jyB6ugYw3yJ8otQPr0R4hUDqDZ9MwFsSBXXiJCZBMXM5gf0 -vPSQ7RPi6ovDj6MzD8EpTBNO2hVWcXNyglD2mjN8orGoGjR0ZVzO0eurU+AagNjq -OknkJjCb5RyKqKkVMoaZkgoQI1YS4PbOTOK7vtuNknMBZi9iPrJyJ0U27U1W45eZ -/zo1PqVUSlJZS2Db7v54EX9K3BR5YLZrZAPbFYPhor72I5dQ8AkzNqdxliXzuUJ9 -2zg/LFis6ELhDtjTO0wugumDLmsx2d1Hhk9tl5EuT+IocTUW0fJz/iUrB0ckYyfI -+PbZa/wSMVYIwFNCr5zQM378BvAxRAMU8Vjq8moNqRGyg77FGr8H6lnco4g175x2 -MjxNBiLOFeXdntiP2t7SxDnlF4HPOEfrf4htWRvfn0IUrn7PqLBmZdo3r5+qPeoo -tt7VMVgWglvquxl1AnMaykgaIZOQCo6ThKd9OyMYkomgjaw= ------END CERTIFICATE----- - -# Issuer: CN=Certum EC-384 CA O=Asseco Data Systems S.A. OU=Certum Certification Authority -# Subject: CN=Certum EC-384 CA O=Asseco Data Systems S.A. OU=Certum Certification Authority -# Label: "Certum EC-384 CA" -# Serial: 160250656287871593594747141429395092468 -# MD5 Fingerprint: b6:65:b3:96:60:97:12:a1:ec:4e:e1:3d:a3:c6:c9:f1 -# SHA1 Fingerprint: f3:3e:78:3c:ac:df:f4:a2:cc:ac:67:55:69:56:d7:e5:16:3c:e1:ed -# SHA256 Fingerprint: 6b:32:80:85:62:53:18:aa:50:d1:73:c9:8d:8b:da:09:d5:7e:27:41:3d:11:4c:f7:87:a0:f5:d0:6c:03:0c:f6 ------BEGIN CERTIFICATE----- -MIICZTCCAeugAwIBAgIQeI8nXIESUiClBNAt3bpz9DAKBggqhkjOPQQDAzB0MQsw -CQYDVQQGEwJQTDEhMB8GA1UEChMYQXNzZWNvIERhdGEgU3lzdGVtcyBTLkEuMScw -JQYDVQQLEx5DZXJ0dW0gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxGTAXBgNVBAMT -EENlcnR1bSBFQy0zODQgQ0EwHhcNMTgwMzI2MDcyNDU0WhcNNDMwMzI2MDcyNDU0 -WjB0MQswCQYDVQQGEwJQTDEhMB8GA1UEChMYQXNzZWNvIERhdGEgU3lzdGVtcyBT -LkEuMScwJQYDVQQLEx5DZXJ0dW0gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxGTAX -BgNVBAMTEENlcnR1bSBFQy0zODQgQ0EwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAATE -KI6rGFtqvm5kN2PkzeyrOvfMobgOgknXhimfoZTy42B4mIF4Bk3y7JoOV2CDn7Tm -Fy8as10CW4kjPMIRBSqniBMY81CE1700LCeJVf/OTOffph8oxPBUw7l8t1Ot68Kj -QjBAMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFI0GZnQkdjrzife81r1HfS+8 -EF9LMA4GA1UdDwEB/wQEAwIBBjAKBggqhkjOPQQDAwNoADBlAjADVS2m5hjEfO/J -UG7BJw+ch69u1RsIGL2SKcHvlJF40jocVYli5RsJHrpka/F2tNQCMQC0QoSZ/6vn -nvuRlydd3LBbMHHOXjgaatkl5+r3YZJW+OraNsKHZZYuciUvf9/DE8k= ------END CERTIFICATE----- - -# Issuer: CN=Certum Trusted Root CA O=Asseco Data Systems S.A. OU=Certum Certification Authority -# Subject: CN=Certum Trusted Root CA O=Asseco Data Systems S.A. OU=Certum Certification Authority -# Label: "Certum Trusted Root CA" -# Serial: 40870380103424195783807378461123655149 -# MD5 Fingerprint: 51:e1:c2:e7:fe:4c:84:af:59:0e:2f:f4:54:6f:ea:29 -# SHA1 Fingerprint: c8:83:44:c0:18:ae:9f:cc:f1:87:b7:8f:22:d1:c5:d7:45:84:ba:e5 -# SHA256 Fingerprint: fe:76:96:57:38:55:77:3e:37:a9:5e:7a:d4:d9:cc:96:c3:01:57:c1:5d:31:76:5b:a9:b1:57:04:e1:ae:78:fd ------BEGIN CERTIFICATE----- -MIIFwDCCA6igAwIBAgIQHr9ZULjJgDdMBvfrVU+17TANBgkqhkiG9w0BAQ0FADB6 -MQswCQYDVQQGEwJQTDEhMB8GA1UEChMYQXNzZWNvIERhdGEgU3lzdGVtcyBTLkEu -MScwJQYDVQQLEx5DZXJ0dW0gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxHzAdBgNV -BAMTFkNlcnR1bSBUcnVzdGVkIFJvb3QgQ0EwHhcNMTgwMzE2MTIxMDEzWhcNNDMw -MzE2MTIxMDEzWjB6MQswCQYDVQQGEwJQTDEhMB8GA1UEChMYQXNzZWNvIERhdGEg -U3lzdGVtcyBTLkEuMScwJQYDVQQLEx5DZXJ0dW0gQ2VydGlmaWNhdGlvbiBBdXRo -b3JpdHkxHzAdBgNVBAMTFkNlcnR1bSBUcnVzdGVkIFJvb3QgQ0EwggIiMA0GCSqG -SIb3DQEBAQUAA4ICDwAwggIKAoICAQDRLY67tzbqbTeRn06TpwXkKQMlzhyC93yZ -n0EGze2jusDbCSzBfN8pfktlL5On1AFrAygYo9idBcEq2EXxkd7fO9CAAozPOA/q -p1x4EaTByIVcJdPTsuclzxFUl6s1wB52HO8AU5853BSlLCIls3Jy/I2z5T4IHhQq -NwuIPMqw9MjCoa68wb4pZ1Xi/K1ZXP69VyywkI3C7Te2fJmItdUDmj0VDT06qKhF -8JVOJVkdzZhpu9PMMsmN74H+rX2Ju7pgE8pllWeg8xn2A1bUatMn4qGtg/BKEiJ3 -HAVz4hlxQsDsdUaakFjgao4rpUYwBI4Zshfjvqm6f1bxJAPXsiEodg42MEx51UGa -mqi4NboMOvJEGyCI98Ul1z3G4z5D3Yf+xOr1Uz5MZf87Sst4WmsXXw3Hw09Omiqi -7VdNIuJGmj8PkTQkfVXjjJU30xrwCSss0smNtA0Aq2cpKNgB9RkEth2+dv5yXMSF -ytKAQd8FqKPVhJBPC/PgP5sZ0jeJP/J7UhyM9uH3PAeXjA6iWYEMspA90+NZRu0P -qafegGtaqge2Gcu8V/OXIXoMsSt0Puvap2ctTMSYnjYJdmZm/Bo/6khUHL4wvYBQ -v3y1zgD2DGHZ5yQD4OMBgQ692IU0iL2yNqh7XAjlRICMb/gv1SHKHRzQ+8S1h9E6 -Tsd2tTVItQIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBSM+xx1 -vALTn04uSNn5YFSqxLNP+jAOBgNVHQ8BAf8EBAMCAQYwDQYJKoZIhvcNAQENBQAD -ggIBAEii1QALLtA/vBzVtVRJHlpr9OTy4EA34MwUe7nJ+jW1dReTagVphZzNTxl4 -WxmB82M+w85bj/UvXgF2Ez8sALnNllI5SW0ETsXpD4YN4fqzX4IS8TrOZgYkNCvo -zMrnadyHncI013nR03e4qllY/p0m+jiGPp2Kh2RX5Rc64vmNueMzeMGQ2Ljdt4NR -5MTMI9UGfOZR0800McD2RrsLrfw9EAUqO0qRJe6M1ISHgCq8CYyqOhNf6DR5UMEQ -GfnTKB7U0VEwKbOukGfWHwpjscWpxkIxYxeU72nLL/qMFH3EQxiJ2fAyQOaA4kZf -5ePBAFmo+eggvIksDkc0C+pXwlM2/KfUrzHN/gLldfq5Jwn58/U7yn2fqSLLiMmq -0Uc9NneoWWRrJ8/vJ8HjJLWG965+Mk2weWjROeiQWMODvA8s1pfrzgzhIMfatz7D -P78v3DSk+yshzWePS/Tj6tQ/50+6uaWTRRxmHyH6ZF5v4HaUMst19W7l9o/HuKTM -qJZ9ZPskWkoDbGs4xugDQ5r3V7mzKWmTOPQD8rv7gmsHINFSH5pkAnuYZttcTVoP -0ISVoDwUQwbKytu4QTbaakRnh6+v40URFWkIsr4WOZckbxJF0WddCajJFdr60qZf -E2Efv4WstK2tBZQIgx51F9NxO5NQI1mg7TyRVJ12AMXDuDjb ------END CERTIFICATE----- - -# Issuer: CN=TunTrust Root CA O=Agence Nationale de Certification Electronique -# Subject: CN=TunTrust Root CA O=Agence Nationale de Certification Electronique -# Label: "TunTrust Root CA" -# Serial: 108534058042236574382096126452369648152337120275 -# MD5 Fingerprint: 85:13:b9:90:5b:36:5c:b6:5e:b8:5a:f8:e0:31:57:b4 -# SHA1 Fingerprint: cf:e9:70:84:0f:e0:73:0f:9d:f6:0c:7f:2c:4b:ee:20:46:34:9c:bb -# SHA256 Fingerprint: 2e:44:10:2a:b5:8c:b8:54:19:45:1c:8e:19:d9:ac:f3:66:2c:af:bc:61:4b:6a:53:96:0a:30:f7:d0:e2:eb:41 ------BEGIN CERTIFICATE----- -MIIFszCCA5ugAwIBAgIUEwLV4kBMkkaGFmddtLu7sms+/BMwDQYJKoZIhvcNAQEL -BQAwYTELMAkGA1UEBhMCVE4xNzA1BgNVBAoMLkFnZW5jZSBOYXRpb25hbGUgZGUg -Q2VydGlmaWNhdGlvbiBFbGVjdHJvbmlxdWUxGTAXBgNVBAMMEFR1blRydXN0IFJv -b3QgQ0EwHhcNMTkwNDI2MDg1NzU2WhcNNDQwNDI2MDg1NzU2WjBhMQswCQYDVQQG -EwJUTjE3MDUGA1UECgwuQWdlbmNlIE5hdGlvbmFsZSBkZSBDZXJ0aWZpY2F0aW9u -IEVsZWN0cm9uaXF1ZTEZMBcGA1UEAwwQVHVuVHJ1c3QgUm9vdCBDQTCCAiIwDQYJ -KoZIhvcNAQEBBQADggIPADCCAgoCggIBAMPN0/y9BFPdDCA61YguBUtB9YOCfvdZ -n56eY+hz2vYGqU8ftPkLHzmMmiDQfgbU7DTZhrx1W4eI8NLZ1KMKsmwb60ksPqxd -2JQDoOw05TDENX37Jk0bbjBU2PWARZw5rZzJJQRNmpA+TkBuimvNKWfGzC3gdOgF -VwpIUPp6Q9p+7FuaDmJ2/uqdHYVy7BG7NegfJ7/Boce7SBbdVtfMTqDhuazb1YMZ -GoXRlJfXyqNlC/M4+QKu3fZnz8k/9YosRxqZbwUN/dAdgjH8KcwAWJeRTIAAHDOF -li/LQcKLEITDCSSJH7UP2dl3RxiSlGBcx5kDPP73lad9UKGAwqmDrViWVSHbhlnU -r8a83YFuB9tgYv7sEG7aaAH0gxupPqJbI9dkxt/con3YS7qC0lH4Zr8GRuR5KiY2 -eY8fTpkdso8MDhz/yV3A/ZAQprE38806JG60hZC/gLkMjNWb1sjxVj8agIl6qeIb -MlEsPvLfe/ZdeikZjuXIvTZxi11Mwh0/rViizz1wTaZQmCXcI/m4WEEIcb9PuISg -jwBUFfyRbVinljvrS5YnzWuioYasDXxU5mZMZl+QviGaAkYt5IPCgLnPSz7ofzwB -7I9ezX/SKEIBlYrilz0QIX32nRzFNKHsLA4KUiwSVXAkPcvCFDVDXSdOvsC9qnyW -5/yeYa1E0wCXAgMBAAGjYzBhMB0GA1UdDgQWBBQGmpsfU33x9aTI04Y+oXNZtPdE -ITAPBgNVHRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFAaamx9TffH1pMjThj6hc1m0 -90QhMA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQsFAAOCAgEAqgVutt0Vyb+z -xiD2BkewhpMl0425yAA/l/VSJ4hxyXT968pk21vvHl26v9Hr7lxpuhbI87mP0zYu -QEkHDVneixCwSQXi/5E/S7fdAo74gShczNxtr18UnH1YeA32gAm56Q6XKRm4t+v4 -FstVEuTGfbvE7Pi1HE4+Z7/FXxttbUcoqgRYYdZ2vyJ/0Adqp2RT8JeNnYA/u8EH -22Wv5psymsNUk8QcCMNE+3tjEUPRahphanltkE8pjkcFwRJpadbGNjHh/PqAulxP -xOu3Mqz4dWEX1xAZufHSCe96Qp1bWgvUxpVOKs7/B9dPfhgGiPEZtdmYu65xxBzn -dFlY7wyJz4sfdZMaBBSSSFCp61cpABbjNhzI+L/wM9VBD8TMPN3pM0MBkRArHtG5 -Xc0yGYuPjCB31yLEQtyEFpslbei0VXF/sHyz03FJuc9SpAQ/3D2gu68zngowYI7b -nV2UqL1g52KAdoGDDIzMMEZJ4gzSqK/rYXHv5yJiqfdcZGyfFoxnNidF9Ql7v/YQ -CvGwjVRDjAS6oz/v4jXH+XTgbzRB0L9zZVcg+ZtnemZoJE6AZb0QmQZZ8mWvuMZH -u/2QeItBcy6vVR/cO5JyboTT0GFMDcx2V+IthSIVNg3rAZ3r2OvEhJn7wAzMMujj -d9qDRIueVSjAi1jTkD5OGwDxFa2DK5o= ------END CERTIFICATE----- - -# Issuer: CN=HARICA TLS RSA Root CA 2021 O=Hellenic Academic and Research Institutions CA -# Subject: CN=HARICA TLS RSA Root CA 2021 O=Hellenic Academic and Research Institutions CA -# Label: "HARICA TLS RSA Root CA 2021" -# Serial: 76817823531813593706434026085292783742 -# MD5 Fingerprint: 65:47:9b:58:86:dd:2c:f0:fc:a2:84:1f:1e:96:c4:91 -# SHA1 Fingerprint: 02:2d:05:82:fa:88:ce:14:0c:06:79:de:7f:14:10:e9:45:d7:a5:6d -# SHA256 Fingerprint: d9:5d:0e:8e:da:79:52:5b:f9:be:b1:1b:14:d2:10:0d:32:94:98:5f:0c:62:d9:fa:bd:9c:d9:99:ec:cb:7b:1d ------BEGIN CERTIFICATE----- -MIIFpDCCA4ygAwIBAgIQOcqTHO9D88aOk8f0ZIk4fjANBgkqhkiG9w0BAQsFADBs -MQswCQYDVQQGEwJHUjE3MDUGA1UECgwuSGVsbGVuaWMgQWNhZGVtaWMgYW5kIFJl -c2VhcmNoIEluc3RpdHV0aW9ucyBDQTEkMCIGA1UEAwwbSEFSSUNBIFRMUyBSU0Eg -Um9vdCBDQSAyMDIxMB4XDTIxMDIxOTEwNTUzOFoXDTQ1MDIxMzEwNTUzN1owbDEL -MAkGA1UEBhMCR1IxNzA1BgNVBAoMLkhlbGxlbmljIEFjYWRlbWljIGFuZCBSZXNl -YXJjaCBJbnN0aXR1dGlvbnMgQ0ExJDAiBgNVBAMMG0hBUklDQSBUTFMgUlNBIFJv -b3QgQ0EgMjAyMTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAIvC569l -mwVnlskNJLnQDmT8zuIkGCyEf3dRywQRNrhe7Wlxp57kJQmXZ8FHws+RFjZiPTgE -4VGC/6zStGndLuwRo0Xua2s7TL+MjaQenRG56Tj5eg4MmOIjHdFOY9TnuEFE+2uv -a9of08WRiFukiZLRgeaMOVig1mlDqa2YUlhu2wr7a89o+uOkXjpFc5gH6l8Cct4M -pbOfrqkdtx2z/IpZ525yZa31MJQjB/OCFks1mJxTuy/K5FrZx40d/JiZ+yykgmvw -Kh+OC19xXFyuQnspiYHLA6OZyoieC0AJQTPb5lh6/a6ZcMBaD9YThnEvdmn8kN3b -LW7R8pv1GmuebxWMevBLKKAiOIAkbDakO/IwkfN4E8/BPzWr8R0RI7VDIp4BkrcY -AuUR0YLbFQDMYTfBKnya4dC6s1BG7oKsnTH4+yPiAwBIcKMJJnkVU2DzOFytOOqB -AGMUuTNe3QvboEUHGjMJ+E20pwKmafTCWQWIZYVWrkvL4N48fS0ayOn7H6NhStYq -E613TBoYm5EPWNgGVMWX+Ko/IIqmhaZ39qb8HOLubpQzKoNQhArlT4b4UEV4AIHr -W2jjJo3Me1xR9BQsQL4aYB16cmEdH2MtiKrOokWQCPxrvrNQKlr9qEgYRtaQQJKQ -CoReaDH46+0N0x3GfZkYVVYnZS6NRcUk7M7jAgMBAAGjQjBAMA8GA1UdEwEB/wQF -MAMBAf8wHQYDVR0OBBYEFApII6ZgpJIKM+qTW8VX6iVNvRLuMA4GA1UdDwEB/wQE -AwIBhjANBgkqhkiG9w0BAQsFAAOCAgEAPpBIqm5iFSVmewzVjIuJndftTgfvnNAU -X15QvWiWkKQUEapobQk1OUAJ2vQJLDSle1mESSmXdMgHHkdt8s4cUCbjnj1AUz/3 -f5Z2EMVGpdAgS1D0NTsY9FVqQRtHBmg8uwkIYtlfVUKqrFOFrJVWNlar5AWMxaja -H6NpvVMPxP/cyuN+8kyIhkdGGvMA9YCRotxDQpSbIPDRzbLrLFPCU3hKTwSUQZqP -JzLB5UkZv/HywouoCjkxKLR9YjYsTewfM7Z+d21+UPCfDtcRj88YxeMn/ibvBZ3P -zzfF0HvaO7AWhAw6k9a+F9sPPg4ZeAnHqQJyIkv3N3a6dcSFA1pj1bF1BcK5vZSt -jBWZp5N99sXzqnTPBIWUmAD04vnKJGW/4GKvyMX6ssmeVkjaef2WdhW+o45WxLM0 -/L5H9MG0qPzVMIho7suuyWPEdr6sOBjhXlzPrjoiUevRi7PzKzMHVIf6tLITe7pT -BGIBnfHAT+7hOtSLIBD6Alfm78ELt5BGnBkpjNxvoEppaZS3JGWg/6w/zgH7IS79 -aPib8qXPMThcFarmlwDB31qlpzmq6YR/PFGoOtmUW4y/Twhx5duoXNTSpv4Ao8YW -xw/ogM4cKGR0GQjTQuPOAF1/sdwTsOEFy9EgqoZ0njnnkf3/W9b3raYvAwtt41dU -63ZTGI0RmLo= ------END CERTIFICATE----- - -# Issuer: CN=HARICA TLS ECC Root CA 2021 O=Hellenic Academic and Research Institutions CA -# Subject: CN=HARICA TLS ECC Root CA 2021 O=Hellenic Academic and Research Institutions CA -# Label: "HARICA TLS ECC Root CA 2021" -# Serial: 137515985548005187474074462014555733966 -# MD5 Fingerprint: ae:f7:4c:e5:66:35:d1:b7:9b:8c:22:93:74:d3:4b:b0 -# SHA1 Fingerprint: bc:b0:c1:9d:e9:98:92:70:19:38:57:e9:8d:a7:b4:5d:6e:ee:01:48 -# SHA256 Fingerprint: 3f:99:cc:47:4a:cf:ce:4d:fe:d5:87:94:66:5e:47:8d:15:47:73:9f:2e:78:0f:1b:b4:ca:9b:13:30:97:d4:01 ------BEGIN CERTIFICATE----- -MIICVDCCAdugAwIBAgIQZ3SdjXfYO2rbIvT/WeK/zjAKBggqhkjOPQQDAzBsMQsw -CQYDVQQGEwJHUjE3MDUGA1UECgwuSGVsbGVuaWMgQWNhZGVtaWMgYW5kIFJlc2Vh -cmNoIEluc3RpdHV0aW9ucyBDQTEkMCIGA1UEAwwbSEFSSUNBIFRMUyBFQ0MgUm9v -dCBDQSAyMDIxMB4XDTIxMDIxOTExMDExMFoXDTQ1MDIxMzExMDEwOVowbDELMAkG -A1UEBhMCR1IxNzA1BgNVBAoMLkhlbGxlbmljIEFjYWRlbWljIGFuZCBSZXNlYXJj -aCBJbnN0aXR1dGlvbnMgQ0ExJDAiBgNVBAMMG0hBUklDQSBUTFMgRUNDIFJvb3Qg -Q0EgMjAyMTB2MBAGByqGSM49AgEGBSuBBAAiA2IABDgI/rGgltJ6rK9JOtDA4MM7 -KKrxcm1lAEeIhPyaJmuqS7psBAqIXhfyVYf8MLA04jRYVxqEU+kw2anylnTDUR9Y -STHMmE5gEYd103KUkE+bECUqqHgtvpBBWJAVcqeht6NCMEAwDwYDVR0TAQH/BAUw -AwEB/zAdBgNVHQ4EFgQUyRtTgRL+BNUW0aq8mm+3oJUZbsowDgYDVR0PAQH/BAQD -AgGGMAoGCCqGSM49BAMDA2cAMGQCMBHervjcToiwqfAircJRQO9gcS3ujwLEXQNw -SaSS6sUUiHCm0w2wqsosQJz76YJumgIwK0eaB8bRwoF8yguWGEEbo/QwCZ61IygN -nxS2PFOiTAZpffpskcYqSUXm7LcT4Tps ------END CERTIFICATE----- - -# Issuer: CN=Autoridad de Certificacion Firmaprofesional CIF A62634068 -# Subject: CN=Autoridad de Certificacion Firmaprofesional CIF A62634068 -# Label: "Autoridad de Certificacion Firmaprofesional CIF A62634068" -# Serial: 1977337328857672817 -# MD5 Fingerprint: 4e:6e:9b:54:4c:ca:b7:fa:48:e4:90:b1:15:4b:1c:a3 -# SHA1 Fingerprint: 0b:be:c2:27:22:49:cb:39:aa:db:35:5c:53:e3:8c:ae:78:ff:b6:fe -# SHA256 Fingerprint: 57:de:05:83:ef:d2:b2:6e:03:61:da:99:da:9d:f4:64:8d:ef:7e:e8:44:1c:3b:72:8a:fa:9b:cd:e0:f9:b2:6a ------BEGIN CERTIFICATE----- -MIIGFDCCA/ygAwIBAgIIG3Dp0v+ubHEwDQYJKoZIhvcNAQELBQAwUTELMAkGA1UE -BhMCRVMxQjBABgNVBAMMOUF1dG9yaWRhZCBkZSBDZXJ0aWZpY2FjaW9uIEZpcm1h -cHJvZmVzaW9uYWwgQ0lGIEE2MjYzNDA2ODAeFw0xNDA5MjMxNTIyMDdaFw0zNjA1 -MDUxNTIyMDdaMFExCzAJBgNVBAYTAkVTMUIwQAYDVQQDDDlBdXRvcmlkYWQgZGUg -Q2VydGlmaWNhY2lvbiBGaXJtYXByb2Zlc2lvbmFsIENJRiBBNjI2MzQwNjgwggIi -MA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDKlmuO6vj78aI14H9M2uDDUtd9 -thDIAl6zQyrET2qyyhxdKJp4ERppWVevtSBC5IsP5t9bpgOSL/UR5GLXMnE42QQM -cas9UX4PB99jBVzpv5RvwSmCwLTaUbDBPLutN0pcyvFLNg4kq7/DhHf9qFD0sefG -L9ItWY16Ck6WaVICqjaY7Pz6FIMMNx/Jkjd/14Et5cS54D40/mf0PmbR0/RAz15i -NA9wBj4gGFrO93IbJWyTdBSTo3OxDqqHECNZXyAFGUftaI6SEspd/NYrspI8IM/h -X68gvqB2f3bl7BqGYTM+53u0P6APjqK5am+5hyZvQWyIplD9amML9ZMWGxmPsu2b -m8mQ9QEM3xk9Dz44I8kvjwzRAv4bVdZO0I08r0+k8/6vKtMFnXkIoctXMbScyJCy -Z/QYFpM6/EfY0XiWMR+6KwxfXZmtY4laJCB22N/9q06mIqqdXuYnin1oKaPnirja -EbsXLZmdEyRG98Xi2J+Of8ePdG1asuhy9azuJBCtLxTa/y2aRnFHvkLfuwHb9H/T -KI8xWVvTyQKmtFLKbpf7Q8UIJm+K9Lv9nyiqDdVF8xM6HdjAeI9BZzwelGSuewvF -6NkBiDkal4ZkQdU7hwxu+g/GvUgUvzlN1J5Bto+WHWOWk9mVBngxaJ43BjuAiUVh -OSPHG0SjFeUc+JIwuwIDAQABo4HvMIHsMB0GA1UdDgQWBBRlzeurNR4APn7VdMAc -tHNHDhpkLzASBgNVHRMBAf8ECDAGAQH/AgEBMIGmBgNVHSAEgZ4wgZswgZgGBFUd -IAAwgY8wLwYIKwYBBQUHAgEWI2h0dHA6Ly93d3cuZmlybWFwcm9mZXNpb25hbC5j -b20vY3BzMFwGCCsGAQUFBwICMFAeTgBQAGEAcwBlAG8AIABkAGUAIABsAGEAIABC -AG8AbgBhAG4AbwB2AGEAIAA0ADcAIABCAGEAcgBjAGUAbABvAG4AYQAgADAAOAAw -ADEANzAOBgNVHQ8BAf8EBAMCAQYwDQYJKoZIhvcNAQELBQADggIBAHSHKAIrdx9m -iWTtj3QuRhy7qPj4Cx2Dtjqn6EWKB7fgPiDL4QjbEwj4KKE1soCzC1HA01aajTNF -Sa9J8OA9B3pFE1r/yJfY0xgsfZb43aJlQ3CTkBW6kN/oGbDbLIpgD7dvlAceHabJ -hfa9NPhAeGIQcDq+fUs5gakQ1JZBu/hfHAsdCPKxsIl68veg4MSPi3i1O1ilI45P -Vf42O+AMt8oqMEEgtIDNrvx2ZnOorm7hfNoD6JQg5iKj0B+QXSBTFCZX2lSX3xZE -EAEeiGaPcjiT3SC3NL7X8e5jjkd5KAb881lFJWAiMxujX6i6KtoaPc1A6ozuBRWV -1aUsIC+nmCjuRfzxuIgALI9C2lHVnOUTaHFFQ4ueCyE8S1wF3BqfmI7avSKecs2t -CsvMo2ebKHTEm9caPARYpoKdrcd7b/+Alun4jWq9GJAd/0kakFI3ky88Al2CdgtR -5xbHV/g4+afNmyJU72OwFW1TZQNKXkqgsqeOSQBZONXH9IBk9W6VULgRfhVwOEqw -f9DEMnDAGf/JOC0ULGb0QkTmVXYbgBVX/8Cnp6o5qtjTcNAuuuuUavpfNIbnYrX9 -ivAwhZTJryQCL2/W3Wf+47BVTwSYT6RBVuKT0Gro1vP7ZeDOdcQxWQzugsgMYDNK -GbqEZycPvEJdvSRUDewdcAZfpLz6IHxV ------END CERTIFICATE----- - -# Issuer: CN=vTrus ECC Root CA O=iTrusChina Co.,Ltd. -# Subject: CN=vTrus ECC Root CA O=iTrusChina Co.,Ltd. -# Label: "vTrus ECC Root CA" -# Serial: 630369271402956006249506845124680065938238527194 -# MD5 Fingerprint: de:4b:c1:f5:52:8c:9b:43:e1:3e:8f:55:54:17:8d:85 -# SHA1 Fingerprint: f6:9c:db:b0:fc:f6:02:13:b6:52:32:a6:a3:91:3f:16:70:da:c3:e1 -# SHA256 Fingerprint: 30:fb:ba:2c:32:23:8e:2a:98:54:7a:f9:79:31:e5:50:42:8b:9b:3f:1c:8e:eb:66:33:dc:fa:86:c5:b2:7d:d3 ------BEGIN CERTIFICATE----- -MIICDzCCAZWgAwIBAgIUbmq8WapTvpg5Z6LSa6Q75m0c1towCgYIKoZIzj0EAwMw -RzELMAkGA1UEBhMCQ04xHDAaBgNVBAoTE2lUcnVzQ2hpbmEgQ28uLEx0ZC4xGjAY -BgNVBAMTEXZUcnVzIEVDQyBSb290IENBMB4XDTE4MDczMTA3MjY0NFoXDTQzMDcz -MTA3MjY0NFowRzELMAkGA1UEBhMCQ04xHDAaBgNVBAoTE2lUcnVzQ2hpbmEgQ28u -LEx0ZC4xGjAYBgNVBAMTEXZUcnVzIEVDQyBSb290IENBMHYwEAYHKoZIzj0CAQYF -K4EEACIDYgAEZVBKrox5lkqqHAjDo6LN/llWQXf9JpRCux3NCNtzslt188+cToL0 -v/hhJoVs1oVbcnDS/dtitN9Ti72xRFhiQgnH+n9bEOf+QP3A2MMrMudwpremIFUd -e4BdS49nTPEQo0IwQDAdBgNVHQ4EFgQUmDnNvtiyjPeyq+GtJK97fKHbH88wDwYD -VR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwCgYIKoZIzj0EAwMDaAAwZQIw -V53dVvHH4+m4SVBrm2nDb+zDfSXkV5UTQJtS0zvzQBm8JsctBp61ezaf9SXUY2sA -AjEA6dPGnlaaKsyh2j/IZivTWJwghfqrkYpwcBE4YGQLYgmRWAD5Tfs0aNoJrSEG -GJTO ------END CERTIFICATE----- - -# Issuer: CN=vTrus Root CA O=iTrusChina Co.,Ltd. -# Subject: CN=vTrus Root CA O=iTrusChina Co.,Ltd. -# Label: "vTrus Root CA" -# Serial: 387574501246983434957692974888460947164905180485 -# MD5 Fingerprint: b8:c9:37:df:fa:6b:31:84:64:c5:ea:11:6a:1b:75:fc -# SHA1 Fingerprint: 84:1a:69:fb:f5:cd:1a:25:34:13:3d:e3:f8:fc:b8:99:d0:c9:14:b7 -# SHA256 Fingerprint: 8a:71:de:65:59:33:6f:42:6c:26:e5:38:80:d0:0d:88:a1:8d:a4:c6:a9:1f:0d:cb:61:94:e2:06:c5:c9:63:87 ------BEGIN CERTIFICATE----- -MIIFVjCCAz6gAwIBAgIUQ+NxE9izWRRdt86M/TX9b7wFjUUwDQYJKoZIhvcNAQEL -BQAwQzELMAkGA1UEBhMCQ04xHDAaBgNVBAoTE2lUcnVzQ2hpbmEgQ28uLEx0ZC4x -FjAUBgNVBAMTDXZUcnVzIFJvb3QgQ0EwHhcNMTgwNzMxMDcyNDA1WhcNNDMwNzMx -MDcyNDA1WjBDMQswCQYDVQQGEwJDTjEcMBoGA1UEChMTaVRydXNDaGluYSBDby4s -THRkLjEWMBQGA1UEAxMNdlRydXMgUm9vdCBDQTCCAiIwDQYJKoZIhvcNAQEBBQAD -ggIPADCCAgoCggIBAL1VfGHTuB0EYgWgrmy3cLRB6ksDXhA/kFocizuwZotsSKYc -IrrVQJLuM7IjWcmOvFjai57QGfIvWcaMY1q6n6MLsLOaXLoRuBLpDLvPbmyAhykU -AyyNJJrIZIO1aqwTLDPxn9wsYTwaP3BVm60AUn/PBLn+NvqcwBauYv6WTEN+VRS+ -GrPSbcKvdmaVayqwlHeFXgQPYh1jdfdr58tbmnDsPmcF8P4HCIDPKNsFxhQnL4Z9 -8Cfe/+Z+M0jnCx5Y0ScrUw5XSmXX+6KAYPxMvDVTAWqXcoKv8R1w6Jz1717CbMdH -flqUhSZNO7rrTOiwCcJlwp2dCZtOtZcFrPUGoPc2BX70kLJrxLT5ZOrpGgrIDajt -J8nU57O5q4IikCc9Kuh8kO+8T/3iCiSn3mUkpF3qwHYw03dQ+A0Em5Q2AXPKBlim -0zvc+gRGE1WKyURHuFE5Gi7oNOJ5y1lKCn+8pu8fA2dqWSslYpPZUxlmPCdiKYZN -pGvu/9ROutW04o5IWgAZCfEF2c6Rsffr6TlP9m8EQ5pV9T4FFL2/s1m02I4zhKOQ -UqqzApVg+QxMaPnu1RcN+HFXtSXkKe5lXa/R7jwXC1pDxaWG6iSe4gUH3DRCEpHW -OXSuTEGC2/KmSNGzm/MzqvOmwMVO9fSddmPmAsYiS8GVP1BkLFTltvA8Kc9XAgMB -AAGjQjBAMB0GA1UdDgQWBBRUYnBj8XWEQ1iO0RYgscasGrz2iTAPBgNVHRMBAf8E -BTADAQH/MA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQsFAAOCAgEAKbqSSaet -8PFww+SX8J+pJdVrnjT+5hpk9jprUrIQeBqfTNqK2uwcN1LgQkv7bHbKJAs5EhWd -nxEt/Hlk3ODg9d3gV8mlsnZwUKT+twpw1aA08XXXTUm6EdGz2OyC/+sOxL9kLX1j -bhd47F18iMjrjld22VkE+rxSH0Ws8HqA7Oxvdq6R2xCOBNyS36D25q5J08FsEhvM -Kar5CKXiNxTKsbhm7xqC5PD48acWabfbqWE8n/Uxy+QARsIvdLGx14HuqCaVvIiv -TDUHKgLKeBRtRytAVunLKmChZwOgzoy8sHJnxDHO2zTlJQNgJXtxmOTAGytfdELS -S8VZCAeHvsXDf+eW2eHcKJfWjwXj9ZtOyh1QRwVTsMo554WgicEFOwE30z9J4nfr -I8iIZjs9OXYhRvHsXyO466JmdXTBQPfYaJqT4i2pLr0cox7IdMakLXogqzu4sEb9 -b91fUlV1YvCXoHzXOP0l382gmxDPi7g4Xl7FtKYCNqEeXxzP4padKar9mK5S4fNB -UvupLnKWnyfjqnN9+BojZns7q2WwMgFLFT49ok8MKzWixtlnEjUwzXYuFrOZnk1P -Ti07NEPhmg4NpGaXutIcSkwsKouLgU9xGqndXHt7CMUADTdA43x7VF8vhV929ven -sBxXVsFy6K2ir40zSbofitzmdHxghm+Hl3s= ------END CERTIFICATE----- - -# Issuer: CN=ISRG Root X2 O=Internet Security Research Group -# Subject: CN=ISRG Root X2 O=Internet Security Research Group -# Label: "ISRG Root X2" -# Serial: 87493402998870891108772069816698636114 -# MD5 Fingerprint: d3:9e:c4:1e:23:3c:a6:df:cf:a3:7e:6d:e0:14:e6:e5 -# SHA1 Fingerprint: bd:b1:b9:3c:d5:97:8d:45:c6:26:14:55:f8:db:95:c7:5a:d1:53:af -# SHA256 Fingerprint: 69:72:9b:8e:15:a8:6e:fc:17:7a:57:af:b7:17:1d:fc:64:ad:d2:8c:2f:ca:8c:f1:50:7e:34:45:3c:cb:14:70 ------BEGIN CERTIFICATE----- -MIICGzCCAaGgAwIBAgIQQdKd0XLq7qeAwSxs6S+HUjAKBggqhkjOPQQDAzBPMQsw -CQYDVQQGEwJVUzEpMCcGA1UEChMgSW50ZXJuZXQgU2VjdXJpdHkgUmVzZWFyY2gg -R3JvdXAxFTATBgNVBAMTDElTUkcgUm9vdCBYMjAeFw0yMDA5MDQwMDAwMDBaFw00 -MDA5MTcxNjAwMDBaME8xCzAJBgNVBAYTAlVTMSkwJwYDVQQKEyBJbnRlcm5ldCBT -ZWN1cml0eSBSZXNlYXJjaCBHcm91cDEVMBMGA1UEAxMMSVNSRyBSb290IFgyMHYw -EAYHKoZIzj0CAQYFK4EEACIDYgAEzZvVn4CDCuwJSvMWSj5cz3es3mcFDR0HttwW -+1qLFNvicWDEukWVEYmO6gbf9yoWHKS5xcUy4APgHoIYOIvXRdgKam7mAHf7AlF9 -ItgKbppbd9/w+kHsOdx1ymgHDB/qo0IwQDAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0T -AQH/BAUwAwEB/zAdBgNVHQ4EFgQUfEKWrt5LSDv6kviejM9ti6lyN5UwCgYIKoZI -zj0EAwMDaAAwZQIwe3lORlCEwkSHRhtFcP9Ymd70/aTSVaYgLXTWNLxBo1BfASdW -tL4ndQavEi51mI38AjEAi/V3bNTIZargCyzuFJ0nN6T5U6VR5CmD1/iQMVtCnwr1 -/q4AaOeMSQ+2b1tbFfLn ------END CERTIFICATE----- - -# Issuer: CN=HiPKI Root CA - G1 O=Chunghwa Telecom Co., Ltd. -# Subject: CN=HiPKI Root CA - G1 O=Chunghwa Telecom Co., Ltd. -# Label: "HiPKI Root CA - G1" -# Serial: 60966262342023497858655262305426234976 -# MD5 Fingerprint: 69:45:df:16:65:4b:e8:68:9a:8f:76:5f:ff:80:9e:d3 -# SHA1 Fingerprint: 6a:92:e4:a8:ee:1b:ec:96:45:37:e3:29:57:49:cd:96:e3:e5:d2:60 -# SHA256 Fingerprint: f0:15:ce:3c:c2:39:bf:ef:06:4b:e9:f1:d2:c4:17:e1:a0:26:4a:0a:94:be:1f:0c:8d:12:18:64:eb:69:49:cc ------BEGIN CERTIFICATE----- -MIIFajCCA1KgAwIBAgIQLd2szmKXlKFD6LDNdmpeYDANBgkqhkiG9w0BAQsFADBP -MQswCQYDVQQGEwJUVzEjMCEGA1UECgwaQ2h1bmdod2EgVGVsZWNvbSBDby4sIEx0 -ZC4xGzAZBgNVBAMMEkhpUEtJIFJvb3QgQ0EgLSBHMTAeFw0xOTAyMjIwOTQ2MDRa -Fw0zNzEyMzExNTU5NTlaME8xCzAJBgNVBAYTAlRXMSMwIQYDVQQKDBpDaHVuZ2h3 -YSBUZWxlY29tIENvLiwgTHRkLjEbMBkGA1UEAwwSSGlQS0kgUm9vdCBDQSAtIEcx -MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA9B5/UnMyDHPkvRN0o9Qw -qNCuS9i233VHZvR85zkEHmpwINJaR3JnVfSl6J3VHiGh8Ge6zCFovkRTv4354twv -Vcg3Px+kwJyz5HdcoEb+d/oaoDjq7Zpy3iu9lFc6uux55199QmQ5eiY29yTw1S+6 -lZgRZq2XNdZ1AYDgr/SEYYwNHl98h5ZeQa/rh+r4XfEuiAU+TCK72h8q3VJGZDnz -Qs7ZngyzsHeXZJzA9KMuH5UHsBffMNsAGJZMoYFL3QRtU6M9/Aes1MU3guvklQgZ -KILSQjqj2FPseYlgSGDIcpJQ3AOPgz+yQlda22rpEZfdhSi8MEyr48KxRURHH+CK -FgeW0iEPU8DtqX7UTuybCeyvQqww1r/REEXgphaypcXTT3OUM3ECoWqj1jOXTyFj -HluP2cFeRXF3D4FdXyGarYPM+l7WjSNfGz1BryB1ZlpK9p/7qxj3ccC2HTHsOyDr -y+K49a6SsvfhhEvyovKTmiKe0xRvNlS9H15ZFblzqMF8b3ti6RZsR1pl8w4Rm0bZ -/W3c1pzAtH2lsN0/Vm+h+fbkEkj9Bn8SV7apI09bA8PgcSojt/ewsTu8mL3WmKgM -a/aOEmem8rJY5AIJEzypuxC00jBF8ez3ABHfZfjcK0NVvxaXxA/VLGGEqnKG/uY6 -fsI/fe78LxQ+5oXdUG+3Se0CAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAdBgNV -HQ4EFgQU8ncX+l6o/vY9cdVouslGDDjYr7AwDgYDVR0PAQH/BAQDAgGGMA0GCSqG -SIb3DQEBCwUAA4ICAQBQUfB13HAE4/+qddRxosuej6ip0691x1TPOhwEmSKsxBHi -7zNKpiMdDg1H2DfHb680f0+BazVP6XKlMeJ45/dOlBhbQH3PayFUhuaVevvGyuqc -SE5XCV0vrPSltJczWNWseanMX/mF+lLFjfiRFOs6DRfQUsJ748JzjkZ4Bjgs6Fza -ZsT0pPBWGTMpWmWSBUdGSquEwx4noR8RkpkndZMPvDY7l1ePJlsMu5wP1G4wB9Tc -XzZoZjmDlicmisjEOf6aIW/Vcobpf2Lll07QJNBAsNB1CI69aO4I1258EHBGG3zg -iLKecoaZAeO/n0kZtCW+VmWuF2PlHt/o/0elv+EmBYTksMCv5wiZqAxeJoBF1Pho -L5aPruJKHJwWDBNvOIf2u8g0X5IDUXlwpt/L9ZlNec1OvFefQ05rLisY+GpzjLrF -Ne85akEez3GoorKGB1s6yeHvP2UEgEcyRHCVTjFnanRbEEV16rCf0OY1/k6fi8wr -kkVbbiVghUbN0aqwdmaTd5a+g744tiROJgvM7XpWGuDpWsZkrUx6AEhEL7lAuxM+ -vhV4nYWBSipX3tUZQ9rbyltHhoMLP7YNdnhzeSJesYAfz77RP1YQmCuVh6EfnWQU -YDksswBVLuT1sw5XxJFBAJw/6KXf6vb/yPCtbVKoF6ubYfwSUTXkJf2vqmqGOQ== ------END CERTIFICATE----- - -# Issuer: CN=GlobalSign O=GlobalSign OU=GlobalSign ECC Root CA - R4 -# Subject: CN=GlobalSign O=GlobalSign OU=GlobalSign ECC Root CA - R4 -# Label: "GlobalSign ECC Root CA - R4" -# Serial: 159662223612894884239637590694 -# MD5 Fingerprint: 26:29:f8:6d:e1:88:bf:a2:65:7f:aa:c4:cd:0f:7f:fc -# SHA1 Fingerprint: 6b:a0:b0:98:e1:71:ef:5a:ad:fe:48:15:80:77:10:f4:bd:6f:0b:28 -# SHA256 Fingerprint: b0:85:d7:0b:96:4f:19:1a:73:e4:af:0d:54:ae:7a:0e:07:aa:fd:af:9b:71:dd:08:62:13:8a:b7:32:5a:24:a2 ------BEGIN CERTIFICATE----- -MIIB3DCCAYOgAwIBAgINAgPlfvU/k/2lCSGypjAKBggqhkjOPQQDAjBQMSQwIgYD -VQQLExtHbG9iYWxTaWduIEVDQyBSb290IENBIC0gUjQxEzARBgNVBAoTCkdsb2Jh -bFNpZ24xEzARBgNVBAMTCkdsb2JhbFNpZ24wHhcNMTIxMTEzMDAwMDAwWhcNMzgw -MTE5MDMxNDA3WjBQMSQwIgYDVQQLExtHbG9iYWxTaWduIEVDQyBSb290IENBIC0g -UjQxEzARBgNVBAoTCkdsb2JhbFNpZ24xEzARBgNVBAMTCkdsb2JhbFNpZ24wWTAT -BgcqhkjOPQIBBggqhkjOPQMBBwNCAAS4xnnTj2wlDp8uORkcA6SumuU5BwkWymOx -uYb4ilfBV85C+nOh92VC/x7BALJucw7/xyHlGKSq2XE/qNS5zowdo0IwQDAOBgNV -HQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUVLB7rUW44kB/ -+wpu+74zyTyjhNUwCgYIKoZIzj0EAwIDRwAwRAIgIk90crlgr/HmnKAWBVBfw147 -bmF0774BxL4YSFlhgjICICadVGNA3jdgUM/I2O2dgq43mLyjj0xMqTQrbO/7lZsm ------END CERTIFICATE----- - -# Issuer: CN=GTS Root R1 O=Google Trust Services LLC -# Subject: CN=GTS Root R1 O=Google Trust Services LLC -# Label: "GTS Root R1" -# Serial: 159662320309726417404178440727 -# MD5 Fingerprint: 05:fe:d0:bf:71:a8:a3:76:63:da:01:e0:d8:52:dc:40 -# SHA1 Fingerprint: e5:8c:1c:c4:91:3b:38:63:4b:e9:10:6e:e3:ad:8e:6b:9d:d9:81:4a -# SHA256 Fingerprint: d9:47:43:2a:bd:e7:b7:fa:90:fc:2e:6b:59:10:1b:12:80:e0:e1:c7:e4:e4:0f:a3:c6:88:7f:ff:57:a7:f4:cf ------BEGIN CERTIFICATE----- -MIIFVzCCAz+gAwIBAgINAgPlk28xsBNJiGuiFzANBgkqhkiG9w0BAQwFADBHMQsw -CQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzEU -MBIGA1UEAxMLR1RTIFJvb3QgUjEwHhcNMTYwNjIyMDAwMDAwWhcNMzYwNjIyMDAw -MDAwWjBHMQswCQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZp -Y2VzIExMQzEUMBIGA1UEAxMLR1RTIFJvb3QgUjEwggIiMA0GCSqGSIb3DQEBAQUA -A4ICDwAwggIKAoICAQC2EQKLHuOhd5s73L+UPreVp0A8of2C+X0yBoJx9vaMf/vo -27xqLpeXo4xL+Sv2sfnOhB2x+cWX3u+58qPpvBKJXqeqUqv4IyfLpLGcY9vXmX7w -Cl7raKb0xlpHDU0QM+NOsROjyBhsS+z8CZDfnWQpJSMHobTSPS5g4M/SCYe7zUjw -TcLCeoiKu7rPWRnWr4+wB7CeMfGCwcDfLqZtbBkOtdh+JhpFAz2weaSUKK0Pfybl -qAj+lug8aJRT7oM6iCsVlgmy4HqMLnXWnOunVmSPlk9orj2XwoSPwLxAwAtcvfaH -szVsrBhQf4TgTM2S0yDpM7xSma8ytSmzJSq0SPly4cpk9+aCEI3oncKKiPo4Zor8 -Y/kB+Xj9e1x3+naH+uzfsQ55lVe0vSbv1gHR6xYKu44LtcXFilWr06zqkUspzBmk -MiVOKvFlRNACzqrOSbTqn3yDsEB750Orp2yjj32JgfpMpf/VjsPOS+C12LOORc92 -wO1AK/1TD7Cn1TsNsYqiA94xrcx36m97PtbfkSIS5r762DL8EGMUUXLeXdYWk70p -aDPvOmbsB4om3xPXV2V4J95eSRQAogB/mqghtqmxlbCluQ0WEdrHbEg8QOB+DVrN -VjzRlwW5y0vtOUucxD/SVRNuJLDWcfr0wbrM7Rv1/oFB2ACYPTrIrnqYNxgFlQID -AQABo0IwQDAOBgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4E -FgQU5K8rJnEaK0gnhS9SZizv8IkTcT4wDQYJKoZIhvcNAQEMBQADggIBAJ+qQibb -C5u+/x6Wki4+omVKapi6Ist9wTrYggoGxval3sBOh2Z5ofmmWJyq+bXmYOfg6LEe -QkEzCzc9zolwFcq1JKjPa7XSQCGYzyI0zzvFIoTgxQ6KfF2I5DUkzps+GlQebtuy -h6f88/qBVRRiClmpIgUxPoLW7ttXNLwzldMXG+gnoot7TiYaelpkttGsN/H9oPM4 -7HLwEXWdyzRSjeZ2axfG34arJ45JK3VmgRAhpuo+9K4l/3wV3s6MJT/KYnAK9y8J -ZgfIPxz88NtFMN9iiMG1D53Dn0reWVlHxYciNuaCp+0KueIHoI17eko8cdLiA6Ef -MgfdG+RCzgwARWGAtQsgWSl4vflVy2PFPEz0tv/bal8xa5meLMFrUKTX5hgUvYU/ -Z6tGn6D/Qqc6f1zLXbBwHSs09dR2CQzreExZBfMzQsNhFRAbd03OIozUhfJFfbdT -6u9AWpQKXCBfTkBdYiJ23//OYb2MI3jSNwLgjt7RETeJ9r/tSQdirpLsQBqvFAnZ -0E6yove+7u7Y/9waLd64NnHi/Hm3lCXRSHNboTXns5lndcEZOitHTtNCjv0xyBZm -2tIMPNuzjsmhDYAPexZ3FL//2wmUspO8IFgV6dtxQ/PeEMMA3KgqlbbC1j+Qa3bb -bP6MvPJwNQzcmRk13NfIRmPVNnGuV/u3gm3c ------END CERTIFICATE----- - -# Issuer: CN=GTS Root R3 O=Google Trust Services LLC -# Subject: CN=GTS Root R3 O=Google Trust Services LLC -# Label: "GTS Root R3" -# Serial: 159662495401136852707857743206 -# MD5 Fingerprint: 3e:e7:9d:58:02:94:46:51:94:e5:e0:22:4a:8b:e7:73 -# SHA1 Fingerprint: ed:e5:71:80:2b:c8:92:b9:5b:83:3c:d2:32:68:3f:09:cd:a0:1e:46 -# SHA256 Fingerprint: 34:d8:a7:3e:e2:08:d9:bc:db:0d:95:65:20:93:4b:4e:40:e6:94:82:59:6e:8b:6f:73:c8:42:6b:01:0a:6f:48 ------BEGIN CERTIFICATE----- -MIICCTCCAY6gAwIBAgINAgPluILrIPglJ209ZjAKBggqhkjOPQQDAzBHMQswCQYD -VQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzEUMBIG -A1UEAxMLR1RTIFJvb3QgUjMwHhcNMTYwNjIyMDAwMDAwWhcNMzYwNjIyMDAwMDAw -WjBHMQswCQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2Vz -IExMQzEUMBIGA1UEAxMLR1RTIFJvb3QgUjMwdjAQBgcqhkjOPQIBBgUrgQQAIgNi -AAQfTzOHMymKoYTey8chWEGJ6ladK0uFxh1MJ7x/JlFyb+Kf1qPKzEUURout736G -jOyxfi//qXGdGIRFBEFVbivqJn+7kAHjSxm65FSWRQmx1WyRRK2EE46ajA2ADDL2 -4CejQjBAMA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQW -BBTB8Sa6oC2uhYHP0/EqEr24Cmf9vDAKBggqhkjOPQQDAwNpADBmAjEA9uEglRR7 -VKOQFhG/hMjqb2sXnh5GmCCbn9MN2azTL818+FsuVbu/3ZL3pAzcMeGiAjEA/Jdm -ZuVDFhOD3cffL74UOO0BzrEXGhF16b0DjyZ+hOXJYKaV11RZt+cRLInUue4X ------END CERTIFICATE----- - -# Issuer: CN=GTS Root R4 O=Google Trust Services LLC -# Subject: CN=GTS Root R4 O=Google Trust Services LLC -# Label: "GTS Root R4" -# Serial: 159662532700760215368942768210 -# MD5 Fingerprint: 43:96:83:77:19:4d:76:b3:9d:65:52:e4:1d:22:a5:e8 -# SHA1 Fingerprint: 77:d3:03:67:b5:e0:0c:15:f6:0c:38:61:df:7c:e1:3b:92:46:4d:47 -# SHA256 Fingerprint: 34:9d:fa:40:58:c5:e2:63:12:3b:39:8a:e7:95:57:3c:4e:13:13:c8:3f:e6:8f:93:55:6c:d5:e8:03:1b:3c:7d ------BEGIN CERTIFICATE----- -MIICCTCCAY6gAwIBAgINAgPlwGjvYxqccpBQUjAKBggqhkjOPQQDAzBHMQswCQYD -VQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzEUMBIG -A1UEAxMLR1RTIFJvb3QgUjQwHhcNMTYwNjIyMDAwMDAwWhcNMzYwNjIyMDAwMDAw -WjBHMQswCQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2Vz -IExMQzEUMBIGA1UEAxMLR1RTIFJvb3QgUjQwdjAQBgcqhkjOPQIBBgUrgQQAIgNi -AATzdHOnaItgrkO4NcWBMHtLSZ37wWHO5t5GvWvVYRg1rkDdc/eJkTBa6zzuhXyi -QHY7qca4R9gq55KRanPpsXI5nymfopjTX15YhmUPoYRlBtHci8nHc8iMai/lxKvR -HYqjQjBAMA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQW -BBSATNbrdP9JNqPV2Py1PsVq8JQdjDAKBggqhkjOPQQDAwNpADBmAjEA6ED/g94D -9J+uHXqnLrmvT/aDHQ4thQEd0dlq7A/Cr8deVl5c1RxYIigL9zC2L7F8AjEA8GE8 -p/SgguMh1YQdc4acLa/KNJvxn7kjNuK8YAOdgLOaVsjh4rsUecrNIdSUtUlD ------END CERTIFICATE----- - -# Issuer: CN=Telia Root CA v2 O=Telia Finland Oyj -# Subject: CN=Telia Root CA v2 O=Telia Finland Oyj -# Label: "Telia Root CA v2" -# Serial: 7288924052977061235122729490515358 -# MD5 Fingerprint: 0e:8f:ac:aa:82:df:85:b1:f4:dc:10:1c:fc:99:d9:48 -# SHA1 Fingerprint: b9:99:cd:d1:73:50:8a:c4:47:05:08:9c:8c:88:fb:be:a0:2b:40:cd -# SHA256 Fingerprint: 24:2b:69:74:2f:cb:1e:5b:2a:bf:98:89:8b:94:57:21:87:54:4e:5b:4d:99:11:78:65:73:62:1f:6a:74:b8:2c ------BEGIN CERTIFICATE----- -MIIFdDCCA1ygAwIBAgIPAWdfJ9b+euPkrL4JWwWeMA0GCSqGSIb3DQEBCwUAMEQx -CzAJBgNVBAYTAkZJMRowGAYDVQQKDBFUZWxpYSBGaW5sYW5kIE95ajEZMBcGA1UE -AwwQVGVsaWEgUm9vdCBDQSB2MjAeFw0xODExMjkxMTU1NTRaFw00MzExMjkxMTU1 -NTRaMEQxCzAJBgNVBAYTAkZJMRowGAYDVQQKDBFUZWxpYSBGaW5sYW5kIE95ajEZ -MBcGA1UEAwwQVGVsaWEgUm9vdCBDQSB2MjCCAiIwDQYJKoZIhvcNAQEBBQADggIP -ADCCAgoCggIBALLQPwe84nvQa5n44ndp586dpAO8gm2h/oFlH0wnrI4AuhZ76zBq -AMCzdGh+sq/H1WKzej9Qyow2RCRj0jbpDIX2Q3bVTKFgcmfiKDOlyzG4OiIjNLh9 -vVYiQJ3q9HsDrWj8soFPmNB06o3lfc1jw6P23pLCWBnglrvFxKk9pXSW/q/5iaq9 -lRdU2HhE8Qx3FZLgmEKnpNaqIJLNwaCzlrI6hEKNfdWV5Nbb6WLEWLN5xYzTNTOD -n3WhUidhOPFZPY5Q4L15POdslv5e2QJltI5c0BE0312/UqeBAMN/mUWZFdUXyApT -7GPzmX3MaRKGwhfwAZ6/hLzRUssbkmbOpFPlob/E2wnW5olWK8jjfN7j/4nlNW4o -6GwLI1GpJQXrSPjdscr6bAhR77cYbETKJuFzxokGgeWKrLDiKca5JLNrRBH0pUPC -TEPlcDaMtjNXepUugqD0XBCzYYP2AgWGLnwtbNwDRm41k9V6lS/eINhbfpSQBGq6 -WT0EBXWdN6IOLj3rwaRSg/7Qa9RmjtzG6RJOHSpXqhC8fF6CfaamyfItufUXJ63R -DolUK5X6wK0dmBR4M0KGCqlztft0DbcbMBnEWg4cJ7faGND/isgFuvGqHKI3t+ZI -pEYslOqodmJHixBTB0hXbOKSTbauBcvcwUpej6w9GU7C7WB1K9vBykLVAgMBAAGj -YzBhMB8GA1UdIwQYMBaAFHKs5DN5qkWH9v2sHZ7Wxy+G2CQ5MB0GA1UdDgQWBBRy -rOQzeapFh/b9rB2e1scvhtgkOTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUw -AwEB/zANBgkqhkiG9w0BAQsFAAOCAgEAoDtZpwmUPjaE0n4vOaWWl/oRrfxn83EJ -8rKJhGdEr7nv7ZbsnGTbMjBvZ5qsfl+yqwE2foH65IRe0qw24GtixX1LDoJt0nZi -0f6X+J8wfBj5tFJ3gh1229MdqfDBmgC9bXXYfef6xzijnHDoRnkDry5023X4blMM -A8iZGok1GTzTyVR8qPAs5m4HeW9q4ebqkYJpCh3DflminmtGFZhb069GHWLIzoBS -SRE/yQQSwxN8PzuKlts8oB4KtItUsiRnDe+Cy748fdHif64W1lZYudogsYMVoe+K -TTJvQS8TUoKU1xrBeKJR3Stwbbca+few4GeXVtt8YVMJAygCQMez2P2ccGrGKMOF -6eLtGpOg3kuYooQ+BXcBlj37tCAPnHICehIv1aO6UXivKitEZU61/Qrowc15h2Er -3oBXRb9n8ZuRXqWk7FlIEA04x7D6w0RtBPV4UBySllva9bguulvP5fBqnUsvWHMt -Ty3EHD70sz+rFQ47GUGKpMFXEmZxTPpT41frYpUJnlTd0cI8Vzy9OK2YZLe4A5pT -VmBds9hCG1xLEooc6+t9xnppxyd/pPiL8uSUZodL6ZQHCRJ5irLrdATczvREWeAW -ysUsWNc8e89ihmpQfTU2Zqf7N+cox9jQraVplI/owd8k+BsHMYeB2F326CjYSlKA -rBPuUBQemMc= ------END CERTIFICATE----- - -# Issuer: CN=D-TRUST BR Root CA 1 2020 O=D-Trust GmbH -# Subject: CN=D-TRUST BR Root CA 1 2020 O=D-Trust GmbH -# Label: "D-TRUST BR Root CA 1 2020" -# Serial: 165870826978392376648679885835942448534 -# MD5 Fingerprint: b5:aa:4b:d5:ed:f7:e3:55:2e:8f:72:0a:f3:75:b8:ed -# SHA1 Fingerprint: 1f:5b:98:f0:e3:b5:f7:74:3c:ed:e6:b0:36:7d:32:cd:f4:09:41:67 -# SHA256 Fingerprint: e5:9a:aa:81:60:09:c2:2b:ff:5b:25:ba:d3:7d:f3:06:f0:49:79:7c:1f:81:d8:5a:b0:89:e6:57:bd:8f:00:44 ------BEGIN CERTIFICATE----- -MIIC2zCCAmCgAwIBAgIQfMmPK4TX3+oPyWWa00tNljAKBggqhkjOPQQDAzBIMQsw -CQYDVQQGEwJERTEVMBMGA1UEChMMRC1UcnVzdCBHbWJIMSIwIAYDVQQDExlELVRS -VVNUIEJSIFJvb3QgQ0EgMSAyMDIwMB4XDTIwMDIxMTA5NDUwMFoXDTM1MDIxMTA5 -NDQ1OVowSDELMAkGA1UEBhMCREUxFTATBgNVBAoTDEQtVHJ1c3QgR21iSDEiMCAG -A1UEAxMZRC1UUlVTVCBCUiBSb290IENBIDEgMjAyMDB2MBAGByqGSM49AgEGBSuB -BAAiA2IABMbLxyjR+4T1mu9CFCDhQ2tuda38KwOE1HaTJddZO0Flax7mNCq7dPYS -zuht56vkPE4/RAiLzRZxy7+SmfSk1zxQVFKQhYN4lGdnoxwJGT11NIXe7WB9xwy0 -QVK5buXuQqOCAQ0wggEJMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFHOREKv/ -VbNafAkl1bK6CKBrqx9tMA4GA1UdDwEB/wQEAwIBBjCBxgYDVR0fBIG+MIG7MD6g -PKA6hjhodHRwOi8vY3JsLmQtdHJ1c3QubmV0L2NybC9kLXRydXN0X2JyX3Jvb3Rf -Y2FfMV8yMDIwLmNybDB5oHegdYZzbGRhcDovL2RpcmVjdG9yeS5kLXRydXN0Lm5l -dC9DTj1ELVRSVVNUJTIwQlIlMjBSb290JTIwQ0ElMjAxJTIwMjAyMCxPPUQtVHJ1 -c3QlMjBHbWJILEM9REU/Y2VydGlmaWNhdGVyZXZvY2F0aW9ubGlzdDAKBggqhkjO -PQQDAwNpADBmAjEAlJAtE/rhY/hhY+ithXhUkZy4kzg+GkHaQBZTQgjKL47xPoFW -wKrY7RjEsK70PvomAjEA8yjixtsrmfu3Ubgko6SUeho/5jbiA1czijDLgsfWFBHV -dWNbFJWcHwHP2NVypw87 ------END CERTIFICATE----- - -# Issuer: CN=D-TRUST EV Root CA 1 2020 O=D-Trust GmbH -# Subject: CN=D-TRUST EV Root CA 1 2020 O=D-Trust GmbH -# Label: "D-TRUST EV Root CA 1 2020" -# Serial: 126288379621884218666039612629459926992 -# MD5 Fingerprint: 8c:2d:9d:70:9f:48:99:11:06:11:fb:e9:cb:30:c0:6e -# SHA1 Fingerprint: 61:db:8c:21:59:69:03:90:d8:7c:9c:12:86:54:cf:9d:3d:f4:dd:07 -# SHA256 Fingerprint: 08:17:0d:1a:a3:64:53:90:1a:2f:95:92:45:e3:47:db:0c:8d:37:ab:aa:bc:56:b8:1a:a1:00:dc:95:89:70:db ------BEGIN CERTIFICATE----- -MIIC2zCCAmCgAwIBAgIQXwJB13qHfEwDo6yWjfv/0DAKBggqhkjOPQQDAzBIMQsw -CQYDVQQGEwJERTEVMBMGA1UEChMMRC1UcnVzdCBHbWJIMSIwIAYDVQQDExlELVRS -VVNUIEVWIFJvb3QgQ0EgMSAyMDIwMB4XDTIwMDIxMTEwMDAwMFoXDTM1MDIxMTA5 -NTk1OVowSDELMAkGA1UEBhMCREUxFTATBgNVBAoTDEQtVHJ1c3QgR21iSDEiMCAG -A1UEAxMZRC1UUlVTVCBFViBSb290IENBIDEgMjAyMDB2MBAGByqGSM49AgEGBSuB -BAAiA2IABPEL3YZDIBnfl4XoIkqbz52Yv7QFJsnL46bSj8WeeHsxiamJrSc8ZRCC -/N/DnU7wMyPE0jL1HLDfMxddxfCxivnvubcUyilKwg+pf3VlSSowZ/Rk99Yad9rD -wpdhQntJraOCAQ0wggEJMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFH8QARY3 -OqQo5FD4pPfsazK2/umLMA4GA1UdDwEB/wQEAwIBBjCBxgYDVR0fBIG+MIG7MD6g -PKA6hjhodHRwOi8vY3JsLmQtdHJ1c3QubmV0L2NybC9kLXRydXN0X2V2X3Jvb3Rf -Y2FfMV8yMDIwLmNybDB5oHegdYZzbGRhcDovL2RpcmVjdG9yeS5kLXRydXN0Lm5l -dC9DTj1ELVRSVVNUJTIwRVYlMjBSb290JTIwQ0ElMjAxJTIwMjAyMCxPPUQtVHJ1 -c3QlMjBHbWJILEM9REU/Y2VydGlmaWNhdGVyZXZvY2F0aW9ubGlzdDAKBggqhkjO -PQQDAwNpADBmAjEAyjzGKnXCXnViOTYAYFqLwZOZzNnbQTs7h5kXO9XMT8oi96CA -y/m0sRtW9XLS/BnRAjEAkfcwkz8QRitxpNA7RJvAKQIFskF3UfN5Wp6OFKBOQtJb -gfM0agPnIjhQW+0ZT0MW ------END CERTIFICATE----- - -# Issuer: CN=DigiCert TLS ECC P384 Root G5 O=DigiCert, Inc. -# Subject: CN=DigiCert TLS ECC P384 Root G5 O=DigiCert, Inc. -# Label: "DigiCert TLS ECC P384 Root G5" -# Serial: 13129116028163249804115411775095713523 -# MD5 Fingerprint: d3:71:04:6a:43:1c:db:a6:59:e1:a8:a3:aa:c5:71:ed -# SHA1 Fingerprint: 17:f3:de:5e:9f:0f:19:e9:8e:f6:1f:32:26:6e:20:c4:07:ae:30:ee -# SHA256 Fingerprint: 01:8e:13:f0:77:25:32:cf:80:9b:d1:b1:72:81:86:72:83:fc:48:c6:e1:3b:e9:c6:98:12:85:4a:49:0c:1b:05 ------BEGIN CERTIFICATE----- -MIICGTCCAZ+gAwIBAgIQCeCTZaz32ci5PhwLBCou8zAKBggqhkjOPQQDAzBOMQsw -CQYDVQQGEwJVUzEXMBUGA1UEChMORGlnaUNlcnQsIEluYy4xJjAkBgNVBAMTHURp -Z2lDZXJ0IFRMUyBFQ0MgUDM4NCBSb290IEc1MB4XDTIxMDExNTAwMDAwMFoXDTQ2 -MDExNDIzNTk1OVowTjELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDkRpZ2lDZXJ0LCBJ -bmMuMSYwJAYDVQQDEx1EaWdpQ2VydCBUTFMgRUNDIFAzODQgUm9vdCBHNTB2MBAG -ByqGSM49AgEGBSuBBAAiA2IABMFEoc8Rl1Ca3iOCNQfN0MsYndLxf3c1TzvdlHJS -7cI7+Oz6e2tYIOyZrsn8aLN1udsJ7MgT9U7GCh1mMEy7H0cKPGEQQil8pQgO4CLp -0zVozptjn4S1mU1YoI71VOeVyaNCMEAwHQYDVR0OBBYEFMFRRVBZqz7nLFr6ICIS -B4CIfBFqMA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8EBTADAQH/MAoGCCqGSM49 -BAMDA2gAMGUCMQCJao1H5+z8blUD2WdsJk6Dxv3J+ysTvLd6jLRl0mlpYxNjOyZQ -LgGheQaRnUi/wr4CMEfDFXuxoJGZSZOoPHzoRgaLLPIxAJSdYsiJvRmEFOml+wG4 -DXZDjC5Ty3zfDBeWUA== ------END CERTIFICATE----- - -# Issuer: CN=DigiCert TLS RSA4096 Root G5 O=DigiCert, Inc. -# Subject: CN=DigiCert TLS RSA4096 Root G5 O=DigiCert, Inc. -# Label: "DigiCert TLS RSA4096 Root G5" -# Serial: 11930366277458970227240571539258396554 -# MD5 Fingerprint: ac:fe:f7:34:96:a9:f2:b3:b4:12:4b:e4:27:41:6f:e1 -# SHA1 Fingerprint: a7:88:49:dc:5d:7c:75:8c:8c:de:39:98:56:b3:aa:d0:b2:a5:71:35 -# SHA256 Fingerprint: 37:1a:00:dc:05:33:b3:72:1a:7e:eb:40:e8:41:9e:70:79:9d:2b:0a:0f:2c:1d:80:69:31:65:f7:ce:c4:ad:75 ------BEGIN CERTIFICATE----- -MIIFZjCCA06gAwIBAgIQCPm0eKj6ftpqMzeJ3nzPijANBgkqhkiG9w0BAQwFADBN -MQswCQYDVQQGEwJVUzEXMBUGA1UEChMORGlnaUNlcnQsIEluYy4xJTAjBgNVBAMT -HERpZ2lDZXJ0IFRMUyBSU0E0MDk2IFJvb3QgRzUwHhcNMjEwMTE1MDAwMDAwWhcN -NDYwMTE0MjM1OTU5WjBNMQswCQYDVQQGEwJVUzEXMBUGA1UEChMORGlnaUNlcnQs -IEluYy4xJTAjBgNVBAMTHERpZ2lDZXJ0IFRMUyBSU0E0MDk2IFJvb3QgRzUwggIi -MA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCz0PTJeRGd/fxmgefM1eS87IE+ -ajWOLrfn3q/5B03PMJ3qCQuZvWxX2hhKuHisOjmopkisLnLlvevxGs3npAOpPxG0 -2C+JFvuUAT27L/gTBaF4HI4o4EXgg/RZG5Wzrn4DReW+wkL+7vI8toUTmDKdFqgp -wgscONyfMXdcvyej/Cestyu9dJsXLfKB2l2w4SMXPohKEiPQ6s+d3gMXsUJKoBZM -pG2T6T867jp8nVid9E6P/DsjyG244gXazOvswzH016cpVIDPRFtMbzCe88zdH5RD -nU1/cHAN1DrRN/BsnZvAFJNY781BOHW8EwOVfH/jXOnVDdXifBBiqmvwPXbzP6Po -sMH976pXTayGpxi0KcEsDr9kvimM2AItzVwv8n/vFfQMFawKsPHTDU9qTXeXAaDx -Zre3zu/O7Oyldcqs4+Fj97ihBMi8ez9dLRYiVu1ISf6nL3kwJZu6ay0/nTvEF+cd -Lvvyz6b84xQslpghjLSR6Rlgg/IwKwZzUNWYOwbpx4oMYIwo+FKbbuH2TbsGJJvX -KyY//SovcfXWJL5/MZ4PbeiPT02jP/816t9JXkGPhvnxd3lLG7SjXi/7RgLQZhNe -XoVPzthwiHvOAbWWl9fNff2C+MIkwcoBOU+NosEUQB+cZtUMCUbW8tDRSHZWOkPL -tgoRObqME2wGtZ7P6wIDAQABo0IwQDAdBgNVHQ4EFgQUUTMc7TZArxfTJc1paPKv -TiM+s0EwDgYDVR0PAQH/BAQDAgGGMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcN -AQEMBQADggIBAGCmr1tfV9qJ20tQqcQjNSH/0GEwhJG3PxDPJY7Jv0Y02cEhJhxw -GXIeo8mH/qlDZJY6yFMECrZBu8RHANmfGBg7sg7zNOok992vIGCukihfNudd5N7H -PNtQOa27PShNlnx2xlv0wdsUpasZYgcYQF+Xkdycx6u1UQ3maVNVzDl92sURVXLF -O4uJ+DQtpBflF+aZfTCIITfNMBc9uPK8qHWgQ9w+iUuQrm0D4ByjoJYJu32jtyoQ -REtGBzRj7TG5BO6jm5qu5jF49OokYTurWGT/u4cnYiWB39yhL/btp/96j1EuMPik -AdKFOV8BmZZvWltwGUb+hmA+rYAQCd05JS9Yf7vSdPD3Rh9GOUrYU9DzLjtxpdRv -/PNn5AeP3SYZ4Y1b+qOTEZvpyDrDVWiakuFSdjjo4bq9+0/V77PnSIMx8IIh47a+ -p6tv75/fTM8BuGJqIz3nCU2AG3swpMPdB380vqQmsvZB6Akd4yCYqjdP//fx4ilw -MUc/dNAUFvohigLVigmUdy7yWSiLfFCSCmZ4OIN1xLVaqBHG5cGdZlXPU8Sv13WF -qUITVuwhd4GTWgzqltlJyqEI8pc7bZsEGCREjnwB8twl2F6GmrE52/WRMmrRpnCK -ovfepEWFJqgejF0pW8hL2JpqA15w8oVPbEtoL8pU9ozaMv7Da4M/OMZ+ ------END CERTIFICATE----- - -# Issuer: CN=Certainly Root R1 O=Certainly -# Subject: CN=Certainly Root R1 O=Certainly -# Label: "Certainly Root R1" -# Serial: 188833316161142517227353805653483829216 -# MD5 Fingerprint: 07:70:d4:3e:82:87:a0:fa:33:36:13:f4:fa:33:e7:12 -# SHA1 Fingerprint: a0:50:ee:0f:28:71:f4:27:b2:12:6d:6f:50:96:25:ba:cc:86:42:af -# SHA256 Fingerprint: 77:b8:2c:d8:64:4c:43:05:f7:ac:c5:cb:15:6b:45:67:50:04:03:3d:51:c6:0c:62:02:a8:e0:c3:34:67:d3:a0 ------BEGIN CERTIFICATE----- -MIIFRzCCAy+gAwIBAgIRAI4P+UuQcWhlM1T01EQ5t+AwDQYJKoZIhvcNAQELBQAw -PTELMAkGA1UEBhMCVVMxEjAQBgNVBAoTCUNlcnRhaW5seTEaMBgGA1UEAxMRQ2Vy -dGFpbmx5IFJvb3QgUjEwHhcNMjEwNDAxMDAwMDAwWhcNNDYwNDAxMDAwMDAwWjA9 -MQswCQYDVQQGEwJVUzESMBAGA1UEChMJQ2VydGFpbmx5MRowGAYDVQQDExFDZXJ0 -YWlubHkgUm9vdCBSMTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBANA2 -1B/q3avk0bbm+yLA3RMNansiExyXPGhjZjKcA7WNpIGD2ngwEc/csiu+kr+O5MQT -vqRoTNoCaBZ0vrLdBORrKt03H2As2/X3oXyVtwxwhi7xOu9S98zTm/mLvg7fMbed -aFySpvXl8wo0tf97ouSHocavFwDvA5HtqRxOcT3Si2yJ9HiG5mpJoM610rCrm/b0 -1C7jcvk2xusVtyWMOvwlDbMicyF0yEqWYZL1LwsYpfSt4u5BvQF5+paMjRcCMLT5 -r3gajLQ2EBAHBXDQ9DGQilHFhiZ5shGIXsXwClTNSaa/ApzSRKft43jvRl5tcdF5 -cBxGX1HpyTfcX35pe0HfNEXgO4T0oYoKNp43zGJS4YkNKPl6I7ENPT2a/Z2B7yyQ -wHtETrtJ4A5KVpK8y7XdeReJkd5hiXSSqOMyhb5OhaRLWcsrxXiOcVTQAjeZjOVJ -6uBUcqQRBi8LjMFbvrWhsFNunLhgkR9Za/kt9JQKl7XsxXYDVBtlUrpMklZRNaBA -2CnbrlJ2Oy0wQJuK0EJWtLeIAaSHO1OWzaMWj/Nmqhexx2DgwUMFDO6bW2BvBlyH -Wyf5QBGenDPBt+U1VwV/J84XIIwc/PH72jEpSe31C4SnT8H2TsIonPru4K8H+zMR -eiFPCyEQtkA6qyI6BJyLm4SGcprSp6XEtHWRqSsjAgMBAAGjQjBAMA4GA1UdDwEB -/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBTgqj8ljZ9EXME66C6u -d0yEPmcM9DANBgkqhkiG9w0BAQsFAAOCAgEAuVevuBLaV4OPaAszHQNTVfSVcOQr -PbA56/qJYv331hgELyE03fFo8NWWWt7CgKPBjcZq91l3rhVkz1t5BXdm6ozTaw3d -8VkswTOlMIAVRQdFGjEitpIAq5lNOo93r6kiyi9jyhXWx8bwPWz8HA2YEGGeEaIi -1wrykXprOQ4vMMM2SZ/g6Q8CRFA3lFV96p/2O7qUpUzpvD5RtOjKkjZUbVwlKNrd -rRT90+7iIgXr0PK3aBLXWopBGsaSpVo7Y0VPv+E6dyIvXL9G+VoDhRNCX8reU9di -taY1BMJH/5n9hN9czulegChB8n3nHpDYT3Y+gjwN/KUD+nsa2UUeYNrEjvn8K8l7 -lcUq/6qJ34IxD3L/DCfXCh5WAFAeDJDBlrXYFIW7pw0WwfgHJBu6haEaBQmAupVj -yTrsJZ9/nbqkRxWbRHDxakvWOF5D8xh+UG7pWijmZeZ3Gzr9Hb4DJqPb1OG7fpYn -Kx3upPvaJVQTA945xsMfTZDsjxtK0hzthZU4UHlG1sGQUDGpXJpuHfUzVounmdLy -yCwzk5Iwx06MZTMQZBf9JBeW0Y3COmor6xOLRPIh80oat3df1+2IpHLlOR+Vnb5n -wXARPbv0+Em34yaXOp/SX3z7wJl8OSngex2/DaeP0ik0biQVy96QXr8axGbqwua6 -OV+KmalBWQewLK8= ------END CERTIFICATE----- - -# Issuer: CN=Certainly Root E1 O=Certainly -# Subject: CN=Certainly Root E1 O=Certainly -# Label: "Certainly Root E1" -# Serial: 8168531406727139161245376702891150584 -# MD5 Fingerprint: 0a:9e:ca:cd:3e:52:50:c6:36:f3:4b:a3:ed:a7:53:e9 -# SHA1 Fingerprint: f9:e1:6d:dc:01:89:cf:d5:82:45:63:3e:c5:37:7d:c2:eb:93:6f:2b -# SHA256 Fingerprint: b4:58:5f:22:e4:ac:75:6a:4e:86:12:a1:36:1c:5d:9d:03:1a:93:fd:84:fe:bb:77:8f:a3:06:8b:0f:c4:2d:c2 ------BEGIN CERTIFICATE----- -MIIB9zCCAX2gAwIBAgIQBiUzsUcDMydc+Y2aub/M+DAKBggqhkjOPQQDAzA9MQsw -CQYDVQQGEwJVUzESMBAGA1UEChMJQ2VydGFpbmx5MRowGAYDVQQDExFDZXJ0YWlu -bHkgUm9vdCBFMTAeFw0yMTA0MDEwMDAwMDBaFw00NjA0MDEwMDAwMDBaMD0xCzAJ -BgNVBAYTAlVTMRIwEAYDVQQKEwlDZXJ0YWlubHkxGjAYBgNVBAMTEUNlcnRhaW5s -eSBSb290IEUxMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAE3m/4fxzf7flHh4axpMCK -+IKXgOqPyEpeKn2IaKcBYhSRJHpcnqMXfYqGITQYUBsQ3tA3SybHGWCA6TS9YBk2 -QNYphwk8kXr2vBMj3VlOBF7PyAIcGFPBMdjaIOlEjeR2o0IwQDAOBgNVHQ8BAf8E -BAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQU8ygYy2R17ikq6+2uI1g4 -hevIIgcwCgYIKoZIzj0EAwMDaAAwZQIxALGOWiDDshliTd6wT99u0nCK8Z9+aozm -ut6Dacpps6kFtZaSF4fC0urQe87YQVt8rgIwRt7qy12a7DLCZRawTDBcMPPaTnOG -BtjOiQRINzf43TNRnXCve1XYAS59BWQOhriR ------END CERTIFICATE----- - -# Issuer: CN=Security Communication ECC RootCA1 O=SECOM Trust Systems CO.,LTD. -# Subject: CN=Security Communication ECC RootCA1 O=SECOM Trust Systems CO.,LTD. -# Label: "Security Communication ECC RootCA1" -# Serial: 15446673492073852651 -# MD5 Fingerprint: 7e:43:b0:92:68:ec:05:43:4c:98:ab:5d:35:2e:7e:86 -# SHA1 Fingerprint: b8:0e:26:a9:bf:d2:b2:3b:c0:ef:46:c9:ba:c7:bb:f6:1d:0d:41:41 -# SHA256 Fingerprint: e7:4f:bd:a5:5b:d5:64:c4:73:a3:6b:44:1a:a7:99:c8:a6:8e:07:74:40:e8:28:8b:9f:a1:e5:0e:4b:ba:ca:11 ------BEGIN CERTIFICATE----- -MIICODCCAb6gAwIBAgIJANZdm7N4gS7rMAoGCCqGSM49BAMDMGExCzAJBgNVBAYT -AkpQMSUwIwYDVQQKExxTRUNPTSBUcnVzdCBTeXN0ZW1zIENPLixMVEQuMSswKQYD -VQQDEyJTZWN1cml0eSBDb21tdW5pY2F0aW9uIEVDQyBSb290Q0ExMB4XDTE2MDYx -NjA1MTUyOFoXDTM4MDExODA1MTUyOFowYTELMAkGA1UEBhMCSlAxJTAjBgNVBAoT -HFNFQ09NIFRydXN0IFN5c3RlbXMgQ08uLExURC4xKzApBgNVBAMTIlNlY3VyaXR5 -IENvbW11bmljYXRpb24gRUNDIFJvb3RDQTEwdjAQBgcqhkjOPQIBBgUrgQQAIgNi -AASkpW9gAwPDvTH00xecK4R1rOX9PVdu12O/5gSJko6BnOPpR27KkBLIE+Cnnfdl -dB9sELLo5OnvbYUymUSxXv3MdhDYW72ixvnWQuRXdtyQwjWpS4g8EkdtXP9JTxpK -ULGjQjBAMB0GA1UdDgQWBBSGHOf+LaVKiwj+KBH6vqNm+GBZLzAOBgNVHQ8BAf8E -BAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAKBggqhkjOPQQDAwNoADBlAjAVXUI9/Lbu -9zuxNuie9sRGKEkz0FhDKmMpzE2xtHqiuQ04pV1IKv3LsnNdo4gIxwwCMQDAqy0O -be0YottT6SXbVQjgUMzfRGEWgqtJsLKB7HOHeLRMsmIbEvoWTSVLY70eN9k= ------END CERTIFICATE----- - -# Issuer: CN=BJCA Global Root CA1 O=BEIJING CERTIFICATE AUTHORITY -# Subject: CN=BJCA Global Root CA1 O=BEIJING CERTIFICATE AUTHORITY -# Label: "BJCA Global Root CA1" -# Serial: 113562791157148395269083148143378328608 -# MD5 Fingerprint: 42:32:99:76:43:33:36:24:35:07:82:9b:28:f9:d0:90 -# SHA1 Fingerprint: d5:ec:8d:7b:4c:ba:79:f4:e7:e8:cb:9d:6b:ae:77:83:10:03:21:6a -# SHA256 Fingerprint: f3:89:6f:88:fe:7c:0a:88:27:66:a7:fa:6a:d2:74:9f:b5:7a:7f:3e:98:fb:76:9c:1f:a7:b0:9c:2c:44:d5:ae ------BEGIN CERTIFICATE----- -MIIFdDCCA1ygAwIBAgIQVW9l47TZkGobCdFsPsBsIDANBgkqhkiG9w0BAQsFADBU -MQswCQYDVQQGEwJDTjEmMCQGA1UECgwdQkVJSklORyBDRVJUSUZJQ0FURSBBVVRI -T1JJVFkxHTAbBgNVBAMMFEJKQ0EgR2xvYmFsIFJvb3QgQ0ExMB4XDTE5MTIxOTAz -MTYxN1oXDTQ0MTIxMjAzMTYxN1owVDELMAkGA1UEBhMCQ04xJjAkBgNVBAoMHUJF -SUpJTkcgQ0VSVElGSUNBVEUgQVVUSE9SSVRZMR0wGwYDVQQDDBRCSkNBIEdsb2Jh -bCBSb290IENBMTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAPFmCL3Z -xRVhy4QEQaVpN3cdwbB7+sN3SJATcmTRuHyQNZ0YeYjjlwE8R4HyDqKYDZ4/N+AZ -spDyRhySsTphzvq3Rp4Dhtczbu33RYx2N95ulpH3134rhxfVizXuhJFyV9xgw8O5 -58dnJCNPYwpj9mZ9S1WnP3hkSWkSl+BMDdMJoDIwOvqfwPKcxRIqLhy1BDPapDgR -at7GGPZHOiJBhyL8xIkoVNiMpTAK+BcWyqw3/XmnkRd4OJmtWO2y3syJfQOcs4ll -5+M7sSKGjwZteAf9kRJ/sGsciQ35uMt0WwfCyPQ10WRjeulumijWML3mG90Vr4Tq -nMfK9Q7q8l0ph49pczm+LiRvRSGsxdRpJQaDrXpIhRMsDQa4bHlW/KNnMoH1V6XK -V0Jp6VwkYe/iMBhORJhVb3rCk9gZtt58R4oRTklH2yiUAguUSiz5EtBP6DF+bHq/ -pj+bOT0CFqMYs2esWz8sgytnOYFcuX6U1WTdno9uruh8W7TXakdI136z1C2OVnZO -z2nxbkRs1CTqjSShGL+9V/6pmTW12xB3uD1IutbB5/EjPtffhZ0nPNRAvQoMvfXn -jSXWgXSHRtQpdaJCbPdzied9v3pKH9MiyRVVz99vfFXQpIsHETdfg6YmV6YBW37+ -WGgHqel62bno/1Afq8K0wM7o6v0PvY1NuLxxAgMBAAGjQjBAMB0GA1UdDgQWBBTF -7+3M2I0hxkjk49cULqcWk+WYATAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQE -AwIBBjANBgkqhkiG9w0BAQsFAAOCAgEAUoKsITQfI/Ki2Pm4rzc2IInRNwPWaZ+4 -YRC6ojGYWUfo0Q0lHhVBDOAqVdVXUsv45Mdpox1NcQJeXyFFYEhcCY5JEMEE3Kli -awLwQ8hOnThJdMkycFRtwUf8jrQ2ntScvd0g1lPJGKm1Vrl2i5VnZu69mP6u775u -+2D2/VnGKhs/I0qUJDAnyIm860Qkmss9vk/Ves6OF8tiwdneHg56/0OGNFK8YT88 -X7vZdrRTvJez/opMEi4r89fO4aL/3Xtw+zuhTaRjAv04l5U/BXCga99igUOLtFkN -SoxUnMW7gZ/NfaXvCyUeOiDbHPwfmGcCCtRzRBPbUYQaVQNW4AB+dAb/OMRyHdOo -P2gxXdMJxy6MW2Pg6Nwe0uxhHvLe5e/2mXZgLR6UcnHGCyoyx5JO1UbXHfmpGQrI -+pXObSOYqgs4rZpWDW+N8TEAiMEXnM0ZNjX+VVOg4DwzX5Ze4jLp3zO7Bkqp2IRz -znfSxqxx4VyjHQy7Ct9f4qNx2No3WqB4K/TUfet27fJhcKVlmtOJNBir+3I+17Q9 -eVzYH6Eze9mCUAyTF6ps3MKCuwJXNq+YJyo5UOGwifUll35HaBC07HPKs5fRJNz2 -YqAo07WjuGS3iGJCz51TzZm+ZGiPTx4SSPfSKcOYKMryMguTjClPPGAyzQWWYezy -r/6zcCwupvI= ------END CERTIFICATE----- - -# Issuer: CN=BJCA Global Root CA2 O=BEIJING CERTIFICATE AUTHORITY -# Subject: CN=BJCA Global Root CA2 O=BEIJING CERTIFICATE AUTHORITY -# Label: "BJCA Global Root CA2" -# Serial: 58605626836079930195615843123109055211 -# MD5 Fingerprint: 5e:0a:f6:47:5f:a6:14:e8:11:01:95:3f:4d:01:eb:3c -# SHA1 Fingerprint: f4:27:86:eb:6e:b8:6d:88:31:67:02:fb:ba:66:a4:53:00:aa:7a:a6 -# SHA256 Fingerprint: 57:4d:f6:93:1e:27:80:39:66:7b:72:0a:fd:c1:60:0f:c2:7e:b6:6d:d3:09:29:79:fb:73:85:64:87:21:28:82 ------BEGIN CERTIFICATE----- -MIICJTCCAaugAwIBAgIQLBcIfWQqwP6FGFkGz7RK6zAKBggqhkjOPQQDAzBUMQsw -CQYDVQQGEwJDTjEmMCQGA1UECgwdQkVJSklORyBDRVJUSUZJQ0FURSBBVVRIT1JJ -VFkxHTAbBgNVBAMMFEJKQ0EgR2xvYmFsIFJvb3QgQ0EyMB4XDTE5MTIxOTAzMTgy -MVoXDTQ0MTIxMjAzMTgyMVowVDELMAkGA1UEBhMCQ04xJjAkBgNVBAoMHUJFSUpJ -TkcgQ0VSVElGSUNBVEUgQVVUSE9SSVRZMR0wGwYDVQQDDBRCSkNBIEdsb2JhbCBS -b290IENBMjB2MBAGByqGSM49AgEGBSuBBAAiA2IABJ3LgJGNU2e1uVCxA/jlSR9B -IgmwUVJY1is0j8USRhTFiy8shP8sbqjV8QnjAyEUxEM9fMEsxEtqSs3ph+B99iK+ -+kpRuDCK/eHeGBIK9ke35xe/J4rUQUyWPGCWwf0VHKNCMEAwHQYDVR0OBBYEFNJK -sVF/BvDRgh9Obl+rg/xI1LCRMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQD -AgEGMAoGCCqGSM49BAMDA2gAMGUCMBq8W9f+qdJUDkpd0m2xQNz0Q9XSSpkZElaA -94M04TVOSG0ED1cxMDAtsaqdAzjbBgIxAMvMh1PLet8gUXOQwKhbYdDFUDn9hf7B -43j4ptZLvZuHjw/l1lOWqzzIQNph91Oj9w== ------END CERTIFICATE----- - -# Issuer: CN=Sectigo Public Server Authentication Root E46 O=Sectigo Limited -# Subject: CN=Sectigo Public Server Authentication Root E46 O=Sectigo Limited -# Label: "Sectigo Public Server Authentication Root E46" -# Serial: 88989738453351742415770396670917916916 -# MD5 Fingerprint: 28:23:f8:b2:98:5c:37:16:3b:3e:46:13:4e:b0:b3:01 -# SHA1 Fingerprint: ec:8a:39:6c:40:f0:2e:bc:42:75:d4:9f:ab:1c:1a:5b:67:be:d2:9a -# SHA256 Fingerprint: c9:0f:26:f0:fb:1b:40:18:b2:22:27:51:9b:5c:a2:b5:3e:2c:a5:b3:be:5c:f1:8e:fe:1b:ef:47:38:0c:53:83 ------BEGIN CERTIFICATE----- -MIICOjCCAcGgAwIBAgIQQvLM2htpN0RfFf51KBC49DAKBggqhkjOPQQDAzBfMQsw -CQYDVQQGEwJHQjEYMBYGA1UEChMPU2VjdGlnbyBMaW1pdGVkMTYwNAYDVQQDEy1T -ZWN0aWdvIFB1YmxpYyBTZXJ2ZXIgQXV0aGVudGljYXRpb24gUm9vdCBFNDYwHhcN -MjEwMzIyMDAwMDAwWhcNNDYwMzIxMjM1OTU5WjBfMQswCQYDVQQGEwJHQjEYMBYG -A1UEChMPU2VjdGlnbyBMaW1pdGVkMTYwNAYDVQQDEy1TZWN0aWdvIFB1YmxpYyBT -ZXJ2ZXIgQXV0aGVudGljYXRpb24gUm9vdCBFNDYwdjAQBgcqhkjOPQIBBgUrgQQA -IgNiAAR2+pmpbiDt+dd34wc7qNs9Xzjoq1WmVk/WSOrsfy2qw7LFeeyZYX8QeccC -WvkEN/U0NSt3zn8gj1KjAIns1aeibVvjS5KToID1AZTc8GgHHs3u/iVStSBDHBv+ -6xnOQ6OjQjBAMB0GA1UdDgQWBBTRItpMWfFLXyY4qp3W7usNw/upYTAOBgNVHQ8B -Af8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAKBggqhkjOPQQDAwNnADBkAjAn7qRa -qCG76UeXlImldCBteU/IvZNeWBj7LRoAasm4PdCkT0RHlAFWovgzJQxC36oCMB3q -4S6ILuH5px0CMk7yn2xVdOOurvulGu7t0vzCAxHrRVxgED1cf5kDW21USAGKcw== ------END CERTIFICATE----- - -# Issuer: CN=Sectigo Public Server Authentication Root R46 O=Sectigo Limited -# Subject: CN=Sectigo Public Server Authentication Root R46 O=Sectigo Limited -# Label: "Sectigo Public Server Authentication Root R46" -# Serial: 156256931880233212765902055439220583700 -# MD5 Fingerprint: 32:10:09:52:00:d5:7e:6c:43:df:15:c0:b1:16:93:e5 -# SHA1 Fingerprint: ad:98:f9:f3:e4:7d:75:3b:65:d4:82:b3:a4:52:17:bb:6e:f5:e4:38 -# SHA256 Fingerprint: 7b:b6:47:a6:2a:ee:ac:88:bf:25:7a:a5:22:d0:1f:fe:a3:95:e0:ab:45:c7:3f:93:f6:56:54:ec:38:f2:5a:06 ------BEGIN CERTIFICATE----- -MIIFijCCA3KgAwIBAgIQdY39i658BwD6qSWn4cetFDANBgkqhkiG9w0BAQwFADBf -MQswCQYDVQQGEwJHQjEYMBYGA1UEChMPU2VjdGlnbyBMaW1pdGVkMTYwNAYDVQQD -Ey1TZWN0aWdvIFB1YmxpYyBTZXJ2ZXIgQXV0aGVudGljYXRpb24gUm9vdCBSNDYw -HhcNMjEwMzIyMDAwMDAwWhcNNDYwMzIxMjM1OTU5WjBfMQswCQYDVQQGEwJHQjEY -MBYGA1UEChMPU2VjdGlnbyBMaW1pdGVkMTYwNAYDVQQDEy1TZWN0aWdvIFB1Ymxp -YyBTZXJ2ZXIgQXV0aGVudGljYXRpb24gUm9vdCBSNDYwggIiMA0GCSqGSIb3DQEB -AQUAA4ICDwAwggIKAoICAQCTvtU2UnXYASOgHEdCSe5jtrch/cSV1UgrJnwUUxDa -ef0rty2k1Cz66jLdScK5vQ9IPXtamFSvnl0xdE8H/FAh3aTPaE8bEmNtJZlMKpnz -SDBh+oF8HqcIStw+KxwfGExxqjWMrfhu6DtK2eWUAtaJhBOqbchPM8xQljeSM9xf -iOefVNlI8JhD1mb9nxc4Q8UBUQvX4yMPFF1bFOdLvt30yNoDN9HWOaEhUTCDsG3X -ME6WW5HwcCSrv0WBZEMNvSE6Lzzpng3LILVCJ8zab5vuZDCQOc2TZYEhMbUjUDM3 -IuM47fgxMMxF/mL50V0yeUKH32rMVhlATc6qu/m1dkmU8Sf4kaWD5QazYw6A3OAS -VYCmO2a0OYctyPDQ0RTp5A1NDvZdV3LFOxxHVp3i1fuBYYzMTYCQNFu31xR13NgE -SJ/AwSiItOkcyqex8Va3e0lMWeUgFaiEAin6OJRpmkkGj80feRQXEgyDet4fsZfu -+Zd4KKTIRJLpfSYFplhym3kT2BFfrsU4YjRosoYwjviQYZ4ybPUHNs2iTG7sijbt -8uaZFURww3y8nDnAtOFr94MlI1fZEoDlSfB1D++N6xybVCi0ITz8fAr/73trdf+L -HaAZBav6+CuBQug4urv7qv094PPK306Xlynt8xhW6aWWrL3DkJiy4Pmi1KZHQ3xt -zwIDAQABo0IwQDAdBgNVHQ4EFgQUVnNYZJX5khqwEioEYnmhQBWIIUkwDgYDVR0P -AQH/BAQDAgGGMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEMBQADggIBAC9c -mTz8Bl6MlC5w6tIyMY208FHVvArzZJ8HXtXBc2hkeqK5Duj5XYUtqDdFqij0lgVQ -YKlJfp/imTYpE0RHap1VIDzYm/EDMrraQKFz6oOht0SmDpkBm+S8f74TlH7Kph52 -gDY9hAaLMyZlbcp+nv4fjFg4exqDsQ+8FxG75gbMY/qB8oFM2gsQa6H61SilzwZA -Fv97fRheORKkU55+MkIQpiGRqRxOF3yEvJ+M0ejf5lG5Nkc/kLnHvALcWxxPDkjB -JYOcCj+esQMzEhonrPcibCTRAUH4WAP+JWgiH5paPHxsnnVI84HxZmduTILA7rpX -DhjvLpr3Etiga+kFpaHpaPi8TD8SHkXoUsCjvxInebnMMTzD9joiFgOgyY9mpFui -TdaBJQbpdqQACj7LzTWb4OE4y2BThihCQRxEV+ioratF4yUQvNs+ZUH7G6aXD+u5 -dHn5HrwdVw1Hr8Mvn4dGp+smWg9WY7ViYG4A++MnESLn/pmPNPW56MORcr3Ywx65 -LvKRRFHQV80MNNVIIb/bE/FmJUNS0nAiNs2fxBx1IK1jcmMGDw4nztJqDby1ORrp -0XZ60Vzk50lJLVU3aPAaOpg+VBeHVOmmJ1CJeyAvP/+/oYtKR5j/K3tJPsMpRmAY -QqszKbrAKbkTidOIijlBO8n9pu0f9GBj39ItVQGL ------END CERTIFICATE----- - -# Issuer: CN=SSL.com TLS RSA Root CA 2022 O=SSL Corporation -# Subject: CN=SSL.com TLS RSA Root CA 2022 O=SSL Corporation -# Label: "SSL.com TLS RSA Root CA 2022" -# Serial: 148535279242832292258835760425842727825 -# MD5 Fingerprint: d8:4e:c6:59:30:d8:fe:a0:d6:7a:5a:2c:2c:69:78:da -# SHA1 Fingerprint: ec:2c:83:40:72:af:26:95:10:ff:0e:f2:03:ee:31:70:f6:78:9d:ca -# SHA256 Fingerprint: 8f:af:7d:2e:2c:b4:70:9b:b8:e0:b3:36:66:bf:75:a5:dd:45:b5:de:48:0f:8e:a8:d4:bf:e6:be:bc:17:f2:ed ------BEGIN CERTIFICATE----- -MIIFiTCCA3GgAwIBAgIQb77arXO9CEDii02+1PdbkTANBgkqhkiG9w0BAQsFADBO -MQswCQYDVQQGEwJVUzEYMBYGA1UECgwPU1NMIENvcnBvcmF0aW9uMSUwIwYDVQQD -DBxTU0wuY29tIFRMUyBSU0EgUm9vdCBDQSAyMDIyMB4XDTIyMDgyNTE2MzQyMloX -DTQ2MDgxOTE2MzQyMVowTjELMAkGA1UEBhMCVVMxGDAWBgNVBAoMD1NTTCBDb3Jw -b3JhdGlvbjElMCMGA1UEAwwcU1NMLmNvbSBUTFMgUlNBIFJvb3QgQ0EgMjAyMjCC -AiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBANCkCXJPQIgSYT41I57u9nTP -L3tYPc48DRAokC+X94xI2KDYJbFMsBFMF3NQ0CJKY7uB0ylu1bUJPiYYf7ISf5OY -t6/wNr/y7hienDtSxUcZXXTzZGbVXcdotL8bHAajvI9AI7YexoS9UcQbOcGV0ins -S657Lb85/bRi3pZ7QcacoOAGcvvwB5cJOYF0r/c0WRFXCsJbwST0MXMwgsadugL3 -PnxEX4MN8/HdIGkWCVDi1FW24IBydm5MR7d1VVm0U3TZlMZBrViKMWYPHqIbKUBO -L9975hYsLfy/7PO0+r4Y9ptJ1O4Fbtk085zx7AGL0SDGD6C1vBdOSHtRwvzpXGk3 -R2azaPgVKPC506QVzFpPulJwoxJF3ca6TvvC0PeoUidtbnm1jPx7jMEWTO6Af77w -dr5BUxIzrlo4QqvXDz5BjXYHMtWrifZOZ9mxQnUjbvPNQrL8VfVThxc7wDNY8VLS -+YCk8OjwO4s4zKTGkH8PnP2L0aPP2oOnaclQNtVcBdIKQXTbYxE3waWglksejBYS -d66UNHsef8JmAOSqg+qKkK3ONkRN0VHpvB/zagX9wHQfJRlAUW7qglFA35u5CCoG -AtUjHBPW6dvbxrB6y3snm/vg1UYk7RBLY0ulBY+6uB0rpvqR4pJSvezrZ5dtmi2f -gTIFZzL7SAg/2SW4BCUvAgMBAAGjYzBhMA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0j -BBgwFoAU+y437uOEeicuzRk1sTN8/9REQrkwHQYDVR0OBBYEFPsuN+7jhHonLs0Z -NbEzfP/UREK5MA4GA1UdDwEB/wQEAwIBhjANBgkqhkiG9w0BAQsFAAOCAgEAjYlt -hEUY8U+zoO9opMAdrDC8Z2awms22qyIZZtM7QbUQnRC6cm4pJCAcAZli05bg4vsM -QtfhWsSWTVTNj8pDU/0quOr4ZcoBwq1gaAafORpR2eCNJvkLTqVTJXojpBzOCBvf -R4iyrT7gJ4eLSYwfqUdYe5byiB0YrrPRpgqU+tvT5TgKa3kSM/tKWTcWQA673vWJ -DPFs0/dRa1419dvAJuoSc06pkZCmF8NsLzjUo3KUQyxi4U5cMj29TH0ZR6LDSeeW -P4+a0zvkEdiLA9z2tmBVGKaBUfPhqBVq6+AL8BQx1rmMRTqoENjwuSfr98t67wVy -lrXEj5ZzxOhWc5y8aVFjvO9nHEMaX3cZHxj4HCUp+UmZKbaSPaKDN7EgkaibMOlq -bLQjk2UEqxHzDh1TJElTHaE/nUiSEeJ9DU/1172iWD54nR4fK/4huxoTtrEoZP2w -AgDHbICivRZQIA9ygV/MlP+7mea6kMvq+cYMwq7FGc4zoWtcu358NFcXrfA/rs3q -r5nsLFR+jM4uElZI7xc7P0peYNLcdDa8pUNjyw9bowJWCZ4kLOGGgYz+qxcs+sji -Mho6/4UIyYOf8kpIEFR3N+2ivEC+5BB09+Rbu7nzifmPQdjH5FCQNYA+HLhNkNPU -98OwoX6EyneSMSy4kLGCenROmxMmtNVQZlR4rmA= ------END CERTIFICATE----- - -# Issuer: CN=SSL.com TLS ECC Root CA 2022 O=SSL Corporation -# Subject: CN=SSL.com TLS ECC Root CA 2022 O=SSL Corporation -# Label: "SSL.com TLS ECC Root CA 2022" -# Serial: 26605119622390491762507526719404364228 -# MD5 Fingerprint: 99:d7:5c:f1:51:36:cc:e9:ce:d9:19:2e:77:71:56:c5 -# SHA1 Fingerprint: 9f:5f:d9:1a:54:6d:f5:0c:71:f0:ee:7a:bd:17:49:98:84:73:e2:39 -# SHA256 Fingerprint: c3:2f:fd:9f:46:f9:36:d1:6c:36:73:99:09:59:43:4b:9a:d6:0a:af:bb:9e:7c:f3:36:54:f1:44:cc:1b:a1:43 ------BEGIN CERTIFICATE----- -MIICOjCCAcCgAwIBAgIQFAP1q/s3ixdAW+JDsqXRxDAKBggqhkjOPQQDAzBOMQsw -CQYDVQQGEwJVUzEYMBYGA1UECgwPU1NMIENvcnBvcmF0aW9uMSUwIwYDVQQDDBxT -U0wuY29tIFRMUyBFQ0MgUm9vdCBDQSAyMDIyMB4XDTIyMDgyNTE2MzM0OFoXDTQ2 -MDgxOTE2MzM0N1owTjELMAkGA1UEBhMCVVMxGDAWBgNVBAoMD1NTTCBDb3Jwb3Jh -dGlvbjElMCMGA1UEAwwcU1NMLmNvbSBUTFMgRUNDIFJvb3QgQ0EgMjAyMjB2MBAG -ByqGSM49AgEGBSuBBAAiA2IABEUpNXP6wrgjzhR9qLFNoFs27iosU8NgCTWyJGYm -acCzldZdkkAZDsalE3D07xJRKF3nzL35PIXBz5SQySvOkkJYWWf9lCcQZIxPBLFN -SeR7T5v15wj4A4j3p8OSSxlUgaNjMGEwDwYDVR0TAQH/BAUwAwEB/zAfBgNVHSME -GDAWgBSJjy+j6CugFFR781a4Jl9nOAuc0DAdBgNVHQ4EFgQUiY8vo+groBRUe/NW -uCZfZzgLnNAwDgYDVR0PAQH/BAQDAgGGMAoGCCqGSM49BAMDA2gAMGUCMFXjIlbp -15IkWE8elDIPDAI2wv2sdDJO4fscgIijzPvX6yv/N33w7deedWo1dlJF4AIxAMeN -b0Igj762TVntd00pxCAgRWSGOlDGxK0tk/UYfXLtqc/ErFc2KAhl3zx5Zn6g6g== ------END CERTIFICATE----- - -# Issuer: CN=Atos TrustedRoot Root CA ECC TLS 2021 O=Atos -# Subject: CN=Atos TrustedRoot Root CA ECC TLS 2021 O=Atos -# Label: "Atos TrustedRoot Root CA ECC TLS 2021" -# Serial: 81873346711060652204712539181482831616 -# MD5 Fingerprint: 16:9f:ad:f1:70:ad:79:d6:ed:29:b4:d1:c5:79:70:a8 -# SHA1 Fingerprint: 9e:bc:75:10:42:b3:02:f3:81:f4:f7:30:62:d4:8f:c3:a7:51:b2:dd -# SHA256 Fingerprint: b2:fa:e5:3e:14:cc:d7:ab:92:12:06:47:01:ae:27:9c:1d:89:88:fa:cb:77:5f:a8:a0:08:91:4e:66:39:88:a8 ------BEGIN CERTIFICATE----- -MIICFTCCAZugAwIBAgIQPZg7pmY9kGP3fiZXOATvADAKBggqhkjOPQQDAzBMMS4w -LAYDVQQDDCVBdG9zIFRydXN0ZWRSb290IFJvb3QgQ0EgRUNDIFRMUyAyMDIxMQ0w -CwYDVQQKDARBdG9zMQswCQYDVQQGEwJERTAeFw0yMTA0MjIwOTI2MjNaFw00MTA0 -MTcwOTI2MjJaMEwxLjAsBgNVBAMMJUF0b3MgVHJ1c3RlZFJvb3QgUm9vdCBDQSBF -Q0MgVExTIDIwMjExDTALBgNVBAoMBEF0b3MxCzAJBgNVBAYTAkRFMHYwEAYHKoZI -zj0CAQYFK4EEACIDYgAEloZYKDcKZ9Cg3iQZGeHkBQcfl+3oZIK59sRxUM6KDP/X -tXa7oWyTbIOiaG6l2b4siJVBzV3dscqDY4PMwL502eCdpO5KTlbgmClBk1IQ1SQ4 -AjJn8ZQSb+/Xxd4u/RmAo0IwQDAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBR2 -KCXWfeBmmnoJsmo7jjPXNtNPojAOBgNVHQ8BAf8EBAMCAYYwCgYIKoZIzj0EAwMD -aAAwZQIwW5kp85wxtolrbNa9d+F851F+uDrNozZffPc8dz7kUK2o59JZDCaOMDtu -CCrCp1rIAjEAmeMM56PDr9NJLkaCI2ZdyQAUEv049OGYa3cpetskz2VAv9LcjBHo -9H1/IISpQuQo ------END CERTIFICATE----- - -# Issuer: CN=Atos TrustedRoot Root CA RSA TLS 2021 O=Atos -# Subject: CN=Atos TrustedRoot Root CA RSA TLS 2021 O=Atos -# Label: "Atos TrustedRoot Root CA RSA TLS 2021" -# Serial: 111436099570196163832749341232207667876 -# MD5 Fingerprint: d4:d3:46:b8:9a:c0:9c:76:5d:9e:3a:c3:b9:99:31:d2 -# SHA1 Fingerprint: 18:52:3b:0d:06:37:e4:d6:3a:df:23:e4:98:fb:5b:16:fb:86:74:48 -# SHA256 Fingerprint: 81:a9:08:8e:a5:9f:b3:64:c5:48:a6:f8:55:59:09:9b:6f:04:05:ef:bf:18:e5:32:4e:c9:f4:57:ba:00:11:2f ------BEGIN CERTIFICATE----- -MIIFZDCCA0ygAwIBAgIQU9XP5hmTC/srBRLYwiqipDANBgkqhkiG9w0BAQwFADBM -MS4wLAYDVQQDDCVBdG9zIFRydXN0ZWRSb290IFJvb3QgQ0EgUlNBIFRMUyAyMDIx -MQ0wCwYDVQQKDARBdG9zMQswCQYDVQQGEwJERTAeFw0yMTA0MjIwOTIxMTBaFw00 -MTA0MTcwOTIxMDlaMEwxLjAsBgNVBAMMJUF0b3MgVHJ1c3RlZFJvb3QgUm9vdCBD -QSBSU0EgVExTIDIwMjExDTALBgNVBAoMBEF0b3MxCzAJBgNVBAYTAkRFMIICIjAN -BgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAtoAOxHm9BYx9sKOdTSJNy/BBl01Z -4NH+VoyX8te9j2y3I49f1cTYQcvyAh5x5en2XssIKl4w8i1mx4QbZFc4nXUtVsYv -Ye+W/CBGvevUez8/fEc4BKkbqlLfEzfTFRVOvV98r61jx3ncCHvVoOX3W3WsgFWZ -kmGbzSoXfduP9LVq6hdKZChmFSlsAvFr1bqjM9xaZ6cF4r9lthawEO3NUDPJcFDs -GY6wx/J0W2tExn2WuZgIWWbeKQGb9Cpt0xU6kGpn8bRrZtkh68rZYnxGEFzedUln -nkL5/nWpo63/dgpnQOPF943HhZpZnmKaau1Fh5hnstVKPNe0OwANwI8f4UDErmwh -3El+fsqyjW22v5MvoVw+j8rtgI5Y4dtXz4U2OLJxpAmMkokIiEjxQGMYsluMWuPD -0xeqqxmjLBvk1cbiZnrXghmmOxYsL3GHX0WelXOTwkKBIROW1527k2gV+p2kHYzy -geBYBr3JtuP2iV2J+axEoctr+hbxx1A9JNr3w+SH1VbxT5Aw+kUJWdo0zuATHAR8 -ANSbhqRAvNncTFd+rrcztl524WWLZt+NyteYr842mIycg5kDcPOvdO3GDjbnvezB -c6eUWsuSZIKmAMFwoW4sKeFYV+xafJlrJaSQOoD0IJ2azsct+bJLKZWD6TWNp0lI -pw9MGZHQ9b8Q4HECAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQU -dEmZ0f+0emhFdcN+tNzMzjkz2ggwDgYDVR0PAQH/BAQDAgGGMA0GCSqGSIb3DQEB -DAUAA4ICAQAjQ1MkYlxt/T7Cz1UAbMVWiLkO3TriJQ2VSpfKgInuKs1l+NsW4AmS -4BjHeJi78+xCUvuppILXTdiK/ORO/auQxDh1MoSf/7OwKwIzNsAQkG8dnK/haZPs -o0UvFJ/1TCplQ3IM98P4lYsU84UgYt1UU90s3BiVaU+DR3BAM1h3Egyi61IxHkzJ -qM7F78PRreBrAwA0JrRUITWXAdxfG/F851X6LWh3e9NpzNMOa7pNdkTWwhWaJuyw -xfW70Xp0wmzNxbVe9kzmWy2B27O3Opee7c9GslA9hGCZcbUztVdF5kJHdWoOsAgM -rr3e97sPWD2PAzHoPYJQyi9eDF20l74gNAf0xBLh7tew2VktafcxBPTy+av5EzH4 -AXcOPUIjJsyacmdRIXrMPIWo6iFqO9taPKU0nprALN+AnCng33eU0aKAQv9qTFsR -0PXNor6uzFFcw9VUewyu1rkGd4Di7wcaaMxZUa1+XGdrudviB0JbuAEFWDlN5LuY -o7Ey7Nmj1m+UI/87tyll5gfp77YZ6ufCOB0yiJA8EytuzO+rdwY0d4RPcuSBhPm5 -dDTedk+SKlOxJTnbPP/lPqYO5Wue/9vsL3SD3460s6neFE3/MaNFcyT6lSnMEpcE -oji2jbDwN/zIIX8/syQbPYtuzE2wFg2WHYMfRsCbvUOZ58SWLs5fyQ== ------END CERTIFICATE----- - -# Issuer: CN=TrustAsia Global Root CA G3 O=TrustAsia Technologies, Inc. -# Subject: CN=TrustAsia Global Root CA G3 O=TrustAsia Technologies, Inc. -# Label: "TrustAsia Global Root CA G3" -# Serial: 576386314500428537169965010905813481816650257167 -# MD5 Fingerprint: 30:42:1b:b7:bb:81:75:35:e4:16:4f:53:d2:94:de:04 -# SHA1 Fingerprint: 63:cf:b6:c1:27:2b:56:e4:88:8e:1c:23:9a:b6:2e:81:47:24:c3:c7 -# SHA256 Fingerprint: e0:d3:22:6a:eb:11:63:c2:e4:8f:f9:be:3b:50:b4:c6:43:1b:e7:bb:1e:ac:c5:c3:6b:5d:5e:c5:09:03:9a:08 ------BEGIN CERTIFICATE----- -MIIFpTCCA42gAwIBAgIUZPYOZXdhaqs7tOqFhLuxibhxkw8wDQYJKoZIhvcNAQEM -BQAwWjELMAkGA1UEBhMCQ04xJTAjBgNVBAoMHFRydXN0QXNpYSBUZWNobm9sb2dp -ZXMsIEluYy4xJDAiBgNVBAMMG1RydXN0QXNpYSBHbG9iYWwgUm9vdCBDQSBHMzAe -Fw0yMTA1MjAwMjEwMTlaFw00NjA1MTkwMjEwMTlaMFoxCzAJBgNVBAYTAkNOMSUw -IwYDVQQKDBxUcnVzdEFzaWEgVGVjaG5vbG9naWVzLCBJbmMuMSQwIgYDVQQDDBtU -cnVzdEFzaWEgR2xvYmFsIFJvb3QgQ0EgRzMwggIiMA0GCSqGSIb3DQEBAQUAA4IC -DwAwggIKAoICAQDAMYJhkuSUGwoqZdC+BqmHO1ES6nBBruL7dOoKjbmzTNyPtxNS -T1QY4SxzlZHFZjtqz6xjbYdT8PfxObegQ2OwxANdV6nnRM7EoYNl9lA+sX4WuDqK -AtCWHwDNBSHvBm3dIZwZQ0WhxeiAysKtQGIXBsaqvPPW5vxQfmZCHzyLpnl5hkA1 -nyDvP+uLRx+PjsXUjrYsyUQE49RDdT/VP68czH5GX6zfZBCK70bwkPAPLfSIC7Ep -qq+FqklYqL9joDiR5rPmd2jE+SoZhLsO4fWvieylL1AgdB4SQXMeJNnKziyhWTXA -yB1GJ2Faj/lN03J5Zh6fFZAhLf3ti1ZwA0pJPn9pMRJpxx5cynoTi+jm9WAPzJMs -hH/x/Gr8m0ed262IPfN2dTPXS6TIi/n1Q1hPy8gDVI+lhXgEGvNz8teHHUGf59gX -zhqcD0r83ERoVGjiQTz+LISGNzzNPy+i2+f3VANfWdP3kXjHi3dqFuVJhZBFcnAv -kV34PmVACxmZySYgWmjBNb9Pp1Hx2BErW+Canig7CjoKH8GB5S7wprlppYiU5msT -f9FkPz2ccEblooV7WIQn3MSAPmeamseaMQ4w7OYXQJXZRe0Blqq/DPNL0WP3E1jA -uPP6Z92bfW1K/zJMtSU7/xxnD4UiWQWRkUF3gdCFTIcQcf+eQxuulXUtgQIDAQAB -o2MwYTAPBgNVHRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFEDk5PIj7zjKsK5Xf/Ih -MBY027ySMB0GA1UdDgQWBBRA5OTyI+84yrCuV3/yITAWNNu8kjAOBgNVHQ8BAf8E -BAMCAQYwDQYJKoZIhvcNAQEMBQADggIBACY7UeFNOPMyGLS0XuFlXsSUT9SnYaP4 -wM8zAQLpw6o1D/GUE3d3NZ4tVlFEbuHGLige/9rsR82XRBf34EzC4Xx8MnpmyFq2 -XFNFV1pF1AWZLy4jVe5jaN/TG3inEpQGAHUNcoTpLrxaatXeL1nHo+zSh2bbt1S1 -JKv0Q3jbSwTEb93mPmY+KfJLaHEih6D4sTNjduMNhXJEIlU/HHzp/LgV6FL6qj6j -ITk1dImmasI5+njPtqzn59ZW/yOSLlALqbUHM/Q4X6RJpstlcHboCoWASzY9M/eV -VHUl2qzEc4Jl6VL1XP04lQJqaTDFHApXB64ipCz5xUG3uOyfT0gA+QEEVcys+TIx -xHWVBqB/0Y0n3bOppHKH/lmLmnp0Ft0WpWIp6zqW3IunaFnT63eROfjXy9mPX1on -AX1daBli2MjN9LdyR75bl87yraKZk62Uy5P2EgmVtqvXO9A/EcswFi55gORngS1d -7XB4tmBZrOFdRWOPyN9yaFvqHbgB8X7754qz41SgOAngPN5C8sLtLpvzHzW2Ntjj -gKGLzZlkD8Kqq7HK9W+eQ42EVJmzbsASZthwEPEGNTNDqJwuuhQxzhB/HIbjj9LV -+Hfsm6vxL2PZQl/gZ4FkkfGXL/xuJvYz+NO1+MRiqzFRJQJ6+N1rZdVtTTDIZbpo -FGWsJwt0ivKH ------END CERTIFICATE----- - -# Issuer: CN=TrustAsia Global Root CA G4 O=TrustAsia Technologies, Inc. -# Subject: CN=TrustAsia Global Root CA G4 O=TrustAsia Technologies, Inc. -# Label: "TrustAsia Global Root CA G4" -# Serial: 451799571007117016466790293371524403291602933463 -# MD5 Fingerprint: 54:dd:b2:d7:5f:d8:3e:ed:7c:e0:0b:2e:cc:ed:eb:eb -# SHA1 Fingerprint: 57:73:a5:61:5d:80:b2:e6:ac:38:82:fc:68:07:31:ac:9f:b5:92:5a -# SHA256 Fingerprint: be:4b:56:cb:50:56:c0:13:6a:52:6d:f4:44:50:8d:aa:36:a0:b5:4f:42:e4:ac:38:f7:2a:f4:70:e4:79:65:4c ------BEGIN CERTIFICATE----- -MIICVTCCAdygAwIBAgIUTyNkuI6XY57GU4HBdk7LKnQV1tcwCgYIKoZIzj0EAwMw -WjELMAkGA1UEBhMCQ04xJTAjBgNVBAoMHFRydXN0QXNpYSBUZWNobm9sb2dpZXMs -IEluYy4xJDAiBgNVBAMMG1RydXN0QXNpYSBHbG9iYWwgUm9vdCBDQSBHNDAeFw0y -MTA1MjAwMjEwMjJaFw00NjA1MTkwMjEwMjJaMFoxCzAJBgNVBAYTAkNOMSUwIwYD -VQQKDBxUcnVzdEFzaWEgVGVjaG5vbG9naWVzLCBJbmMuMSQwIgYDVQQDDBtUcnVz -dEFzaWEgR2xvYmFsIFJvb3QgQ0EgRzQwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAATx -s8045CVD5d4ZCbuBeaIVXxVjAd7Cq92zphtnS4CDr5nLrBfbK5bKfFJV4hrhPVbw -LxYI+hW8m7tH5j/uqOFMjPXTNvk4XatwmkcN4oFBButJ+bAp3TPsUKV/eSm4IJij -YzBhMA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAUpbtKl86zK3+kMd6Xg1mD -pm9xy94wHQYDVR0OBBYEFKW7SpfOsyt/pDHel4NZg6ZvccveMA4GA1UdDwEB/wQE -AwIBBjAKBggqhkjOPQQDAwNnADBkAjBe8usGzEkxn0AAbbd+NvBNEU/zy4k6LHiR -UKNbwMp1JvK/kF0LgoxgKJ/GcJpo5PECMFxYDlZ2z1jD1xCMuo6u47xkdUfFVZDj -/bpV6wfEU6s3qe4hsiFbYI89MvHVI5TWWA== ------END CERTIFICATE----- - -# Issuer: CN=Telekom Security TLS ECC Root 2020 O=Deutsche Telekom Security GmbH -# Subject: CN=Telekom Security TLS ECC Root 2020 O=Deutsche Telekom Security GmbH -# Label: "Telekom Security TLS ECC Root 2020" -# Serial: 72082518505882327255703894282316633856 -# MD5 Fingerprint: c1:ab:fe:6a:10:2c:03:8d:bc:1c:22:32:c0:85:a7:fd -# SHA1 Fingerprint: c0:f8:96:c5:a9:3b:01:06:21:07:da:18:42:48:bc:e9:9d:88:d5:ec -# SHA256 Fingerprint: 57:8a:f4:de:d0:85:3f:4e:59:98:db:4a:ea:f9:cb:ea:8d:94:5f:60:b6:20:a3:8d:1a:3c:13:b2:bc:7b:a8:e1 ------BEGIN CERTIFICATE----- -MIICQjCCAcmgAwIBAgIQNjqWjMlcsljN0AFdxeVXADAKBggqhkjOPQQDAzBjMQsw -CQYDVQQGEwJERTEnMCUGA1UECgweRGV1dHNjaGUgVGVsZWtvbSBTZWN1cml0eSBH -bWJIMSswKQYDVQQDDCJUZWxla29tIFNlY3VyaXR5IFRMUyBFQ0MgUm9vdCAyMDIw -MB4XDTIwMDgyNTA3NDgyMFoXDTQ1MDgyNTIzNTk1OVowYzELMAkGA1UEBhMCREUx -JzAlBgNVBAoMHkRldXRzY2hlIFRlbGVrb20gU2VjdXJpdHkgR21iSDErMCkGA1UE -AwwiVGVsZWtvbSBTZWN1cml0eSBUTFMgRUNDIFJvb3QgMjAyMDB2MBAGByqGSM49 -AgEGBSuBBAAiA2IABM6//leov9Wq9xCazbzREaK9Z0LMkOsVGJDZos0MKiXrPk/O -tdKPD/M12kOLAoC+b1EkHQ9rK8qfwm9QMuU3ILYg/4gND21Ju9sGpIeQkpT0CdDP -f8iAC8GXs7s1J8nCG6NCMEAwHQYDVR0OBBYEFONyzG6VmUex5rNhTNHLq+O6zd6f -MA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMAoGCCqGSM49BAMDA2cA -MGQCMHVSi7ekEE+uShCLsoRbQuHmKjYC2qBuGT8lv9pZMo7k+5Dck2TOrbRBR2Di -z6fLHgIwN0GMZt9Ba9aDAEH9L1r3ULRn0SyocddDypwnJJGDSA3PzfdUga/sf+Rn -27iQ7t0l ------END CERTIFICATE----- - -# Issuer: CN=Telekom Security TLS RSA Root 2023 O=Deutsche Telekom Security GmbH -# Subject: CN=Telekom Security TLS RSA Root 2023 O=Deutsche Telekom Security GmbH -# Label: "Telekom Security TLS RSA Root 2023" -# Serial: 44676229530606711399881795178081572759 -# MD5 Fingerprint: bf:5b:eb:54:40:cd:48:71:c4:20:8d:7d:de:0a:42:f2 -# SHA1 Fingerprint: 54:d3:ac:b3:bd:57:56:f6:85:9d:ce:e5:c3:21:e2:d4:ad:83:d0:93 -# SHA256 Fingerprint: ef:c6:5c:ad:bb:59:ad:b6:ef:e8:4d:a2:23:11:b3:56:24:b7:1b:3b:1e:a0:da:8b:66:55:17:4e:c8:97:86:46 ------BEGIN CERTIFICATE----- -MIIFszCCA5ugAwIBAgIQIZxULej27HF3+k7ow3BXlzANBgkqhkiG9w0BAQwFADBj -MQswCQYDVQQGEwJERTEnMCUGA1UECgweRGV1dHNjaGUgVGVsZWtvbSBTZWN1cml0 -eSBHbWJIMSswKQYDVQQDDCJUZWxla29tIFNlY3VyaXR5IFRMUyBSU0EgUm9vdCAy -MDIzMB4XDTIzMDMyODEyMTY0NVoXDTQ4MDMyNzIzNTk1OVowYzELMAkGA1UEBhMC -REUxJzAlBgNVBAoMHkRldXRzY2hlIFRlbGVrb20gU2VjdXJpdHkgR21iSDErMCkG -A1UEAwwiVGVsZWtvbSBTZWN1cml0eSBUTFMgUlNBIFJvb3QgMjAyMzCCAiIwDQYJ -KoZIhvcNAQEBBQADggIPADCCAgoCggIBAO01oYGA88tKaVvC+1GDrib94W7zgRJ9 -cUD/h3VCKSHtgVIs3xLBGYSJwb3FKNXVS2xE1kzbB5ZKVXrKNoIENqil/Cf2SfHV -cp6R+SPWcHu79ZvB7JPPGeplfohwoHP89v+1VmLhc2o0mD6CuKyVU/QBoCcHcqMA -U6DksquDOFczJZSfvkgdmOGjup5czQRxUX11eKvzWarE4GC+j4NSuHUaQTXtvPM6 -Y+mpFEXX5lLRbtLevOP1Czvm4MS9Q2QTps70mDdsipWol8hHD/BeEIvnHRz+sTug -BTNoBUGCwQMrAcjnj02r6LX2zWtEtefdi+zqJbQAIldNsLGyMcEWzv/9FIS3R/qy -8XDe24tsNlikfLMR0cN3f1+2JeANxdKz+bi4d9s3cXFH42AYTyS2dTd4uaNir73J -co4vzLuu2+QVUhkHM/tqty1LkCiCc/4YizWN26cEar7qwU02OxY2kTLvtkCJkUPg -8qKrBC7m8kwOFjQgrIfBLX7JZkcXFBGk8/ehJImr2BrIoVyxo/eMbcgByU/J7MT8 -rFEz0ciD0cmfHdRHNCk+y7AO+oMLKFjlKdw/fKifybYKu6boRhYPluV75Gp6SG12 -mAWl3G0eQh5C2hrgUve1g8Aae3g1LDj1H/1Joy7SWWO/gLCMk3PLNaaZlSJhZQNg -+y+TS/qanIA7AgMBAAGjYzBhMA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUtqeX -gj10hZv3PJ+TmpV5dVKMbUcwDwYDVR0TAQH/BAUwAwEB/zAfBgNVHSMEGDAWgBS2 -p5eCPXSFm/c8n5OalXl1UoxtRzANBgkqhkiG9w0BAQwFAAOCAgEAqMxhpr51nhVQ -pGv7qHBFfLp+sVr8WyP6Cnf4mHGCDG3gXkaqk/QeoMPhk9tLrbKmXauw1GLLXrtm -9S3ul0A8Yute1hTWjOKWi0FpkzXmuZlrYrShF2Y0pmtjxrlO8iLpWA1WQdH6DErw -M807u20hOq6OcrXDSvvpfeWxm4bu4uB9tPcy/SKE8YXJN3nptT+/XOR0so8RYgDd -GGah2XsjX/GO1WfoVNpbOms2b/mBsTNHM3dA+VKq3dSDz4V4mZqTuXNnQkYRIer+ -CqkbGmVps4+uFrb2S1ayLfmlyOw7YqPta9BO1UAJpB+Y1zqlklkg5LB9zVtzaL1t -xKITDmcZuI1CfmwMmm6gJC3VRRvcxAIU/oVbZZfKTpBQCHpCNfnqwmbU+AGuHrS+ -w6jv/naaoqYfRvaE7fzbzsQCzndILIyy7MMAo+wsVRjBfhnu4S/yrYObnqsZ38aK -L4x35bcF7DvB7L6Gs4a8wPfc5+pbrrLMtTWGS9DiP7bY+A4A7l3j941Y/8+LN+lj -X273CXE2whJdV/LItM3z7gLfEdxquVeEHVlNjM7IDiPCtyaaEBRx/pOyiriA8A4Q -ntOoUAw3gi/q4Iqd4Sw5/7W0cwDk90imc6y/st53BIe0o82bNSQ3+pCTE4FCxpgm -dTdmQRCsu/WU48IxK63nI1bMNSWSs1A= ------END CERTIFICATE----- - -# Issuer: CN=TWCA CYBER Root CA O=TAIWAN-CA OU=Root CA -# Subject: CN=TWCA CYBER Root CA O=TAIWAN-CA OU=Root CA -# Label: "TWCA CYBER Root CA" -# Serial: 85076849864375384482682434040119489222 -# MD5 Fingerprint: 0b:33:a0:97:52:95:d4:a9:fd:bb:db:6e:a3:55:5b:51 -# SHA1 Fingerprint: f6:b1:1c:1a:83:38:e9:7b:db:b3:a8:c8:33:24:e0:2d:9c:7f:26:66 -# SHA256 Fingerprint: 3f:63:bb:28:14:be:17:4e:c8:b6:43:9c:f0:8d:6d:56:f0:b7:c4:05:88:3a:56:48:a3:34:42:4d:6b:3e:c5:58 ------BEGIN CERTIFICATE----- -MIIFjTCCA3WgAwIBAgIQQAE0jMIAAAAAAAAAATzyxjANBgkqhkiG9w0BAQwFADBQ -MQswCQYDVQQGEwJUVzESMBAGA1UEChMJVEFJV0FOLUNBMRAwDgYDVQQLEwdSb290 -IENBMRswGQYDVQQDExJUV0NBIENZQkVSIFJvb3QgQ0EwHhcNMjIxMTIyMDY1NDI5 -WhcNNDcxMTIyMTU1OTU5WjBQMQswCQYDVQQGEwJUVzESMBAGA1UEChMJVEFJV0FO -LUNBMRAwDgYDVQQLEwdSb290IENBMRswGQYDVQQDExJUV0NBIENZQkVSIFJvb3Qg -Q0EwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDG+Moe2Qkgfh1sTs6P -40czRJzHyWmqOlt47nDSkvgEs1JSHWdyKKHfi12VCv7qze33Kc7wb3+szT3vsxxF -avcokPFhV8UMxKNQXd7UtcsZyoC5dc4pztKFIuwCY8xEMCDa6pFbVuYdHNWdZsc/ -34bKS1PE2Y2yHer43CdTo0fhYcx9tbD47nORxc5zb87uEB8aBs/pJ2DFTxnk684i -JkXXYJndzk834H/nY62wuFm40AZoNWDTNq5xQwTxaWV4fPMf88oon1oglWa0zbfu -j3ikRRjpJi+NmykosaS3Om251Bw4ckVYsV7r8Cibt4LK/c/WMw+f+5eesRycnupf -Xtuq3VTpMCEobY5583WSjCb+3MX2w7DfRFlDo7YDKPYIMKoNM+HvnKkHIuNZW0CP -2oi3aQiotyMuRAlZN1vH4xfyIutuOVLF3lSnmMlLIJXcRolftBL5hSmO68gnFSDA -S9TMfAxsNAwmmyYxpjyn9tnQS6Jk/zuZQXLB4HCX8SS7K8R0IrGsayIyJNN4KsDA -oS/xUgXJP+92ZuJF2A09rZXIx4kmyA+upwMu+8Ff+iDhcK2wZSA3M2Cw1a/XDBzC -kHDXShi8fgGwsOsVHkQGzaRP6AzRwyAQ4VRlnrZR0Bp2a0JaWHY06rc3Ga4udfmW -5cFZ95RXKSWNOkyrTZpB0F8mAwIDAQABo2MwYTAOBgNVHQ8BAf8EBAMCAQYwDwYD -VR0TAQH/BAUwAwEB/zAfBgNVHSMEGDAWgBSdhWEUfMFib5do5E83QOGt4A1WNzAd -BgNVHQ4EFgQUnYVhFHzBYm+XaORPN0DhreANVjcwDQYJKoZIhvcNAQEMBQADggIB -AGSPesRiDrWIzLjHhg6hShbNcAu3p4ULs3a2D6f/CIsLJc+o1IN1KriWiLb73y0t -tGlTITVX1olNc79pj3CjYcya2x6a4CD4bLubIp1dhDGaLIrdaqHXKGnK/nZVekZn -68xDiBaiA9a5F/gZbG0jAn/xX9AKKSM70aoK7akXJlQKTcKlTfjF/biBzysseKNn -TKkHmvPfXvt89YnNdJdhEGoHK4Fa0o635yDRIG4kqIQnoVesqlVYL9zZyvpoBJ7t -RCT5dEA7IzOrg1oYJkK2bVS1FmAwbLGg+LhBoF1JSdJlBTrq/p1hvIbZv97Tujqx -f36SNI7JAG7cmL3c7IAFrQI932XtCwP39xaEBDG6k5TY8hL4iuO/Qq+n1M0RFxbI -Qh0UqEL20kCGoE8jypZFVmAGzbdVAaYBlGX+bgUJurSkquLvWL69J1bY73NxW0Qz -8ppy6rBePm6pUlvscG21h483XjyMnM7k8M4MZ0HMzvaAq07MTFb1wWFZk7Q+ptq4 -NxKfKjLji7gh7MMrZQzvIt6IKTtM1/r+t+FHvpw+PoP7UV31aPcuIYXcv/Fa4nzX -xeSDwWrruoBa3lwtcHb4yOWHh8qgnaHlIhInD0Q9HWzq1MKLL295q39QpsQZp6F6 -t5b5wR9iWqJDB0BeJsas7a5wFsWqynKKTbDPAYsDP27X ------END CERTIFICATE----- - -# Issuer: CN=SecureSign Root CA12 O=Cybertrust Japan Co., Ltd. -# Subject: CN=SecureSign Root CA12 O=Cybertrust Japan Co., Ltd. -# Label: "SecureSign Root CA12" -# Serial: 587887345431707215246142177076162061960426065942 -# MD5 Fingerprint: c6:89:ca:64:42:9b:62:08:49:0b:1e:7f:e9:07:3d:e8 -# SHA1 Fingerprint: 7a:22:1e:3d:de:1b:06:ac:9e:c8:47:70:16:8e:3c:e5:f7:6b:06:f4 -# SHA256 Fingerprint: 3f:03:4b:b5:70:4d:44:b2:d0:85:45:a0:20:57:de:93:eb:f3:90:5f:ce:72:1a:cb:c7:30:c0:6d:da:ee:90:4e ------BEGIN CERTIFICATE----- -MIIDcjCCAlqgAwIBAgIUZvnHwa/swlG07VOX5uaCwysckBYwDQYJKoZIhvcNAQEL -BQAwUTELMAkGA1UEBhMCSlAxIzAhBgNVBAoTGkN5YmVydHJ1c3QgSmFwYW4gQ28u -LCBMdGQuMR0wGwYDVQQDExRTZWN1cmVTaWduIFJvb3QgQ0ExMjAeFw0yMDA0MDgw -NTM2NDZaFw00MDA0MDgwNTM2NDZaMFExCzAJBgNVBAYTAkpQMSMwIQYDVQQKExpD -eWJlcnRydXN0IEphcGFuIENvLiwgTHRkLjEdMBsGA1UEAxMUU2VjdXJlU2lnbiBS -b290IENBMTIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC6OcE3emhF -KxS06+QT61d1I02PJC0W6K6OyX2kVzsqdiUzg2zqMoqUm048luT9Ub+ZyZN+v/mt -p7JIKwccJ/VMvHASd6SFVLX9kHrko+RRWAPNEHl57muTH2SOa2SroxPjcf59q5zd -J1M3s6oYwlkm7Fsf0uZlfO+TvdhYXAvA42VvPMfKWeP+bl+sg779XSVOKik71gur -FzJ4pOE+lEa+Ym6b3kaosRbnhW70CEBFEaCeVESE99g2zvVQR9wsMJvuwPWW0v4J -hscGWa5Pro4RmHvzC1KqYiaqId+OJTN5lxZJjfU+1UefNzFJM3IFTQy2VYzxV4+K -h9GtxRESOaCtAgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQD -AgEGMB0GA1UdDgQWBBRXNPN0zwRL1SXm8UC2LEzZLemgrTANBgkqhkiG9w0BAQsF -AAOCAQEAPrvbFxbS8hQBICw4g0utvsqFepq2m2um4fylOqyttCg6r9cBg0krY6Ld -mmQOmFxv3Y67ilQiLUoT865AQ9tPkbeGGuwAtEGBpE/6aouIs3YIcipJQMPTw4WJ -mBClnW8Zt7vPemVV2zfrPIpyMpcemik+rY3moxtt9XUa5rBouVui7mlHJzWhhpmA -8zNL4WukJsPvdFlseqJkth5Ew1DgDzk9qTPxpfPSvWKErI4cqc1avTc7bgoitPQV -55FYxTpE05Uo2cBl6XLK0A+9H7MV2anjpEcJnuDLN/v9vZfVvhgaaaI5gdka9at/ -yOPiZwud9AzqVN/Ssq+xIvEg37xEHA== ------END CERTIFICATE----- - -# Issuer: CN=SecureSign Root CA14 O=Cybertrust Japan Co., Ltd. -# Subject: CN=SecureSign Root CA14 O=Cybertrust Japan Co., Ltd. -# Label: "SecureSign Root CA14" -# Serial: 575790784512929437950770173562378038616896959179 -# MD5 Fingerprint: 71:0d:72:fa:92:19:65:5e:89:04:ac:16:33:f0:bc:d5 -# SHA1 Fingerprint: dd:50:c0:f7:79:b3:64:2e:74:a2:b8:9d:9f:d3:40:dd:bb:f0:f2:4f -# SHA256 Fingerprint: 4b:00:9c:10:34:49:4f:9a:b5:6b:ba:3b:a1:d6:27:31:fc:4d:20:d8:95:5a:dc:ec:10:a9:25:60:72:61:e3:38 ------BEGIN CERTIFICATE----- -MIIFcjCCA1qgAwIBAgIUZNtaDCBO6Ncpd8hQJ6JaJ90t8sswDQYJKoZIhvcNAQEM -BQAwUTELMAkGA1UEBhMCSlAxIzAhBgNVBAoTGkN5YmVydHJ1c3QgSmFwYW4gQ28u -LCBMdGQuMR0wGwYDVQQDExRTZWN1cmVTaWduIFJvb3QgQ0ExNDAeFw0yMDA0MDgw -NzA2MTlaFw00NTA0MDgwNzA2MTlaMFExCzAJBgNVBAYTAkpQMSMwIQYDVQQKExpD -eWJlcnRydXN0IEphcGFuIENvLiwgTHRkLjEdMBsGA1UEAxMUU2VjdXJlU2lnbiBS -b290IENBMTQwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDF0nqh1oq/ -FjHQmNE6lPxauG4iwWL3pwon71D2LrGeaBLwbCRjOfHw3xDG3rdSINVSW0KZnvOg -vlIfX8xnbacuUKLBl422+JX1sLrcneC+y9/3OPJH9aaakpUqYllQC6KxNedlsmGy -6pJxaeQp8E+BgQQ8sqVb1MWoWWd7VRxJq3qdwudzTe/NCcLEVxLbAQ4jeQkHO6Lo -/IrPj8BGJJw4J+CDnRugv3gVEOuGTgpa/d/aLIJ+7sr2KeH6caH3iGicnPCNvg9J -kdjqOvn90Ghx2+m1K06Ckm9mH+Dw3EzsytHqunQG+bOEkJTRX45zGRBdAuVwpcAQ -0BB8b8VYSbSwbprafZX1zNoCr7gsfXmPvkPx+SgojQlD+Ajda8iLLCSxjVIHvXib -y8posqTdDEx5YMaZ0ZPxMBoH064iwurO8YQJzOAUbn8/ftKChazcqRZOhaBgy/ac -18izju3Gm5h1DVXoX+WViwKkrkMpKBGk5hIwAUt1ax5mnXkvpXYvHUC0bcl9eQjs -0Wq2XSqypWa9a4X0dFbD9ed1Uigspf9mR6XU/v6eVL9lfgHWMI+lNpyiUBzuOIAB -SMbHdPTGrMNASRZhdCyvjG817XsYAFs2PJxQDcqSMxDxJklt33UkN4Ii1+iW/RVL -ApY+B3KVfqs9TC7XyvDf4Fg/LS8EmjijAQIDAQABo0IwQDAPBgNVHRMBAf8EBTAD -AQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUBpOjCl4oaTeqYR3r6/wtbyPk -86AwDQYJKoZIhvcNAQEMBQADggIBAJaAcgkGfpzMkwQWu6A6jZJOtxEaCnFxEM0E -rX+lRVAQZk5KQaID2RFPeje5S+LGjzJmdSX7684/AykmjbgWHfYfM25I5uj4V7Ib -ed87hwriZLoAymzvftAj63iP/2SbNDefNWWipAA9EiOWWF3KY4fGoweITedpdopT -zfFP7ELyk+OZpDc8h7hi2/DsHzc/N19DzFGdtfCXwreFamgLRB7lUe6TzktuhsHS -DCRZNhqfLJGP4xjblJUK7ZGqDpncllPjYYPGFrojutzdfhrGe0K22VoF3Jpf1d+4 -2kd92jjbrDnVHmtsKheMYc2xbXIBw8MgAGJoFjHVdqqGuw6qnsb58Nn4DSEC5MUo -FlkRudlpcyqSeLiSV5sI8jrlL5WwWLdrIBRtFO8KvH7YVdiI2i/6GaX7i+B/OfVy -K4XELKzvGUWSTLNhB9xNH27SgRNcmvMSZ4PPmz+Ln52kuaiWA3rF7iDeM9ovnhp6 -dB7h7sxaOgTdsxoEqBRjrLdHEoOabPXm6RUVkRqEGQ6UROcSjiVbgGcZ3GOTEAtl -Lor6CZpO2oYofaphNdgOpygau1LgePhsumywbrmHXumZNTfxPWQrqaA0k89jL9WB -365jJ6UeTo3cKXhZ+PmhIIynJkBugnLNeLLIjzwec+fBH7/PzqUqm9tEZDKgu39c -JRNItX+S ------END CERTIFICATE----- - -# Issuer: CN=SecureSign Root CA15 O=Cybertrust Japan Co., Ltd. -# Subject: CN=SecureSign Root CA15 O=Cybertrust Japan Co., Ltd. -# Label: "SecureSign Root CA15" -# Serial: 126083514594751269499665114766174399806381178503 -# MD5 Fingerprint: 13:30:fc:c4:62:a6:a9:de:b5:c1:68:af:b5:d2:31:47 -# SHA1 Fingerprint: cb:ba:83:c8:c1:5a:5d:f1:f9:73:6f:ca:d7:ef:28:13:06:4a:07:7d -# SHA256 Fingerprint: e7:78:f0:f0:95:fe:84:37:29:cd:1a:00:82:17:9e:53:14:a9:c2:91:44:28:05:e1:fb:1d:8f:b6:b8:88:6c:3a ------BEGIN CERTIFICATE----- -MIICIzCCAamgAwIBAgIUFhXHw9hJp75pDIqI7fBw+d23PocwCgYIKoZIzj0EAwMw -UTELMAkGA1UEBhMCSlAxIzAhBgNVBAoTGkN5YmVydHJ1c3QgSmFwYW4gQ28uLCBM -dGQuMR0wGwYDVQQDExRTZWN1cmVTaWduIFJvb3QgQ0ExNTAeFw0yMDA0MDgwODMy -NTZaFw00NTA0MDgwODMyNTZaMFExCzAJBgNVBAYTAkpQMSMwIQYDVQQKExpDeWJl -cnRydXN0IEphcGFuIENvLiwgTHRkLjEdMBsGA1UEAxMUU2VjdXJlU2lnbiBSb290 -IENBMTUwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAAQLUHSNZDKZmbPSYAi4Io5GdCx4 -wCtELW1fHcmuS1Iggz24FG1Th2CeX2yF2wYUleDHKP+dX+Sq8bOLbe1PL0vJSpSR -ZHX+AezB2Ot6lHhWGENfa4HL9rzatAy2KZMIaY+jQjBAMA8GA1UdEwEB/wQFMAMB -Af8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBTrQciu/NWeUUj1vYv0hyCTQSvT -9DAKBggqhkjOPQQDAwNoADBlAjEA2S6Jfl5OpBEHvVnCB96rMjhTKkZEBhd6zlHp -4P9mLQlO4E/0BdGF9jVg3PVys0Z9AjBEmEYagoUeYWmJSwdLZrWeqrqgHkHZAXQ6 -bkU6iYAZezKYVWOr62Nuk22rGwlgMU4= ------END CERTIFICATE----- - -# Issuer: CN=D-TRUST BR Root CA 2 2023 O=D-Trust GmbH -# Subject: CN=D-TRUST BR Root CA 2 2023 O=D-Trust GmbH -# Label: "D-TRUST BR Root CA 2 2023" -# Serial: 153168538924886464690566649552453098598 -# MD5 Fingerprint: e1:09:ed:d3:60:d4:56:1b:47:1f:b7:0c:5f:1b:5f:85 -# SHA1 Fingerprint: 2d:b0:70:ee:71:94:af:69:68:17:db:79:ce:58:9f:a0:6b:96:f7:87 -# SHA256 Fingerprint: 05:52:e6:f8:3f:df:65:e8:fa:96:70:e6:66:df:28:a4:e2:13:40:b5:10:cb:e5:25:66:f9:7c:4f:b9:4b:2b:d1 ------BEGIN CERTIFICATE----- -MIIFqTCCA5GgAwIBAgIQczswBEhb2U14LnNLyaHcZjANBgkqhkiG9w0BAQ0FADBI -MQswCQYDVQQGEwJERTEVMBMGA1UEChMMRC1UcnVzdCBHbWJIMSIwIAYDVQQDExlE -LVRSVVNUIEJSIFJvb3QgQ0EgMiAyMDIzMB4XDTIzMDUwOTA4NTYzMVoXDTM4MDUw -OTA4NTYzMFowSDELMAkGA1UEBhMCREUxFTATBgNVBAoTDEQtVHJ1c3QgR21iSDEi -MCAGA1UEAxMZRC1UUlVTVCBCUiBSb290IENBIDIgMjAyMzCCAiIwDQYJKoZIhvcN -AQEBBQADggIPADCCAgoCggIBAK7/CVmRgApKaOYkP7in5Mg6CjoWzckjYaCTcfKr -i3OPoGdlYNJUa2NRb0kz4HIHE304zQaSBylSa053bATTlfrdTIzZXcFhfUvnKLNE -gXtRr90zsWh81k5M/itoucpmacTsXld/9w3HnDY25QdgrMBM6ghs7wZ8T1soegj8 -k12b9py0i4a6Ibn08OhZWiihNIQaJZG2tY/vsvmA+vk9PBFy2OMvhnbFeSzBqZCT -Rphny4NqoFAjpzv2gTng7fC5v2Xx2Mt6++9zA84A9H3X4F07ZrjcjrqDy4d2A/wl -2ecjbwb9Z/Pg/4S8R7+1FhhGaRTMBffb00msa8yr5LULQyReS2tNZ9/WtT5PeB+U -cSTq3nD88ZP+npNa5JRal1QMNXtfbO4AHyTsA7oC9Xb0n9Sa7YUsOCIvx9gvdhFP -/Wxc6PWOJ4d/GUohR5AdeY0cW/jPSoXk7bNbjb7EZChdQcRurDhaTyN0dKkSw/bS -uREVMweR2Ds3OmMwBtHFIjYoYiMQ4EbMl6zWK11kJNXuHA7e+whadSr2Y23OC0K+ -0bpwHJwh5Q8xaRfX/Aq03u2AnMuStIv13lmiWAmlY0cL4UEyNEHZmrHZqLAbWt4N -DfTisl01gLmB1IRpkQLLddCNxbU9CZEJjxShFHR5PtbJFR2kWVki3PaKRT08EtY+ -XTIvAgMBAAGjgY4wgYswDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUZ5Dw1t61 -GNVGKX5cq/ieCLxklRAwDgYDVR0PAQH/BAQDAgEGMEkGA1UdHwRCMEAwPqA8oDqG -OGh0dHA6Ly9jcmwuZC10cnVzdC5uZXQvY3JsL2QtdHJ1c3RfYnJfcm9vdF9jYV8y -XzIwMjMuY3JsMA0GCSqGSIb3DQEBDQUAA4ICAQA097N3U9swFrktpSHxQCF16+tI -FoE9c+CeJyrrd6kTpGoKWloUMz1oH4Guaf2Mn2VsNELZLdB/eBaxOqwjMa1ef67n -riv6uvw8l5VAk1/DLQOj7aRvU9f6QA4w9QAgLABMjDu0ox+2v5Eyq6+SmNMW5tTR -VFxDWy6u71cqqLRvpO8NVhTaIasgdp4D/Ca4nj8+AybmTNudX0KEPUUDAxxZiMrc -LmEkWqTqJwtzEr5SswrPMhfiHocaFpVIbVrg0M8JkiZmkdijYQ6qgYF/6FKC0ULn -4B0Y+qSFNueG4A3rvNTJ1jxD8V1Jbn6Bm2m1iWKPiFLY1/4nwSPFyysCu7Ff/vtD -hQNGvl3GyiEm/9cCnnRK3PgTFbGBVzbLZVzRHTF36SXDw7IyN9XxmAnkbWOACKsG -koHU6XCPpz+y7YaMgmo1yEJagtFSGkUPFaUA8JR7ZSdXOUPPfH/mvTWze/EZTN46 -ls/pdu4D58JDUjxqgejBWoC9EV2Ta/vH5mQ/u2kc6d0li690yVRAysuTEwrt+2aS -Ecr1wPrYg1UDfNPFIkZ1cGt5SAYqgpq/5usWDiJFAbzdNpQ0qTUmiteXue4Icr80 -knCDgKs4qllo3UCkGJCy89UDyibK79XH4I9TjvAA46jtn/mtd+ArY0+ew+43u3gJ -hJ65bvspmZDogNOfJA== ------END CERTIFICATE----- - -# Issuer: CN=TrustAsia TLS ECC Root CA O=TrustAsia Technologies, Inc. -# Subject: CN=TrustAsia TLS ECC Root CA O=TrustAsia Technologies, Inc. -# Label: "TrustAsia TLS ECC Root CA" -# Serial: 310892014698942880364840003424242768478804666567 -# MD5 Fingerprint: 09:48:04:77:d2:fc:65:93:71:66:b1:11:95:4f:06:8c -# SHA1 Fingerprint: b5:ec:39:f3:a1:66:37:ae:c3:05:94:57:e2:be:11:be:b7:a1:7f:36 -# SHA256 Fingerprint: c0:07:6b:9e:f0:53:1f:b1:a6:56:d6:7c:4e:be:97:cd:5d:ba:a4:1e:f4:45:98:ac:c2:48:98:78:c9:2d:87:11 ------BEGIN CERTIFICATE----- -MIICMTCCAbegAwIBAgIUNnThTXxlE8msg1UloD5Sfi9QaMcwCgYIKoZIzj0EAwMw -WDELMAkGA1UEBhMCQ04xJTAjBgNVBAoTHFRydXN0QXNpYSBUZWNobm9sb2dpZXMs -IEluYy4xIjAgBgNVBAMTGVRydXN0QXNpYSBUTFMgRUNDIFJvb3QgQ0EwHhcNMjQw -NTE1MDU0MTU2WhcNNDQwNTE1MDU0MTU1WjBYMQswCQYDVQQGEwJDTjElMCMGA1UE -ChMcVHJ1c3RBc2lhIFRlY2hub2xvZ2llcywgSW5jLjEiMCAGA1UEAxMZVHJ1c3RB -c2lhIFRMUyBFQ0MgUm9vdCBDQTB2MBAGByqGSM49AgEGBSuBBAAiA2IABLh/pVs/ -AT598IhtrimY4ZtcU5nb9wj/1WrgjstEpvDBjL1P1M7UiFPoXlfXTr4sP/MSpwDp -guMqWzJ8S5sUKZ74LYO1644xST0mYekdcouJtgq7nDM1D9rs3qlKH8kzsaNCMEAw -DwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQULIVTu7FDzTLqnqOH/qKYqKaT6RAw -DgYDVR0PAQH/BAQDAgEGMAoGCCqGSM49BAMDA2gAMGUCMFRH18MtYYZI9HlaVQ01 -L18N9mdsd0AaRuf4aFtOJx24mH1/k78ITcTaRTChD15KeAIxAKORh/IRM4PDwYqR -OkwrULG9IpRdNYlzg8WbGf60oenUoWa2AaU2+dhoYSi3dOGiMQ== ------END CERTIFICATE----- - -# Issuer: CN=TrustAsia TLS RSA Root CA O=TrustAsia Technologies, Inc. -# Subject: CN=TrustAsia TLS RSA Root CA O=TrustAsia Technologies, Inc. -# Label: "TrustAsia TLS RSA Root CA" -# Serial: 160405846464868906657516898462547310235378010780 -# MD5 Fingerprint: 3b:9e:c3:86:0f:34:3c:6b:c5:46:c4:8e:1d:e7:19:12 -# SHA1 Fingerprint: a5:46:50:c5:62:ea:95:9a:1a:a7:04:6f:17:58:c7:29:53:3d:03:fa -# SHA256 Fingerprint: 06:c0:8d:7d:af:d8:76:97:1e:b1:12:4f:e6:7f:84:7e:c0:c7:a1:58:d3:ea:53:cb:e9:40:e2:ea:97:91:f4:c3 ------BEGIN CERTIFICATE----- -MIIFgDCCA2igAwIBAgIUHBjYz+VTPyI1RlNUJDxsR9FcSpwwDQYJKoZIhvcNAQEM -BQAwWDELMAkGA1UEBhMCQ04xJTAjBgNVBAoTHFRydXN0QXNpYSBUZWNobm9sb2dp -ZXMsIEluYy4xIjAgBgNVBAMTGVRydXN0QXNpYSBUTFMgUlNBIFJvb3QgQ0EwHhcN -MjQwNTE1MDU0MTU3WhcNNDQwNTE1MDU0MTU2WjBYMQswCQYDVQQGEwJDTjElMCMG -A1UEChMcVHJ1c3RBc2lhIFRlY2hub2xvZ2llcywgSW5jLjEiMCAGA1UEAxMZVHJ1 -c3RBc2lhIFRMUyBSU0EgUm9vdCBDQTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCC -AgoCggIBAMMWuBtqpERz5dZO9LnPWwvB0ZqB9WOwj0PBuwhaGnrhB3YmH49pVr7+ -NmDQDIPNlOrnxS1cLwUWAp4KqC/lYCZUlviYQB2srp10Zy9U+5RjmOMmSoPGlbYJ -Q1DNDX3eRA5gEk9bNb2/mThtfWza4mhzH/kxpRkQcwUqwzIZheo0qt1CHjCNP561 -HmHVb70AcnKtEj+qpklz8oYVlQwQX1Fkzv93uMltrOXVmPGZLmzjyUT5tUMnCE32 -ft5EebuyjBza00tsLtbDeLdM1aTk2tyKjg7/D8OmYCYozza/+lcK7Fs/6TAWe8Tb -xNRkoDD75f0dcZLdKY9BWN4ArTr9PXwaqLEX8E40eFgl1oUh63kd0Nyrz2I8sMeX -i9bQn9P+PN7F4/w6g3CEIR0JwqH8uyghZVNgepBtljhb//HXeltt08lwSUq6HTrQ -UNoyIBnkiz/r1RYmNzz7dZ6wB3C4FGB33PYPXFIKvF1tjVEK2sUYyJtt3LCDs3+j -TnhMmCWr8n4uIF6CFabW2I+s5c0yhsj55NqJ4js+k8UTav/H9xj8Z7XvGCxUq0DT -bE3txci3OE9kxJRMT6DNrqXGJyV1J23G2pyOsAWZ1SgRxSHUuPzHlqtKZFlhaxP8 -S8ySpg+kUb8OWJDZgoM5pl+z+m6Ss80zDoWo8SnTq1mt1tve1CuBAgMBAAGjQjBA -MA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFLgHkXlcBvRG/XtZylomkadFK/hT -MA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQwFAAOCAgEAIZtqBSBdGBanEqT3 -Rz/NyjuujsCCztxIJXgXbODgcMTWltnZ9r96nBO7U5WS/8+S4PPFJzVXqDuiGev4 -iqME3mmL5Dw8veWv0BIb5Ylrc5tvJQJLkIKvQMKtuppgJFqBTQUYo+IzeXoLH5Pt -7DlK9RME7I10nYEKqG/odv6LTytpEoYKNDbdgptvT+Bz3Ul/KD7JO6NXBNiT2Twp -2xIQaOHEibgGIOcberyxk2GaGUARtWqFVwHxtlotJnMnlvm5P1vQiJ3koP26TpUJ -g3933FEFlJ0gcXax7PqJtZwuhfG5WyRasQmr2soaB82G39tp27RIGAAtvKLEiUUj -pQ7hRGU+isFqMB3iYPg6qocJQrmBktwliJiJ8Xw18WLK7nn4GS/+X/jbh87qqA8M -pugLoDzga5SYnH+tBuYc6kIQX+ImFTw3OffXvO645e8D7r0i+yiGNFjEWn9hongP -XvPKnbwbPKfILfanIhHKA9jnZwqKDss1jjQ52MjqjZ9k4DewbNfFj8GQYSbbJIwe -SsCI3zWQzj8C9GRh3sfIB5XeMhg6j6JCQCTl1jNdfK7vsU1P1FeQNWrcrgSXSYk0 -ly4wBOeY99sLAZDBHwo/+ML+TvrbmnNzFrwFuHnYWa8G5z9nODmxfKuU4CkUpijy -323imttUQ/hHWKNddBWcwauwxzQ= ------END CERTIFICATE----- - -# Issuer: CN=D-TRUST EV Root CA 2 2023 O=D-Trust GmbH -# Subject: CN=D-TRUST EV Root CA 2 2023 O=D-Trust GmbH -# Label: "D-TRUST EV Root CA 2 2023" -# Serial: 139766439402180512324132425437959641711 -# MD5 Fingerprint: 96:b4:78:09:f0:09:cb:77:eb:bb:1b:4d:6f:36:bc:b6 -# SHA1 Fingerprint: a5:5b:d8:47:6c:8f:19:f7:4c:f4:6d:6b:b6:c2:79:82:22:df:54:8b -# SHA256 Fingerprint: 8e:82:21:b2:e7:d4:00:78:36:a1:67:2f:0d:cc:29:9c:33:bc:07:d3:16:f1:32:fa:1a:20:6d:58:71:50:f1:ce ------BEGIN CERTIFICATE----- -MIIFqTCCA5GgAwIBAgIQaSYJfoBLTKCnjHhiU19abzANBgkqhkiG9w0BAQ0FADBI -MQswCQYDVQQGEwJERTEVMBMGA1UEChMMRC1UcnVzdCBHbWJIMSIwIAYDVQQDExlE -LVRSVVNUIEVWIFJvb3QgQ0EgMiAyMDIzMB4XDTIzMDUwOTA5MTAzM1oXDTM4MDUw -OTA5MTAzMlowSDELMAkGA1UEBhMCREUxFTATBgNVBAoTDEQtVHJ1c3QgR21iSDEi -MCAGA1UEAxMZRC1UUlVTVCBFViBSb290IENBIDIgMjAyMzCCAiIwDQYJKoZIhvcN -AQEBBQADggIPADCCAgoCggIBANiOo4mAC7JXUtypU0w3uX9jFxPvp1sjW2l1sJkK -F8GLxNuo4MwxusLyzV3pt/gdr2rElYfXR8mV2IIEUD2BCP/kPbOx1sWy/YgJ25yE -7CUXFId/MHibaljJtnMoPDT3mfd/06b4HEV8rSyMlD/YZxBTfiLNTiVR8CUkNRFe -EMbsh2aJgWi6zCudR3Mfvc2RpHJqnKIbGKBv7FD0fUDCqDDPvXPIEysQEx6Lmqg6 -lHPTGGkKSv/BAQP/eX+1SH977ugpbzZMlWGG2Pmic4ruri+W7mjNPU0oQvlFKzIb -RlUWaqZLKfm7lVa/Rh3sHZMdwGWyH6FDrlaeoLGPaxK3YG14C8qKXO0elg6DpkiV -jTujIcSuWMYAsoS0I6SWhjW42J7YrDRJmGOVxcttSEfi8i4YHtAxq9107PncjLgc -jmgjutDzUNzPZY9zOjLHfP7KgiJPvo5iR2blzYfi6NUPGJ/lBHJLRjwQ8kTCZFZx -TnXonMkmdMV9WdEKWw9t/p51HBjGGjp82A0EzM23RWV6sY+4roRIPrN6TagD4uJ+ -ARZZaBhDM7DS3LAaQzXupdqpRlyuhoFBAUp0JuyfBr/CBTdkdXgpaP3F9ev+R/nk -hbDhezGdpn9yo7nELC7MmVcOIQxFAZRl62UJxmMiCzNJkkg8/M3OsD6Onov4/knF -NXJHAgMBAAGjgY4wgYswDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUqvyREBuH -kV8Wub9PS5FeAByxMoAwDgYDVR0PAQH/BAQDAgEGMEkGA1UdHwRCMEAwPqA8oDqG -OGh0dHA6Ly9jcmwuZC10cnVzdC5uZXQvY3JsL2QtdHJ1c3RfZXZfcm9vdF9jYV8y -XzIwMjMuY3JsMA0GCSqGSIb3DQEBDQUAA4ICAQCTy6UfmRHsmg1fLBWTxj++EI14 -QvBukEdHjqOSMo1wj/Zbjb6JzkcBahsgIIlbyIIQbODnmaprxiqgYzWRaoUlrRc4 -pZt+UPJ26oUFKidBK7GB0aL2QHWpDsvxVUjY7NHss+jOFKE17MJeNRqrphYBBo7q -3C+jisosketSjl8MmxfPy3MHGcRqwnNU73xDUmPBEcrCRbH0O1P1aa4846XerOhU -t7KR/aypH/KH5BfGSah82ApB9PI+53c0BFLd6IHyTS9URZ0V4U/M5d40VxDJI3IX -cI1QcB9WbMy5/zpaT2N6w25lBx2Eof+pDGOJbbJAiDnXH3dotfyc1dZnaVuodNv8 -ifYbMvekJKZ2t0dT741Jj6m2g1qllpBFYfXeA08mD6iL8AOWsKwV0HFaanuU5nCT -2vFp4LJiTZ6P/4mdm13NRemUAiKN4DV/6PEEeXFsVIP4M7kFMhtYVRFP0OUnR3Hs -7dpn1mKmS00PaaLJvOwiS5THaJQXfuKOKD62xur1NGyfN4gHONuGcfrNlUhDbqNP -gofXNJhuS5N5YHVpD/Aa1VP6IQzCP+k/HxiMkl14p3ZnGbuy6n/pcAlWVqOwDAst -Nl7F6cTVg8uGF5csbBNvh1qvSaYd2804BC5f4ko1Di1L+KIkBI3Y4WNeApI02phh -XBxvWHZks/wCuPWdCg== ------END CERTIFICATE----- - -# Issuer: CN=SwissSign RSA TLS Root CA 2022 - 1 O=SwissSign AG -# Subject: CN=SwissSign RSA TLS Root CA 2022 - 1 O=SwissSign AG -# Label: "SwissSign RSA TLS Root CA 2022 - 1" -# Serial: 388078645722908516278762308316089881486363258315 -# MD5 Fingerprint: 16:2e:e4:19:76:81:85:ba:8e:91:58:f1:15:ef:72:39 -# SHA1 Fingerprint: 81:34:0a:be:4c:cd:ce:cc:e7:7d:cc:8a:d4:57:e2:45:a0:77:5d:ce -# SHA256 Fingerprint: 19:31:44:f4:31:e0:fd:db:74:07:17:d4:de:92:6a:57:11:33:88:4b:43:60:d3:0e:27:29:13:cb:e6:60:ce:41 ------BEGIN CERTIFICATE----- -MIIFkzCCA3ugAwIBAgIUQ/oMX04bgBhE79G0TzUfRPSA7cswDQYJKoZIhvcNAQEL -BQAwUTELMAkGA1UEBhMCQ0gxFTATBgNVBAoTDFN3aXNzU2lnbiBBRzErMCkGA1UE -AxMiU3dpc3NTaWduIFJTQSBUTFMgUm9vdCBDQSAyMDIyIC0gMTAeFw0yMjA2MDgx -MTA4MjJaFw00NzA2MDgxMTA4MjJaMFExCzAJBgNVBAYTAkNIMRUwEwYDVQQKEwxT -d2lzc1NpZ24gQUcxKzApBgNVBAMTIlN3aXNzU2lnbiBSU0EgVExTIFJvb3QgQ0Eg -MjAyMiAtIDEwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDLKmjiC8NX -vDVjvHClO/OMPE5Xlm7DTjak9gLKHqquuN6orx122ro10JFwB9+zBvKK8i5VUXu7 -LCTLf5ImgKO0lPaCoaTo+nUdWfMHamFk4saMla+ju45vVs9xzF6BYQ1t8qsCLqSX -5XH8irCRIFucdFJtrhUnWXjyCcplDn/L9Ovn3KlMd/YrFgSVrpxxpT8q2kFC5zyE -EPThPYxr4iuRR1VPuFa+Rd4iUU1OKNlfGUEGjw5NBuBwQCMBauTLE5tzrE0USJIt -/m2n+IdreXXhvhCxqohAWVTXz8TQm0SzOGlkjIHRI36qOTw7D59Ke4LKa2/KIj4x -0LDQKhySio/YGZxH5D4MucLNvkEM+KRHBdvBFzA4OmnczcNpI/2aDwLOEGrOyvi5 -KaM2iYauC8BPY7kGWUleDsFpswrzd34unYyzJ5jSmY0lpx+Gs6ZUcDj8fV3oT4MM -0ZPlEuRU2j7yrTrePjxF8CgPBrnh25d7mUWe3f6VWQQvdT/TromZhqwUtKiE+shd -OxtYk8EXlFXIC+OCeYSf8wCENO7cMdWP8vpPlkwGqnj73mSiI80fPsWMvDdUDrta -clXvyFu1cvh43zcgTFeRc5JzrBh3Q4IgaezprClG5QtO+DdziZaKHG29777YtvTK -wP1H8K4LWCDFyB02rpeNUIMmJCn3nTsPBQIDAQABo2MwYTAPBgNVHRMBAf8EBTAD -AQH/MA4GA1UdDwEB/wQEAwIBBjAfBgNVHSMEGDAWgBRvjmKLk0Ow4UD2p8P98Q+4 -DxU4pTAdBgNVHQ4EFgQUb45ii5NDsOFA9qfD/fEPuA8VOKUwDQYJKoZIhvcNAQEL -BQADggIBAKwsKUF9+lz1GpUYvyypiqkkVHX1uECry6gkUSsYP2OprphWKwVDIqO3 -10aewCoSPY6WlkDfDDOLazeROpW7OSltwAJsipQLBwJNGD77+3v1dj2b9l4wBlgz -Hqp41eZUBDqyggmNzhYzWUUo8aWjlw5DI/0LIICQ/+Mmz7hkkeUFjxOgdg3XNwwQ -iJb0Pr6VvfHDffCjw3lHC1ySFWPtUnWK50Zpy1FVCypM9fJkT6lc/2cyjlUtMoIc -gC9qkfjLvH4YoiaoLqNTKIftV+Vlek4ASltOU8liNr3CjlvrzG4ngRhZi0Rjn9UM -ZfQpZX+RLOV/fuiJz48gy20HQhFRJjKKLjpHE7iNvUcNCfAWpO2Whi4Z2L6MOuhF -LhG6rlrnub+xzI/goP+4s9GFe3lmozm1O2bYQL7Pt2eLSMkZJVX8vY3PXtpOpvJp -zv1/THfQwUY1mFwjmwJFQ5Ra3bxHrSL+ul4vkSkphnsh3m5kt8sNjzdbowhq6/Td -Ao9QAwKxuDdollDruF/UKIqlIgyKhPBZLtU30WHlQnNYKoH3dtvi4k0NX/a3vgW0 -rk4N3hY9A4GzJl5LuEsAz/+MF7psYC0nhzck5npgL7XTgwSqT0N1osGDsieYK7EO -gLrAhV5Cud+xYJHT6xh+cHiudoO+cVrQkOPKwRYlZ0rwtnu64ZzZ ------END CERTIFICATE----- - -# Issuer: CN=OISTE Server Root ECC G1 O=OISTE Foundation -# Subject: CN=OISTE Server Root ECC G1 O=OISTE Foundation -# Label: "OISTE Server Root ECC G1" -# Serial: 47819833811561661340092227008453318557 -# MD5 Fingerprint: 42:a7:d2:35:ae:02:92:db:19:76:08:de:2f:05:b4:d4 -# SHA1 Fingerprint: 3b:f6:8b:09:ae:2a:92:7b:ba:e3:8d:3f:11:95:d9:e6:44:0c:45:e2 -# SHA256 Fingerprint: ee:c9:97:c0:c3:0f:21:6f:7e:3b:8b:30:7d:2b:ae:42:41:2d:75:3f:c8:21:9d:af:d1:52:0b:25:72:85:0f:49 ------BEGIN CERTIFICATE----- -MIICNTCCAbqgAwIBAgIQI/nD1jWvjyhLH/BU6n6XnTAKBggqhkjOPQQDAzBLMQsw -CQYDVQQGEwJDSDEZMBcGA1UECgwQT0lTVEUgRm91bmRhdGlvbjEhMB8GA1UEAwwY -T0lTVEUgU2VydmVyIFJvb3QgRUNDIEcxMB4XDTIzMDUzMTE0NDIyOFoXDTQ4MDUy -NDE0NDIyN1owSzELMAkGA1UEBhMCQ0gxGTAXBgNVBAoMEE9JU1RFIEZvdW5kYXRp -b24xITAfBgNVBAMMGE9JU1RFIFNlcnZlciBSb290IEVDQyBHMTB2MBAGByqGSM49 -AgEGBSuBBAAiA2IABBcv+hK8rBjzCvRE1nZCnrPoH7d5qVi2+GXROiFPqOujvqQy -cvO2Ackr/XeFblPdreqqLiWStukhEaivtUwL85Zgmjvn6hp4LrQ95SjeHIC6XG4N -2xml4z+cKrhAS93mT6NjMGEwDwYDVR0TAQH/BAUwAwEB/zAfBgNVHSMEGDAWgBQ3 -TYhlz/w9itWj8UnATgwQb0K0nDAdBgNVHQ4EFgQUN02IZc/8PYrVo/FJwE4MEG9C -tJwwDgYDVR0PAQH/BAQDAgGGMAoGCCqGSM49BAMDA2kAMGYCMQCpKjAd0MKfkFFR -QD6VVCHNFmb3U2wIFjnQEnx/Yxvf4zgAOdktUyBFCxxgZzFDJe0CMQCSia7pXGKD -YmH5LVerVrkR3SW+ak5KGoJr3M/TvEqzPNcum9v4KGm8ay3sMaE641c= ------END CERTIFICATE----- - -# Issuer: CN=OISTE Server Root RSA G1 O=OISTE Foundation -# Subject: CN=OISTE Server Root RSA G1 O=OISTE Foundation -# Label: "OISTE Server Root RSA G1" -# Serial: 113845518112613905024960613408179309848 -# MD5 Fingerprint: 23:a7:9e:d4:70:b8:b9:14:57:41:8a:7e:44:59:e2:68 -# SHA1 Fingerprint: f7:00:34:25:94:88:68:31:e4:34:87:3f:70:fe:86:b3:86:9f:f0:6e -# SHA256 Fingerprint: 9a:e3:62:32:a5:18:9f:fd:db:35:3d:fd:26:52:0c:01:53:95:d2:27:77:da:c5:9d:b5:7b:98:c0:89:a6:51:e6 ------BEGIN CERTIFICATE----- -MIIFgzCCA2ugAwIBAgIQVaXZZ5Qoxu0M+ifdWwFNGDANBgkqhkiG9w0BAQwFADBL -MQswCQYDVQQGEwJDSDEZMBcGA1UECgwQT0lTVEUgRm91bmRhdGlvbjEhMB8GA1UE -AwwYT0lTVEUgU2VydmVyIFJvb3QgUlNBIEcxMB4XDTIzMDUzMTE0MzcxNloXDTQ4 -MDUyNDE0MzcxNVowSzELMAkGA1UEBhMCQ0gxGTAXBgNVBAoMEE9JU1RFIEZvdW5k -YXRpb24xITAfBgNVBAMMGE9JU1RFIFNlcnZlciBSb290IFJTQSBHMTCCAiIwDQYJ -KoZIhvcNAQEBBQADggIPADCCAgoCggIBAKqu9KuCz/vlNwvn1ZatkOhLKdxVYOPM -vLO8LZK55KN68YG0nnJyQ98/qwsmtO57Gmn7KNByXEptaZnwYx4M0rH/1ow00O7b -rEi56rAUjtgHqSSY3ekJvqgiG1k50SeH3BzN+Puz6+mTeO0Pzjd8JnduodgsIUzk -ik/HEzxux9UTl7Ko2yRpg1bTacuCErudG/L4NPKYKyqOBGf244ehHa1uzjZ0Dl4z -O8vbUZeUapU8zhhabkvG/AePLhq5SvdkNCncpo1Q4Y2LS+VIG24ugBA/5J8bZT8R -tOpXaZ+0AOuFJJkk9SGdl6r7NH8CaxWQrbueWhl/pIzY+m0o/DjH40ytas7ZTpOS -jswMZ78LS5bOZmdTaMsXEY5Z96ycG7mOaES3GK/m5Q9l3JUJsJMStR8+lKXHiHUh -sd4JJCpM4rzsTGdHwimIuQq6+cF0zowYJmXa92/GjHtoXAvuY8BeS/FOzJ8vD+Ho -mnqT8eDI278n5mUpezbgMxVz8p1rhAhoKzYHKyfMeNhqhw5HdPSqoBNdZH702xSu -+zrkL8Fl47l6QGzwBrd7KJvX4V84c5Ss2XCTLdyEr0YconosP4EmQufU2MVshGYR -i3drVByjtdgQ8K4p92cIiBdcuJd5z+orKu5YM+Vt6SmqZQENghPsJQtdLEByFSnT -kCz3GkPVavBpAgMBAAGjYzBhMA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAU -8snBDw1jALvsRQ5KH7WxszbNDo0wHQYDVR0OBBYEFPLJwQ8NYwC77EUOSh+1sbM2 -zQ6NMA4GA1UdDwEB/wQEAwIBhjANBgkqhkiG9w0BAQwFAAOCAgEANGd5sjrG5T33 -I3K5Ce+SrScfoE4KsvXaFwyihdJ+klH9FWXXXGtkFu6KRcoMQzZENdl//nk6HOjG -5D1rd9QhEOP28yBOqb6J8xycqd+8MDoX0TJD0KqKchxRKEzdNsjkLWd9kYccnbz8 -qyiWXmFcuCIzGEgWUOrKL+mlSdx/PKQZvDatkuK59EvV6wit53j+F8Bdh3foZ3dP -AGav9LEDOr4SfEE15fSmG0eLy3n31r8Xbk5l8PjaV8GUgeV6Vg27Rn9vkf195hfk -gSe7BYhW3SCl95gtkRlpMV+bMPKZrXJAlszYd2abtNUOshD+FKrDgHGdPY3ofRRs -YWSGRqbXVMW215AWRqWFyp464+YTFrYVI8ypKVL9AMb2kI5Wj4kI3Zaq5tNqqYY1 -9tVFeEJKRvwDyF7YZvZFZSS0vod7VSCd9521Kvy5YhnLbDuv0204bKt7ph6N/Ome -/msVuduCmsuY33OhkKCgxeDoAaijFJzIwZqsFVAzje18KotzlUBDJvyBpCpfOZC3 -J8tRd/iWkx7P8nd9H0aTolkelUTFLXVksNb54Dxp6gS1HAviRkRNQzuXSXERvSS2 -wq1yVAb+axj5d9spLFKebXd7Yv0PTY6YMjAwcRLWJTXjn/hvnLXrahut6hDTlhZy -BiElxky8j3C7DOReIoMt0r7+hVu05L0= ------END CERTIFICATE----- - -# Issuer: CN=e-Szigno TLS Root CA 2023 O=Microsec Ltd. -# Subject: CN=e-Szigno TLS Root CA 2023 O=Microsec Ltd. -# Label: "e-Szigno TLS Root CA 2023" -# Serial: 71934828665710877219916191754 -# MD5 Fingerprint: 6a:e9:99:74:a5:da:5e:f1:d9:2e:f2:c8:d1:86:8b:71 -# SHA1 Fingerprint: 6f:9a:d5:d5:df:e8:2c:eb:be:37:07:ee:4f:4f:52:58:29:41:d1:fe -# SHA256 Fingerprint: b4:91:41:50:2d:00:66:3d:74:0f:2e:7e:c3:40:c5:28:00:96:26:66:12:1a:36:d0:9c:f7:dd:2b:90:38:4f:b4 ------BEGIN CERTIFICATE----- -MIICzzCCAjGgAwIBAgINAOhvGHvWOWuYSkmYCjAKBggqhkjOPQQDBDB1MQswCQYD -VQQGEwJIVTERMA8GA1UEBwwIQnVkYXBlc3QxFjAUBgNVBAoMDU1pY3Jvc2VjIEx0 -ZC4xFzAVBgNVBGEMDlZBVEhVLTIzNTg0NDk3MSIwIAYDVQQDDBllLVN6aWdubyBU -TFMgUm9vdCBDQSAyMDIzMB4XDTIzMDcxNzE0MDAwMFoXDTM4MDcxNzE0MDAwMFow -dTELMAkGA1UEBhMCSFUxETAPBgNVBAcMCEJ1ZGFwZXN0MRYwFAYDVQQKDA1NaWNy -b3NlYyBMdGQuMRcwFQYDVQRhDA5WQVRIVS0yMzU4NDQ5NzEiMCAGA1UEAwwZZS1T -emlnbm8gVExTIFJvb3QgQ0EgMjAyMzCBmzAQBgcqhkjOPQIBBgUrgQQAIwOBhgAE -AGgP36J8PKp0iGEKjcJMpQEiFNT3YHdCnAo4YKGMZz6zY+n6kbCLS+Y53wLCMAFS -AL/fjO1ZrTJlqwlZULUZwmgcAOAFX9pQJhzDrAQixTpN7+lXWDajwRlTEArRzT/v -SzUaQ49CE0y5LBqcvjC2xN7cS53kpDzLLtmt3999Cd8ukv+ho2MwYTAPBgNVHRMB -Af8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUWYQCYlpGePVd3I8K -ECgj3NXW+0UwHwYDVR0jBBgwFoAUWYQCYlpGePVd3I8KECgj3NXW+0UwCgYIKoZI -zj0EAwQDgYsAMIGHAkIBLdqu9S54tma4n7Zwf2Z0z+yOfP7AAXmazlIC58PRDHpt -y7Ve7hekm9sEdu4pKeiv+62sUvTXK9Z3hBC9xdIoaDQCQTV2WnXzkoYI9bIeCvZl -C9p2x1L/Cx6AcCIwwzPbGO2E14vs7dOoY4G1VnxHx1YwlGhza9IuqbnZLBwpvQy6 -uWWL ------END CERTIFICATE----- diff --git a/venv/lib/python3.9/site-packages/certifi/core.py b/venv/lib/python3.9/site-packages/certifi/core.py deleted file mode 100644 index 1c9661c..0000000 --- a/venv/lib/python3.9/site-packages/certifi/core.py +++ /dev/null @@ -1,83 +0,0 @@ -""" -certifi.py -~~~~~~~~~~ - -This module returns the installation location of cacert.pem or its contents. -""" -import sys -import atexit - -def exit_cacert_ctx() -> None: - _CACERT_CTX.__exit__(None, None, None) # type: ignore[union-attr] - - -if sys.version_info >= (3, 11): - - from importlib.resources import as_file, files - - _CACERT_CTX = None - _CACERT_PATH = None - - def where() -> str: - # This is slightly terrible, but we want to delay extracting the file - # in cases where we're inside of a zipimport situation until someone - # actually calls where(), but we don't want to re-extract the file - # on every call of where(), so we'll do it once then store it in a - # global variable. - global _CACERT_CTX - global _CACERT_PATH - if _CACERT_PATH is None: - # This is slightly janky, the importlib.resources API wants you to - # manage the cleanup of this file, so it doesn't actually return a - # path, it returns a context manager that will give you the path - # when you enter it and will do any cleanup when you leave it. In - # the common case of not needing a temporary file, it will just - # return the file system location and the __exit__() is a no-op. - # - # We also have to hold onto the actual context manager, because - # it will do the cleanup whenever it gets garbage collected, so - # we will also store that at the global level as well. - _CACERT_CTX = as_file(files("certifi").joinpath("cacert.pem")) - _CACERT_PATH = str(_CACERT_CTX.__enter__()) - atexit.register(exit_cacert_ctx) - - return _CACERT_PATH - - def contents() -> str: - return files("certifi").joinpath("cacert.pem").read_text(encoding="ascii") - -else: - - from importlib.resources import path as get_path, read_text - - _CACERT_CTX = None - _CACERT_PATH = None - - def where() -> str: - # This is slightly terrible, but we want to delay extracting the - # file in cases where we're inside of a zipimport situation until - # someone actually calls where(), but we don't want to re-extract - # the file on every call of where(), so we'll do it once then store - # it in a global variable. - global _CACERT_CTX - global _CACERT_PATH - if _CACERT_PATH is None: - # This is slightly janky, the importlib.resources API wants you - # to manage the cleanup of this file, so it doesn't actually - # return a path, it returns a context manager that will give - # you the path when you enter it and will do any cleanup when - # you leave it. In the common case of not needing a temporary - # file, it will just return the file system location and the - # __exit__() is a no-op. - # - # We also have to hold onto the actual context manager, because - # it will do the cleanup whenever it gets garbage collected, so - # we will also store that at the global level as well. - _CACERT_CTX = get_path("certifi", "cacert.pem") - _CACERT_PATH = str(_CACERT_CTX.__enter__()) - atexit.register(exit_cacert_ctx) - - return _CACERT_PATH - - def contents() -> str: - return read_text("certifi", "cacert.pem", encoding="ascii") diff --git a/venv/lib/python3.9/site-packages/certifi/py.typed b/venv/lib/python3.9/site-packages/certifi/py.typed deleted file mode 100644 index e69de29..0000000 diff --git a/venv/lib/python3.9/site-packages/cffi-2.0.0.dist-info/INSTALLER b/venv/lib/python3.9/site-packages/cffi-2.0.0.dist-info/INSTALLER deleted file mode 100644 index a1b589e..0000000 --- a/venv/lib/python3.9/site-packages/cffi-2.0.0.dist-info/INSTALLER +++ /dev/null @@ -1 +0,0 @@ -pip diff --git a/venv/lib/python3.9/site-packages/cffi-2.0.0.dist-info/METADATA b/venv/lib/python3.9/site-packages/cffi-2.0.0.dist-info/METADATA deleted file mode 100644 index 67508e5..0000000 --- a/venv/lib/python3.9/site-packages/cffi-2.0.0.dist-info/METADATA +++ /dev/null @@ -1,68 +0,0 @@ -Metadata-Version: 2.4 -Name: cffi -Version: 2.0.0 -Summary: Foreign Function Interface for Python calling C code. -Author: Armin Rigo, Maciej Fijalkowski -Maintainer: Matt Davis, Matt Clay, Matti Picus -License-Expression: MIT -Project-URL: Documentation, https://cffi.readthedocs.io/ -Project-URL: Changelog, https://cffi.readthedocs.io/en/latest/whatsnew.html -Project-URL: Downloads, https://github.com/python-cffi/cffi/releases -Project-URL: Contact, https://groups.google.com/forum/#!forum/python-cffi -Project-URL: Source Code, https://github.com/python-cffi/cffi -Project-URL: Issue Tracker, https://github.com/python-cffi/cffi/issues -Classifier: Programming Language :: Python -Classifier: Programming Language :: Python :: 3 -Classifier: Programming Language :: Python :: 3.9 -Classifier: Programming Language :: Python :: 3.10 -Classifier: Programming Language :: Python :: 3.11 -Classifier: Programming Language :: Python :: 3.12 -Classifier: Programming Language :: Python :: 3.13 -Classifier: Programming Language :: Python :: 3.14 -Classifier: Programming Language :: Python :: Free Threading :: 2 - Beta -Classifier: Programming Language :: Python :: Implementation :: CPython -Requires-Python: >=3.9 -Description-Content-Type: text/markdown -License-File: LICENSE -License-File: AUTHORS -Requires-Dist: pycparser; implementation_name != "PyPy" -Dynamic: license-file - -[![GitHub Actions Status](https://github.com/python-cffi/cffi/actions/workflows/ci.yaml/badge.svg?branch=main)](https://github.com/python-cffi/cffi/actions/workflows/ci.yaml?query=branch%3Amain++) -[![PyPI version](https://img.shields.io/pypi/v/cffi.svg)](https://pypi.org/project/cffi) -[![Read the Docs](https://img.shields.io/badge/docs-latest-blue.svg)][Documentation] - - -CFFI -==== - -Foreign Function Interface for Python calling C code. - -Please see the [Documentation] or uncompiled in the `doc/` subdirectory. - -Download --------- - -[Download page](https://github.com/python-cffi/cffi/releases) - -Source Code ------------ - -Source code is publicly available on -[GitHub](https://github.com/python-cffi/cffi). - -Contact -------- - -[Mailing list](https://groups.google.com/forum/#!forum/python-cffi) - -Testing/development tips ------------------------- - -After `git clone` or `wget && tar`, we will get a directory called `cffi` or `cffi-x.x.x`. we call it `repo-directory`. To run tests under CPython, run the following in the `repo-directory`: - - pip install pytest - pip install -e . # editable install of CFFI for local development - pytest src/c/ testing/ - -[Documentation]: http://cffi.readthedocs.org/ diff --git a/venv/lib/python3.9/site-packages/cffi-2.0.0.dist-info/RECORD b/venv/lib/python3.9/site-packages/cffi-2.0.0.dist-info/RECORD deleted file mode 100644 index 25e5445..0000000 --- a/venv/lib/python3.9/site-packages/cffi-2.0.0.dist-info/RECORD +++ /dev/null @@ -1,49 +0,0 @@ -_cffi_backend.cpython-39-x86_64-linux-gnu.so,sha256=9J_Iuv_0UXORJQsmFFKfZwHTQDTC313tRixPBAunqCU,339784 -cffi-2.0.0.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 -cffi-2.0.0.dist-info/METADATA,sha256=uYzn40F68Im8EtXHNBLZs7FoPM-OxzyYbDWsjJvhujk,2559 -cffi-2.0.0.dist-info/RECORD,, -cffi-2.0.0.dist-info/WHEEL,sha256=A4SdjgbIBZ_kjTsEuOcR8fCpVKV5dez8wjeT_kpjoQs,147 -cffi-2.0.0.dist-info/entry_points.txt,sha256=y6jTxnyeuLnL-XJcDv8uML3n6wyYiGRg8MTp_QGJ9Ho,75 -cffi-2.0.0.dist-info/licenses/AUTHORS,sha256=KmemC7-zN1nWfWRf8TG45ta8TK_CMtdR_Kw-2k0xTMg,208 -cffi-2.0.0.dist-info/licenses/LICENSE,sha256=W6JN3FcGf5JJrdZEw6_EGl1tw34jQz73Wdld83Cwr2M,1123 -cffi-2.0.0.dist-info/top_level.txt,sha256=rE7WR3rZfNKxWI9-jn6hsHCAl7MDkB-FmuQbxWjFehQ,19 -cffi/__init__.py,sha256=-ksBQ7MfDzVvbBlV_ftYBWAmEqfA86ljIzMxzaZeAlI,511 -cffi/__pycache__/__init__.cpython-39.pyc,, -cffi/__pycache__/_imp_emulation.cpython-39.pyc,, -cffi/__pycache__/_shimmed_dist_utils.cpython-39.pyc,, -cffi/__pycache__/api.cpython-39.pyc,, -cffi/__pycache__/backend_ctypes.cpython-39.pyc,, -cffi/__pycache__/cffi_opcode.cpython-39.pyc,, -cffi/__pycache__/commontypes.cpython-39.pyc,, -cffi/__pycache__/cparser.cpython-39.pyc,, -cffi/__pycache__/error.cpython-39.pyc,, -cffi/__pycache__/ffiplatform.cpython-39.pyc,, -cffi/__pycache__/lock.cpython-39.pyc,, -cffi/__pycache__/model.cpython-39.pyc,, -cffi/__pycache__/pkgconfig.cpython-39.pyc,, -cffi/__pycache__/recompiler.cpython-39.pyc,, -cffi/__pycache__/setuptools_ext.cpython-39.pyc,, -cffi/__pycache__/vengine_cpy.cpython-39.pyc,, -cffi/__pycache__/vengine_gen.cpython-39.pyc,, -cffi/__pycache__/verifier.cpython-39.pyc,, -cffi/_cffi_errors.h,sha256=zQXt7uR_m8gUW-fI2hJg0KoSkJFwXv8RGUkEDZ177dQ,3908 -cffi/_cffi_include.h,sha256=Exhmgm9qzHWzWivjfTe0D7Xp4rPUkVxdNuwGhMTMzbw,15055 -cffi/_embedding.h,sha256=Ai33FHblE7XSpHOCp8kPcWwN5_9BV14OvN0JVa6ITpw,18786 -cffi/_imp_emulation.py,sha256=RxREG8zAbI2RPGBww90u_5fi8sWdahpdipOoPzkp7C0,2960 -cffi/_shimmed_dist_utils.py,sha256=Bjj2wm8yZbvFvWEx5AEfmqaqZyZFhYfoyLLQHkXZuao,2230 -cffi/api.py,sha256=alBv6hZQkjpmZplBphdaRn2lPO9-CORs_M7ixabvZWI,42169 -cffi/backend_ctypes.py,sha256=h5ZIzLc6BFVXnGyc9xPqZWUS7qGy7yFSDqXe68Sa8z4,42454 -cffi/cffi_opcode.py,sha256=JDV5l0R0_OadBX_uE7xPPTYtMdmpp8I9UYd6av7aiDU,5731 -cffi/commontypes.py,sha256=7N6zPtCFlvxXMWhHV08psUjdYIK2XgsN3yo5dgua_v4,2805 -cffi/cparser.py,sha256=QUTfmlL-aO-MYR8bFGlvAUHc36OQr7XYLe0WLkGFjRo,44790 -cffi/error.py,sha256=v6xTiS4U0kvDcy4h_BDRo5v39ZQuj-IMRYLv5ETddZs,877 -cffi/ffiplatform.py,sha256=avxFjdikYGJoEtmJO7ewVmwG_VEVl6EZ_WaNhZYCqv4,3584 -cffi/lock.py,sha256=l9TTdwMIMpi6jDkJGnQgE9cvTIR7CAntIJr8EGHt3pY,747 -cffi/model.py,sha256=W30UFQZE73jL5Mx5N81YT77us2W2iJjTm0XYfnwz1cg,21797 -cffi/parse_c_type.h,sha256=OdwQfwM9ktq6vlCB43exFQmxDBtj2MBNdK8LYl15tjw,5976 -cffi/pkgconfig.py,sha256=LP1w7vmWvmKwyqLaU1Z243FOWGNQMrgMUZrvgFuOlco,4374 -cffi/recompiler.py,sha256=78J6lMEEOygXNmjN9-fOFFO3j7eW-iFxSrxfvQb54bY,65509 -cffi/setuptools_ext.py,sha256=0rCwBJ1W7FHWtiMKfNXsSST88V8UXrui5oeXFlDNLG8,9411 -cffi/vengine_cpy.py,sha256=oyQKD23kpE0aChUKA8Jg0e723foPiYzLYEdb-J0MiNs,43881 -cffi/vengine_gen.py,sha256=DUlEIrDiVin1Pnhn1sfoamnS5NLqfJcOdhRoeSNeJRg,26939 -cffi/verifier.py,sha256=oX8jpaohg2Qm3aHcznidAdvrVm5N4sQYG0a3Eo5mIl4,11182 diff --git a/venv/lib/python3.9/site-packages/cffi-2.0.0.dist-info/WHEEL b/venv/lib/python3.9/site-packages/cffi-2.0.0.dist-info/WHEEL deleted file mode 100644 index fb8eff6..0000000 --- a/venv/lib/python3.9/site-packages/cffi-2.0.0.dist-info/WHEEL +++ /dev/null @@ -1,6 +0,0 @@ -Wheel-Version: 1.0 -Generator: setuptools (80.9.0) -Root-Is-Purelib: false -Tag: cp39-cp39-manylinux_2_17_x86_64 -Tag: cp39-cp39-manylinux2014_x86_64 - diff --git a/venv/lib/python3.9/site-packages/cffi-2.0.0.dist-info/entry_points.txt b/venv/lib/python3.9/site-packages/cffi-2.0.0.dist-info/entry_points.txt deleted file mode 100644 index 4b0274f..0000000 --- a/venv/lib/python3.9/site-packages/cffi-2.0.0.dist-info/entry_points.txt +++ /dev/null @@ -1,2 +0,0 @@ -[distutils.setup_keywords] -cffi_modules = cffi.setuptools_ext:cffi_modules diff --git a/venv/lib/python3.9/site-packages/cffi-2.0.0.dist-info/licenses/AUTHORS b/venv/lib/python3.9/site-packages/cffi-2.0.0.dist-info/licenses/AUTHORS deleted file mode 100644 index 370a25d..0000000 --- a/venv/lib/python3.9/site-packages/cffi-2.0.0.dist-info/licenses/AUTHORS +++ /dev/null @@ -1,8 +0,0 @@ -This package has been mostly done by Armin Rigo with help from -Maciej Fijałkowski. The idea is heavily based (although not directly -copied) from LuaJIT ffi by Mike Pall. - - -Other contributors: - - Google Inc. diff --git a/venv/lib/python3.9/site-packages/cffi-2.0.0.dist-info/licenses/LICENSE b/venv/lib/python3.9/site-packages/cffi-2.0.0.dist-info/licenses/LICENSE deleted file mode 100644 index 0a1dbfb..0000000 --- a/venv/lib/python3.9/site-packages/cffi-2.0.0.dist-info/licenses/LICENSE +++ /dev/null @@ -1,23 +0,0 @@ - -Except when otherwise stated (look for LICENSE files in directories or -information at the beginning of each file) all software and -documentation is licensed as follows: - - MIT No Attribution - - Permission is hereby granted, free of charge, to any person - obtaining a copy of this software and associated documentation - files (the "Software"), to deal in the Software without - restriction, including without limitation the rights to use, - copy, modify, merge, publish, distribute, sublicense, and/or - sell copies of the Software, and to permit persons to whom the - Software is furnished to do so. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - DEALINGS IN THE SOFTWARE. - diff --git a/venv/lib/python3.9/site-packages/cffi-2.0.0.dist-info/top_level.txt b/venv/lib/python3.9/site-packages/cffi-2.0.0.dist-info/top_level.txt deleted file mode 100644 index f645779..0000000 --- a/venv/lib/python3.9/site-packages/cffi-2.0.0.dist-info/top_level.txt +++ /dev/null @@ -1,2 +0,0 @@ -_cffi_backend -cffi diff --git a/venv/lib/python3.9/site-packages/cffi/__init__.py b/venv/lib/python3.9/site-packages/cffi/__init__.py deleted file mode 100644 index c99ec3d..0000000 --- a/venv/lib/python3.9/site-packages/cffi/__init__.py +++ /dev/null @@ -1,14 +0,0 @@ -__all__ = ['FFI', 'VerificationError', 'VerificationMissing', 'CDefError', - 'FFIError'] - -from .api import FFI -from .error import CDefError, FFIError, VerificationError, VerificationMissing -from .error import PkgConfigError - -__version__ = "2.0.0" -__version_info__ = (2, 0, 0) - -# The verifier module file names are based on the CRC32 of a string that -# contains the following version number. It may be older than __version__ -# if nothing is clearly incompatible. -__version_verifier_modules__ = "0.8.6" diff --git a/venv/lib/python3.9/site-packages/cffi/_cffi_errors.h b/venv/lib/python3.9/site-packages/cffi/_cffi_errors.h deleted file mode 100644 index 158e059..0000000 --- a/venv/lib/python3.9/site-packages/cffi/_cffi_errors.h +++ /dev/null @@ -1,149 +0,0 @@ -#ifndef CFFI_MESSAGEBOX -# ifdef _MSC_VER -# define CFFI_MESSAGEBOX 1 -# else -# define CFFI_MESSAGEBOX 0 -# endif -#endif - - -#if CFFI_MESSAGEBOX -/* Windows only: logic to take the Python-CFFI embedding logic - initialization errors and display them in a background thread - with MessageBox. The idea is that if the whole program closes - as a result of this problem, then likely it is already a console - program and you can read the stderr output in the console too. - If it is not a console program, then it will likely show its own - dialog to complain, or generally not abruptly close, and for this - case the background thread should stay alive. -*/ -static void *volatile _cffi_bootstrap_text; - -static PyObject *_cffi_start_error_capture(void) -{ - PyObject *result = NULL; - PyObject *x, *m, *bi; - - if (InterlockedCompareExchangePointer(&_cffi_bootstrap_text, - (void *)1, NULL) != NULL) - return (PyObject *)1; - - m = PyImport_AddModule("_cffi_error_capture"); - if (m == NULL) - goto error; - - result = PyModule_GetDict(m); - if (result == NULL) - goto error; - -#if PY_MAJOR_VERSION >= 3 - bi = PyImport_ImportModule("builtins"); -#else - bi = PyImport_ImportModule("__builtin__"); -#endif - if (bi == NULL) - goto error; - PyDict_SetItemString(result, "__builtins__", bi); - Py_DECREF(bi); - - x = PyRun_String( - "import sys\n" - "class FileLike:\n" - " def write(self, x):\n" - " try:\n" - " of.write(x)\n" - " except: pass\n" - " self.buf += x\n" - " def flush(self):\n" - " pass\n" - "fl = FileLike()\n" - "fl.buf = ''\n" - "of = sys.stderr\n" - "sys.stderr = fl\n" - "def done():\n" - " sys.stderr = of\n" - " return fl.buf\n", /* make sure the returned value stays alive */ - Py_file_input, - result, result); - Py_XDECREF(x); - - error: - if (PyErr_Occurred()) - { - PyErr_WriteUnraisable(Py_None); - PyErr_Clear(); - } - return result; -} - -#pragma comment(lib, "user32.lib") - -static DWORD WINAPI _cffi_bootstrap_dialog(LPVOID ignored) -{ - Sleep(666); /* may be interrupted if the whole process is closing */ -#if PY_MAJOR_VERSION >= 3 - MessageBoxW(NULL, (wchar_t *)_cffi_bootstrap_text, - L"Python-CFFI error", - MB_OK | MB_ICONERROR); -#else - MessageBoxA(NULL, (char *)_cffi_bootstrap_text, - "Python-CFFI error", - MB_OK | MB_ICONERROR); -#endif - _cffi_bootstrap_text = NULL; - return 0; -} - -static void _cffi_stop_error_capture(PyObject *ecap) -{ - PyObject *s; - void *text; - - if (ecap == (PyObject *)1) - return; - - if (ecap == NULL) - goto error; - - s = PyRun_String("done()", Py_eval_input, ecap, ecap); - if (s == NULL) - goto error; - - /* Show a dialog box, but in a background thread, and - never show multiple dialog boxes at once. */ -#if PY_MAJOR_VERSION >= 3 - text = PyUnicode_AsWideCharString(s, NULL); -#else - text = PyString_AsString(s); -#endif - - _cffi_bootstrap_text = text; - - if (text != NULL) - { - HANDLE h; - h = CreateThread(NULL, 0, _cffi_bootstrap_dialog, - NULL, 0, NULL); - if (h != NULL) - CloseHandle(h); - } - /* decref the string, but it should stay alive as 'fl.buf' - in the small module above. It will really be freed only if - we later get another similar error. So it's a leak of at - most one copy of the small module. That's fine for this - situation which is usually a "fatal error" anyway. */ - Py_DECREF(s); - PyErr_Clear(); - return; - - error: - _cffi_bootstrap_text = NULL; - PyErr_Clear(); -} - -#else - -static PyObject *_cffi_start_error_capture(void) { return NULL; } -static void _cffi_stop_error_capture(PyObject *ecap) { } - -#endif diff --git a/venv/lib/python3.9/site-packages/cffi/_cffi_include.h b/venv/lib/python3.9/site-packages/cffi/_cffi_include.h deleted file mode 100644 index 908a1d7..0000000 --- a/venv/lib/python3.9/site-packages/cffi/_cffi_include.h +++ /dev/null @@ -1,389 +0,0 @@ -#define _CFFI_ - -/* We try to define Py_LIMITED_API before including Python.h. - - Mess: we can only define it if Py_DEBUG, Py_TRACE_REFS and - Py_REF_DEBUG are not defined. This is a best-effort approximation: - we can learn about Py_DEBUG from pyconfig.h, but it is unclear if - the same works for the other two macros. Py_DEBUG implies them, - but not the other way around. - - The implementation is messy (issue #350): on Windows, with _MSC_VER, - we have to define Py_LIMITED_API even before including pyconfig.h. - In that case, we guess what pyconfig.h will do to the macros above, - and check our guess after the #include. - - Note that on Windows, with CPython 3.x, you need >= 3.5 and virtualenv - version >= 16.0.0. With older versions of either, you don't get a - copy of PYTHON3.DLL in the virtualenv. We can't check the version of - CPython *before* we even include pyconfig.h. ffi.set_source() puts - a ``#define _CFFI_NO_LIMITED_API'' at the start of this file if it is - running on Windows < 3.5, as an attempt at fixing it, but that's - arguably wrong because it may not be the target version of Python. - Still better than nothing I guess. As another workaround, you can - remove the definition of Py_LIMITED_API here. - - See also 'py_limited_api' in cffi/setuptools_ext.py. -*/ -#if !defined(_CFFI_USE_EMBEDDING) && !defined(Py_LIMITED_API) -# ifdef _MSC_VER -# if !defined(_DEBUG) && !defined(Py_DEBUG) && !defined(Py_TRACE_REFS) && !defined(Py_REF_DEBUG) && !defined(_CFFI_NO_LIMITED_API) -# define Py_LIMITED_API -# endif -# include - /* sanity-check: Py_LIMITED_API will cause crashes if any of these - are also defined. Normally, the Python file PC/pyconfig.h does not - cause any of these to be defined, with the exception that _DEBUG - causes Py_DEBUG. Double-check that. */ -# ifdef Py_LIMITED_API -# if defined(Py_DEBUG) -# error "pyconfig.h unexpectedly defines Py_DEBUG, but Py_LIMITED_API is set" -# endif -# if defined(Py_TRACE_REFS) -# error "pyconfig.h unexpectedly defines Py_TRACE_REFS, but Py_LIMITED_API is set" -# endif -# if defined(Py_REF_DEBUG) -# error "pyconfig.h unexpectedly defines Py_REF_DEBUG, but Py_LIMITED_API is set" -# endif -# endif -# else -# include -# if !defined(Py_DEBUG) && !defined(Py_TRACE_REFS) && !defined(Py_REF_DEBUG) && !defined(_CFFI_NO_LIMITED_API) -# define Py_LIMITED_API -# endif -# endif -#endif - -#include -#ifdef __cplusplus -extern "C" { -#endif -#include -#include "parse_c_type.h" - -/* this block of #ifs should be kept exactly identical between - c/_cffi_backend.c, cffi/vengine_cpy.py, cffi/vengine_gen.py - and cffi/_cffi_include.h */ -#if defined(_MSC_VER) -# include /* for alloca() */ -# if _MSC_VER < 1600 /* MSVC < 2010 */ - typedef __int8 int8_t; - typedef __int16 int16_t; - typedef __int32 int32_t; - typedef __int64 int64_t; - typedef unsigned __int8 uint8_t; - typedef unsigned __int16 uint16_t; - typedef unsigned __int32 uint32_t; - typedef unsigned __int64 uint64_t; - typedef __int8 int_least8_t; - typedef __int16 int_least16_t; - typedef __int32 int_least32_t; - typedef __int64 int_least64_t; - typedef unsigned __int8 uint_least8_t; - typedef unsigned __int16 uint_least16_t; - typedef unsigned __int32 uint_least32_t; - typedef unsigned __int64 uint_least64_t; - typedef __int8 int_fast8_t; - typedef __int16 int_fast16_t; - typedef __int32 int_fast32_t; - typedef __int64 int_fast64_t; - typedef unsigned __int8 uint_fast8_t; - typedef unsigned __int16 uint_fast16_t; - typedef unsigned __int32 uint_fast32_t; - typedef unsigned __int64 uint_fast64_t; - typedef __int64 intmax_t; - typedef unsigned __int64 uintmax_t; -# else -# include -# endif -# if _MSC_VER < 1800 /* MSVC < 2013 */ -# ifndef __cplusplus - typedef unsigned char _Bool; -# endif -# endif -# define _cffi_float_complex_t _Fcomplex /* include for it */ -# define _cffi_double_complex_t _Dcomplex /* include for it */ -#else -# include -# if (defined (__SVR4) && defined (__sun)) || defined(_AIX) || defined(__hpux) -# include -# endif -# define _cffi_float_complex_t float _Complex -# define _cffi_double_complex_t double _Complex -#endif - -#ifdef __GNUC__ -# define _CFFI_UNUSED_FN __attribute__((unused)) -#else -# define _CFFI_UNUSED_FN /* nothing */ -#endif - -#ifdef __cplusplus -# ifndef _Bool - typedef bool _Bool; /* semi-hackish: C++ has no _Bool; bool is builtin */ -# endif -#endif - -/********** CPython-specific section **********/ -#ifndef PYPY_VERSION - - -#if PY_MAJOR_VERSION >= 3 -# define PyInt_FromLong PyLong_FromLong -#endif - -#define _cffi_from_c_double PyFloat_FromDouble -#define _cffi_from_c_float PyFloat_FromDouble -#define _cffi_from_c_long PyInt_FromLong -#define _cffi_from_c_ulong PyLong_FromUnsignedLong -#define _cffi_from_c_longlong PyLong_FromLongLong -#define _cffi_from_c_ulonglong PyLong_FromUnsignedLongLong -#define _cffi_from_c__Bool PyBool_FromLong - -#define _cffi_to_c_double PyFloat_AsDouble -#define _cffi_to_c_float PyFloat_AsDouble - -#define _cffi_from_c_int(x, type) \ - (((type)-1) > 0 ? /* unsigned */ \ - (sizeof(type) < sizeof(long) ? \ - PyInt_FromLong((long)x) : \ - sizeof(type) == sizeof(long) ? \ - PyLong_FromUnsignedLong((unsigned long)x) : \ - PyLong_FromUnsignedLongLong((unsigned long long)x)) : \ - (sizeof(type) <= sizeof(long) ? \ - PyInt_FromLong((long)x) : \ - PyLong_FromLongLong((long long)x))) - -#define _cffi_to_c_int(o, type) \ - ((type)( \ - sizeof(type) == 1 ? (((type)-1) > 0 ? (type)_cffi_to_c_u8(o) \ - : (type)_cffi_to_c_i8(o)) : \ - sizeof(type) == 2 ? (((type)-1) > 0 ? (type)_cffi_to_c_u16(o) \ - : (type)_cffi_to_c_i16(o)) : \ - sizeof(type) == 4 ? (((type)-1) > 0 ? (type)_cffi_to_c_u32(o) \ - : (type)_cffi_to_c_i32(o)) : \ - sizeof(type) == 8 ? (((type)-1) > 0 ? (type)_cffi_to_c_u64(o) \ - : (type)_cffi_to_c_i64(o)) : \ - (Py_FatalError("unsupported size for type " #type), (type)0))) - -#define _cffi_to_c_i8 \ - ((int(*)(PyObject *))_cffi_exports[1]) -#define _cffi_to_c_u8 \ - ((int(*)(PyObject *))_cffi_exports[2]) -#define _cffi_to_c_i16 \ - ((int(*)(PyObject *))_cffi_exports[3]) -#define _cffi_to_c_u16 \ - ((int(*)(PyObject *))_cffi_exports[4]) -#define _cffi_to_c_i32 \ - ((int(*)(PyObject *))_cffi_exports[5]) -#define _cffi_to_c_u32 \ - ((unsigned int(*)(PyObject *))_cffi_exports[6]) -#define _cffi_to_c_i64 \ - ((long long(*)(PyObject *))_cffi_exports[7]) -#define _cffi_to_c_u64 \ - ((unsigned long long(*)(PyObject *))_cffi_exports[8]) -#define _cffi_to_c_char \ - ((int(*)(PyObject *))_cffi_exports[9]) -#define _cffi_from_c_pointer \ - ((PyObject *(*)(char *, struct _cffi_ctypedescr *))_cffi_exports[10]) -#define _cffi_to_c_pointer \ - ((char *(*)(PyObject *, struct _cffi_ctypedescr *))_cffi_exports[11]) -#define _cffi_get_struct_layout \ - not used any more -#define _cffi_restore_errno \ - ((void(*)(void))_cffi_exports[13]) -#define _cffi_save_errno \ - ((void(*)(void))_cffi_exports[14]) -#define _cffi_from_c_char \ - ((PyObject *(*)(char))_cffi_exports[15]) -#define _cffi_from_c_deref \ - ((PyObject *(*)(char *, struct _cffi_ctypedescr *))_cffi_exports[16]) -#define _cffi_to_c \ - ((int(*)(char *, struct _cffi_ctypedescr *, PyObject *))_cffi_exports[17]) -#define _cffi_from_c_struct \ - ((PyObject *(*)(char *, struct _cffi_ctypedescr *))_cffi_exports[18]) -#define _cffi_to_c_wchar_t \ - ((_cffi_wchar_t(*)(PyObject *))_cffi_exports[19]) -#define _cffi_from_c_wchar_t \ - ((PyObject *(*)(_cffi_wchar_t))_cffi_exports[20]) -#define _cffi_to_c_long_double \ - ((long double(*)(PyObject *))_cffi_exports[21]) -#define _cffi_to_c__Bool \ - ((_Bool(*)(PyObject *))_cffi_exports[22]) -#define _cffi_prepare_pointer_call_argument \ - ((Py_ssize_t(*)(struct _cffi_ctypedescr *, \ - PyObject *, char **))_cffi_exports[23]) -#define _cffi_convert_array_from_object \ - ((int(*)(char *, struct _cffi_ctypedescr *, PyObject *))_cffi_exports[24]) -#define _CFFI_CPIDX 25 -#define _cffi_call_python \ - ((void(*)(struct _cffi_externpy_s *, char *))_cffi_exports[_CFFI_CPIDX]) -#define _cffi_to_c_wchar3216_t \ - ((int(*)(PyObject *))_cffi_exports[26]) -#define _cffi_from_c_wchar3216_t \ - ((PyObject *(*)(int))_cffi_exports[27]) -#define _CFFI_NUM_EXPORTS 28 - -struct _cffi_ctypedescr; - -static void *_cffi_exports[_CFFI_NUM_EXPORTS]; - -#define _cffi_type(index) ( \ - assert((((uintptr_t)_cffi_types[index]) & 1) == 0), \ - (struct _cffi_ctypedescr *)_cffi_types[index]) - -static PyObject *_cffi_init(const char *module_name, Py_ssize_t version, - const struct _cffi_type_context_s *ctx) -{ - PyObject *module, *o_arg, *new_module; - void *raw[] = { - (void *)module_name, - (void *)version, - (void *)_cffi_exports, - (void *)ctx, - }; - - module = PyImport_ImportModule("_cffi_backend"); - if (module == NULL) - goto failure; - - o_arg = PyLong_FromVoidPtr((void *)raw); - if (o_arg == NULL) - goto failure; - - new_module = PyObject_CallMethod( - module, (char *)"_init_cffi_1_0_external_module", (char *)"O", o_arg); - - Py_DECREF(o_arg); - Py_DECREF(module); - return new_module; - - failure: - Py_XDECREF(module); - return NULL; -} - - -#ifdef HAVE_WCHAR_H -typedef wchar_t _cffi_wchar_t; -#else -typedef uint16_t _cffi_wchar_t; /* same random pick as _cffi_backend.c */ -#endif - -_CFFI_UNUSED_FN static uint16_t _cffi_to_c_char16_t(PyObject *o) -{ - if (sizeof(_cffi_wchar_t) == 2) - return (uint16_t)_cffi_to_c_wchar_t(o); - else - return (uint16_t)_cffi_to_c_wchar3216_t(o); -} - -_CFFI_UNUSED_FN static PyObject *_cffi_from_c_char16_t(uint16_t x) -{ - if (sizeof(_cffi_wchar_t) == 2) - return _cffi_from_c_wchar_t((_cffi_wchar_t)x); - else - return _cffi_from_c_wchar3216_t((int)x); -} - -_CFFI_UNUSED_FN static int _cffi_to_c_char32_t(PyObject *o) -{ - if (sizeof(_cffi_wchar_t) == 4) - return (int)_cffi_to_c_wchar_t(o); - else - return (int)_cffi_to_c_wchar3216_t(o); -} - -_CFFI_UNUSED_FN static PyObject *_cffi_from_c_char32_t(unsigned int x) -{ - if (sizeof(_cffi_wchar_t) == 4) - return _cffi_from_c_wchar_t((_cffi_wchar_t)x); - else - return _cffi_from_c_wchar3216_t((int)x); -} - -union _cffi_union_alignment_u { - unsigned char m_char; - unsigned short m_short; - unsigned int m_int; - unsigned long m_long; - unsigned long long m_longlong; - float m_float; - double m_double; - long double m_longdouble; -}; - -struct _cffi_freeme_s { - struct _cffi_freeme_s *next; - union _cffi_union_alignment_u alignment; -}; - -_CFFI_UNUSED_FN static int -_cffi_convert_array_argument(struct _cffi_ctypedescr *ctptr, PyObject *arg, - char **output_data, Py_ssize_t datasize, - struct _cffi_freeme_s **freeme) -{ - char *p; - if (datasize < 0) - return -1; - - p = *output_data; - if (p == NULL) { - struct _cffi_freeme_s *fp = (struct _cffi_freeme_s *)PyObject_Malloc( - offsetof(struct _cffi_freeme_s, alignment) + (size_t)datasize); - if (fp == NULL) - return -1; - fp->next = *freeme; - *freeme = fp; - p = *output_data = (char *)&fp->alignment; - } - memset((void *)p, 0, (size_t)datasize); - return _cffi_convert_array_from_object(p, ctptr, arg); -} - -_CFFI_UNUSED_FN static void -_cffi_free_array_arguments(struct _cffi_freeme_s *freeme) -{ - do { - void *p = (void *)freeme; - freeme = freeme->next; - PyObject_Free(p); - } while (freeme != NULL); -} - -/********** end CPython-specific section **********/ -#else -_CFFI_UNUSED_FN -static void (*_cffi_call_python_org)(struct _cffi_externpy_s *, char *); -# define _cffi_call_python _cffi_call_python_org -#endif - - -#define _cffi_array_len(array) (sizeof(array) / sizeof((array)[0])) - -#define _cffi_prim_int(size, sign) \ - ((size) == 1 ? ((sign) ? _CFFI_PRIM_INT8 : _CFFI_PRIM_UINT8) : \ - (size) == 2 ? ((sign) ? _CFFI_PRIM_INT16 : _CFFI_PRIM_UINT16) : \ - (size) == 4 ? ((sign) ? _CFFI_PRIM_INT32 : _CFFI_PRIM_UINT32) : \ - (size) == 8 ? ((sign) ? _CFFI_PRIM_INT64 : _CFFI_PRIM_UINT64) : \ - _CFFI__UNKNOWN_PRIM) - -#define _cffi_prim_float(size) \ - ((size) == sizeof(float) ? _CFFI_PRIM_FLOAT : \ - (size) == sizeof(double) ? _CFFI_PRIM_DOUBLE : \ - (size) == sizeof(long double) ? _CFFI__UNKNOWN_LONG_DOUBLE : \ - _CFFI__UNKNOWN_FLOAT_PRIM) - -#define _cffi_check_int(got, got_nonpos, expected) \ - ((got_nonpos) == (expected <= 0) && \ - (got) == (unsigned long long)expected) - -#ifdef MS_WIN32 -# define _cffi_stdcall __stdcall -#else -# define _cffi_stdcall /* nothing */ -#endif - -#ifdef __cplusplus -} -#endif diff --git a/venv/lib/python3.9/site-packages/cffi/_embedding.h b/venv/lib/python3.9/site-packages/cffi/_embedding.h deleted file mode 100644 index 64c04f6..0000000 --- a/venv/lib/python3.9/site-packages/cffi/_embedding.h +++ /dev/null @@ -1,550 +0,0 @@ - -/***** Support code for embedding *****/ - -#ifdef __cplusplus -extern "C" { -#endif - - -#if defined(_WIN32) -# define CFFI_DLLEXPORT __declspec(dllexport) -#elif defined(__GNUC__) -# define CFFI_DLLEXPORT __attribute__((visibility("default"))) -#else -# define CFFI_DLLEXPORT /* nothing */ -#endif - - -/* There are two global variables of type _cffi_call_python_fnptr: - - * _cffi_call_python, which we declare just below, is the one called - by ``extern "Python"`` implementations. - - * _cffi_call_python_org, which on CPython is actually part of the - _cffi_exports[] array, is the function pointer copied from - _cffi_backend. If _cffi_start_python() fails, then this is set - to NULL; otherwise, it should never be NULL. - - After initialization is complete, both are equal. However, the - first one remains equal to &_cffi_start_and_call_python until the - very end of initialization, when we are (or should be) sure that - concurrent threads also see a completely initialized world, and - only then is it changed. -*/ -#undef _cffi_call_python -typedef void (*_cffi_call_python_fnptr)(struct _cffi_externpy_s *, char *); -static void _cffi_start_and_call_python(struct _cffi_externpy_s *, char *); -static _cffi_call_python_fnptr _cffi_call_python = &_cffi_start_and_call_python; - - -#ifndef _MSC_VER - /* --- Assuming a GCC not infinitely old --- */ -# define cffi_compare_and_swap(l,o,n) __sync_bool_compare_and_swap(l,o,n) -# define cffi_write_barrier() __sync_synchronize() -# if !defined(__amd64__) && !defined(__x86_64__) && \ - !defined(__i386__) && !defined(__i386) -# define cffi_read_barrier() __sync_synchronize() -# else -# define cffi_read_barrier() (void)0 -# endif -#else - /* --- Windows threads version --- */ -# include -# define cffi_compare_and_swap(l,o,n) \ - (InterlockedCompareExchangePointer(l,n,o) == (o)) -# define cffi_write_barrier() InterlockedCompareExchange(&_cffi_dummy,0,0) -# define cffi_read_barrier() (void)0 -static volatile LONG _cffi_dummy; -#endif - -#ifdef WITH_THREAD -# ifndef _MSC_VER -# include - static pthread_mutex_t _cffi_embed_startup_lock; -# else - static CRITICAL_SECTION _cffi_embed_startup_lock; -# endif - static char _cffi_embed_startup_lock_ready = 0; -#endif - -static void _cffi_acquire_reentrant_mutex(void) -{ - static void *volatile lock = NULL; - - while (!cffi_compare_and_swap(&lock, NULL, (void *)1)) { - /* should ideally do a spin loop instruction here, but - hard to do it portably and doesn't really matter I - think: pthread_mutex_init() should be very fast, and - this is only run at start-up anyway. */ - } - -#ifdef WITH_THREAD - if (!_cffi_embed_startup_lock_ready) { -# ifndef _MSC_VER - pthread_mutexattr_t attr; - pthread_mutexattr_init(&attr); - pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE); - pthread_mutex_init(&_cffi_embed_startup_lock, &attr); -# else - InitializeCriticalSection(&_cffi_embed_startup_lock); -# endif - _cffi_embed_startup_lock_ready = 1; - } -#endif - - while (!cffi_compare_and_swap(&lock, (void *)1, NULL)) - ; - -#ifndef _MSC_VER - pthread_mutex_lock(&_cffi_embed_startup_lock); -#else - EnterCriticalSection(&_cffi_embed_startup_lock); -#endif -} - -static void _cffi_release_reentrant_mutex(void) -{ -#ifndef _MSC_VER - pthread_mutex_unlock(&_cffi_embed_startup_lock); -#else - LeaveCriticalSection(&_cffi_embed_startup_lock); -#endif -} - - -/********** CPython-specific section **********/ -#ifndef PYPY_VERSION - -#include "_cffi_errors.h" - - -#define _cffi_call_python_org _cffi_exports[_CFFI_CPIDX] - -PyMODINIT_FUNC _CFFI_PYTHON_STARTUP_FUNC(void); /* forward */ - -static void _cffi_py_initialize(void) -{ - /* XXX use initsigs=0, which "skips initialization registration of - signal handlers, which might be useful when Python is - embedded" according to the Python docs. But review and think - if it should be a user-controllable setting. - - XXX we should also give a way to write errors to a buffer - instead of to stderr. - - XXX if importing 'site' fails, CPython (any version) calls - exit(). Should we try to work around this behavior here? - */ - Py_InitializeEx(0); -} - -static int _cffi_initialize_python(void) -{ - /* This initializes Python, imports _cffi_backend, and then the - present .dll/.so is set up as a CPython C extension module. - */ - int result; - PyGILState_STATE state; - PyObject *pycode=NULL, *global_dict=NULL, *x; - PyObject *builtins; - - state = PyGILState_Ensure(); - - /* Call the initxxx() function from the present module. It will - create and initialize us as a CPython extension module, instead - of letting the startup Python code do it---it might reimport - the same .dll/.so and get maybe confused on some platforms. - It might also have troubles locating the .dll/.so again for all - I know. - */ - (void)_CFFI_PYTHON_STARTUP_FUNC(); - if (PyErr_Occurred()) - goto error; - - /* Now run the Python code provided to ffi.embedding_init_code(). - */ - pycode = Py_CompileString(_CFFI_PYTHON_STARTUP_CODE, - "", - Py_file_input); - if (pycode == NULL) - goto error; - global_dict = PyDict_New(); - if (global_dict == NULL) - goto error; - builtins = PyEval_GetBuiltins(); - if (builtins == NULL) - goto error; - if (PyDict_SetItemString(global_dict, "__builtins__", builtins) < 0) - goto error; - x = PyEval_EvalCode( -#if PY_MAJOR_VERSION < 3 - (PyCodeObject *) -#endif - pycode, global_dict, global_dict); - if (x == NULL) - goto error; - Py_DECREF(x); - - /* Done! Now if we've been called from - _cffi_start_and_call_python() in an ``extern "Python"``, we can - only hope that the Python code did correctly set up the - corresponding @ffi.def_extern() function. Otherwise, the - general logic of ``extern "Python"`` functions (inside the - _cffi_backend module) will find that the reference is still - missing and print an error. - */ - result = 0; - done: - Py_XDECREF(pycode); - Py_XDECREF(global_dict); - PyGILState_Release(state); - return result; - - error:; - { - /* Print as much information as potentially useful. - Debugging load-time failures with embedding is not fun - */ - PyObject *ecap; - PyObject *exception, *v, *tb, *f, *modules, *mod; - PyErr_Fetch(&exception, &v, &tb); - ecap = _cffi_start_error_capture(); - f = PySys_GetObject((char *)"stderr"); - if (f != NULL && f != Py_None) { - PyFile_WriteString( - "Failed to initialize the Python-CFFI embedding logic:\n\n", f); - } - - if (exception != NULL) { - PyErr_NormalizeException(&exception, &v, &tb); - PyErr_Display(exception, v, tb); - } - Py_XDECREF(exception); - Py_XDECREF(v); - Py_XDECREF(tb); - - if (f != NULL && f != Py_None) { - PyFile_WriteString("\nFrom: " _CFFI_MODULE_NAME - "\ncompiled with cffi version: 2.0.0" - "\n_cffi_backend module: ", f); - modules = PyImport_GetModuleDict(); - mod = PyDict_GetItemString(modules, "_cffi_backend"); - if (mod == NULL) { - PyFile_WriteString("not loaded", f); - } - else { - v = PyObject_GetAttrString(mod, "__file__"); - PyFile_WriteObject(v, f, 0); - Py_XDECREF(v); - } - PyFile_WriteString("\nsys.path: ", f); - PyFile_WriteObject(PySys_GetObject((char *)"path"), f, 0); - PyFile_WriteString("\n\n", f); - } - _cffi_stop_error_capture(ecap); - } - result = -1; - goto done; -} - -#if PY_VERSION_HEX < 0x03080000 -PyAPI_DATA(char *) _PyParser_TokenNames[]; /* from CPython */ -#endif - -static int _cffi_carefully_make_gil(void) -{ - /* This does the basic initialization of Python. It can be called - completely concurrently from unrelated threads. It assumes - that we don't hold the GIL before (if it exists), and we don't - hold it afterwards. - - (What it really does used to be completely different in Python 2 - and Python 3, with the Python 2 solution avoiding the spin-lock - around the Py_InitializeEx() call. However, after recent changes - to CPython 2.7 (issue #358) it no longer works. So we use the - Python 3 solution everywhere.) - - This initializes Python by calling Py_InitializeEx(). - Important: this must not be called concurrently at all. - So we use a global variable as a simple spin lock. This global - variable must be from 'libpythonX.Y.so', not from this - cffi-based extension module, because it must be shared from - different cffi-based extension modules. - - In Python < 3.8, we choose - _PyParser_TokenNames[0] as a completely arbitrary pointer value - that is never written to. The default is to point to the - string "ENDMARKER". We change it temporarily to point to the - next character in that string. (Yes, I know it's REALLY - obscure.) - - In Python >= 3.8, this string array is no longer writable, so - instead we pick PyCapsuleType.tp_version_tag. We can't change - Python < 3.8 because someone might use a mixture of cffi - embedded modules, some of which were compiled before this file - changed. - - In Python >= 3.12, this stopped working because that particular - tp_version_tag gets modified during interpreter startup. It's - arguably a bad idea before 3.12 too, but again we can't change - that because someone might use a mixture of cffi embedded - modules, and no-one reported a bug so far. In Python >= 3.12 - we go instead for PyCapsuleType.tp_as_buffer, which is supposed - to always be NULL. We write to it temporarily a pointer to - a struct full of NULLs, which is semantically the same. - */ - -#ifdef WITH_THREAD -# if PY_VERSION_HEX < 0x03080000 - char *volatile *lock = (char *volatile *)_PyParser_TokenNames; - char *old_value, *locked_value; - - while (1) { /* spin loop */ - old_value = *lock; - locked_value = old_value + 1; - if (old_value[0] == 'E') { - assert(old_value[1] == 'N'); - if (cffi_compare_and_swap(lock, old_value, locked_value)) - break; - } - else { - assert(old_value[0] == 'N'); - /* should ideally do a spin loop instruction here, but - hard to do it portably and doesn't really matter I - think: PyEval_InitThreads() should be very fast, and - this is only run at start-up anyway. */ - } - } -# else -# if PY_VERSION_HEX < 0x030C0000 - int volatile *lock = (int volatile *)&PyCapsule_Type.tp_version_tag; - int old_value, locked_value = -42; - assert(!(PyCapsule_Type.tp_flags & Py_TPFLAGS_HAVE_VERSION_TAG)); -# else - static struct ebp_s { PyBufferProcs buf; int mark; } empty_buffer_procs; - empty_buffer_procs.mark = -42; - PyBufferProcs *volatile *lock = (PyBufferProcs *volatile *) - &PyCapsule_Type.tp_as_buffer; - PyBufferProcs *old_value, *locked_value = &empty_buffer_procs.buf; -# endif - - while (1) { /* spin loop */ - old_value = *lock; - if (old_value == 0) { - if (cffi_compare_and_swap(lock, old_value, locked_value)) - break; - } - else { -# if PY_VERSION_HEX < 0x030C0000 - assert(old_value == locked_value); -# else - /* The pointer should point to a possibly different - empty_buffer_procs from another C extension module */ - assert(((struct ebp_s *)old_value)->mark == -42); -# endif - /* should ideally do a spin loop instruction here, but - hard to do it portably and doesn't really matter I - think: PyEval_InitThreads() should be very fast, and - this is only run at start-up anyway. */ - } - } -# endif -#endif - - /* call Py_InitializeEx() */ - if (!Py_IsInitialized()) { - _cffi_py_initialize(); -#if PY_VERSION_HEX < 0x03070000 - PyEval_InitThreads(); -#endif - PyEval_SaveThread(); /* release the GIL */ - /* the returned tstate must be the one that has been stored into the - autoTLSkey by _PyGILState_Init() called from Py_Initialize(). */ - } - else { -#if PY_VERSION_HEX < 0x03070000 - /* PyEval_InitThreads() is always a no-op from CPython 3.7 */ - PyGILState_STATE state = PyGILState_Ensure(); - PyEval_InitThreads(); - PyGILState_Release(state); -#endif - } - -#ifdef WITH_THREAD - /* release the lock */ - while (!cffi_compare_and_swap(lock, locked_value, old_value)) - ; -#endif - - return 0; -} - -/********** end CPython-specific section **********/ - - -#else - - -/********** PyPy-specific section **********/ - -PyMODINIT_FUNC _CFFI_PYTHON_STARTUP_FUNC(const void *[]); /* forward */ - -static struct _cffi_pypy_init_s { - const char *name; - void *func; /* function pointer */ - const char *code; -} _cffi_pypy_init = { - _CFFI_MODULE_NAME, - _CFFI_PYTHON_STARTUP_FUNC, - _CFFI_PYTHON_STARTUP_CODE, -}; - -extern int pypy_carefully_make_gil(const char *); -extern int pypy_init_embedded_cffi_module(int, struct _cffi_pypy_init_s *); - -static int _cffi_carefully_make_gil(void) -{ - return pypy_carefully_make_gil(_CFFI_MODULE_NAME); -} - -static int _cffi_initialize_python(void) -{ - return pypy_init_embedded_cffi_module(0xB011, &_cffi_pypy_init); -} - -/********** end PyPy-specific section **********/ - - -#endif - - -#ifdef __GNUC__ -__attribute__((noinline)) -#endif -static _cffi_call_python_fnptr _cffi_start_python(void) -{ - /* Delicate logic to initialize Python. This function can be - called multiple times concurrently, e.g. when the process calls - its first ``extern "Python"`` functions in multiple threads at - once. It can also be called recursively, in which case we must - ignore it. We also have to consider what occurs if several - different cffi-based extensions reach this code in parallel - threads---it is a different copy of the code, then, and we - can't have any shared global variable unless it comes from - 'libpythonX.Y.so'. - - Idea: - - * _cffi_carefully_make_gil(): "carefully" call - PyEval_InitThreads() (possibly with Py_InitializeEx() first). - - * then we use a (local) custom lock to make sure that a call to this - cffi-based extension will wait if another call to the *same* - extension is running the initialization in another thread. - It is reentrant, so that a recursive call will not block, but - only one from a different thread. - - * then we grab the GIL and (Python 2) we call Py_InitializeEx(). - At this point, concurrent calls to Py_InitializeEx() are not - possible: we have the GIL. - - * do the rest of the specific initialization, which may - temporarily release the GIL but not the custom lock. - Only release the custom lock when we are done. - */ - static char called = 0; - - if (_cffi_carefully_make_gil() != 0) - return NULL; - - _cffi_acquire_reentrant_mutex(); - - /* Here the GIL exists, but we don't have it. We're only protected - from concurrency by the reentrant mutex. */ - - /* This file only initializes the embedded module once, the first - time this is called, even if there are subinterpreters. */ - if (!called) { - called = 1; /* invoke _cffi_initialize_python() only once, - but don't set '_cffi_call_python' right now, - otherwise concurrent threads won't call - this function at all (we need them to wait) */ - if (_cffi_initialize_python() == 0) { - /* now initialization is finished. Switch to the fast-path. */ - - /* We would like nobody to see the new value of - '_cffi_call_python' without also seeing the rest of the - data initialized. However, this is not possible. But - the new value of '_cffi_call_python' is the function - 'cffi_call_python()' from _cffi_backend. So: */ - cffi_write_barrier(); - /* ^^^ we put a write barrier here, and a corresponding - read barrier at the start of cffi_call_python(). This - ensures that after that read barrier, we see everything - done here before the write barrier. - */ - - assert(_cffi_call_python_org != NULL); - _cffi_call_python = (_cffi_call_python_fnptr)_cffi_call_python_org; - } - else { - /* initialization failed. Reset this to NULL, even if it was - already set to some other value. Future calls to - _cffi_start_python() are still forced to occur, and will - always return NULL from now on. */ - _cffi_call_python_org = NULL; - } - } - - _cffi_release_reentrant_mutex(); - - return (_cffi_call_python_fnptr)_cffi_call_python_org; -} - -static -void _cffi_start_and_call_python(struct _cffi_externpy_s *externpy, char *args) -{ - _cffi_call_python_fnptr fnptr; - int current_err = errno; -#ifdef _MSC_VER - int current_lasterr = GetLastError(); -#endif - fnptr = _cffi_start_python(); - if (fnptr == NULL) { - fprintf(stderr, "function %s() called, but initialization code " - "failed. Returning 0.\n", externpy->name); - memset(args, 0, externpy->size_of_result); - } -#ifdef _MSC_VER - SetLastError(current_lasterr); -#endif - errno = current_err; - - if (fnptr != NULL) - fnptr(externpy, args); -} - - -/* The cffi_start_python() function makes sure Python is initialized - and our cffi module is set up. It can be called manually from the - user C code. The same effect is obtained automatically from any - dll-exported ``extern "Python"`` function. This function returns - -1 if initialization failed, 0 if all is OK. */ -_CFFI_UNUSED_FN -static int cffi_start_python(void) -{ - if (_cffi_call_python == &_cffi_start_and_call_python) { - if (_cffi_start_python() == NULL) - return -1; - } - cffi_read_barrier(); - return 0; -} - -#undef cffi_compare_and_swap -#undef cffi_write_barrier -#undef cffi_read_barrier - -#ifdef __cplusplus -} -#endif diff --git a/venv/lib/python3.9/site-packages/cffi/_imp_emulation.py b/venv/lib/python3.9/site-packages/cffi/_imp_emulation.py deleted file mode 100644 index 136abdd..0000000 --- a/venv/lib/python3.9/site-packages/cffi/_imp_emulation.py +++ /dev/null @@ -1,83 +0,0 @@ - -try: - # this works on Python < 3.12 - from imp import * - -except ImportError: - # this is a limited emulation for Python >= 3.12. - # Note that this is used only for tests or for the old ffi.verify(). - # This is copied from the source code of Python 3.11. - - from _imp import (acquire_lock, release_lock, - is_builtin, is_frozen) - - from importlib._bootstrap import _load - - from importlib import machinery - import os - import sys - import tokenize - - SEARCH_ERROR = 0 - PY_SOURCE = 1 - PY_COMPILED = 2 - C_EXTENSION = 3 - PY_RESOURCE = 4 - PKG_DIRECTORY = 5 - C_BUILTIN = 6 - PY_FROZEN = 7 - PY_CODERESOURCE = 8 - IMP_HOOK = 9 - - def get_suffixes(): - extensions = [(s, 'rb', C_EXTENSION) - for s in machinery.EXTENSION_SUFFIXES] - source = [(s, 'r', PY_SOURCE) for s in machinery.SOURCE_SUFFIXES] - bytecode = [(s, 'rb', PY_COMPILED) for s in machinery.BYTECODE_SUFFIXES] - return extensions + source + bytecode - - def find_module(name, path=None): - if not isinstance(name, str): - raise TypeError("'name' must be a str, not {}".format(type(name))) - elif not isinstance(path, (type(None), list)): - # Backwards-compatibility - raise RuntimeError("'path' must be None or a list, " - "not {}".format(type(path))) - - if path is None: - if is_builtin(name): - return None, None, ('', '', C_BUILTIN) - elif is_frozen(name): - return None, None, ('', '', PY_FROZEN) - else: - path = sys.path - - for entry in path: - package_directory = os.path.join(entry, name) - for suffix in ['.py', machinery.BYTECODE_SUFFIXES[0]]: - package_file_name = '__init__' + suffix - file_path = os.path.join(package_directory, package_file_name) - if os.path.isfile(file_path): - return None, package_directory, ('', '', PKG_DIRECTORY) - for suffix, mode, type_ in get_suffixes(): - file_name = name + suffix - file_path = os.path.join(entry, file_name) - if os.path.isfile(file_path): - break - else: - continue - break # Break out of outer loop when breaking out of inner loop. - else: - raise ImportError(name, name=name) - - encoding = None - if 'b' not in mode: - with open(file_path, 'rb') as file: - encoding = tokenize.detect_encoding(file.readline)[0] - file = open(file_path, mode, encoding=encoding) - return file, file_path, (suffix, mode, type_) - - def load_dynamic(name, path, file=None): - loader = machinery.ExtensionFileLoader(name, path) - spec = machinery.ModuleSpec(name=name, loader=loader, origin=path) - return _load(spec) diff --git a/venv/lib/python3.9/site-packages/cffi/_shimmed_dist_utils.py b/venv/lib/python3.9/site-packages/cffi/_shimmed_dist_utils.py deleted file mode 100644 index c3d2312..0000000 --- a/venv/lib/python3.9/site-packages/cffi/_shimmed_dist_utils.py +++ /dev/null @@ -1,45 +0,0 @@ -""" -Temporary shim module to indirect the bits of distutils we need from setuptools/distutils while providing useful -error messages beyond `No module named 'distutils' on Python >= 3.12, or when setuptools' vendored distutils is broken. - -This is a compromise to avoid a hard-dep on setuptools for Python >= 3.12, since many users don't need runtime compilation support from CFFI. -""" -import sys - -try: - # import setuptools first; this is the most robust way to ensure its embedded distutils is available - # (the .pth shim should usually work, but this is even more robust) - import setuptools -except Exception as ex: - if sys.version_info >= (3, 12): - # Python 3.12 has no built-in distutils to fall back on, so any import problem is fatal - raise Exception("This CFFI feature requires setuptools on Python >= 3.12. The setuptools module is missing or non-functional.") from ex - - # silently ignore on older Pythons (support fallback to stdlib distutils where available) -else: - del setuptools - -try: - # bring in just the bits of distutils we need, whether they really came from setuptools or stdlib-embedded distutils - from distutils import log, sysconfig - from distutils.ccompiler import CCompiler - from distutils.command.build_ext import build_ext - from distutils.core import Distribution, Extension - from distutils.dir_util import mkpath - from distutils.errors import DistutilsSetupError, CompileError, LinkError - from distutils.log import set_threshold, set_verbosity - - if sys.platform == 'win32': - try: - # FUTURE: msvc9compiler module was removed in setuptools 74; consider removing, as it's only used by an ancient patch in `recompiler` - from distutils.msvc9compiler import MSVCCompiler - except ImportError: - MSVCCompiler = None -except Exception as ex: - if sys.version_info >= (3, 12): - raise Exception("This CFFI feature requires setuptools on Python >= 3.12. Please install the setuptools package.") from ex - - # anything older, just let the underlying distutils import error fly - raise Exception("This CFFI feature requires distutils. Please install the distutils or setuptools package.") from ex - -del sys diff --git a/venv/lib/python3.9/site-packages/cffi/api.py b/venv/lib/python3.9/site-packages/cffi/api.py deleted file mode 100644 index 5a474f3..0000000 --- a/venv/lib/python3.9/site-packages/cffi/api.py +++ /dev/null @@ -1,967 +0,0 @@ -import sys, types -from .lock import allocate_lock -from .error import CDefError -from . import model - -try: - callable -except NameError: - # Python 3.1 - from collections import Callable - callable = lambda x: isinstance(x, Callable) - -try: - basestring -except NameError: - # Python 3.x - basestring = str - -_unspecified = object() - - - -class FFI(object): - r''' - The main top-level class that you instantiate once, or once per module. - - Example usage: - - ffi = FFI() - ffi.cdef(""" - int printf(const char *, ...); - """) - - C = ffi.dlopen(None) # standard library - -or- - C = ffi.verify() # use a C compiler: verify the decl above is right - - C.printf("hello, %s!\n", ffi.new("char[]", "world")) - ''' - - def __init__(self, backend=None): - """Create an FFI instance. The 'backend' argument is used to - select a non-default backend, mostly for tests. - """ - if backend is None: - # You need PyPy (>= 2.0 beta), or a CPython (>= 2.6) with - # _cffi_backend.so compiled. - import _cffi_backend as backend - from . import __version__ - if backend.__version__ != __version__: - # bad version! Try to be as explicit as possible. - if hasattr(backend, '__file__'): - # CPython - raise Exception("Version mismatch: this is the 'cffi' package version %s, located in %r. When we import the top-level '_cffi_backend' extension module, we get version %s, located in %r. The two versions should be equal; check your installation." % ( - __version__, __file__, - backend.__version__, backend.__file__)) - else: - # PyPy - raise Exception("Version mismatch: this is the 'cffi' package version %s, located in %r. This interpreter comes with a built-in '_cffi_backend' module, which is version %s. The two versions should be equal; check your installation." % ( - __version__, __file__, backend.__version__)) - # (If you insist you can also try to pass the option - # 'backend=backend_ctypes.CTypesBackend()', but don't - # rely on it! It's probably not going to work well.) - - from . import cparser - self._backend = backend - self._lock = allocate_lock() - self._parser = cparser.Parser() - self._cached_btypes = {} - self._parsed_types = types.ModuleType('parsed_types').__dict__ - self._new_types = types.ModuleType('new_types').__dict__ - self._function_caches = [] - self._libraries = [] - self._cdefsources = [] - self._included_ffis = [] - self._windows_unicode = None - self._init_once_cache = {} - self._cdef_version = None - self._embedding = None - self._typecache = model.get_typecache(backend) - if hasattr(backend, 'set_ffi'): - backend.set_ffi(self) - for name in list(backend.__dict__): - if name.startswith('RTLD_'): - setattr(self, name, getattr(backend, name)) - # - with self._lock: - self.BVoidP = self._get_cached_btype(model.voidp_type) - self.BCharA = self._get_cached_btype(model.char_array_type) - if isinstance(backend, types.ModuleType): - # _cffi_backend: attach these constants to the class - if not hasattr(FFI, 'NULL'): - FFI.NULL = self.cast(self.BVoidP, 0) - FFI.CData, FFI.CType = backend._get_types() - else: - # ctypes backend: attach these constants to the instance - self.NULL = self.cast(self.BVoidP, 0) - self.CData, self.CType = backend._get_types() - self.buffer = backend.buffer - - def cdef(self, csource, override=False, packed=False, pack=None): - """Parse the given C source. This registers all declared functions, - types, and global variables. The functions and global variables can - then be accessed via either 'ffi.dlopen()' or 'ffi.verify()'. - The types can be used in 'ffi.new()' and other functions. - If 'packed' is specified as True, all structs declared inside this - cdef are packed, i.e. laid out without any field alignment at all. - Alternatively, 'pack' can be a small integer, and requests for - alignment greater than that are ignored (pack=1 is equivalent to - packed=True). - """ - self._cdef(csource, override=override, packed=packed, pack=pack) - - def embedding_api(self, csource, packed=False, pack=None): - self._cdef(csource, packed=packed, pack=pack, dllexport=True) - if self._embedding is None: - self._embedding = '' - - def _cdef(self, csource, override=False, **options): - if not isinstance(csource, str): # unicode, on Python 2 - if not isinstance(csource, basestring): - raise TypeError("cdef() argument must be a string") - csource = csource.encode('ascii') - with self._lock: - self._cdef_version = object() - self._parser.parse(csource, override=override, **options) - self._cdefsources.append(csource) - if override: - for cache in self._function_caches: - cache.clear() - finishlist = self._parser._recomplete - if finishlist: - self._parser._recomplete = [] - for tp in finishlist: - tp.finish_backend_type(self, finishlist) - - def dlopen(self, name, flags=0): - """Load and return a dynamic library identified by 'name'. - The standard C library can be loaded by passing None. - Note that functions and types declared by 'ffi.cdef()' are not - linked to a particular library, just like C headers; in the - library we only look for the actual (untyped) symbols. - """ - if not (isinstance(name, basestring) or - name is None or - isinstance(name, self.CData)): - raise TypeError("dlopen(name): name must be a file name, None, " - "or an already-opened 'void *' handle") - with self._lock: - lib, function_cache = _make_ffi_library(self, name, flags) - self._function_caches.append(function_cache) - self._libraries.append(lib) - return lib - - def dlclose(self, lib): - """Close a library obtained with ffi.dlopen(). After this call, - access to functions or variables from the library will fail - (possibly with a segmentation fault). - """ - type(lib).__cffi_close__(lib) - - def _typeof_locked(self, cdecl): - # call me with the lock! - key = cdecl - if key in self._parsed_types: - return self._parsed_types[key] - # - if not isinstance(cdecl, str): # unicode, on Python 2 - cdecl = cdecl.encode('ascii') - # - type = self._parser.parse_type(cdecl) - really_a_function_type = type.is_raw_function - if really_a_function_type: - type = type.as_function_pointer() - btype = self._get_cached_btype(type) - result = btype, really_a_function_type - self._parsed_types[key] = result - return result - - def _typeof(self, cdecl, consider_function_as_funcptr=False): - # string -> ctype object - try: - result = self._parsed_types[cdecl] - except KeyError: - with self._lock: - result = self._typeof_locked(cdecl) - # - btype, really_a_function_type = result - if really_a_function_type and not consider_function_as_funcptr: - raise CDefError("the type %r is a function type, not a " - "pointer-to-function type" % (cdecl,)) - return btype - - def typeof(self, cdecl): - """Parse the C type given as a string and return the - corresponding object. - It can also be used on 'cdata' instance to get its C type. - """ - if isinstance(cdecl, basestring): - return self._typeof(cdecl) - if isinstance(cdecl, self.CData): - return self._backend.typeof(cdecl) - if isinstance(cdecl, types.BuiltinFunctionType): - res = _builtin_function_type(cdecl) - if res is not None: - return res - if (isinstance(cdecl, types.FunctionType) - and hasattr(cdecl, '_cffi_base_type')): - with self._lock: - return self._get_cached_btype(cdecl._cffi_base_type) - raise TypeError(type(cdecl)) - - def sizeof(self, cdecl): - """Return the size in bytes of the argument. It can be a - string naming a C type, or a 'cdata' instance. - """ - if isinstance(cdecl, basestring): - BType = self._typeof(cdecl) - return self._backend.sizeof(BType) - else: - return self._backend.sizeof(cdecl) - - def alignof(self, cdecl): - """Return the natural alignment size in bytes of the C type - given as a string. - """ - if isinstance(cdecl, basestring): - cdecl = self._typeof(cdecl) - return self._backend.alignof(cdecl) - - def offsetof(self, cdecl, *fields_or_indexes): - """Return the offset of the named field inside the given - structure or array, which must be given as a C type name. - You can give several field names in case of nested structures. - You can also give numeric values which correspond to array - items, in case of an array type. - """ - if isinstance(cdecl, basestring): - cdecl = self._typeof(cdecl) - return self._typeoffsetof(cdecl, *fields_or_indexes)[1] - - def new(self, cdecl, init=None): - """Allocate an instance according to the specified C type and - return a pointer to it. The specified C type must be either a - pointer or an array: ``new('X *')`` allocates an X and returns - a pointer to it, whereas ``new('X[n]')`` allocates an array of - n X'es and returns an array referencing it (which works - mostly like a pointer, like in C). You can also use - ``new('X[]', n)`` to allocate an array of a non-constant - length n. - - The memory is initialized following the rules of declaring a - global variable in C: by default it is zero-initialized, but - an explicit initializer can be given which can be used to - fill all or part of the memory. - - When the returned object goes out of scope, the memory - is freed. In other words the returned object has - ownership of the value of type 'cdecl' that it points to. This - means that the raw data can be used as long as this object is - kept alive, but must not be used for a longer time. Be careful - about that when copying the pointer to the memory somewhere - else, e.g. into another structure. - """ - if isinstance(cdecl, basestring): - cdecl = self._typeof(cdecl) - return self._backend.newp(cdecl, init) - - def new_allocator(self, alloc=None, free=None, - should_clear_after_alloc=True): - """Return a new allocator, i.e. a function that behaves like ffi.new() - but uses the provided low-level 'alloc' and 'free' functions. - - 'alloc' is called with the size as argument. If it returns NULL, a - MemoryError is raised. 'free' is called with the result of 'alloc' - as argument. Both can be either Python function or directly C - functions. If 'free' is None, then no free function is called. - If both 'alloc' and 'free' are None, the default is used. - - If 'should_clear_after_alloc' is set to False, then the memory - returned by 'alloc' is assumed to be already cleared (or you are - fine with garbage); otherwise CFFI will clear it. - """ - compiled_ffi = self._backend.FFI() - allocator = compiled_ffi.new_allocator(alloc, free, - should_clear_after_alloc) - def allocate(cdecl, init=None): - if isinstance(cdecl, basestring): - cdecl = self._typeof(cdecl) - return allocator(cdecl, init) - return allocate - - def cast(self, cdecl, source): - """Similar to a C cast: returns an instance of the named C - type initialized with the given 'source'. The source is - casted between integers or pointers of any type. - """ - if isinstance(cdecl, basestring): - cdecl = self._typeof(cdecl) - return self._backend.cast(cdecl, source) - - def string(self, cdata, maxlen=-1): - """Return a Python string (or unicode string) from the 'cdata'. - If 'cdata' is a pointer or array of characters or bytes, returns - the null-terminated string. The returned string extends until - the first null character, or at most 'maxlen' characters. If - 'cdata' is an array then 'maxlen' defaults to its length. - - If 'cdata' is a pointer or array of wchar_t, returns a unicode - string following the same rules. - - If 'cdata' is a single character or byte or a wchar_t, returns - it as a string or unicode string. - - If 'cdata' is an enum, returns the value of the enumerator as a - string, or 'NUMBER' if the value is out of range. - """ - return self._backend.string(cdata, maxlen) - - def unpack(self, cdata, length): - """Unpack an array of C data of the given length, - returning a Python string/unicode/list. - - If 'cdata' is a pointer to 'char', returns a byte string. - It does not stop at the first null. This is equivalent to: - ffi.buffer(cdata, length)[:] - - If 'cdata' is a pointer to 'wchar_t', returns a unicode string. - 'length' is measured in wchar_t's; it is not the size in bytes. - - If 'cdata' is a pointer to anything else, returns a list of - 'length' items. This is a faster equivalent to: - [cdata[i] for i in range(length)] - """ - return self._backend.unpack(cdata, length) - - #def buffer(self, cdata, size=-1): - # """Return a read-write buffer object that references the raw C data - # pointed to by the given 'cdata'. The 'cdata' must be a pointer or - # an array. Can be passed to functions expecting a buffer, or directly - # manipulated with: - # - # buf[:] get a copy of it in a regular string, or - # buf[idx] as a single character - # buf[:] = ... - # buf[idx] = ... change the content - # """ - # note that 'buffer' is a type, set on this instance by __init__ - - def from_buffer(self, cdecl, python_buffer=_unspecified, - require_writable=False): - """Return a cdata of the given type pointing to the data of the - given Python object, which must support the buffer interface. - Note that this is not meant to be used on the built-in types - str or unicode (you can build 'char[]' arrays explicitly) - but only on objects containing large quantities of raw data - in some other format, like 'array.array' or numpy arrays. - - The first argument is optional and default to 'char[]'. - """ - if python_buffer is _unspecified: - cdecl, python_buffer = self.BCharA, cdecl - elif isinstance(cdecl, basestring): - cdecl = self._typeof(cdecl) - return self._backend.from_buffer(cdecl, python_buffer, - require_writable) - - def memmove(self, dest, src, n): - """ffi.memmove(dest, src, n) copies n bytes of memory from src to dest. - - Like the C function memmove(), the memory areas may overlap; - apart from that it behaves like the C function memcpy(). - - 'src' can be any cdata ptr or array, or any Python buffer object. - 'dest' can be any cdata ptr or array, or a writable Python buffer - object. The size to copy, 'n', is always measured in bytes. - - Unlike other methods, this one supports all Python buffer including - byte strings and bytearrays---but it still does not support - non-contiguous buffers. - """ - return self._backend.memmove(dest, src, n) - - def callback(self, cdecl, python_callable=None, error=None, onerror=None): - """Return a callback object or a decorator making such a - callback object. 'cdecl' must name a C function pointer type. - The callback invokes the specified 'python_callable' (which may - be provided either directly or via a decorator). Important: the - callback object must be manually kept alive for as long as the - callback may be invoked from the C level. - """ - def callback_decorator_wrap(python_callable): - if not callable(python_callable): - raise TypeError("the 'python_callable' argument " - "is not callable") - return self._backend.callback(cdecl, python_callable, - error, onerror) - if isinstance(cdecl, basestring): - cdecl = self._typeof(cdecl, consider_function_as_funcptr=True) - if python_callable is None: - return callback_decorator_wrap # decorator mode - else: - return callback_decorator_wrap(python_callable) # direct mode - - def getctype(self, cdecl, replace_with=''): - """Return a string giving the C type 'cdecl', which may be itself - a string or a object. If 'replace_with' is given, it gives - extra text to append (or insert for more complicated C types), like - a variable name, or '*' to get actually the C type 'pointer-to-cdecl'. - """ - if isinstance(cdecl, basestring): - cdecl = self._typeof(cdecl) - replace_with = replace_with.strip() - if (replace_with.startswith('*') - and '&[' in self._backend.getcname(cdecl, '&')): - replace_with = '(%s)' % replace_with - elif replace_with and not replace_with[0] in '[(': - replace_with = ' ' + replace_with - return self._backend.getcname(cdecl, replace_with) - - def gc(self, cdata, destructor, size=0): - """Return a new cdata object that points to the same - data. Later, when this new cdata object is garbage-collected, - 'destructor(old_cdata_object)' will be called. - - The optional 'size' gives an estimate of the size, used to - trigger the garbage collection more eagerly. So far only used - on PyPy. It tells the GC that the returned object keeps alive - roughly 'size' bytes of external memory. - """ - return self._backend.gcp(cdata, destructor, size) - - def _get_cached_btype(self, type): - assert self._lock.acquire(False) is False - # call me with the lock! - try: - BType = self._cached_btypes[type] - except KeyError: - finishlist = [] - BType = type.get_cached_btype(self, finishlist) - for type in finishlist: - type.finish_backend_type(self, finishlist) - return BType - - def verify(self, source='', tmpdir=None, **kwargs): - """Verify that the current ffi signatures compile on this - machine, and return a dynamic library object. The dynamic - library can be used to call functions and access global - variables declared in this 'ffi'. The library is compiled - by the C compiler: it gives you C-level API compatibility - (including calling macros). This is unlike 'ffi.dlopen()', - which requires binary compatibility in the signatures. - """ - from .verifier import Verifier, _caller_dir_pycache - # - # If set_unicode(True) was called, insert the UNICODE and - # _UNICODE macro declarations - if self._windows_unicode: - self._apply_windows_unicode(kwargs) - # - # Set the tmpdir here, and not in Verifier.__init__: it picks - # up the caller's directory, which we want to be the caller of - # ffi.verify(), as opposed to the caller of Veritier(). - tmpdir = tmpdir or _caller_dir_pycache() - # - # Make a Verifier() and use it to load the library. - self.verifier = Verifier(self, source, tmpdir, **kwargs) - lib = self.verifier.load_library() - # - # Save the loaded library for keep-alive purposes, even - # if the caller doesn't keep it alive itself (it should). - self._libraries.append(lib) - return lib - - def _get_errno(self): - return self._backend.get_errno() - def _set_errno(self, errno): - self._backend.set_errno(errno) - errno = property(_get_errno, _set_errno, None, - "the value of 'errno' from/to the C calls") - - def getwinerror(self, code=-1): - return self._backend.getwinerror(code) - - def _pointer_to(self, ctype): - with self._lock: - return model.pointer_cache(self, ctype) - - def addressof(self, cdata, *fields_or_indexes): - """Return the address of a . - If 'fields_or_indexes' are given, returns the address of that - field or array item in the structure or array, recursively in - case of nested structures. - """ - try: - ctype = self._backend.typeof(cdata) - except TypeError: - if '__addressof__' in type(cdata).__dict__: - return type(cdata).__addressof__(cdata, *fields_or_indexes) - raise - if fields_or_indexes: - ctype, offset = self._typeoffsetof(ctype, *fields_or_indexes) - else: - if ctype.kind == "pointer": - raise TypeError("addressof(pointer)") - offset = 0 - ctypeptr = self._pointer_to(ctype) - return self._backend.rawaddressof(ctypeptr, cdata, offset) - - def _typeoffsetof(self, ctype, field_or_index, *fields_or_indexes): - ctype, offset = self._backend.typeoffsetof(ctype, field_or_index) - for field1 in fields_or_indexes: - ctype, offset1 = self._backend.typeoffsetof(ctype, field1, 1) - offset += offset1 - return ctype, offset - - def include(self, ffi_to_include): - """Includes the typedefs, structs, unions and enums defined - in another FFI instance. Usage is similar to a #include in C, - where a part of the program might include types defined in - another part for its own usage. Note that the include() - method has no effect on functions, constants and global - variables, which must anyway be accessed directly from the - lib object returned by the original FFI instance. - """ - if not isinstance(ffi_to_include, FFI): - raise TypeError("ffi.include() expects an argument that is also of" - " type cffi.FFI, not %r" % ( - type(ffi_to_include).__name__,)) - if ffi_to_include is self: - raise ValueError("self.include(self)") - with ffi_to_include._lock: - with self._lock: - self._parser.include(ffi_to_include._parser) - self._cdefsources.append('[') - self._cdefsources.extend(ffi_to_include._cdefsources) - self._cdefsources.append(']') - self._included_ffis.append(ffi_to_include) - - def new_handle(self, x): - return self._backend.newp_handle(self.BVoidP, x) - - def from_handle(self, x): - return self._backend.from_handle(x) - - def release(self, x): - self._backend.release(x) - - def set_unicode(self, enabled_flag): - """Windows: if 'enabled_flag' is True, enable the UNICODE and - _UNICODE defines in C, and declare the types like TCHAR and LPTCSTR - to be (pointers to) wchar_t. If 'enabled_flag' is False, - declare these types to be (pointers to) plain 8-bit characters. - This is mostly for backward compatibility; you usually want True. - """ - if self._windows_unicode is not None: - raise ValueError("set_unicode() can only be called once") - enabled_flag = bool(enabled_flag) - if enabled_flag: - self.cdef("typedef wchar_t TBYTE;" - "typedef wchar_t TCHAR;" - "typedef const wchar_t *LPCTSTR;" - "typedef const wchar_t *PCTSTR;" - "typedef wchar_t *LPTSTR;" - "typedef wchar_t *PTSTR;" - "typedef TBYTE *PTBYTE;" - "typedef TCHAR *PTCHAR;") - else: - self.cdef("typedef char TBYTE;" - "typedef char TCHAR;" - "typedef const char *LPCTSTR;" - "typedef const char *PCTSTR;" - "typedef char *LPTSTR;" - "typedef char *PTSTR;" - "typedef TBYTE *PTBYTE;" - "typedef TCHAR *PTCHAR;") - self._windows_unicode = enabled_flag - - def _apply_windows_unicode(self, kwds): - defmacros = kwds.get('define_macros', ()) - if not isinstance(defmacros, (list, tuple)): - raise TypeError("'define_macros' must be a list or tuple") - defmacros = list(defmacros) + [('UNICODE', '1'), - ('_UNICODE', '1')] - kwds['define_macros'] = defmacros - - def _apply_embedding_fix(self, kwds): - # must include an argument like "-lpython2.7" for the compiler - def ensure(key, value): - lst = kwds.setdefault(key, []) - if value not in lst: - lst.append(value) - # - if '__pypy__' in sys.builtin_module_names: - import os - if sys.platform == "win32": - # we need 'libpypy-c.lib'. Current distributions of - # pypy (>= 4.1) contain it as 'libs/python27.lib'. - pythonlib = "python{0[0]}{0[1]}".format(sys.version_info) - if hasattr(sys, 'prefix'): - ensure('library_dirs', os.path.join(sys.prefix, 'libs')) - else: - # we need 'libpypy-c.{so,dylib}', which should be by - # default located in 'sys.prefix/bin' for installed - # systems. - if sys.version_info < (3,): - pythonlib = "pypy-c" - else: - pythonlib = "pypy3-c" - if hasattr(sys, 'prefix'): - ensure('library_dirs', os.path.join(sys.prefix, 'bin')) - # On uninstalled pypy's, the libpypy-c is typically found in - # .../pypy/goal/. - if hasattr(sys, 'prefix'): - ensure('library_dirs', os.path.join(sys.prefix, 'pypy', 'goal')) - else: - if sys.platform == "win32": - template = "python%d%d" - if hasattr(sys, 'gettotalrefcount'): - template += '_d' - else: - try: - import sysconfig - except ImportError: # 2.6 - from cffi._shimmed_dist_utils import sysconfig - template = "python%d.%d" - if sysconfig.get_config_var('DEBUG_EXT'): - template += sysconfig.get_config_var('DEBUG_EXT') - pythonlib = (template % - (sys.hexversion >> 24, (sys.hexversion >> 16) & 0xff)) - if hasattr(sys, 'abiflags'): - pythonlib += sys.abiflags - ensure('libraries', pythonlib) - if sys.platform == "win32": - ensure('extra_link_args', '/MANIFEST') - - def set_source(self, module_name, source, source_extension='.c', **kwds): - import os - if hasattr(self, '_assigned_source'): - raise ValueError("set_source() cannot be called several times " - "per ffi object") - if not isinstance(module_name, basestring): - raise TypeError("'module_name' must be a string") - if os.sep in module_name or (os.altsep and os.altsep in module_name): - raise ValueError("'module_name' must not contain '/': use a dotted " - "name to make a 'package.module' location") - self._assigned_source = (str(module_name), source, - source_extension, kwds) - - def set_source_pkgconfig(self, module_name, pkgconfig_libs, source, - source_extension='.c', **kwds): - from . import pkgconfig - if not isinstance(pkgconfig_libs, list): - raise TypeError("the pkgconfig_libs argument must be a list " - "of package names") - kwds2 = pkgconfig.flags_from_pkgconfig(pkgconfig_libs) - pkgconfig.merge_flags(kwds, kwds2) - self.set_source(module_name, source, source_extension, **kwds) - - def distutils_extension(self, tmpdir='build', verbose=True): - from cffi._shimmed_dist_utils import mkpath - from .recompiler import recompile - # - if not hasattr(self, '_assigned_source'): - if hasattr(self, 'verifier'): # fallback, 'tmpdir' ignored - return self.verifier.get_extension() - raise ValueError("set_source() must be called before" - " distutils_extension()") - module_name, source, source_extension, kwds = self._assigned_source - if source is None: - raise TypeError("distutils_extension() is only for C extension " - "modules, not for dlopen()-style pure Python " - "modules") - mkpath(tmpdir) - ext, updated = recompile(self, module_name, - source, tmpdir=tmpdir, extradir=tmpdir, - source_extension=source_extension, - call_c_compiler=False, **kwds) - if verbose: - if updated: - sys.stderr.write("regenerated: %r\n" % (ext.sources[0],)) - else: - sys.stderr.write("not modified: %r\n" % (ext.sources[0],)) - return ext - - def emit_c_code(self, filename): - from .recompiler import recompile - # - if not hasattr(self, '_assigned_source'): - raise ValueError("set_source() must be called before emit_c_code()") - module_name, source, source_extension, kwds = self._assigned_source - if source is None: - raise TypeError("emit_c_code() is only for C extension modules, " - "not for dlopen()-style pure Python modules") - recompile(self, module_name, source, - c_file=filename, call_c_compiler=False, - uses_ffiplatform=False, **kwds) - - def emit_python_code(self, filename): - from .recompiler import recompile - # - if not hasattr(self, '_assigned_source'): - raise ValueError("set_source() must be called before emit_c_code()") - module_name, source, source_extension, kwds = self._assigned_source - if source is not None: - raise TypeError("emit_python_code() is only for dlopen()-style " - "pure Python modules, not for C extension modules") - recompile(self, module_name, source, - c_file=filename, call_c_compiler=False, - uses_ffiplatform=False, **kwds) - - def compile(self, tmpdir='.', verbose=0, target=None, debug=None): - """The 'target' argument gives the final file name of the - compiled DLL. Use '*' to force distutils' choice, suitable for - regular CPython C API modules. Use a file name ending in '.*' - to ask for the system's default extension for dynamic libraries - (.so/.dll/.dylib). - - The default is '*' when building a non-embedded C API extension, - and (module_name + '.*') when building an embedded library. - """ - from .recompiler import recompile - # - if not hasattr(self, '_assigned_source'): - raise ValueError("set_source() must be called before compile()") - module_name, source, source_extension, kwds = self._assigned_source - return recompile(self, module_name, source, tmpdir=tmpdir, - target=target, source_extension=source_extension, - compiler_verbose=verbose, debug=debug, **kwds) - - def init_once(self, func, tag): - # Read _init_once_cache[tag], which is either (False, lock) if - # we're calling the function now in some thread, or (True, result). - # Don't call setdefault() in most cases, to avoid allocating and - # immediately freeing a lock; but still use setdefaut() to avoid - # races. - try: - x = self._init_once_cache[tag] - except KeyError: - x = self._init_once_cache.setdefault(tag, (False, allocate_lock())) - # Common case: we got (True, result), so we return the result. - if x[0]: - return x[1] - # Else, it's a lock. Acquire it to serialize the following tests. - with x[1]: - # Read again from _init_once_cache the current status. - x = self._init_once_cache[tag] - if x[0]: - return x[1] - # Call the function and store the result back. - result = func() - self._init_once_cache[tag] = (True, result) - return result - - def embedding_init_code(self, pysource): - if self._embedding: - raise ValueError("embedding_init_code() can only be called once") - # fix 'pysource' before it gets dumped into the C file: - # - remove empty lines at the beginning, so it starts at "line 1" - # - dedent, if all non-empty lines are indented - # - check for SyntaxErrors - import re - match = re.match(r'\s*\n', pysource) - if match: - pysource = pysource[match.end():] - lines = pysource.splitlines() or [''] - prefix = re.match(r'\s*', lines[0]).group() - for i in range(1, len(lines)): - line = lines[i] - if line.rstrip(): - while not line.startswith(prefix): - prefix = prefix[:-1] - i = len(prefix) - lines = [line[i:]+'\n' for line in lines] - pysource = ''.join(lines) - # - compile(pysource, "cffi_init", "exec") - # - self._embedding = pysource - - def def_extern(self, *args, **kwds): - raise ValueError("ffi.def_extern() is only available on API-mode FFI " - "objects") - - def list_types(self): - """Returns the user type names known to this FFI instance. - This returns a tuple containing three lists of names: - (typedef_names, names_of_structs, names_of_unions) - """ - typedefs = [] - structs = [] - unions = [] - for key in self._parser._declarations: - if key.startswith('typedef '): - typedefs.append(key[8:]) - elif key.startswith('struct '): - structs.append(key[7:]) - elif key.startswith('union '): - unions.append(key[6:]) - typedefs.sort() - structs.sort() - unions.sort() - return (typedefs, structs, unions) - - -def _load_backend_lib(backend, name, flags): - import os - if not isinstance(name, basestring): - if sys.platform != "win32" or name is not None: - return backend.load_library(name, flags) - name = "c" # Windows: load_library(None) fails, but this works - # on Python 2 (backward compatibility hack only) - first_error = None - if '.' in name or '/' in name or os.sep in name: - try: - return backend.load_library(name, flags) - except OSError as e: - first_error = e - import ctypes.util - path = ctypes.util.find_library(name) - if path is None: - if name == "c" and sys.platform == "win32" and sys.version_info >= (3,): - raise OSError("dlopen(None) cannot work on Windows for Python 3 " - "(see http://bugs.python.org/issue23606)") - msg = ("ctypes.util.find_library() did not manage " - "to locate a library called %r" % (name,)) - if first_error is not None: - msg = "%s. Additionally, %s" % (first_error, msg) - raise OSError(msg) - return backend.load_library(path, flags) - -def _make_ffi_library(ffi, libname, flags): - backend = ffi._backend - backendlib = _load_backend_lib(backend, libname, flags) - # - def accessor_function(name): - key = 'function ' + name - tp, _ = ffi._parser._declarations[key] - BType = ffi._get_cached_btype(tp) - value = backendlib.load_function(BType, name) - library.__dict__[name] = value - # - def accessor_variable(name): - key = 'variable ' + name - tp, _ = ffi._parser._declarations[key] - BType = ffi._get_cached_btype(tp) - read_variable = backendlib.read_variable - write_variable = backendlib.write_variable - setattr(FFILibrary, name, property( - lambda self: read_variable(BType, name), - lambda self, value: write_variable(BType, name, value))) - # - def addressof_var(name): - try: - return addr_variables[name] - except KeyError: - with ffi._lock: - if name not in addr_variables: - key = 'variable ' + name - tp, _ = ffi._parser._declarations[key] - BType = ffi._get_cached_btype(tp) - if BType.kind != 'array': - BType = model.pointer_cache(ffi, BType) - p = backendlib.load_function(BType, name) - addr_variables[name] = p - return addr_variables[name] - # - def accessor_constant(name): - raise NotImplementedError("non-integer constant '%s' cannot be " - "accessed from a dlopen() library" % (name,)) - # - def accessor_int_constant(name): - library.__dict__[name] = ffi._parser._int_constants[name] - # - accessors = {} - accessors_version = [False] - addr_variables = {} - # - def update_accessors(): - if accessors_version[0] is ffi._cdef_version: - return - # - for key, (tp, _) in ffi._parser._declarations.items(): - if not isinstance(tp, model.EnumType): - tag, name = key.split(' ', 1) - if tag == 'function': - accessors[name] = accessor_function - elif tag == 'variable': - accessors[name] = accessor_variable - elif tag == 'constant': - accessors[name] = accessor_constant - else: - for i, enumname in enumerate(tp.enumerators): - def accessor_enum(name, tp=tp, i=i): - tp.check_not_partial() - library.__dict__[name] = tp.enumvalues[i] - accessors[enumname] = accessor_enum - for name in ffi._parser._int_constants: - accessors.setdefault(name, accessor_int_constant) - accessors_version[0] = ffi._cdef_version - # - def make_accessor(name): - with ffi._lock: - if name in library.__dict__ or name in FFILibrary.__dict__: - return # added by another thread while waiting for the lock - if name not in accessors: - update_accessors() - if name not in accessors: - raise AttributeError(name) - accessors[name](name) - # - class FFILibrary(object): - def __getattr__(self, name): - make_accessor(name) - return getattr(self, name) - def __setattr__(self, name, value): - try: - property = getattr(self.__class__, name) - except AttributeError: - make_accessor(name) - setattr(self, name, value) - else: - property.__set__(self, value) - def __dir__(self): - with ffi._lock: - update_accessors() - return accessors.keys() - def __addressof__(self, name): - if name in library.__dict__: - return library.__dict__[name] - if name in FFILibrary.__dict__: - return addressof_var(name) - make_accessor(name) - if name in library.__dict__: - return library.__dict__[name] - if name in FFILibrary.__dict__: - return addressof_var(name) - raise AttributeError("cffi library has no function or " - "global variable named '%s'" % (name,)) - def __cffi_close__(self): - backendlib.close_lib() - self.__dict__.clear() - # - if isinstance(libname, basestring): - try: - if not isinstance(libname, str): # unicode, on Python 2 - libname = libname.encode('utf-8') - FFILibrary.__name__ = 'FFILibrary_%s' % libname - except UnicodeError: - pass - library = FFILibrary() - return library, library.__dict__ - -def _builtin_function_type(func): - # a hack to make at least ffi.typeof(builtin_function) work, - # if the builtin function was obtained by 'vengine_cpy'. - import sys - try: - module = sys.modules[func.__module__] - ffi = module._cffi_original_ffi - types_of_builtin_funcs = module._cffi_types_of_builtin_funcs - tp = types_of_builtin_funcs[func] - except (KeyError, AttributeError, TypeError): - return None - else: - with ffi._lock: - return ffi._get_cached_btype(tp) diff --git a/venv/lib/python3.9/site-packages/cffi/backend_ctypes.py b/venv/lib/python3.9/site-packages/cffi/backend_ctypes.py deleted file mode 100644 index e7956a7..0000000 --- a/venv/lib/python3.9/site-packages/cffi/backend_ctypes.py +++ /dev/null @@ -1,1121 +0,0 @@ -import ctypes, ctypes.util, operator, sys -from . import model - -if sys.version_info < (3,): - bytechr = chr -else: - unicode = str - long = int - xrange = range - bytechr = lambda num: bytes([num]) - -class CTypesType(type): - pass - -class CTypesData(object): - __metaclass__ = CTypesType - __slots__ = ['__weakref__'] - __name__ = '' - - def __init__(self, *args): - raise TypeError("cannot instantiate %r" % (self.__class__,)) - - @classmethod - def _newp(cls, init): - raise TypeError("expected a pointer or array ctype, got '%s'" - % (cls._get_c_name(),)) - - @staticmethod - def _to_ctypes(value): - raise TypeError - - @classmethod - def _arg_to_ctypes(cls, *value): - try: - ctype = cls._ctype - except AttributeError: - raise TypeError("cannot create an instance of %r" % (cls,)) - if value: - res = cls._to_ctypes(*value) - if not isinstance(res, ctype): - res = cls._ctype(res) - else: - res = cls._ctype() - return res - - @classmethod - def _create_ctype_obj(cls, init): - if init is None: - return cls._arg_to_ctypes() - else: - return cls._arg_to_ctypes(init) - - @staticmethod - def _from_ctypes(ctypes_value): - raise TypeError - - @classmethod - def _get_c_name(cls, replace_with=''): - return cls._reftypename.replace(' &', replace_with) - - @classmethod - def _fix_class(cls): - cls.__name__ = 'CData<%s>' % (cls._get_c_name(),) - cls.__qualname__ = 'CData<%s>' % (cls._get_c_name(),) - cls.__module__ = 'ffi' - - def _get_own_repr(self): - raise NotImplementedError - - def _addr_repr(self, address): - if address == 0: - return 'NULL' - else: - if address < 0: - address += 1 << (8*ctypes.sizeof(ctypes.c_void_p)) - return '0x%x' % address - - def __repr__(self, c_name=None): - own = self._get_own_repr() - return '' % (c_name or self._get_c_name(), own) - - def _convert_to_address(self, BClass): - if BClass is None: - raise TypeError("cannot convert %r to an address" % ( - self._get_c_name(),)) - else: - raise TypeError("cannot convert %r to %r" % ( - self._get_c_name(), BClass._get_c_name())) - - @classmethod - def _get_size(cls): - return ctypes.sizeof(cls._ctype) - - def _get_size_of_instance(self): - return ctypes.sizeof(self._ctype) - - @classmethod - def _cast_from(cls, source): - raise TypeError("cannot cast to %r" % (cls._get_c_name(),)) - - def _cast_to_integer(self): - return self._convert_to_address(None) - - @classmethod - def _alignment(cls): - return ctypes.alignment(cls._ctype) - - def __iter__(self): - raise TypeError("cdata %r does not support iteration" % ( - self._get_c_name()),) - - def _make_cmp(name): - cmpfunc = getattr(operator, name) - def cmp(self, other): - v_is_ptr = not isinstance(self, CTypesGenericPrimitive) - w_is_ptr = (isinstance(other, CTypesData) and - not isinstance(other, CTypesGenericPrimitive)) - if v_is_ptr and w_is_ptr: - return cmpfunc(self._convert_to_address(None), - other._convert_to_address(None)) - elif v_is_ptr or w_is_ptr: - return NotImplemented - else: - if isinstance(self, CTypesGenericPrimitive): - self = self._value - if isinstance(other, CTypesGenericPrimitive): - other = other._value - return cmpfunc(self, other) - cmp.func_name = name - return cmp - - __eq__ = _make_cmp('__eq__') - __ne__ = _make_cmp('__ne__') - __lt__ = _make_cmp('__lt__') - __le__ = _make_cmp('__le__') - __gt__ = _make_cmp('__gt__') - __ge__ = _make_cmp('__ge__') - - def __hash__(self): - return hash(self._convert_to_address(None)) - - def _to_string(self, maxlen): - raise TypeError("string(): %r" % (self,)) - - -class CTypesGenericPrimitive(CTypesData): - __slots__ = [] - - def __hash__(self): - return hash(self._value) - - def _get_own_repr(self): - return repr(self._from_ctypes(self._value)) - - -class CTypesGenericArray(CTypesData): - __slots__ = [] - - @classmethod - def _newp(cls, init): - return cls(init) - - def __iter__(self): - for i in xrange(len(self)): - yield self[i] - - def _get_own_repr(self): - return self._addr_repr(ctypes.addressof(self._blob)) - - -class CTypesGenericPtr(CTypesData): - __slots__ = ['_address', '_as_ctype_ptr'] - _automatic_casts = False - kind = "pointer" - - @classmethod - def _newp(cls, init): - return cls(init) - - @classmethod - def _cast_from(cls, source): - if source is None: - address = 0 - elif isinstance(source, CTypesData): - address = source._cast_to_integer() - elif isinstance(source, (int, long)): - address = source - else: - raise TypeError("bad type for cast to %r: %r" % - (cls, type(source).__name__)) - return cls._new_pointer_at(address) - - @classmethod - def _new_pointer_at(cls, address): - self = cls.__new__(cls) - self._address = address - self._as_ctype_ptr = ctypes.cast(address, cls._ctype) - return self - - def _get_own_repr(self): - try: - return self._addr_repr(self._address) - except AttributeError: - return '???' - - def _cast_to_integer(self): - return self._address - - def __nonzero__(self): - return bool(self._address) - __bool__ = __nonzero__ - - @classmethod - def _to_ctypes(cls, value): - if not isinstance(value, CTypesData): - raise TypeError("unexpected %s object" % type(value).__name__) - address = value._convert_to_address(cls) - return ctypes.cast(address, cls._ctype) - - @classmethod - def _from_ctypes(cls, ctypes_ptr): - address = ctypes.cast(ctypes_ptr, ctypes.c_void_p).value or 0 - return cls._new_pointer_at(address) - - @classmethod - def _initialize(cls, ctypes_ptr, value): - if value: - ctypes_ptr.contents = cls._to_ctypes(value).contents - - def _convert_to_address(self, BClass): - if (BClass in (self.__class__, None) or BClass._automatic_casts - or self._automatic_casts): - return self._address - else: - return CTypesData._convert_to_address(self, BClass) - - -class CTypesBaseStructOrUnion(CTypesData): - __slots__ = ['_blob'] - - @classmethod - def _create_ctype_obj(cls, init): - # may be overridden - raise TypeError("cannot instantiate opaque type %s" % (cls,)) - - def _get_own_repr(self): - return self._addr_repr(ctypes.addressof(self._blob)) - - @classmethod - def _offsetof(cls, fieldname): - return getattr(cls._ctype, fieldname).offset - - def _convert_to_address(self, BClass): - if getattr(BClass, '_BItem', None) is self.__class__: - return ctypes.addressof(self._blob) - else: - return CTypesData._convert_to_address(self, BClass) - - @classmethod - def _from_ctypes(cls, ctypes_struct_or_union): - self = cls.__new__(cls) - self._blob = ctypes_struct_or_union - return self - - @classmethod - def _to_ctypes(cls, value): - return value._blob - - def __repr__(self, c_name=None): - return CTypesData.__repr__(self, c_name or self._get_c_name(' &')) - - -class CTypesBackend(object): - - PRIMITIVE_TYPES = { - 'char': ctypes.c_char, - 'short': ctypes.c_short, - 'int': ctypes.c_int, - 'long': ctypes.c_long, - 'long long': ctypes.c_longlong, - 'signed char': ctypes.c_byte, - 'unsigned char': ctypes.c_ubyte, - 'unsigned short': ctypes.c_ushort, - 'unsigned int': ctypes.c_uint, - 'unsigned long': ctypes.c_ulong, - 'unsigned long long': ctypes.c_ulonglong, - 'float': ctypes.c_float, - 'double': ctypes.c_double, - '_Bool': ctypes.c_bool, - } - - for _name in ['unsigned long long', 'unsigned long', - 'unsigned int', 'unsigned short', 'unsigned char']: - _size = ctypes.sizeof(PRIMITIVE_TYPES[_name]) - PRIMITIVE_TYPES['uint%d_t' % (8*_size)] = PRIMITIVE_TYPES[_name] - if _size == ctypes.sizeof(ctypes.c_void_p): - PRIMITIVE_TYPES['uintptr_t'] = PRIMITIVE_TYPES[_name] - if _size == ctypes.sizeof(ctypes.c_size_t): - PRIMITIVE_TYPES['size_t'] = PRIMITIVE_TYPES[_name] - - for _name in ['long long', 'long', 'int', 'short', 'signed char']: - _size = ctypes.sizeof(PRIMITIVE_TYPES[_name]) - PRIMITIVE_TYPES['int%d_t' % (8*_size)] = PRIMITIVE_TYPES[_name] - if _size == ctypes.sizeof(ctypes.c_void_p): - PRIMITIVE_TYPES['intptr_t'] = PRIMITIVE_TYPES[_name] - PRIMITIVE_TYPES['ptrdiff_t'] = PRIMITIVE_TYPES[_name] - if _size == ctypes.sizeof(ctypes.c_size_t): - PRIMITIVE_TYPES['ssize_t'] = PRIMITIVE_TYPES[_name] - - - def __init__(self): - self.RTLD_LAZY = 0 # not supported anyway by ctypes - self.RTLD_NOW = 0 - self.RTLD_GLOBAL = ctypes.RTLD_GLOBAL - self.RTLD_LOCAL = ctypes.RTLD_LOCAL - - def set_ffi(self, ffi): - self.ffi = ffi - - def _get_types(self): - return CTypesData, CTypesType - - def load_library(self, path, flags=0): - cdll = ctypes.CDLL(path, flags) - return CTypesLibrary(self, cdll) - - def new_void_type(self): - class CTypesVoid(CTypesData): - __slots__ = [] - _reftypename = 'void &' - @staticmethod - def _from_ctypes(novalue): - return None - @staticmethod - def _to_ctypes(novalue): - if novalue is not None: - raise TypeError("None expected, got %s object" % - (type(novalue).__name__,)) - return None - CTypesVoid._fix_class() - return CTypesVoid - - def new_primitive_type(self, name): - if name == 'wchar_t': - raise NotImplementedError(name) - ctype = self.PRIMITIVE_TYPES[name] - if name == 'char': - kind = 'char' - elif name in ('float', 'double'): - kind = 'float' - else: - if name in ('signed char', 'unsigned char'): - kind = 'byte' - elif name == '_Bool': - kind = 'bool' - else: - kind = 'int' - is_signed = (ctype(-1).value == -1) - # - def _cast_source_to_int(source): - if isinstance(source, (int, long, float)): - source = int(source) - elif isinstance(source, CTypesData): - source = source._cast_to_integer() - elif isinstance(source, bytes): - source = ord(source) - elif source is None: - source = 0 - else: - raise TypeError("bad type for cast to %r: %r" % - (CTypesPrimitive, type(source).__name__)) - return source - # - kind1 = kind - class CTypesPrimitive(CTypesGenericPrimitive): - __slots__ = ['_value'] - _ctype = ctype - _reftypename = '%s &' % name - kind = kind1 - - def __init__(self, value): - self._value = value - - @staticmethod - def _create_ctype_obj(init): - if init is None: - return ctype() - return ctype(CTypesPrimitive._to_ctypes(init)) - - if kind == 'int' or kind == 'byte': - @classmethod - def _cast_from(cls, source): - source = _cast_source_to_int(source) - source = ctype(source).value # cast within range - return cls(source) - def __int__(self): - return self._value - - if kind == 'bool': - @classmethod - def _cast_from(cls, source): - if not isinstance(source, (int, long, float)): - source = _cast_source_to_int(source) - return cls(bool(source)) - def __int__(self): - return int(self._value) - - if kind == 'char': - @classmethod - def _cast_from(cls, source): - source = _cast_source_to_int(source) - source = bytechr(source & 0xFF) - return cls(source) - def __int__(self): - return ord(self._value) - - if kind == 'float': - @classmethod - def _cast_from(cls, source): - if isinstance(source, float): - pass - elif isinstance(source, CTypesGenericPrimitive): - if hasattr(source, '__float__'): - source = float(source) - else: - source = int(source) - else: - source = _cast_source_to_int(source) - source = ctype(source).value # fix precision - return cls(source) - def __int__(self): - return int(self._value) - def __float__(self): - return self._value - - _cast_to_integer = __int__ - - if kind == 'int' or kind == 'byte' or kind == 'bool': - @staticmethod - def _to_ctypes(x): - if not isinstance(x, (int, long)): - if isinstance(x, CTypesData): - x = int(x) - else: - raise TypeError("integer expected, got %s" % - type(x).__name__) - if ctype(x).value != x: - if not is_signed and x < 0: - raise OverflowError("%s: negative integer" % name) - else: - raise OverflowError("%s: integer out of bounds" - % name) - return x - - if kind == 'char': - @staticmethod - def _to_ctypes(x): - if isinstance(x, bytes) and len(x) == 1: - return x - if isinstance(x, CTypesPrimitive): # > - return x._value - raise TypeError("character expected, got %s" % - type(x).__name__) - def __nonzero__(self): - return ord(self._value) != 0 - else: - def __nonzero__(self): - return self._value != 0 - __bool__ = __nonzero__ - - if kind == 'float': - @staticmethod - def _to_ctypes(x): - if not isinstance(x, (int, long, float, CTypesData)): - raise TypeError("float expected, got %s" % - type(x).__name__) - return ctype(x).value - - @staticmethod - def _from_ctypes(value): - return getattr(value, 'value', value) - - @staticmethod - def _initialize(blob, init): - blob.value = CTypesPrimitive._to_ctypes(init) - - if kind == 'char': - def _to_string(self, maxlen): - return self._value - if kind == 'byte': - def _to_string(self, maxlen): - return chr(self._value & 0xff) - # - CTypesPrimitive._fix_class() - return CTypesPrimitive - - def new_pointer_type(self, BItem): - getbtype = self.ffi._get_cached_btype - if BItem is getbtype(model.PrimitiveType('char')): - kind = 'charp' - elif BItem in (getbtype(model.PrimitiveType('signed char')), - getbtype(model.PrimitiveType('unsigned char'))): - kind = 'bytep' - elif BItem is getbtype(model.void_type): - kind = 'voidp' - else: - kind = 'generic' - # - class CTypesPtr(CTypesGenericPtr): - __slots__ = ['_own'] - if kind == 'charp': - __slots__ += ['__as_strbuf'] - _BItem = BItem - if hasattr(BItem, '_ctype'): - _ctype = ctypes.POINTER(BItem._ctype) - _bitem_size = ctypes.sizeof(BItem._ctype) - else: - _ctype = ctypes.c_void_p - if issubclass(BItem, CTypesGenericArray): - _reftypename = BItem._get_c_name('(* &)') - else: - _reftypename = BItem._get_c_name(' * &') - - def __init__(self, init): - ctypeobj = BItem._create_ctype_obj(init) - if kind == 'charp': - self.__as_strbuf = ctypes.create_string_buffer( - ctypeobj.value + b'\x00') - self._as_ctype_ptr = ctypes.cast( - self.__as_strbuf, self._ctype) - else: - self._as_ctype_ptr = ctypes.pointer(ctypeobj) - self._address = ctypes.cast(self._as_ctype_ptr, - ctypes.c_void_p).value - self._own = True - - def __add__(self, other): - if isinstance(other, (int, long)): - return self._new_pointer_at(self._address + - other * self._bitem_size) - else: - return NotImplemented - - def __sub__(self, other): - if isinstance(other, (int, long)): - return self._new_pointer_at(self._address - - other * self._bitem_size) - elif type(self) is type(other): - return (self._address - other._address) // self._bitem_size - else: - return NotImplemented - - def __getitem__(self, index): - if getattr(self, '_own', False) and index != 0: - raise IndexError - return BItem._from_ctypes(self._as_ctype_ptr[index]) - - def __setitem__(self, index, value): - self._as_ctype_ptr[index] = BItem._to_ctypes(value) - - if kind == 'charp' or kind == 'voidp': - @classmethod - def _arg_to_ctypes(cls, *value): - if value and isinstance(value[0], bytes): - return ctypes.c_char_p(value[0]) - else: - return super(CTypesPtr, cls)._arg_to_ctypes(*value) - - if kind == 'charp' or kind == 'bytep': - def _to_string(self, maxlen): - if maxlen < 0: - maxlen = sys.maxsize - p = ctypes.cast(self._as_ctype_ptr, - ctypes.POINTER(ctypes.c_char)) - n = 0 - while n < maxlen and p[n] != b'\x00': - n += 1 - return b''.join([p[i] for i in range(n)]) - - def _get_own_repr(self): - if getattr(self, '_own', False): - return 'owning %d bytes' % ( - ctypes.sizeof(self._as_ctype_ptr.contents),) - return super(CTypesPtr, self)._get_own_repr() - # - if (BItem is self.ffi._get_cached_btype(model.void_type) or - BItem is self.ffi._get_cached_btype(model.PrimitiveType('char'))): - CTypesPtr._automatic_casts = True - # - CTypesPtr._fix_class() - return CTypesPtr - - def new_array_type(self, CTypesPtr, length): - if length is None: - brackets = ' &[]' - else: - brackets = ' &[%d]' % length - BItem = CTypesPtr._BItem - getbtype = self.ffi._get_cached_btype - if BItem is getbtype(model.PrimitiveType('char')): - kind = 'char' - elif BItem in (getbtype(model.PrimitiveType('signed char')), - getbtype(model.PrimitiveType('unsigned char'))): - kind = 'byte' - else: - kind = 'generic' - # - class CTypesArray(CTypesGenericArray): - __slots__ = ['_blob', '_own'] - if length is not None: - _ctype = BItem._ctype * length - else: - __slots__.append('_ctype') - _reftypename = BItem._get_c_name(brackets) - _declared_length = length - _CTPtr = CTypesPtr - - def __init__(self, init): - if length is None: - if isinstance(init, (int, long)): - len1 = init - init = None - elif kind == 'char' and isinstance(init, bytes): - len1 = len(init) + 1 # extra null - else: - init = tuple(init) - len1 = len(init) - self._ctype = BItem._ctype * len1 - self._blob = self._ctype() - self._own = True - if init is not None: - self._initialize(self._blob, init) - - @staticmethod - def _initialize(blob, init): - if isinstance(init, bytes): - init = [init[i:i+1] for i in range(len(init))] - else: - if isinstance(init, CTypesGenericArray): - if (len(init) != len(blob) or - not isinstance(init, CTypesArray)): - raise TypeError("length/type mismatch: %s" % (init,)) - init = tuple(init) - if len(init) > len(blob): - raise IndexError("too many initializers") - addr = ctypes.cast(blob, ctypes.c_void_p).value - PTR = ctypes.POINTER(BItem._ctype) - itemsize = ctypes.sizeof(BItem._ctype) - for i, value in enumerate(init): - p = ctypes.cast(addr + i * itemsize, PTR) - BItem._initialize(p.contents, value) - - def __len__(self): - return len(self._blob) - - def __getitem__(self, index): - if not (0 <= index < len(self._blob)): - raise IndexError - return BItem._from_ctypes(self._blob[index]) - - def __setitem__(self, index, value): - if not (0 <= index < len(self._blob)): - raise IndexError - self._blob[index] = BItem._to_ctypes(value) - - if kind == 'char' or kind == 'byte': - def _to_string(self, maxlen): - if maxlen < 0: - maxlen = len(self._blob) - p = ctypes.cast(self._blob, - ctypes.POINTER(ctypes.c_char)) - n = 0 - while n < maxlen and p[n] != b'\x00': - n += 1 - return b''.join([p[i] for i in range(n)]) - - def _get_own_repr(self): - if getattr(self, '_own', False): - return 'owning %d bytes' % (ctypes.sizeof(self._blob),) - return super(CTypesArray, self)._get_own_repr() - - def _convert_to_address(self, BClass): - if BClass in (CTypesPtr, None) or BClass._automatic_casts: - return ctypes.addressof(self._blob) - else: - return CTypesData._convert_to_address(self, BClass) - - @staticmethod - def _from_ctypes(ctypes_array): - self = CTypesArray.__new__(CTypesArray) - self._blob = ctypes_array - return self - - @staticmethod - def _arg_to_ctypes(value): - return CTypesPtr._arg_to_ctypes(value) - - def __add__(self, other): - if isinstance(other, (int, long)): - return CTypesPtr._new_pointer_at( - ctypes.addressof(self._blob) + - other * ctypes.sizeof(BItem._ctype)) - else: - return NotImplemented - - @classmethod - def _cast_from(cls, source): - raise NotImplementedError("casting to %r" % ( - cls._get_c_name(),)) - # - CTypesArray._fix_class() - return CTypesArray - - def _new_struct_or_union(self, kind, name, base_ctypes_class): - # - class struct_or_union(base_ctypes_class): - pass - struct_or_union.__name__ = '%s_%s' % (kind, name) - kind1 = kind - # - class CTypesStructOrUnion(CTypesBaseStructOrUnion): - __slots__ = ['_blob'] - _ctype = struct_or_union - _reftypename = '%s &' % (name,) - _kind = kind = kind1 - # - CTypesStructOrUnion._fix_class() - return CTypesStructOrUnion - - def new_struct_type(self, name): - return self._new_struct_or_union('struct', name, ctypes.Structure) - - def new_union_type(self, name): - return self._new_struct_or_union('union', name, ctypes.Union) - - def complete_struct_or_union(self, CTypesStructOrUnion, fields, tp, - totalsize=-1, totalalignment=-1, sflags=0, - pack=0): - if totalsize >= 0 or totalalignment >= 0: - raise NotImplementedError("the ctypes backend of CFFI does not support " - "structures completed by verify(); please " - "compile and install the _cffi_backend module.") - struct_or_union = CTypesStructOrUnion._ctype - fnames = [fname for (fname, BField, bitsize) in fields] - btypes = [BField for (fname, BField, bitsize) in fields] - bitfields = [bitsize for (fname, BField, bitsize) in fields] - # - bfield_types = {} - cfields = [] - for (fname, BField, bitsize) in fields: - if bitsize < 0: - cfields.append((fname, BField._ctype)) - bfield_types[fname] = BField - else: - cfields.append((fname, BField._ctype, bitsize)) - bfield_types[fname] = Ellipsis - if sflags & 8: - struct_or_union._pack_ = 1 - elif pack: - struct_or_union._pack_ = pack - struct_or_union._fields_ = cfields - CTypesStructOrUnion._bfield_types = bfield_types - # - @staticmethod - def _create_ctype_obj(init): - result = struct_or_union() - if init is not None: - initialize(result, init) - return result - CTypesStructOrUnion._create_ctype_obj = _create_ctype_obj - # - def initialize(blob, init): - if is_union: - if len(init) > 1: - raise ValueError("union initializer: %d items given, but " - "only one supported (use a dict if needed)" - % (len(init),)) - if not isinstance(init, dict): - if isinstance(init, (bytes, unicode)): - raise TypeError("union initializer: got a str") - init = tuple(init) - if len(init) > len(fnames): - raise ValueError("too many values for %s initializer" % - CTypesStructOrUnion._get_c_name()) - init = dict(zip(fnames, init)) - addr = ctypes.addressof(blob) - for fname, value in init.items(): - BField, bitsize = name2fieldtype[fname] - assert bitsize < 0, \ - "not implemented: initializer with bit fields" - offset = CTypesStructOrUnion._offsetof(fname) - PTR = ctypes.POINTER(BField._ctype) - p = ctypes.cast(addr + offset, PTR) - BField._initialize(p.contents, value) - is_union = CTypesStructOrUnion._kind == 'union' - name2fieldtype = dict(zip(fnames, zip(btypes, bitfields))) - # - for fname, BField, bitsize in fields: - if fname == '': - raise NotImplementedError("nested anonymous structs/unions") - if hasattr(CTypesStructOrUnion, fname): - raise ValueError("the field name %r conflicts in " - "the ctypes backend" % fname) - if bitsize < 0: - def getter(self, fname=fname, BField=BField, - offset=CTypesStructOrUnion._offsetof(fname), - PTR=ctypes.POINTER(BField._ctype)): - addr = ctypes.addressof(self._blob) - p = ctypes.cast(addr + offset, PTR) - return BField._from_ctypes(p.contents) - def setter(self, value, fname=fname, BField=BField): - setattr(self._blob, fname, BField._to_ctypes(value)) - # - if issubclass(BField, CTypesGenericArray): - setter = None - if BField._declared_length == 0: - def getter(self, fname=fname, BFieldPtr=BField._CTPtr, - offset=CTypesStructOrUnion._offsetof(fname), - PTR=ctypes.POINTER(BField._ctype)): - addr = ctypes.addressof(self._blob) - p = ctypes.cast(addr + offset, PTR) - return BFieldPtr._from_ctypes(p) - # - else: - def getter(self, fname=fname, BField=BField): - return BField._from_ctypes(getattr(self._blob, fname)) - def setter(self, value, fname=fname, BField=BField): - # xxx obscure workaround - value = BField._to_ctypes(value) - oldvalue = getattr(self._blob, fname) - setattr(self._blob, fname, value) - if value != getattr(self._blob, fname): - setattr(self._blob, fname, oldvalue) - raise OverflowError("value too large for bitfield") - setattr(CTypesStructOrUnion, fname, property(getter, setter)) - # - CTypesPtr = self.ffi._get_cached_btype(model.PointerType(tp)) - for fname in fnames: - if hasattr(CTypesPtr, fname): - raise ValueError("the field name %r conflicts in " - "the ctypes backend" % fname) - def getter(self, fname=fname): - return getattr(self[0], fname) - def setter(self, value, fname=fname): - setattr(self[0], fname, value) - setattr(CTypesPtr, fname, property(getter, setter)) - - def new_function_type(self, BArgs, BResult, has_varargs): - nameargs = [BArg._get_c_name() for BArg in BArgs] - if has_varargs: - nameargs.append('...') - nameargs = ', '.join(nameargs) - # - class CTypesFunctionPtr(CTypesGenericPtr): - __slots__ = ['_own_callback', '_name'] - _ctype = ctypes.CFUNCTYPE(getattr(BResult, '_ctype', None), - *[BArg._ctype for BArg in BArgs], - use_errno=True) - _reftypename = BResult._get_c_name('(* &)(%s)' % (nameargs,)) - - def __init__(self, init, error=None): - # create a callback to the Python callable init() - import traceback - assert not has_varargs, "varargs not supported for callbacks" - if getattr(BResult, '_ctype', None) is not None: - error = BResult._from_ctypes( - BResult._create_ctype_obj(error)) - else: - error = None - def callback(*args): - args2 = [] - for arg, BArg in zip(args, BArgs): - args2.append(BArg._from_ctypes(arg)) - try: - res2 = init(*args2) - res2 = BResult._to_ctypes(res2) - except: - traceback.print_exc() - res2 = error - if issubclass(BResult, CTypesGenericPtr): - if res2: - res2 = ctypes.cast(res2, ctypes.c_void_p).value - # .value: http://bugs.python.org/issue1574593 - else: - res2 = None - #print repr(res2) - return res2 - if issubclass(BResult, CTypesGenericPtr): - # The only pointers callbacks can return are void*s: - # http://bugs.python.org/issue5710 - callback_ctype = ctypes.CFUNCTYPE( - ctypes.c_void_p, - *[BArg._ctype for BArg in BArgs], - use_errno=True) - else: - callback_ctype = CTypesFunctionPtr._ctype - self._as_ctype_ptr = callback_ctype(callback) - self._address = ctypes.cast(self._as_ctype_ptr, - ctypes.c_void_p).value - self._own_callback = init - - @staticmethod - def _initialize(ctypes_ptr, value): - if value: - raise NotImplementedError("ctypes backend: not supported: " - "initializers for function pointers") - - def __repr__(self): - c_name = getattr(self, '_name', None) - if c_name: - i = self._reftypename.index('(* &)') - if self._reftypename[i-1] not in ' )*': - c_name = ' ' + c_name - c_name = self._reftypename.replace('(* &)', c_name) - return CTypesData.__repr__(self, c_name) - - def _get_own_repr(self): - if getattr(self, '_own_callback', None) is not None: - return 'calling %r' % (self._own_callback,) - return super(CTypesFunctionPtr, self)._get_own_repr() - - def __call__(self, *args): - if has_varargs: - assert len(args) >= len(BArgs) - extraargs = args[len(BArgs):] - args = args[:len(BArgs)] - else: - assert len(args) == len(BArgs) - ctypes_args = [] - for arg, BArg in zip(args, BArgs): - ctypes_args.append(BArg._arg_to_ctypes(arg)) - if has_varargs: - for i, arg in enumerate(extraargs): - if arg is None: - ctypes_args.append(ctypes.c_void_p(0)) # NULL - continue - if not isinstance(arg, CTypesData): - raise TypeError( - "argument %d passed in the variadic part " - "needs to be a cdata object (got %s)" % - (1 + len(BArgs) + i, type(arg).__name__)) - ctypes_args.append(arg._arg_to_ctypes(arg)) - result = self._as_ctype_ptr(*ctypes_args) - return BResult._from_ctypes(result) - # - CTypesFunctionPtr._fix_class() - return CTypesFunctionPtr - - def new_enum_type(self, name, enumerators, enumvalues, CTypesInt): - assert isinstance(name, str) - reverse_mapping = dict(zip(reversed(enumvalues), - reversed(enumerators))) - # - class CTypesEnum(CTypesInt): - __slots__ = [] - _reftypename = '%s &' % name - - def _get_own_repr(self): - value = self._value - try: - return '%d: %s' % (value, reverse_mapping[value]) - except KeyError: - return str(value) - - def _to_string(self, maxlen): - value = self._value - try: - return reverse_mapping[value] - except KeyError: - return str(value) - # - CTypesEnum._fix_class() - return CTypesEnum - - def get_errno(self): - return ctypes.get_errno() - - def set_errno(self, value): - ctypes.set_errno(value) - - def string(self, b, maxlen=-1): - return b._to_string(maxlen) - - def buffer(self, bptr, size=-1): - raise NotImplementedError("buffer() with ctypes backend") - - def sizeof(self, cdata_or_BType): - if isinstance(cdata_or_BType, CTypesData): - return cdata_or_BType._get_size_of_instance() - else: - assert issubclass(cdata_or_BType, CTypesData) - return cdata_or_BType._get_size() - - def alignof(self, BType): - assert issubclass(BType, CTypesData) - return BType._alignment() - - def newp(self, BType, source): - if not issubclass(BType, CTypesData): - raise TypeError - return BType._newp(source) - - def cast(self, BType, source): - return BType._cast_from(source) - - def callback(self, BType, source, error, onerror): - assert onerror is None # XXX not implemented - return BType(source, error) - - _weakref_cache_ref = None - - def gcp(self, cdata, destructor, size=0): - if self._weakref_cache_ref is None: - import weakref - class MyRef(weakref.ref): - def __eq__(self, other): - myref = self() - return self is other or ( - myref is not None and myref is other()) - def __ne__(self, other): - return not (self == other) - def __hash__(self): - try: - return self._hash - except AttributeError: - self._hash = hash(self()) - return self._hash - self._weakref_cache_ref = {}, MyRef - weak_cache, MyRef = self._weakref_cache_ref - - if destructor is None: - try: - del weak_cache[MyRef(cdata)] - except KeyError: - raise TypeError("Can remove destructor only on a object " - "previously returned by ffi.gc()") - return None - - def remove(k): - cdata, destructor = weak_cache.pop(k, (None, None)) - if destructor is not None: - destructor(cdata) - - new_cdata = self.cast(self.typeof(cdata), cdata) - assert new_cdata is not cdata - weak_cache[MyRef(new_cdata, remove)] = (cdata, destructor) - return new_cdata - - typeof = type - - def getcname(self, BType, replace_with): - return BType._get_c_name(replace_with) - - def typeoffsetof(self, BType, fieldname, num=0): - if isinstance(fieldname, str): - if num == 0 and issubclass(BType, CTypesGenericPtr): - BType = BType._BItem - if not issubclass(BType, CTypesBaseStructOrUnion): - raise TypeError("expected a struct or union ctype") - BField = BType._bfield_types[fieldname] - if BField is Ellipsis: - raise TypeError("not supported for bitfields") - return (BField, BType._offsetof(fieldname)) - elif isinstance(fieldname, (int, long)): - if issubclass(BType, CTypesGenericArray): - BType = BType._CTPtr - if not issubclass(BType, CTypesGenericPtr): - raise TypeError("expected an array or ptr ctype") - BItem = BType._BItem - offset = BItem._get_size() * fieldname - if offset > sys.maxsize: - raise OverflowError - return (BItem, offset) - else: - raise TypeError(type(fieldname)) - - def rawaddressof(self, BTypePtr, cdata, offset=None): - if isinstance(cdata, CTypesBaseStructOrUnion): - ptr = ctypes.pointer(type(cdata)._to_ctypes(cdata)) - elif isinstance(cdata, CTypesGenericPtr): - if offset is None or not issubclass(type(cdata)._BItem, - CTypesBaseStructOrUnion): - raise TypeError("unexpected cdata type") - ptr = type(cdata)._to_ctypes(cdata) - elif isinstance(cdata, CTypesGenericArray): - ptr = type(cdata)._to_ctypes(cdata) - else: - raise TypeError("expected a ") - if offset: - ptr = ctypes.cast( - ctypes.c_void_p( - ctypes.cast(ptr, ctypes.c_void_p).value + offset), - type(ptr)) - return BTypePtr._from_ctypes(ptr) - - -class CTypesLibrary(object): - - def __init__(self, backend, cdll): - self.backend = backend - self.cdll = cdll - - def load_function(self, BType, name): - c_func = getattr(self.cdll, name) - funcobj = BType._from_ctypes(c_func) - funcobj._name = name - return funcobj - - def read_variable(self, BType, name): - try: - ctypes_obj = BType._ctype.in_dll(self.cdll, name) - except AttributeError as e: - raise NotImplementedError(e) - return BType._from_ctypes(ctypes_obj) - - def write_variable(self, BType, name, value): - new_ctypes_obj = BType._to_ctypes(value) - ctypes_obj = BType._ctype.in_dll(self.cdll, name) - ctypes.memmove(ctypes.addressof(ctypes_obj), - ctypes.addressof(new_ctypes_obj), - ctypes.sizeof(BType._ctype)) diff --git a/venv/lib/python3.9/site-packages/cffi/cffi_opcode.py b/venv/lib/python3.9/site-packages/cffi/cffi_opcode.py deleted file mode 100644 index 6421df6..0000000 --- a/venv/lib/python3.9/site-packages/cffi/cffi_opcode.py +++ /dev/null @@ -1,187 +0,0 @@ -from .error import VerificationError - -class CffiOp(object): - def __init__(self, op, arg): - self.op = op - self.arg = arg - - def as_c_expr(self): - if self.op is None: - assert isinstance(self.arg, str) - return '(_cffi_opcode_t)(%s)' % (self.arg,) - classname = CLASS_NAME[self.op] - return '_CFFI_OP(_CFFI_OP_%s, %s)' % (classname, self.arg) - - def as_python_bytes(self): - if self.op is None and self.arg.isdigit(): - value = int(self.arg) # non-negative: '-' not in self.arg - if value >= 2**31: - raise OverflowError("cannot emit %r: limited to 2**31-1" - % (self.arg,)) - return format_four_bytes(value) - if isinstance(self.arg, str): - raise VerificationError("cannot emit to Python: %r" % (self.arg,)) - return format_four_bytes((self.arg << 8) | self.op) - - def __str__(self): - classname = CLASS_NAME.get(self.op, self.op) - return '(%s %s)' % (classname, self.arg) - -def format_four_bytes(num): - return '\\x%02X\\x%02X\\x%02X\\x%02X' % ( - (num >> 24) & 0xFF, - (num >> 16) & 0xFF, - (num >> 8) & 0xFF, - (num ) & 0xFF) - -OP_PRIMITIVE = 1 -OP_POINTER = 3 -OP_ARRAY = 5 -OP_OPEN_ARRAY = 7 -OP_STRUCT_UNION = 9 -OP_ENUM = 11 -OP_FUNCTION = 13 -OP_FUNCTION_END = 15 -OP_NOOP = 17 -OP_BITFIELD = 19 -OP_TYPENAME = 21 -OP_CPYTHON_BLTN_V = 23 # varargs -OP_CPYTHON_BLTN_N = 25 # noargs -OP_CPYTHON_BLTN_O = 27 # O (i.e. a single arg) -OP_CONSTANT = 29 -OP_CONSTANT_INT = 31 -OP_GLOBAL_VAR = 33 -OP_DLOPEN_FUNC = 35 -OP_DLOPEN_CONST = 37 -OP_GLOBAL_VAR_F = 39 -OP_EXTERN_PYTHON = 41 - -PRIM_VOID = 0 -PRIM_BOOL = 1 -PRIM_CHAR = 2 -PRIM_SCHAR = 3 -PRIM_UCHAR = 4 -PRIM_SHORT = 5 -PRIM_USHORT = 6 -PRIM_INT = 7 -PRIM_UINT = 8 -PRIM_LONG = 9 -PRIM_ULONG = 10 -PRIM_LONGLONG = 11 -PRIM_ULONGLONG = 12 -PRIM_FLOAT = 13 -PRIM_DOUBLE = 14 -PRIM_LONGDOUBLE = 15 - -PRIM_WCHAR = 16 -PRIM_INT8 = 17 -PRIM_UINT8 = 18 -PRIM_INT16 = 19 -PRIM_UINT16 = 20 -PRIM_INT32 = 21 -PRIM_UINT32 = 22 -PRIM_INT64 = 23 -PRIM_UINT64 = 24 -PRIM_INTPTR = 25 -PRIM_UINTPTR = 26 -PRIM_PTRDIFF = 27 -PRIM_SIZE = 28 -PRIM_SSIZE = 29 -PRIM_INT_LEAST8 = 30 -PRIM_UINT_LEAST8 = 31 -PRIM_INT_LEAST16 = 32 -PRIM_UINT_LEAST16 = 33 -PRIM_INT_LEAST32 = 34 -PRIM_UINT_LEAST32 = 35 -PRIM_INT_LEAST64 = 36 -PRIM_UINT_LEAST64 = 37 -PRIM_INT_FAST8 = 38 -PRIM_UINT_FAST8 = 39 -PRIM_INT_FAST16 = 40 -PRIM_UINT_FAST16 = 41 -PRIM_INT_FAST32 = 42 -PRIM_UINT_FAST32 = 43 -PRIM_INT_FAST64 = 44 -PRIM_UINT_FAST64 = 45 -PRIM_INTMAX = 46 -PRIM_UINTMAX = 47 -PRIM_FLOATCOMPLEX = 48 -PRIM_DOUBLECOMPLEX = 49 -PRIM_CHAR16 = 50 -PRIM_CHAR32 = 51 - -_NUM_PRIM = 52 -_UNKNOWN_PRIM = -1 -_UNKNOWN_FLOAT_PRIM = -2 -_UNKNOWN_LONG_DOUBLE = -3 - -_IO_FILE_STRUCT = -1 - -PRIMITIVE_TO_INDEX = { - 'char': PRIM_CHAR, - 'short': PRIM_SHORT, - 'int': PRIM_INT, - 'long': PRIM_LONG, - 'long long': PRIM_LONGLONG, - 'signed char': PRIM_SCHAR, - 'unsigned char': PRIM_UCHAR, - 'unsigned short': PRIM_USHORT, - 'unsigned int': PRIM_UINT, - 'unsigned long': PRIM_ULONG, - 'unsigned long long': PRIM_ULONGLONG, - 'float': PRIM_FLOAT, - 'double': PRIM_DOUBLE, - 'long double': PRIM_LONGDOUBLE, - '_cffi_float_complex_t': PRIM_FLOATCOMPLEX, - '_cffi_double_complex_t': PRIM_DOUBLECOMPLEX, - '_Bool': PRIM_BOOL, - 'wchar_t': PRIM_WCHAR, - 'char16_t': PRIM_CHAR16, - 'char32_t': PRIM_CHAR32, - 'int8_t': PRIM_INT8, - 'uint8_t': PRIM_UINT8, - 'int16_t': PRIM_INT16, - 'uint16_t': PRIM_UINT16, - 'int32_t': PRIM_INT32, - 'uint32_t': PRIM_UINT32, - 'int64_t': PRIM_INT64, - 'uint64_t': PRIM_UINT64, - 'intptr_t': PRIM_INTPTR, - 'uintptr_t': PRIM_UINTPTR, - 'ptrdiff_t': PRIM_PTRDIFF, - 'size_t': PRIM_SIZE, - 'ssize_t': PRIM_SSIZE, - 'int_least8_t': PRIM_INT_LEAST8, - 'uint_least8_t': PRIM_UINT_LEAST8, - 'int_least16_t': PRIM_INT_LEAST16, - 'uint_least16_t': PRIM_UINT_LEAST16, - 'int_least32_t': PRIM_INT_LEAST32, - 'uint_least32_t': PRIM_UINT_LEAST32, - 'int_least64_t': PRIM_INT_LEAST64, - 'uint_least64_t': PRIM_UINT_LEAST64, - 'int_fast8_t': PRIM_INT_FAST8, - 'uint_fast8_t': PRIM_UINT_FAST8, - 'int_fast16_t': PRIM_INT_FAST16, - 'uint_fast16_t': PRIM_UINT_FAST16, - 'int_fast32_t': PRIM_INT_FAST32, - 'uint_fast32_t': PRIM_UINT_FAST32, - 'int_fast64_t': PRIM_INT_FAST64, - 'uint_fast64_t': PRIM_UINT_FAST64, - 'intmax_t': PRIM_INTMAX, - 'uintmax_t': PRIM_UINTMAX, - } - -F_UNION = 0x01 -F_CHECK_FIELDS = 0x02 -F_PACKED = 0x04 -F_EXTERNAL = 0x08 -F_OPAQUE = 0x10 - -G_FLAGS = dict([('_CFFI_' + _key, globals()[_key]) - for _key in ['F_UNION', 'F_CHECK_FIELDS', 'F_PACKED', - 'F_EXTERNAL', 'F_OPAQUE']]) - -CLASS_NAME = {} -for _name, _value in list(globals().items()): - if _name.startswith('OP_') and isinstance(_value, int): - CLASS_NAME[_value] = _name[3:] diff --git a/venv/lib/python3.9/site-packages/cffi/commontypes.py b/venv/lib/python3.9/site-packages/cffi/commontypes.py deleted file mode 100644 index d4dae35..0000000 --- a/venv/lib/python3.9/site-packages/cffi/commontypes.py +++ /dev/null @@ -1,82 +0,0 @@ -import sys -from . import model -from .error import FFIError - - -COMMON_TYPES = {} - -try: - # fetch "bool" and all simple Windows types - from _cffi_backend import _get_common_types - _get_common_types(COMMON_TYPES) -except ImportError: - pass - -COMMON_TYPES['FILE'] = model.unknown_type('FILE', '_IO_FILE') -COMMON_TYPES['bool'] = '_Bool' # in case we got ImportError above -COMMON_TYPES['float _Complex'] = '_cffi_float_complex_t' -COMMON_TYPES['double _Complex'] = '_cffi_double_complex_t' - -for _type in model.PrimitiveType.ALL_PRIMITIVE_TYPES: - if _type.endswith('_t'): - COMMON_TYPES[_type] = _type -del _type - -_CACHE = {} - -def resolve_common_type(parser, commontype): - try: - return _CACHE[commontype] - except KeyError: - cdecl = COMMON_TYPES.get(commontype, commontype) - if not isinstance(cdecl, str): - result, quals = cdecl, 0 # cdecl is already a BaseType - elif cdecl in model.PrimitiveType.ALL_PRIMITIVE_TYPES: - result, quals = model.PrimitiveType(cdecl), 0 - elif cdecl == 'set-unicode-needed': - raise FFIError("The Windows type %r is only available after " - "you call ffi.set_unicode()" % (commontype,)) - else: - if commontype == cdecl: - raise FFIError( - "Unsupported type: %r. Please look at " - "http://cffi.readthedocs.io/en/latest/cdef.html#ffi-cdef-limitations " - "and file an issue if you think this type should really " - "be supported." % (commontype,)) - result, quals = parser.parse_type_and_quals(cdecl) # recursive - - assert isinstance(result, model.BaseTypeByIdentity) - _CACHE[commontype] = result, quals - return result, quals - - -# ____________________________________________________________ -# extra types for Windows (most of them are in commontypes.c) - - -def win_common_types(): - return { - "UNICODE_STRING": model.StructType( - "_UNICODE_STRING", - ["Length", - "MaximumLength", - "Buffer"], - [model.PrimitiveType("unsigned short"), - model.PrimitiveType("unsigned short"), - model.PointerType(model.PrimitiveType("wchar_t"))], - [-1, -1, -1]), - "PUNICODE_STRING": "UNICODE_STRING *", - "PCUNICODE_STRING": "const UNICODE_STRING *", - - "TBYTE": "set-unicode-needed", - "TCHAR": "set-unicode-needed", - "LPCTSTR": "set-unicode-needed", - "PCTSTR": "set-unicode-needed", - "LPTSTR": "set-unicode-needed", - "PTSTR": "set-unicode-needed", - "PTBYTE": "set-unicode-needed", - "PTCHAR": "set-unicode-needed", - } - -if sys.platform == 'win32': - COMMON_TYPES.update(win_common_types()) diff --git a/venv/lib/python3.9/site-packages/cffi/cparser.py b/venv/lib/python3.9/site-packages/cffi/cparser.py deleted file mode 100644 index dd590d8..0000000 --- a/venv/lib/python3.9/site-packages/cffi/cparser.py +++ /dev/null @@ -1,1015 +0,0 @@ -from . import model -from .commontypes import COMMON_TYPES, resolve_common_type -from .error import FFIError, CDefError -try: - from . import _pycparser as pycparser -except ImportError: - import pycparser -import weakref, re, sys - -try: - if sys.version_info < (3,): - import thread as _thread - else: - import _thread - lock = _thread.allocate_lock() -except ImportError: - lock = None - -def _workaround_for_static_import_finders(): - # Issue #392: packaging tools like cx_Freeze can not find these - # because pycparser uses exec dynamic import. This is an obscure - # workaround. This function is never called. - import pycparser.yacctab - import pycparser.lextab - -CDEF_SOURCE_STRING = "" -_r_comment = re.compile(r"/\*.*?\*/|//([^\n\\]|\\.)*?$", - re.DOTALL | re.MULTILINE) -_r_define = re.compile(r"^\s*#\s*define\s+([A-Za-z_][A-Za-z_0-9]*)" - r"\b((?:[^\n\\]|\\.)*?)$", - re.DOTALL | re.MULTILINE) -_r_line_directive = re.compile(r"^[ \t]*#[ \t]*(?:line|\d+)\b.*$", re.MULTILINE) -_r_partial_enum = re.compile(r"=\s*\.\.\.\s*[,}]|\.\.\.\s*\}") -_r_enum_dotdotdot = re.compile(r"__dotdotdot\d+__$") -_r_partial_array = re.compile(r"\[\s*\.\.\.\s*\]") -_r_words = re.compile(r"\w+|\S") -_parser_cache = None -_r_int_literal = re.compile(r"-?0?x?[0-9a-f]+[lu]*$", re.IGNORECASE) -_r_stdcall1 = re.compile(r"\b(__stdcall|WINAPI)\b") -_r_stdcall2 = re.compile(r"[(]\s*(__stdcall|WINAPI)\b") -_r_cdecl = re.compile(r"\b__cdecl\b") -_r_extern_python = re.compile(r'\bextern\s*"' - r'(Python|Python\s*\+\s*C|C\s*\+\s*Python)"\s*.') -_r_star_const_space = re.compile( # matches "* const " - r"[*]\s*((const|volatile|restrict)\b\s*)+") -_r_int_dotdotdot = re.compile(r"(\b(int|long|short|signed|unsigned|char)\s*)+" - r"\.\.\.") -_r_float_dotdotdot = re.compile(r"\b(double|float)\s*\.\.\.") - -def _get_parser(): - global _parser_cache - if _parser_cache is None: - _parser_cache = pycparser.CParser() - return _parser_cache - -def _workaround_for_old_pycparser(csource): - # Workaround for a pycparser issue (fixed between pycparser 2.10 and - # 2.14): "char*const***" gives us a wrong syntax tree, the same as - # for "char***(*const)". This means we can't tell the difference - # afterwards. But "char(*const(***))" gives us the right syntax - # tree. The issue only occurs if there are several stars in - # sequence with no parenthesis in between, just possibly qualifiers. - # Attempt to fix it by adding some parentheses in the source: each - # time we see "* const" or "* const *", we add an opening - # parenthesis before each star---the hard part is figuring out where - # to close them. - parts = [] - while True: - match = _r_star_const_space.search(csource) - if not match: - break - #print repr(''.join(parts)+csource), '=>', - parts.append(csource[:match.start()]) - parts.append('('); closing = ')' - parts.append(match.group()) # e.g. "* const " - endpos = match.end() - if csource.startswith('*', endpos): - parts.append('('); closing += ')' - level = 0 - i = endpos - while i < len(csource): - c = csource[i] - if c == '(': - level += 1 - elif c == ')': - if level == 0: - break - level -= 1 - elif c in ',;=': - if level == 0: - break - i += 1 - csource = csource[endpos:i] + closing + csource[i:] - #print repr(''.join(parts)+csource) - parts.append(csource) - return ''.join(parts) - -def _preprocess_extern_python(csource): - # input: `extern "Python" int foo(int);` or - # `extern "Python" { int foo(int); }` - # output: - # void __cffi_extern_python_start; - # int foo(int); - # void __cffi_extern_python_stop; - # - # input: `extern "Python+C" int foo(int);` - # output: - # void __cffi_extern_python_plus_c_start; - # int foo(int); - # void __cffi_extern_python_stop; - parts = [] - while True: - match = _r_extern_python.search(csource) - if not match: - break - endpos = match.end() - 1 - #print - #print ''.join(parts)+csource - #print '=>' - parts.append(csource[:match.start()]) - if 'C' in match.group(1): - parts.append('void __cffi_extern_python_plus_c_start; ') - else: - parts.append('void __cffi_extern_python_start; ') - if csource[endpos] == '{': - # grouping variant - closing = csource.find('}', endpos) - if closing < 0: - raise CDefError("'extern \"Python\" {': no '}' found") - if csource.find('{', endpos + 1, closing) >= 0: - raise NotImplementedError("cannot use { } inside a block " - "'extern \"Python\" { ... }'") - parts.append(csource[endpos+1:closing]) - csource = csource[closing+1:] - else: - # non-grouping variant - semicolon = csource.find(';', endpos) - if semicolon < 0: - raise CDefError("'extern \"Python\": no ';' found") - parts.append(csource[endpos:semicolon+1]) - csource = csource[semicolon+1:] - parts.append(' void __cffi_extern_python_stop;') - #print ''.join(parts)+csource - #print - parts.append(csource) - return ''.join(parts) - -def _warn_for_string_literal(csource): - if '"' not in csource: - return - for line in csource.splitlines(): - if '"' in line and not line.lstrip().startswith('#'): - import warnings - warnings.warn("String literal found in cdef() or type source. " - "String literals are ignored here, but you should " - "remove them anyway because some character sequences " - "confuse pre-parsing.") - break - -def _warn_for_non_extern_non_static_global_variable(decl): - if not decl.storage: - import warnings - warnings.warn("Global variable '%s' in cdef(): for consistency " - "with C it should have a storage class specifier " - "(usually 'extern')" % (decl.name,)) - -def _remove_line_directives(csource): - # _r_line_directive matches whole lines, without the final \n, if they - # start with '#line' with some spacing allowed, or '#NUMBER'. This - # function stores them away and replaces them with exactly the string - # '#line@N', where N is the index in the list 'line_directives'. - line_directives = [] - def replace(m): - i = len(line_directives) - line_directives.append(m.group()) - return '#line@%d' % i - csource = _r_line_directive.sub(replace, csource) - return csource, line_directives - -def _put_back_line_directives(csource, line_directives): - def replace(m): - s = m.group() - if not s.startswith('#line@'): - raise AssertionError("unexpected #line directive " - "(should have been processed and removed") - return line_directives[int(s[6:])] - return _r_line_directive.sub(replace, csource) - -def _preprocess(csource): - # First, remove the lines of the form '#line N "filename"' because - # the "filename" part could confuse the rest - csource, line_directives = _remove_line_directives(csource) - # Remove comments. NOTE: this only work because the cdef() section - # should not contain any string literals (except in line directives)! - def replace_keeping_newlines(m): - return ' ' + m.group().count('\n') * '\n' - csource = _r_comment.sub(replace_keeping_newlines, csource) - # Remove the "#define FOO x" lines - macros = {} - for match in _r_define.finditer(csource): - macroname, macrovalue = match.groups() - macrovalue = macrovalue.replace('\\\n', '').strip() - macros[macroname] = macrovalue - csource = _r_define.sub('', csource) - # - if pycparser.__version__ < '2.14': - csource = _workaround_for_old_pycparser(csource) - # - # BIG HACK: replace WINAPI or __stdcall with "volatile const". - # It doesn't make sense for the return type of a function to be - # "volatile volatile const", so we abuse it to detect __stdcall... - # Hack number 2 is that "int(volatile *fptr)();" is not valid C - # syntax, so we place the "volatile" before the opening parenthesis. - csource = _r_stdcall2.sub(' volatile volatile const(', csource) - csource = _r_stdcall1.sub(' volatile volatile const ', csource) - csource = _r_cdecl.sub(' ', csource) - # - # Replace `extern "Python"` with start/end markers - csource = _preprocess_extern_python(csource) - # - # Now there should not be any string literal left; warn if we get one - _warn_for_string_literal(csource) - # - # Replace "[...]" with "[__dotdotdotarray__]" - csource = _r_partial_array.sub('[__dotdotdotarray__]', csource) - # - # Replace "...}" with "__dotdotdotNUM__}". This construction should - # occur only at the end of enums; at the end of structs we have "...;}" - # and at the end of vararg functions "...);". Also replace "=...[,}]" - # with ",__dotdotdotNUM__[,}]": this occurs in the enums too, when - # giving an unknown value. - matches = list(_r_partial_enum.finditer(csource)) - for number, match in enumerate(reversed(matches)): - p = match.start() - if csource[p] == '=': - p2 = csource.find('...', p, match.end()) - assert p2 > p - csource = '%s,__dotdotdot%d__ %s' % (csource[:p], number, - csource[p2+3:]) - else: - assert csource[p:p+3] == '...' - csource = '%s __dotdotdot%d__ %s' % (csource[:p], number, - csource[p+3:]) - # Replace "int ..." or "unsigned long int..." with "__dotdotdotint__" - csource = _r_int_dotdotdot.sub(' __dotdotdotint__ ', csource) - # Replace "float ..." or "double..." with "__dotdotdotfloat__" - csource = _r_float_dotdotdot.sub(' __dotdotdotfloat__ ', csource) - # Replace all remaining "..." with the same name, "__dotdotdot__", - # which is declared with a typedef for the purpose of C parsing. - csource = csource.replace('...', ' __dotdotdot__ ') - # Finally, put back the line directives - csource = _put_back_line_directives(csource, line_directives) - return csource, macros - -def _common_type_names(csource): - # Look in the source for what looks like usages of types from the - # list of common types. A "usage" is approximated here as the - # appearance of the word, minus a "definition" of the type, which - # is the last word in a "typedef" statement. Approximative only - # but should be fine for all the common types. - look_for_words = set(COMMON_TYPES) - look_for_words.add(';') - look_for_words.add(',') - look_for_words.add('(') - look_for_words.add(')') - look_for_words.add('typedef') - words_used = set() - is_typedef = False - paren = 0 - previous_word = '' - for word in _r_words.findall(csource): - if word in look_for_words: - if word == ';': - if is_typedef: - words_used.discard(previous_word) - look_for_words.discard(previous_word) - is_typedef = False - elif word == 'typedef': - is_typedef = True - paren = 0 - elif word == '(': - paren += 1 - elif word == ')': - paren -= 1 - elif word == ',': - if is_typedef and paren == 0: - words_used.discard(previous_word) - look_for_words.discard(previous_word) - else: # word in COMMON_TYPES - words_used.add(word) - previous_word = word - return words_used - - -class Parser(object): - - def __init__(self): - self._declarations = {} - self._included_declarations = set() - self._anonymous_counter = 0 - self._structnode2type = weakref.WeakKeyDictionary() - self._options = {} - self._int_constants = {} - self._recomplete = [] - self._uses_new_feature = None - - def _parse(self, csource): - csource, macros = _preprocess(csource) - # XXX: for more efficiency we would need to poke into the - # internals of CParser... the following registers the - # typedefs, because their presence or absence influences the - # parsing itself (but what they are typedef'ed to plays no role) - ctn = _common_type_names(csource) - typenames = [] - for name in sorted(self._declarations): - if name.startswith('typedef '): - name = name[8:] - typenames.append(name) - ctn.discard(name) - typenames += sorted(ctn) - # - csourcelines = [] - csourcelines.append('# 1 ""') - for typename in typenames: - csourcelines.append('typedef int %s;' % typename) - csourcelines.append('typedef int __dotdotdotint__, __dotdotdotfloat__,' - ' __dotdotdot__;') - # this forces pycparser to consider the following in the file - # called from line 1 - csourcelines.append('# 1 "%s"' % (CDEF_SOURCE_STRING,)) - csourcelines.append(csource) - csourcelines.append('') # see test_missing_newline_bug - fullcsource = '\n'.join(csourcelines) - if lock is not None: - lock.acquire() # pycparser is not thread-safe... - try: - ast = _get_parser().parse(fullcsource) - except pycparser.c_parser.ParseError as e: - self.convert_pycparser_error(e, csource) - finally: - if lock is not None: - lock.release() - # csource will be used to find buggy source text - return ast, macros, csource - - def _convert_pycparser_error(self, e, csource): - # xxx look for ":NUM:" at the start of str(e) - # and interpret that as a line number. This will not work if - # the user gives explicit ``# NUM "FILE"`` directives. - line = None - msg = str(e) - match = re.match(r"%s:(\d+):" % (CDEF_SOURCE_STRING,), msg) - if match: - linenum = int(match.group(1), 10) - csourcelines = csource.splitlines() - if 1 <= linenum <= len(csourcelines): - line = csourcelines[linenum-1] - return line - - def convert_pycparser_error(self, e, csource): - line = self._convert_pycparser_error(e, csource) - - msg = str(e) - if line: - msg = 'cannot parse "%s"\n%s' % (line.strip(), msg) - else: - msg = 'parse error\n%s' % (msg,) - raise CDefError(msg) - - def parse(self, csource, override=False, packed=False, pack=None, - dllexport=False): - if packed: - if packed != True: - raise ValueError("'packed' should be False or True; use " - "'pack' to give another value") - if pack: - raise ValueError("cannot give both 'pack' and 'packed'") - pack = 1 - elif pack: - if pack & (pack - 1): - raise ValueError("'pack' must be a power of two, not %r" % - (pack,)) - else: - pack = 0 - prev_options = self._options - try: - self._options = {'override': override, - 'packed': pack, - 'dllexport': dllexport} - self._internal_parse(csource) - finally: - self._options = prev_options - - def _internal_parse(self, csource): - ast, macros, csource = self._parse(csource) - # add the macros - self._process_macros(macros) - # find the first "__dotdotdot__" and use that as a separator - # between the repeated typedefs and the real csource - iterator = iter(ast.ext) - for decl in iterator: - if decl.name == '__dotdotdot__': - break - else: - assert 0 - current_decl = None - # - try: - self._inside_extern_python = '__cffi_extern_python_stop' - for decl in iterator: - current_decl = decl - if isinstance(decl, pycparser.c_ast.Decl): - self._parse_decl(decl) - elif isinstance(decl, pycparser.c_ast.Typedef): - if not decl.name: - raise CDefError("typedef does not declare any name", - decl) - quals = 0 - if (isinstance(decl.type.type, pycparser.c_ast.IdentifierType) and - decl.type.type.names[-1].startswith('__dotdotdot')): - realtype = self._get_unknown_type(decl) - elif (isinstance(decl.type, pycparser.c_ast.PtrDecl) and - isinstance(decl.type.type, pycparser.c_ast.TypeDecl) and - isinstance(decl.type.type.type, - pycparser.c_ast.IdentifierType) and - decl.type.type.type.names[-1].startswith('__dotdotdot')): - realtype = self._get_unknown_ptr_type(decl) - else: - realtype, quals = self._get_type_and_quals( - decl.type, name=decl.name, partial_length_ok=True, - typedef_example="*(%s *)0" % (decl.name,)) - self._declare('typedef ' + decl.name, realtype, quals=quals) - elif decl.__class__.__name__ == 'Pragma': - # skip pragma, only in pycparser 2.15 - import warnings - warnings.warn( - "#pragma in cdef() are entirely ignored. " - "They should be removed for now, otherwise your " - "code might behave differently in a future version " - "of CFFI if #pragma support gets added. Note that " - "'#pragma pack' needs to be replaced with the " - "'packed' keyword argument to cdef().") - else: - raise CDefError("unexpected <%s>: this construct is valid " - "C but not valid in cdef()" % - decl.__class__.__name__, decl) - except CDefError as e: - if len(e.args) == 1: - e.args = e.args + (current_decl,) - raise - except FFIError as e: - msg = self._convert_pycparser_error(e, csource) - if msg: - e.args = (e.args[0] + "\n *** Err: %s" % msg,) - raise - - def _add_constants(self, key, val): - if key in self._int_constants: - if self._int_constants[key] == val: - return # ignore identical double declarations - raise FFIError( - "multiple declarations of constant: %s" % (key,)) - self._int_constants[key] = val - - def _add_integer_constant(self, name, int_str): - int_str = int_str.lower().rstrip("ul") - neg = int_str.startswith('-') - if neg: - int_str = int_str[1:] - # "010" is not valid oct in py3 - if (int_str.startswith("0") and int_str != '0' - and not int_str.startswith("0x")): - int_str = "0o" + int_str[1:] - pyvalue = int(int_str, 0) - if neg: - pyvalue = -pyvalue - self._add_constants(name, pyvalue) - self._declare('macro ' + name, pyvalue) - - def _process_macros(self, macros): - for key, value in macros.items(): - value = value.strip() - if _r_int_literal.match(value): - self._add_integer_constant(key, value) - elif value == '...': - self._declare('macro ' + key, value) - else: - raise CDefError( - 'only supports one of the following syntax:\n' - ' #define %s ... (literally dot-dot-dot)\n' - ' #define %s NUMBER (with NUMBER an integer' - ' constant, decimal/hex/octal)\n' - 'got:\n' - ' #define %s %s' - % (key, key, key, value)) - - def _declare_function(self, tp, quals, decl): - tp = self._get_type_pointer(tp, quals) - if self._options.get('dllexport'): - tag = 'dllexport_python ' - elif self._inside_extern_python == '__cffi_extern_python_start': - tag = 'extern_python ' - elif self._inside_extern_python == '__cffi_extern_python_plus_c_start': - tag = 'extern_python_plus_c ' - else: - tag = 'function ' - self._declare(tag + decl.name, tp) - - def _parse_decl(self, decl): - node = decl.type - if isinstance(node, pycparser.c_ast.FuncDecl): - tp, quals = self._get_type_and_quals(node, name=decl.name) - assert isinstance(tp, model.RawFunctionType) - self._declare_function(tp, quals, decl) - else: - if isinstance(node, pycparser.c_ast.Struct): - self._get_struct_union_enum_type('struct', node) - elif isinstance(node, pycparser.c_ast.Union): - self._get_struct_union_enum_type('union', node) - elif isinstance(node, pycparser.c_ast.Enum): - self._get_struct_union_enum_type('enum', node) - elif not decl.name: - raise CDefError("construct does not declare any variable", - decl) - # - if decl.name: - tp, quals = self._get_type_and_quals(node, - partial_length_ok=True) - if tp.is_raw_function: - self._declare_function(tp, quals, decl) - elif (tp.is_integer_type() and - hasattr(decl, 'init') and - hasattr(decl.init, 'value') and - _r_int_literal.match(decl.init.value)): - self._add_integer_constant(decl.name, decl.init.value) - elif (tp.is_integer_type() and - isinstance(decl.init, pycparser.c_ast.UnaryOp) and - decl.init.op == '-' and - hasattr(decl.init.expr, 'value') and - _r_int_literal.match(decl.init.expr.value)): - self._add_integer_constant(decl.name, - '-' + decl.init.expr.value) - elif (tp is model.void_type and - decl.name.startswith('__cffi_extern_python_')): - # hack: `extern "Python"` in the C source is replaced - # with "void __cffi_extern_python_start;" and - # "void __cffi_extern_python_stop;" - self._inside_extern_python = decl.name - else: - if self._inside_extern_python !='__cffi_extern_python_stop': - raise CDefError( - "cannot declare constants or " - "variables with 'extern \"Python\"'") - if (quals & model.Q_CONST) and not tp.is_array_type: - self._declare('constant ' + decl.name, tp, quals=quals) - else: - _warn_for_non_extern_non_static_global_variable(decl) - self._declare('variable ' + decl.name, tp, quals=quals) - - def parse_type(self, cdecl): - return self.parse_type_and_quals(cdecl)[0] - - def parse_type_and_quals(self, cdecl): - ast, macros = self._parse('void __dummy(\n%s\n);' % cdecl)[:2] - assert not macros - exprnode = ast.ext[-1].type.args.params[0] - if isinstance(exprnode, pycparser.c_ast.ID): - raise CDefError("unknown identifier '%s'" % (exprnode.name,)) - return self._get_type_and_quals(exprnode.type) - - def _declare(self, name, obj, included=False, quals=0): - if name in self._declarations: - prevobj, prevquals = self._declarations[name] - if prevobj is obj and prevquals == quals: - return - if not self._options.get('override'): - raise FFIError( - "multiple declarations of %s (for interactive usage, " - "try cdef(xx, override=True))" % (name,)) - assert '__dotdotdot__' not in name.split() - self._declarations[name] = (obj, quals) - if included: - self._included_declarations.add(obj) - - def _extract_quals(self, type): - quals = 0 - if isinstance(type, (pycparser.c_ast.TypeDecl, - pycparser.c_ast.PtrDecl)): - if 'const' in type.quals: - quals |= model.Q_CONST - if 'volatile' in type.quals: - quals |= model.Q_VOLATILE - if 'restrict' in type.quals: - quals |= model.Q_RESTRICT - return quals - - def _get_type_pointer(self, type, quals, declname=None): - if isinstance(type, model.RawFunctionType): - return type.as_function_pointer() - if (isinstance(type, model.StructOrUnionOrEnum) and - type.name.startswith('$') and type.name[1:].isdigit() and - type.forcename is None and declname is not None): - return model.NamedPointerType(type, declname, quals) - return model.PointerType(type, quals) - - def _get_type_and_quals(self, typenode, name=None, partial_length_ok=False, - typedef_example=None): - # first, dereference typedefs, if we have it already parsed, we're good - if (isinstance(typenode, pycparser.c_ast.TypeDecl) and - isinstance(typenode.type, pycparser.c_ast.IdentifierType) and - len(typenode.type.names) == 1 and - ('typedef ' + typenode.type.names[0]) in self._declarations): - tp, quals = self._declarations['typedef ' + typenode.type.names[0]] - quals |= self._extract_quals(typenode) - return tp, quals - # - if isinstance(typenode, pycparser.c_ast.ArrayDecl): - # array type - if typenode.dim is None: - length = None - else: - length = self._parse_constant( - typenode.dim, partial_length_ok=partial_length_ok) - # a hack: in 'typedef int foo_t[...][...];', don't use '...' as - # the length but use directly the C expression that would be - # generated by recompiler.py. This lets the typedef be used in - # many more places within recompiler.py - if typedef_example is not None: - if length == '...': - length = '_cffi_array_len(%s)' % (typedef_example,) - typedef_example = "*" + typedef_example - # - tp, quals = self._get_type_and_quals(typenode.type, - partial_length_ok=partial_length_ok, - typedef_example=typedef_example) - return model.ArrayType(tp, length), quals - # - if isinstance(typenode, pycparser.c_ast.PtrDecl): - # pointer type - itemtype, itemquals = self._get_type_and_quals(typenode.type) - tp = self._get_type_pointer(itemtype, itemquals, declname=name) - quals = self._extract_quals(typenode) - return tp, quals - # - if isinstance(typenode, pycparser.c_ast.TypeDecl): - quals = self._extract_quals(typenode) - type = typenode.type - if isinstance(type, pycparser.c_ast.IdentifierType): - # assume a primitive type. get it from .names, but reduce - # synonyms to a single chosen combination - names = list(type.names) - if names != ['signed', 'char']: # keep this unmodified - prefixes = {} - while names: - name = names[0] - if name in ('short', 'long', 'signed', 'unsigned'): - prefixes[name] = prefixes.get(name, 0) + 1 - del names[0] - else: - break - # ignore the 'signed' prefix below, and reorder the others - newnames = [] - for prefix in ('unsigned', 'short', 'long'): - for i in range(prefixes.get(prefix, 0)): - newnames.append(prefix) - if not names: - names = ['int'] # implicitly - if names == ['int']: # but kill it if 'short' or 'long' - if 'short' in prefixes or 'long' in prefixes: - names = [] - names = newnames + names - ident = ' '.join(names) - if ident == 'void': - return model.void_type, quals - if ident == '__dotdotdot__': - raise FFIError(':%d: bad usage of "..."' % - typenode.coord.line) - tp0, quals0 = resolve_common_type(self, ident) - return tp0, (quals | quals0) - # - if isinstance(type, pycparser.c_ast.Struct): - # 'struct foobar' - tp = self._get_struct_union_enum_type('struct', type, name) - return tp, quals - # - if isinstance(type, pycparser.c_ast.Union): - # 'union foobar' - tp = self._get_struct_union_enum_type('union', type, name) - return tp, quals - # - if isinstance(type, pycparser.c_ast.Enum): - # 'enum foobar' - tp = self._get_struct_union_enum_type('enum', type, name) - return tp, quals - # - if isinstance(typenode, pycparser.c_ast.FuncDecl): - # a function type - return self._parse_function_type(typenode, name), 0 - # - # nested anonymous structs or unions end up here - if isinstance(typenode, pycparser.c_ast.Struct): - return self._get_struct_union_enum_type('struct', typenode, name, - nested=True), 0 - if isinstance(typenode, pycparser.c_ast.Union): - return self._get_struct_union_enum_type('union', typenode, name, - nested=True), 0 - # - raise FFIError(":%d: bad or unsupported type declaration" % - typenode.coord.line) - - def _parse_function_type(self, typenode, funcname=None): - params = list(getattr(typenode.args, 'params', [])) - for i, arg in enumerate(params): - if not hasattr(arg, 'type'): - raise CDefError("%s arg %d: unknown type '%s'" - " (if you meant to use the old C syntax of giving" - " untyped arguments, it is not supported)" - % (funcname or 'in expression', i + 1, - getattr(arg, 'name', '?'))) - ellipsis = ( - len(params) > 0 and - isinstance(params[-1].type, pycparser.c_ast.TypeDecl) and - isinstance(params[-1].type.type, - pycparser.c_ast.IdentifierType) and - params[-1].type.type.names == ['__dotdotdot__']) - if ellipsis: - params.pop() - if not params: - raise CDefError( - "%s: a function with only '(...)' as argument" - " is not correct C" % (funcname or 'in expression')) - args = [self._as_func_arg(*self._get_type_and_quals(argdeclnode.type)) - for argdeclnode in params] - if not ellipsis and args == [model.void_type]: - args = [] - result, quals = self._get_type_and_quals(typenode.type) - # the 'quals' on the result type are ignored. HACK: we absure them - # to detect __stdcall functions: we textually replace "__stdcall" - # with "volatile volatile const" above. - abi = None - if hasattr(typenode.type, 'quals'): # else, probable syntax error anyway - if typenode.type.quals[-3:] == ['volatile', 'volatile', 'const']: - abi = '__stdcall' - return model.RawFunctionType(tuple(args), result, ellipsis, abi) - - def _as_func_arg(self, type, quals): - if isinstance(type, model.ArrayType): - return model.PointerType(type.item, quals) - elif isinstance(type, model.RawFunctionType): - return type.as_function_pointer() - else: - return type - - def _get_struct_union_enum_type(self, kind, type, name=None, nested=False): - # First, a level of caching on the exact 'type' node of the AST. - # This is obscure, but needed because pycparser "unrolls" declarations - # such as "typedef struct { } foo_t, *foo_p" and we end up with - # an AST that is not a tree, but a DAG, with the "type" node of the - # two branches foo_t and foo_p of the trees being the same node. - # It's a bit silly but detecting "DAG-ness" in the AST tree seems - # to be the only way to distinguish this case from two independent - # structs. See test_struct_with_two_usages. - try: - return self._structnode2type[type] - except KeyError: - pass - # - # Note that this must handle parsing "struct foo" any number of - # times and always return the same StructType object. Additionally, - # one of these times (not necessarily the first), the fields of - # the struct can be specified with "struct foo { ...fields... }". - # If no name is given, then we have to create a new anonymous struct - # with no caching; in this case, the fields are either specified - # right now or never. - # - force_name = name - name = type.name - # - # get the type or create it if needed - if name is None: - # 'force_name' is used to guess a more readable name for - # anonymous structs, for the common case "typedef struct { } foo". - if force_name is not None: - explicit_name = '$%s' % force_name - else: - self._anonymous_counter += 1 - explicit_name = '$%d' % self._anonymous_counter - tp = None - else: - explicit_name = name - key = '%s %s' % (kind, name) - tp, _ = self._declarations.get(key, (None, None)) - # - if tp is None: - if kind == 'struct': - tp = model.StructType(explicit_name, None, None, None) - elif kind == 'union': - tp = model.UnionType(explicit_name, None, None, None) - elif kind == 'enum': - if explicit_name == '__dotdotdot__': - raise CDefError("Enums cannot be declared with ...") - tp = self._build_enum_type(explicit_name, type.values) - else: - raise AssertionError("kind = %r" % (kind,)) - if name is not None: - self._declare(key, tp) - else: - if kind == 'enum' and type.values is not None: - raise NotImplementedError( - "enum %s: the '{}' declaration should appear on the first " - "time the enum is mentioned, not later" % explicit_name) - if not tp.forcename: - tp.force_the_name(force_name) - if tp.forcename and '$' in tp.name: - self._declare('anonymous %s' % tp.forcename, tp) - # - self._structnode2type[type] = tp - # - # enums: done here - if kind == 'enum': - return tp - # - # is there a 'type.decls'? If yes, then this is the place in the - # C sources that declare the fields. If no, then just return the - # existing type, possibly still incomplete. - if type.decls is None: - return tp - # - if tp.fldnames is not None: - raise CDefError("duplicate declaration of struct %s" % name) - fldnames = [] - fldtypes = [] - fldbitsize = [] - fldquals = [] - for decl in type.decls: - if (isinstance(decl.type, pycparser.c_ast.IdentifierType) and - ''.join(decl.type.names) == '__dotdotdot__'): - # XXX pycparser is inconsistent: 'names' should be a list - # of strings, but is sometimes just one string. Use - # str.join() as a way to cope with both. - self._make_partial(tp, nested) - continue - if decl.bitsize is None: - bitsize = -1 - else: - bitsize = self._parse_constant(decl.bitsize) - self._partial_length = False - type, fqual = self._get_type_and_quals(decl.type, - partial_length_ok=True) - if self._partial_length: - self._make_partial(tp, nested) - if isinstance(type, model.StructType) and type.partial: - self._make_partial(tp, nested) - fldnames.append(decl.name or '') - fldtypes.append(type) - fldbitsize.append(bitsize) - fldquals.append(fqual) - tp.fldnames = tuple(fldnames) - tp.fldtypes = tuple(fldtypes) - tp.fldbitsize = tuple(fldbitsize) - tp.fldquals = tuple(fldquals) - if fldbitsize != [-1] * len(fldbitsize): - if isinstance(tp, model.StructType) and tp.partial: - raise NotImplementedError("%s: using both bitfields and '...;'" - % (tp,)) - tp.packed = self._options.get('packed') - if tp.completed: # must be re-completed: it is not opaque any more - tp.completed = 0 - self._recomplete.append(tp) - return tp - - def _make_partial(self, tp, nested): - if not isinstance(tp, model.StructOrUnion): - raise CDefError("%s cannot be partial" % (tp,)) - if not tp.has_c_name() and not nested: - raise NotImplementedError("%s is partial but has no C name" %(tp,)) - tp.partial = True - - def _parse_constant(self, exprnode, partial_length_ok=False): - # for now, limited to expressions that are an immediate number - # or positive/negative number - if isinstance(exprnode, pycparser.c_ast.Constant): - s = exprnode.value - if '0' <= s[0] <= '9': - s = s.rstrip('uUlL') - try: - if s.startswith('0'): - return int(s, 8) - else: - return int(s, 10) - except ValueError: - if len(s) > 1: - if s.lower()[0:2] == '0x': - return int(s, 16) - elif s.lower()[0:2] == '0b': - return int(s, 2) - raise CDefError("invalid constant %r" % (s,)) - elif s[0] == "'" and s[-1] == "'" and ( - len(s) == 3 or (len(s) == 4 and s[1] == "\\")): - return ord(s[-2]) - else: - raise CDefError("invalid constant %r" % (s,)) - # - if (isinstance(exprnode, pycparser.c_ast.UnaryOp) and - exprnode.op == '+'): - return self._parse_constant(exprnode.expr) - # - if (isinstance(exprnode, pycparser.c_ast.UnaryOp) and - exprnode.op == '-'): - return -self._parse_constant(exprnode.expr) - # load previously defined int constant - if (isinstance(exprnode, pycparser.c_ast.ID) and - exprnode.name in self._int_constants): - return self._int_constants[exprnode.name] - # - if (isinstance(exprnode, pycparser.c_ast.ID) and - exprnode.name == '__dotdotdotarray__'): - if partial_length_ok: - self._partial_length = True - return '...' - raise FFIError(":%d: unsupported '[...]' here, cannot derive " - "the actual array length in this context" - % exprnode.coord.line) - # - if isinstance(exprnode, pycparser.c_ast.BinaryOp): - left = self._parse_constant(exprnode.left) - right = self._parse_constant(exprnode.right) - if exprnode.op == '+': - return left + right - elif exprnode.op == '-': - return left - right - elif exprnode.op == '*': - return left * right - elif exprnode.op == '/': - return self._c_div(left, right) - elif exprnode.op == '%': - return left - self._c_div(left, right) * right - elif exprnode.op == '<<': - return left << right - elif exprnode.op == '>>': - return left >> right - elif exprnode.op == '&': - return left & right - elif exprnode.op == '|': - return left | right - elif exprnode.op == '^': - return left ^ right - # - raise FFIError(":%d: unsupported expression: expected a " - "simple numeric constant" % exprnode.coord.line) - - def _c_div(self, a, b): - result = a // b - if ((a < 0) ^ (b < 0)) and (a % b) != 0: - result += 1 - return result - - def _build_enum_type(self, explicit_name, decls): - if decls is not None: - partial = False - enumerators = [] - enumvalues = [] - nextenumvalue = 0 - for enum in decls.enumerators: - if _r_enum_dotdotdot.match(enum.name): - partial = True - continue - if enum.value is not None: - nextenumvalue = self._parse_constant(enum.value) - enumerators.append(enum.name) - enumvalues.append(nextenumvalue) - self._add_constants(enum.name, nextenumvalue) - nextenumvalue += 1 - enumerators = tuple(enumerators) - enumvalues = tuple(enumvalues) - tp = model.EnumType(explicit_name, enumerators, enumvalues) - tp.partial = partial - else: # opaque enum - tp = model.EnumType(explicit_name, (), ()) - return tp - - def include(self, other): - for name, (tp, quals) in other._declarations.items(): - if name.startswith('anonymous $enum_$'): - continue # fix for test_anonymous_enum_include - kind = name.split(' ', 1)[0] - if kind in ('struct', 'union', 'enum', 'anonymous', 'typedef'): - self._declare(name, tp, included=True, quals=quals) - for k, v in other._int_constants.items(): - self._add_constants(k, v) - - def _get_unknown_type(self, decl): - typenames = decl.type.type.names - if typenames == ['__dotdotdot__']: - return model.unknown_type(decl.name) - - if typenames == ['__dotdotdotint__']: - if self._uses_new_feature is None: - self._uses_new_feature = "'typedef int... %s'" % decl.name - return model.UnknownIntegerType(decl.name) - - if typenames == ['__dotdotdotfloat__']: - # note: not for 'long double' so far - if self._uses_new_feature is None: - self._uses_new_feature = "'typedef float... %s'" % decl.name - return model.UnknownFloatType(decl.name) - - raise FFIError(':%d: unsupported usage of "..." in typedef' - % decl.coord.line) - - def _get_unknown_ptr_type(self, decl): - if decl.type.type.type.names == ['__dotdotdot__']: - return model.unknown_ptr_type(decl.name) - raise FFIError(':%d: unsupported usage of "..." in typedef' - % decl.coord.line) diff --git a/venv/lib/python3.9/site-packages/cffi/error.py b/venv/lib/python3.9/site-packages/cffi/error.py deleted file mode 100644 index 0a27247..0000000 --- a/venv/lib/python3.9/site-packages/cffi/error.py +++ /dev/null @@ -1,31 +0,0 @@ - -class FFIError(Exception): - __module__ = 'cffi' - -class CDefError(Exception): - __module__ = 'cffi' - def __str__(self): - try: - current_decl = self.args[1] - filename = current_decl.coord.file - linenum = current_decl.coord.line - prefix = '%s:%d: ' % (filename, linenum) - except (AttributeError, TypeError, IndexError): - prefix = '' - return '%s%s' % (prefix, self.args[0]) - -class VerificationError(Exception): - """ An error raised when verification fails - """ - __module__ = 'cffi' - -class VerificationMissing(Exception): - """ An error raised when incomplete structures are passed into - cdef, but no verification has been done - """ - __module__ = 'cffi' - -class PkgConfigError(Exception): - """ An error raised for missing modules in pkg-config - """ - __module__ = 'cffi' diff --git a/venv/lib/python3.9/site-packages/cffi/ffiplatform.py b/venv/lib/python3.9/site-packages/cffi/ffiplatform.py deleted file mode 100644 index adca28f..0000000 --- a/venv/lib/python3.9/site-packages/cffi/ffiplatform.py +++ /dev/null @@ -1,113 +0,0 @@ -import sys, os -from .error import VerificationError - - -LIST_OF_FILE_NAMES = ['sources', 'include_dirs', 'library_dirs', - 'extra_objects', 'depends'] - -def get_extension(srcfilename, modname, sources=(), **kwds): - from cffi._shimmed_dist_utils import Extension - allsources = [srcfilename] - for src in sources: - allsources.append(os.path.normpath(src)) - return Extension(name=modname, sources=allsources, **kwds) - -def compile(tmpdir, ext, compiler_verbose=0, debug=None): - """Compile a C extension module using distutils.""" - - saved_environ = os.environ.copy() - try: - outputfilename = _build(tmpdir, ext, compiler_verbose, debug) - outputfilename = os.path.abspath(outputfilename) - finally: - # workaround for a distutils bugs where some env vars can - # become longer and longer every time it is used - for key, value in saved_environ.items(): - if os.environ.get(key) != value: - os.environ[key] = value - return outputfilename - -def _build(tmpdir, ext, compiler_verbose=0, debug=None): - # XXX compact but horrible :-( - from cffi._shimmed_dist_utils import Distribution, CompileError, LinkError, set_threshold, set_verbosity - - dist = Distribution({'ext_modules': [ext]}) - dist.parse_config_files() - options = dist.get_option_dict('build_ext') - if debug is None: - debug = sys.flags.debug - options['debug'] = ('ffiplatform', debug) - options['force'] = ('ffiplatform', True) - options['build_lib'] = ('ffiplatform', tmpdir) - options['build_temp'] = ('ffiplatform', tmpdir) - # - try: - old_level = set_threshold(0) or 0 - try: - set_verbosity(compiler_verbose) - dist.run_command('build_ext') - cmd_obj = dist.get_command_obj('build_ext') - [soname] = cmd_obj.get_outputs() - finally: - set_threshold(old_level) - except (CompileError, LinkError) as e: - raise VerificationError('%s: %s' % (e.__class__.__name__, e)) - # - return soname - -try: - from os.path import samefile -except ImportError: - def samefile(f1, f2): - return os.path.abspath(f1) == os.path.abspath(f2) - -def maybe_relative_path(path): - if not os.path.isabs(path): - return path # already relative - dir = path - names = [] - while True: - prevdir = dir - dir, name = os.path.split(prevdir) - if dir == prevdir or not dir: - return path # failed to make it relative - names.append(name) - try: - if samefile(dir, os.curdir): - names.reverse() - return os.path.join(*names) - except OSError: - pass - -# ____________________________________________________________ - -try: - int_or_long = (int, long) - import cStringIO -except NameError: - int_or_long = int # Python 3 - import io as cStringIO - -def _flatten(x, f): - if isinstance(x, str): - f.write('%ds%s' % (len(x), x)) - elif isinstance(x, dict): - keys = sorted(x.keys()) - f.write('%dd' % len(keys)) - for key in keys: - _flatten(key, f) - _flatten(x[key], f) - elif isinstance(x, (list, tuple)): - f.write('%dl' % len(x)) - for value in x: - _flatten(value, f) - elif isinstance(x, int_or_long): - f.write('%di' % (x,)) - else: - raise TypeError( - "the keywords to verify() contains unsupported object %r" % (x,)) - -def flatten(x): - f = cStringIO.StringIO() - _flatten(x, f) - return f.getvalue() diff --git a/venv/lib/python3.9/site-packages/cffi/lock.py b/venv/lib/python3.9/site-packages/cffi/lock.py deleted file mode 100644 index db91b71..0000000 --- a/venv/lib/python3.9/site-packages/cffi/lock.py +++ /dev/null @@ -1,30 +0,0 @@ -import sys - -if sys.version_info < (3,): - try: - from thread import allocate_lock - except ImportError: - from dummy_thread import allocate_lock -else: - try: - from _thread import allocate_lock - except ImportError: - from _dummy_thread import allocate_lock - - -##import sys -##l1 = allocate_lock - -##class allocate_lock(object): -## def __init__(self): -## self._real = l1() -## def __enter__(self): -## for i in range(4, 0, -1): -## print sys._getframe(i).f_code -## print -## return self._real.__enter__() -## def __exit__(self, *args): -## return self._real.__exit__(*args) -## def acquire(self, f): -## assert f is False -## return self._real.acquire(f) diff --git a/venv/lib/python3.9/site-packages/cffi/model.py b/venv/lib/python3.9/site-packages/cffi/model.py deleted file mode 100644 index e5f4cae..0000000 --- a/venv/lib/python3.9/site-packages/cffi/model.py +++ /dev/null @@ -1,618 +0,0 @@ -import types -import weakref - -from .lock import allocate_lock -from .error import CDefError, VerificationError, VerificationMissing - -# type qualifiers -Q_CONST = 0x01 -Q_RESTRICT = 0x02 -Q_VOLATILE = 0x04 - -def qualify(quals, replace_with): - if quals & Q_CONST: - replace_with = ' const ' + replace_with.lstrip() - if quals & Q_VOLATILE: - replace_with = ' volatile ' + replace_with.lstrip() - if quals & Q_RESTRICT: - # It seems that __restrict is supported by gcc and msvc. - # If you hit some different compiler, add a #define in - # _cffi_include.h for it (and in its copies, documented there) - replace_with = ' __restrict ' + replace_with.lstrip() - return replace_with - - -class BaseTypeByIdentity(object): - is_array_type = False - is_raw_function = False - - def get_c_name(self, replace_with='', context='a C file', quals=0): - result = self.c_name_with_marker - assert result.count('&') == 1 - # some logic duplication with ffi.getctype()... :-( - replace_with = replace_with.strip() - if replace_with: - if replace_with.startswith('*') and '&[' in result: - replace_with = '(%s)' % replace_with - elif not replace_with[0] in '[(': - replace_with = ' ' + replace_with - replace_with = qualify(quals, replace_with) - result = result.replace('&', replace_with) - if '$' in result: - raise VerificationError( - "cannot generate '%s' in %s: unknown type name" - % (self._get_c_name(), context)) - return result - - def _get_c_name(self): - return self.c_name_with_marker.replace('&', '') - - def has_c_name(self): - return '$' not in self._get_c_name() - - def is_integer_type(self): - return False - - def get_cached_btype(self, ffi, finishlist, can_delay=False): - try: - BType = ffi._cached_btypes[self] - except KeyError: - BType = self.build_backend_type(ffi, finishlist) - BType2 = ffi._cached_btypes.setdefault(self, BType) - assert BType2 is BType - return BType - - def __repr__(self): - return '<%s>' % (self._get_c_name(),) - - def _get_items(self): - return [(name, getattr(self, name)) for name in self._attrs_] - - -class BaseType(BaseTypeByIdentity): - - def __eq__(self, other): - return (self.__class__ == other.__class__ and - self._get_items() == other._get_items()) - - def __ne__(self, other): - return not self == other - - def __hash__(self): - return hash((self.__class__, tuple(self._get_items()))) - - -class VoidType(BaseType): - _attrs_ = () - - def __init__(self): - self.c_name_with_marker = 'void&' - - def build_backend_type(self, ffi, finishlist): - return global_cache(self, ffi, 'new_void_type') - -void_type = VoidType() - - -class BasePrimitiveType(BaseType): - def is_complex_type(self): - return False - - -class PrimitiveType(BasePrimitiveType): - _attrs_ = ('name',) - - ALL_PRIMITIVE_TYPES = { - 'char': 'c', - 'short': 'i', - 'int': 'i', - 'long': 'i', - 'long long': 'i', - 'signed char': 'i', - 'unsigned char': 'i', - 'unsigned short': 'i', - 'unsigned int': 'i', - 'unsigned long': 'i', - 'unsigned long long': 'i', - 'float': 'f', - 'double': 'f', - 'long double': 'f', - '_cffi_float_complex_t': 'j', - '_cffi_double_complex_t': 'j', - '_Bool': 'i', - # the following types are not primitive in the C sense - 'wchar_t': 'c', - 'char16_t': 'c', - 'char32_t': 'c', - 'int8_t': 'i', - 'uint8_t': 'i', - 'int16_t': 'i', - 'uint16_t': 'i', - 'int32_t': 'i', - 'uint32_t': 'i', - 'int64_t': 'i', - 'uint64_t': 'i', - 'int_least8_t': 'i', - 'uint_least8_t': 'i', - 'int_least16_t': 'i', - 'uint_least16_t': 'i', - 'int_least32_t': 'i', - 'uint_least32_t': 'i', - 'int_least64_t': 'i', - 'uint_least64_t': 'i', - 'int_fast8_t': 'i', - 'uint_fast8_t': 'i', - 'int_fast16_t': 'i', - 'uint_fast16_t': 'i', - 'int_fast32_t': 'i', - 'uint_fast32_t': 'i', - 'int_fast64_t': 'i', - 'uint_fast64_t': 'i', - 'intptr_t': 'i', - 'uintptr_t': 'i', - 'intmax_t': 'i', - 'uintmax_t': 'i', - 'ptrdiff_t': 'i', - 'size_t': 'i', - 'ssize_t': 'i', - } - - def __init__(self, name): - assert name in self.ALL_PRIMITIVE_TYPES - self.name = name - self.c_name_with_marker = name + '&' - - def is_char_type(self): - return self.ALL_PRIMITIVE_TYPES[self.name] == 'c' - def is_integer_type(self): - return self.ALL_PRIMITIVE_TYPES[self.name] == 'i' - def is_float_type(self): - return self.ALL_PRIMITIVE_TYPES[self.name] == 'f' - def is_complex_type(self): - return self.ALL_PRIMITIVE_TYPES[self.name] == 'j' - - def build_backend_type(self, ffi, finishlist): - return global_cache(self, ffi, 'new_primitive_type', self.name) - - -class UnknownIntegerType(BasePrimitiveType): - _attrs_ = ('name',) - - def __init__(self, name): - self.name = name - self.c_name_with_marker = name + '&' - - def is_integer_type(self): - return True - - def build_backend_type(self, ffi, finishlist): - raise NotImplementedError("integer type '%s' can only be used after " - "compilation" % self.name) - -class UnknownFloatType(BasePrimitiveType): - _attrs_ = ('name', ) - - def __init__(self, name): - self.name = name - self.c_name_with_marker = name + '&' - - def build_backend_type(self, ffi, finishlist): - raise NotImplementedError("float type '%s' can only be used after " - "compilation" % self.name) - - -class BaseFunctionType(BaseType): - _attrs_ = ('args', 'result', 'ellipsis', 'abi') - - def __init__(self, args, result, ellipsis, abi=None): - self.args = args - self.result = result - self.ellipsis = ellipsis - self.abi = abi - # - reprargs = [arg._get_c_name() for arg in self.args] - if self.ellipsis: - reprargs.append('...') - reprargs = reprargs or ['void'] - replace_with = self._base_pattern % (', '.join(reprargs),) - if abi is not None: - replace_with = replace_with[:1] + abi + ' ' + replace_with[1:] - self.c_name_with_marker = ( - self.result.c_name_with_marker.replace('&', replace_with)) - - -class RawFunctionType(BaseFunctionType): - # Corresponds to a C type like 'int(int)', which is the C type of - # a function, but not a pointer-to-function. The backend has no - # notion of such a type; it's used temporarily by parsing. - _base_pattern = '(&)(%s)' - is_raw_function = True - - def build_backend_type(self, ffi, finishlist): - raise CDefError("cannot render the type %r: it is a function " - "type, not a pointer-to-function type" % (self,)) - - def as_function_pointer(self): - return FunctionPtrType(self.args, self.result, self.ellipsis, self.abi) - - -class FunctionPtrType(BaseFunctionType): - _base_pattern = '(*&)(%s)' - - def build_backend_type(self, ffi, finishlist): - result = self.result.get_cached_btype(ffi, finishlist) - args = [] - for tp in self.args: - args.append(tp.get_cached_btype(ffi, finishlist)) - abi_args = () - if self.abi == "__stdcall": - if not self.ellipsis: # __stdcall ignored for variadic funcs - try: - abi_args = (ffi._backend.FFI_STDCALL,) - except AttributeError: - pass - return global_cache(self, ffi, 'new_function_type', - tuple(args), result, self.ellipsis, *abi_args) - - def as_raw_function(self): - return RawFunctionType(self.args, self.result, self.ellipsis, self.abi) - - -class PointerType(BaseType): - _attrs_ = ('totype', 'quals') - - def __init__(self, totype, quals=0): - self.totype = totype - self.quals = quals - extra = " *&" - if totype.is_array_type: - extra = "(%s)" % (extra.lstrip(),) - extra = qualify(quals, extra) - self.c_name_with_marker = totype.c_name_with_marker.replace('&', extra) - - def build_backend_type(self, ffi, finishlist): - BItem = self.totype.get_cached_btype(ffi, finishlist, can_delay=True) - return global_cache(self, ffi, 'new_pointer_type', BItem) - -voidp_type = PointerType(void_type) - -def ConstPointerType(totype): - return PointerType(totype, Q_CONST) - -const_voidp_type = ConstPointerType(void_type) - - -class NamedPointerType(PointerType): - _attrs_ = ('totype', 'name') - - def __init__(self, totype, name, quals=0): - PointerType.__init__(self, totype, quals) - self.name = name - self.c_name_with_marker = name + '&' - - -class ArrayType(BaseType): - _attrs_ = ('item', 'length') - is_array_type = True - - def __init__(self, item, length): - self.item = item - self.length = length - # - if length is None: - brackets = '&[]' - elif length == '...': - brackets = '&[/*...*/]' - else: - brackets = '&[%s]' % length - self.c_name_with_marker = ( - self.item.c_name_with_marker.replace('&', brackets)) - - def length_is_unknown(self): - return isinstance(self.length, str) - - def resolve_length(self, newlength): - return ArrayType(self.item, newlength) - - def build_backend_type(self, ffi, finishlist): - if self.length_is_unknown(): - raise CDefError("cannot render the type %r: unknown length" % - (self,)) - self.item.get_cached_btype(ffi, finishlist) # force the item BType - BPtrItem = PointerType(self.item).get_cached_btype(ffi, finishlist) - return global_cache(self, ffi, 'new_array_type', BPtrItem, self.length) - -char_array_type = ArrayType(PrimitiveType('char'), None) - - -class StructOrUnionOrEnum(BaseTypeByIdentity): - _attrs_ = ('name',) - forcename = None - - def build_c_name_with_marker(self): - name = self.forcename or '%s %s' % (self.kind, self.name) - self.c_name_with_marker = name + '&' - - def force_the_name(self, forcename): - self.forcename = forcename - self.build_c_name_with_marker() - - def get_official_name(self): - assert self.c_name_with_marker.endswith('&') - return self.c_name_with_marker[:-1] - - -class StructOrUnion(StructOrUnionOrEnum): - fixedlayout = None - completed = 0 - partial = False - packed = 0 - - def __init__(self, name, fldnames, fldtypes, fldbitsize, fldquals=None): - self.name = name - self.fldnames = fldnames - self.fldtypes = fldtypes - self.fldbitsize = fldbitsize - self.fldquals = fldquals - self.build_c_name_with_marker() - - def anonymous_struct_fields(self): - if self.fldtypes is not None: - for name, type in zip(self.fldnames, self.fldtypes): - if name == '' and isinstance(type, StructOrUnion): - yield type - - def enumfields(self, expand_anonymous_struct_union=True): - fldquals = self.fldquals - if fldquals is None: - fldquals = (0,) * len(self.fldnames) - for name, type, bitsize, quals in zip(self.fldnames, self.fldtypes, - self.fldbitsize, fldquals): - if (name == '' and isinstance(type, StructOrUnion) - and expand_anonymous_struct_union): - # nested anonymous struct/union - for result in type.enumfields(): - yield result - else: - yield (name, type, bitsize, quals) - - def force_flatten(self): - # force the struct or union to have a declaration that lists - # directly all fields returned by enumfields(), flattening - # nested anonymous structs/unions. - names = [] - types = [] - bitsizes = [] - fldquals = [] - for name, type, bitsize, quals in self.enumfields(): - names.append(name) - types.append(type) - bitsizes.append(bitsize) - fldquals.append(quals) - self.fldnames = tuple(names) - self.fldtypes = tuple(types) - self.fldbitsize = tuple(bitsizes) - self.fldquals = tuple(fldquals) - - def get_cached_btype(self, ffi, finishlist, can_delay=False): - BType = StructOrUnionOrEnum.get_cached_btype(self, ffi, finishlist, - can_delay) - if not can_delay: - self.finish_backend_type(ffi, finishlist) - return BType - - def finish_backend_type(self, ffi, finishlist): - if self.completed: - if self.completed != 2: - raise NotImplementedError("recursive structure declaration " - "for '%s'" % (self.name,)) - return - BType = ffi._cached_btypes[self] - # - self.completed = 1 - # - if self.fldtypes is None: - pass # not completing it: it's an opaque struct - # - elif self.fixedlayout is None: - fldtypes = [tp.get_cached_btype(ffi, finishlist) - for tp in self.fldtypes] - lst = list(zip(self.fldnames, fldtypes, self.fldbitsize)) - extra_flags = () - if self.packed: - if self.packed == 1: - extra_flags = (8,) # SF_PACKED - else: - extra_flags = (0, self.packed) - ffi._backend.complete_struct_or_union(BType, lst, self, - -1, -1, *extra_flags) - # - else: - fldtypes = [] - fieldofs, fieldsize, totalsize, totalalignment = self.fixedlayout - for i in range(len(self.fldnames)): - fsize = fieldsize[i] - ftype = self.fldtypes[i] - # - if isinstance(ftype, ArrayType) and ftype.length_is_unknown(): - # fix the length to match the total size - BItemType = ftype.item.get_cached_btype(ffi, finishlist) - nlen, nrest = divmod(fsize, ffi.sizeof(BItemType)) - if nrest != 0: - self._verification_error( - "field '%s.%s' has a bogus size?" % ( - self.name, self.fldnames[i] or '{}')) - ftype = ftype.resolve_length(nlen) - self.fldtypes = (self.fldtypes[:i] + (ftype,) + - self.fldtypes[i+1:]) - # - BFieldType = ftype.get_cached_btype(ffi, finishlist) - if isinstance(ftype, ArrayType) and ftype.length is None: - assert fsize == 0 - else: - bitemsize = ffi.sizeof(BFieldType) - if bitemsize != fsize: - self._verification_error( - "field '%s.%s' is declared as %d bytes, but is " - "really %d bytes" % (self.name, - self.fldnames[i] or '{}', - bitemsize, fsize)) - fldtypes.append(BFieldType) - # - lst = list(zip(self.fldnames, fldtypes, self.fldbitsize, fieldofs)) - ffi._backend.complete_struct_or_union(BType, lst, self, - totalsize, totalalignment) - self.completed = 2 - - def _verification_error(self, msg): - raise VerificationError(msg) - - def check_not_partial(self): - if self.partial and self.fixedlayout is None: - raise VerificationMissing(self._get_c_name()) - - def build_backend_type(self, ffi, finishlist): - self.check_not_partial() - finishlist.append(self) - # - return global_cache(self, ffi, 'new_%s_type' % self.kind, - self.get_official_name(), key=self) - - -class StructType(StructOrUnion): - kind = 'struct' - - -class UnionType(StructOrUnion): - kind = 'union' - - -class EnumType(StructOrUnionOrEnum): - kind = 'enum' - partial = False - partial_resolved = False - - def __init__(self, name, enumerators, enumvalues, baseinttype=None): - self.name = name - self.enumerators = enumerators - self.enumvalues = enumvalues - self.baseinttype = baseinttype - self.build_c_name_with_marker() - - def force_the_name(self, forcename): - StructOrUnionOrEnum.force_the_name(self, forcename) - if self.forcename is None: - name = self.get_official_name() - self.forcename = '$' + name.replace(' ', '_') - - def check_not_partial(self): - if self.partial and not self.partial_resolved: - raise VerificationMissing(self._get_c_name()) - - def build_backend_type(self, ffi, finishlist): - self.check_not_partial() - base_btype = self.build_baseinttype(ffi, finishlist) - return global_cache(self, ffi, 'new_enum_type', - self.get_official_name(), - self.enumerators, self.enumvalues, - base_btype, key=self) - - def build_baseinttype(self, ffi, finishlist): - if self.baseinttype is not None: - return self.baseinttype.get_cached_btype(ffi, finishlist) - # - if self.enumvalues: - smallest_value = min(self.enumvalues) - largest_value = max(self.enumvalues) - else: - import warnings - try: - # XXX! The goal is to ensure that the warnings.warn() - # will not suppress the warning. We want to get it - # several times if we reach this point several times. - __warningregistry__.clear() - except NameError: - pass - warnings.warn("%r has no values explicitly defined; " - "guessing that it is equivalent to 'unsigned int'" - % self._get_c_name()) - smallest_value = largest_value = 0 - if smallest_value < 0: # needs a signed type - sign = 1 - candidate1 = PrimitiveType("int") - candidate2 = PrimitiveType("long") - else: - sign = 0 - candidate1 = PrimitiveType("unsigned int") - candidate2 = PrimitiveType("unsigned long") - btype1 = candidate1.get_cached_btype(ffi, finishlist) - btype2 = candidate2.get_cached_btype(ffi, finishlist) - size1 = ffi.sizeof(btype1) - size2 = ffi.sizeof(btype2) - if (smallest_value >= ((-1) << (8*size1-1)) and - largest_value < (1 << (8*size1-sign))): - return btype1 - if (smallest_value >= ((-1) << (8*size2-1)) and - largest_value < (1 << (8*size2-sign))): - return btype2 - raise CDefError("%s values don't all fit into either 'long' " - "or 'unsigned long'" % self._get_c_name()) - -def unknown_type(name, structname=None): - if structname is None: - structname = '$%s' % name - tp = StructType(structname, None, None, None) - tp.force_the_name(name) - tp.origin = "unknown_type" - return tp - -def unknown_ptr_type(name, structname=None): - if structname is None: - structname = '$$%s' % name - tp = StructType(structname, None, None, None) - return NamedPointerType(tp, name) - - -global_lock = allocate_lock() -_typecache_cffi_backend = weakref.WeakValueDictionary() - -def get_typecache(backend): - # returns _typecache_cffi_backend if backend is the _cffi_backend - # module, or type(backend).__typecache if backend is an instance of - # CTypesBackend (or some FakeBackend class during tests) - if isinstance(backend, types.ModuleType): - return _typecache_cffi_backend - with global_lock: - if not hasattr(type(backend), '__typecache'): - type(backend).__typecache = weakref.WeakValueDictionary() - return type(backend).__typecache - -def global_cache(srctype, ffi, funcname, *args, **kwds): - key = kwds.pop('key', (funcname, args)) - assert not kwds - try: - return ffi._typecache[key] - except KeyError: - pass - try: - res = getattr(ffi._backend, funcname)(*args) - except NotImplementedError as e: - raise NotImplementedError("%s: %r: %s" % (funcname, srctype, e)) - # note that setdefault() on WeakValueDictionary is not atomic - # and contains a rare bug (http://bugs.python.org/issue19542); - # we have to use a lock and do it ourselves - cache = ffi._typecache - with global_lock: - res1 = cache.get(key) - if res1 is None: - cache[key] = res - return res - else: - return res1 - -def pointer_cache(ffi, BType): - return global_cache('?', ffi, 'new_pointer_type', BType) - -def attach_exception_info(e, name): - if e.args and type(e.args[0]) is str: - e.args = ('%s: %s' % (name, e.args[0]),) + e.args[1:] diff --git a/venv/lib/python3.9/site-packages/cffi/parse_c_type.h b/venv/lib/python3.9/site-packages/cffi/parse_c_type.h deleted file mode 100644 index 84e4ef8..0000000 --- a/venv/lib/python3.9/site-packages/cffi/parse_c_type.h +++ /dev/null @@ -1,181 +0,0 @@ - -/* This part is from file 'cffi/parse_c_type.h'. It is copied at the - beginning of C sources generated by CFFI's ffi.set_source(). */ - -typedef void *_cffi_opcode_t; - -#define _CFFI_OP(opcode, arg) (_cffi_opcode_t)(opcode | (((uintptr_t)(arg)) << 8)) -#define _CFFI_GETOP(cffi_opcode) ((unsigned char)(uintptr_t)cffi_opcode) -#define _CFFI_GETARG(cffi_opcode) (((intptr_t)cffi_opcode) >> 8) - -#define _CFFI_OP_PRIMITIVE 1 -#define _CFFI_OP_POINTER 3 -#define _CFFI_OP_ARRAY 5 -#define _CFFI_OP_OPEN_ARRAY 7 -#define _CFFI_OP_STRUCT_UNION 9 -#define _CFFI_OP_ENUM 11 -#define _CFFI_OP_FUNCTION 13 -#define _CFFI_OP_FUNCTION_END 15 -#define _CFFI_OP_NOOP 17 -#define _CFFI_OP_BITFIELD 19 -#define _CFFI_OP_TYPENAME 21 -#define _CFFI_OP_CPYTHON_BLTN_V 23 // varargs -#define _CFFI_OP_CPYTHON_BLTN_N 25 // noargs -#define _CFFI_OP_CPYTHON_BLTN_O 27 // O (i.e. a single arg) -#define _CFFI_OP_CONSTANT 29 -#define _CFFI_OP_CONSTANT_INT 31 -#define _CFFI_OP_GLOBAL_VAR 33 -#define _CFFI_OP_DLOPEN_FUNC 35 -#define _CFFI_OP_DLOPEN_CONST 37 -#define _CFFI_OP_GLOBAL_VAR_F 39 -#define _CFFI_OP_EXTERN_PYTHON 41 - -#define _CFFI_PRIM_VOID 0 -#define _CFFI_PRIM_BOOL 1 -#define _CFFI_PRIM_CHAR 2 -#define _CFFI_PRIM_SCHAR 3 -#define _CFFI_PRIM_UCHAR 4 -#define _CFFI_PRIM_SHORT 5 -#define _CFFI_PRIM_USHORT 6 -#define _CFFI_PRIM_INT 7 -#define _CFFI_PRIM_UINT 8 -#define _CFFI_PRIM_LONG 9 -#define _CFFI_PRIM_ULONG 10 -#define _CFFI_PRIM_LONGLONG 11 -#define _CFFI_PRIM_ULONGLONG 12 -#define _CFFI_PRIM_FLOAT 13 -#define _CFFI_PRIM_DOUBLE 14 -#define _CFFI_PRIM_LONGDOUBLE 15 - -#define _CFFI_PRIM_WCHAR 16 -#define _CFFI_PRIM_INT8 17 -#define _CFFI_PRIM_UINT8 18 -#define _CFFI_PRIM_INT16 19 -#define _CFFI_PRIM_UINT16 20 -#define _CFFI_PRIM_INT32 21 -#define _CFFI_PRIM_UINT32 22 -#define _CFFI_PRIM_INT64 23 -#define _CFFI_PRIM_UINT64 24 -#define _CFFI_PRIM_INTPTR 25 -#define _CFFI_PRIM_UINTPTR 26 -#define _CFFI_PRIM_PTRDIFF 27 -#define _CFFI_PRIM_SIZE 28 -#define _CFFI_PRIM_SSIZE 29 -#define _CFFI_PRIM_INT_LEAST8 30 -#define _CFFI_PRIM_UINT_LEAST8 31 -#define _CFFI_PRIM_INT_LEAST16 32 -#define _CFFI_PRIM_UINT_LEAST16 33 -#define _CFFI_PRIM_INT_LEAST32 34 -#define _CFFI_PRIM_UINT_LEAST32 35 -#define _CFFI_PRIM_INT_LEAST64 36 -#define _CFFI_PRIM_UINT_LEAST64 37 -#define _CFFI_PRIM_INT_FAST8 38 -#define _CFFI_PRIM_UINT_FAST8 39 -#define _CFFI_PRIM_INT_FAST16 40 -#define _CFFI_PRIM_UINT_FAST16 41 -#define _CFFI_PRIM_INT_FAST32 42 -#define _CFFI_PRIM_UINT_FAST32 43 -#define _CFFI_PRIM_INT_FAST64 44 -#define _CFFI_PRIM_UINT_FAST64 45 -#define _CFFI_PRIM_INTMAX 46 -#define _CFFI_PRIM_UINTMAX 47 -#define _CFFI_PRIM_FLOATCOMPLEX 48 -#define _CFFI_PRIM_DOUBLECOMPLEX 49 -#define _CFFI_PRIM_CHAR16 50 -#define _CFFI_PRIM_CHAR32 51 - -#define _CFFI__NUM_PRIM 52 -#define _CFFI__UNKNOWN_PRIM (-1) -#define _CFFI__UNKNOWN_FLOAT_PRIM (-2) -#define _CFFI__UNKNOWN_LONG_DOUBLE (-3) - -#define _CFFI__IO_FILE_STRUCT (-1) - - -struct _cffi_global_s { - const char *name; - void *address; - _cffi_opcode_t type_op; - void *size_or_direct_fn; // OP_GLOBAL_VAR: size, or 0 if unknown - // OP_CPYTHON_BLTN_*: addr of direct function -}; - -struct _cffi_getconst_s { - unsigned long long value; - const struct _cffi_type_context_s *ctx; - int gindex; -}; - -struct _cffi_struct_union_s { - const char *name; - int type_index; // -> _cffi_types, on a OP_STRUCT_UNION - int flags; // _CFFI_F_* flags below - size_t size; - int alignment; - int first_field_index; // -> _cffi_fields array - int num_fields; -}; -#define _CFFI_F_UNION 0x01 // is a union, not a struct -#define _CFFI_F_CHECK_FIELDS 0x02 // complain if fields are not in the - // "standard layout" or if some are missing -#define _CFFI_F_PACKED 0x04 // for CHECK_FIELDS, assume a packed struct -#define _CFFI_F_EXTERNAL 0x08 // in some other ffi.include() -#define _CFFI_F_OPAQUE 0x10 // opaque - -struct _cffi_field_s { - const char *name; - size_t field_offset; - size_t field_size; - _cffi_opcode_t field_type_op; -}; - -struct _cffi_enum_s { - const char *name; - int type_index; // -> _cffi_types, on a OP_ENUM - int type_prim; // _CFFI_PRIM_xxx - const char *enumerators; // comma-delimited string -}; - -struct _cffi_typename_s { - const char *name; - int type_index; /* if opaque, points to a possibly artificial - OP_STRUCT which is itself opaque */ -}; - -struct _cffi_type_context_s { - _cffi_opcode_t *types; - const struct _cffi_global_s *globals; - const struct _cffi_field_s *fields; - const struct _cffi_struct_union_s *struct_unions; - const struct _cffi_enum_s *enums; - const struct _cffi_typename_s *typenames; - int num_globals; - int num_struct_unions; - int num_enums; - int num_typenames; - const char *const *includes; - int num_types; - int flags; /* future extension */ -}; - -struct _cffi_parse_info_s { - const struct _cffi_type_context_s *ctx; - _cffi_opcode_t *output; - unsigned int output_size; - size_t error_location; - const char *error_message; -}; - -struct _cffi_externpy_s { - const char *name; - size_t size_of_result; - void *reserved1, *reserved2; -}; - -#ifdef _CFFI_INTERNAL -static int parse_c_type(struct _cffi_parse_info_s *info, const char *input); -static int search_in_globals(const struct _cffi_type_context_s *ctx, - const char *search, size_t search_len); -static int search_in_struct_unions(const struct _cffi_type_context_s *ctx, - const char *search, size_t search_len); -#endif diff --git a/venv/lib/python3.9/site-packages/cffi/pkgconfig.py b/venv/lib/python3.9/site-packages/cffi/pkgconfig.py deleted file mode 100644 index 5c93f15..0000000 --- a/venv/lib/python3.9/site-packages/cffi/pkgconfig.py +++ /dev/null @@ -1,121 +0,0 @@ -# pkg-config, https://www.freedesktop.org/wiki/Software/pkg-config/ integration for cffi -import sys, os, subprocess - -from .error import PkgConfigError - - -def merge_flags(cfg1, cfg2): - """Merge values from cffi config flags cfg2 to cf1 - - Example: - merge_flags({"libraries": ["one"]}, {"libraries": ["two"]}) - {"libraries": ["one", "two"]} - """ - for key, value in cfg2.items(): - if key not in cfg1: - cfg1[key] = value - else: - if not isinstance(cfg1[key], list): - raise TypeError("cfg1[%r] should be a list of strings" % (key,)) - if not isinstance(value, list): - raise TypeError("cfg2[%r] should be a list of strings" % (key,)) - cfg1[key].extend(value) - return cfg1 - - -def call(libname, flag, encoding=sys.getfilesystemencoding()): - """Calls pkg-config and returns the output if found - """ - a = ["pkg-config", "--print-errors"] - a.append(flag) - a.append(libname) - try: - pc = subprocess.Popen(a, stdout=subprocess.PIPE, stderr=subprocess.PIPE) - except EnvironmentError as e: - raise PkgConfigError("cannot run pkg-config: %s" % (str(e).strip(),)) - - bout, berr = pc.communicate() - if pc.returncode != 0: - try: - berr = berr.decode(encoding) - except Exception: - pass - raise PkgConfigError(berr.strip()) - - if sys.version_info >= (3,) and not isinstance(bout, str): # Python 3.x - try: - bout = bout.decode(encoding) - except UnicodeDecodeError: - raise PkgConfigError("pkg-config %s %s returned bytes that cannot " - "be decoded with encoding %r:\n%r" % - (flag, libname, encoding, bout)) - - if os.altsep != '\\' and '\\' in bout: - raise PkgConfigError("pkg-config %s %s returned an unsupported " - "backslash-escaped output:\n%r" % - (flag, libname, bout)) - return bout - - -def flags_from_pkgconfig(libs): - r"""Return compiler line flags for FFI.set_source based on pkg-config output - - Usage - ... - ffibuilder.set_source("_foo", pkgconfig = ["libfoo", "libbar >= 1.8.3"]) - - If pkg-config is installed on build machine, then arguments include_dirs, - library_dirs, libraries, define_macros, extra_compile_args and - extra_link_args are extended with an output of pkg-config for libfoo and - libbar. - - Raises PkgConfigError in case the pkg-config call fails. - """ - - def get_include_dirs(string): - return [x[2:] for x in string.split() if x.startswith("-I")] - - def get_library_dirs(string): - return [x[2:] for x in string.split() if x.startswith("-L")] - - def get_libraries(string): - return [x[2:] for x in string.split() if x.startswith("-l")] - - # convert -Dfoo=bar to list of tuples [("foo", "bar")] expected by distutils - def get_macros(string): - def _macro(x): - x = x[2:] # drop "-D" - if '=' in x: - return tuple(x.split("=", 1)) # "-Dfoo=bar" => ("foo", "bar") - else: - return (x, None) # "-Dfoo" => ("foo", None) - return [_macro(x) for x in string.split() if x.startswith("-D")] - - def get_other_cflags(string): - return [x for x in string.split() if not x.startswith("-I") and - not x.startswith("-D")] - - def get_other_libs(string): - return [x for x in string.split() if not x.startswith("-L") and - not x.startswith("-l")] - - # return kwargs for given libname - def kwargs(libname): - fse = sys.getfilesystemencoding() - all_cflags = call(libname, "--cflags") - all_libs = call(libname, "--libs") - return { - "include_dirs": get_include_dirs(all_cflags), - "library_dirs": get_library_dirs(all_libs), - "libraries": get_libraries(all_libs), - "define_macros": get_macros(all_cflags), - "extra_compile_args": get_other_cflags(all_cflags), - "extra_link_args": get_other_libs(all_libs), - } - - # merge all arguments together - ret = {} - for libname in libs: - lib_flags = kwargs(libname) - merge_flags(ret, lib_flags) - return ret diff --git a/venv/lib/python3.9/site-packages/cffi/recompiler.py b/venv/lib/python3.9/site-packages/cffi/recompiler.py deleted file mode 100644 index 7734a34..0000000 --- a/venv/lib/python3.9/site-packages/cffi/recompiler.py +++ /dev/null @@ -1,1598 +0,0 @@ -import io, os, sys, sysconfig -from . import ffiplatform, model -from .error import VerificationError -from .cffi_opcode import * - -VERSION_BASE = 0x2601 -VERSION_EMBEDDED = 0x2701 -VERSION_CHAR16CHAR32 = 0x2801 - -USE_LIMITED_API = ((sys.platform != 'win32' or sys.version_info < (3, 0) or - sys.version_info >= (3, 5)) and - not sysconfig.get_config_var("Py_GIL_DISABLED")) # free-threaded doesn't yet support limited API - -class GlobalExpr: - def __init__(self, name, address, type_op, size=0, check_value=0): - self.name = name - self.address = address - self.type_op = type_op - self.size = size - self.check_value = check_value - - def as_c_expr(self): - return ' { "%s", (void *)%s, %s, (void *)%s },' % ( - self.name, self.address, self.type_op.as_c_expr(), self.size) - - def as_python_expr(self): - return "b'%s%s',%d" % (self.type_op.as_python_bytes(), self.name, - self.check_value) - -class FieldExpr: - def __init__(self, name, field_offset, field_size, fbitsize, field_type_op): - self.name = name - self.field_offset = field_offset - self.field_size = field_size - self.fbitsize = fbitsize - self.field_type_op = field_type_op - - def as_c_expr(self): - spaces = " " * len(self.name) - return (' { "%s", %s,\n' % (self.name, self.field_offset) + - ' %s %s,\n' % (spaces, self.field_size) + - ' %s %s },' % (spaces, self.field_type_op.as_c_expr())) - - def as_python_expr(self): - raise NotImplementedError - - def as_field_python_expr(self): - if self.field_type_op.op == OP_NOOP: - size_expr = '' - elif self.field_type_op.op == OP_BITFIELD: - size_expr = format_four_bytes(self.fbitsize) - else: - raise NotImplementedError - return "b'%s%s%s'" % (self.field_type_op.as_python_bytes(), - size_expr, - self.name) - -class StructUnionExpr: - def __init__(self, name, type_index, flags, size, alignment, comment, - first_field_index, c_fields): - self.name = name - self.type_index = type_index - self.flags = flags - self.size = size - self.alignment = alignment - self.comment = comment - self.first_field_index = first_field_index - self.c_fields = c_fields - - def as_c_expr(self): - return (' { "%s", %d, %s,' % (self.name, self.type_index, self.flags) - + '\n %s, %s, ' % (self.size, self.alignment) - + '%d, %d ' % (self.first_field_index, len(self.c_fields)) - + ('/* %s */ ' % self.comment if self.comment else '') - + '},') - - def as_python_expr(self): - flags = eval(self.flags, G_FLAGS) - fields_expr = [c_field.as_field_python_expr() - for c_field in self.c_fields] - return "(b'%s%s%s',%s)" % ( - format_four_bytes(self.type_index), - format_four_bytes(flags), - self.name, - ','.join(fields_expr)) - -class EnumExpr: - def __init__(self, name, type_index, size, signed, allenums): - self.name = name - self.type_index = type_index - self.size = size - self.signed = signed - self.allenums = allenums - - def as_c_expr(self): - return (' { "%s", %d, _cffi_prim_int(%s, %s),\n' - ' "%s" },' % (self.name, self.type_index, - self.size, self.signed, self.allenums)) - - def as_python_expr(self): - prim_index = { - (1, 0): PRIM_UINT8, (1, 1): PRIM_INT8, - (2, 0): PRIM_UINT16, (2, 1): PRIM_INT16, - (4, 0): PRIM_UINT32, (4, 1): PRIM_INT32, - (8, 0): PRIM_UINT64, (8, 1): PRIM_INT64, - }[self.size, self.signed] - return "b'%s%s%s\\x00%s'" % (format_four_bytes(self.type_index), - format_four_bytes(prim_index), - self.name, self.allenums) - -class TypenameExpr: - def __init__(self, name, type_index): - self.name = name - self.type_index = type_index - - def as_c_expr(self): - return ' { "%s", %d },' % (self.name, self.type_index) - - def as_python_expr(self): - return "b'%s%s'" % (format_four_bytes(self.type_index), self.name) - - -# ____________________________________________________________ - - -class Recompiler: - _num_externpy = 0 - - def __init__(self, ffi, module_name, target_is_python=False): - self.ffi = ffi - self.module_name = module_name - self.target_is_python = target_is_python - self._version = VERSION_BASE - - def needs_version(self, ver): - self._version = max(self._version, ver) - - def collect_type_table(self): - self._typesdict = {} - self._generate("collecttype") - # - all_decls = sorted(self._typesdict, key=str) - # - # prepare all FUNCTION bytecode sequences first - self.cffi_types = [] - for tp in all_decls: - if tp.is_raw_function: - assert self._typesdict[tp] is None - self._typesdict[tp] = len(self.cffi_types) - self.cffi_types.append(tp) # placeholder - for tp1 in tp.args: - assert isinstance(tp1, (model.VoidType, - model.BasePrimitiveType, - model.PointerType, - model.StructOrUnionOrEnum, - model.FunctionPtrType)) - if self._typesdict[tp1] is None: - self._typesdict[tp1] = len(self.cffi_types) - self.cffi_types.append(tp1) # placeholder - self.cffi_types.append('END') # placeholder - # - # prepare all OTHER bytecode sequences - for tp in all_decls: - if not tp.is_raw_function and self._typesdict[tp] is None: - self._typesdict[tp] = len(self.cffi_types) - self.cffi_types.append(tp) # placeholder - if tp.is_array_type and tp.length is not None: - self.cffi_types.append('LEN') # placeholder - assert None not in self._typesdict.values() - # - # collect all structs and unions and enums - self._struct_unions = {} - self._enums = {} - for tp in all_decls: - if isinstance(tp, model.StructOrUnion): - self._struct_unions[tp] = None - elif isinstance(tp, model.EnumType): - self._enums[tp] = None - for i, tp in enumerate(sorted(self._struct_unions, - key=lambda tp: tp.name)): - self._struct_unions[tp] = i - for i, tp in enumerate(sorted(self._enums, - key=lambda tp: tp.name)): - self._enums[tp] = i - # - # emit all bytecode sequences now - for tp in all_decls: - method = getattr(self, '_emit_bytecode_' + tp.__class__.__name__) - method(tp, self._typesdict[tp]) - # - # consistency check - for op in self.cffi_types: - assert isinstance(op, CffiOp) - self.cffi_types = tuple(self.cffi_types) # don't change any more - - def _enum_fields(self, tp): - # When producing C, expand all anonymous struct/union fields. - # That's necessary to have C code checking the offsets of the - # individual fields contained in them. When producing Python, - # don't do it and instead write it like it is, with the - # corresponding fields having an empty name. Empty names are - # recognized at runtime when we import the generated Python - # file. - expand_anonymous_struct_union = not self.target_is_python - return tp.enumfields(expand_anonymous_struct_union) - - def _do_collect_type(self, tp): - if not isinstance(tp, model.BaseTypeByIdentity): - if isinstance(tp, tuple): - for x in tp: - self._do_collect_type(x) - return - if tp not in self._typesdict: - self._typesdict[tp] = None - if isinstance(tp, model.FunctionPtrType): - self._do_collect_type(tp.as_raw_function()) - elif isinstance(tp, model.StructOrUnion): - if tp.fldtypes is not None and ( - tp not in self.ffi._parser._included_declarations): - for name1, tp1, _, _ in self._enum_fields(tp): - self._do_collect_type(self._field_type(tp, name1, tp1)) - else: - for _, x in tp._get_items(): - self._do_collect_type(x) - - def _generate(self, step_name): - lst = self.ffi._parser._declarations.items() - for name, (tp, quals) in sorted(lst): - kind, realname = name.split(' ', 1) - try: - method = getattr(self, '_generate_cpy_%s_%s' % (kind, - step_name)) - except AttributeError: - raise VerificationError( - "not implemented in recompile(): %r" % name) - try: - self._current_quals = quals - method(tp, realname) - except Exception as e: - model.attach_exception_info(e, name) - raise - - # ---------- - - ALL_STEPS = ["global", "field", "struct_union", "enum", "typename"] - - def collect_step_tables(self): - # collect the declarations for '_cffi_globals', '_cffi_typenames', etc. - self._lsts = {} - for step_name in self.ALL_STEPS: - self._lsts[step_name] = [] - self._seen_struct_unions = set() - self._generate("ctx") - self._add_missing_struct_unions() - # - for step_name in self.ALL_STEPS: - lst = self._lsts[step_name] - if step_name != "field": - lst.sort(key=lambda entry: entry.name) - self._lsts[step_name] = tuple(lst) # don't change any more - # - # check for a possible internal inconsistency: _cffi_struct_unions - # should have been generated with exactly self._struct_unions - lst = self._lsts["struct_union"] - for tp, i in self._struct_unions.items(): - assert i < len(lst) - assert lst[i].name == tp.name - assert len(lst) == len(self._struct_unions) - # same with enums - lst = self._lsts["enum"] - for tp, i in self._enums.items(): - assert i < len(lst) - assert lst[i].name == tp.name - assert len(lst) == len(self._enums) - - # ---------- - - def _prnt(self, what=''): - self._f.write(what + '\n') - - def write_source_to_f(self, f, preamble): - if self.target_is_python: - assert preamble is None - self.write_py_source_to_f(f) - else: - assert preamble is not None - self.write_c_source_to_f(f, preamble) - - def _rel_readlines(self, filename): - g = open(os.path.join(os.path.dirname(__file__), filename), 'r') - lines = g.readlines() - g.close() - return lines - - def write_c_source_to_f(self, f, preamble): - self._f = f - prnt = self._prnt - if self.ffi._embedding is not None: - prnt('#define _CFFI_USE_EMBEDDING') - if not USE_LIMITED_API: - prnt('#define _CFFI_NO_LIMITED_API') - # - # first the '#include' (actually done by inlining the file's content) - lines = self._rel_readlines('_cffi_include.h') - i = lines.index('#include "parse_c_type.h"\n') - lines[i:i+1] = self._rel_readlines('parse_c_type.h') - prnt(''.join(lines)) - # - # if we have ffi._embedding != None, we give it here as a macro - # and include an extra file - base_module_name = self.module_name.split('.')[-1] - if self.ffi._embedding is not None: - prnt('#define _CFFI_MODULE_NAME "%s"' % (self.module_name,)) - prnt('static const char _CFFI_PYTHON_STARTUP_CODE[] = {') - self._print_string_literal_in_array(self.ffi._embedding) - prnt('0 };') - prnt('#ifdef PYPY_VERSION') - prnt('# define _CFFI_PYTHON_STARTUP_FUNC _cffi_pypyinit_%s' % ( - base_module_name,)) - prnt('#elif PY_MAJOR_VERSION >= 3') - prnt('# define _CFFI_PYTHON_STARTUP_FUNC PyInit_%s' % ( - base_module_name,)) - prnt('#else') - prnt('# define _CFFI_PYTHON_STARTUP_FUNC init%s' % ( - base_module_name,)) - prnt('#endif') - lines = self._rel_readlines('_embedding.h') - i = lines.index('#include "_cffi_errors.h"\n') - lines[i:i+1] = self._rel_readlines('_cffi_errors.h') - prnt(''.join(lines)) - self.needs_version(VERSION_EMBEDDED) - # - # then paste the C source given by the user, verbatim. - prnt('/************************************************************/') - prnt() - prnt(preamble) - prnt() - prnt('/************************************************************/') - prnt() - # - # the declaration of '_cffi_types' - prnt('static void *_cffi_types[] = {') - typeindex2type = dict([(i, tp) for (tp, i) in self._typesdict.items()]) - for i, op in enumerate(self.cffi_types): - comment = '' - if i in typeindex2type: - comment = ' // ' + typeindex2type[i]._get_c_name() - prnt('/* %2d */ %s,%s' % (i, op.as_c_expr(), comment)) - if not self.cffi_types: - prnt(' 0') - prnt('};') - prnt() - # - # call generate_cpy_xxx_decl(), for every xxx found from - # ffi._parser._declarations. This generates all the functions. - self._seen_constants = set() - self._generate("decl") - # - # the declaration of '_cffi_globals' and '_cffi_typenames' - nums = {} - for step_name in self.ALL_STEPS: - lst = self._lsts[step_name] - nums[step_name] = len(lst) - if nums[step_name] > 0: - prnt('static const struct _cffi_%s_s _cffi_%ss[] = {' % ( - step_name, step_name)) - for entry in lst: - prnt(entry.as_c_expr()) - prnt('};') - prnt() - # - # the declaration of '_cffi_includes' - if self.ffi._included_ffis: - prnt('static const char * const _cffi_includes[] = {') - for ffi_to_include in self.ffi._included_ffis: - try: - included_module_name, included_source = ( - ffi_to_include._assigned_source[:2]) - except AttributeError: - raise VerificationError( - "ffi object %r includes %r, but the latter has not " - "been prepared with set_source()" % ( - self.ffi, ffi_to_include,)) - if included_source is None: - raise VerificationError( - "not implemented yet: ffi.include() of a Python-based " - "ffi inside a C-based ffi") - prnt(' "%s",' % (included_module_name,)) - prnt(' NULL') - prnt('};') - prnt() - # - # the declaration of '_cffi_type_context' - prnt('static const struct _cffi_type_context_s _cffi_type_context = {') - prnt(' _cffi_types,') - for step_name in self.ALL_STEPS: - if nums[step_name] > 0: - prnt(' _cffi_%ss,' % step_name) - else: - prnt(' NULL, /* no %ss */' % step_name) - for step_name in self.ALL_STEPS: - if step_name != "field": - prnt(' %d, /* num_%ss */' % (nums[step_name], step_name)) - if self.ffi._included_ffis: - prnt(' _cffi_includes,') - else: - prnt(' NULL, /* no includes */') - prnt(' %d, /* num_types */' % (len(self.cffi_types),)) - flags = 0 - if self._num_externpy > 0 or self.ffi._embedding is not None: - flags |= 1 # set to mean that we use extern "Python" - prnt(' %d, /* flags */' % flags) - prnt('};') - prnt() - # - # the init function - prnt('#ifdef __GNUC__') - prnt('# pragma GCC visibility push(default) /* for -fvisibility= */') - prnt('#endif') - prnt() - prnt('#ifdef PYPY_VERSION') - prnt('PyMODINIT_FUNC') - prnt('_cffi_pypyinit_%s(const void *p[])' % (base_module_name,)) - prnt('{') - if flags & 1: - prnt(' if (((intptr_t)p[0]) >= 0x0A03) {') - prnt(' _cffi_call_python_org = ' - '(void(*)(struct _cffi_externpy_s *, char *))p[1];') - prnt(' }') - prnt(' p[0] = (const void *)0x%x;' % self._version) - prnt(' p[1] = &_cffi_type_context;') - prnt('#if PY_MAJOR_VERSION >= 3') - prnt(' return NULL;') - prnt('#endif') - prnt('}') - # on Windows, distutils insists on putting init_cffi_xyz in - # 'export_symbols', so instead of fighting it, just give up and - # give it one - prnt('# ifdef _MSC_VER') - prnt(' PyMODINIT_FUNC') - prnt('# if PY_MAJOR_VERSION >= 3') - prnt(' PyInit_%s(void) { return NULL; }' % (base_module_name,)) - prnt('# else') - prnt(' init%s(void) { }' % (base_module_name,)) - prnt('# endif') - prnt('# endif') - prnt('#elif PY_MAJOR_VERSION >= 3') - prnt('PyMODINIT_FUNC') - prnt('PyInit_%s(void)' % (base_module_name,)) - prnt('{') - prnt(' return _cffi_init("%s", 0x%x, &_cffi_type_context);' % ( - self.module_name, self._version)) - prnt('}') - prnt('#else') - prnt('PyMODINIT_FUNC') - prnt('init%s(void)' % (base_module_name,)) - prnt('{') - prnt(' _cffi_init("%s", 0x%x, &_cffi_type_context);' % ( - self.module_name, self._version)) - prnt('}') - prnt('#endif') - prnt() - prnt('#ifdef __GNUC__') - prnt('# pragma GCC visibility pop') - prnt('#endif') - self._version = None - - def _to_py(self, x): - if isinstance(x, str): - return "b'%s'" % (x,) - if isinstance(x, (list, tuple)): - rep = [self._to_py(item) for item in x] - if len(rep) == 1: - rep.append('') - return "(%s)" % (','.join(rep),) - return x.as_python_expr() # Py2: unicode unexpected; Py3: bytes unexp. - - def write_py_source_to_f(self, f): - self._f = f - prnt = self._prnt - # - # header - prnt("# auto-generated file") - prnt("import _cffi_backend") - # - # the 'import' of the included ffis - num_includes = len(self.ffi._included_ffis or ()) - for i in range(num_includes): - ffi_to_include = self.ffi._included_ffis[i] - try: - included_module_name, included_source = ( - ffi_to_include._assigned_source[:2]) - except AttributeError: - raise VerificationError( - "ffi object %r includes %r, but the latter has not " - "been prepared with set_source()" % ( - self.ffi, ffi_to_include,)) - if included_source is not None: - raise VerificationError( - "not implemented yet: ffi.include() of a C-based " - "ffi inside a Python-based ffi") - prnt('from %s import ffi as _ffi%d' % (included_module_name, i)) - prnt() - prnt("ffi = _cffi_backend.FFI('%s'," % (self.module_name,)) - prnt(" _version = 0x%x," % (self._version,)) - self._version = None - # - # the '_types' keyword argument - self.cffi_types = tuple(self.cffi_types) # don't change any more - types_lst = [op.as_python_bytes() for op in self.cffi_types] - prnt(' _types = %s,' % (self._to_py(''.join(types_lst)),)) - typeindex2type = dict([(i, tp) for (tp, i) in self._typesdict.items()]) - # - # the keyword arguments from ALL_STEPS - for step_name in self.ALL_STEPS: - lst = self._lsts[step_name] - if len(lst) > 0 and step_name != "field": - prnt(' _%ss = %s,' % (step_name, self._to_py(lst))) - # - # the '_includes' keyword argument - if num_includes > 0: - prnt(' _includes = (%s,),' % ( - ', '.join(['_ffi%d' % i for i in range(num_includes)]),)) - # - # the footer - prnt(')') - - # ---------- - - def _gettypenum(self, type): - # a KeyError here is a bug. please report it! :-) - return self._typesdict[type] - - def _convert_funcarg_to_c(self, tp, fromvar, tovar, errcode): - extraarg = '' - if isinstance(tp, model.BasePrimitiveType) and not tp.is_complex_type(): - if tp.is_integer_type() and tp.name != '_Bool': - converter = '_cffi_to_c_int' - extraarg = ', %s' % tp.name - elif isinstance(tp, model.UnknownFloatType): - # don't check with is_float_type(): it may be a 'long - # double' here, and _cffi_to_c_double would loose precision - converter = '(%s)_cffi_to_c_double' % (tp.get_c_name(''),) - else: - cname = tp.get_c_name('') - converter = '(%s)_cffi_to_c_%s' % (cname, - tp.name.replace(' ', '_')) - if cname in ('char16_t', 'char32_t'): - self.needs_version(VERSION_CHAR16CHAR32) - errvalue = '-1' - # - elif isinstance(tp, model.PointerType): - self._convert_funcarg_to_c_ptr_or_array(tp, fromvar, - tovar, errcode) - return - # - elif (isinstance(tp, model.StructOrUnionOrEnum) or - isinstance(tp, model.BasePrimitiveType)): - # a struct (not a struct pointer) as a function argument; - # or, a complex (the same code works) - self._prnt(' if (_cffi_to_c((char *)&%s, _cffi_type(%d), %s) < 0)' - % (tovar, self._gettypenum(tp), fromvar)) - self._prnt(' %s;' % errcode) - return - # - elif isinstance(tp, model.FunctionPtrType): - converter = '(%s)_cffi_to_c_pointer' % tp.get_c_name('') - extraarg = ', _cffi_type(%d)' % self._gettypenum(tp) - errvalue = 'NULL' - # - else: - raise NotImplementedError(tp) - # - self._prnt(' %s = %s(%s%s);' % (tovar, converter, fromvar, extraarg)) - self._prnt(' if (%s == (%s)%s && PyErr_Occurred())' % ( - tovar, tp.get_c_name(''), errvalue)) - self._prnt(' %s;' % errcode) - - def _extra_local_variables(self, tp, localvars, freelines): - if isinstance(tp, model.PointerType): - localvars.add('Py_ssize_t datasize') - localvars.add('struct _cffi_freeme_s *large_args_free = NULL') - freelines.add('if (large_args_free != NULL)' - ' _cffi_free_array_arguments(large_args_free);') - - def _convert_funcarg_to_c_ptr_or_array(self, tp, fromvar, tovar, errcode): - self._prnt(' datasize = _cffi_prepare_pointer_call_argument(') - self._prnt(' _cffi_type(%d), %s, (char **)&%s);' % ( - self._gettypenum(tp), fromvar, tovar)) - self._prnt(' if (datasize != 0) {') - self._prnt(' %s = ((size_t)datasize) <= 640 ? ' - '(%s)alloca((size_t)datasize) : NULL;' % ( - tovar, tp.get_c_name(''))) - self._prnt(' if (_cffi_convert_array_argument(_cffi_type(%d), %s, ' - '(char **)&%s,' % (self._gettypenum(tp), fromvar, tovar)) - self._prnt(' datasize, &large_args_free) < 0)') - self._prnt(' %s;' % errcode) - self._prnt(' }') - - def _convert_expr_from_c(self, tp, var, context): - if isinstance(tp, model.BasePrimitiveType): - if tp.is_integer_type() and tp.name != '_Bool': - return '_cffi_from_c_int(%s, %s)' % (var, tp.name) - elif isinstance(tp, model.UnknownFloatType): - return '_cffi_from_c_double(%s)' % (var,) - elif tp.name != 'long double' and not tp.is_complex_type(): - cname = tp.name.replace(' ', '_') - if cname in ('char16_t', 'char32_t'): - self.needs_version(VERSION_CHAR16CHAR32) - return '_cffi_from_c_%s(%s)' % (cname, var) - else: - return '_cffi_from_c_deref((char *)&%s, _cffi_type(%d))' % ( - var, self._gettypenum(tp)) - elif isinstance(tp, (model.PointerType, model.FunctionPtrType)): - return '_cffi_from_c_pointer((char *)%s, _cffi_type(%d))' % ( - var, self._gettypenum(tp)) - elif isinstance(tp, model.ArrayType): - return '_cffi_from_c_pointer((char *)%s, _cffi_type(%d))' % ( - var, self._gettypenum(model.PointerType(tp.item))) - elif isinstance(tp, model.StructOrUnion): - if tp.fldnames is None: - raise TypeError("'%s' is used as %s, but is opaque" % ( - tp._get_c_name(), context)) - return '_cffi_from_c_struct((char *)&%s, _cffi_type(%d))' % ( - var, self._gettypenum(tp)) - elif isinstance(tp, model.EnumType): - return '_cffi_from_c_deref((char *)&%s, _cffi_type(%d))' % ( - var, self._gettypenum(tp)) - else: - raise NotImplementedError(tp) - - # ---------- - # typedefs - - def _typedef_type(self, tp, name): - return self._global_type(tp, "(*(%s *)0)" % (name,)) - - def _generate_cpy_typedef_collecttype(self, tp, name): - self._do_collect_type(self._typedef_type(tp, name)) - - def _generate_cpy_typedef_decl(self, tp, name): - pass - - def _typedef_ctx(self, tp, name): - type_index = self._typesdict[tp] - self._lsts["typename"].append(TypenameExpr(name, type_index)) - - def _generate_cpy_typedef_ctx(self, tp, name): - tp = self._typedef_type(tp, name) - self._typedef_ctx(tp, name) - if getattr(tp, "origin", None) == "unknown_type": - self._struct_ctx(tp, tp.name, approxname=None) - elif isinstance(tp, model.NamedPointerType): - self._struct_ctx(tp.totype, tp.totype.name, approxname=tp.name, - named_ptr=tp) - - # ---------- - # function declarations - - def _generate_cpy_function_collecttype(self, tp, name): - self._do_collect_type(tp.as_raw_function()) - if tp.ellipsis and not self.target_is_python: - self._do_collect_type(tp) - - def _generate_cpy_function_decl(self, tp, name): - assert not self.target_is_python - assert isinstance(tp, model.FunctionPtrType) - if tp.ellipsis: - # cannot support vararg functions better than this: check for its - # exact type (including the fixed arguments), and build it as a - # constant function pointer (no CPython wrapper) - self._generate_cpy_constant_decl(tp, name) - return - prnt = self._prnt - numargs = len(tp.args) - if numargs == 0: - argname = 'noarg' - elif numargs == 1: - argname = 'arg0' - else: - argname = 'args' - # - # ------------------------------ - # the 'd' version of the function, only for addressof(lib, 'func') - arguments = [] - call_arguments = [] - context = 'argument of %s' % name - for i, type in enumerate(tp.args): - arguments.append(type.get_c_name(' x%d' % i, context)) - call_arguments.append('x%d' % i) - repr_arguments = ', '.join(arguments) - repr_arguments = repr_arguments or 'void' - if tp.abi: - abi = tp.abi + ' ' - else: - abi = '' - name_and_arguments = '%s_cffi_d_%s(%s)' % (abi, name, repr_arguments) - prnt('static %s' % (tp.result.get_c_name(name_and_arguments),)) - prnt('{') - call_arguments = ', '.join(call_arguments) - result_code = 'return ' - if isinstance(tp.result, model.VoidType): - result_code = '' - prnt(' %s%s(%s);' % (result_code, name, call_arguments)) - prnt('}') - # - prnt('#ifndef PYPY_VERSION') # ------------------------------ - # - prnt('static PyObject *') - prnt('_cffi_f_%s(PyObject *self, PyObject *%s)' % (name, argname)) - prnt('{') - # - context = 'argument of %s' % name - for i, type in enumerate(tp.args): - arg = type.get_c_name(' x%d' % i, context) - prnt(' %s;' % arg) - # - localvars = set() - freelines = set() - for type in tp.args: - self._extra_local_variables(type, localvars, freelines) - for decl in sorted(localvars): - prnt(' %s;' % (decl,)) - # - if not isinstance(tp.result, model.VoidType): - result_code = 'result = ' - context = 'result of %s' % name - result_decl = ' %s;' % tp.result.get_c_name(' result', context) - prnt(result_decl) - prnt(' PyObject *pyresult;') - else: - result_decl = None - result_code = '' - # - if len(tp.args) > 1: - rng = range(len(tp.args)) - for i in rng: - prnt(' PyObject *arg%d;' % i) - prnt() - prnt(' if (!PyArg_UnpackTuple(args, "%s", %d, %d, %s))' % ( - name, len(rng), len(rng), - ', '.join(['&arg%d' % i for i in rng]))) - prnt(' return NULL;') - prnt() - # - for i, type in enumerate(tp.args): - self._convert_funcarg_to_c(type, 'arg%d' % i, 'x%d' % i, - 'return NULL') - prnt() - # - prnt(' Py_BEGIN_ALLOW_THREADS') - prnt(' _cffi_restore_errno();') - call_arguments = ['x%d' % i for i in range(len(tp.args))] - call_arguments = ', '.join(call_arguments) - prnt(' { %s%s(%s); }' % (result_code, name, call_arguments)) - prnt(' _cffi_save_errno();') - prnt(' Py_END_ALLOW_THREADS') - prnt() - # - prnt(' (void)self; /* unused */') - if numargs == 0: - prnt(' (void)noarg; /* unused */') - if result_code: - prnt(' pyresult = %s;' % - self._convert_expr_from_c(tp.result, 'result', 'result type')) - for freeline in freelines: - prnt(' ' + freeline) - prnt(' return pyresult;') - else: - for freeline in freelines: - prnt(' ' + freeline) - prnt(' Py_INCREF(Py_None);') - prnt(' return Py_None;') - prnt('}') - # - prnt('#else') # ------------------------------ - # - # the PyPy version: need to replace struct/union arguments with - # pointers, and if the result is a struct/union, insert a first - # arg that is a pointer to the result. We also do that for - # complex args and return type. - def need_indirection(type): - return (isinstance(type, model.StructOrUnion) or - (isinstance(type, model.PrimitiveType) and - type.is_complex_type())) - difference = False - arguments = [] - call_arguments = [] - context = 'argument of %s' % name - for i, type in enumerate(tp.args): - indirection = '' - if need_indirection(type): - indirection = '*' - difference = True - arg = type.get_c_name(' %sx%d' % (indirection, i), context) - arguments.append(arg) - call_arguments.append('%sx%d' % (indirection, i)) - tp_result = tp.result - if need_indirection(tp_result): - context = 'result of %s' % name - arg = tp_result.get_c_name(' *result', context) - arguments.insert(0, arg) - tp_result = model.void_type - result_decl = None - result_code = '*result = ' - difference = True - if difference: - repr_arguments = ', '.join(arguments) - repr_arguments = repr_arguments or 'void' - name_and_arguments = '%s_cffi_f_%s(%s)' % (abi, name, - repr_arguments) - prnt('static %s' % (tp_result.get_c_name(name_and_arguments),)) - prnt('{') - if result_decl: - prnt(result_decl) - call_arguments = ', '.join(call_arguments) - prnt(' { %s%s(%s); }' % (result_code, name, call_arguments)) - if result_decl: - prnt(' return result;') - prnt('}') - else: - prnt('# define _cffi_f_%s _cffi_d_%s' % (name, name)) - # - prnt('#endif') # ------------------------------ - prnt() - - def _generate_cpy_function_ctx(self, tp, name): - if tp.ellipsis and not self.target_is_python: - self._generate_cpy_constant_ctx(tp, name) - return - type_index = self._typesdict[tp.as_raw_function()] - numargs = len(tp.args) - if self.target_is_python: - meth_kind = OP_DLOPEN_FUNC - elif numargs == 0: - meth_kind = OP_CPYTHON_BLTN_N # 'METH_NOARGS' - elif numargs == 1: - meth_kind = OP_CPYTHON_BLTN_O # 'METH_O' - else: - meth_kind = OP_CPYTHON_BLTN_V # 'METH_VARARGS' - self._lsts["global"].append( - GlobalExpr(name, '_cffi_f_%s' % name, - CffiOp(meth_kind, type_index), - size='_cffi_d_%s' % name)) - - # ---------- - # named structs or unions - - def _field_type(self, tp_struct, field_name, tp_field): - if isinstance(tp_field, model.ArrayType): - actual_length = tp_field.length - if actual_length == '...': - ptr_struct_name = tp_struct.get_c_name('*') - actual_length = '_cffi_array_len(((%s)0)->%s)' % ( - ptr_struct_name, field_name) - tp_item = self._field_type(tp_struct, '%s[0]' % field_name, - tp_field.item) - tp_field = model.ArrayType(tp_item, actual_length) - return tp_field - - def _struct_collecttype(self, tp): - self._do_collect_type(tp) - if self.target_is_python: - # also requires nested anon struct/unions in ABI mode, recursively - for fldtype in tp.anonymous_struct_fields(): - self._struct_collecttype(fldtype) - - def _struct_decl(self, tp, cname, approxname): - if tp.fldtypes is None: - return - prnt = self._prnt - checkfuncname = '_cffi_checkfld_%s' % (approxname,) - prnt('_CFFI_UNUSED_FN') - prnt('static void %s(%s *p)' % (checkfuncname, cname)) - prnt('{') - prnt(' /* only to generate compile-time warnings or errors */') - prnt(' (void)p;') - for fname, ftype, fbitsize, fqual in self._enum_fields(tp): - try: - if ftype.is_integer_type() or fbitsize >= 0: - # accept all integers, but complain on float or double - if fname != '': - prnt(" (void)((p->%s) | 0); /* check that '%s.%s' is " - "an integer */" % (fname, cname, fname)) - continue - # only accept exactly the type declared, except that '[]' - # is interpreted as a '*' and so will match any array length. - # (It would also match '*', but that's harder to detect...) - while (isinstance(ftype, model.ArrayType) - and (ftype.length is None or ftype.length == '...')): - ftype = ftype.item - fname = fname + '[0]' - prnt(' { %s = &p->%s; (void)tmp; }' % ( - ftype.get_c_name('*tmp', 'field %r'%fname, quals=fqual), - fname)) - except VerificationError as e: - prnt(' /* %s */' % str(e)) # cannot verify it, ignore - prnt('}') - prnt('struct _cffi_align_%s { char x; %s y; };' % (approxname, cname)) - prnt() - - def _struct_ctx(self, tp, cname, approxname, named_ptr=None): - type_index = self._typesdict[tp] - reason_for_not_expanding = None - flags = [] - if isinstance(tp, model.UnionType): - flags.append("_CFFI_F_UNION") - if tp.fldtypes is None: - flags.append("_CFFI_F_OPAQUE") - reason_for_not_expanding = "opaque" - if (tp not in self.ffi._parser._included_declarations and - (named_ptr is None or - named_ptr not in self.ffi._parser._included_declarations)): - if tp.fldtypes is None: - pass # opaque - elif tp.partial or any(tp.anonymous_struct_fields()): - pass # field layout obtained silently from the C compiler - else: - flags.append("_CFFI_F_CHECK_FIELDS") - if tp.packed: - if tp.packed > 1: - raise NotImplementedError( - "%r is declared with 'pack=%r'; only 0 or 1 are " - "supported in API mode (try to use \"...;\", which " - "does not require a 'pack' declaration)" % - (tp, tp.packed)) - flags.append("_CFFI_F_PACKED") - else: - flags.append("_CFFI_F_EXTERNAL") - reason_for_not_expanding = "external" - flags = '|'.join(flags) or '0' - c_fields = [] - if reason_for_not_expanding is None: - enumfields = list(self._enum_fields(tp)) - for fldname, fldtype, fbitsize, fqual in enumfields: - fldtype = self._field_type(tp, fldname, fldtype) - self._check_not_opaque(fldtype, - "field '%s.%s'" % (tp.name, fldname)) - # cname is None for _add_missing_struct_unions() only - op = OP_NOOP - if fbitsize >= 0: - op = OP_BITFIELD - size = '%d /* bits */' % fbitsize - elif cname is None or ( - isinstance(fldtype, model.ArrayType) and - fldtype.length is None): - size = '(size_t)-1' - else: - size = 'sizeof(((%s)0)->%s)' % ( - tp.get_c_name('*') if named_ptr is None - else named_ptr.name, - fldname) - if cname is None or fbitsize >= 0: - offset = '(size_t)-1' - elif named_ptr is not None: - offset = '(size_t)(((char *)&((%s)4096)->%s) - (char *)4096)' % ( - named_ptr.name, fldname) - else: - offset = 'offsetof(%s, %s)' % (tp.get_c_name(''), fldname) - c_fields.append( - FieldExpr(fldname, offset, size, fbitsize, - CffiOp(op, self._typesdict[fldtype]))) - first_field_index = len(self._lsts["field"]) - self._lsts["field"].extend(c_fields) - # - if cname is None: # unknown name, for _add_missing_struct_unions - size = '(size_t)-2' - align = -2 - comment = "unnamed" - else: - if named_ptr is not None: - size = 'sizeof(*(%s)0)' % (named_ptr.name,) - align = '-1 /* unknown alignment */' - else: - size = 'sizeof(%s)' % (cname,) - align = 'offsetof(struct _cffi_align_%s, y)' % (approxname,) - comment = None - else: - size = '(size_t)-1' - align = -1 - first_field_index = -1 - comment = reason_for_not_expanding - self._lsts["struct_union"].append( - StructUnionExpr(tp.name, type_index, flags, size, align, comment, - first_field_index, c_fields)) - self._seen_struct_unions.add(tp) - - def _check_not_opaque(self, tp, location): - while isinstance(tp, model.ArrayType): - tp = tp.item - if isinstance(tp, model.StructOrUnion) and tp.fldtypes is None: - raise TypeError( - "%s is of an opaque type (not declared in cdef())" % location) - - def _add_missing_struct_unions(self): - # not very nice, but some struct declarations might be missing - # because they don't have any known C name. Check that they are - # not partial (we can't complete or verify them!) and emit them - # anonymously. - lst = list(self._struct_unions.items()) - lst.sort(key=lambda tp_order: tp_order[1]) - for tp, order in lst: - if tp not in self._seen_struct_unions: - if tp.partial: - raise NotImplementedError("internal inconsistency: %r is " - "partial but was not seen at " - "this point" % (tp,)) - if tp.name.startswith('$') and tp.name[1:].isdigit(): - approxname = tp.name[1:] - elif tp.name == '_IO_FILE' and tp.forcename == 'FILE': - approxname = 'FILE' - self._typedef_ctx(tp, 'FILE') - else: - raise NotImplementedError("internal inconsistency: %r" % - (tp,)) - self._struct_ctx(tp, None, approxname) - - def _generate_cpy_struct_collecttype(self, tp, name): - self._struct_collecttype(tp) - _generate_cpy_union_collecttype = _generate_cpy_struct_collecttype - - def _struct_names(self, tp): - cname = tp.get_c_name('') - if ' ' in cname: - return cname, cname.replace(' ', '_') - else: - return cname, '_' + cname - - def _generate_cpy_struct_decl(self, tp, name): - self._struct_decl(tp, *self._struct_names(tp)) - _generate_cpy_union_decl = _generate_cpy_struct_decl - - def _generate_cpy_struct_ctx(self, tp, name): - self._struct_ctx(tp, *self._struct_names(tp)) - _generate_cpy_union_ctx = _generate_cpy_struct_ctx - - # ---------- - # 'anonymous' declarations. These are produced for anonymous structs - # or unions; the 'name' is obtained by a typedef. - - def _generate_cpy_anonymous_collecttype(self, tp, name): - if isinstance(tp, model.EnumType): - self._generate_cpy_enum_collecttype(tp, name) - else: - self._struct_collecttype(tp) - - def _generate_cpy_anonymous_decl(self, tp, name): - if isinstance(tp, model.EnumType): - self._generate_cpy_enum_decl(tp) - else: - self._struct_decl(tp, name, 'typedef_' + name) - - def _generate_cpy_anonymous_ctx(self, tp, name): - if isinstance(tp, model.EnumType): - self._enum_ctx(tp, name) - else: - self._struct_ctx(tp, name, 'typedef_' + name) - - # ---------- - # constants, declared with "static const ..." - - def _generate_cpy_const(self, is_int, name, tp=None, category='const', - check_value=None): - if (category, name) in self._seen_constants: - raise VerificationError( - "duplicate declaration of %s '%s'" % (category, name)) - self._seen_constants.add((category, name)) - # - prnt = self._prnt - funcname = '_cffi_%s_%s' % (category, name) - if is_int: - prnt('static int %s(unsigned long long *o)' % funcname) - prnt('{') - prnt(' int n = (%s) <= 0;' % (name,)) - prnt(' *o = (unsigned long long)((%s) | 0);' - ' /* check that %s is an integer */' % (name, name)) - if check_value is not None: - if check_value > 0: - check_value = '%dU' % (check_value,) - prnt(' if (!_cffi_check_int(*o, n, %s))' % (check_value,)) - prnt(' n |= 2;') - prnt(' return n;') - prnt('}') - else: - assert check_value is None - prnt('static void %s(char *o)' % funcname) - prnt('{') - prnt(' *(%s)o = %s;' % (tp.get_c_name('*'), name)) - prnt('}') - prnt() - - def _generate_cpy_constant_collecttype(self, tp, name): - is_int = tp.is_integer_type() - if not is_int or self.target_is_python: - self._do_collect_type(tp) - - def _generate_cpy_constant_decl(self, tp, name): - is_int = tp.is_integer_type() - self._generate_cpy_const(is_int, name, tp) - - def _generate_cpy_constant_ctx(self, tp, name): - if not self.target_is_python and tp.is_integer_type(): - type_op = CffiOp(OP_CONSTANT_INT, -1) - else: - if self.target_is_python: - const_kind = OP_DLOPEN_CONST - else: - const_kind = OP_CONSTANT - type_index = self._typesdict[tp] - type_op = CffiOp(const_kind, type_index) - self._lsts["global"].append( - GlobalExpr(name, '_cffi_const_%s' % name, type_op)) - - # ---------- - # enums - - def _generate_cpy_enum_collecttype(self, tp, name): - self._do_collect_type(tp) - - def _generate_cpy_enum_decl(self, tp, name=None): - for enumerator in tp.enumerators: - self._generate_cpy_const(True, enumerator) - - def _enum_ctx(self, tp, cname): - type_index = self._typesdict[tp] - type_op = CffiOp(OP_ENUM, -1) - if self.target_is_python: - tp.check_not_partial() - for enumerator, enumvalue in zip(tp.enumerators, tp.enumvalues): - self._lsts["global"].append( - GlobalExpr(enumerator, '_cffi_const_%s' % enumerator, type_op, - check_value=enumvalue)) - # - if cname is not None and '$' not in cname and not self.target_is_python: - size = "sizeof(%s)" % cname - signed = "((%s)-1) <= 0" % cname - else: - basetp = tp.build_baseinttype(self.ffi, []) - size = self.ffi.sizeof(basetp) - signed = int(int(self.ffi.cast(basetp, -1)) < 0) - allenums = ",".join(tp.enumerators) - self._lsts["enum"].append( - EnumExpr(tp.name, type_index, size, signed, allenums)) - - def _generate_cpy_enum_ctx(self, tp, name): - self._enum_ctx(tp, tp._get_c_name()) - - # ---------- - # macros: for now only for integers - - def _generate_cpy_macro_collecttype(self, tp, name): - pass - - def _generate_cpy_macro_decl(self, tp, name): - if tp == '...': - check_value = None - else: - check_value = tp # an integer - self._generate_cpy_const(True, name, check_value=check_value) - - def _generate_cpy_macro_ctx(self, tp, name): - if tp == '...': - if self.target_is_python: - raise VerificationError( - "cannot use the syntax '...' in '#define %s ...' when " - "using the ABI mode" % (name,)) - check_value = None - else: - check_value = tp # an integer - type_op = CffiOp(OP_CONSTANT_INT, -1) - self._lsts["global"].append( - GlobalExpr(name, '_cffi_const_%s' % name, type_op, - check_value=check_value)) - - # ---------- - # global variables - - def _global_type(self, tp, global_name): - if isinstance(tp, model.ArrayType): - actual_length = tp.length - if actual_length == '...': - actual_length = '_cffi_array_len(%s)' % (global_name,) - tp_item = self._global_type(tp.item, '%s[0]' % global_name) - tp = model.ArrayType(tp_item, actual_length) - return tp - - def _generate_cpy_variable_collecttype(self, tp, name): - self._do_collect_type(self._global_type(tp, name)) - - def _generate_cpy_variable_decl(self, tp, name): - prnt = self._prnt - tp = self._global_type(tp, name) - if isinstance(tp, model.ArrayType) and tp.length is None: - tp = tp.item - ampersand = '' - else: - ampersand = '&' - # This code assumes that casts from "tp *" to "void *" is a - # no-op, i.e. a function that returns a "tp *" can be called - # as if it returned a "void *". This should be generally true - # on any modern machine. The only exception to that rule (on - # uncommon architectures, and as far as I can tell) might be - # if 'tp' were a function type, but that is not possible here. - # (If 'tp' is a function _pointer_ type, then casts from "fn_t - # **" to "void *" are again no-ops, as far as I can tell.) - decl = '*_cffi_var_%s(void)' % (name,) - prnt('static ' + tp.get_c_name(decl, quals=self._current_quals)) - prnt('{') - prnt(' return %s(%s);' % (ampersand, name)) - prnt('}') - prnt() - - def _generate_cpy_variable_ctx(self, tp, name): - tp = self._global_type(tp, name) - type_index = self._typesdict[tp] - if self.target_is_python: - op = OP_GLOBAL_VAR - else: - op = OP_GLOBAL_VAR_F - self._lsts["global"].append( - GlobalExpr(name, '_cffi_var_%s' % name, CffiOp(op, type_index))) - - # ---------- - # extern "Python" - - def _generate_cpy_extern_python_collecttype(self, tp, name): - assert isinstance(tp, model.FunctionPtrType) - self._do_collect_type(tp) - _generate_cpy_dllexport_python_collecttype = \ - _generate_cpy_extern_python_plus_c_collecttype = \ - _generate_cpy_extern_python_collecttype - - def _extern_python_decl(self, tp, name, tag_and_space): - prnt = self._prnt - if isinstance(tp.result, model.VoidType): - size_of_result = '0' - else: - context = 'result of %s' % name - size_of_result = '(int)sizeof(%s)' % ( - tp.result.get_c_name('', context),) - prnt('static struct _cffi_externpy_s _cffi_externpy__%s =' % name) - prnt(' { "%s.%s", %s, 0, 0 };' % ( - self.module_name, name, size_of_result)) - prnt() - # - arguments = [] - context = 'argument of %s' % name - for i, type in enumerate(tp.args): - arg = type.get_c_name(' a%d' % i, context) - arguments.append(arg) - # - repr_arguments = ', '.join(arguments) - repr_arguments = repr_arguments or 'void' - name_and_arguments = '%s(%s)' % (name, repr_arguments) - if tp.abi == "__stdcall": - name_and_arguments = '_cffi_stdcall ' + name_and_arguments - # - def may_need_128_bits(tp): - return (isinstance(tp, model.PrimitiveType) and - tp.name == 'long double') - # - size_of_a = max(len(tp.args)*8, 8) - if may_need_128_bits(tp.result): - size_of_a = max(size_of_a, 16) - if isinstance(tp.result, model.StructOrUnion): - size_of_a = 'sizeof(%s) > %d ? sizeof(%s) : %d' % ( - tp.result.get_c_name(''), size_of_a, - tp.result.get_c_name(''), size_of_a) - prnt('%s%s' % (tag_and_space, tp.result.get_c_name(name_and_arguments))) - prnt('{') - prnt(' char a[%s];' % size_of_a) - prnt(' char *p = a;') - for i, type in enumerate(tp.args): - arg = 'a%d' % i - if (isinstance(type, model.StructOrUnion) or - may_need_128_bits(type)): - arg = '&' + arg - type = model.PointerType(type) - prnt(' *(%s)(p + %d) = %s;' % (type.get_c_name('*'), i*8, arg)) - prnt(' _cffi_call_python(&_cffi_externpy__%s, p);' % name) - if not isinstance(tp.result, model.VoidType): - prnt(' return *(%s)p;' % (tp.result.get_c_name('*'),)) - prnt('}') - prnt() - self._num_externpy += 1 - - def _generate_cpy_extern_python_decl(self, tp, name): - self._extern_python_decl(tp, name, 'static ') - - def _generate_cpy_dllexport_python_decl(self, tp, name): - self._extern_python_decl(tp, name, 'CFFI_DLLEXPORT ') - - def _generate_cpy_extern_python_plus_c_decl(self, tp, name): - self._extern_python_decl(tp, name, '') - - def _generate_cpy_extern_python_ctx(self, tp, name): - if self.target_is_python: - raise VerificationError( - "cannot use 'extern \"Python\"' in the ABI mode") - if tp.ellipsis: - raise NotImplementedError("a vararg function is extern \"Python\"") - type_index = self._typesdict[tp] - type_op = CffiOp(OP_EXTERN_PYTHON, type_index) - self._lsts["global"].append( - GlobalExpr(name, '&_cffi_externpy__%s' % name, type_op, name)) - - _generate_cpy_dllexport_python_ctx = \ - _generate_cpy_extern_python_plus_c_ctx = \ - _generate_cpy_extern_python_ctx - - def _print_string_literal_in_array(self, s): - prnt = self._prnt - prnt('// # NB. this is not a string because of a size limit in MSVC') - if not isinstance(s, bytes): # unicode - s = s.encode('utf-8') # -> bytes - else: - s.decode('utf-8') # got bytes, check for valid utf-8 - try: - s.decode('ascii') - except UnicodeDecodeError: - s = b'# -*- encoding: utf8 -*-\n' + s - for line in s.splitlines(True): - comment = line - if type('//') is bytes: # python2 - line = map(ord, line) # make a list of integers - else: # python3 - # type(line) is bytes, which enumerates like a list of integers - comment = ascii(comment)[1:-1] - prnt(('// ' + comment).rstrip()) - printed_line = '' - for c in line: - if len(printed_line) >= 76: - prnt(printed_line) - printed_line = '' - printed_line += '%d,' % (c,) - prnt(printed_line) - - # ---------- - # emitting the opcodes for individual types - - def _emit_bytecode_VoidType(self, tp, index): - self.cffi_types[index] = CffiOp(OP_PRIMITIVE, PRIM_VOID) - - def _emit_bytecode_PrimitiveType(self, tp, index): - prim_index = PRIMITIVE_TO_INDEX[tp.name] - self.cffi_types[index] = CffiOp(OP_PRIMITIVE, prim_index) - - def _emit_bytecode_UnknownIntegerType(self, tp, index): - s = ('_cffi_prim_int(sizeof(%s), (\n' - ' ((%s)-1) | 0 /* check that %s is an integer type */\n' - ' ) <= 0)' % (tp.name, tp.name, tp.name)) - self.cffi_types[index] = CffiOp(OP_PRIMITIVE, s) - - def _emit_bytecode_UnknownFloatType(self, tp, index): - s = ('_cffi_prim_float(sizeof(%s) *\n' - ' (((%s)1) / 2) * 2 /* integer => 0, float => 1 */\n' - ' )' % (tp.name, tp.name)) - self.cffi_types[index] = CffiOp(OP_PRIMITIVE, s) - - def _emit_bytecode_RawFunctionType(self, tp, index): - self.cffi_types[index] = CffiOp(OP_FUNCTION, self._typesdict[tp.result]) - index += 1 - for tp1 in tp.args: - realindex = self._typesdict[tp1] - if index != realindex: - if isinstance(tp1, model.PrimitiveType): - self._emit_bytecode_PrimitiveType(tp1, index) - else: - self.cffi_types[index] = CffiOp(OP_NOOP, realindex) - index += 1 - flags = int(tp.ellipsis) - if tp.abi is not None: - if tp.abi == '__stdcall': - flags |= 2 - else: - raise NotImplementedError("abi=%r" % (tp.abi,)) - self.cffi_types[index] = CffiOp(OP_FUNCTION_END, flags) - - def _emit_bytecode_PointerType(self, tp, index): - self.cffi_types[index] = CffiOp(OP_POINTER, self._typesdict[tp.totype]) - - _emit_bytecode_ConstPointerType = _emit_bytecode_PointerType - _emit_bytecode_NamedPointerType = _emit_bytecode_PointerType - - def _emit_bytecode_FunctionPtrType(self, tp, index): - raw = tp.as_raw_function() - self.cffi_types[index] = CffiOp(OP_POINTER, self._typesdict[raw]) - - def _emit_bytecode_ArrayType(self, tp, index): - item_index = self._typesdict[tp.item] - if tp.length is None: - self.cffi_types[index] = CffiOp(OP_OPEN_ARRAY, item_index) - elif tp.length == '...': - raise VerificationError( - "type %s badly placed: the '...' array length can only be " - "used on global arrays or on fields of structures" % ( - str(tp).replace('/*...*/', '...'),)) - else: - assert self.cffi_types[index + 1] == 'LEN' - self.cffi_types[index] = CffiOp(OP_ARRAY, item_index) - self.cffi_types[index + 1] = CffiOp(None, str(tp.length)) - - def _emit_bytecode_StructType(self, tp, index): - struct_index = self._struct_unions[tp] - self.cffi_types[index] = CffiOp(OP_STRUCT_UNION, struct_index) - _emit_bytecode_UnionType = _emit_bytecode_StructType - - def _emit_bytecode_EnumType(self, tp, index): - enum_index = self._enums[tp] - self.cffi_types[index] = CffiOp(OP_ENUM, enum_index) - - -if sys.version_info >= (3,): - NativeIO = io.StringIO -else: - class NativeIO(io.BytesIO): - def write(self, s): - if isinstance(s, unicode): - s = s.encode('ascii') - super(NativeIO, self).write(s) - -def _is_file_like(maybefile): - # compare to xml.etree.ElementTree._get_writer - return hasattr(maybefile, 'write') - -def _make_c_or_py_source(ffi, module_name, preamble, target_file, verbose): - if verbose: - print("generating %s" % (target_file,)) - recompiler = Recompiler(ffi, module_name, - target_is_python=(preamble is None)) - recompiler.collect_type_table() - recompiler.collect_step_tables() - if _is_file_like(target_file): - recompiler.write_source_to_f(target_file, preamble) - return True - f = NativeIO() - recompiler.write_source_to_f(f, preamble) - output = f.getvalue() - try: - with open(target_file, 'r') as f1: - if f1.read(len(output) + 1) != output: - raise IOError - if verbose: - print("(already up-to-date)") - return False # already up-to-date - except IOError: - tmp_file = '%s.~%d' % (target_file, os.getpid()) - with open(tmp_file, 'w') as f1: - f1.write(output) - try: - os.rename(tmp_file, target_file) - except OSError: - os.unlink(target_file) - os.rename(tmp_file, target_file) - return True - -def make_c_source(ffi, module_name, preamble, target_c_file, verbose=False): - assert preamble is not None - return _make_c_or_py_source(ffi, module_name, preamble, target_c_file, - verbose) - -def make_py_source(ffi, module_name, target_py_file, verbose=False): - return _make_c_or_py_source(ffi, module_name, None, target_py_file, - verbose) - -def _modname_to_file(outputdir, modname, extension): - parts = modname.split('.') - try: - os.makedirs(os.path.join(outputdir, *parts[:-1])) - except OSError: - pass - parts[-1] += extension - return os.path.join(outputdir, *parts), parts - - -# Aaargh. Distutils is not tested at all for the purpose of compiling -# DLLs that are not extension modules. Here are some hacks to work -# around that, in the _patch_for_*() functions... - -def _patch_meth(patchlist, cls, name, new_meth): - old = getattr(cls, name) - patchlist.append((cls, name, old)) - setattr(cls, name, new_meth) - return old - -def _unpatch_meths(patchlist): - for cls, name, old_meth in reversed(patchlist): - setattr(cls, name, old_meth) - -def _patch_for_embedding(patchlist): - if sys.platform == 'win32': - # we must not remove the manifest when building for embedding! - # FUTURE: this module was removed in setuptools 74; this is likely dead code and should be removed, - # since the toolchain it supports (VS2005-2008) is also long dead. - from cffi._shimmed_dist_utils import MSVCCompiler - if MSVCCompiler is not None: - _patch_meth(patchlist, MSVCCompiler, '_remove_visual_c_ref', - lambda self, manifest_file: manifest_file) - - if sys.platform == 'darwin': - # we must not make a '-bundle', but a '-dynamiclib' instead - from cffi._shimmed_dist_utils import CCompiler - def my_link_shared_object(self, *args, **kwds): - if '-bundle' in self.linker_so: - self.linker_so = list(self.linker_so) - i = self.linker_so.index('-bundle') - self.linker_so[i] = '-dynamiclib' - return old_link_shared_object(self, *args, **kwds) - old_link_shared_object = _patch_meth(patchlist, CCompiler, - 'link_shared_object', - my_link_shared_object) - -def _patch_for_target(patchlist, target): - from cffi._shimmed_dist_utils import build_ext - # if 'target' is different from '*', we need to patch some internal - # method to just return this 'target' value, instead of having it - # built from module_name - if target.endswith('.*'): - target = target[:-2] - if sys.platform == 'win32': - target += '.dll' - elif sys.platform == 'darwin': - target += '.dylib' - else: - target += '.so' - _patch_meth(patchlist, build_ext, 'get_ext_filename', - lambda self, ext_name: target) - - -def recompile(ffi, module_name, preamble, tmpdir='.', call_c_compiler=True, - c_file=None, source_extension='.c', extradir=None, - compiler_verbose=1, target=None, debug=None, - uses_ffiplatform=True, **kwds): - if not isinstance(module_name, str): - module_name = module_name.encode('ascii') - if ffi._windows_unicode: - ffi._apply_windows_unicode(kwds) - if preamble is not None: - if call_c_compiler and _is_file_like(c_file): - raise TypeError("Writing to file-like objects is not supported " - "with call_c_compiler=True") - embedding = (ffi._embedding is not None) - if embedding: - ffi._apply_embedding_fix(kwds) - if c_file is None: - c_file, parts = _modname_to_file(tmpdir, module_name, - source_extension) - if extradir: - parts = [extradir] + parts - ext_c_file = os.path.join(*parts) - else: - ext_c_file = c_file - # - if target is None: - if embedding: - target = '%s.*' % module_name - else: - target = '*' - # - if uses_ffiplatform: - ext = ffiplatform.get_extension(ext_c_file, module_name, **kwds) - else: - ext = None - updated = make_c_source(ffi, module_name, preamble, c_file, - verbose=compiler_verbose) - if call_c_compiler: - patchlist = [] - cwd = os.getcwd() - try: - if embedding: - _patch_for_embedding(patchlist) - if target != '*': - _patch_for_target(patchlist, target) - if compiler_verbose: - if tmpdir == '.': - msg = 'the current directory is' - else: - msg = 'setting the current directory to' - print('%s %r' % (msg, os.path.abspath(tmpdir))) - os.chdir(tmpdir) - outputfilename = ffiplatform.compile('.', ext, - compiler_verbose, debug) - finally: - os.chdir(cwd) - _unpatch_meths(patchlist) - return outputfilename - else: - return ext, updated - else: - if c_file is None: - c_file, _ = _modname_to_file(tmpdir, module_name, '.py') - updated = make_py_source(ffi, module_name, c_file, - verbose=compiler_verbose) - if call_c_compiler: - return c_file - else: - return None, updated - diff --git a/venv/lib/python3.9/site-packages/cffi/setuptools_ext.py b/venv/lib/python3.9/site-packages/cffi/setuptools_ext.py deleted file mode 100644 index 5cdd246..0000000 --- a/venv/lib/python3.9/site-packages/cffi/setuptools_ext.py +++ /dev/null @@ -1,229 +0,0 @@ -import os -import sys -import sysconfig - -try: - basestring -except NameError: - # Python 3.x - basestring = str - -def error(msg): - from cffi._shimmed_dist_utils import DistutilsSetupError - raise DistutilsSetupError(msg) - - -def execfile(filename, glob): - # We use execfile() (here rewritten for Python 3) instead of - # __import__() to load the build script. The problem with - # a normal import is that in some packages, the intermediate - # __init__.py files may already try to import the file that - # we are generating. - with open(filename) as f: - src = f.read() - src += '\n' # Python 2.6 compatibility - code = compile(src, filename, 'exec') - exec(code, glob, glob) - - -def add_cffi_module(dist, mod_spec): - from cffi.api import FFI - - if not isinstance(mod_spec, basestring): - error("argument to 'cffi_modules=...' must be a str or a list of str," - " not %r" % (type(mod_spec).__name__,)) - mod_spec = str(mod_spec) - try: - build_file_name, ffi_var_name = mod_spec.split(':') - except ValueError: - error("%r must be of the form 'path/build.py:ffi_variable'" % - (mod_spec,)) - if not os.path.exists(build_file_name): - ext = '' - rewritten = build_file_name.replace('.', '/') + '.py' - if os.path.exists(rewritten): - ext = ' (rewrite cffi_modules to [%r])' % ( - rewritten + ':' + ffi_var_name,) - error("%r does not name an existing file%s" % (build_file_name, ext)) - - mod_vars = {'__name__': '__cffi__', '__file__': build_file_name} - execfile(build_file_name, mod_vars) - - try: - ffi = mod_vars[ffi_var_name] - except KeyError: - error("%r: object %r not found in module" % (mod_spec, - ffi_var_name)) - if not isinstance(ffi, FFI): - ffi = ffi() # maybe it's a function instead of directly an ffi - if not isinstance(ffi, FFI): - error("%r is not an FFI instance (got %r)" % (mod_spec, - type(ffi).__name__)) - if not hasattr(ffi, '_assigned_source'): - error("%r: the set_source() method was not called" % (mod_spec,)) - module_name, source, source_extension, kwds = ffi._assigned_source - if ffi._windows_unicode: - kwds = kwds.copy() - ffi._apply_windows_unicode(kwds) - - if source is None: - _add_py_module(dist, ffi, module_name) - else: - _add_c_module(dist, ffi, module_name, source, source_extension, kwds) - -def _set_py_limited_api(Extension, kwds): - """ - Add py_limited_api to kwds if setuptools >= 26 is in use. - Do not alter the setting if it already exists. - Setuptools takes care of ignoring the flag on Python 2 and PyPy. - - CPython itself should ignore the flag in a debugging version - (by not listing .abi3.so in the extensions it supports), but - it doesn't so far, creating troubles. That's why we check - for "not hasattr(sys, 'gettotalrefcount')" (the 2.7 compatible equivalent - of 'd' not in sys.abiflags). (http://bugs.python.org/issue28401) - - On Windows, with CPython <= 3.4, it's better not to use py_limited_api - because virtualenv *still* doesn't copy PYTHON3.DLL on these versions. - Recently (2020) we started shipping only >= 3.5 wheels, though. So - we'll give it another try and set py_limited_api on Windows >= 3.5. - """ - from cffi._shimmed_dist_utils import log - from cffi import recompiler - - if ('py_limited_api' not in kwds and not hasattr(sys, 'gettotalrefcount') - and recompiler.USE_LIMITED_API): - import setuptools - try: - setuptools_major_version = int(setuptools.__version__.partition('.')[0]) - if setuptools_major_version >= 26: - kwds['py_limited_api'] = True - except ValueError: # certain development versions of setuptools - # If we don't know the version number of setuptools, we - # try to set 'py_limited_api' anyway. At worst, we get a - # warning. - kwds['py_limited_api'] = True - - if sysconfig.get_config_var("Py_GIL_DISABLED"): - if kwds.get('py_limited_api'): - log.info("Ignoring py_limited_api=True for free-threaded build.") - - kwds['py_limited_api'] = False - - if kwds.get('py_limited_api') is False: - # avoid setting Py_LIMITED_API if py_limited_api=False - # which _cffi_include.h does unless _CFFI_NO_LIMITED_API is defined - kwds.setdefault("define_macros", []).append(("_CFFI_NO_LIMITED_API", None)) - return kwds - -def _add_c_module(dist, ffi, module_name, source, source_extension, kwds): - # We are a setuptools extension. Need this build_ext for py_limited_api. - from setuptools.command.build_ext import build_ext - from cffi._shimmed_dist_utils import Extension, log, mkpath - from cffi import recompiler - - allsources = ['$PLACEHOLDER'] - allsources.extend(kwds.pop('sources', [])) - kwds = _set_py_limited_api(Extension, kwds) - ext = Extension(name=module_name, sources=allsources, **kwds) - - def make_mod(tmpdir, pre_run=None): - c_file = os.path.join(tmpdir, module_name + source_extension) - log.info("generating cffi module %r" % c_file) - mkpath(tmpdir) - # a setuptools-only, API-only hook: called with the "ext" and "ffi" - # arguments just before we turn the ffi into C code. To use it, - # subclass the 'distutils.command.build_ext.build_ext' class and - # add a method 'def pre_run(self, ext, ffi)'. - if pre_run is not None: - pre_run(ext, ffi) - updated = recompiler.make_c_source(ffi, module_name, source, c_file) - if not updated: - log.info("already up-to-date") - return c_file - - if dist.ext_modules is None: - dist.ext_modules = [] - dist.ext_modules.append(ext) - - base_class = dist.cmdclass.get('build_ext', build_ext) - class build_ext_make_mod(base_class): - def run(self): - if ext.sources[0] == '$PLACEHOLDER': - pre_run = getattr(self, 'pre_run', None) - ext.sources[0] = make_mod(self.build_temp, pre_run) - base_class.run(self) - dist.cmdclass['build_ext'] = build_ext_make_mod - # NB. multiple runs here will create multiple 'build_ext_make_mod' - # classes. Even in this case the 'build_ext' command should be - # run once; but just in case, the logic above does nothing if - # called again. - - -def _add_py_module(dist, ffi, module_name): - from setuptools.command.build_py import build_py - from setuptools.command.build_ext import build_ext - from cffi._shimmed_dist_utils import log, mkpath - from cffi import recompiler - - def generate_mod(py_file): - log.info("generating cffi module %r" % py_file) - mkpath(os.path.dirname(py_file)) - updated = recompiler.make_py_source(ffi, module_name, py_file) - if not updated: - log.info("already up-to-date") - - base_class = dist.cmdclass.get('build_py', build_py) - class build_py_make_mod(base_class): - def run(self): - base_class.run(self) - module_path = module_name.split('.') - module_path[-1] += '.py' - generate_mod(os.path.join(self.build_lib, *module_path)) - def get_source_files(self): - # This is called from 'setup.py sdist' only. Exclude - # the generate .py module in this case. - saved_py_modules = self.py_modules - try: - if saved_py_modules: - self.py_modules = [m for m in saved_py_modules - if m != module_name] - return base_class.get_source_files(self) - finally: - self.py_modules = saved_py_modules - dist.cmdclass['build_py'] = build_py_make_mod - - # distutils and setuptools have no notion I could find of a - # generated python module. If we don't add module_name to - # dist.py_modules, then things mostly work but there are some - # combination of options (--root and --record) that will miss - # the module. So we add it here, which gives a few apparently - # harmless warnings about not finding the file outside the - # build directory. - # Then we need to hack more in get_source_files(); see above. - if dist.py_modules is None: - dist.py_modules = [] - dist.py_modules.append(module_name) - - # the following is only for "build_ext -i" - base_class_2 = dist.cmdclass.get('build_ext', build_ext) - class build_ext_make_mod(base_class_2): - def run(self): - base_class_2.run(self) - if self.inplace: - # from get_ext_fullpath() in distutils/command/build_ext.py - module_path = module_name.split('.') - package = '.'.join(module_path[:-1]) - build_py = self.get_finalized_command('build_py') - package_dir = build_py.get_package_dir(package) - file_name = module_path[-1] + '.py' - generate_mod(os.path.join(package_dir, file_name)) - dist.cmdclass['build_ext'] = build_ext_make_mod - -def cffi_modules(dist, attr, value): - assert attr == 'cffi_modules' - if isinstance(value, basestring): - value = [value] - - for cffi_module in value: - add_cffi_module(dist, cffi_module) diff --git a/venv/lib/python3.9/site-packages/cffi/vengine_cpy.py b/venv/lib/python3.9/site-packages/cffi/vengine_cpy.py deleted file mode 100644 index 02e6a47..0000000 --- a/venv/lib/python3.9/site-packages/cffi/vengine_cpy.py +++ /dev/null @@ -1,1087 +0,0 @@ -# -# DEPRECATED: implementation for ffi.verify() -# -import sys -from . import model -from .error import VerificationError -from . import _imp_emulation as imp - - -class VCPythonEngine(object): - _class_key = 'x' - _gen_python_module = True - - def __init__(self, verifier): - self.verifier = verifier - self.ffi = verifier.ffi - self._struct_pending_verification = {} - self._types_of_builtin_functions = {} - - def patch_extension_kwds(self, kwds): - pass - - def find_module(self, module_name, path, so_suffixes): - try: - f, filename, descr = imp.find_module(module_name, path) - except ImportError: - return None - if f is not None: - f.close() - # Note that after a setuptools installation, there are both .py - # and .so files with the same basename. The code here relies on - # imp.find_module() locating the .so in priority. - if descr[0] not in so_suffixes: - return None - return filename - - def collect_types(self): - self._typesdict = {} - self._generate("collecttype") - - def _prnt(self, what=''): - self._f.write(what + '\n') - - def _gettypenum(self, type): - # a KeyError here is a bug. please report it! :-) - return self._typesdict[type] - - def _do_collect_type(self, tp): - if ((not isinstance(tp, model.PrimitiveType) - or tp.name == 'long double') - and tp not in self._typesdict): - num = len(self._typesdict) - self._typesdict[tp] = num - - def write_source_to_f(self): - self.collect_types() - # - # The new module will have a _cffi_setup() function that receives - # objects from the ffi world, and that calls some setup code in - # the module. This setup code is split in several independent - # functions, e.g. one per constant. The functions are "chained" - # by ending in a tail call to each other. - # - # This is further split in two chained lists, depending on if we - # can do it at import-time or if we must wait for _cffi_setup() to - # provide us with the objects. This is needed because we - # need the values of the enum constants in order to build the - # that we may have to pass to _cffi_setup(). - # - # The following two 'chained_list_constants' items contains - # the head of these two chained lists, as a string that gives the - # call to do, if any. - self._chained_list_constants = ['((void)lib,0)', '((void)lib,0)'] - # - prnt = self._prnt - # first paste some standard set of lines that are mostly '#define' - prnt(cffimod_header) - prnt() - # then paste the C source given by the user, verbatim. - prnt(self.verifier.preamble) - prnt() - # - # call generate_cpy_xxx_decl(), for every xxx found from - # ffi._parser._declarations. This generates all the functions. - self._generate("decl") - # - # implement the function _cffi_setup_custom() as calling the - # head of the chained list. - self._generate_setup_custom() - prnt() - # - # produce the method table, including the entries for the - # generated Python->C function wrappers, which are done - # by generate_cpy_function_method(). - prnt('static PyMethodDef _cffi_methods[] = {') - self._generate("method") - prnt(' {"_cffi_setup", _cffi_setup, METH_VARARGS, NULL},') - prnt(' {NULL, NULL, 0, NULL} /* Sentinel */') - prnt('};') - prnt() - # - # standard init. - modname = self.verifier.get_module_name() - constants = self._chained_list_constants[False] - prnt('#if PY_MAJOR_VERSION >= 3') - prnt() - prnt('static struct PyModuleDef _cffi_module_def = {') - prnt(' PyModuleDef_HEAD_INIT,') - prnt(' "%s",' % modname) - prnt(' NULL,') - prnt(' -1,') - prnt(' _cffi_methods,') - prnt(' NULL, NULL, NULL, NULL') - prnt('};') - prnt() - prnt('PyMODINIT_FUNC') - prnt('PyInit_%s(void)' % modname) - prnt('{') - prnt(' PyObject *lib;') - prnt(' lib = PyModule_Create(&_cffi_module_def);') - prnt(' if (lib == NULL)') - prnt(' return NULL;') - prnt(' if (%s < 0 || _cffi_init() < 0) {' % (constants,)) - prnt(' Py_DECREF(lib);') - prnt(' return NULL;') - prnt(' }') - prnt('#if Py_GIL_DISABLED') - prnt(' PyUnstable_Module_SetGIL(lib, Py_MOD_GIL_NOT_USED);') - prnt('#endif') - prnt(' return lib;') - prnt('}') - prnt() - prnt('#else') - prnt() - prnt('PyMODINIT_FUNC') - prnt('init%s(void)' % modname) - prnt('{') - prnt(' PyObject *lib;') - prnt(' lib = Py_InitModule("%s", _cffi_methods);' % modname) - prnt(' if (lib == NULL)') - prnt(' return;') - prnt(' if (%s < 0 || _cffi_init() < 0)' % (constants,)) - prnt(' return;') - prnt(' return;') - prnt('}') - prnt() - prnt('#endif') - - def load_library(self, flags=None): - # XXX review all usages of 'self' here! - # import it as a new extension module - imp.acquire_lock() - try: - if hasattr(sys, "getdlopenflags"): - previous_flags = sys.getdlopenflags() - try: - if hasattr(sys, "setdlopenflags") and flags is not None: - sys.setdlopenflags(flags) - module = imp.load_dynamic(self.verifier.get_module_name(), - self.verifier.modulefilename) - except ImportError as e: - error = "importing %r: %s" % (self.verifier.modulefilename, e) - raise VerificationError(error) - finally: - if hasattr(sys, "setdlopenflags"): - sys.setdlopenflags(previous_flags) - finally: - imp.release_lock() - # - # call loading_cpy_struct() to get the struct layout inferred by - # the C compiler - self._load(module, 'loading') - # - # the C code will need the objects. Collect them in - # order in a list. - revmapping = dict([(value, key) - for (key, value) in self._typesdict.items()]) - lst = [revmapping[i] for i in range(len(revmapping))] - lst = list(map(self.ffi._get_cached_btype, lst)) - # - # build the FFILibrary class and instance and call _cffi_setup(). - # this will set up some fields like '_cffi_types', and only then - # it will invoke the chained list of functions that will really - # build (notably) the constant objects, as if they are - # pointers, and store them as attributes on the 'library' object. - class FFILibrary(object): - _cffi_python_module = module - _cffi_ffi = self.ffi - _cffi_dir = [] - def __dir__(self): - return FFILibrary._cffi_dir + list(self.__dict__) - library = FFILibrary() - if module._cffi_setup(lst, VerificationError, library): - import warnings - warnings.warn("reimporting %r might overwrite older definitions" - % (self.verifier.get_module_name())) - # - # finally, call the loaded_cpy_xxx() functions. This will perform - # the final adjustments, like copying the Python->C wrapper - # functions from the module to the 'library' object, and setting - # up the FFILibrary class with properties for the global C variables. - self._load(module, 'loaded', library=library) - module._cffi_original_ffi = self.ffi - module._cffi_types_of_builtin_funcs = self._types_of_builtin_functions - return library - - def _get_declarations(self): - lst = [(key, tp) for (key, (tp, qual)) in - self.ffi._parser._declarations.items()] - lst.sort() - return lst - - def _generate(self, step_name): - for name, tp in self._get_declarations(): - kind, realname = name.split(' ', 1) - try: - method = getattr(self, '_generate_cpy_%s_%s' % (kind, - step_name)) - except AttributeError: - raise VerificationError( - "not implemented in verify(): %r" % name) - try: - method(tp, realname) - except Exception as e: - model.attach_exception_info(e, name) - raise - - def _load(self, module, step_name, **kwds): - for name, tp in self._get_declarations(): - kind, realname = name.split(' ', 1) - method = getattr(self, '_%s_cpy_%s' % (step_name, kind)) - try: - method(tp, realname, module, **kwds) - except Exception as e: - model.attach_exception_info(e, name) - raise - - def _generate_nothing(self, tp, name): - pass - - def _loaded_noop(self, tp, name, module, **kwds): - pass - - # ---------- - - def _convert_funcarg_to_c(self, tp, fromvar, tovar, errcode): - extraarg = '' - if isinstance(tp, model.PrimitiveType): - if tp.is_integer_type() and tp.name != '_Bool': - converter = '_cffi_to_c_int' - extraarg = ', %s' % tp.name - elif tp.is_complex_type(): - raise VerificationError( - "not implemented in verify(): complex types") - else: - converter = '(%s)_cffi_to_c_%s' % (tp.get_c_name(''), - tp.name.replace(' ', '_')) - errvalue = '-1' - # - elif isinstance(tp, model.PointerType): - self._convert_funcarg_to_c_ptr_or_array(tp, fromvar, - tovar, errcode) - return - # - elif isinstance(tp, (model.StructOrUnion, model.EnumType)): - # a struct (not a struct pointer) as a function argument - self._prnt(' if (_cffi_to_c((char *)&%s, _cffi_type(%d), %s) < 0)' - % (tovar, self._gettypenum(tp), fromvar)) - self._prnt(' %s;' % errcode) - return - # - elif isinstance(tp, model.FunctionPtrType): - converter = '(%s)_cffi_to_c_pointer' % tp.get_c_name('') - extraarg = ', _cffi_type(%d)' % self._gettypenum(tp) - errvalue = 'NULL' - # - else: - raise NotImplementedError(tp) - # - self._prnt(' %s = %s(%s%s);' % (tovar, converter, fromvar, extraarg)) - self._prnt(' if (%s == (%s)%s && PyErr_Occurred())' % ( - tovar, tp.get_c_name(''), errvalue)) - self._prnt(' %s;' % errcode) - - def _extra_local_variables(self, tp, localvars, freelines): - if isinstance(tp, model.PointerType): - localvars.add('Py_ssize_t datasize') - localvars.add('struct _cffi_freeme_s *large_args_free = NULL') - freelines.add('if (large_args_free != NULL)' - ' _cffi_free_array_arguments(large_args_free);') - - def _convert_funcarg_to_c_ptr_or_array(self, tp, fromvar, tovar, errcode): - self._prnt(' datasize = _cffi_prepare_pointer_call_argument(') - self._prnt(' _cffi_type(%d), %s, (char **)&%s);' % ( - self._gettypenum(tp), fromvar, tovar)) - self._prnt(' if (datasize != 0) {') - self._prnt(' %s = ((size_t)datasize) <= 640 ? ' - 'alloca((size_t)datasize) : NULL;' % (tovar,)) - self._prnt(' if (_cffi_convert_array_argument(_cffi_type(%d), %s, ' - '(char **)&%s,' % (self._gettypenum(tp), fromvar, tovar)) - self._prnt(' datasize, &large_args_free) < 0)') - self._prnt(' %s;' % errcode) - self._prnt(' }') - - def _convert_expr_from_c(self, tp, var, context): - if isinstance(tp, model.PrimitiveType): - if tp.is_integer_type() and tp.name != '_Bool': - return '_cffi_from_c_int(%s, %s)' % (var, tp.name) - elif tp.name != 'long double': - return '_cffi_from_c_%s(%s)' % (tp.name.replace(' ', '_'), var) - else: - return '_cffi_from_c_deref((char *)&%s, _cffi_type(%d))' % ( - var, self._gettypenum(tp)) - elif isinstance(tp, (model.PointerType, model.FunctionPtrType)): - return '_cffi_from_c_pointer((char *)%s, _cffi_type(%d))' % ( - var, self._gettypenum(tp)) - elif isinstance(tp, model.ArrayType): - return '_cffi_from_c_pointer((char *)%s, _cffi_type(%d))' % ( - var, self._gettypenum(model.PointerType(tp.item))) - elif isinstance(tp, model.StructOrUnion): - if tp.fldnames is None: - raise TypeError("'%s' is used as %s, but is opaque" % ( - tp._get_c_name(), context)) - return '_cffi_from_c_struct((char *)&%s, _cffi_type(%d))' % ( - var, self._gettypenum(tp)) - elif isinstance(tp, model.EnumType): - return '_cffi_from_c_deref((char *)&%s, _cffi_type(%d))' % ( - var, self._gettypenum(tp)) - else: - raise NotImplementedError(tp) - - # ---------- - # typedefs: generates no code so far - - _generate_cpy_typedef_collecttype = _generate_nothing - _generate_cpy_typedef_decl = _generate_nothing - _generate_cpy_typedef_method = _generate_nothing - _loading_cpy_typedef = _loaded_noop - _loaded_cpy_typedef = _loaded_noop - - # ---------- - # function declarations - - def _generate_cpy_function_collecttype(self, tp, name): - assert isinstance(tp, model.FunctionPtrType) - if tp.ellipsis: - self._do_collect_type(tp) - else: - # don't call _do_collect_type(tp) in this common case, - # otherwise test_autofilled_struct_as_argument fails - for type in tp.args: - self._do_collect_type(type) - self._do_collect_type(tp.result) - - def _generate_cpy_function_decl(self, tp, name): - assert isinstance(tp, model.FunctionPtrType) - if tp.ellipsis: - # cannot support vararg functions better than this: check for its - # exact type (including the fixed arguments), and build it as a - # constant function pointer (no CPython wrapper) - self._generate_cpy_const(False, name, tp) - return - prnt = self._prnt - numargs = len(tp.args) - if numargs == 0: - argname = 'noarg' - elif numargs == 1: - argname = 'arg0' - else: - argname = 'args' - prnt('static PyObject *') - prnt('_cffi_f_%s(PyObject *self, PyObject *%s)' % (name, argname)) - prnt('{') - # - context = 'argument of %s' % name - for i, type in enumerate(tp.args): - prnt(' %s;' % type.get_c_name(' x%d' % i, context)) - # - localvars = set() - freelines = set() - for type in tp.args: - self._extra_local_variables(type, localvars, freelines) - for decl in sorted(localvars): - prnt(' %s;' % (decl,)) - # - if not isinstance(tp.result, model.VoidType): - result_code = 'result = ' - context = 'result of %s' % name - prnt(' %s;' % tp.result.get_c_name(' result', context)) - prnt(' PyObject *pyresult;') - else: - result_code = '' - # - if len(tp.args) > 1: - rng = range(len(tp.args)) - for i in rng: - prnt(' PyObject *arg%d;' % i) - prnt() - prnt(' if (!PyArg_ParseTuple(args, "%s:%s", %s))' % ( - 'O' * numargs, name, ', '.join(['&arg%d' % i for i in rng]))) - prnt(' return NULL;') - prnt() - # - for i, type in enumerate(tp.args): - self._convert_funcarg_to_c(type, 'arg%d' % i, 'x%d' % i, - 'return NULL') - prnt() - # - prnt(' Py_BEGIN_ALLOW_THREADS') - prnt(' _cffi_restore_errno();') - prnt(' { %s%s(%s); }' % ( - result_code, name, - ', '.join(['x%d' % i for i in range(len(tp.args))]))) - prnt(' _cffi_save_errno();') - prnt(' Py_END_ALLOW_THREADS') - prnt() - # - prnt(' (void)self; /* unused */') - if numargs == 0: - prnt(' (void)noarg; /* unused */') - if result_code: - prnt(' pyresult = %s;' % - self._convert_expr_from_c(tp.result, 'result', 'result type')) - for freeline in freelines: - prnt(' ' + freeline) - prnt(' return pyresult;') - else: - for freeline in freelines: - prnt(' ' + freeline) - prnt(' Py_INCREF(Py_None);') - prnt(' return Py_None;') - prnt('}') - prnt() - - def _generate_cpy_function_method(self, tp, name): - if tp.ellipsis: - return - numargs = len(tp.args) - if numargs == 0: - meth = 'METH_NOARGS' - elif numargs == 1: - meth = 'METH_O' - else: - meth = 'METH_VARARGS' - self._prnt(' {"%s", _cffi_f_%s, %s, NULL},' % (name, name, meth)) - - _loading_cpy_function = _loaded_noop - - def _loaded_cpy_function(self, tp, name, module, library): - if tp.ellipsis: - return - func = getattr(module, name) - setattr(library, name, func) - self._types_of_builtin_functions[func] = tp - - # ---------- - # named structs - - _generate_cpy_struct_collecttype = _generate_nothing - def _generate_cpy_struct_decl(self, tp, name): - assert name == tp.name - self._generate_struct_or_union_decl(tp, 'struct', name) - def _generate_cpy_struct_method(self, tp, name): - self._generate_struct_or_union_method(tp, 'struct', name) - def _loading_cpy_struct(self, tp, name, module): - self._loading_struct_or_union(tp, 'struct', name, module) - def _loaded_cpy_struct(self, tp, name, module, **kwds): - self._loaded_struct_or_union(tp) - - _generate_cpy_union_collecttype = _generate_nothing - def _generate_cpy_union_decl(self, tp, name): - assert name == tp.name - self._generate_struct_or_union_decl(tp, 'union', name) - def _generate_cpy_union_method(self, tp, name): - self._generate_struct_or_union_method(tp, 'union', name) - def _loading_cpy_union(self, tp, name, module): - self._loading_struct_or_union(tp, 'union', name, module) - def _loaded_cpy_union(self, tp, name, module, **kwds): - self._loaded_struct_or_union(tp) - - def _generate_struct_or_union_decl(self, tp, prefix, name): - if tp.fldnames is None: - return # nothing to do with opaque structs - checkfuncname = '_cffi_check_%s_%s' % (prefix, name) - layoutfuncname = '_cffi_layout_%s_%s' % (prefix, name) - cname = ('%s %s' % (prefix, name)).strip() - # - prnt = self._prnt - prnt('static void %s(%s *p)' % (checkfuncname, cname)) - prnt('{') - prnt(' /* only to generate compile-time warnings or errors */') - prnt(' (void)p;') - for fname, ftype, fbitsize, fqual in tp.enumfields(): - if (isinstance(ftype, model.PrimitiveType) - and ftype.is_integer_type()) or fbitsize >= 0: - # accept all integers, but complain on float or double - prnt(' (void)((p->%s) << 1);' % fname) - else: - # only accept exactly the type declared. - try: - prnt(' { %s = &p->%s; (void)tmp; }' % ( - ftype.get_c_name('*tmp', 'field %r'%fname, quals=fqual), - fname)) - except VerificationError as e: - prnt(' /* %s */' % str(e)) # cannot verify it, ignore - prnt('}') - prnt('static PyObject *') - prnt('%s(PyObject *self, PyObject *noarg)' % (layoutfuncname,)) - prnt('{') - prnt(' struct _cffi_aligncheck { char x; %s y; };' % cname) - prnt(' static Py_ssize_t nums[] = {') - prnt(' sizeof(%s),' % cname) - prnt(' offsetof(struct _cffi_aligncheck, y),') - for fname, ftype, fbitsize, fqual in tp.enumfields(): - if fbitsize >= 0: - continue # xxx ignore fbitsize for now - prnt(' offsetof(%s, %s),' % (cname, fname)) - if isinstance(ftype, model.ArrayType) and ftype.length is None: - prnt(' 0, /* %s */' % ftype._get_c_name()) - else: - prnt(' sizeof(((%s *)0)->%s),' % (cname, fname)) - prnt(' -1') - prnt(' };') - prnt(' (void)self; /* unused */') - prnt(' (void)noarg; /* unused */') - prnt(' return _cffi_get_struct_layout(nums);') - prnt(' /* the next line is not executed, but compiled */') - prnt(' %s(0);' % (checkfuncname,)) - prnt('}') - prnt() - - def _generate_struct_or_union_method(self, tp, prefix, name): - if tp.fldnames is None: - return # nothing to do with opaque structs - layoutfuncname = '_cffi_layout_%s_%s' % (prefix, name) - self._prnt(' {"%s", %s, METH_NOARGS, NULL},' % (layoutfuncname, - layoutfuncname)) - - def _loading_struct_or_union(self, tp, prefix, name, module): - if tp.fldnames is None: - return # nothing to do with opaque structs - layoutfuncname = '_cffi_layout_%s_%s' % (prefix, name) - # - function = getattr(module, layoutfuncname) - layout = function() - if isinstance(tp, model.StructOrUnion) and tp.partial: - # use the function()'s sizes and offsets to guide the - # layout of the struct - totalsize = layout[0] - totalalignment = layout[1] - fieldofs = layout[2::2] - fieldsize = layout[3::2] - tp.force_flatten() - assert len(fieldofs) == len(fieldsize) == len(tp.fldnames) - tp.fixedlayout = fieldofs, fieldsize, totalsize, totalalignment - else: - cname = ('%s %s' % (prefix, name)).strip() - self._struct_pending_verification[tp] = layout, cname - - def _loaded_struct_or_union(self, tp): - if tp.fldnames is None: - return # nothing to do with opaque structs - self.ffi._get_cached_btype(tp) # force 'fixedlayout' to be considered - - if tp in self._struct_pending_verification: - # check that the layout sizes and offsets match the real ones - def check(realvalue, expectedvalue, msg): - if realvalue != expectedvalue: - raise VerificationError( - "%s (we have %d, but C compiler says %d)" - % (msg, expectedvalue, realvalue)) - ffi = self.ffi - BStruct = ffi._get_cached_btype(tp) - layout, cname = self._struct_pending_verification.pop(tp) - check(layout[0], ffi.sizeof(BStruct), "wrong total size") - check(layout[1], ffi.alignof(BStruct), "wrong total alignment") - i = 2 - for fname, ftype, fbitsize, fqual in tp.enumfields(): - if fbitsize >= 0: - continue # xxx ignore fbitsize for now - check(layout[i], ffi.offsetof(BStruct, fname), - "wrong offset for field %r" % (fname,)) - if layout[i+1] != 0: - BField = ffi._get_cached_btype(ftype) - check(layout[i+1], ffi.sizeof(BField), - "wrong size for field %r" % (fname,)) - i += 2 - assert i == len(layout) - - # ---------- - # 'anonymous' declarations. These are produced for anonymous structs - # or unions; the 'name' is obtained by a typedef. - - _generate_cpy_anonymous_collecttype = _generate_nothing - - def _generate_cpy_anonymous_decl(self, tp, name): - if isinstance(tp, model.EnumType): - self._generate_cpy_enum_decl(tp, name, '') - else: - self._generate_struct_or_union_decl(tp, '', name) - - def _generate_cpy_anonymous_method(self, tp, name): - if not isinstance(tp, model.EnumType): - self._generate_struct_or_union_method(tp, '', name) - - def _loading_cpy_anonymous(self, tp, name, module): - if isinstance(tp, model.EnumType): - self._loading_cpy_enum(tp, name, module) - else: - self._loading_struct_or_union(tp, '', name, module) - - def _loaded_cpy_anonymous(self, tp, name, module, **kwds): - if isinstance(tp, model.EnumType): - self._loaded_cpy_enum(tp, name, module, **kwds) - else: - self._loaded_struct_or_union(tp) - - # ---------- - # constants, likely declared with '#define' - - def _generate_cpy_const(self, is_int, name, tp=None, category='const', - vartp=None, delayed=True, size_too=False, - check_value=None): - prnt = self._prnt - funcname = '_cffi_%s_%s' % (category, name) - prnt('static int %s(PyObject *lib)' % funcname) - prnt('{') - prnt(' PyObject *o;') - prnt(' int res;') - if not is_int: - prnt(' %s;' % (vartp or tp).get_c_name(' i', name)) - else: - assert category == 'const' - # - if check_value is not None: - self._check_int_constant_value(name, check_value) - # - if not is_int: - if category == 'var': - realexpr = '&' + name - else: - realexpr = name - prnt(' i = (%s);' % (realexpr,)) - prnt(' o = %s;' % (self._convert_expr_from_c(tp, 'i', - 'variable type'),)) - assert delayed - else: - prnt(' o = _cffi_from_c_int_const(%s);' % name) - prnt(' if (o == NULL)') - prnt(' return -1;') - if size_too: - prnt(' {') - prnt(' PyObject *o1 = o;') - prnt(' o = Py_BuildValue("On", o1, (Py_ssize_t)sizeof(%s));' - % (name,)) - prnt(' Py_DECREF(o1);') - prnt(' if (o == NULL)') - prnt(' return -1;') - prnt(' }') - prnt(' res = PyObject_SetAttrString(lib, "%s", o);' % name) - prnt(' Py_DECREF(o);') - prnt(' if (res < 0)') - prnt(' return -1;') - prnt(' return %s;' % self._chained_list_constants[delayed]) - self._chained_list_constants[delayed] = funcname + '(lib)' - prnt('}') - prnt() - - def _generate_cpy_constant_collecttype(self, tp, name): - is_int = isinstance(tp, model.PrimitiveType) and tp.is_integer_type() - if not is_int: - self._do_collect_type(tp) - - def _generate_cpy_constant_decl(self, tp, name): - is_int = isinstance(tp, model.PrimitiveType) and tp.is_integer_type() - self._generate_cpy_const(is_int, name, tp) - - _generate_cpy_constant_method = _generate_nothing - _loading_cpy_constant = _loaded_noop - _loaded_cpy_constant = _loaded_noop - - # ---------- - # enums - - def _check_int_constant_value(self, name, value, err_prefix=''): - prnt = self._prnt - if value <= 0: - prnt(' if ((%s) > 0 || (long)(%s) != %dL) {' % ( - name, name, value)) - else: - prnt(' if ((%s) <= 0 || (unsigned long)(%s) != %dUL) {' % ( - name, name, value)) - prnt(' char buf[64];') - prnt(' if ((%s) <= 0)' % name) - prnt(' snprintf(buf, 63, "%%ld", (long)(%s));' % name) - prnt(' else') - prnt(' snprintf(buf, 63, "%%lu", (unsigned long)(%s));' % - name) - prnt(' PyErr_Format(_cffi_VerificationError,') - prnt(' "%s%s has the real value %s, not %s",') - prnt(' "%s", "%s", buf, "%d");' % ( - err_prefix, name, value)) - prnt(' return -1;') - prnt(' }') - - def _enum_funcname(self, prefix, name): - # "$enum_$1" => "___D_enum____D_1" - name = name.replace('$', '___D_') - return '_cffi_e_%s_%s' % (prefix, name) - - def _generate_cpy_enum_decl(self, tp, name, prefix='enum'): - if tp.partial: - for enumerator in tp.enumerators: - self._generate_cpy_const(True, enumerator, delayed=False) - return - # - funcname = self._enum_funcname(prefix, name) - prnt = self._prnt - prnt('static int %s(PyObject *lib)' % funcname) - prnt('{') - for enumerator, enumvalue in zip(tp.enumerators, tp.enumvalues): - self._check_int_constant_value(enumerator, enumvalue, - "enum %s: " % name) - prnt(' return %s;' % self._chained_list_constants[True]) - self._chained_list_constants[True] = funcname + '(lib)' - prnt('}') - prnt() - - _generate_cpy_enum_collecttype = _generate_nothing - _generate_cpy_enum_method = _generate_nothing - - def _loading_cpy_enum(self, tp, name, module): - if tp.partial: - enumvalues = [getattr(module, enumerator) - for enumerator in tp.enumerators] - tp.enumvalues = tuple(enumvalues) - tp.partial_resolved = True - - def _loaded_cpy_enum(self, tp, name, module, library): - for enumerator, enumvalue in zip(tp.enumerators, tp.enumvalues): - setattr(library, enumerator, enumvalue) - - # ---------- - # macros: for now only for integers - - def _generate_cpy_macro_decl(self, tp, name): - if tp == '...': - check_value = None - else: - check_value = tp # an integer - self._generate_cpy_const(True, name, check_value=check_value) - - _generate_cpy_macro_collecttype = _generate_nothing - _generate_cpy_macro_method = _generate_nothing - _loading_cpy_macro = _loaded_noop - _loaded_cpy_macro = _loaded_noop - - # ---------- - # global variables - - def _generate_cpy_variable_collecttype(self, tp, name): - if isinstance(tp, model.ArrayType): - tp_ptr = model.PointerType(tp.item) - else: - tp_ptr = model.PointerType(tp) - self._do_collect_type(tp_ptr) - - def _generate_cpy_variable_decl(self, tp, name): - if isinstance(tp, model.ArrayType): - tp_ptr = model.PointerType(tp.item) - self._generate_cpy_const(False, name, tp, vartp=tp_ptr, - size_too = tp.length_is_unknown()) - else: - tp_ptr = model.PointerType(tp) - self._generate_cpy_const(False, name, tp_ptr, category='var') - - _generate_cpy_variable_method = _generate_nothing - _loading_cpy_variable = _loaded_noop - - def _loaded_cpy_variable(self, tp, name, module, library): - value = getattr(library, name) - if isinstance(tp, model.ArrayType): # int a[5] is "constant" in the - # sense that "a=..." is forbidden - if tp.length_is_unknown(): - assert isinstance(value, tuple) - (value, size) = value - BItemType = self.ffi._get_cached_btype(tp.item) - length, rest = divmod(size, self.ffi.sizeof(BItemType)) - if rest != 0: - raise VerificationError( - "bad size: %r does not seem to be an array of %s" % - (name, tp.item)) - tp = tp.resolve_length(length) - # 'value' is a which we have to replace with - # a if the N is actually known - if tp.length is not None: - BArray = self.ffi._get_cached_btype(tp) - value = self.ffi.cast(BArray, value) - setattr(library, name, value) - return - # remove ptr= from the library instance, and replace - # it by a property on the class, which reads/writes into ptr[0]. - ptr = value - delattr(library, name) - def getter(library): - return ptr[0] - def setter(library, value): - ptr[0] = value - setattr(type(library), name, property(getter, setter)) - type(library)._cffi_dir.append(name) - - # ---------- - - def _generate_setup_custom(self): - prnt = self._prnt - prnt('static int _cffi_setup_custom(PyObject *lib)') - prnt('{') - prnt(' return %s;' % self._chained_list_constants[True]) - prnt('}') - -cffimod_header = r''' -#include -#include - -/* this block of #ifs should be kept exactly identical between - c/_cffi_backend.c, cffi/vengine_cpy.py, cffi/vengine_gen.py - and cffi/_cffi_include.h */ -#if defined(_MSC_VER) -# include /* for alloca() */ -# if _MSC_VER < 1600 /* MSVC < 2010 */ - typedef __int8 int8_t; - typedef __int16 int16_t; - typedef __int32 int32_t; - typedef __int64 int64_t; - typedef unsigned __int8 uint8_t; - typedef unsigned __int16 uint16_t; - typedef unsigned __int32 uint32_t; - typedef unsigned __int64 uint64_t; - typedef __int8 int_least8_t; - typedef __int16 int_least16_t; - typedef __int32 int_least32_t; - typedef __int64 int_least64_t; - typedef unsigned __int8 uint_least8_t; - typedef unsigned __int16 uint_least16_t; - typedef unsigned __int32 uint_least32_t; - typedef unsigned __int64 uint_least64_t; - typedef __int8 int_fast8_t; - typedef __int16 int_fast16_t; - typedef __int32 int_fast32_t; - typedef __int64 int_fast64_t; - typedef unsigned __int8 uint_fast8_t; - typedef unsigned __int16 uint_fast16_t; - typedef unsigned __int32 uint_fast32_t; - typedef unsigned __int64 uint_fast64_t; - typedef __int64 intmax_t; - typedef unsigned __int64 uintmax_t; -# else -# include -# endif -# if _MSC_VER < 1800 /* MSVC < 2013 */ -# ifndef __cplusplus - typedef unsigned char _Bool; -# endif -# endif -# define _cffi_float_complex_t _Fcomplex /* include for it */ -# define _cffi_double_complex_t _Dcomplex /* include for it */ -#else -# include -# if (defined (__SVR4) && defined (__sun)) || defined(_AIX) || defined(__hpux) -# include -# endif -# define _cffi_float_complex_t float _Complex -# define _cffi_double_complex_t double _Complex -#endif - -#if PY_MAJOR_VERSION < 3 -# undef PyCapsule_CheckExact -# undef PyCapsule_GetPointer -# define PyCapsule_CheckExact(capsule) (PyCObject_Check(capsule)) -# define PyCapsule_GetPointer(capsule, name) \ - (PyCObject_AsVoidPtr(capsule)) -#endif - -#if PY_MAJOR_VERSION >= 3 -# define PyInt_FromLong PyLong_FromLong -#endif - -#define _cffi_from_c_double PyFloat_FromDouble -#define _cffi_from_c_float PyFloat_FromDouble -#define _cffi_from_c_long PyInt_FromLong -#define _cffi_from_c_ulong PyLong_FromUnsignedLong -#define _cffi_from_c_longlong PyLong_FromLongLong -#define _cffi_from_c_ulonglong PyLong_FromUnsignedLongLong -#define _cffi_from_c__Bool PyBool_FromLong - -#define _cffi_to_c_double PyFloat_AsDouble -#define _cffi_to_c_float PyFloat_AsDouble - -#define _cffi_from_c_int_const(x) \ - (((x) > 0) ? \ - ((unsigned long long)(x) <= (unsigned long long)LONG_MAX) ? \ - PyInt_FromLong((long)(x)) : \ - PyLong_FromUnsignedLongLong((unsigned long long)(x)) : \ - ((long long)(x) >= (long long)LONG_MIN) ? \ - PyInt_FromLong((long)(x)) : \ - PyLong_FromLongLong((long long)(x))) - -#define _cffi_from_c_int(x, type) \ - (((type)-1) > 0 ? /* unsigned */ \ - (sizeof(type) < sizeof(long) ? \ - PyInt_FromLong((long)x) : \ - sizeof(type) == sizeof(long) ? \ - PyLong_FromUnsignedLong((unsigned long)x) : \ - PyLong_FromUnsignedLongLong((unsigned long long)x)) : \ - (sizeof(type) <= sizeof(long) ? \ - PyInt_FromLong((long)x) : \ - PyLong_FromLongLong((long long)x))) - -#define _cffi_to_c_int(o, type) \ - ((type)( \ - sizeof(type) == 1 ? (((type)-1) > 0 ? (type)_cffi_to_c_u8(o) \ - : (type)_cffi_to_c_i8(o)) : \ - sizeof(type) == 2 ? (((type)-1) > 0 ? (type)_cffi_to_c_u16(o) \ - : (type)_cffi_to_c_i16(o)) : \ - sizeof(type) == 4 ? (((type)-1) > 0 ? (type)_cffi_to_c_u32(o) \ - : (type)_cffi_to_c_i32(o)) : \ - sizeof(type) == 8 ? (((type)-1) > 0 ? (type)_cffi_to_c_u64(o) \ - : (type)_cffi_to_c_i64(o)) : \ - (Py_FatalError("unsupported size for type " #type), (type)0))) - -#define _cffi_to_c_i8 \ - ((int(*)(PyObject *))_cffi_exports[1]) -#define _cffi_to_c_u8 \ - ((int(*)(PyObject *))_cffi_exports[2]) -#define _cffi_to_c_i16 \ - ((int(*)(PyObject *))_cffi_exports[3]) -#define _cffi_to_c_u16 \ - ((int(*)(PyObject *))_cffi_exports[4]) -#define _cffi_to_c_i32 \ - ((int(*)(PyObject *))_cffi_exports[5]) -#define _cffi_to_c_u32 \ - ((unsigned int(*)(PyObject *))_cffi_exports[6]) -#define _cffi_to_c_i64 \ - ((long long(*)(PyObject *))_cffi_exports[7]) -#define _cffi_to_c_u64 \ - ((unsigned long long(*)(PyObject *))_cffi_exports[8]) -#define _cffi_to_c_char \ - ((int(*)(PyObject *))_cffi_exports[9]) -#define _cffi_from_c_pointer \ - ((PyObject *(*)(char *, CTypeDescrObject *))_cffi_exports[10]) -#define _cffi_to_c_pointer \ - ((char *(*)(PyObject *, CTypeDescrObject *))_cffi_exports[11]) -#define _cffi_get_struct_layout \ - ((PyObject *(*)(Py_ssize_t[]))_cffi_exports[12]) -#define _cffi_restore_errno \ - ((void(*)(void))_cffi_exports[13]) -#define _cffi_save_errno \ - ((void(*)(void))_cffi_exports[14]) -#define _cffi_from_c_char \ - ((PyObject *(*)(char))_cffi_exports[15]) -#define _cffi_from_c_deref \ - ((PyObject *(*)(char *, CTypeDescrObject *))_cffi_exports[16]) -#define _cffi_to_c \ - ((int(*)(char *, CTypeDescrObject *, PyObject *))_cffi_exports[17]) -#define _cffi_from_c_struct \ - ((PyObject *(*)(char *, CTypeDescrObject *))_cffi_exports[18]) -#define _cffi_to_c_wchar_t \ - ((wchar_t(*)(PyObject *))_cffi_exports[19]) -#define _cffi_from_c_wchar_t \ - ((PyObject *(*)(wchar_t))_cffi_exports[20]) -#define _cffi_to_c_long_double \ - ((long double(*)(PyObject *))_cffi_exports[21]) -#define _cffi_to_c__Bool \ - ((_Bool(*)(PyObject *))_cffi_exports[22]) -#define _cffi_prepare_pointer_call_argument \ - ((Py_ssize_t(*)(CTypeDescrObject *, PyObject *, char **))_cffi_exports[23]) -#define _cffi_convert_array_from_object \ - ((int(*)(char *, CTypeDescrObject *, PyObject *))_cffi_exports[24]) -#define _CFFI_NUM_EXPORTS 25 - -typedef struct _ctypedescr CTypeDescrObject; - -static void *_cffi_exports[_CFFI_NUM_EXPORTS]; -static PyObject *_cffi_types, *_cffi_VerificationError; - -static int _cffi_setup_custom(PyObject *lib); /* forward */ - -static PyObject *_cffi_setup(PyObject *self, PyObject *args) -{ - PyObject *library; - int was_alive = (_cffi_types != NULL); - (void)self; /* unused */ - if (!PyArg_ParseTuple(args, "OOO", &_cffi_types, &_cffi_VerificationError, - &library)) - return NULL; - Py_INCREF(_cffi_types); - Py_INCREF(_cffi_VerificationError); - if (_cffi_setup_custom(library) < 0) - return NULL; - return PyBool_FromLong(was_alive); -} - -union _cffi_union_alignment_u { - unsigned char m_char; - unsigned short m_short; - unsigned int m_int; - unsigned long m_long; - unsigned long long m_longlong; - float m_float; - double m_double; - long double m_longdouble; -}; - -struct _cffi_freeme_s { - struct _cffi_freeme_s *next; - union _cffi_union_alignment_u alignment; -}; - -#ifdef __GNUC__ - __attribute__((unused)) -#endif -static int _cffi_convert_array_argument(CTypeDescrObject *ctptr, PyObject *arg, - char **output_data, Py_ssize_t datasize, - struct _cffi_freeme_s **freeme) -{ - char *p; - if (datasize < 0) - return -1; - - p = *output_data; - if (p == NULL) { - struct _cffi_freeme_s *fp = (struct _cffi_freeme_s *)PyObject_Malloc( - offsetof(struct _cffi_freeme_s, alignment) + (size_t)datasize); - if (fp == NULL) - return -1; - fp->next = *freeme; - *freeme = fp; - p = *output_data = (char *)&fp->alignment; - } - memset((void *)p, 0, (size_t)datasize); - return _cffi_convert_array_from_object(p, ctptr, arg); -} - -#ifdef __GNUC__ - __attribute__((unused)) -#endif -static void _cffi_free_array_arguments(struct _cffi_freeme_s *freeme) -{ - do { - void *p = (void *)freeme; - freeme = freeme->next; - PyObject_Free(p); - } while (freeme != NULL); -} - -static int _cffi_init(void) -{ - PyObject *module, *c_api_object = NULL; - - module = PyImport_ImportModule("_cffi_backend"); - if (module == NULL) - goto failure; - - c_api_object = PyObject_GetAttrString(module, "_C_API"); - if (c_api_object == NULL) - goto failure; - if (!PyCapsule_CheckExact(c_api_object)) { - PyErr_SetNone(PyExc_ImportError); - goto failure; - } - memcpy(_cffi_exports, PyCapsule_GetPointer(c_api_object, "cffi"), - _CFFI_NUM_EXPORTS * sizeof(void *)); - - Py_DECREF(module); - Py_DECREF(c_api_object); - return 0; - - failure: - Py_XDECREF(module); - Py_XDECREF(c_api_object); - return -1; -} - -#define _cffi_type(num) ((CTypeDescrObject *)PyList_GET_ITEM(_cffi_types, num)) - -/**********/ -''' diff --git a/venv/lib/python3.9/site-packages/cffi/vengine_gen.py b/venv/lib/python3.9/site-packages/cffi/vengine_gen.py deleted file mode 100644 index bffc821..0000000 --- a/venv/lib/python3.9/site-packages/cffi/vengine_gen.py +++ /dev/null @@ -1,679 +0,0 @@ -# -# DEPRECATED: implementation for ffi.verify() -# -import sys, os -import types - -from . import model -from .error import VerificationError - - -class VGenericEngine(object): - _class_key = 'g' - _gen_python_module = False - - def __init__(self, verifier): - self.verifier = verifier - self.ffi = verifier.ffi - self.export_symbols = [] - self._struct_pending_verification = {} - - def patch_extension_kwds(self, kwds): - # add 'export_symbols' to the dictionary. Note that we add the - # list before filling it. When we fill it, it will thus also show - # up in kwds['export_symbols']. - kwds.setdefault('export_symbols', self.export_symbols) - - def find_module(self, module_name, path, so_suffixes): - for so_suffix in so_suffixes: - basename = module_name + so_suffix - if path is None: - path = sys.path - for dirname in path: - filename = os.path.join(dirname, basename) - if os.path.isfile(filename): - return filename - - def collect_types(self): - pass # not needed in the generic engine - - def _prnt(self, what=''): - self._f.write(what + '\n') - - def write_source_to_f(self): - prnt = self._prnt - # first paste some standard set of lines that are mostly '#include' - prnt(cffimod_header) - # then paste the C source given by the user, verbatim. - prnt(self.verifier.preamble) - # - # call generate_gen_xxx_decl(), for every xxx found from - # ffi._parser._declarations. This generates all the functions. - self._generate('decl') - # - # on Windows, distutils insists on putting init_cffi_xyz in - # 'export_symbols', so instead of fighting it, just give up and - # give it one - if sys.platform == 'win32': - if sys.version_info >= (3,): - prefix = 'PyInit_' - else: - prefix = 'init' - modname = self.verifier.get_module_name() - prnt("void %s%s(void) { }\n" % (prefix, modname)) - - def load_library(self, flags=0): - # import it with the CFFI backend - backend = self.ffi._backend - # needs to make a path that contains '/', on Posix - filename = os.path.join(os.curdir, self.verifier.modulefilename) - module = backend.load_library(filename, flags) - # - # call loading_gen_struct() to get the struct layout inferred by - # the C compiler - self._load(module, 'loading') - - # build the FFILibrary class and instance, this is a module subclass - # because modules are expected to have usually-constant-attributes and - # in PyPy this means the JIT is able to treat attributes as constant, - # which we want. - class FFILibrary(types.ModuleType): - _cffi_generic_module = module - _cffi_ffi = self.ffi - _cffi_dir = [] - def __dir__(self): - return FFILibrary._cffi_dir - library = FFILibrary("") - # - # finally, call the loaded_gen_xxx() functions. This will set - # up the 'library' object. - self._load(module, 'loaded', library=library) - return library - - def _get_declarations(self): - lst = [(key, tp) for (key, (tp, qual)) in - self.ffi._parser._declarations.items()] - lst.sort() - return lst - - def _generate(self, step_name): - for name, tp in self._get_declarations(): - kind, realname = name.split(' ', 1) - try: - method = getattr(self, '_generate_gen_%s_%s' % (kind, - step_name)) - except AttributeError: - raise VerificationError( - "not implemented in verify(): %r" % name) - try: - method(tp, realname) - except Exception as e: - model.attach_exception_info(e, name) - raise - - def _load(self, module, step_name, **kwds): - for name, tp in self._get_declarations(): - kind, realname = name.split(' ', 1) - method = getattr(self, '_%s_gen_%s' % (step_name, kind)) - try: - method(tp, realname, module, **kwds) - except Exception as e: - model.attach_exception_info(e, name) - raise - - def _generate_nothing(self, tp, name): - pass - - def _loaded_noop(self, tp, name, module, **kwds): - pass - - # ---------- - # typedefs: generates no code so far - - _generate_gen_typedef_decl = _generate_nothing - _loading_gen_typedef = _loaded_noop - _loaded_gen_typedef = _loaded_noop - - # ---------- - # function declarations - - def _generate_gen_function_decl(self, tp, name): - assert isinstance(tp, model.FunctionPtrType) - if tp.ellipsis: - # cannot support vararg functions better than this: check for its - # exact type (including the fixed arguments), and build it as a - # constant function pointer (no _cffi_f_%s wrapper) - self._generate_gen_const(False, name, tp) - return - prnt = self._prnt - numargs = len(tp.args) - argnames = [] - for i, type in enumerate(tp.args): - indirection = '' - if isinstance(type, model.StructOrUnion): - indirection = '*' - argnames.append('%sx%d' % (indirection, i)) - context = 'argument of %s' % name - arglist = [type.get_c_name(' %s' % arg, context) - for type, arg in zip(tp.args, argnames)] - tpresult = tp.result - if isinstance(tpresult, model.StructOrUnion): - arglist.insert(0, tpresult.get_c_name(' *r', context)) - tpresult = model.void_type - arglist = ', '.join(arglist) or 'void' - wrappername = '_cffi_f_%s' % name - self.export_symbols.append(wrappername) - if tp.abi: - abi = tp.abi + ' ' - else: - abi = '' - funcdecl = ' %s%s(%s)' % (abi, wrappername, arglist) - context = 'result of %s' % name - prnt(tpresult.get_c_name(funcdecl, context)) - prnt('{') - # - if isinstance(tp.result, model.StructOrUnion): - result_code = '*r = ' - elif not isinstance(tp.result, model.VoidType): - result_code = 'return ' - else: - result_code = '' - prnt(' %s%s(%s);' % (result_code, name, ', '.join(argnames))) - prnt('}') - prnt() - - _loading_gen_function = _loaded_noop - - def _loaded_gen_function(self, tp, name, module, library): - assert isinstance(tp, model.FunctionPtrType) - if tp.ellipsis: - newfunction = self._load_constant(False, tp, name, module) - else: - indirections = [] - base_tp = tp - if (any(isinstance(typ, model.StructOrUnion) for typ in tp.args) - or isinstance(tp.result, model.StructOrUnion)): - indirect_args = [] - for i, typ in enumerate(tp.args): - if isinstance(typ, model.StructOrUnion): - typ = model.PointerType(typ) - indirections.append((i, typ)) - indirect_args.append(typ) - indirect_result = tp.result - if isinstance(indirect_result, model.StructOrUnion): - if indirect_result.fldtypes is None: - raise TypeError("'%s' is used as result type, " - "but is opaque" % ( - indirect_result._get_c_name(),)) - indirect_result = model.PointerType(indirect_result) - indirect_args.insert(0, indirect_result) - indirections.insert(0, ("result", indirect_result)) - indirect_result = model.void_type - tp = model.FunctionPtrType(tuple(indirect_args), - indirect_result, tp.ellipsis) - BFunc = self.ffi._get_cached_btype(tp) - wrappername = '_cffi_f_%s' % name - newfunction = module.load_function(BFunc, wrappername) - for i, typ in indirections: - newfunction = self._make_struct_wrapper(newfunction, i, typ, - base_tp) - setattr(library, name, newfunction) - type(library)._cffi_dir.append(name) - - def _make_struct_wrapper(self, oldfunc, i, tp, base_tp): - backend = self.ffi._backend - BType = self.ffi._get_cached_btype(tp) - if i == "result": - ffi = self.ffi - def newfunc(*args): - res = ffi.new(BType) - oldfunc(res, *args) - return res[0] - else: - def newfunc(*args): - args = args[:i] + (backend.newp(BType, args[i]),) + args[i+1:] - return oldfunc(*args) - newfunc._cffi_base_type = base_tp - return newfunc - - # ---------- - # named structs - - def _generate_gen_struct_decl(self, tp, name): - assert name == tp.name - self._generate_struct_or_union_decl(tp, 'struct', name) - - def _loading_gen_struct(self, tp, name, module): - self._loading_struct_or_union(tp, 'struct', name, module) - - def _loaded_gen_struct(self, tp, name, module, **kwds): - self._loaded_struct_or_union(tp) - - def _generate_gen_union_decl(self, tp, name): - assert name == tp.name - self._generate_struct_or_union_decl(tp, 'union', name) - - def _loading_gen_union(self, tp, name, module): - self._loading_struct_or_union(tp, 'union', name, module) - - def _loaded_gen_union(self, tp, name, module, **kwds): - self._loaded_struct_or_union(tp) - - def _generate_struct_or_union_decl(self, tp, prefix, name): - if tp.fldnames is None: - return # nothing to do with opaque structs - checkfuncname = '_cffi_check_%s_%s' % (prefix, name) - layoutfuncname = '_cffi_layout_%s_%s' % (prefix, name) - cname = ('%s %s' % (prefix, name)).strip() - # - prnt = self._prnt - prnt('static void %s(%s *p)' % (checkfuncname, cname)) - prnt('{') - prnt(' /* only to generate compile-time warnings or errors */') - prnt(' (void)p;') - for fname, ftype, fbitsize, fqual in tp.enumfields(): - if (isinstance(ftype, model.PrimitiveType) - and ftype.is_integer_type()) or fbitsize >= 0: - # accept all integers, but complain on float or double - prnt(' (void)((p->%s) << 1);' % fname) - else: - # only accept exactly the type declared. - try: - prnt(' { %s = &p->%s; (void)tmp; }' % ( - ftype.get_c_name('*tmp', 'field %r'%fname, quals=fqual), - fname)) - except VerificationError as e: - prnt(' /* %s */' % str(e)) # cannot verify it, ignore - prnt('}') - self.export_symbols.append(layoutfuncname) - prnt('intptr_t %s(intptr_t i)' % (layoutfuncname,)) - prnt('{') - prnt(' struct _cffi_aligncheck { char x; %s y; };' % cname) - prnt(' static intptr_t nums[] = {') - prnt(' sizeof(%s),' % cname) - prnt(' offsetof(struct _cffi_aligncheck, y),') - for fname, ftype, fbitsize, fqual in tp.enumfields(): - if fbitsize >= 0: - continue # xxx ignore fbitsize for now - prnt(' offsetof(%s, %s),' % (cname, fname)) - if isinstance(ftype, model.ArrayType) and ftype.length is None: - prnt(' 0, /* %s */' % ftype._get_c_name()) - else: - prnt(' sizeof(((%s *)0)->%s),' % (cname, fname)) - prnt(' -1') - prnt(' };') - prnt(' return nums[i];') - prnt(' /* the next line is not executed, but compiled */') - prnt(' %s(0);' % (checkfuncname,)) - prnt('}') - prnt() - - def _loading_struct_or_union(self, tp, prefix, name, module): - if tp.fldnames is None: - return # nothing to do with opaque structs - layoutfuncname = '_cffi_layout_%s_%s' % (prefix, name) - # - BFunc = self.ffi._typeof_locked("intptr_t(*)(intptr_t)")[0] - function = module.load_function(BFunc, layoutfuncname) - layout = [] - num = 0 - while True: - x = function(num) - if x < 0: break - layout.append(x) - num += 1 - if isinstance(tp, model.StructOrUnion) and tp.partial: - # use the function()'s sizes and offsets to guide the - # layout of the struct - totalsize = layout[0] - totalalignment = layout[1] - fieldofs = layout[2::2] - fieldsize = layout[3::2] - tp.force_flatten() - assert len(fieldofs) == len(fieldsize) == len(tp.fldnames) - tp.fixedlayout = fieldofs, fieldsize, totalsize, totalalignment - else: - cname = ('%s %s' % (prefix, name)).strip() - self._struct_pending_verification[tp] = layout, cname - - def _loaded_struct_or_union(self, tp): - if tp.fldnames is None: - return # nothing to do with opaque structs - self.ffi._get_cached_btype(tp) # force 'fixedlayout' to be considered - - if tp in self._struct_pending_verification: - # check that the layout sizes and offsets match the real ones - def check(realvalue, expectedvalue, msg): - if realvalue != expectedvalue: - raise VerificationError( - "%s (we have %d, but C compiler says %d)" - % (msg, expectedvalue, realvalue)) - ffi = self.ffi - BStruct = ffi._get_cached_btype(tp) - layout, cname = self._struct_pending_verification.pop(tp) - check(layout[0], ffi.sizeof(BStruct), "wrong total size") - check(layout[1], ffi.alignof(BStruct), "wrong total alignment") - i = 2 - for fname, ftype, fbitsize, fqual in tp.enumfields(): - if fbitsize >= 0: - continue # xxx ignore fbitsize for now - check(layout[i], ffi.offsetof(BStruct, fname), - "wrong offset for field %r" % (fname,)) - if layout[i+1] != 0: - BField = ffi._get_cached_btype(ftype) - check(layout[i+1], ffi.sizeof(BField), - "wrong size for field %r" % (fname,)) - i += 2 - assert i == len(layout) - - # ---------- - # 'anonymous' declarations. These are produced for anonymous structs - # or unions; the 'name' is obtained by a typedef. - - def _generate_gen_anonymous_decl(self, tp, name): - if isinstance(tp, model.EnumType): - self._generate_gen_enum_decl(tp, name, '') - else: - self._generate_struct_or_union_decl(tp, '', name) - - def _loading_gen_anonymous(self, tp, name, module): - if isinstance(tp, model.EnumType): - self._loading_gen_enum(tp, name, module, '') - else: - self._loading_struct_or_union(tp, '', name, module) - - def _loaded_gen_anonymous(self, tp, name, module, **kwds): - if isinstance(tp, model.EnumType): - self._loaded_gen_enum(tp, name, module, **kwds) - else: - self._loaded_struct_or_union(tp) - - # ---------- - # constants, likely declared with '#define' - - def _generate_gen_const(self, is_int, name, tp=None, category='const', - check_value=None): - prnt = self._prnt - funcname = '_cffi_%s_%s' % (category, name) - self.export_symbols.append(funcname) - if check_value is not None: - assert is_int - assert category == 'const' - prnt('int %s(char *out_error)' % funcname) - prnt('{') - self._check_int_constant_value(name, check_value) - prnt(' return 0;') - prnt('}') - elif is_int: - assert category == 'const' - prnt('int %s(long long *out_value)' % funcname) - prnt('{') - prnt(' *out_value = (long long)(%s);' % (name,)) - prnt(' return (%s) <= 0;' % (name,)) - prnt('}') - else: - assert tp is not None - assert check_value is None - if category == 'var': - ampersand = '&' - else: - ampersand = '' - extra = '' - if category == 'const' and isinstance(tp, model.StructOrUnion): - extra = 'const *' - ampersand = '&' - prnt(tp.get_c_name(' %s%s(void)' % (extra, funcname), name)) - prnt('{') - prnt(' return (%s%s);' % (ampersand, name)) - prnt('}') - prnt() - - def _generate_gen_constant_decl(self, tp, name): - is_int = isinstance(tp, model.PrimitiveType) and tp.is_integer_type() - self._generate_gen_const(is_int, name, tp) - - _loading_gen_constant = _loaded_noop - - def _load_constant(self, is_int, tp, name, module, check_value=None): - funcname = '_cffi_const_%s' % name - if check_value is not None: - assert is_int - self._load_known_int_constant(module, funcname) - value = check_value - elif is_int: - BType = self.ffi._typeof_locked("long long*")[0] - BFunc = self.ffi._typeof_locked("int(*)(long long*)")[0] - function = module.load_function(BFunc, funcname) - p = self.ffi.new(BType) - negative = function(p) - value = int(p[0]) - if value < 0 and not negative: - BLongLong = self.ffi._typeof_locked("long long")[0] - value += (1 << (8*self.ffi.sizeof(BLongLong))) - else: - assert check_value is None - fntypeextra = '(*)(void)' - if isinstance(tp, model.StructOrUnion): - fntypeextra = '*' + fntypeextra - BFunc = self.ffi._typeof_locked(tp.get_c_name(fntypeextra, name))[0] - function = module.load_function(BFunc, funcname) - value = function() - if isinstance(tp, model.StructOrUnion): - value = value[0] - return value - - def _loaded_gen_constant(self, tp, name, module, library): - is_int = isinstance(tp, model.PrimitiveType) and tp.is_integer_type() - value = self._load_constant(is_int, tp, name, module) - setattr(library, name, value) - type(library)._cffi_dir.append(name) - - # ---------- - # enums - - def _check_int_constant_value(self, name, value): - prnt = self._prnt - if value <= 0: - prnt(' if ((%s) > 0 || (long)(%s) != %dL) {' % ( - name, name, value)) - else: - prnt(' if ((%s) <= 0 || (unsigned long)(%s) != %dUL) {' % ( - name, name, value)) - prnt(' char buf[64];') - prnt(' if ((%s) <= 0)' % name) - prnt(' sprintf(buf, "%%ld", (long)(%s));' % name) - prnt(' else') - prnt(' sprintf(buf, "%%lu", (unsigned long)(%s));' % - name) - prnt(' sprintf(out_error, "%s has the real value %s, not %s",') - prnt(' "%s", buf, "%d");' % (name[:100], value)) - prnt(' return -1;') - prnt(' }') - - def _load_known_int_constant(self, module, funcname): - BType = self.ffi._typeof_locked("char[]")[0] - BFunc = self.ffi._typeof_locked("int(*)(char*)")[0] - function = module.load_function(BFunc, funcname) - p = self.ffi.new(BType, 256) - if function(p) < 0: - error = self.ffi.string(p) - if sys.version_info >= (3,): - error = str(error, 'utf-8') - raise VerificationError(error) - - def _enum_funcname(self, prefix, name): - # "$enum_$1" => "___D_enum____D_1" - name = name.replace('$', '___D_') - return '_cffi_e_%s_%s' % (prefix, name) - - def _generate_gen_enum_decl(self, tp, name, prefix='enum'): - if tp.partial: - for enumerator in tp.enumerators: - self._generate_gen_const(True, enumerator) - return - # - funcname = self._enum_funcname(prefix, name) - self.export_symbols.append(funcname) - prnt = self._prnt - prnt('int %s(char *out_error)' % funcname) - prnt('{') - for enumerator, enumvalue in zip(tp.enumerators, tp.enumvalues): - self._check_int_constant_value(enumerator, enumvalue) - prnt(' return 0;') - prnt('}') - prnt() - - def _loading_gen_enum(self, tp, name, module, prefix='enum'): - if tp.partial: - enumvalues = [self._load_constant(True, tp, enumerator, module) - for enumerator in tp.enumerators] - tp.enumvalues = tuple(enumvalues) - tp.partial_resolved = True - else: - funcname = self._enum_funcname(prefix, name) - self._load_known_int_constant(module, funcname) - - def _loaded_gen_enum(self, tp, name, module, library): - for enumerator, enumvalue in zip(tp.enumerators, tp.enumvalues): - setattr(library, enumerator, enumvalue) - type(library)._cffi_dir.append(enumerator) - - # ---------- - # macros: for now only for integers - - def _generate_gen_macro_decl(self, tp, name): - if tp == '...': - check_value = None - else: - check_value = tp # an integer - self._generate_gen_const(True, name, check_value=check_value) - - _loading_gen_macro = _loaded_noop - - def _loaded_gen_macro(self, tp, name, module, library): - if tp == '...': - check_value = None - else: - check_value = tp # an integer - value = self._load_constant(True, tp, name, module, - check_value=check_value) - setattr(library, name, value) - type(library)._cffi_dir.append(name) - - # ---------- - # global variables - - def _generate_gen_variable_decl(self, tp, name): - if isinstance(tp, model.ArrayType): - if tp.length_is_unknown(): - prnt = self._prnt - funcname = '_cffi_sizeof_%s' % (name,) - self.export_symbols.append(funcname) - prnt("size_t %s(void)" % funcname) - prnt("{") - prnt(" return sizeof(%s);" % (name,)) - prnt("}") - tp_ptr = model.PointerType(tp.item) - self._generate_gen_const(False, name, tp_ptr) - else: - tp_ptr = model.PointerType(tp) - self._generate_gen_const(False, name, tp_ptr, category='var') - - _loading_gen_variable = _loaded_noop - - def _loaded_gen_variable(self, tp, name, module, library): - if isinstance(tp, model.ArrayType): # int a[5] is "constant" in the - # sense that "a=..." is forbidden - if tp.length_is_unknown(): - funcname = '_cffi_sizeof_%s' % (name,) - BFunc = self.ffi._typeof_locked('size_t(*)(void)')[0] - function = module.load_function(BFunc, funcname) - size = function() - BItemType = self.ffi._get_cached_btype(tp.item) - length, rest = divmod(size, self.ffi.sizeof(BItemType)) - if rest != 0: - raise VerificationError( - "bad size: %r does not seem to be an array of %s" % - (name, tp.item)) - tp = tp.resolve_length(length) - tp_ptr = model.PointerType(tp.item) - value = self._load_constant(False, tp_ptr, name, module) - # 'value' is a which we have to replace with - # a if the N is actually known - if tp.length is not None: - BArray = self.ffi._get_cached_btype(tp) - value = self.ffi.cast(BArray, value) - setattr(library, name, value) - type(library)._cffi_dir.append(name) - return - # remove ptr= from the library instance, and replace - # it by a property on the class, which reads/writes into ptr[0]. - funcname = '_cffi_var_%s' % name - BFunc = self.ffi._typeof_locked(tp.get_c_name('*(*)(void)', name))[0] - function = module.load_function(BFunc, funcname) - ptr = function() - def getter(library): - return ptr[0] - def setter(library, value): - ptr[0] = value - setattr(type(library), name, property(getter, setter)) - type(library)._cffi_dir.append(name) - -cffimod_header = r''' -#include -#include -#include -#include -#include /* XXX for ssize_t on some platforms */ - -/* this block of #ifs should be kept exactly identical between - c/_cffi_backend.c, cffi/vengine_cpy.py, cffi/vengine_gen.py - and cffi/_cffi_include.h */ -#if defined(_MSC_VER) -# include /* for alloca() */ -# if _MSC_VER < 1600 /* MSVC < 2010 */ - typedef __int8 int8_t; - typedef __int16 int16_t; - typedef __int32 int32_t; - typedef __int64 int64_t; - typedef unsigned __int8 uint8_t; - typedef unsigned __int16 uint16_t; - typedef unsigned __int32 uint32_t; - typedef unsigned __int64 uint64_t; - typedef __int8 int_least8_t; - typedef __int16 int_least16_t; - typedef __int32 int_least32_t; - typedef __int64 int_least64_t; - typedef unsigned __int8 uint_least8_t; - typedef unsigned __int16 uint_least16_t; - typedef unsigned __int32 uint_least32_t; - typedef unsigned __int64 uint_least64_t; - typedef __int8 int_fast8_t; - typedef __int16 int_fast16_t; - typedef __int32 int_fast32_t; - typedef __int64 int_fast64_t; - typedef unsigned __int8 uint_fast8_t; - typedef unsigned __int16 uint_fast16_t; - typedef unsigned __int32 uint_fast32_t; - typedef unsigned __int64 uint_fast64_t; - typedef __int64 intmax_t; - typedef unsigned __int64 uintmax_t; -# else -# include -# endif -# if _MSC_VER < 1800 /* MSVC < 2013 */ -# ifndef __cplusplus - typedef unsigned char _Bool; -# endif -# endif -# define _cffi_float_complex_t _Fcomplex /* include for it */ -# define _cffi_double_complex_t _Dcomplex /* include for it */ -#else -# include -# if (defined (__SVR4) && defined (__sun)) || defined(_AIX) || defined(__hpux) -# include -# endif -# define _cffi_float_complex_t float _Complex -# define _cffi_double_complex_t double _Complex -#endif -''' diff --git a/venv/lib/python3.9/site-packages/cffi/verifier.py b/venv/lib/python3.9/site-packages/cffi/verifier.py deleted file mode 100644 index e392a2b..0000000 --- a/venv/lib/python3.9/site-packages/cffi/verifier.py +++ /dev/null @@ -1,306 +0,0 @@ -# -# DEPRECATED: implementation for ffi.verify() -# -import sys, os, binascii, shutil, io -from . import __version_verifier_modules__ -from . import ffiplatform -from .error import VerificationError - -if sys.version_info >= (3, 3): - import importlib.machinery - def _extension_suffixes(): - return importlib.machinery.EXTENSION_SUFFIXES[:] -else: - import imp - def _extension_suffixes(): - return [suffix for suffix, _, type in imp.get_suffixes() - if type == imp.C_EXTENSION] - - -if sys.version_info >= (3,): - NativeIO = io.StringIO -else: - class NativeIO(io.BytesIO): - def write(self, s): - if isinstance(s, unicode): - s = s.encode('ascii') - super(NativeIO, self).write(s) - - -class Verifier(object): - - def __init__(self, ffi, preamble, tmpdir=None, modulename=None, - ext_package=None, tag='', force_generic_engine=False, - source_extension='.c', flags=None, relative_to=None, **kwds): - if ffi._parser._uses_new_feature: - raise VerificationError( - "feature not supported with ffi.verify(), but only " - "with ffi.set_source(): %s" % (ffi._parser._uses_new_feature,)) - self.ffi = ffi - self.preamble = preamble - if not modulename: - flattened_kwds = ffiplatform.flatten(kwds) - vengine_class = _locate_engine_class(ffi, force_generic_engine) - self._vengine = vengine_class(self) - self._vengine.patch_extension_kwds(kwds) - self.flags = flags - self.kwds = self.make_relative_to(kwds, relative_to) - # - if modulename: - if tag: - raise TypeError("can't specify both 'modulename' and 'tag'") - else: - key = '\x00'.join(['%d.%d' % sys.version_info[:2], - __version_verifier_modules__, - preamble, flattened_kwds] + - ffi._cdefsources) - if sys.version_info >= (3,): - key = key.encode('utf-8') - k1 = hex(binascii.crc32(key[0::2]) & 0xffffffff) - k1 = k1.lstrip('0x').rstrip('L') - k2 = hex(binascii.crc32(key[1::2]) & 0xffffffff) - k2 = k2.lstrip('0').rstrip('L') - modulename = '_cffi_%s_%s%s%s' % (tag, self._vengine._class_key, - k1, k2) - suffix = _get_so_suffixes()[0] - self.tmpdir = tmpdir or _caller_dir_pycache() - self.sourcefilename = os.path.join(self.tmpdir, modulename + source_extension) - self.modulefilename = os.path.join(self.tmpdir, modulename + suffix) - self.ext_package = ext_package - self._has_source = False - self._has_module = False - - def write_source(self, file=None): - """Write the C source code. It is produced in 'self.sourcefilename', - which can be tweaked beforehand.""" - with self.ffi._lock: - if self._has_source and file is None: - raise VerificationError( - "source code already written") - self._write_source(file) - - def compile_module(self): - """Write the C source code (if not done already) and compile it. - This produces a dynamic link library in 'self.modulefilename'.""" - with self.ffi._lock: - if self._has_module: - raise VerificationError("module already compiled") - if not self._has_source: - self._write_source() - self._compile_module() - - def load_library(self): - """Get a C module from this Verifier instance. - Returns an instance of a FFILibrary class that behaves like the - objects returned by ffi.dlopen(), but that delegates all - operations to the C module. If necessary, the C code is written - and compiled first. - """ - with self.ffi._lock: - if not self._has_module: - self._locate_module() - if not self._has_module: - if not self._has_source: - self._write_source() - self._compile_module() - return self._load_library() - - def get_module_name(self): - basename = os.path.basename(self.modulefilename) - # kill both the .so extension and the other .'s, as introduced - # by Python 3: 'basename.cpython-33m.so' - basename = basename.split('.', 1)[0] - # and the _d added in Python 2 debug builds --- but try to be - # conservative and not kill a legitimate _d - if basename.endswith('_d') and hasattr(sys, 'gettotalrefcount'): - basename = basename[:-2] - return basename - - def get_extension(self): - if not self._has_source: - with self.ffi._lock: - if not self._has_source: - self._write_source() - sourcename = ffiplatform.maybe_relative_path(self.sourcefilename) - modname = self.get_module_name() - return ffiplatform.get_extension(sourcename, modname, **self.kwds) - - def generates_python_module(self): - return self._vengine._gen_python_module - - def make_relative_to(self, kwds, relative_to): - if relative_to and os.path.dirname(relative_to): - dirname = os.path.dirname(relative_to) - kwds = kwds.copy() - for key in ffiplatform.LIST_OF_FILE_NAMES: - if key in kwds: - lst = kwds[key] - if not isinstance(lst, (list, tuple)): - raise TypeError("keyword '%s' should be a list or tuple" - % (key,)) - lst = [os.path.join(dirname, fn) for fn in lst] - kwds[key] = lst - return kwds - - # ---------- - - def _locate_module(self): - if not os.path.isfile(self.modulefilename): - if self.ext_package: - try: - pkg = __import__(self.ext_package, None, None, ['__doc__']) - except ImportError: - return # cannot import the package itself, give up - # (e.g. it might be called differently before installation) - path = pkg.__path__ - else: - path = None - filename = self._vengine.find_module(self.get_module_name(), path, - _get_so_suffixes()) - if filename is None: - return - self.modulefilename = filename - self._vengine.collect_types() - self._has_module = True - - def _write_source_to(self, file): - self._vengine._f = file - try: - self._vengine.write_source_to_f() - finally: - del self._vengine._f - - def _write_source(self, file=None): - if file is not None: - self._write_source_to(file) - else: - # Write our source file to an in memory file. - f = NativeIO() - self._write_source_to(f) - source_data = f.getvalue() - - # Determine if this matches the current file - if os.path.exists(self.sourcefilename): - with open(self.sourcefilename, "r") as fp: - needs_written = not (fp.read() == source_data) - else: - needs_written = True - - # Actually write the file out if it doesn't match - if needs_written: - _ensure_dir(self.sourcefilename) - with open(self.sourcefilename, "w") as fp: - fp.write(source_data) - - # Set this flag - self._has_source = True - - def _compile_module(self): - # compile this C source - tmpdir = os.path.dirname(self.sourcefilename) - outputfilename = ffiplatform.compile(tmpdir, self.get_extension()) - try: - same = ffiplatform.samefile(outputfilename, self.modulefilename) - except OSError: - same = False - if not same: - _ensure_dir(self.modulefilename) - shutil.move(outputfilename, self.modulefilename) - self._has_module = True - - def _load_library(self): - assert self._has_module - if self.flags is not None: - return self._vengine.load_library(self.flags) - else: - return self._vengine.load_library() - -# ____________________________________________________________ - -_FORCE_GENERIC_ENGINE = False # for tests - -def _locate_engine_class(ffi, force_generic_engine): - if _FORCE_GENERIC_ENGINE: - force_generic_engine = True - if not force_generic_engine: - if '__pypy__' in sys.builtin_module_names: - force_generic_engine = True - else: - try: - import _cffi_backend - except ImportError: - _cffi_backend = '?' - if ffi._backend is not _cffi_backend: - force_generic_engine = True - if force_generic_engine: - from . import vengine_gen - return vengine_gen.VGenericEngine - else: - from . import vengine_cpy - return vengine_cpy.VCPythonEngine - -# ____________________________________________________________ - -_TMPDIR = None - -def _caller_dir_pycache(): - if _TMPDIR: - return _TMPDIR - result = os.environ.get('CFFI_TMPDIR') - if result: - return result - filename = sys._getframe(2).f_code.co_filename - return os.path.abspath(os.path.join(os.path.dirname(filename), - '__pycache__')) - -def set_tmpdir(dirname): - """Set the temporary directory to use instead of __pycache__.""" - global _TMPDIR - _TMPDIR = dirname - -def cleanup_tmpdir(tmpdir=None, keep_so=False): - """Clean up the temporary directory by removing all files in it - called `_cffi_*.{c,so}` as well as the `build` subdirectory.""" - tmpdir = tmpdir or _caller_dir_pycache() - try: - filelist = os.listdir(tmpdir) - except OSError: - return - if keep_so: - suffix = '.c' # only remove .c files - else: - suffix = _get_so_suffixes()[0].lower() - for fn in filelist: - if fn.lower().startswith('_cffi_') and ( - fn.lower().endswith(suffix) or fn.lower().endswith('.c')): - try: - os.unlink(os.path.join(tmpdir, fn)) - except OSError: - pass - clean_dir = [os.path.join(tmpdir, 'build')] - for dir in clean_dir: - try: - for fn in os.listdir(dir): - fn = os.path.join(dir, fn) - if os.path.isdir(fn): - clean_dir.append(fn) - else: - os.unlink(fn) - except OSError: - pass - -def _get_so_suffixes(): - suffixes = _extension_suffixes() - if not suffixes: - # bah, no C_EXTENSION available. Occurs on pypy without cpyext - if sys.platform == 'win32': - suffixes = [".pyd"] - else: - suffixes = [".so"] - - return suffixes - -def _ensure_dir(filename): - dirname = os.path.dirname(filename) - if dirname and not os.path.isdir(dirname): - os.makedirs(dirname) diff --git a/venv/lib/python3.9/site-packages/charset_normalizer-3.4.7.dist-info/INSTALLER b/venv/lib/python3.9/site-packages/charset_normalizer-3.4.7.dist-info/INSTALLER deleted file mode 100644 index a1b589e..0000000 --- a/venv/lib/python3.9/site-packages/charset_normalizer-3.4.7.dist-info/INSTALLER +++ /dev/null @@ -1 +0,0 @@ -pip diff --git a/venv/lib/python3.9/site-packages/charset_normalizer-3.4.7.dist-info/METADATA b/venv/lib/python3.9/site-packages/charset_normalizer-3.4.7.dist-info/METADATA deleted file mode 100644 index 6b5a360..0000000 --- a/venv/lib/python3.9/site-packages/charset_normalizer-3.4.7.dist-info/METADATA +++ /dev/null @@ -1,808 +0,0 @@ -Metadata-Version: 2.4 -Name: charset-normalizer -Version: 3.4.7 -Summary: The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet. -Author-email: "Ahmed R. TAHRI" -Maintainer-email: "Ahmed R. TAHRI" -License: MIT -Project-URL: Changelog, https://github.com/jawah/charset_normalizer/blob/master/CHANGELOG.md -Project-URL: Documentation, https://charset-normalizer.readthedocs.io/ -Project-URL: Code, https://github.com/jawah/charset_normalizer -Project-URL: Issue tracker, https://github.com/jawah/charset_normalizer/issues -Keywords: encoding,charset,charset-detector,detector,normalization,unicode,chardet,detect -Classifier: Development Status :: 5 - Production/Stable -Classifier: Intended Audience :: Developers -Classifier: Operating System :: OS Independent -Classifier: Programming Language :: Python -Classifier: Programming Language :: Python :: 3 -Classifier: Programming Language :: Python :: 3.7 -Classifier: Programming Language :: Python :: 3.8 -Classifier: Programming Language :: Python :: 3.9 -Classifier: Programming Language :: Python :: 3.10 -Classifier: Programming Language :: Python :: 3.11 -Classifier: Programming Language :: Python :: 3.12 -Classifier: Programming Language :: Python :: 3.13 -Classifier: Programming Language :: Python :: 3.14 -Classifier: Programming Language :: Python :: 3 :: Only -Classifier: Programming Language :: Python :: Implementation :: CPython -Classifier: Programming Language :: Python :: Implementation :: PyPy -Classifier: Programming Language :: Python :: Free Threading :: 4 - Resilient -Classifier: Topic :: Text Processing :: Linguistic -Classifier: Topic :: Utilities -Classifier: Typing :: Typed -Requires-Python: >=3.7 -Description-Content-Type: text/markdown -License-File: LICENSE -Provides-Extra: unicode-backport -Dynamic: license-file - -

    Charset Detection, for Everyone 👋

    - -

    - The Real First Universal Charset Detector
    - - - - - Download Count Total - - - - -

    -

    - Featured Packages
    - - Static Badge - - - Static Badge - -

    -

    - In other language (unofficial port - by the community)
    - - Static Badge - -

    - -> A library that helps you read text from an unknown charset encoding.
    Motivated by `chardet`, -> I'm trying to resolve the issue by taking a new approach. -> All IANA character set names for which the Python core library provides codecs are supported. -> You can also register your own set of codecs, and yes, it would work as-is. - -

    - >>>>> 👉 Try Me Online Now, Then Adopt Me 👈 <<<<< -

    - -This project offers you an alternative to **Universal Charset Encoding Detector**, also known as **Chardet**. - -| Feature | [Chardet](https://github.com/chardet/chardet) | Charset Normalizer | [cChardet](https://github.com/PyYoshi/cChardet) | -|--------------------------------------------------|:---------------------------------------------:|:-----------------------------------------------------------------------------------------------:|:-----------------------------------------------:| -| `Fast` | ✅ | ✅ | ✅ | -| `Universal`[^1] | ❌ | ✅ | ❌ | -| `Reliable` **without** distinguishable standards | ✅ | ✅ | ✅ | -| `Reliable` **with** distinguishable standards | ✅ | ✅ | ✅ | -| `License` | _Disputed_[^2]
    _restrictive_ | MIT | MPL-1.1
    _restrictive_ | -| `Native Python` | ✅ | ✅ | ❌ | -| `Detect spoken language` | ✅ | ✅ | N/A | -| `UnicodeDecodeError Safety` | ✅ | ✅ | ❌ | -| `Whl Size (min)` | 500 kB | 150 kB | ~200 kB | -| `Supported Encoding` | 99 | [99](https://charset-normalizer.readthedocs.io/en/latest/user/support.html#supported-encodings) | 40 | -| `Can register custom encoding` | ❌ | ✅ | ❌ | - -

    -Reading Normalized TextCat Reading Text -

    - -[^1]: They are clearly using specific code for a specific encoding even if covering most of used one. -[^2]: Chardet 7.0+ was relicensed from LGPL-2.1 to MIT following an AI-assisted rewrite. This relicensing is disputed on two independent grounds: **(a)** the original author [contests](https://github.com/chardet/chardet/issues/327) that the maintainer had the right to relicense, arguing the rewrite is a derivative work of the LGPL-licensed codebase since it was not a clean room implementation; **(b)** the copyright claim itself is [questionable](https://github.com/chardet/chardet/issues/334) given the code was primarily generated by an LLM, and AI-generated output may not be copyrightable under most jurisdictions. Either issue alone could undermine the MIT license. Beyond licensing, the rewrite raises questions about responsible use of AI in open source: key architectural ideas pioneered by charset-normalizer - notably decode-first validity filtering (our foundational approach since v1) and encoding pairwise similarity with the same algorithm and threshold — surfaced in chardet 7 without acknowledgment. The project also imported test files from charset-normalizer to train and benchmark against it, then claimed superior accuracy on those very files. Charset-normalizer has always been MIT-licensed, encoding-agnostic by design, and built on a verifiable human-authored history. - -## ⚡ Performance - -This package offer better performances (99th, and 95th) against Chardet. Here are some numbers. - -| Package | Accuracy | Mean per file (ms) | File per sec (est) | -|---------------------------------------------------|:--------:|:------------------:|:------------------:| -| [chardet 7.1](https://github.com/chardet/chardet) | 89 % | 3 ms | 333 file/sec | -| charset-normalizer | **97 %** | 3 ms | 333 file/sec | - -| Package | 99th percentile | 95th percentile | 50th percentile | -|---------------------------------------------------|:---------------:|:---------------:|:---------------:| -| [chardet 7.1](https://github.com/chardet/chardet) | 32 ms | 17 ms | < 1 ms | -| charset-normalizer | 16 ms | 10 ms | 1 ms | - -_updated as of March 2026 using CPython 3.12, Charset-Normalizer 3.4.6, and Chardet 7.1.0_ - -~Chardet's performance on larger file (1MB+) are very poor. Expect huge difference on large payload.~ No longer the case since Chardet 7.0+ - -> Stats are generated using 400+ files using default parameters. More details on used files, see GHA workflows. -> And yes, these results might change at any time. The dataset can be updated to include more files. -> The actual delays heavily depends on your CPU capabilities. The factors should remain the same. -> Chardet claims on his documentation to have a greater accuracy than us based on the dataset they trained Chardet on(...) -> Well, it's normal, the opposite would have been worrying. Whereas charset-normalizer don't train on anything, our solution -> is based on a completely different algorithm, still heuristic through, it does not need weights across every encoding tables. - -## ✨ Installation - -Using pip: - -```sh -pip install charset-normalizer -U -``` - -## 🚀 Basic Usage - -### CLI -This package comes with a CLI. - -``` -usage: normalizer [-h] [-v] [-a] [-n] [-m] [-r] [-f] [-t THRESHOLD] - file [file ...] - -The Real First Universal Charset Detector. Discover originating encoding used -on text file. Normalize text to unicode. - -positional arguments: - files File(s) to be analysed - -optional arguments: - -h, --help show this help message and exit - -v, --verbose Display complementary information about file if any. - Stdout will contain logs about the detection process. - -a, --with-alternative - Output complementary possibilities if any. Top-level - JSON WILL be a list. - -n, --normalize Permit to normalize input file. If not set, program - does not write anything. - -m, --minimal Only output the charset detected to STDOUT. Disabling - JSON output. - -r, --replace Replace file when trying to normalize it instead of - creating a new one. - -f, --force Replace file without asking if you are sure, use this - flag with caution. - -t THRESHOLD, --threshold THRESHOLD - Define a custom maximum amount of chaos allowed in - decoded content. 0. <= chaos <= 1. - --version Show version information and exit. -``` - -```bash -normalizer ./data/sample.1.fr.srt -``` - -or - -```bash -python -m charset_normalizer ./data/sample.1.fr.srt -``` - -🎉 Since version 1.4.0 the CLI produce easily usable stdout result in JSON format. - -```json -{ - "path": "/home/default/projects/charset_normalizer/data/sample.1.fr.srt", - "encoding": "cp1252", - "encoding_aliases": [ - "1252", - "windows_1252" - ], - "alternative_encodings": [ - "cp1254", - "cp1256", - "cp1258", - "iso8859_14", - "iso8859_15", - "iso8859_16", - "iso8859_3", - "iso8859_9", - "latin_1", - "mbcs" - ], - "language": "French", - "alphabets": [ - "Basic Latin", - "Latin-1 Supplement" - ], - "has_sig_or_bom": false, - "chaos": 0.149, - "coherence": 97.152, - "unicode_path": null, - "is_preferred": true -} -``` - -### Python -*Just print out normalized text* -```python -from charset_normalizer import from_path - -results = from_path('./my_subtitle.srt') - -print(str(results.best())) -``` - -*Upgrade your code without effort* -```python -from charset_normalizer import detect -``` - -The above code will behave the same as **chardet**. We ensure that we offer the best (reasonable) BC result possible. - -See the docs for advanced usage : [readthedocs.io](https://charset-normalizer.readthedocs.io/en/latest/) - -## 😇 Why - -When I started using Chardet, I noticed that it was not suited to my expectations, and I wanted to propose a -reliable alternative using a completely different method. Also! I never back down on a good challenge! - -I **don't care** about the **originating charset** encoding, because **two different tables** can -produce **two identical rendered string.** -What I want is to get readable text, the best I can. - -In a way, **I'm brute forcing text decoding.** How cool is that ? 😎 - -Don't confuse package **ftfy** with charset-normalizer or chardet. ftfy goal is to repair Unicode string whereas charset-normalizer to convert raw file in unknown encoding to unicode. - -## 🍰 How - - - Discard all charset encoding table that could not fit the binary content. - - Measure noise, or the mess once opened (by chunks) with a corresponding charset encoding. - - Extract matches with the lowest mess detected. - - Additionally, we measure coherence / probe for a language. - -**Wait a minute**, what is noise/mess and coherence according to **YOU ?** - -*Noise :* I opened hundred of text files, **written by humans**, with the wrong encoding table. **I observed**, then -**I established** some ground rules about **what is obvious** when **it seems like** a mess (aka. defining noise in rendered text). - I know that my interpretation of what is noise is probably incomplete, feel free to contribute in order to - improve or rewrite it. - -*Coherence :* For each language there is on earth, we have computed ranked letter appearance occurrences (the best we can). So I thought -that intel is worth something here. So I use those records against decoded text to check if I can detect intelligent design. - -## ⚡ Known limitations - - - Language detection is unreliable when text contains two or more languages sharing identical letters. (eg. HTML (english tags) + Turkish content (Sharing Latin characters)) - - Every charset detector heavily depends on sufficient content. In common cases, do not bother run detection on very tiny content. - -## ⚠️ About Python EOLs - -**If you are running:** - -- Python >=2.7,<3.5: Unsupported -- Python 3.5: charset-normalizer < 2.1 -- Python 3.6: charset-normalizer < 3.1 - -Upgrade your Python interpreter as soon as possible. - -## 👤 Contributing - -Contributions, issues and feature requests are very much welcome.
    -Feel free to check [issues page](https://github.com/ousret/charset_normalizer/issues) if you want to contribute. - -## 📝 License - -Copyright © [Ahmed TAHRI @Ousret](https://github.com/Ousret).
    -This project is [MIT](https://github.com/Ousret/charset_normalizer/blob/master/LICENSE) licensed. - -Characters frequencies used in this project © 2012 [Denny Vrandečić](http://simia.net/letters/) - -## 💼 For Enterprise - -Professional support for charset-normalizer is available as part of the [Tidelift -Subscription][1]. Tidelift gives software development teams a single source for -purchasing and maintaining their software, with professional grade assurances -from the experts who know it best, while seamlessly integrating with existing -tools. - -[1]: https://tidelift.com/subscription/pkg/pypi-charset-normalizer?utm_source=pypi-charset-normalizer&utm_medium=readme - -[![OpenSSF Best Practices](https://www.bestpractices.dev/projects/7297/badge)](https://www.bestpractices.dev/projects/7297) - -# Changelog -All notable changes to charset-normalizer will be documented in this file. This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). -The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). - -## [3.4.7](https://github.com/Ousret/charset_normalizer/compare/3.4.6...3.4.7) (2026-04-02) - -### Changed -- Pre-built optimized version using mypy[c] v1.20. -- Relax `setuptools` constraint to `setuptools>=68,<82.1`. - -### Fixed -- Correctly remove SIG remnant in utf-7 decoded string. (#718) (#716) - -## [3.4.6](https://github.com/Ousret/charset_normalizer/compare/3.4.5...3.4.6) (2026-03-15) - -### Changed -- Flattened the logic in `charset_normalizer.md` for higher performance. Removed `eligible(..)` and `feed(...)` - in favor of `feed_info(...)`. -- Raised upper bound for mypy[c] to 1.20, for our optimized version. -- Updated `UNICODE_RANGES_COMBINED` using Unicode blocks v17. - -### Fixed -- Edge case where noise difference between two candidates can be almost insignificant. (#672) -- CLI `--normalize` writing to wrong path when passing multiple files in. (#702) - -### Misc -- Freethreaded pre-built wheels now shipped in PyPI starting with 3.14t. (#616) - -## [3.4.5](https://github.com/Ousret/charset_normalizer/compare/3.4.4...3.4.5) (2026-03-06) - -### Changed -- Update `setuptools` constraint to `setuptools>=68,<=82`. -- Raised upper bound of mypyc for the optional pre-built extension to v1.19.1 - -### Fixed -- Add explicit link to lib math in our optimized build. (#692) -- Logger level not restored correctly for empty byte sequences. (#701) -- TypeError when passing bytearray to from_bytes. (#703) - -### Misc -- Applied safe micro-optimizations in both our noise detector and language detector. -- Rewrote the `query_yes_no` function (inside CLI) to avoid using ambiguous licensed code. -- Added `cd.py` submodule into mypyc optional compilation to reduce further the performance impact. - -## [3.4.4](https://github.com/Ousret/charset_normalizer/compare/3.4.2...3.4.4) (2025-10-13) - -### Changed -- Bound `setuptools` to a specific constraint `setuptools>=68,<=81`. -- Raised upper bound of mypyc for the optional pre-built extension to v1.18.2 - -### Removed -- `setuptools-scm` as a build dependency. - -### Misc -- Enforced hashes in `dev-requirements.txt` and created `ci-requirements.txt` for security purposes. -- Additional pre-built wheels for riscv64, s390x, and armv7l architectures. -- Restore ` multiple.intoto.jsonl` in GitHub releases in addition to individual attestation file per wheel. - -## [3.4.3](https://github.com/Ousret/charset_normalizer/compare/3.4.2...3.4.3) (2025-08-09) - -### Changed -- mypy(c) is no longer a required dependency at build time if `CHARSET_NORMALIZER_USE_MYPYC` isn't set to `1`. (#595) (#583) -- automatically lower confidence on small bytes samples that are not Unicode in `detect` output legacy function. (#391) - -### Added -- Custom build backend to overcome inability to mark mypy as an optional dependency in the build phase. -- Support for Python 3.14 - -### Fixed -- sdist archive contained useless directories. -- automatically fallback on valid UTF-16 or UTF-32 even if the md says it's noisy. (#633) - -### Misc -- SBOM are automatically published to the relevant GitHub release to comply with regulatory changes. - Each published wheel comes with its SBOM. We choose CycloneDX as the format. -- Prebuilt optimized wheel are no longer distributed by default for CPython 3.7 due to a change in cibuildwheel. - -## [3.4.2](https://github.com/Ousret/charset_normalizer/compare/3.4.1...3.4.2) (2025-05-02) - -### Fixed -- Addressed the DeprecationWarning in our CLI regarding `argparse.FileType` by backporting the target class into the package. (#591) -- Improved the overall reliability of the detector with CJK Ideographs. (#605) (#587) - -### Changed -- Optional mypyc compilation upgraded to version 1.15 for Python >= 3.8 - -## [3.4.1](https://github.com/Ousret/charset_normalizer/compare/3.4.0...3.4.1) (2024-12-24) - -### Changed -- Project metadata are now stored using `pyproject.toml` instead of `setup.cfg` using setuptools as the build backend. -- Enforce annotation delayed loading for a simpler and consistent types in the project. -- Optional mypyc compilation upgraded to version 1.14 for Python >= 3.8 - -### Added -- pre-commit configuration. -- noxfile. - -### Removed -- `build-requirements.txt` as per using `pyproject.toml` native build configuration. -- `bin/integration.py` and `bin/serve.py` in favor of downstream integration test (see noxfile). -- `setup.cfg` in favor of `pyproject.toml` metadata configuration. -- Unused `utils.range_scan` function. - -### Fixed -- Converting content to Unicode bytes may insert `utf_8` instead of preferred `utf-8`. (#572) -- Deprecation warning "'count' is passed as positional argument" when converting to Unicode bytes on Python 3.13+ - -## [3.4.0](https://github.com/Ousret/charset_normalizer/compare/3.3.2...3.4.0) (2024-10-08) - -### Added -- Argument `--no-preemptive` in the CLI to prevent the detector to search for hints. -- Support for Python 3.13 (#512) - -### Fixed -- Relax the TypeError exception thrown when trying to compare a CharsetMatch with anything else than a CharsetMatch. -- Improved the general reliability of the detector based on user feedbacks. (#520) (#509) (#498) (#407) (#537) -- Declared charset in content (preemptive detection) not changed when converting to utf-8 bytes. (#381) - -## [3.3.2](https://github.com/Ousret/charset_normalizer/compare/3.3.1...3.3.2) (2023-10-31) - -### Fixed -- Unintentional memory usage regression when using large payload that match several encoding (#376) -- Regression on some detection case showcased in the documentation (#371) - -### Added -- Noise (md) probe that identify malformed arabic representation due to the presence of letters in isolated form (credit to my wife) - -## [3.3.1](https://github.com/Ousret/charset_normalizer/compare/3.3.0...3.3.1) (2023-10-22) - -### Changed -- Optional mypyc compilation upgraded to version 1.6.1 for Python >= 3.8 -- Improved the general detection reliability based on reports from the community - -## [3.3.0](https://github.com/Ousret/charset_normalizer/compare/3.2.0...3.3.0) (2023-09-30) - -### Added -- Allow to execute the CLI (e.g. normalizer) through `python -m charset_normalizer.cli` or `python -m charset_normalizer` -- Support for 9 forgotten encoding that are supported by Python but unlisted in `encoding.aliases` as they have no alias (#323) - -### Removed -- (internal) Redundant utils.is_ascii function and unused function is_private_use_only -- (internal) charset_normalizer.assets is moved inside charset_normalizer.constant - -### Changed -- (internal) Unicode code blocks in constants are updated using the latest v15.0.0 definition to improve detection -- Optional mypyc compilation upgraded to version 1.5.1 for Python >= 3.8 - -### Fixed -- Unable to properly sort CharsetMatch when both chaos/noise and coherence were close due to an unreachable condition in \_\_lt\_\_ (#350) - -## [3.2.0](https://github.com/Ousret/charset_normalizer/compare/3.1.0...3.2.0) (2023-06-07) - -### Changed -- Typehint for function `from_path` no longer enforce `PathLike` as its first argument -- Minor improvement over the global detection reliability - -### Added -- Introduce function `is_binary` that relies on main capabilities, and optimized to detect binaries -- Propagate `enable_fallback` argument throughout `from_bytes`, `from_path`, and `from_fp` that allow a deeper control over the detection (default True) -- Explicit support for Python 3.12 - -### Fixed -- Edge case detection failure where a file would contain 'very-long' camel cased word (Issue #289) - -## [3.1.0](https://github.com/Ousret/charset_normalizer/compare/3.0.1...3.1.0) (2023-03-06) - -### Added -- Argument `should_rename_legacy` for legacy function `detect` and disregard any new arguments without errors (PR #262) - -### Removed -- Support for Python 3.6 (PR #260) - -### Changed -- Optional speedup provided by mypy/c 1.0.1 - -## [3.0.1](https://github.com/Ousret/charset_normalizer/compare/3.0.0...3.0.1) (2022-11-18) - -### Fixed -- Multi-bytes cutter/chunk generator did not always cut correctly (PR #233) - -### Changed -- Speedup provided by mypy/c 0.990 on Python >= 3.7 - -## [3.0.0](https://github.com/Ousret/charset_normalizer/compare/2.1.1...3.0.0) (2022-10-20) - -### Added -- Extend the capability of explain=True when cp_isolation contains at most two entries (min one), will log in details of the Mess-detector results -- Support for alternative language frequency set in charset_normalizer.assets.FREQUENCIES -- Add parameter `language_threshold` in `from_bytes`, `from_path` and `from_fp` to adjust the minimum expected coherence ratio -- `normalizer --version` now specify if current version provide extra speedup (meaning mypyc compilation whl) - -### Changed -- Build with static metadata using 'build' frontend -- Make the language detection stricter -- Optional: Module `md.py` can be compiled using Mypyc to provide an extra speedup up to 4x faster than v2.1 - -### Fixed -- CLI with opt --normalize fail when using full path for files -- TooManyAccentuatedPlugin induce false positive on the mess detection when too few alpha character have been fed to it -- Sphinx warnings when generating the documentation - -### Removed -- Coherence detector no longer return 'Simple English' instead return 'English' -- Coherence detector no longer return 'Classical Chinese' instead return 'Chinese' -- Breaking: Method `first()` and `best()` from CharsetMatch -- UTF-7 will no longer appear as "detected" without a recognized SIG/mark (is unreliable/conflict with ASCII) -- Breaking: Class aliases CharsetDetector, CharsetDoctor, CharsetNormalizerMatch and CharsetNormalizerMatches -- Breaking: Top-level function `normalize` -- Breaking: Properties `chaos_secondary_pass`, `coherence_non_latin` and `w_counter` from CharsetMatch -- Support for the backport `unicodedata2` - -## [3.0.0rc1](https://github.com/Ousret/charset_normalizer/compare/3.0.0b2...3.0.0rc1) (2022-10-18) - -### Added -- Extend the capability of explain=True when cp_isolation contains at most two entries (min one), will log in details of the Mess-detector results -- Support for alternative language frequency set in charset_normalizer.assets.FREQUENCIES -- Add parameter `language_threshold` in `from_bytes`, `from_path` and `from_fp` to adjust the minimum expected coherence ratio - -### Changed -- Build with static metadata using 'build' frontend -- Make the language detection stricter - -### Fixed -- CLI with opt --normalize fail when using full path for files -- TooManyAccentuatedPlugin induce false positive on the mess detection when too few alpha character have been fed to it - -### Removed -- Coherence detector no longer return 'Simple English' instead return 'English' -- Coherence detector no longer return 'Classical Chinese' instead return 'Chinese' - -## [3.0.0b2](https://github.com/Ousret/charset_normalizer/compare/3.0.0b1...3.0.0b2) (2022-08-21) - -### Added -- `normalizer --version` now specify if current version provide extra speedup (meaning mypyc compilation whl) - -### Removed -- Breaking: Method `first()` and `best()` from CharsetMatch -- UTF-7 will no longer appear as "detected" without a recognized SIG/mark (is unreliable/conflict with ASCII) - -### Fixed -- Sphinx warnings when generating the documentation - -## [3.0.0b1](https://github.com/Ousret/charset_normalizer/compare/2.1.0...3.0.0b1) (2022-08-15) - -### Changed -- Optional: Module `md.py` can be compiled using Mypyc to provide an extra speedup up to 4x faster than v2.1 - -### Removed -- Breaking: Class aliases CharsetDetector, CharsetDoctor, CharsetNormalizerMatch and CharsetNormalizerMatches -- Breaking: Top-level function `normalize` -- Breaking: Properties `chaos_secondary_pass`, `coherence_non_latin` and `w_counter` from CharsetMatch -- Support for the backport `unicodedata2` - -## [2.1.1](https://github.com/Ousret/charset_normalizer/compare/2.1.0...2.1.1) (2022-08-19) - -### Deprecated -- Function `normalize` scheduled for removal in 3.0 - -### Changed -- Removed useless call to decode in fn is_unprintable (#206) - -### Fixed -- Third-party library (i18n xgettext) crashing not recognizing utf_8 (PEP 263) with underscore from [@aleksandernovikov](https://github.com/aleksandernovikov) (#204) - -## [2.1.0](https://github.com/Ousret/charset_normalizer/compare/2.0.12...2.1.0) (2022-06-19) - -### Added -- Output the Unicode table version when running the CLI with `--version` (PR #194) - -### Changed -- Re-use decoded buffer for single byte character sets from [@nijel](https://github.com/nijel) (PR #175) -- Fixing some performance bottlenecks from [@deedy5](https://github.com/deedy5) (PR #183) - -### Fixed -- Workaround potential bug in cpython with Zero Width No-Break Space located in Arabic Presentation Forms-B, Unicode 1.1 not acknowledged as space (PR #175) -- CLI default threshold aligned with the API threshold from [@oleksandr-kuzmenko](https://github.com/oleksandr-kuzmenko) (PR #181) - -### Removed -- Support for Python 3.5 (PR #192) - -### Deprecated -- Use of backport unicodedata from `unicodedata2` as Python is quickly catching up, scheduled for removal in 3.0 (PR #194) - -## [2.0.12](https://github.com/Ousret/charset_normalizer/compare/2.0.11...2.0.12) (2022-02-12) - -### Fixed -- ASCII miss-detection on rare cases (PR #170) - -## [2.0.11](https://github.com/Ousret/charset_normalizer/compare/2.0.10...2.0.11) (2022-01-30) - -### Added -- Explicit support for Python 3.11 (PR #164) - -### Changed -- The logging behavior have been completely reviewed, now using only TRACE and DEBUG levels (PR #163 #165) - -## [2.0.10](https://github.com/Ousret/charset_normalizer/compare/2.0.9...2.0.10) (2022-01-04) - -### Fixed -- Fallback match entries might lead to UnicodeDecodeError for large bytes sequence (PR #154) - -### Changed -- Skipping the language-detection (CD) on ASCII (PR #155) - -## [2.0.9](https://github.com/Ousret/charset_normalizer/compare/2.0.8...2.0.9) (2021-12-03) - -### Changed -- Moderating the logging impact (since 2.0.8) for specific environments (PR #147) - -### Fixed -- Wrong logging level applied when setting kwarg `explain` to True (PR #146) - -## [2.0.8](https://github.com/Ousret/charset_normalizer/compare/2.0.7...2.0.8) (2021-11-24) -### Changed -- Improvement over Vietnamese detection (PR #126) -- MD improvement on trailing data and long foreign (non-pure latin) data (PR #124) -- Efficiency improvements in cd/alphabet_languages from [@adbar](https://github.com/adbar) (PR #122) -- call sum() without an intermediary list following PEP 289 recommendations from [@adbar](https://github.com/adbar) (PR #129) -- Code style as refactored by Sourcery-AI (PR #131) -- Minor adjustment on the MD around european words (PR #133) -- Remove and replace SRTs from assets / tests (PR #139) -- Initialize the library logger with a `NullHandler` by default from [@nmaynes](https://github.com/nmaynes) (PR #135) -- Setting kwarg `explain` to True will add provisionally (bounded to function lifespan) a specific stream handler (PR #135) - -### Fixed -- Fix large (misleading) sequence giving UnicodeDecodeError (PR #137) -- Avoid using too insignificant chunk (PR #137) - -### Added -- Add and expose function `set_logging_handler` to configure a specific StreamHandler from [@nmaynes](https://github.com/nmaynes) (PR #135) -- Add `CHANGELOG.md` entries, format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) (PR #141) - -## [2.0.7](https://github.com/Ousret/charset_normalizer/compare/2.0.6...2.0.7) (2021-10-11) -### Added -- Add support for Kazakh (Cyrillic) language detection (PR #109) - -### Changed -- Further, improve inferring the language from a given single-byte code page (PR #112) -- Vainly trying to leverage PEP263 when PEP3120 is not supported (PR #116) -- Refactoring for potential performance improvements in loops from [@adbar](https://github.com/adbar) (PR #113) -- Various detection improvement (MD+CD) (PR #117) - -### Removed -- Remove redundant logging entry about detected language(s) (PR #115) - -### Fixed -- Fix a minor inconsistency between Python 3.5 and other versions regarding language detection (PR #117 #102) - -## [2.0.6](https://github.com/Ousret/charset_normalizer/compare/2.0.5...2.0.6) (2021-09-18) -### Fixed -- Unforeseen regression with the loss of the backward-compatibility with some older minor of Python 3.5.x (PR #100) -- Fix CLI crash when using --minimal output in certain cases (PR #103) - -### Changed -- Minor improvement to the detection efficiency (less than 1%) (PR #106 #101) - -## [2.0.5](https://github.com/Ousret/charset_normalizer/compare/2.0.4...2.0.5) (2021-09-14) -### Changed -- The project now comply with: flake8, mypy, isort and black to ensure a better overall quality (PR #81) -- The BC-support with v1.x was improved, the old staticmethods are restored (PR #82) -- The Unicode detection is slightly improved (PR #93) -- Add syntax sugar \_\_bool\_\_ for results CharsetMatches list-container (PR #91) - -### Removed -- The project no longer raise warning on tiny content given for detection, will be simply logged as warning instead (PR #92) - -### Fixed -- In some rare case, the chunks extractor could cut in the middle of a multi-byte character and could mislead the mess detection (PR #95) -- Some rare 'space' characters could trip up the UnprintablePlugin/Mess detection (PR #96) -- The MANIFEST.in was not exhaustive (PR #78) - -## [2.0.4](https://github.com/Ousret/charset_normalizer/compare/2.0.3...2.0.4) (2021-07-30) -### Fixed -- The CLI no longer raise an unexpected exception when no encoding has been found (PR #70) -- Fix accessing the 'alphabets' property when the payload contains surrogate characters (PR #68) -- The logger could mislead (explain=True) on detected languages and the impact of one MBCS match (PR #72) -- Submatch factoring could be wrong in rare edge cases (PR #72) -- Multiple files given to the CLI were ignored when publishing results to STDOUT. (After the first path) (PR #72) -- Fix line endings from CRLF to LF for certain project files (PR #67) - -### Changed -- Adjust the MD to lower the sensitivity, thus improving the global detection reliability (PR #69 #76) -- Allow fallback on specified encoding if any (PR #71) - -## [2.0.3](https://github.com/Ousret/charset_normalizer/compare/2.0.2...2.0.3) (2021-07-16) -### Changed -- Part of the detection mechanism has been improved to be less sensitive, resulting in more accurate detection results. Especially ASCII. (PR #63) -- According to the community wishes, the detection will fall back on ASCII or UTF-8 in a last-resort case. (PR #64) - -## [2.0.2](https://github.com/Ousret/charset_normalizer/compare/2.0.1...2.0.2) (2021-07-15) -### Fixed -- Empty/Too small JSON payload miss-detection fixed. Report from [@tseaver](https://github.com/tseaver) (PR #59) - -### Changed -- Don't inject unicodedata2 into sys.modules from [@akx](https://github.com/akx) (PR #57) - -## [2.0.1](https://github.com/Ousret/charset_normalizer/compare/2.0.0...2.0.1) (2021-07-13) -### Fixed -- Make it work where there isn't a filesystem available, dropping assets frequencies.json. Report from [@sethmlarson](https://github.com/sethmlarson). (PR #55) -- Using explain=False permanently disable the verbose output in the current runtime (PR #47) -- One log entry (language target preemptive) was not show in logs when using explain=True (PR #47) -- Fix undesired exception (ValueError) on getitem of instance CharsetMatches (PR #52) - -### Changed -- Public function normalize default args values were not aligned with from_bytes (PR #53) - -### Added -- You may now use charset aliases in cp_isolation and cp_exclusion arguments (PR #47) - -## [2.0.0](https://github.com/Ousret/charset_normalizer/compare/1.4.1...2.0.0) (2021-07-02) -### Changed -- 4x to 5 times faster than the previous 1.4.0 release. At least 2x faster than Chardet. -- Accent has been made on UTF-8 detection, should perform rather instantaneous. -- The backward compatibility with Chardet has been greatly improved. The legacy detect function returns an identical charset name whenever possible. -- The detection mechanism has been slightly improved, now Turkish content is detected correctly (most of the time) -- The program has been rewritten to ease the readability and maintainability. (+Using static typing)+ -- utf_7 detection has been reinstated. - -### Removed -- This package no longer require anything when used with Python 3.5 (Dropped cached_property) -- Removed support for these languages: Catalan, Esperanto, Kazakh, Baque, Volapük, Azeri, Galician, Nynorsk, Macedonian, and Serbocroatian. -- The exception hook on UnicodeDecodeError has been removed. - -### Deprecated -- Methods coherence_non_latin, w_counter, chaos_secondary_pass of the class CharsetMatch are now deprecated and scheduled for removal in v3.0 - -### Fixed -- The CLI output used the relative path of the file(s). Should be absolute. - -## [1.4.1](https://github.com/Ousret/charset_normalizer/compare/1.4.0...1.4.1) (2021-05-28) -### Fixed -- Logger configuration/usage no longer conflict with others (PR #44) - -## [1.4.0](https://github.com/Ousret/charset_normalizer/compare/1.3.9...1.4.0) (2021-05-21) -### Removed -- Using standard logging instead of using the package loguru. -- Dropping nose test framework in favor of the maintained pytest. -- Choose to not use dragonmapper package to help with gibberish Chinese/CJK text. -- Require cached_property only for Python 3.5 due to constraint. Dropping for every other interpreter version. -- Stop support for UTF-7 that does not contain a SIG. -- Dropping PrettyTable, replaced with pure JSON output in CLI. - -### Fixed -- BOM marker in a CharsetNormalizerMatch instance could be False in rare cases even if obviously present. Due to the sub-match factoring process. -- Not searching properly for the BOM when trying utf32/16 parent codec. - -### Changed -- Improving the package final size by compressing frequencies.json. -- Huge improvement over the larges payload. - -### Added -- CLI now produces JSON consumable output. -- Return ASCII if given sequences fit. Given reasonable confidence. - -## [1.3.9](https://github.com/Ousret/charset_normalizer/compare/1.3.8...1.3.9) (2021-05-13) - -### Fixed -- In some very rare cases, you may end up getting encode/decode errors due to a bad bytes payload (PR #40) - -## [1.3.8](https://github.com/Ousret/charset_normalizer/compare/1.3.7...1.3.8) (2021-05-12) - -### Fixed -- Empty given payload for detection may cause an exception if trying to access the `alphabets` property. (PR #39) - -## [1.3.7](https://github.com/Ousret/charset_normalizer/compare/1.3.6...1.3.7) (2021-05-12) - -### Fixed -- The legacy detect function should return UTF-8-SIG if sig is present in the payload. (PR #38) - -## [1.3.6](https://github.com/Ousret/charset_normalizer/compare/1.3.5...1.3.6) (2021-02-09) - -### Changed -- Amend the previous release to allow prettytable 2.0 (PR #35) - -## [1.3.5](https://github.com/Ousret/charset_normalizer/compare/1.3.4...1.3.5) (2021-02-08) - -### Fixed -- Fix error while using the package with a python pre-release interpreter (PR #33) - -### Changed -- Dependencies refactoring, constraints revised. - -### Added -- Add python 3.9 and 3.10 to the supported interpreters - -MIT License - -Copyright (c) 2025 TAHRI Ahmed R. - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/venv/lib/python3.9/site-packages/charset_normalizer-3.4.7.dist-info/RECORD b/venv/lib/python3.9/site-packages/charset_normalizer-3.4.7.dist-info/RECORD deleted file mode 100644 index 98e4e02..0000000 --- a/venv/lib/python3.9/site-packages/charset_normalizer-3.4.7.dist-info/RECORD +++ /dev/null @@ -1,36 +0,0 @@ -../../../bin/normalizer,sha256=yAm3CjdxDfNfljUzrm_8za_BbnOFgJfLtYXQ3n133iE,207 -81d243bd2c585b0f4821__mypyc.cpython-39-x86_64-linux-gnu.so,sha256=Ujxa5iPb6AesmIlxxCdsF1WEp8tSMlzb-rW_532i3cU,410832 -charset_normalizer-3.4.7.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 -charset_normalizer-3.4.7.dist-info/METADATA,sha256=K8lK8L8LaZ1YmKvWLt3zEkpIxiCOC58xNhzFQrfQJxQ,40931 -charset_normalizer-3.4.7.dist-info/RECORD,, -charset_normalizer-3.4.7.dist-info/WHEEL,sha256=OZLCzpIUHEX42a9RmtxH4_auVuxdXhghS0dmIdhxCRQ,184 -charset_normalizer-3.4.7.dist-info/entry_points.txt,sha256=ADSTKrkXZ3hhdOVFi6DcUEHQRS0xfxDIE_pEz4wLIXA,65 -charset_normalizer-3.4.7.dist-info/licenses/LICENSE,sha256=bQ1Bv-FwrGx9wkjJpj4lTQ-0WmDVCoJX0K-SxuJJuIc,1071 -charset_normalizer-3.4.7.dist-info/top_level.txt,sha256=c_vZbitqecT2GfK3zdxSTLCn8C-6pGnHQY5o_5Y32M0,47 -charset_normalizer/__init__.py,sha256=OKRxRv2Zhnqk00tqkN0c1BtJjm165fWXLydE52IKuHc,1590 -charset_normalizer/__main__.py,sha256=yzYxMR-IhKRHYwcSlavEv8oGdwxsR89mr2X09qXGdps,109 -charset_normalizer/__pycache__/__init__.cpython-39.pyc,, -charset_normalizer/__pycache__/__main__.cpython-39.pyc,, -charset_normalizer/__pycache__/api.cpython-39.pyc,, -charset_normalizer/__pycache__/cd.cpython-39.pyc,, -charset_normalizer/__pycache__/constant.cpython-39.pyc,, -charset_normalizer/__pycache__/legacy.cpython-39.pyc,, -charset_normalizer/__pycache__/md.cpython-39.pyc,, -charset_normalizer/__pycache__/models.cpython-39.pyc,, -charset_normalizer/__pycache__/utils.cpython-39.pyc,, -charset_normalizer/__pycache__/version.cpython-39.pyc,, -charset_normalizer/api.py,sha256=387F3n23MlMu-xfSbFULW2DLGsBmVrZVGhnkiGXeKBo,38844 -charset_normalizer/cd.cpython-39-x86_64-linux-gnu.so,sha256=q9uObNt5v2-3JR3GmbMsHY7cJIiCz9Eez4Hmvs0IR3M,15912 -charset_normalizer/cd.py,sha256=v0iPJweGsRegXywrM1LzUgqW9bJ1KFvIblQHP1jm5FQ,15174 -charset_normalizer/cli/__init__.py,sha256=D8I86lFk2-py45JvqxniTirSj_sFyE6sjaY_0-G1shc,136 -charset_normalizer/cli/__main__.py,sha256=E9FFSV1E2iOE_B2B1tJHQT9ExJqc60Ks_c-08sNawh8,11940 -charset_normalizer/cli/__pycache__/__init__.cpython-39.pyc,, -charset_normalizer/cli/__pycache__/__main__.cpython-39.pyc,, -charset_normalizer/constant.py,sha256=yvLAWDrdSC743Cu4amhwHLIO-FGuRTOTZouCzZKGikc,44431 -charset_normalizer/legacy.py,sha256=yBIFMNABNPE5JkdKOWyVo36fZtV9nm8bf37LrDWulz8,2661 -charset_normalizer/md.cpython-39-x86_64-linux-gnu.so,sha256=MvlOADQzK-FTt2QLGo1y7joPU_7evdj0LunrWj6uzXs,15912 -charset_normalizer/md.py,sha256=AYCdfDX79FrgoId3zXqmbCuDcbGr1NRuGqgJN94Rx9Q,30441 -charset_normalizer/models.py,sha256=FbaQnI6ECmVmyHRSvVM5fHNeMAQ3KSGdwLjGcQqWDws,12821 -charset_normalizer/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 -charset_normalizer/utils.py,sha256=9cpi-_0-vC9pGDfuoarhC6VlF_Jxwx5Jsa_8I4w2D8k,12282 -charset_normalizer/version.py,sha256=2LxFuGp3BBuIwt95cp64y7v8bCNHcMAi08IfXt_47Co,115 diff --git a/venv/lib/python3.9/site-packages/charset_normalizer-3.4.7.dist-info/WHEEL b/venv/lib/python3.9/site-packages/charset_normalizer-3.4.7.dist-info/WHEEL deleted file mode 100644 index fbcc8e7..0000000 --- a/venv/lib/python3.9/site-packages/charset_normalizer-3.4.7.dist-info/WHEEL +++ /dev/null @@ -1,7 +0,0 @@ -Wheel-Version: 1.0 -Generator: setuptools (82.0.1) -Root-Is-Purelib: false -Tag: cp39-cp39-manylinux_2_17_x86_64 -Tag: cp39-cp39-manylinux2014_x86_64 -Tag: cp39-cp39-manylinux_2_28_x86_64 - diff --git a/venv/lib/python3.9/site-packages/charset_normalizer-3.4.7.dist-info/entry_points.txt b/venv/lib/python3.9/site-packages/charset_normalizer-3.4.7.dist-info/entry_points.txt deleted file mode 100644 index 65619e7..0000000 --- a/venv/lib/python3.9/site-packages/charset_normalizer-3.4.7.dist-info/entry_points.txt +++ /dev/null @@ -1,2 +0,0 @@ -[console_scripts] -normalizer = charset_normalizer.cli:cli_detect diff --git a/venv/lib/python3.9/site-packages/charset_normalizer-3.4.7.dist-info/licenses/LICENSE b/venv/lib/python3.9/site-packages/charset_normalizer-3.4.7.dist-info/licenses/LICENSE deleted file mode 100644 index 9725772..0000000 --- a/venv/lib/python3.9/site-packages/charset_normalizer-3.4.7.dist-info/licenses/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -MIT License - -Copyright (c) 2025 TAHRI Ahmed R. - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/venv/lib/python3.9/site-packages/charset_normalizer-3.4.7.dist-info/top_level.txt b/venv/lib/python3.9/site-packages/charset_normalizer-3.4.7.dist-info/top_level.txt deleted file mode 100644 index 89847be..0000000 --- a/venv/lib/python3.9/site-packages/charset_normalizer-3.4.7.dist-info/top_level.txt +++ /dev/null @@ -1,2 +0,0 @@ -81d243bd2c585b0f4821__mypyc -charset_normalizer diff --git a/venv/lib/python3.9/site-packages/charset_normalizer/__init__.py b/venv/lib/python3.9/site-packages/charset_normalizer/__init__.py deleted file mode 100644 index 0d3a379..0000000 --- a/venv/lib/python3.9/site-packages/charset_normalizer/__init__.py +++ /dev/null @@ -1,48 +0,0 @@ -""" -Charset-Normalizer -~~~~~~~~~~~~~~ -The Real First Universal Charset Detector. -A library that helps you read text from an unknown charset encoding. -Motivated by chardet, This package is trying to resolve the issue by taking a new approach. -All IANA character set names for which the Python core library provides codecs are supported. - -Basic usage: - >>> from charset_normalizer import from_bytes - >>> results = from_bytes('Bсеки човек има право на образование. Oбразованието!'.encode('utf_8')) - >>> best_guess = results.best() - >>> str(best_guess) - 'Bсеки човек има право на образование. Oбразованието!' - -Others methods and usages are available - see the full documentation -at . -:copyright: (c) 2021 by Ahmed TAHRI -:license: MIT, see LICENSE for more details. -""" - -from __future__ import annotations - -import logging - -from .api import from_bytes, from_fp, from_path, is_binary -from .legacy import detect -from .models import CharsetMatch, CharsetMatches -from .utils import set_logging_handler -from .version import VERSION, __version__ - -__all__ = ( - "from_fp", - "from_path", - "from_bytes", - "is_binary", - "detect", - "CharsetMatch", - "CharsetMatches", - "__version__", - "VERSION", - "set_logging_handler", -) - -# Attach a NullHandler to the top level logger by default -# https://docs.python.org/3.3/howto/logging.html#configuring-logging-for-a-library - -logging.getLogger("charset_normalizer").addHandler(logging.NullHandler()) diff --git a/venv/lib/python3.9/site-packages/charset_normalizer/__main__.py b/venv/lib/python3.9/site-packages/charset_normalizer/__main__.py deleted file mode 100644 index e0e76f7..0000000 --- a/venv/lib/python3.9/site-packages/charset_normalizer/__main__.py +++ /dev/null @@ -1,6 +0,0 @@ -from __future__ import annotations - -from .cli import cli_detect - -if __name__ == "__main__": - cli_detect() diff --git a/venv/lib/python3.9/site-packages/charset_normalizer/api.py b/venv/lib/python3.9/site-packages/charset_normalizer/api.py deleted file mode 100644 index 50cb955..0000000 --- a/venv/lib/python3.9/site-packages/charset_normalizer/api.py +++ /dev/null @@ -1,988 +0,0 @@ -from __future__ import annotations - -import logging -from os import PathLike -from typing import BinaryIO - -from .cd import ( - coherence_ratio, - encoding_languages, - mb_encoding_languages, - merge_coherence_ratios, -) -from .constant import ( - IANA_SUPPORTED, - IANA_SUPPORTED_SIMILAR, - TOO_BIG_SEQUENCE, - TOO_SMALL_SEQUENCE, - TRACE, -) -from .md import mess_ratio -from .models import CharsetMatch, CharsetMatches -from .utils import ( - any_specified_encoding, - cut_sequence_chunks, - iana_name, - identify_sig_or_bom, - is_multi_byte_encoding, - should_strip_sig_or_bom, -) - -logger = logging.getLogger("charset_normalizer") -explain_handler = logging.StreamHandler() -explain_handler.setFormatter( - logging.Formatter("%(asctime)s | %(levelname)s | %(message)s") -) - -# Pre-compute a reordered encoding list: multibyte first, then single-byte. -# This allows the mb_definitive_match optimization to fire earlier, skipping -# all single-byte encodings for genuine CJK content. Multibyte codecs -# hard-fail (UnicodeDecodeError) on single-byte data almost instantly, so -# testing them first costs negligible time for non-CJK files. -_mb_supported: list[str] = [] -_sb_supported: list[str] = [] - -for _supported_enc in IANA_SUPPORTED: - try: - if is_multi_byte_encoding(_supported_enc): - _mb_supported.append(_supported_enc) - else: - _sb_supported.append(_supported_enc) - except ImportError: - _sb_supported.append(_supported_enc) - -IANA_SUPPORTED_MB_FIRST: list[str] = _mb_supported + _sb_supported - - -def from_bytes( - sequences: bytes | bytearray, - steps: int = 5, - chunk_size: int = 512, - threshold: float = 0.2, - cp_isolation: list[str] | None = None, - cp_exclusion: list[str] | None = None, - preemptive_behaviour: bool = True, - explain: bool = False, - language_threshold: float = 0.1, - enable_fallback: bool = True, -) -> CharsetMatches: - """ - Given a raw bytes sequence, return the best possibles charset usable to render str objects. - If there is no results, it is a strong indicator that the source is binary/not text. - By default, the process will extract 5 blocks of 512o each to assess the mess and coherence of a given sequence. - And will give up a particular code page after 20% of measured mess. Those criteria are customizable at will. - - The preemptive behavior DOES NOT replace the traditional detection workflow, it prioritize a particular code page - but never take it for granted. Can improve the performance. - - You may want to focus your attention to some code page or/and not others, use cp_isolation and cp_exclusion for that - purpose. - - This function will strip the SIG in the payload/sequence every time except on UTF-16, UTF-32. - By default the library does not setup any handler other than the NullHandler, if you choose to set the 'explain' - toggle to True it will alter the logger configuration to add a StreamHandler that is suitable for debugging. - Custom logging format and handler can be set manually. - """ - - if not isinstance(sequences, (bytearray, bytes)): - raise TypeError( - "Expected object of type bytes or bytearray, got: {}".format( - type(sequences) - ) - ) - - if explain: - previous_logger_level: int = logger.level - logger.addHandler(explain_handler) - logger.setLevel(TRACE) - - length: int = len(sequences) - - if length == 0: - logger.debug("Encoding detection on empty bytes, assuming utf_8 intention.") - if explain: # Defensive: ensure exit path clean handler - logger.removeHandler(explain_handler) - logger.setLevel(previous_logger_level) - return CharsetMatches([CharsetMatch(sequences, "utf_8", 0.0, False, [], "")]) - - if cp_isolation is not None: - logger.log( - TRACE, - "cp_isolation is set. use this flag for debugging purpose. " - "limited list of encoding allowed : %s.", - ", ".join(cp_isolation), - ) - cp_isolation = [iana_name(cp, False) for cp in cp_isolation] - else: - cp_isolation = [] - - if cp_exclusion is not None: - logger.log( - TRACE, - "cp_exclusion is set. use this flag for debugging purpose. " - "limited list of encoding excluded : %s.", - ", ".join(cp_exclusion), - ) - cp_exclusion = [iana_name(cp, False) for cp in cp_exclusion] - else: - cp_exclusion = [] - - if length <= (chunk_size * steps): - logger.log( - TRACE, - "override steps (%i) and chunk_size (%i) as content does not fit (%i byte(s) given) parameters.", - steps, - chunk_size, - length, - ) - steps = 1 - chunk_size = length - - if steps > 1 and length / steps < chunk_size: - chunk_size = int(length / steps) - - is_too_small_sequence: bool = len(sequences) < TOO_SMALL_SEQUENCE - is_too_large_sequence: bool = len(sequences) >= TOO_BIG_SEQUENCE - - if is_too_small_sequence: - logger.log( - TRACE, - "Trying to detect encoding from a tiny portion of ({}) byte(s).".format( - length - ), - ) - elif is_too_large_sequence: - logger.log( - TRACE, - "Using lazy str decoding because the payload is quite large, ({}) byte(s).".format( - length - ), - ) - - prioritized_encodings: list[str] = [] - - specified_encoding: str | None = ( - any_specified_encoding(sequences) if preemptive_behaviour else None - ) - - if specified_encoding is not None: - prioritized_encodings.append(specified_encoding) - logger.log( - TRACE, - "Detected declarative mark in sequence. Priority +1 given for %s.", - specified_encoding, - ) - - tested: set[str] = set() - tested_but_hard_failure: list[str] = [] - tested_but_soft_failure: list[str] = [] - soft_failure_skip: set[str] = set() - success_fast_tracked: set[str] = set() - - # Cache for decoded payload deduplication: hash(decoded_payload) -> (mean_mess_ratio, cd_ratios_merged, passed) - # When multiple encodings decode to the exact same string, we can skip the expensive - # mess_ratio and coherence_ratio analysis and reuse the results from the first encoding. - payload_result_cache: dict[int, tuple[float, list[tuple[str, float]], bool]] = {} - - # When a definitive result (chaos=0.0 and good coherence) is found after testing - # the prioritized encodings (ascii, utf_8), we can significantly reduce the remaining - # work. Encodings that target completely different language families (e.g., Cyrillic - # when the definitive match is Latin) are skipped entirely. - # Additionally, for same-family encodings that pass chaos probing, we reuse the - # definitive match's coherence ratios instead of recomputing them — a major savings - # since coherence_ratio accounts for ~30% of total time on slow Latin files. - definitive_match_found: bool = False - definitive_target_languages: set[str] = set() - # After the definitive match fires, we cap the number of additional same-family - # single-byte encodings that pass chaos probing. Once we've accumulated enough - # good candidates (N), further same-family SB encodings are unlikely to produce - # a better best() result and just waste mess_ratio + coherence_ratio time. - # The first encoding to trigger the definitive match is NOT counted (it's already in). - post_definitive_sb_success_count: int = 0 - POST_DEFINITIVE_SB_CAP: int = 7 - - # When a non-UTF multibyte encoding passes chaos probing with significant multibyte - # content (decoded length < 98% of raw length), skip all remaining single-byte encodings. - # Rationale: multi-byte decoders (CJK) have strict byte-sequence validation — if they - # decode without error AND pass chaos probing with substantial multibyte content, the - # data is genuinely multibyte encoded. Single-byte encodings will always decode (every - # byte maps to something) but waste time on mess_ratio before failing. - # The 98% threshold prevents false triggers on files that happen to have a few valid - # multibyte pairs (e.g., cp424/_ude_1.txt where big5 decodes with 99% ratio). - mb_definitive_match_found: bool = False - - fallback_ascii: CharsetMatch | None = None - fallback_u8: CharsetMatch | None = None - fallback_specified: CharsetMatch | None = None - - results: CharsetMatches = CharsetMatches() - - early_stop_results: CharsetMatches = CharsetMatches() - - sig_encoding, sig_payload = identify_sig_or_bom(sequences) - - if sig_encoding is not None: - prioritized_encodings.append(sig_encoding) - logger.log( - TRACE, - "Detected a SIG or BOM mark on first %i byte(s). Priority +1 given for %s.", - len(sig_payload), - sig_encoding, - ) - - prioritized_encodings.append("ascii") - - if "utf_8" not in prioritized_encodings: - prioritized_encodings.append("utf_8") - - for encoding_iana in prioritized_encodings + IANA_SUPPORTED_MB_FIRST: - if cp_isolation and encoding_iana not in cp_isolation: - continue - - if cp_exclusion and encoding_iana in cp_exclusion: - continue - - if encoding_iana in tested: - continue - - tested.add(encoding_iana) - - decoded_payload: str | None = None - bom_or_sig_available: bool = sig_encoding == encoding_iana - strip_sig_or_bom: bool = bom_or_sig_available and should_strip_sig_or_bom( - encoding_iana - ) - - if encoding_iana in {"utf_16", "utf_32"} and not bom_or_sig_available: - logger.log( - TRACE, - "Encoding %s won't be tested as-is because it require a BOM. Will try some sub-encoder LE/BE.", - encoding_iana, - ) - continue - if encoding_iana in {"utf_7"} and not bom_or_sig_available: - logger.log( - TRACE, - "Encoding %s won't be tested as-is because detection is unreliable without BOM/SIG.", - encoding_iana, - ) - continue - - # Skip encodings similar to ones that already soft-failed (high mess ratio). - # Checked BEFORE the expensive decode attempt. - if encoding_iana in soft_failure_skip: - logger.log( - TRACE, - "%s is deemed too similar to a code page that was already considered unsuited. Continuing!", - encoding_iana, - ) - continue - - # Skip encodings that were already fast-tracked from a similar successful encoding. - if encoding_iana in success_fast_tracked: - logger.log( - TRACE, - "Skipping %s: already fast-tracked from a similar successful encoding.", - encoding_iana, - ) - continue - - try: - is_multi_byte_decoder: bool = is_multi_byte_encoding(encoding_iana) - except (ModuleNotFoundError, ImportError): # Defensive: - logger.log( - TRACE, - "Encoding %s does not provide an IncrementalDecoder", - encoding_iana, - ) - continue - - # When we've already found a definitive match (chaos=0.0 with good coherence) - # after testing the prioritized encodings, skip encodings that target - # completely different language families. This avoids running expensive - # mess_ratio + coherence_ratio on clearly unrelated candidates (e.g., Cyrillic - # when the definitive match is Latin-based). - if definitive_match_found: - if not is_multi_byte_decoder: - enc_languages = set(encoding_languages(encoding_iana)) - else: - enc_languages = set(mb_encoding_languages(encoding_iana)) - if not enc_languages.intersection(definitive_target_languages): - logger.log( - TRACE, - "Skipping %s: definitive match already found, this encoding targets different languages (%s vs %s).", - encoding_iana, - enc_languages, - definitive_target_languages, - ) - continue - - # After the definitive match, cap the number of additional same-family - # single-byte encodings that pass chaos probing. This avoids testing the - # tail of rare, low-value same-family encodings (mac_iceland, cp860, etc.) - # that almost never change best() but each cost ~1-2ms of mess_ratio + coherence. - if ( - definitive_match_found - and not is_multi_byte_decoder - and post_definitive_sb_success_count >= POST_DEFINITIVE_SB_CAP - ): - logger.log( - TRACE, - "Skipping %s: already accumulated %d same-family results after definitive match (cap=%d).", - encoding_iana, - post_definitive_sb_success_count, - POST_DEFINITIVE_SB_CAP, - ) - continue - - # When a multibyte encoding with significant multibyte content has already - # passed chaos probing, skip all single-byte encodings. They will either fail - # chaos probing (wasting mess_ratio time) or produce inferior results. - if mb_definitive_match_found and not is_multi_byte_decoder: - logger.log( - TRACE, - "Skipping single-byte %s: multi-byte definitive match already found.", - encoding_iana, - ) - continue - - try: - if is_too_large_sequence and is_multi_byte_decoder is False: - str( - ( - sequences[: int(50e4)] - if strip_sig_or_bom is False - else sequences[len(sig_payload) : int(50e4)] - ), - encoding=encoding_iana, - ) - else: - # UTF-7 BOM is encoded in modified Base64 whose byte boundary - # can overlap with the next character. Stripping raw SIG bytes - # before decoding may leave stray bytes that decode as garbage. - # Decode the full sequence and remove the leading BOM char instead. - # see https://github.com/jawah/charset_normalizer/issues/718 - # and https://github.com/jawah/charset_normalizer/issues/716 - if encoding_iana == "utf_7" and bom_or_sig_available: - decoded_payload = str( - sequences, - encoding=encoding_iana, - ) - if decoded_payload and decoded_payload[0] == "\ufeff": - decoded_payload = decoded_payload[1:] - else: - decoded_payload = str( - ( - sequences - if strip_sig_or_bom is False - else sequences[len(sig_payload) :] - ), - encoding=encoding_iana, - ) - except (UnicodeDecodeError, LookupError) as e: - if not isinstance(e, LookupError): - logger.log( - TRACE, - "Code page %s does not fit given bytes sequence at ALL. %s", - encoding_iana, - str(e), - ) - tested_but_hard_failure.append(encoding_iana) - continue - - r_ = range( - 0 if not bom_or_sig_available else len(sig_payload), - length, - int(length / steps), - ) - - multi_byte_bonus: bool = ( - is_multi_byte_decoder - and decoded_payload is not None - and len(decoded_payload) < length - ) - - if multi_byte_bonus: - logger.log( - TRACE, - "Code page %s is a multi byte encoding table and it appear that at least one character " - "was encoded using n-bytes.", - encoding_iana, - ) - - # Payload-hash deduplication: if another encoding already decoded to the - # exact same string, reuse its mess_ratio and coherence results entirely. - # This is strictly more general than the old IANA_SUPPORTED_SIMILAR approach - # because it catches ALL identical decoding, not just pre-mapped ones. - if decoded_payload is not None and not is_multi_byte_decoder: - payload_hash: int = hash(decoded_payload) - cached = payload_result_cache.get(payload_hash) - if cached is not None: - cached_mess, cached_cd, cached_passed = cached - if cached_passed: - # The previous encoding with identical output passed chaos probing. - fast_match = CharsetMatch( - sequences, - encoding_iana, - cached_mess, - bom_or_sig_available, - cached_cd, - ( - decoded_payload - if ( - is_too_large_sequence is False - or encoding_iana - in [specified_encoding, "ascii", "utf_8"] - ) - else None - ), - preemptive_declaration=specified_encoding, - ) - results.append(fast_match) - success_fast_tracked.add(encoding_iana) - logger.log( - TRACE, - "%s fast-tracked (identical decoded payload to a prior encoding, chaos=%f %%).", - encoding_iana, - round(cached_mess * 100, ndigits=3), - ) - - if ( - encoding_iana in [specified_encoding, "ascii", "utf_8"] - and cached_mess < 0.1 - ): - if cached_mess == 0.0: - logger.debug( - "Encoding detection: %s is most likely the one.", - fast_match.encoding, - ) - if explain: - logger.removeHandler(explain_handler) - logger.setLevel(previous_logger_level) - return CharsetMatches([fast_match]) - early_stop_results.append(fast_match) - - if ( - len(early_stop_results) - and (specified_encoding is None or specified_encoding in tested) - and "ascii" in tested - and "utf_8" in tested - ): - probable_result: CharsetMatch = early_stop_results.best() # type: ignore[assignment] - logger.debug( - "Encoding detection: %s is most likely the one.", - probable_result.encoding, - ) - if explain: - logger.removeHandler(explain_handler) - logger.setLevel(previous_logger_level) - return CharsetMatches([probable_result]) - - continue - else: - # The previous encoding with identical output failed chaos probing. - tested_but_soft_failure.append(encoding_iana) - logger.log( - TRACE, - "%s fast-skipped (identical decoded payload to a prior encoding that failed chaos probing).", - encoding_iana, - ) - # Prepare fallbacks for special encodings even when skipped. - if enable_fallback and encoding_iana in [ - "ascii", - "utf_8", - specified_encoding, - "utf_16", - "utf_32", - ]: - fallback_entry = CharsetMatch( - sequences, - encoding_iana, - threshold, - bom_or_sig_available, - [], - decoded_payload, - preemptive_declaration=specified_encoding, - ) - if encoding_iana == specified_encoding: - fallback_specified = fallback_entry - elif encoding_iana == "ascii": - fallback_ascii = fallback_entry - else: - fallback_u8 = fallback_entry - continue - - max_chunk_gave_up: int = int(len(r_) / 4) - - max_chunk_gave_up = max(max_chunk_gave_up, 2) - early_stop_count: int = 0 - lazy_str_hard_failure = False - - md_chunks: list[str] = [] - md_ratios = [] - - try: - for chunk in cut_sequence_chunks( - sequences, - encoding_iana, - r_, - chunk_size, - bom_or_sig_available, - strip_sig_or_bom, - sig_payload, - is_multi_byte_decoder, - decoded_payload, - ): - md_chunks.append(chunk) - - md_ratios.append( - mess_ratio( - chunk, - threshold, - explain is True and 1 <= len(cp_isolation) <= 2, - ) - ) - - if md_ratios[-1] >= threshold: - early_stop_count += 1 - - if (early_stop_count >= max_chunk_gave_up) or ( - bom_or_sig_available and strip_sig_or_bom is False - ): - break - except ( - UnicodeDecodeError - ) as e: # Lazy str loading may have missed something there - logger.log( - TRACE, - "LazyStr Loading: After MD chunk decode, code page %s does not fit given bytes sequence at ALL. %s", - encoding_iana, - str(e), - ) - early_stop_count = max_chunk_gave_up - lazy_str_hard_failure = True - - # We might want to check the sequence again with the whole content - # Only if initial MD tests passes - if ( - not lazy_str_hard_failure - and is_too_large_sequence - and not is_multi_byte_decoder - ): - try: - sequences[int(50e3) :].decode(encoding_iana, errors="strict") - except UnicodeDecodeError as e: - logger.log( - TRACE, - "LazyStr Loading: After final lookup, code page %s does not fit given bytes sequence at ALL. %s", - encoding_iana, - str(e), - ) - tested_but_hard_failure.append(encoding_iana) - continue - - mean_mess_ratio: float = sum(md_ratios) / len(md_ratios) if md_ratios else 0.0 - if mean_mess_ratio >= threshold or early_stop_count >= max_chunk_gave_up: - tested_but_soft_failure.append(encoding_iana) - if encoding_iana in IANA_SUPPORTED_SIMILAR: - soft_failure_skip.update(IANA_SUPPORTED_SIMILAR[encoding_iana]) - # Cache this soft-failure so identical decoding from other encodings - # can be skipped immediately. - if decoded_payload is not None and not is_multi_byte_decoder: - payload_result_cache.setdefault( - hash(decoded_payload), (mean_mess_ratio, [], False) - ) - logger.log( - TRACE, - "%s was excluded because of initial chaos probing. Gave up %i time(s). " - "Computed mean chaos is %f %%.", - encoding_iana, - early_stop_count, - round(mean_mess_ratio * 100, ndigits=3), - ) - # Preparing those fallbacks in case we got nothing. - if ( - enable_fallback - and encoding_iana - in ["ascii", "utf_8", specified_encoding, "utf_16", "utf_32"] - and not lazy_str_hard_failure - ): - fallback_entry = CharsetMatch( - sequences, - encoding_iana, - threshold, - bom_or_sig_available, - [], - decoded_payload, - preemptive_declaration=specified_encoding, - ) - if encoding_iana == specified_encoding: - fallback_specified = fallback_entry - elif encoding_iana == "ascii": - fallback_ascii = fallback_entry - else: - fallback_u8 = fallback_entry - continue - - logger.log( - TRACE, - "%s passed initial chaos probing. Mean measured chaos is %f %%", - encoding_iana, - round(mean_mess_ratio * 100, ndigits=3), - ) - - if not is_multi_byte_decoder: - target_languages: list[str] = encoding_languages(encoding_iana) - else: - target_languages = mb_encoding_languages(encoding_iana) - - if target_languages: - logger.log( - TRACE, - "{} should target any language(s) of {}".format( - encoding_iana, str(target_languages) - ), - ) - - cd_ratios = [] - - # Run coherence detection on all chunks. We previously tried limiting to - # 1-2 chunks for post-definitive encodings to save time, but this caused - # coverage regressions by producing unrepresentative coherence scores. - # The SB cap and language-family skip optimizations provide sufficient - # speedup without sacrificing coherence accuracy. - if encoding_iana != "ascii": - # We shall skip the CD when its about ASCII - # Most of the time its not relevant to run "language-detection" on it. - for chunk in md_chunks: - chunk_languages = coherence_ratio( - chunk, - language_threshold, - ",".join(target_languages) if target_languages else None, - ) - - cd_ratios.append(chunk_languages) - cd_ratios_merged = merge_coherence_ratios(cd_ratios) - else: - cd_ratios_merged = merge_coherence_ratios(cd_ratios) - - if cd_ratios_merged: - logger.log( - TRACE, - "We detected language {} using {}".format( - cd_ratios_merged, encoding_iana - ), - ) - - current_match = CharsetMatch( - sequences, - encoding_iana, - mean_mess_ratio, - bom_or_sig_available, - cd_ratios_merged, - ( - decoded_payload - if ( - is_too_large_sequence is False - or encoding_iana in [specified_encoding, "ascii", "utf_8"] - ) - else None - ), - preemptive_declaration=specified_encoding, - ) - - results.append(current_match) - - # Cache the successful result for payload-hash deduplication. - if decoded_payload is not None and not is_multi_byte_decoder: - payload_result_cache.setdefault( - hash(decoded_payload), - (mean_mess_ratio, cd_ratios_merged, True), - ) - - # Count post-definitive same-family SB successes for the early termination cap. - # Only count low-mess encodings (< 2%) toward the cap. High-mess encodings are - # marginal results that shouldn't prevent better-quality candidates from being - # tested. For example, iso8859_4 (mess=0%) should not be skipped just because - # 7 high-mess Latin encodings (cp1252 at 8%, etc.) were tried first. - if ( - definitive_match_found - and not is_multi_byte_decoder - and mean_mess_ratio < 0.02 - ): - post_definitive_sb_success_count += 1 - - if ( - encoding_iana in [specified_encoding, "ascii", "utf_8"] - and mean_mess_ratio < 0.1 - ): - # If md says nothing to worry about, then... stop immediately! - if mean_mess_ratio == 0.0: - logger.debug( - "Encoding detection: %s is most likely the one.", - current_match.encoding, - ) - if explain: # Defensive: ensure exit path clean handler - logger.removeHandler(explain_handler) - logger.setLevel(previous_logger_level) - return CharsetMatches([current_match]) - - early_stop_results.append(current_match) - - if ( - len(early_stop_results) - and (specified_encoding is None or specified_encoding in tested) - and "ascii" in tested - and "utf_8" in tested - ): - probable_result = early_stop_results.best() # type: ignore[assignment] - logger.debug( - "Encoding detection: %s is most likely the one.", - probable_result.encoding, # type: ignore[union-attr] - ) - if explain: # Defensive: ensure exit path clean handler - logger.removeHandler(explain_handler) - logger.setLevel(previous_logger_level) - - return CharsetMatches([probable_result]) - - # Once we find a result with good coherence (>= 0.5) after testing the - # prioritized encodings (ascii, utf_8), activate "definitive mode": skip - # encodings that target completely different language families. This avoids - # running expensive mess_ratio + coherence_ratio on clearly unrelated - # candidates (e.g., Cyrillic encodings when the match is Latin-based). - # We require coherence >= 0.5 to avoid false positives (e.g., cp1251 decoding - # Hebrew text with 0.0 chaos but wrong language detection at coherence 0.33). - if not definitive_match_found and not is_multi_byte_decoder: - best_coherence = ( - max((v for _, v in cd_ratios_merged), default=0.0) - if cd_ratios_merged - else 0.0 - ) - if best_coherence >= 0.5 and "ascii" in tested and "utf_8" in tested: - definitive_match_found = True - definitive_target_languages.update(target_languages) - logger.log( - TRACE, - "Definitive match found: %s (chaos=%.3f, coherence=%.2f). Encodings targeting different language families will be skipped.", - encoding_iana, - mean_mess_ratio, - best_coherence, - ) - - # When a non-UTF multibyte encoding passes chaos probing with significant - # multibyte content (decoded < 98% of raw), activate mb_definitive_match. - # This skips all remaining single-byte encodings which would either soft-fail - # (running expensive mess_ratio for nothing) or produce inferior results. - if ( - not mb_definitive_match_found - and is_multi_byte_decoder - and multi_byte_bonus - and decoded_payload is not None - and len(decoded_payload) < length * 0.98 - and encoding_iana - not in { - "utf_8", - "utf_8_sig", - "utf_16", - "utf_16_be", - "utf_16_le", - "utf_32", - "utf_32_be", - "utf_32_le", - "utf_7", - } - and "ascii" in tested - and "utf_8" in tested - ): - mb_definitive_match_found = True - logger.log( - TRACE, - "Multi-byte definitive match: %s (chaos=%.3f, decoded=%d/%d=%.1f%%). Single-byte encodings will be skipped.", - encoding_iana, - mean_mess_ratio, - len(decoded_payload), - length, - len(decoded_payload) / length * 100, - ) - - if encoding_iana == sig_encoding: - logger.debug( - "Encoding detection: %s is most likely the one as we detected a BOM or SIG within " - "the beginning of the sequence.", - encoding_iana, - ) - if explain: # Defensive: ensure exit path clean handler - logger.removeHandler(explain_handler) - logger.setLevel(previous_logger_level) - return CharsetMatches([results[encoding_iana]]) - - if len(results) == 0: - if fallback_u8 or fallback_ascii or fallback_specified: - logger.log( - TRACE, - "Nothing got out of the detection process. Using ASCII/UTF-8/Specified fallback.", - ) - - if fallback_specified: - logger.debug( - "Encoding detection: %s will be used as a fallback match", - fallback_specified.encoding, - ) - results.append(fallback_specified) - elif ( - (fallback_u8 and fallback_ascii is None) - or ( - fallback_u8 - and fallback_ascii - and fallback_u8.fingerprint != fallback_ascii.fingerprint - ) - or (fallback_u8 is not None) - ): - logger.debug("Encoding detection: utf_8 will be used as a fallback match") - results.append(fallback_u8) - elif fallback_ascii: - logger.debug("Encoding detection: ascii will be used as a fallback match") - results.append(fallback_ascii) - - if results: - logger.debug( - "Encoding detection: Found %s as plausible (best-candidate) for content. With %i alternatives.", - results.best().encoding, # type: ignore - len(results) - 1, - ) - else: - logger.debug("Encoding detection: Unable to determine any suitable charset.") - - if explain: - logger.removeHandler(explain_handler) - logger.setLevel(previous_logger_level) - - return results - - -def from_fp( - fp: BinaryIO, - steps: int = 5, - chunk_size: int = 512, - threshold: float = 0.20, - cp_isolation: list[str] | None = None, - cp_exclusion: list[str] | None = None, - preemptive_behaviour: bool = True, - explain: bool = False, - language_threshold: float = 0.1, - enable_fallback: bool = True, -) -> CharsetMatches: - """ - Same thing than the function from_bytes but using a file pointer that is already ready. - Will not close the file pointer. - """ - return from_bytes( - fp.read(), - steps, - chunk_size, - threshold, - cp_isolation, - cp_exclusion, - preemptive_behaviour, - explain, - language_threshold, - enable_fallback, - ) - - -def from_path( - path: str | bytes | PathLike, # type: ignore[type-arg] - steps: int = 5, - chunk_size: int = 512, - threshold: float = 0.20, - cp_isolation: list[str] | None = None, - cp_exclusion: list[str] | None = None, - preemptive_behaviour: bool = True, - explain: bool = False, - language_threshold: float = 0.1, - enable_fallback: bool = True, -) -> CharsetMatches: - """ - Same thing than the function from_bytes but with one extra step. Opening and reading given file path in binary mode. - Can raise IOError. - """ - with open(path, "rb") as fp: - return from_fp( - fp, - steps, - chunk_size, - threshold, - cp_isolation, - cp_exclusion, - preemptive_behaviour, - explain, - language_threshold, - enable_fallback, - ) - - -def is_binary( - fp_or_path_or_payload: PathLike | str | BinaryIO | bytes, # type: ignore[type-arg] - steps: int = 5, - chunk_size: int = 512, - threshold: float = 0.20, - cp_isolation: list[str] | None = None, - cp_exclusion: list[str] | None = None, - preemptive_behaviour: bool = True, - explain: bool = False, - language_threshold: float = 0.1, - enable_fallback: bool = False, -) -> bool: - """ - Detect if the given input (file, bytes, or path) points to a binary file. aka. not a string. - Based on the same main heuristic algorithms and default kwargs at the sole exception that fallbacks match - are disabled to be stricter around ASCII-compatible but unlikely to be a string. - """ - if isinstance(fp_or_path_or_payload, (str, PathLike)): - guesses = from_path( - fp_or_path_or_payload, - steps=steps, - chunk_size=chunk_size, - threshold=threshold, - cp_isolation=cp_isolation, - cp_exclusion=cp_exclusion, - preemptive_behaviour=preemptive_behaviour, - explain=explain, - language_threshold=language_threshold, - enable_fallback=enable_fallback, - ) - elif isinstance( - fp_or_path_or_payload, - ( - bytes, - bytearray, - ), - ): - guesses = from_bytes( - fp_or_path_or_payload, - steps=steps, - chunk_size=chunk_size, - threshold=threshold, - cp_isolation=cp_isolation, - cp_exclusion=cp_exclusion, - preemptive_behaviour=preemptive_behaviour, - explain=explain, - language_threshold=language_threshold, - enable_fallback=enable_fallback, - ) - else: - guesses = from_fp( - fp_or_path_or_payload, - steps=steps, - chunk_size=chunk_size, - threshold=threshold, - cp_isolation=cp_isolation, - cp_exclusion=cp_exclusion, - preemptive_behaviour=preemptive_behaviour, - explain=explain, - language_threshold=language_threshold, - enable_fallback=enable_fallback, - ) - - return not guesses diff --git a/venv/lib/python3.9/site-packages/charset_normalizer/cd.cpython-39-x86_64-linux-gnu.so b/venv/lib/python3.9/site-packages/charset_normalizer/cd.cpython-39-x86_64-linux-gnu.so deleted file mode 100755 index 15eb479..0000000 Binary files a/venv/lib/python3.9/site-packages/charset_normalizer/cd.cpython-39-x86_64-linux-gnu.so and /dev/null differ diff --git a/venv/lib/python3.9/site-packages/charset_normalizer/cd.py b/venv/lib/python3.9/site-packages/charset_normalizer/cd.py deleted file mode 100644 index 9545d35..0000000 --- a/venv/lib/python3.9/site-packages/charset_normalizer/cd.py +++ /dev/null @@ -1,454 +0,0 @@ -from __future__ import annotations - -import importlib -from codecs import IncrementalDecoder -from collections import Counter -from functools import lru_cache -from typing import Counter as TypeCounter - -from .constant import ( - FREQUENCIES, - KO_NAMES, - LANGUAGE_SUPPORTED_COUNT, - TOO_SMALL_SEQUENCE, - ZH_NAMES, - _FREQUENCIES_SET, - _FREQUENCIES_RANK, -) -from .md import is_suspiciously_successive_range -from .models import CoherenceMatches -from .utils import ( - is_accentuated, - is_latin, - is_multi_byte_encoding, - is_unicode_range_secondary, - unicode_range, -) - - -def encoding_unicode_range(iana_name: str) -> list[str]: - """ - Return associated unicode ranges in a single byte code page. - """ - if is_multi_byte_encoding(iana_name): - raise OSError( # Defensive: - "Function not supported on multi-byte code page" - ) - - decoder = importlib.import_module(f"encodings.{iana_name}").IncrementalDecoder - - p: IncrementalDecoder = decoder(errors="ignore") - seen_ranges: dict[str, int] = {} - character_count: int = 0 - - for i in range(0x40, 0xFF): - chunk: str = p.decode(bytes([i])) - - if chunk: - character_range: str | None = unicode_range(chunk) - - if character_range is None: - continue - - if is_unicode_range_secondary(character_range) is False: - if character_range not in seen_ranges: - seen_ranges[character_range] = 0 - seen_ranges[character_range] += 1 - character_count += 1 - - return sorted( - [ - character_range - for character_range in seen_ranges - if seen_ranges[character_range] / character_count >= 0.15 - ] - ) - - -def unicode_range_languages(primary_range: str) -> list[str]: - """ - Return inferred languages used with a unicode range. - """ - languages: list[str] = [] - - for language, characters in FREQUENCIES.items(): - for character in characters: - if unicode_range(character) == primary_range: - languages.append(language) - break - - return languages - - -@lru_cache() -def encoding_languages(iana_name: str) -> list[str]: - """ - Single-byte encoding language association. Some code page are heavily linked to particular language(s). - This function does the correspondence. - """ - unicode_ranges: list[str] = encoding_unicode_range(iana_name) - primary_range: str | None = None - - for specified_range in unicode_ranges: - if "Latin" not in specified_range: - primary_range = specified_range - break - - if primary_range is None: - return ["Latin Based"] - - return unicode_range_languages(primary_range) - - -@lru_cache() -def mb_encoding_languages(iana_name: str) -> list[str]: - """ - Multi-byte encoding language association. Some code page are heavily linked to particular language(s). - This function does the correspondence. - """ - if ( - iana_name.startswith("shift_") - or iana_name.startswith("iso2022_jp") - or iana_name.startswith("euc_j") - or iana_name == "cp932" - ): - return ["Japanese"] - if iana_name.startswith("gb") or iana_name in ZH_NAMES: - return ["Chinese"] - if iana_name.startswith("iso2022_kr") or iana_name in KO_NAMES: - return ["Korean"] - - return [] - - -@lru_cache(maxsize=LANGUAGE_SUPPORTED_COUNT) -def get_target_features(language: str) -> tuple[bool, bool]: - """ - Determine main aspects from a supported language if it contains accents and if is pure Latin. - """ - target_have_accents: bool = False - target_pure_latin: bool = True - - for character in FREQUENCIES[language]: - if not target_have_accents and is_accentuated(character): - target_have_accents = True - if target_pure_latin and is_latin(character) is False: - target_pure_latin = False - - return target_have_accents, target_pure_latin - - -def alphabet_languages( - characters: list[str], ignore_non_latin: bool = False -) -> list[str]: - """ - Return associated languages associated to given characters. - """ - languages: list[tuple[str, float]] = [] - - characters_set: frozenset[str] = frozenset(characters) - source_have_accents = any(is_accentuated(character) for character in characters) - - for language, language_characters in FREQUENCIES.items(): - target_have_accents, target_pure_latin = get_target_features(language) - - if ignore_non_latin and target_pure_latin is False: - continue - - if target_have_accents is False and source_have_accents: - continue - - character_count: int = len(language_characters) - - character_match_count: int = len(_FREQUENCIES_SET[language] & characters_set) - - ratio: float = character_match_count / character_count - - if ratio >= 0.2: - languages.append((language, ratio)) - - languages = sorted(languages, key=lambda x: x[1], reverse=True) - - return [compatible_language[0] for compatible_language in languages] - - -def characters_popularity_compare( - language: str, ordered_characters: list[str] -) -> float: - """ - Determine if a ordered characters list (by occurrence from most appearance to rarest) match a particular language. - The result is a ratio between 0. (absolutely no correspondence) and 1. (near perfect fit). - Beware that is function is not strict on the match in order to ease the detection. (Meaning close match is 1.) - """ - if language not in FREQUENCIES: - raise ValueError(f"{language} not available") # Defensive: - - character_approved_count: int = 0 - frequencies_language_set: frozenset[str] = _FREQUENCIES_SET[language] - lang_rank: dict[str, int] = _FREQUENCIES_RANK[language] - - ordered_characters_count: int = len(ordered_characters) - target_language_characters_count: int = len(FREQUENCIES[language]) - - large_alphabet: bool = target_language_characters_count > 26 - - expected_projection_ratio: float = ( - target_language_characters_count / ordered_characters_count - ) - - # Pre-built rank dict for ordered_characters (avoids repeated list slicing). - ordered_rank: dict[str, int] = { - char: rank for rank, char in enumerate(ordered_characters) - } - - # Pre-compute characters common to both orderings. - # Avoids repeated `c in ordered_rank` dict lookups in the inner counts. - common_chars: list[tuple[int, int]] = [ - (lr, ordered_rank[c]) for c, lr in lang_rank.items() if c in ordered_rank - ] - - # Pre-extract lr and orr arrays for faster iteration in the inner loop. - # Plain integer loops with local arrays are much faster under mypyc than - # generator expression sums over a list of tuples. - common_count: int = len(common_chars) - common_lr: list[int] = [p[0] for p in common_chars] - common_orr: list[int] = [p[1] for p in common_chars] - - for character, character_rank in zip( - ordered_characters, range(0, ordered_characters_count) - ): - if character not in frequencies_language_set: - continue - - character_rank_in_language: int = lang_rank[character] - character_rank_projection: int = int(character_rank * expected_projection_ratio) - - if ( - large_alphabet is False - and abs(character_rank_projection - character_rank_in_language) > 4 - ): - continue - - if ( - large_alphabet is True - and abs(character_rank_projection - character_rank_in_language) - < target_language_characters_count / 3 - ): - character_approved_count += 1 - continue - - # Count how many characters appear "before" in both orderings, - # and how many appear "at or after" in both orderings. - # Single pass over pre-extracted arrays — much faster under mypyc - # than two generator expression sums. - before_match_count: int = 0 - after_match_count: int = 0 - for i in range(common_count): - lr_i: int = common_lr[i] - orr_i: int = common_orr[i] - if lr_i < character_rank_in_language: - if orr_i < character_rank: - before_match_count += 1 - else: - if orr_i >= character_rank: - after_match_count += 1 - - after_len: int = target_language_characters_count - character_rank_in_language - - if character_rank_in_language == 0 and before_match_count <= 4: - character_approved_count += 1 - continue - - if after_len == 0 and after_match_count <= 4: - character_approved_count += 1 - continue - - if ( - character_rank_in_language > 0 - and before_match_count / character_rank_in_language >= 0.4 - ) or (after_len > 0 and after_match_count / after_len >= 0.4): - character_approved_count += 1 - continue - - return character_approved_count / len(ordered_characters) - - -def alpha_unicode_split(decoded_sequence: str) -> list[str]: - """ - Given a decoded text sequence, return a list of str. Unicode range / alphabet separation. - Ex. a text containing English/Latin with a bit a Hebrew will return two items in the resulting list; - One containing the latin letters and the other hebrew. - """ - layers: dict[str, list[str]] = {} - - # Fast path: track single-layer key to skip dict iteration for single-script text. - single_layer_key: str | None = None - multi_layer: bool = False - - # Cache the last character_range and its resolved layer to avoid repeated - # is_suspiciously_successive_range calls for consecutive same-range chars. - prev_character_range: str | None = None - prev_layer_target: str | None = None - - for character in decoded_sequence: - if character.isalpha() is False: - continue - - # ASCII fast-path: a-z and A-Z are always "Basic Latin". - # Avoids unicode_range() function call overhead for the most common case. - character_ord: int = ord(character) - if character_ord < 128: - character_range: str | None = "Basic Latin" - else: - character_range = unicode_range(character) - - if character_range is None: - continue - - # Fast path: same range as previous character → reuse cached layer target. - if character_range == prev_character_range: - if prev_layer_target is not None: - layers[prev_layer_target].append(character) - continue - - layer_target_range: str | None = None - - if multi_layer: - for discovered_range in layers: - if ( - is_suspiciously_successive_range(discovered_range, character_range) - is False - ): - layer_target_range = discovered_range - break - elif single_layer_key is not None: - if ( - is_suspiciously_successive_range(single_layer_key, character_range) - is False - ): - layer_target_range = single_layer_key - - if layer_target_range is None: - layer_target_range = character_range - - if layer_target_range not in layers: - layers[layer_target_range] = [] - if single_layer_key is None: - single_layer_key = layer_target_range - else: - multi_layer = True - - layers[layer_target_range].append(character) - - # Cache for next iteration - prev_character_range = character_range - prev_layer_target = layer_target_range - - return ["".join(chars).lower() for chars in layers.values()] - - -def merge_coherence_ratios(results: list[CoherenceMatches]) -> CoherenceMatches: - """ - This function merge results previously given by the function coherence_ratio. - The return type is the same as coherence_ratio. - """ - per_language_ratios: dict[str, list[float]] = {} - for result in results: - for sub_result in result: - language, ratio = sub_result - if language not in per_language_ratios: - per_language_ratios[language] = [ratio] - continue - per_language_ratios[language].append(ratio) - - merge = [ - ( - language, - round( - sum(per_language_ratios[language]) / len(per_language_ratios[language]), - 4, - ), - ) - for language in per_language_ratios - ] - - return sorted(merge, key=lambda x: x[1], reverse=True) - - -def filter_alt_coherence_matches(results: CoherenceMatches) -> CoherenceMatches: - """ - We shall NOT return "English—" in CoherenceMatches because it is an alternative - of "English". This function only keeps the best match and remove the em-dash in it. - """ - index_results: dict[str, list[float]] = dict() - - for result in results: - language, ratio = result - no_em_name: str = language.replace("—", "") - - if no_em_name not in index_results: - index_results[no_em_name] = [] - - index_results[no_em_name].append(ratio) - - if any(len(index_results[e]) > 1 for e in index_results): - filtered_results: CoherenceMatches = [] - - for language in index_results: - filtered_results.append((language, max(index_results[language]))) - - return filtered_results - - return results - - -@lru_cache(maxsize=2048) -def coherence_ratio( - decoded_sequence: str, threshold: float = 0.1, lg_inclusion: str | None = None -) -> CoherenceMatches: - """ - Detect ANY language that can be identified in given sequence. The sequence will be analysed by layers. - A layer = Character extraction by alphabets/ranges. - """ - - results: list[tuple[str, float]] = [] - ignore_non_latin: bool = False - - sufficient_match_count: int = 0 - - lg_inclusion_list = lg_inclusion.split(",") if lg_inclusion is not None else [] - if "Latin Based" in lg_inclusion_list: - ignore_non_latin = True - lg_inclusion_list.remove("Latin Based") - - for layer in alpha_unicode_split(decoded_sequence): - sequence_frequencies: TypeCounter[str] = Counter(layer) - most_common = sequence_frequencies.most_common() - - character_count: int = len(layer) - - if character_count <= TOO_SMALL_SEQUENCE: - continue - - popular_character_ordered: list[str] = [c for c, o in most_common] - - for language in lg_inclusion_list or alphabet_languages( - popular_character_ordered, ignore_non_latin - ): - ratio: float = characters_popularity_compare( - language, popular_character_ordered - ) - - if ratio < threshold: - continue - elif ratio >= 0.8: - sufficient_match_count += 1 - - results.append((language, round(ratio, 4))) - - if sufficient_match_count >= 3: - break - - return sorted( - filter_alt_coherence_matches(results), key=lambda x: x[1], reverse=True - ) diff --git a/venv/lib/python3.9/site-packages/charset_normalizer/cli/__init__.py b/venv/lib/python3.9/site-packages/charset_normalizer/cli/__init__.py deleted file mode 100644 index 543a5a4..0000000 --- a/venv/lib/python3.9/site-packages/charset_normalizer/cli/__init__.py +++ /dev/null @@ -1,8 +0,0 @@ -from __future__ import annotations - -from .__main__ import cli_detect, query_yes_no - -__all__ = ( - "cli_detect", - "query_yes_no", -) diff --git a/venv/lib/python3.9/site-packages/charset_normalizer/cli/__main__.py b/venv/lib/python3.9/site-packages/charset_normalizer/cli/__main__.py deleted file mode 100644 index ad843c1..0000000 --- a/venv/lib/python3.9/site-packages/charset_normalizer/cli/__main__.py +++ /dev/null @@ -1,362 +0,0 @@ -from __future__ import annotations - -import argparse -import sys -import typing -from json import dumps -from os.path import abspath, basename, dirname, join, realpath -from platform import python_version -from unicodedata import unidata_version - -import charset_normalizer.md as md_module -from charset_normalizer import from_fp -from charset_normalizer.models import CliDetectionResult -from charset_normalizer.version import __version__ - - -def query_yes_no(question: str, default: str = "yes") -> bool: # Defensive: - """Ask a yes/no question via input() and return the answer as a bool.""" - prompt = " [Y/n] " if default == "yes" else " [y/N] " - - while True: - choice = input(question + prompt).strip().lower() - if not choice: - return default == "yes" - if choice in ("y", "yes"): - return True - if choice in ("n", "no"): - return False - print("Please respond with 'y' or 'n'.") - - -class FileType: - """Factory for creating file object types - - Instances of FileType are typically passed as type= arguments to the - ArgumentParser add_argument() method. - - Keyword Arguments: - - mode -- A string indicating how the file is to be opened. Accepts the - same values as the builtin open() function. - - bufsize -- The file's desired buffer size. Accepts the same values as - the builtin open() function. - - encoding -- The file's encoding. Accepts the same values as the - builtin open() function. - - errors -- A string indicating how encoding and decoding errors are to - be handled. Accepts the same value as the builtin open() function. - - Backported from CPython 3.12 - """ - - def __init__( - self, - mode: str = "r", - bufsize: int = -1, - encoding: str | None = None, - errors: str | None = None, - ): - self._mode = mode - self._bufsize = bufsize - self._encoding = encoding - self._errors = errors - - def __call__(self, string: str) -> typing.IO: # type: ignore[type-arg] - # the special argument "-" means sys.std{in,out} - if string == "-": - if "r" in self._mode: - return sys.stdin.buffer if "b" in self._mode else sys.stdin - elif any(c in self._mode for c in "wax"): - return sys.stdout.buffer if "b" in self._mode else sys.stdout - else: - msg = f'argument "-" with mode {self._mode}' - raise ValueError(msg) - - # all other arguments are used as file names - try: - return open(string, self._mode, self._bufsize, self._encoding, self._errors) - except OSError as e: - message = f"can't open '{string}': {e}" - raise argparse.ArgumentTypeError(message) - - def __repr__(self) -> str: - args = self._mode, self._bufsize - kwargs = [("encoding", self._encoding), ("errors", self._errors)] - args_str = ", ".join( - [repr(arg) for arg in args if arg != -1] - + [f"{kw}={arg!r}" for kw, arg in kwargs if arg is not None] - ) - return f"{type(self).__name__}({args_str})" - - -def cli_detect(argv: list[str] | None = None) -> int: - """ - CLI assistant using ARGV and ArgumentParser - :param argv: - :return: 0 if everything is fine, anything else equal trouble - """ - parser = argparse.ArgumentParser( - description="The Real First Universal Charset Detector. " - "Discover originating encoding used on text file. " - "Normalize text to unicode." - ) - - parser.add_argument( - "files", type=FileType("rb"), nargs="+", help="File(s) to be analysed" - ) - parser.add_argument( - "-v", - "--verbose", - action="store_true", - default=False, - dest="verbose", - help="Display complementary information about file if any. " - "Stdout will contain logs about the detection process.", - ) - parser.add_argument( - "-a", - "--with-alternative", - action="store_true", - default=False, - dest="alternatives", - help="Output complementary possibilities if any. Top-level JSON WILL be a list.", - ) - parser.add_argument( - "-n", - "--normalize", - action="store_true", - default=False, - dest="normalize", - help="Permit to normalize input file. If not set, program does not write anything.", - ) - parser.add_argument( - "-m", - "--minimal", - action="store_true", - default=False, - dest="minimal", - help="Only output the charset detected to STDOUT. Disabling JSON output.", - ) - parser.add_argument( - "-r", - "--replace", - action="store_true", - default=False, - dest="replace", - help="Replace file when trying to normalize it instead of creating a new one.", - ) - parser.add_argument( - "-f", - "--force", - action="store_true", - default=False, - dest="force", - help="Replace file without asking if you are sure, use this flag with caution.", - ) - parser.add_argument( - "-i", - "--no-preemptive", - action="store_true", - default=False, - dest="no_preemptive", - help="Disable looking at a charset declaration to hint the detector.", - ) - parser.add_argument( - "-t", - "--threshold", - action="store", - default=0.2, - type=float, - dest="threshold", - help="Define a custom maximum amount of noise allowed in decoded content. 0. <= noise <= 1.", - ) - parser.add_argument( - "--version", - action="version", - version="Charset-Normalizer {} - Python {} - Unicode {} - SpeedUp {}".format( - __version__, - python_version(), - unidata_version, - "OFF" if md_module.__file__.lower().endswith(".py") else "ON", - ), - help="Show version information and exit.", - ) - - args = parser.parse_args(argv) - - if args.replace is True and args.normalize is False: - if args.files: - for my_file in args.files: - my_file.close() - print("Use --replace in addition of --normalize only.", file=sys.stderr) - return 1 - - if args.force is True and args.replace is False: - if args.files: - for my_file in args.files: - my_file.close() - print("Use --force in addition of --replace only.", file=sys.stderr) - return 1 - - if args.threshold < 0.0 or args.threshold > 1.0: - if args.files: - for my_file in args.files: - my_file.close() - print("--threshold VALUE should be between 0. AND 1.", file=sys.stderr) - return 1 - - x_ = [] - - for my_file in args.files: - matches = from_fp( - my_file, - threshold=args.threshold, - explain=args.verbose, - preemptive_behaviour=args.no_preemptive is False, - ) - - best_guess = matches.best() - - if best_guess is None: - print( - 'Unable to identify originating encoding for "{}". {}'.format( - my_file.name, - ( - "Maybe try increasing maximum amount of chaos." - if args.threshold < 1.0 - else "" - ), - ), - file=sys.stderr, - ) - x_.append( - CliDetectionResult( - abspath(my_file.name), - None, - [], - [], - "Unknown", - [], - False, - 1.0, - 0.0, - None, - True, - ) - ) - else: - cli_result = CliDetectionResult( - abspath(my_file.name), - best_guess.encoding, - best_guess.encoding_aliases, - [ - cp - for cp in best_guess.could_be_from_charset - if cp != best_guess.encoding - ], - best_guess.language, - best_guess.alphabets, - best_guess.bom, - best_guess.percent_chaos, - best_guess.percent_coherence, - None, - True, - ) - x_.append(cli_result) - - if len(matches) > 1 and args.alternatives: - for el in matches: - if el != best_guess: - x_.append( - CliDetectionResult( - abspath(my_file.name), - el.encoding, - el.encoding_aliases, - [ - cp - for cp in el.could_be_from_charset - if cp != el.encoding - ], - el.language, - el.alphabets, - el.bom, - el.percent_chaos, - el.percent_coherence, - None, - False, - ) - ) - - if args.normalize is True: - if best_guess.encoding.startswith("utf") is True: - print( - '"{}" file does not need to be normalized, as it already came from unicode.'.format( - my_file.name - ), - file=sys.stderr, - ) - if my_file.closed is False: - my_file.close() - continue - - dir_path = dirname(realpath(my_file.name)) - file_name = basename(realpath(my_file.name)) - - o_: list[str] = file_name.split(".") - - if args.replace is False: - o_.insert(-1, best_guess.encoding) - if my_file.closed is False: - my_file.close() - elif ( - args.force is False - and query_yes_no( - 'Are you sure to normalize "{}" by replacing it ?'.format( - my_file.name - ), - "no", - ) - is False - ): - if my_file.closed is False: - my_file.close() - continue - - try: - cli_result.unicode_path = join(dir_path, ".".join(o_)) - - with open(cli_result.unicode_path, "wb") as fp: - fp.write(best_guess.output()) - except OSError as e: # Defensive: - print(str(e), file=sys.stderr) - if my_file.closed is False: - my_file.close() - return 2 - - if my_file.closed is False: - my_file.close() - - if args.minimal is False: - print( - dumps( - [el.__dict__ for el in x_] if len(x_) > 1 else x_[0].__dict__, - ensure_ascii=True, - indent=4, - ) - ) - else: - for my_file in args.files: - print( - ", ".join( - [ - el.encoding or "undefined" - for el in x_ - if el.path == abspath(my_file.name) - ] - ) - ) - - return 0 - - -if __name__ == "__main__": # Defensive: - cli_detect() diff --git a/venv/lib/python3.9/site-packages/charset_normalizer/constant.py b/venv/lib/python3.9/site-packages/charset_normalizer/constant.py deleted file mode 100644 index e1297d2..0000000 --- a/venv/lib/python3.9/site-packages/charset_normalizer/constant.py +++ /dev/null @@ -1,2050 +0,0 @@ -from __future__ import annotations - -from codecs import BOM_UTF8, BOM_UTF16_BE, BOM_UTF16_LE, BOM_UTF32_BE, BOM_UTF32_LE -from encodings.aliases import aliases -from re import IGNORECASE -from re import compile as re_compile - -# Contain for each eligible encoding a list of/item bytes SIG/BOM -ENCODING_MARKS: dict[str, bytes | list[bytes]] = { - "utf_8": BOM_UTF8, - "utf_7": [ - b"\x2b\x2f\x76\x38\x2d", - b"\x2b\x2f\x76\x38", - b"\x2b\x2f\x76\x39", - b"\x2b\x2f\x76\x2b", - b"\x2b\x2f\x76\x2f", - ], - "gb18030": b"\x84\x31\x95\x33", - "utf_32": [BOM_UTF32_BE, BOM_UTF32_LE], - "utf_16": [BOM_UTF16_BE, BOM_UTF16_LE], -} - -TOO_SMALL_SEQUENCE: int = 32 -TOO_BIG_SEQUENCE: int = int(10e6) - -UTF8_MAXIMAL_ALLOCATION: int = 1_112_064 - -# Up-to-date Unicode ucd/17.0.0 -UNICODE_RANGES_COMBINED: dict[str, range] = { - "Control character": range(32), - "Basic Latin": range(32, 128), - "Latin-1 Supplement": range(128, 256), - "Latin Extended-A": range(256, 384), - "Latin Extended-B": range(384, 592), - "IPA Extensions": range(592, 688), - "Spacing Modifier Letters": range(688, 768), - "Combining Diacritical Marks": range(768, 880), - "Greek and Coptic": range(880, 1024), - "Cyrillic": range(1024, 1280), - "Cyrillic Supplement": range(1280, 1328), - "Armenian": range(1328, 1424), - "Hebrew": range(1424, 1536), - "Arabic": range(1536, 1792), - "Syriac": range(1792, 1872), - "Arabic Supplement": range(1872, 1920), - "Thaana": range(1920, 1984), - "NKo": range(1984, 2048), - "Samaritan": range(2048, 2112), - "Mandaic": range(2112, 2144), - "Syriac Supplement": range(2144, 2160), - "Arabic Extended-B": range(2160, 2208), - "Arabic Extended-A": range(2208, 2304), - "Devanagari": range(2304, 2432), - "Bengali": range(2432, 2560), - "Gurmukhi": range(2560, 2688), - "Gujarati": range(2688, 2816), - "Oriya": range(2816, 2944), - "Tamil": range(2944, 3072), - "Telugu": range(3072, 3200), - "Kannada": range(3200, 3328), - "Malayalam": range(3328, 3456), - "Sinhala": range(3456, 3584), - "Thai": range(3584, 3712), - "Lao": range(3712, 3840), - "Tibetan": range(3840, 4096), - "Myanmar": range(4096, 4256), - "Georgian": range(4256, 4352), - "Hangul Jamo": range(4352, 4608), - "Ethiopic": range(4608, 4992), - "Ethiopic Supplement": range(4992, 5024), - "Cherokee": range(5024, 5120), - "Unified Canadian Aboriginal Syllabics": range(5120, 5760), - "Ogham": range(5760, 5792), - "Runic": range(5792, 5888), - "Tagalog": range(5888, 5920), - "Hanunoo": range(5920, 5952), - "Buhid": range(5952, 5984), - "Tagbanwa": range(5984, 6016), - "Khmer": range(6016, 6144), - "Mongolian": range(6144, 6320), - "Unified Canadian Aboriginal Syllabics Extended": range(6320, 6400), - "Limbu": range(6400, 6480), - "Tai Le": range(6480, 6528), - "New Tai Lue": range(6528, 6624), - "Khmer Symbols": range(6624, 6656), - "Buginese": range(6656, 6688), - "Tai Tham": range(6688, 6832), - "Combining Diacritical Marks Extended": range(6832, 6912), - "Balinese": range(6912, 7040), - "Sundanese": range(7040, 7104), - "Batak": range(7104, 7168), - "Lepcha": range(7168, 7248), - "Ol Chiki": range(7248, 7296), - "Cyrillic Extended-C": range(7296, 7312), - "Georgian Extended": range(7312, 7360), - "Sundanese Supplement": range(7360, 7376), - "Vedic Extensions": range(7376, 7424), - "Phonetic Extensions": range(7424, 7552), - "Phonetic Extensions Supplement": range(7552, 7616), - "Combining Diacritical Marks Supplement": range(7616, 7680), - "Latin Extended Additional": range(7680, 7936), - "Greek Extended": range(7936, 8192), - "General Punctuation": range(8192, 8304), - "Superscripts and Subscripts": range(8304, 8352), - "Currency Symbols": range(8352, 8400), - "Combining Diacritical Marks for Symbols": range(8400, 8448), - "Letterlike Symbols": range(8448, 8528), - "Number Forms": range(8528, 8592), - "Arrows": range(8592, 8704), - "Mathematical Operators": range(8704, 8960), - "Miscellaneous Technical": range(8960, 9216), - "Control Pictures": range(9216, 9280), - "Optical Character Recognition": range(9280, 9312), - "Enclosed Alphanumerics": range(9312, 9472), - "Box Drawing": range(9472, 9600), - "Block Elements": range(9600, 9632), - "Geometric Shapes": range(9632, 9728), - "Miscellaneous Symbols": range(9728, 9984), - "Dingbats": range(9984, 10176), - "Miscellaneous Mathematical Symbols-A": range(10176, 10224), - "Supplemental Arrows-A": range(10224, 10240), - "Braille Patterns": range(10240, 10496), - "Supplemental Arrows-B": range(10496, 10624), - "Miscellaneous Mathematical Symbols-B": range(10624, 10752), - "Supplemental Mathematical Operators": range(10752, 11008), - "Miscellaneous Symbols and Arrows": range(11008, 11264), - "Glagolitic": range(11264, 11360), - "Latin Extended-C": range(11360, 11392), - "Coptic": range(11392, 11520), - "Georgian Supplement": range(11520, 11568), - "Tifinagh": range(11568, 11648), - "Ethiopic Extended": range(11648, 11744), - "Cyrillic Extended-A": range(11744, 11776), - "Supplemental Punctuation": range(11776, 11904), - "CJK Radicals Supplement": range(11904, 12032), - "Kangxi Radicals": range(12032, 12256), - "Ideographic Description Characters": range(12272, 12288), - "CJK Symbols and Punctuation": range(12288, 12352), - "Hiragana": range(12352, 12448), - "Katakana": range(12448, 12544), - "Bopomofo": range(12544, 12592), - "Hangul Compatibility Jamo": range(12592, 12688), - "Kanbun": range(12688, 12704), - "Bopomofo Extended": range(12704, 12736), - "CJK Strokes": range(12736, 12784), - "Katakana Phonetic Extensions": range(12784, 12800), - "Enclosed CJK Letters and Months": range(12800, 13056), - "CJK Compatibility": range(13056, 13312), - "CJK Unified Ideographs Extension A": range(13312, 19904), - "Yijing Hexagram Symbols": range(19904, 19968), - "CJK Unified Ideographs": range(19968, 40960), - "Yi Syllables": range(40960, 42128), - "Yi Radicals": range(42128, 42192), - "Lisu": range(42192, 42240), - "Vai": range(42240, 42560), - "Cyrillic Extended-B": range(42560, 42656), - "Bamum": range(42656, 42752), - "Modifier Tone Letters": range(42752, 42784), - "Latin Extended-D": range(42784, 43008), - "Syloti Nagri": range(43008, 43056), - "Common Indic Number Forms": range(43056, 43072), - "Phags-pa": range(43072, 43136), - "Saurashtra": range(43136, 43232), - "Devanagari Extended": range(43232, 43264), - "Kayah Li": range(43264, 43312), - "Rejang": range(43312, 43360), - "Hangul Jamo Extended-A": range(43360, 43392), - "Javanese": range(43392, 43488), - "Myanmar Extended-B": range(43488, 43520), - "Cham": range(43520, 43616), - "Myanmar Extended-A": range(43616, 43648), - "Tai Viet": range(43648, 43744), - "Meetei Mayek Extensions": range(43744, 43776), - "Ethiopic Extended-A": range(43776, 43824), - "Latin Extended-E": range(43824, 43888), - "Cherokee Supplement": range(43888, 43968), - "Meetei Mayek": range(43968, 44032), - "Hangul Syllables": range(44032, 55216), - "Hangul Jamo Extended-B": range(55216, 55296), - "High Surrogates": range(55296, 56192), - "High Private Use Surrogates": range(56192, 56320), - "Low Surrogates": range(56320, 57344), - "Private Use Area": range(57344, 63744), - "CJK Compatibility Ideographs": range(63744, 64256), - "Alphabetic Presentation Forms": range(64256, 64336), - "Arabic Presentation Forms-A": range(64336, 65024), - "Variation Selectors": range(65024, 65040), - "Vertical Forms": range(65040, 65056), - "Combining Half Marks": range(65056, 65072), - "CJK Compatibility Forms": range(65072, 65104), - "Small Form Variants": range(65104, 65136), - "Arabic Presentation Forms-B": range(65136, 65280), - "Halfwidth and Fullwidth Forms": range(65280, 65520), - "Specials": range(65520, 65536), - "Linear B Syllabary": range(65536, 65664), - "Linear B Ideograms": range(65664, 65792), - "Aegean Numbers": range(65792, 65856), - "Ancient Greek Numbers": range(65856, 65936), - "Ancient Symbols": range(65936, 66000), - "Phaistos Disc": range(66000, 66048), - "Lycian": range(66176, 66208), - "Carian": range(66208, 66272), - "Coptic Epact Numbers": range(66272, 66304), - "Old Italic": range(66304, 66352), - "Gothic": range(66352, 66384), - "Old Permic": range(66384, 66432), - "Ugaritic": range(66432, 66464), - "Old Persian": range(66464, 66528), - "Deseret": range(66560, 66640), - "Shavian": range(66640, 66688), - "Osmanya": range(66688, 66736), - "Osage": range(66736, 66816), - "Elbasan": range(66816, 66864), - "Caucasian Albanian": range(66864, 66928), - "Vithkuqi": range(66928, 67008), - "Todhri": range(67008, 67072), - "Linear A": range(67072, 67456), - "Latin Extended-F": range(67456, 67520), - "Cypriot Syllabary": range(67584, 67648), - "Imperial Aramaic": range(67648, 67680), - "Palmyrene": range(67680, 67712), - "Nabataean": range(67712, 67760), - "Hatran": range(67808, 67840), - "Phoenician": range(67840, 67872), - "Lydian": range(67872, 67904), - "Sidetic": range(67904, 67936), - "Meroitic Hieroglyphs": range(67968, 68000), - "Meroitic Cursive": range(68000, 68096), - "Kharoshthi": range(68096, 68192), - "Old South Arabian": range(68192, 68224), - "Old North Arabian": range(68224, 68256), - "Manichaean": range(68288, 68352), - "Avestan": range(68352, 68416), - "Inscriptional Parthian": range(68416, 68448), - "Inscriptional Pahlavi": range(68448, 68480), - "Psalter Pahlavi": range(68480, 68528), - "Old Turkic": range(68608, 68688), - "Old Hungarian": range(68736, 68864), - "Hanifi Rohingya": range(68864, 68928), - "Garay": range(68928, 69008), - "Rumi Numeral Symbols": range(69216, 69248), - "Yezidi": range(69248, 69312), - "Arabic Extended-C": range(69312, 69376), - "Old Sogdian": range(69376, 69424), - "Sogdian": range(69424, 69488), - "Old Uyghur": range(69488, 69552), - "Chorasmian": range(69552, 69600), - "Elymaic": range(69600, 69632), - "Brahmi": range(69632, 69760), - "Kaithi": range(69760, 69840), - "Sora Sompeng": range(69840, 69888), - "Chakma": range(69888, 69968), - "Mahajani": range(69968, 70016), - "Sharada": range(70016, 70112), - "Sinhala Archaic Numbers": range(70112, 70144), - "Khojki": range(70144, 70224), - "Multani": range(70272, 70320), - "Khudawadi": range(70320, 70400), - "Grantha": range(70400, 70528), - "Tulu-Tigalari": range(70528, 70656), - "Newa": range(70656, 70784), - "Tirhuta": range(70784, 70880), - "Siddham": range(71040, 71168), - "Modi": range(71168, 71264), - "Mongolian Supplement": range(71264, 71296), - "Takri": range(71296, 71376), - "Myanmar Extended-C": range(71376, 71424), - "Ahom": range(71424, 71504), - "Dogra": range(71680, 71760), - "Warang Citi": range(71840, 71936), - "Dives Akuru": range(71936, 72032), - "Nandinagari": range(72096, 72192), - "Zanabazar Square": range(72192, 72272), - "Soyombo": range(72272, 72368), - "Unified Canadian Aboriginal Syllabics Extended-A": range(72368, 72384), - "Pau Cin Hau": range(72384, 72448), - "Devanagari Extended-A": range(72448, 72544), - "Sharada Supplement": range(72544, 72576), - "Sunuwar": range(72640, 72704), - "Bhaiksuki": range(72704, 72816), - "Marchen": range(72816, 72896), - "Masaram Gondi": range(72960, 73056), - "Gunjala Gondi": range(73056, 73136), - "Tolong Siki": range(73136, 73200), - "Makasar": range(73440, 73472), - "Kawi": range(73472, 73568), - "Lisu Supplement": range(73648, 73664), - "Tamil Supplement": range(73664, 73728), - "Cuneiform": range(73728, 74752), - "Cuneiform Numbers and Punctuation": range(74752, 74880), - "Early Dynastic Cuneiform": range(74880, 75088), - "Cypro-Minoan": range(77712, 77824), - "Egyptian Hieroglyphs": range(77824, 78896), - "Egyptian Hieroglyph Format Controls": range(78896, 78944), - "Egyptian Hieroglyphs Extended-A": range(78944, 82944), - "Anatolian Hieroglyphs": range(82944, 83584), - "Gurung Khema": range(90368, 90432), - "Bamum Supplement": range(92160, 92736), - "Mro": range(92736, 92784), - "Tangsa": range(92784, 92880), - "Bassa Vah": range(92880, 92928), - "Pahawh Hmong": range(92928, 93072), - "Kirat Rai": range(93504, 93568), - "Medefaidrin": range(93760, 93856), - "Beria Erfe": range(93856, 93920), - "Miao": range(93952, 94112), - "Ideographic Symbols and Punctuation": range(94176, 94208), - "Tangut": range(94208, 100352), - "Tangut Components": range(100352, 101120), - "Khitan Small Script": range(101120, 101632), - "Tangut Supplement": range(101632, 101760), - "Tangut Components Supplement": range(101760, 101888), - "Kana Extended-B": range(110576, 110592), - "Kana Supplement": range(110592, 110848), - "Kana Extended-A": range(110848, 110896), - "Small Kana Extension": range(110896, 110960), - "Nushu": range(110960, 111360), - "Duployan": range(113664, 113824), - "Shorthand Format Controls": range(113824, 113840), - "Symbols for Legacy Computing Supplement": range(117760, 118464), - "Miscellaneous Symbols Supplement": range(118464, 118528), - "Znamenny Musical Notation": range(118528, 118736), - "Byzantine Musical Symbols": range(118784, 119040), - "Musical Symbols": range(119040, 119296), - "Ancient Greek Musical Notation": range(119296, 119376), - "Kaktovik Numerals": range(119488, 119520), - "Mayan Numerals": range(119520, 119552), - "Tai Xuan Jing Symbols": range(119552, 119648), - "Counting Rod Numerals": range(119648, 119680), - "Mathematical Alphanumeric Symbols": range(119808, 120832), - "Sutton SignWriting": range(120832, 121520), - "Latin Extended-G": range(122624, 122880), - "Glagolitic Supplement": range(122880, 122928), - "Cyrillic Extended-D": range(122928, 123024), - "Nyiakeng Puachue Hmong": range(123136, 123216), - "Toto": range(123536, 123584), - "Wancho": range(123584, 123648), - "Nag Mundari": range(124112, 124160), - "Ol Onal": range(124368, 124416), - "Tai Yo": range(124608, 124672), - "Ethiopic Extended-B": range(124896, 124928), - "Mende Kikakui": range(124928, 125152), - "Adlam": range(125184, 125280), - "Indic Siyaq Numbers": range(126064, 126144), - "Ottoman Siyaq Numbers": range(126208, 126288), - "Arabic Mathematical Alphabetic Symbols": range(126464, 126720), - "Mahjong Tiles": range(126976, 127024), - "Domino Tiles": range(127024, 127136), - "Playing Cards": range(127136, 127232), - "Enclosed Alphanumeric Supplement": range(127232, 127488), - "Enclosed Ideographic Supplement": range(127488, 127744), - "Miscellaneous Symbols and Pictographs": range(127744, 128512), - "Emoticons": range(128512, 128592), - "Ornamental Dingbats": range(128592, 128640), - "Transport and Map Symbols": range(128640, 128768), - "Alchemical Symbols": range(128768, 128896), - "Geometric Shapes Extended": range(128896, 129024), - "Supplemental Arrows-C": range(129024, 129280), - "Supplemental Symbols and Pictographs": range(129280, 129536), - "Chess Symbols": range(129536, 129648), - "Symbols and Pictographs Extended-A": range(129648, 129792), - "Symbols for Legacy Computing": range(129792, 130048), - "CJK Unified Ideographs Extension B": range(131072, 173792), - "CJK Unified Ideographs Extension C": range(173824, 177984), - "CJK Unified Ideographs Extension D": range(177984, 178208), - "CJK Unified Ideographs Extension E": range(178208, 183984), - "CJK Unified Ideographs Extension F": range(183984, 191472), - "CJK Unified Ideographs Extension I": range(191472, 192096), - "CJK Compatibility Ideographs Supplement": range(194560, 195104), - "CJK Unified Ideographs Extension G": range(196608, 201552), - "CJK Unified Ideographs Extension H": range(201552, 205744), - "CJK Unified Ideographs Extension J": range(205744, 210048), - "Tags": range(917504, 917632), - "Variation Selectors Supplement": range(917760, 918000), - "Supplementary Private Use Area-A": range(983040, 1048576), - "Supplementary Private Use Area-B": range(1048576, 1114112), -} - - -UNICODE_SECONDARY_RANGE_KEYWORD: list[str] = [ - "Supplement", - "Extended", - "Extensions", - "Modifier", - "Marks", - "Punctuation", - "Symbols", - "Forms", - "Operators", - "Miscellaneous", - "Drawing", - "Block", - "Shapes", - "Supplemental", - "Tags", -] - -RE_POSSIBLE_ENCODING_INDICATION = re_compile( - r"(?:(?:encoding)|(?:charset)|(?:coding))(?:[\:= ]{1,10})(?:[\"\']?)([a-zA-Z0-9\-_]+)(?:[\"\']?)", - IGNORECASE, -) - -IANA_NO_ALIASES = [ - "cp720", - "cp737", - "cp856", - "cp874", - "cp875", - "cp1006", - "koi8_r", - "koi8_t", - "koi8_u", -] - -IANA_SUPPORTED: list[str] = sorted( - filter( - lambda x: x.endswith("_codec") is False - and x not in {"rot_13", "tactis", "mbcs"}, - list(set(aliases.values())) + IANA_NO_ALIASES, - ) -) - -IANA_SUPPORTED_COUNT: int = len(IANA_SUPPORTED) - -# pre-computed code page that are similar using the function cp_similarity. -IANA_SUPPORTED_SIMILAR: dict[str, list[str]] = { - "cp037": ["cp1026", "cp1140", "cp273", "cp500"], - "cp1026": ["cp037", "cp1140", "cp273", "cp500"], - "cp1125": ["cp866"], - "cp1140": ["cp037", "cp1026", "cp273", "cp500"], - "cp1250": ["iso8859_2"], - "cp1251": ["kz1048", "ptcp154"], - "cp1252": ["iso8859_15", "iso8859_9", "latin_1"], - "cp1253": ["iso8859_7"], - "cp1254": ["iso8859_15", "iso8859_9", "latin_1"], - "cp1257": ["iso8859_13"], - "cp273": ["cp037", "cp1026", "cp1140", "cp500"], - "cp437": ["cp850", "cp858", "cp860", "cp861", "cp862", "cp863", "cp865"], - "cp500": ["cp037", "cp1026", "cp1140", "cp273"], - "cp850": ["cp437", "cp857", "cp858", "cp865"], - "cp857": ["cp850", "cp858", "cp865"], - "cp858": ["cp437", "cp850", "cp857", "cp865"], - "cp860": ["cp437", "cp861", "cp862", "cp863", "cp865"], - "cp861": ["cp437", "cp860", "cp862", "cp863", "cp865"], - "cp862": ["cp437", "cp860", "cp861", "cp863", "cp865"], - "cp863": ["cp437", "cp860", "cp861", "cp862", "cp865"], - "cp865": ["cp437", "cp850", "cp857", "cp858", "cp860", "cp861", "cp862", "cp863"], - "cp866": ["cp1125"], - "iso8859_10": ["iso8859_14", "iso8859_15", "iso8859_4", "iso8859_9", "latin_1"], - "iso8859_11": ["tis_620"], - "iso8859_13": ["cp1257"], - "iso8859_14": [ - "iso8859_10", - "iso8859_15", - "iso8859_16", - "iso8859_3", - "iso8859_9", - "latin_1", - ], - "iso8859_15": [ - "cp1252", - "cp1254", - "iso8859_10", - "iso8859_14", - "iso8859_16", - "iso8859_3", - "iso8859_9", - "latin_1", - ], - "iso8859_16": [ - "iso8859_14", - "iso8859_15", - "iso8859_2", - "iso8859_3", - "iso8859_9", - "latin_1", - ], - "iso8859_2": ["cp1250", "iso8859_16", "iso8859_4"], - "iso8859_3": ["iso8859_14", "iso8859_15", "iso8859_16", "iso8859_9", "latin_1"], - "iso8859_4": ["iso8859_10", "iso8859_2", "iso8859_9", "latin_1"], - "iso8859_7": ["cp1253"], - "iso8859_9": [ - "cp1252", - "cp1254", - "cp1258", - "iso8859_10", - "iso8859_14", - "iso8859_15", - "iso8859_16", - "iso8859_3", - "iso8859_4", - "latin_1", - ], - "kz1048": ["cp1251", "ptcp154"], - "latin_1": [ - "cp1252", - "cp1254", - "cp1258", - "iso8859_10", - "iso8859_14", - "iso8859_15", - "iso8859_16", - "iso8859_3", - "iso8859_4", - "iso8859_9", - ], - "mac_iceland": ["mac_roman", "mac_turkish"], - "mac_roman": ["mac_iceland", "mac_turkish"], - "mac_turkish": ["mac_iceland", "mac_roman"], - "ptcp154": ["cp1251", "kz1048"], - "tis_620": ["iso8859_11"], -} - - -CHARDET_CORRESPONDENCE: dict[str, str] = { - "iso2022_kr": "ISO-2022-KR", - "iso2022_jp": "ISO-2022-JP", - "euc_kr": "EUC-KR", - "tis_620": "TIS-620", - "utf_32": "UTF-32", - "euc_jp": "EUC-JP", - "koi8_r": "KOI8-R", - "iso8859_1": "ISO-8859-1", - "iso8859_2": "ISO-8859-2", - "iso8859_5": "ISO-8859-5", - "iso8859_6": "ISO-8859-6", - "iso8859_7": "ISO-8859-7", - "iso8859_8": "ISO-8859-8", - "utf_16": "UTF-16", - "cp855": "IBM855", - "mac_cyrillic": "MacCyrillic", - "gb2312": "GB2312", - "gb18030": "GB18030", - "cp932": "CP932", - "cp866": "IBM866", - "utf_8": "utf-8", - "utf_8_sig": "UTF-8-SIG", - "shift_jis": "SHIFT_JIS", - "big5": "Big5", - "cp1250": "windows-1250", - "cp1251": "windows-1251", - "cp1252": "Windows-1252", - "cp1253": "windows-1253", - "cp1255": "windows-1255", - "cp1256": "windows-1256", - "cp1254": "Windows-1254", - "cp949": "CP949", -} - - -COMMON_SAFE_ASCII_CHARACTERS: frozenset[str] = frozenset( - { - "<", - ">", - "=", - ":", - "/", - "&", - ";", - "{", - "}", - "[", - "]", - ",", - "|", - '"', - "-", - "(", - ")", - } -) - -# Sample character sets — replace with full lists if needed -COMMON_CHINESE_CHARACTERS = "的一是在不了有和人这中大为上个国我以要他时来用们生到作地于出就分对成会可主发年动同工也能下过子说产种面而方后多定行学法所民得经十三之进着等部度家电力里如水化高自二理起小物现实加量都两体制机当使点从业本去把性好应开它合还因由其些然前外天政四日那社义事平形相全表间样与关各重新线内数正心反你明看原又么利比或但质气第向道命此变条只没结解问意建月公无系军很情者最立代想已通并提直题党程展五果料象员革位入常文总次品式活设及管特件长求老头基资边流路级少图山统接知较将组见计别她手角期根论运农指几九区强放决西被干做必战先回则任取据处队南给色光门即保治北造百规热领七海口东导器压志世金增争济阶油思术极交受联什认六共权收证改清己美再采转更单风切打白教速花带安场身车例真务具万每目至达走积示议声报斗完类八离华名确才科张信马节话米整空元况今集温传土许步群广石记需段研界拉林律叫且究观越织装影算低持音众书布复容儿须际商非验连断深难近矿千周委素技备半办青省列习响约支般史感劳便团往酸历市克何除消构府太准精值号率族维划选标写存候毛亲快效斯院查江型眼王按格养易置派层片始却专状育厂京识适属圆包火住调满县局照参红细引听该铁价严龙飞" - -COMMON_JAPANESE_CHARACTERS = "日一国年大十二本中長出三時行見月分後前生五間上東四今金九入学高円子外八六下来気小七山話女北午百書先名川千水半男西電校語土木聞食車何南万毎白天母火右読友左休父雨" - -COMMON_KOREAN_CHARACTERS = "一二三四五六七八九十百千萬上下左右中人女子大小山川日月火水木金土父母天地國名年時文校學生" - -# Combine all into a frozenset -COMMON_CJK_CHARACTERS = frozenset( - "".join( - [ - COMMON_CHINESE_CHARACTERS, - COMMON_JAPANESE_CHARACTERS, - COMMON_KOREAN_CHARACTERS, - ] - ) -) - -KO_NAMES: frozenset[str] = frozenset({"johab", "cp949", "euc_kr"}) -ZH_NAMES: frozenset[str] = frozenset({"big5", "cp950", "big5hkscs", "hz"}) - -# Logging LEVEL below DEBUG -TRACE: int = 5 - - -# Language label that contain the em dash "—" -# character are to be considered alternative seq to origin -FREQUENCIES: dict[str, list[str]] = { - "English": [ - "e", - "a", - "t", - "i", - "o", - "n", - "s", - "r", - "h", - "l", - "d", - "c", - "u", - "m", - "f", - "p", - "g", - "w", - "y", - "b", - "v", - "k", - "x", - "j", - "z", - "q", - ], - "English—": [ - "e", - "a", - "t", - "i", - "o", - "n", - "s", - "r", - "h", - "l", - "d", - "c", - "m", - "u", - "f", - "p", - "g", - "w", - "b", - "y", - "v", - "k", - "j", - "x", - "z", - "q", - ], - "German": [ - "e", - "n", - "i", - "r", - "s", - "t", - "a", - "d", - "h", - "u", - "l", - "g", - "o", - "c", - "m", - "b", - "f", - "k", - "w", - "z", - "p", - "v", - "ü", - "ä", - "ö", - "j", - ], - "French": [ - "e", - "a", - "s", - "n", - "i", - "t", - "r", - "l", - "u", - "o", - "d", - "c", - "p", - "m", - "é", - "v", - "g", - "f", - "b", - "h", - "q", - "à", - "x", - "è", - "y", - "j", - ], - "Dutch": [ - "e", - "n", - "a", - "i", - "r", - "t", - "o", - "d", - "s", - "l", - "g", - "h", - "v", - "m", - "u", - "k", - "c", - "p", - "b", - "w", - "j", - "z", - "f", - "y", - "x", - "ë", - ], - "Italian": [ - "e", - "i", - "a", - "o", - "n", - "l", - "t", - "r", - "s", - "c", - "d", - "u", - "p", - "m", - "g", - "v", - "f", - "b", - "z", - "h", - "q", - "è", - "à", - "k", - "y", - "ò", - ], - "Polish": [ - "a", - "i", - "o", - "e", - "n", - "r", - "z", - "w", - "s", - "c", - "t", - "k", - "y", - "d", - "p", - "m", - "u", - "l", - "j", - "ł", - "g", - "b", - "h", - "ą", - "ę", - "ó", - ], - "Spanish": [ - "e", - "a", - "o", - "n", - "s", - "r", - "i", - "l", - "d", - "t", - "c", - "u", - "m", - "p", - "b", - "g", - "v", - "f", - "y", - "ó", - "h", - "q", - "í", - "j", - "z", - "á", - ], - "Russian": [ - "о", - "е", - "а", - "и", - "н", - "т", - "с", - "р", - "в", - "л", - "к", - "м", - "д", - "п", - "у", - "г", - "я", - "ы", - "з", - "б", - "й", - "ь", - "ч", - "х", - "ж", - "ц", - ], - # Jap-Kanji - "Japanese": [ - "日", - "一", - "人", - "年", - "大", - "十", - "二", - "本", - "中", - "長", - "出", - "三", - "時", - "行", - "見", - "月", - "分", - "後", - "前", - "生", - "五", - "間", - "上", - "東", - "四", - "今", - "金", - "九", - "入", - "学", - "高", - "円", - "子", - "外", - "八", - "六", - "下", - "来", - "気", - "小", - "七", - "山", - "話", - "女", - "北", - "午", - "百", - "書", - "先", - "名", - "川", - "千", - "水", - "半", - "男", - "西", - "電", - "校", - "語", - "土", - "木", - "聞", - "食", - "車", - "何", - "南", - "万", - "毎", - "白", - "天", - "母", - "火", - "右", - "読", - "友", - "左", - "休", - "父", - "雨", - ], - # Jap-Katakana - "Japanese—": [ - "ー", - "ン", - "ス", - "・", - "ル", - "ト", - "リ", - "イ", - "ア", - "ラ", - "ッ", - "ク", - "ド", - "シ", - "レ", - "ジ", - "タ", - "フ", - "ロ", - "カ", - "テ", - "マ", - "ィ", - "グ", - "バ", - "ム", - "プ", - "オ", - "コ", - "デ", - "ニ", - "ウ", - "メ", - "サ", - "ビ", - "ナ", - "ブ", - "ャ", - "エ", - "ュ", - "チ", - "キ", - "ズ", - "ダ", - "パ", - "ミ", - "ェ", - "ョ", - "ハ", - "セ", - "ベ", - "ガ", - "モ", - "ツ", - "ネ", - "ボ", - "ソ", - "ノ", - "ァ", - "ヴ", - "ワ", - "ポ", - "ペ", - "ピ", - "ケ", - "ゴ", - "ギ", - "ザ", - "ホ", - "ゲ", - "ォ", - "ヤ", - "ヒ", - "ユ", - "ヨ", - "ヘ", - "ゼ", - "ヌ", - "ゥ", - "ゾ", - "ヶ", - "ヂ", - "ヲ", - "ヅ", - "ヵ", - "ヱ", - "ヰ", - "ヮ", - "ヽ", - "゠", - "ヾ", - "ヷ", - "ヿ", - "ヸ", - "ヹ", - "ヺ", - ], - # Jap-Hiragana - "Japanese——": [ - "の", - "に", - "る", - "た", - "と", - "は", - "し", - "い", - "を", - "で", - "て", - "が", - "な", - "れ", - "か", - "ら", - "さ", - "っ", - "り", - "す", - "あ", - "も", - "こ", - "ま", - "う", - "く", - "よ", - "き", - "ん", - "め", - "お", - "け", - "そ", - "つ", - "だ", - "や", - "え", - "ど", - "わ", - "ち", - "み", - "せ", - "じ", - "ば", - "へ", - "び", - "ず", - "ろ", - "ほ", - "げ", - "む", - "べ", - "ひ", - "ょ", - "ゆ", - "ぶ", - "ご", - "ゃ", - "ね", - "ふ", - "ぐ", - "ぎ", - "ぼ", - "ゅ", - "づ", - "ざ", - "ぞ", - "ぬ", - "ぜ", - "ぱ", - "ぽ", - "ぷ", - "ぴ", - "ぃ", - "ぁ", - "ぇ", - "ぺ", - "ゞ", - "ぢ", - "ぉ", - "ぅ", - "ゐ", - "ゝ", - "ゑ", - "゛", - "゜", - "ゎ", - "ゔ", - "゚", - "ゟ", - "゙", - "ゕ", - "ゖ", - ], - "Portuguese": [ - "a", - "e", - "o", - "s", - "i", - "r", - "d", - "n", - "t", - "m", - "u", - "c", - "l", - "p", - "g", - "v", - "b", - "f", - "h", - "ã", - "q", - "é", - "ç", - "á", - "z", - "í", - ], - "Swedish": [ - "e", - "a", - "n", - "r", - "t", - "s", - "i", - "l", - "d", - "o", - "m", - "k", - "g", - "v", - "h", - "f", - "u", - "p", - "ä", - "c", - "b", - "ö", - "å", - "y", - "j", - "x", - ], - "Chinese": [ - "的", - "一", - "是", - "不", - "了", - "在", - "人", - "有", - "我", - "他", - "这", - "个", - "们", - "中", - "来", - "上", - "大", - "为", - "和", - "国", - "地", - "到", - "以", - "说", - "时", - "要", - "就", - "出", - "会", - "可", - "也", - "你", - "对", - "生", - "能", - "而", - "子", - "那", - "得", - "于", - "着", - "下", - "自", - "之", - "年", - "过", - "发", - "后", - "作", - "里", - "用", - "道", - "行", - "所", - "然", - "家", - "种", - "事", - "成", - "方", - "多", - "经", - "么", - "去", - "法", - "学", - "如", - "都", - "同", - "现", - "当", - "没", - "动", - "面", - "起", - "看", - "定", - "天", - "分", - "还", - "进", - "好", - "小", - "部", - "其", - "些", - "主", - "样", - "理", - "心", - "她", - "本", - "前", - "开", - "但", - "因", - "只", - "从", - "想", - "实", - ], - "Ukrainian": [ - "о", - "а", - "н", - "і", - "и", - "р", - "в", - "т", - "е", - "с", - "к", - "л", - "у", - "д", - "м", - "п", - "з", - "я", - "ь", - "б", - "г", - "й", - "ч", - "х", - "ц", - "ї", - ], - "Norwegian": [ - "e", - "r", - "n", - "t", - "a", - "s", - "i", - "o", - "l", - "d", - "g", - "k", - "m", - "v", - "f", - "p", - "u", - "b", - "h", - "å", - "y", - "j", - "ø", - "c", - "æ", - "w", - ], - "Finnish": [ - "a", - "i", - "n", - "t", - "e", - "s", - "l", - "o", - "u", - "k", - "ä", - "m", - "r", - "v", - "j", - "h", - "p", - "y", - "d", - "ö", - "g", - "c", - "b", - "f", - "w", - "z", - ], - "Vietnamese": [ - "n", - "h", - "t", - "i", - "c", - "g", - "a", - "o", - "u", - "m", - "l", - "r", - "à", - "đ", - "s", - "e", - "v", - "p", - "b", - "y", - "ư", - "d", - "á", - "k", - "ộ", - "ế", - ], - "Czech": [ - "o", - "e", - "a", - "n", - "t", - "s", - "i", - "l", - "v", - "r", - "k", - "d", - "u", - "m", - "p", - "í", - "c", - "h", - "z", - "á", - "y", - "j", - "b", - "ě", - "é", - "ř", - ], - "Hungarian": [ - "e", - "a", - "t", - "l", - "s", - "n", - "k", - "r", - "i", - "o", - "z", - "á", - "é", - "g", - "m", - "b", - "y", - "v", - "d", - "h", - "u", - "p", - "j", - "ö", - "f", - "c", - ], - "Korean": [ - "이", - "다", - "에", - "의", - "는", - "로", - "하", - "을", - "가", - "고", - "지", - "서", - "한", - "은", - "기", - "으", - "년", - "대", - "사", - "시", - "를", - "리", - "도", - "인", - "스", - "일", - ], - "Indonesian": [ - "a", - "n", - "e", - "i", - "r", - "t", - "u", - "s", - "d", - "k", - "m", - "l", - "g", - "p", - "b", - "o", - "h", - "y", - "j", - "c", - "w", - "f", - "v", - "z", - "x", - "q", - ], - "Turkish": [ - "a", - "e", - "i", - "n", - "r", - "l", - "ı", - "k", - "d", - "t", - "s", - "m", - "y", - "u", - "o", - "b", - "ü", - "ş", - "v", - "g", - "z", - "h", - "c", - "p", - "ç", - "ğ", - ], - "Romanian": [ - "e", - "i", - "a", - "r", - "n", - "t", - "u", - "l", - "o", - "c", - "s", - "d", - "p", - "m", - "ă", - "f", - "v", - "î", - "g", - "b", - "ș", - "ț", - "z", - "h", - "â", - "j", - ], - "Farsi": [ - "ا", - "ی", - "ر", - "د", - "ن", - "ه", - "و", - "م", - "ت", - "ب", - "س", - "ل", - "ک", - "ش", - "ز", - "ف", - "گ", - "ع", - "خ", - "ق", - "ج", - "آ", - "پ", - "ح", - "ط", - "ص", - ], - "Arabic": [ - "ا", - "ل", - "ي", - "م", - "و", - "ن", - "ر", - "ت", - "ب", - "ة", - "ع", - "د", - "س", - "ف", - "ه", - "ك", - "ق", - "أ", - "ح", - "ج", - "ش", - "ط", - "ص", - "ى", - "خ", - "إ", - ], - "Danish": [ - "e", - "r", - "n", - "t", - "a", - "i", - "s", - "d", - "l", - "o", - "g", - "m", - "k", - "f", - "v", - "u", - "b", - "h", - "p", - "å", - "y", - "ø", - "æ", - "c", - "j", - "w", - ], - "Serbian": [ - "а", - "и", - "о", - "е", - "н", - "р", - "с", - "у", - "т", - "к", - "ј", - "в", - "д", - "м", - "п", - "л", - "г", - "з", - "б", - "a", - "i", - "e", - "o", - "n", - "ц", - "ш", - ], - "Lithuanian": [ - "i", - "a", - "s", - "o", - "r", - "e", - "t", - "n", - "u", - "k", - "m", - "l", - "p", - "v", - "d", - "j", - "g", - "ė", - "b", - "y", - "ų", - "š", - "ž", - "c", - "ą", - "į", - ], - "Slovene": [ - "e", - "a", - "i", - "o", - "n", - "r", - "s", - "l", - "t", - "j", - "v", - "k", - "d", - "p", - "m", - "u", - "z", - "b", - "g", - "h", - "č", - "c", - "š", - "ž", - "f", - "y", - ], - "Slovak": [ - "o", - "a", - "e", - "n", - "i", - "r", - "v", - "t", - "s", - "l", - "k", - "d", - "m", - "p", - "u", - "c", - "h", - "j", - "b", - "z", - "á", - "y", - "ý", - "í", - "č", - "é", - ], - "Hebrew": [ - "י", - "ו", - "ה", - "ל", - "ר", - "ב", - "ת", - "מ", - "א", - "ש", - "נ", - "ע", - "ם", - "ד", - "ק", - "ח", - "פ", - "ס", - "כ", - "ג", - "ט", - "צ", - "ן", - "ז", - "ך", - ], - "Bulgarian": [ - "а", - "и", - "о", - "е", - "н", - "т", - "р", - "с", - "в", - "л", - "к", - "д", - "п", - "м", - "з", - "г", - "я", - "ъ", - "у", - "б", - "ч", - "ц", - "й", - "ж", - "щ", - "х", - ], - "Croatian": [ - "a", - "i", - "o", - "e", - "n", - "r", - "j", - "s", - "t", - "u", - "k", - "l", - "v", - "d", - "m", - "p", - "g", - "z", - "b", - "c", - "č", - "h", - "š", - "ž", - "ć", - "f", - ], - "Hindi": [ - "क", - "र", - "स", - "न", - "त", - "म", - "ह", - "प", - "य", - "ल", - "व", - "ज", - "द", - "ग", - "ब", - "श", - "ट", - "अ", - "ए", - "थ", - "भ", - "ड", - "च", - "ध", - "ष", - "इ", - ], - "Estonian": [ - "a", - "i", - "e", - "s", - "t", - "l", - "u", - "n", - "o", - "k", - "r", - "d", - "m", - "v", - "g", - "p", - "j", - "h", - "ä", - "b", - "õ", - "ü", - "f", - "c", - "ö", - "y", - ], - "Thai": [ - "า", - "น", - "ร", - "อ", - "ก", - "เ", - "ง", - "ม", - "ย", - "ล", - "ว", - "ด", - "ท", - "ส", - "ต", - "ะ", - "ป", - "บ", - "ค", - "ห", - "แ", - "จ", - "พ", - "ช", - "ข", - "ใ", - ], - "Greek": [ - "α", - "τ", - "ο", - "ι", - "ε", - "ν", - "ρ", - "σ", - "κ", - "η", - "π", - "ς", - "υ", - "μ", - "λ", - "ί", - "ό", - "ά", - "γ", - "έ", - "δ", - "ή", - "ω", - "χ", - "θ", - "ύ", - ], - "Tamil": [ - "க", - "த", - "ப", - "ட", - "ர", - "ம", - "ல", - "ன", - "வ", - "ற", - "ய", - "ள", - "ச", - "ந", - "இ", - "ண", - "அ", - "ஆ", - "ழ", - "ங", - "எ", - "உ", - "ஒ", - "ஸ", - ], - "Kazakh": [ - "а", - "ы", - "е", - "н", - "т", - "р", - "л", - "і", - "д", - "с", - "м", - "қ", - "к", - "о", - "б", - "и", - "у", - "ғ", - "ж", - "ң", - "з", - "ш", - "й", - "п", - "г", - "ө", - ], -} - -LANGUAGE_SUPPORTED_COUNT: int = len(FREQUENCIES) - -# Bit flags for unified character classification. -# A single unicodedata.name() call sets all relevant flags at once. -_LATIN: int = 1 -_ACCENTUATED: int = 1 << 1 -_CJK: int = 1 << 2 -_HANGUL: int = 1 << 3 -_KATAKANA: int = 1 << 4 -_HIRAGANA: int = 1 << 5 -_THAI: int = 1 << 6 -_ARABIC: int = 1 << 7 -_ARABIC_ISOLATED_FORM: int = 1 << 8 - -_ACCENT_KEYWORDS: tuple[str, ...] = ( - "WITH GRAVE", - "WITH ACUTE", - "WITH CEDILLA", - "WITH DIAERESIS", - "WITH CIRCUMFLEX", - "WITH TILDE", - "WITH MACRON", - "WITH RING ABOVE", -) - -# Pre-built lookup structures for FREQUENCIES (computed once at import time). -# character -> rank mapping per language (replaces list .index() calls). -_FREQUENCIES_RANK: dict[str, dict[str, int]] = { - lang: {char: rank for rank, char in enumerate(chars)} - for lang, chars in FREQUENCIES.items() -} - -# frozenset per language (avoids rebuilding set() per call). -_FREQUENCIES_SET: dict[str, frozenset[str]] = { - lang: frozenset(chars) for lang, chars in FREQUENCIES.items() -} diff --git a/venv/lib/python3.9/site-packages/charset_normalizer/legacy.py b/venv/lib/python3.9/site-packages/charset_normalizer/legacy.py deleted file mode 100644 index 293c1ef..0000000 --- a/venv/lib/python3.9/site-packages/charset_normalizer/legacy.py +++ /dev/null @@ -1,79 +0,0 @@ -from __future__ import annotations - -from typing import TYPE_CHECKING, Any -from warnings import warn - -from .api import from_bytes -from .constant import CHARDET_CORRESPONDENCE, TOO_SMALL_SEQUENCE - -if TYPE_CHECKING: - from typing import TypedDict - - class ResultDict(TypedDict): - encoding: str | None - language: str - confidence: float | None - - -def detect( - byte_str: bytes, should_rename_legacy: bool = False, **kwargs: Any -) -> ResultDict: - """ - chardet legacy method - Detect the encoding of the given byte string. It should be mostly backward-compatible. - Encoding name will match Chardet own writing whenever possible. (Not on encoding name unsupported by it) - This function is deprecated and should be used to migrate your project easily, consult the documentation for - further information. Not planned for removal. - - :param byte_str: The byte sequence to examine. - :param should_rename_legacy: Should we rename legacy encodings - to their more modern equivalents? - """ - if len(kwargs): - warn( - f"charset-normalizer disregard arguments '{','.join(list(kwargs.keys()))}' in legacy function detect()" - ) - - if not isinstance(byte_str, (bytearray, bytes)): - raise TypeError( # pragma: nocover - f"Expected object of type bytes or bytearray, got: {type(byte_str)}" - ) - - if isinstance(byte_str, bytearray): - byte_str = bytes(byte_str) - - r = from_bytes(byte_str).best() - - encoding = r.encoding if r is not None else None - language = r.language if r is not None and r.language != "Unknown" else "" - confidence = 1.0 - r.chaos if r is not None else None - - # automatically lower confidence - # on small bytes samples. - # https://github.com/jawah/charset_normalizer/issues/391 - if ( - confidence is not None - and confidence >= 0.9 - and encoding - not in { - "utf_8", - "ascii", - } - and r.bom is False # type: ignore[union-attr] - and len(byte_str) < TOO_SMALL_SEQUENCE - ): - confidence -= 0.2 - - # Note: CharsetNormalizer does not return 'UTF-8-SIG' as the sig get stripped in the detection/normalization process - # but chardet does return 'utf-8-sig' and it is a valid codec name. - if r is not None and encoding == "utf_8" and r.bom: - encoding += "_sig" - - if should_rename_legacy is False and encoding in CHARDET_CORRESPONDENCE: - encoding = CHARDET_CORRESPONDENCE[encoding] - - return { - "encoding": encoding, - "language": language, - "confidence": confidence, - } diff --git a/venv/lib/python3.9/site-packages/charset_normalizer/md.cpython-39-x86_64-linux-gnu.so b/venv/lib/python3.9/site-packages/charset_normalizer/md.cpython-39-x86_64-linux-gnu.so deleted file mode 100755 index 5512842..0000000 Binary files a/venv/lib/python3.9/site-packages/charset_normalizer/md.cpython-39-x86_64-linux-gnu.so and /dev/null differ diff --git a/venv/lib/python3.9/site-packages/charset_normalizer/md.py b/venv/lib/python3.9/site-packages/charset_normalizer/md.py deleted file mode 100644 index b41d9cf..0000000 --- a/venv/lib/python3.9/site-packages/charset_normalizer/md.py +++ /dev/null @@ -1,936 +0,0 @@ -from __future__ import annotations - -import sys -from functools import lru_cache -from logging import getLogger - -if sys.version_info >= (3, 8): - from typing import final -else: - try: - from typing_extensions import final - except ImportError: - - def final(cls): # type: ignore[misc,no-untyped-def] - return cls - - -from .constant import ( - COMMON_CJK_CHARACTERS, - COMMON_SAFE_ASCII_CHARACTERS, - TRACE, - UNICODE_SECONDARY_RANGE_KEYWORD, - _ACCENTUATED, - _ARABIC, - _ARABIC_ISOLATED_FORM, - _CJK, - _HANGUL, - _HIRAGANA, - _KATAKANA, - _LATIN, - _THAI, -) -from .utils import ( - _character_flags, - is_emoticon, - is_punctuation, - is_separator, - is_symbol, - remove_accent, - unicode_range, -) - -# Combined bitmask for CJK/Hangul/Katakana/Hiragana/Thai glyph detection. -_GLYPH_MASK: int = _CJK | _HANGUL | _KATAKANA | _HIRAGANA | _THAI - - -@final -class CharInfo: - """Pre-computed character properties shared across all detectors. - - Instantiated once and reused via :meth:`update` on every character - in the hot loop so that redundant calls to str methods - (``isalpha``, ``isupper``, …) and cached utility functions - (``_character_flags``, ``is_punctuation``, …) are avoided when - several plugins need the same information. - """ - - __slots__ = ( - "character", - "printable", - "alpha", - "upper", - "lower", - "space", - "digit", - "is_ascii", - "case_variable", - "flags", - "accentuated", - "latin", - "is_cjk", - "is_arabic", - "is_glyph", - "punct", - "sym", - ) - - def __init__(self) -> None: - self.character: str = "" - self.printable: bool = False - self.alpha: bool = False - self.upper: bool = False - self.lower: bool = False - self.space: bool = False - self.digit: bool = False - self.is_ascii: bool = False - self.case_variable: bool = False - self.flags: int = 0 - self.accentuated: bool = False - self.latin: bool = False - self.is_cjk: bool = False - self.is_arabic: bool = False - self.is_glyph: bool = False - self.punct: bool = False - self.sym: bool = False - - def update(self, character: str) -> None: - """Update all properties for *character* (called once per character).""" - self.character = character - - # ASCII fast-path: for characters with ord < 128, we can skip - # _character_flags() entirely and derive most properties from ord. - o: int = ord(character) - if o < 128: - self.is_ascii = True - self.accentuated = False - self.is_cjk = False - self.is_arabic = False - self.is_glyph = False - # ASCII alpha: a-z (97-122) or A-Z (65-90) - if 65 <= o <= 90: - # Uppercase ASCII letter - self.alpha = True - self.upper = True - self.lower = False - self.space = False - self.digit = False - self.printable = True - self.case_variable = True - self.flags = _LATIN - self.latin = True - self.punct = False - self.sym = False - elif 97 <= o <= 122: - # Lowercase ASCII letter - self.alpha = True - self.upper = False - self.lower = True - self.space = False - self.digit = False - self.printable = True - self.case_variable = True - self.flags = _LATIN - self.latin = True - self.punct = False - self.sym = False - elif 48 <= o <= 57: - # ASCII digit 0-9 - self.alpha = False - self.upper = False - self.lower = False - self.space = False - self.digit = True - self.printable = True - self.case_variable = False - self.flags = 0 - self.latin = False - self.punct = False - self.sym = False - elif o == 32 or (9 <= o <= 13): - # Space, tab, newline, etc. - self.alpha = False - self.upper = False - self.lower = False - self.space = True - self.digit = False - self.printable = o == 32 - self.case_variable = False - self.flags = 0 - self.latin = False - self.punct = False - self.sym = False - else: - # Other ASCII (punctuation, symbols, control chars) - self.printable = character.isprintable() - self.alpha = False - self.upper = False - self.lower = False - self.space = False - self.digit = False - self.case_variable = False - self.flags = 0 - self.latin = False - self.punct = is_punctuation(character) if self.printable else False - self.sym = is_symbol(character) if self.printable else False - else: - # Non-ASCII path - self.is_ascii = False - self.printable = character.isprintable() - self.alpha = character.isalpha() - self.upper = character.isupper() - self.lower = character.islower() - self.space = character.isspace() - self.digit = character.isdigit() - self.case_variable = self.lower != self.upper - - # Flag-based classification (single unicodedata.name() call, lru-cached) - flags: int - if self.alpha: - flags = _character_flags(character) - else: - flags = 0 - self.flags = flags - self.accentuated = bool(flags & _ACCENTUATED) - self.latin = bool(flags & _LATIN) - self.is_cjk = bool(flags & _CJK) - self.is_arabic = bool(flags & _ARABIC) - self.is_glyph = bool(flags & _GLYPH_MASK) - - # Eagerly compute punct and sym (avoids property dispatch overhead - # on 300K+ accesses in the hot loop). - self.punct = is_punctuation(character) if self.printable else False - self.sym = is_symbol(character) if self.printable else False - - -class MessDetectorPlugin: - """ - Base abstract class used for mess detection plugins. - All detectors MUST extend and implement given methods. - """ - - __slots__ = () - - def feed_info(self, character: str, info: CharInfo) -> None: - """ - The main routine to be executed upon character. - Insert the logic in witch the text would be considered chaotic. - """ - raise NotImplementedError # Defensive: - - def reset(self) -> None: # Defensive: - """ - Permit to reset the plugin to the initial state. - """ - raise NotImplementedError - - @property - def ratio(self) -> float: - """ - Compute the chaos ratio based on what your feed() has seen. - Must NOT be lower than 0.; No restriction gt 0. - """ - raise NotImplementedError # Defensive: - - -@final -class TooManySymbolOrPunctuationPlugin(MessDetectorPlugin): - __slots__ = ( - "_punctuation_count", - "_symbol_count", - "_character_count", - "_last_printable_char", - "_frenzy_symbol_in_word", - ) - - def __init__(self) -> None: - self._punctuation_count: int = 0 - self._symbol_count: int = 0 - self._character_count: int = 0 - - self._last_printable_char: str | None = None - self._frenzy_symbol_in_word: bool = False - - def feed_info(self, character: str, info: CharInfo) -> None: - """Optimized feed using pre-computed character info.""" - self._character_count += 1 - - if ( - character != self._last_printable_char - and character not in COMMON_SAFE_ASCII_CHARACTERS - ): - if info.punct: - self._punctuation_count += 1 - elif not info.digit and info.sym and not is_emoticon(character): - self._symbol_count += 2 - - self._last_printable_char = character - - def reset(self) -> None: # Abstract - self._punctuation_count = 0 - self._character_count = 0 - self._symbol_count = 0 - - @property - def ratio(self) -> float: - if self._character_count == 0: - return 0.0 - - ratio_of_punctuation: float = ( - self._punctuation_count + self._symbol_count - ) / self._character_count - - return ratio_of_punctuation if ratio_of_punctuation >= 0.3 else 0.0 - - -@final -class TooManyAccentuatedPlugin(MessDetectorPlugin): - __slots__ = ("_character_count", "_accentuated_count") - - def __init__(self) -> None: - self._character_count: int = 0 - self._accentuated_count: int = 0 - - def feed_info(self, character: str, info: CharInfo) -> None: - """Optimized feed using pre-computed character info.""" - self._character_count += 1 - - if info.accentuated: - self._accentuated_count += 1 - - def reset(self) -> None: # Abstract - self._character_count = 0 - self._accentuated_count = 0 - - @property - def ratio(self) -> float: - if self._character_count < 8: - return 0.0 - - ratio_of_accentuation: float = self._accentuated_count / self._character_count - return ratio_of_accentuation if ratio_of_accentuation >= 0.35 else 0.0 - - -@final -class UnprintablePlugin(MessDetectorPlugin): - __slots__ = ("_unprintable_count", "_character_count") - - def __init__(self) -> None: - self._unprintable_count: int = 0 - self._character_count: int = 0 - - def feed_info(self, character: str, info: CharInfo) -> None: - """Optimized feed using pre-computed character info.""" - if ( - not info.space - and not info.printable - and character != "\x1a" - and character != "\ufeff" - ): - self._unprintable_count += 1 - self._character_count += 1 - - def reset(self) -> None: # Abstract - self._unprintable_count = 0 - - @property - def ratio(self) -> float: - if self._character_count == 0: # Defensive: - return 0.0 - - return (self._unprintable_count * 8) / self._character_count - - -@final -class SuspiciousDuplicateAccentPlugin(MessDetectorPlugin): - __slots__ = ( - "_successive_count", - "_character_count", - "_last_latin_character", - "_last_was_accentuated", - ) - - def __init__(self) -> None: - self._successive_count: int = 0 - self._character_count: int = 0 - - self._last_latin_character: str | None = None - self._last_was_accentuated: bool = False - - def feed_info(self, character: str, info: CharInfo) -> None: - """Optimized feed using pre-computed character info.""" - self._character_count += 1 - if ( - self._last_latin_character is not None - and info.accentuated - and self._last_was_accentuated - ): - if info.upper and self._last_latin_character.isupper(): - self._successive_count += 1 - if remove_accent(character) == remove_accent(self._last_latin_character): - self._successive_count += 1 - self._last_latin_character = character - self._last_was_accentuated = info.accentuated - - def reset(self) -> None: # Abstract - self._successive_count = 0 - self._character_count = 0 - self._last_latin_character = None - self._last_was_accentuated = False - - @property - def ratio(self) -> float: - if self._character_count == 0: - return 0.0 - - return (self._successive_count * 2) / self._character_count - - -@final -class SuspiciousRange(MessDetectorPlugin): - __slots__ = ( - "_suspicious_successive_range_count", - "_character_count", - "_last_printable_seen", - "_last_printable_range", - ) - - def __init__(self) -> None: - self._suspicious_successive_range_count: int = 0 - self._character_count: int = 0 - self._last_printable_seen: str | None = None - self._last_printable_range: str | None = None - - def feed_info(self, character: str, info: CharInfo) -> None: - """Optimized feed using pre-computed character info.""" - self._character_count += 1 - - if info.space or info.punct or character in COMMON_SAFE_ASCII_CHARACTERS: - self._last_printable_seen = None - self._last_printable_range = None - return - - if self._last_printable_seen is None: - self._last_printable_seen = character - self._last_printable_range = unicode_range(character) - return - - unicode_range_a: str | None = self._last_printable_range - unicode_range_b: str | None = unicode_range(character) - - if is_suspiciously_successive_range(unicode_range_a, unicode_range_b): - self._suspicious_successive_range_count += 1 - - self._last_printable_seen = character - self._last_printable_range = unicode_range_b - - def reset(self) -> None: # Abstract - self._character_count = 0 - self._suspicious_successive_range_count = 0 - self._last_printable_seen = None - self._last_printable_range = None - - @property - def ratio(self) -> float: - if self._character_count <= 13: - return 0.0 - - ratio_of_suspicious_range_usage: float = ( - self._suspicious_successive_range_count * 2 - ) / self._character_count - - return ratio_of_suspicious_range_usage - - -@final -class SuperWeirdWordPlugin(MessDetectorPlugin): - __slots__ = ( - "_word_count", - "_bad_word_count", - "_foreign_long_count", - "_is_current_word_bad", - "_foreign_long_watch", - "_character_count", - "_bad_character_count", - "_buffer_length", - "_buffer_last_char", - "_buffer_last_char_accentuated", - "_buffer_accent_count", - "_buffer_glyph_count", - "_buffer_upper_count", - ) - - def __init__(self) -> None: - self._word_count: int = 0 - self._bad_word_count: int = 0 - self._foreign_long_count: int = 0 - - self._is_current_word_bad: bool = False - self._foreign_long_watch: bool = False - - self._character_count: int = 0 - self._bad_character_count: int = 0 - - self._buffer_length: int = 0 - self._buffer_last_char: str | None = None - self._buffer_last_char_accentuated: bool = False - self._buffer_accent_count: int = 0 - self._buffer_glyph_count: int = 0 - self._buffer_upper_count: int = 0 - - def feed_info(self, character: str, info: CharInfo) -> None: - """Optimized feed using pre-computed character info.""" - if info.alpha: - self._buffer_length += 1 - self._buffer_last_char = character - - if info.upper: - self._buffer_upper_count += 1 - - self._buffer_last_char_accentuated = info.accentuated - - if info.accentuated: - self._buffer_accent_count += 1 - if ( - not self._foreign_long_watch - and (not info.latin or info.accentuated) - and not info.is_glyph - ): - self._foreign_long_watch = True - if info.is_glyph: - self._buffer_glyph_count += 1 - return - if not self._buffer_length: - return - if info.space or info.punct or is_separator(character): - self._word_count += 1 - buffer_length: int = self._buffer_length - - self._character_count += buffer_length - - if buffer_length >= 4: - if self._buffer_accent_count / buffer_length >= 0.5: - self._is_current_word_bad = True - elif ( - self._buffer_last_char_accentuated - and self._buffer_last_char.isupper() # type: ignore[union-attr] - and self._buffer_upper_count != buffer_length - ): - self._foreign_long_count += 1 - self._is_current_word_bad = True - elif self._buffer_glyph_count == 1: - self._is_current_word_bad = True - self._foreign_long_count += 1 - if buffer_length >= 24 and self._foreign_long_watch: - probable_camel_cased: bool = ( - self._buffer_upper_count > 0 - and self._buffer_upper_count / buffer_length <= 0.3 - ) - - if not probable_camel_cased: - self._foreign_long_count += 1 - self._is_current_word_bad = True - - if self._is_current_word_bad: - self._bad_word_count += 1 - self._bad_character_count += buffer_length - self._is_current_word_bad = False - - self._foreign_long_watch = False - self._buffer_length = 0 - self._buffer_last_char = None - self._buffer_last_char_accentuated = False - self._buffer_accent_count = 0 - self._buffer_glyph_count = 0 - self._buffer_upper_count = 0 - elif ( - character not in {"<", ">", "-", "=", "~", "|", "_"} - and not info.digit - and info.sym - ): - self._is_current_word_bad = True - self._buffer_length += 1 - self._buffer_last_char = character - self._buffer_last_char_accentuated = False - - def reset(self) -> None: # Abstract - self._buffer_length = 0 - self._buffer_last_char = None - self._buffer_last_char_accentuated = False - self._is_current_word_bad = False - self._foreign_long_watch = False - self._bad_word_count = 0 - self._word_count = 0 - self._character_count = 0 - self._bad_character_count = 0 - self._foreign_long_count = 0 - self._buffer_accent_count = 0 - self._buffer_glyph_count = 0 - self._buffer_upper_count = 0 - - @property - def ratio(self) -> float: - if self._word_count <= 10 and self._foreign_long_count == 0: - return 0.0 - - return self._bad_character_count / self._character_count - - -@final -class CjkUncommonPlugin(MessDetectorPlugin): - """ - Detect messy CJK text that probably means nothing. - """ - - __slots__ = ("_character_count", "_uncommon_count") - - def __init__(self) -> None: - self._character_count: int = 0 - self._uncommon_count: int = 0 - - def feed_info(self, character: str, info: CharInfo) -> None: - """Optimized feed using pre-computed character info.""" - self._character_count += 1 - - if character not in COMMON_CJK_CHARACTERS: - self._uncommon_count += 1 - - def reset(self) -> None: # Abstract - self._character_count = 0 - self._uncommon_count = 0 - - @property - def ratio(self) -> float: - if self._character_count < 8: - return 0.0 - - uncommon_form_usage: float = self._uncommon_count / self._character_count - - # we can be pretty sure it's garbage when uncommon characters are widely - # used. otherwise it could just be traditional chinese for example. - return uncommon_form_usage / 10 if uncommon_form_usage > 0.5 else 0.0 - - -@final -class ArchaicUpperLowerPlugin(MessDetectorPlugin): - __slots__ = ( - "_buf", - "_character_count_since_last_sep", - "_successive_upper_lower_count", - "_successive_upper_lower_count_final", - "_character_count", - "_last_alpha_seen", - "_last_alpha_seen_upper", - "_last_alpha_seen_lower", - "_current_ascii_only", - ) - - def __init__(self) -> None: - self._buf: bool = False - - self._character_count_since_last_sep: int = 0 - - self._successive_upper_lower_count: int = 0 - self._successive_upper_lower_count_final: int = 0 - - self._character_count: int = 0 - - self._last_alpha_seen: str | None = None - self._last_alpha_seen_upper: bool = False - self._last_alpha_seen_lower: bool = False - self._current_ascii_only: bool = True - - def feed_info(self, character: str, info: CharInfo) -> None: - """Optimized feed using pre-computed character info.""" - is_concerned: bool = info.alpha and info.case_variable - chunk_sep: bool = not is_concerned - - if chunk_sep and self._character_count_since_last_sep > 0: - if ( - self._character_count_since_last_sep <= 64 - and not info.digit - and not self._current_ascii_only - ): - self._successive_upper_lower_count_final += ( - self._successive_upper_lower_count - ) - - self._successive_upper_lower_count = 0 - self._character_count_since_last_sep = 0 - self._last_alpha_seen = None - self._buf = False - self._character_count += 1 - self._current_ascii_only = True - - return - - if self._current_ascii_only and not info.is_ascii: - self._current_ascii_only = False - - if self._last_alpha_seen is not None: - if (info.upper and self._last_alpha_seen_lower) or ( - info.lower and self._last_alpha_seen_upper - ): - if self._buf: - self._successive_upper_lower_count += 2 - self._buf = False - else: - self._buf = True - else: - self._buf = False - - self._character_count += 1 - self._character_count_since_last_sep += 1 - self._last_alpha_seen = character - self._last_alpha_seen_upper = info.upper - self._last_alpha_seen_lower = info.lower - - def reset(self) -> None: # Abstract - self._character_count = 0 - self._character_count_since_last_sep = 0 - self._successive_upper_lower_count = 0 - self._successive_upper_lower_count_final = 0 - self._last_alpha_seen = None - self._last_alpha_seen_upper = False - self._last_alpha_seen_lower = False - self._buf = False - self._current_ascii_only = True - - @property - def ratio(self) -> float: - if self._character_count == 0: # Defensive: - return 0.0 - - return self._successive_upper_lower_count_final / self._character_count - - -@final -class ArabicIsolatedFormPlugin(MessDetectorPlugin): - __slots__ = ("_character_count", "_isolated_form_count") - - def __init__(self) -> None: - self._character_count: int = 0 - self._isolated_form_count: int = 0 - - def reset(self) -> None: # Abstract - self._character_count = 0 - self._isolated_form_count = 0 - - def feed_info(self, character: str, info: CharInfo) -> None: - """Optimized feed using pre-computed character info.""" - self._character_count += 1 - - if info.flags & _ARABIC_ISOLATED_FORM: - self._isolated_form_count += 1 - - @property - def ratio(self) -> float: - if self._character_count < 8: - return 0.0 - - isolated_form_usage: float = self._isolated_form_count / self._character_count - - return isolated_form_usage - - -@lru_cache(maxsize=1024) -def is_suspiciously_successive_range( - unicode_range_a: str | None, unicode_range_b: str | None -) -> bool: - """ - Determine if two Unicode range seen next to each other can be considered as suspicious. - """ - if unicode_range_a is None or unicode_range_b is None: - return True - - if unicode_range_a == unicode_range_b: - return False - - if "Latin" in unicode_range_a and "Latin" in unicode_range_b: - return False - - if "Emoticons" in unicode_range_a or "Emoticons" in unicode_range_b: - return False - - # Latin characters can be accompanied with a combining diacritical mark - # eg. Vietnamese. - if ("Latin" in unicode_range_a or "Latin" in unicode_range_b) and ( - "Combining" in unicode_range_a or "Combining" in unicode_range_b - ): - return False - - keywords_range_a, keywords_range_b = ( - unicode_range_a.split(" "), - unicode_range_b.split(" "), - ) - - for el in keywords_range_a: - if el in UNICODE_SECONDARY_RANGE_KEYWORD: - continue - if el in keywords_range_b: - return False - - # Japanese Exception - range_a_jp_chars, range_b_jp_chars = ( - unicode_range_a - in ( - "Hiragana", - "Katakana", - ), - unicode_range_b in ("Hiragana", "Katakana"), - ) - if (range_a_jp_chars or range_b_jp_chars) and ( - "CJK" in unicode_range_a or "CJK" in unicode_range_b - ): - return False - if range_a_jp_chars and range_b_jp_chars: - return False - - if "Hangul" in unicode_range_a or "Hangul" in unicode_range_b: - if "CJK" in unicode_range_a or "CJK" in unicode_range_b: - return False - if unicode_range_a == "Basic Latin" or unicode_range_b == "Basic Latin": - return False - - # Chinese/Japanese use dedicated range for punctuation and/or separators. - if ("CJK" in unicode_range_a or "CJK" in unicode_range_b) or ( - unicode_range_a in ["Katakana", "Hiragana"] - and unicode_range_b in ["Katakana", "Hiragana"] - ): - if "Punctuation" in unicode_range_a or "Punctuation" in unicode_range_b: - return False - if "Forms" in unicode_range_a or "Forms" in unicode_range_b: - return False - if unicode_range_a == "Basic Latin" or unicode_range_b == "Basic Latin": - return False - - return True - - -@lru_cache(maxsize=2048) -def mess_ratio( - decoded_sequence: str, maximum_threshold: float = 0.2, debug: bool = False -) -> float: - """ - Compute a mess ratio given a decoded bytes sequence. The maximum threshold does stop the computation earlier. - """ - - seq_len: int = len(decoded_sequence) - - if seq_len < 511: - step: int = 32 - elif seq_len < 1024: - step = 64 - else: - step = 128 - - # Create each detector as a named local variable (unrolled from the generic loop). - # This eliminates per-character iteration over the detector list and - # per-character eligible() virtual dispatch, while keeping every plugin class - # intact and fully readable. - d_sp: TooManySymbolOrPunctuationPlugin = TooManySymbolOrPunctuationPlugin() - d_ta: TooManyAccentuatedPlugin = TooManyAccentuatedPlugin() - d_up: UnprintablePlugin = UnprintablePlugin() - d_sda: SuspiciousDuplicateAccentPlugin = SuspiciousDuplicateAccentPlugin() - d_sr: SuspiciousRange = SuspiciousRange() - d_sw: SuperWeirdWordPlugin = SuperWeirdWordPlugin() - d_cu: CjkUncommonPlugin = CjkUncommonPlugin() - d_au: ArchaicUpperLowerPlugin = ArchaicUpperLowerPlugin() - d_ai: ArabicIsolatedFormPlugin = ArabicIsolatedFormPlugin() - - # Local references for feed_info methods called in the hot loop. - d_sp_feed = d_sp.feed_info - d_ta_feed = d_ta.feed_info - d_up_feed = d_up.feed_info - d_sda_feed = d_sda.feed_info - d_sr_feed = d_sr.feed_info - d_sw_feed = d_sw.feed_info - d_cu_feed = d_cu.feed_info - d_au_feed = d_au.feed_info - d_ai_feed = d_ai.feed_info - - # Single reusable CharInfo object (avoids per-character allocation). - info: CharInfo = CharInfo() - info_update = info.update - - mean_mess_ratio: float - - for block_start in range(0, seq_len, step): - for character in decoded_sequence[block_start : block_start + step]: - # Pre-compute all character properties once (shared across all plugins). - info_update(character) - - # Detectors with eligible() == always True - d_up_feed(character, info) - d_sw_feed(character, info) - d_au_feed(character, info) - - # Detectors with eligible() == isprintable - if info.printable: - d_sp_feed(character, info) - d_sr_feed(character, info) - - # Detectors with eligible() == isalpha - if info.alpha: - d_ta_feed(character, info) - # SuspiciousDuplicateAccent: isalpha() and is_latin() - if info.latin: - d_sda_feed(character, info) - # CjkUncommon: is_cjk() - if info.is_cjk: - d_cu_feed(character, info) - # ArabicIsolatedForm: is_arabic() - if info.is_arabic: - d_ai_feed(character, info) - - mean_mess_ratio = ( - d_sp.ratio - + d_ta.ratio - + d_up.ratio - + d_sda.ratio - + d_sr.ratio - + d_sw.ratio - + d_cu.ratio - + d_au.ratio - + d_ai.ratio - ) - - if mean_mess_ratio >= maximum_threshold: - break - else: - # Flush last word buffer in SuperWeirdWordPlugin via trailing newline. - info_update("\n") - d_sw_feed("\n", info) - d_au_feed("\n", info) - d_up_feed("\n", info) - - mean_mess_ratio = ( - d_sp.ratio - + d_ta.ratio - + d_up.ratio - + d_sda.ratio - + d_sr.ratio - + d_sw.ratio - + d_cu.ratio - + d_au.ratio - + d_ai.ratio - ) - - if debug: # Defensive: - logger = getLogger("charset_normalizer") - - logger.log( - TRACE, - "Mess-detector extended-analysis start. " - f"intermediary_mean_mess_ratio_calc={step} mean_mess_ratio={mean_mess_ratio} " - f"maximum_threshold={maximum_threshold}", - ) - - if seq_len > 16: - logger.log(TRACE, f"Starting with: {decoded_sequence[:16]}") - logger.log(TRACE, f"Ending with: {decoded_sequence[-16::]}") - - for dt in [d_sp, d_ta, d_up, d_sda, d_sr, d_sw, d_cu, d_au, d_ai]: - logger.log(TRACE, f"{dt.__class__}: {dt.ratio}") - - return round(mean_mess_ratio, 3) diff --git a/venv/lib/python3.9/site-packages/charset_normalizer/models.py b/venv/lib/python3.9/site-packages/charset_normalizer/models.py deleted file mode 100644 index 382de15..0000000 --- a/venv/lib/python3.9/site-packages/charset_normalizer/models.py +++ /dev/null @@ -1,369 +0,0 @@ -from __future__ import annotations - -from encodings.aliases import aliases -from json import dumps -from re import sub -from typing import Any, Iterator, List, Tuple - -from .constant import RE_POSSIBLE_ENCODING_INDICATION, TOO_BIG_SEQUENCE -from .utils import iana_name, is_multi_byte_encoding, unicode_range - - -class CharsetMatch: - def __init__( - self, - payload: bytes | bytearray, - guessed_encoding: str, - mean_mess_ratio: float, - has_sig_or_bom: bool, - languages: CoherenceMatches, - decoded_payload: str | None = None, - preemptive_declaration: str | None = None, - ): - self._payload: bytes | bytearray = payload - - self._encoding: str = guessed_encoding - self._mean_mess_ratio: float = mean_mess_ratio - self._languages: CoherenceMatches = languages - self._has_sig_or_bom: bool = has_sig_or_bom - self._unicode_ranges: list[str] | None = None - - self._leaves: list[CharsetMatch] = [] - self._mean_coherence_ratio: float = 0.0 - - self._output_payload: bytes | None = None - self._output_encoding: str | None = None - - self._string: str | None = decoded_payload - - self._preemptive_declaration: str | None = preemptive_declaration - - def __eq__(self, other: object) -> bool: - if not isinstance(other, CharsetMatch): - if isinstance(other, str): - return iana_name(other) == self.encoding - return False - return self.encoding == other.encoding and self.fingerprint == other.fingerprint - - def __lt__(self, other: object) -> bool: - """ - Implemented to make sorted available upon CharsetMatches items. - """ - if not isinstance(other, CharsetMatch): - raise ValueError - - chaos_difference: float = abs(self.chaos - other.chaos) - coherence_difference: float = abs(self.coherence - other.coherence) - - # Below 0.5% difference --> Use Coherence - if chaos_difference < 0.005 and coherence_difference > 0.02: - return self.coherence > other.coherence - elif chaos_difference < 0.005 and coherence_difference <= 0.02: - # When having a difficult decision, use the result that decoded as many multi-byte as possible. - # preserve RAM usage! - if len(self._payload) >= TOO_BIG_SEQUENCE: - return self.chaos < other.chaos - return self.multi_byte_usage > other.multi_byte_usage - - return self.chaos < other.chaos - - @property - def multi_byte_usage(self) -> float: - return 1.0 - (len(str(self)) / len(self.raw)) - - def __str__(self) -> str: - # Lazy Str Loading - if self._string is None: - self._string = str(self._payload, self._encoding, "strict") - # UTF-7 BOM is encoded in modified Base64 whose byte boundary - # can overlap with the next character, so raw-byte stripping - # is unreliable. Strip the decoded BOM character instead. - if ( - self._has_sig_or_bom - and self._encoding == "utf_7" - and self._string - and self._string[0] == "\ufeff" - ): - self._string = self._string[1:] - return self._string - - def __repr__(self) -> str: - return f"" - - def add_submatch(self, other: CharsetMatch) -> None: - if not isinstance(other, CharsetMatch) or other == self: - raise ValueError( - "Unable to add instance <{}> as a submatch of a CharsetMatch".format( - other.__class__ - ) - ) - - other._string = None # Unload RAM usage; dirty trick. - self._leaves.append(other) - - @property - def encoding(self) -> str: - return self._encoding - - @property - def encoding_aliases(self) -> list[str]: - """ - Encoding name are known by many name, using this could help when searching for IBM855 when it's listed as CP855. - """ - also_known_as: list[str] = [] - for u, p in aliases.items(): - if self.encoding == u: - also_known_as.append(p) - elif self.encoding == p: - also_known_as.append(u) - return also_known_as - - @property - def bom(self) -> bool: - return self._has_sig_or_bom - - @property - def byte_order_mark(self) -> bool: - return self._has_sig_or_bom - - @property - def languages(self) -> list[str]: - """ - Return the complete list of possible languages found in decoded sequence. - Usually not really useful. Returned list may be empty even if 'language' property return something != 'Unknown'. - """ - return [e[0] for e in self._languages] - - @property - def language(self) -> str: - """ - Most probable language found in decoded sequence. If none were detected or inferred, the property will return - "Unknown". - """ - if not self._languages: - # Trying to infer the language based on the given encoding - # Its either English or we should not pronounce ourselves in certain cases. - if "ascii" in self.could_be_from_charset: - return "English" - - # doing it there to avoid circular import - from charset_normalizer.cd import encoding_languages, mb_encoding_languages - - languages = ( - mb_encoding_languages(self.encoding) - if is_multi_byte_encoding(self.encoding) - else encoding_languages(self.encoding) - ) - - if len(languages) == 0 or "Latin Based" in languages: - return "Unknown" - - return languages[0] - - return self._languages[0][0] - - @property - def chaos(self) -> float: - return self._mean_mess_ratio - - @property - def coherence(self) -> float: - if not self._languages: - return 0.0 - return self._languages[0][1] - - @property - def percent_chaos(self) -> float: - return round(self.chaos * 100, ndigits=3) - - @property - def percent_coherence(self) -> float: - return round(self.coherence * 100, ndigits=3) - - @property - def raw(self) -> bytes | bytearray: - """ - Original untouched bytes. - """ - return self._payload - - @property - def submatch(self) -> list[CharsetMatch]: - return self._leaves - - @property - def has_submatch(self) -> bool: - return len(self._leaves) > 0 - - @property - def alphabets(self) -> list[str]: - if self._unicode_ranges is not None: - return self._unicode_ranges - # list detected ranges - detected_ranges: list[str | None] = [unicode_range(char) for char in str(self)] - # filter and sort - self._unicode_ranges = sorted(list({r for r in detected_ranges if r})) - return self._unicode_ranges - - @property - def could_be_from_charset(self) -> list[str]: - """ - The complete list of encoding that output the exact SAME str result and therefore could be the originating - encoding. - This list does include the encoding available in property 'encoding'. - """ - return [self._encoding] + [m.encoding for m in self._leaves] - - def output(self, encoding: str = "utf_8") -> bytes: - """ - Method to get re-encoded bytes payload using given target encoding. Default to UTF-8. - Any errors will be simply ignored by the encoder NOT replaced. - """ - if self._output_encoding is None or self._output_encoding != encoding: - self._output_encoding = encoding - decoded_string = str(self) - if ( - self._preemptive_declaration is not None - and self._preemptive_declaration.lower() - not in ["utf-8", "utf8", "utf_8"] - ): - patched_header = sub( - RE_POSSIBLE_ENCODING_INDICATION, - lambda m: m.string[m.span()[0] : m.span()[1]].replace( - m.groups()[0], - iana_name(self._output_encoding).replace("_", "-"), # type: ignore[arg-type] - ), - decoded_string[:8192], - count=1, - ) - - decoded_string = patched_header + decoded_string[8192:] - - self._output_payload = decoded_string.encode(encoding, "replace") - - return self._output_payload # type: ignore - - @property - def fingerprint(self) -> int: - """ - Retrieve a hash fingerprint of the decoded payload, used for deduplication. - """ - return hash(str(self)) - - -class CharsetMatches: - """ - Container with every CharsetMatch items ordered by default from most probable to the less one. - Act like a list(iterable) but does not implements all related methods. - """ - - def __init__(self, results: list[CharsetMatch] | None = None): - self._results: list[CharsetMatch] = sorted(results) if results else [] - - def __iter__(self) -> Iterator[CharsetMatch]: - yield from self._results - - def __getitem__(self, item: int | str) -> CharsetMatch: - """ - Retrieve a single item either by its position or encoding name (alias may be used here). - Raise KeyError upon invalid index or encoding not present in results. - """ - if isinstance(item, int): - return self._results[item] - if isinstance(item, str): - item = iana_name(item, False) - for result in self._results: - if item in result.could_be_from_charset: - return result - raise KeyError - - def __len__(self) -> int: - return len(self._results) - - def __bool__(self) -> bool: - return len(self._results) > 0 - - def append(self, item: CharsetMatch) -> None: - """ - Insert a single match. Will be inserted accordingly to preserve sort. - Can be inserted as a submatch. - """ - if not isinstance(item, CharsetMatch): - raise ValueError( - "Cannot append instance '{}' to CharsetMatches".format( - str(item.__class__) - ) - ) - # We should disable the submatch factoring when the input file is too heavy (conserve RAM usage) - if len(item.raw) < TOO_BIG_SEQUENCE: - for match in self._results: - if match.fingerprint == item.fingerprint and match.chaos == item.chaos: - match.add_submatch(item) - return - self._results.append(item) - self._results = sorted(self._results) - - def best(self) -> CharsetMatch | None: - """ - Simply return the first match. Strict equivalent to matches[0]. - """ - if not self._results: - return None - return self._results[0] - - def first(self) -> CharsetMatch | None: - """ - Redundant method, call the method best(). Kept for BC reasons. - """ - return self.best() - - -CoherenceMatch = Tuple[str, float] -CoherenceMatches = List[CoherenceMatch] - - -class CliDetectionResult: - def __init__( - self, - path: str, - encoding: str | None, - encoding_aliases: list[str], - alternative_encodings: list[str], - language: str, - alphabets: list[str], - has_sig_or_bom: bool, - chaos: float, - coherence: float, - unicode_path: str | None, - is_preferred: bool, - ): - self.path: str = path - self.unicode_path: str | None = unicode_path - self.encoding: str | None = encoding - self.encoding_aliases: list[str] = encoding_aliases - self.alternative_encodings: list[str] = alternative_encodings - self.language: str = language - self.alphabets: list[str] = alphabets - self.has_sig_or_bom: bool = has_sig_or_bom - self.chaos: float = chaos - self.coherence: float = coherence - self.is_preferred: bool = is_preferred - - @property - def __dict__(self) -> dict[str, Any]: # type: ignore - return { - "path": self.path, - "encoding": self.encoding, - "encoding_aliases": self.encoding_aliases, - "alternative_encodings": self.alternative_encodings, - "language": self.language, - "alphabets": self.alphabets, - "has_sig_or_bom": self.has_sig_or_bom, - "chaos": self.chaos, - "coherence": self.coherence, - "unicode_path": self.unicode_path, - "is_preferred": self.is_preferred, - } - - def to_json(self) -> str: - return dumps(self.__dict__, ensure_ascii=True, indent=4) diff --git a/venv/lib/python3.9/site-packages/charset_normalizer/py.typed b/venv/lib/python3.9/site-packages/charset_normalizer/py.typed deleted file mode 100644 index e69de29..0000000 diff --git a/venv/lib/python3.9/site-packages/charset_normalizer/utils.py b/venv/lib/python3.9/site-packages/charset_normalizer/utils.py deleted file mode 100644 index 0f529b5..0000000 --- a/venv/lib/python3.9/site-packages/charset_normalizer/utils.py +++ /dev/null @@ -1,422 +0,0 @@ -from __future__ import annotations - -import importlib -import logging -import unicodedata -from bisect import bisect_right -from codecs import IncrementalDecoder -from encodings.aliases import aliases -from functools import lru_cache -from re import findall -from typing import Generator - -from _multibytecodec import ( # type: ignore[import-not-found,import] - MultibyteIncrementalDecoder, -) - -from .constant import ( - ENCODING_MARKS, - IANA_SUPPORTED_SIMILAR, - RE_POSSIBLE_ENCODING_INDICATION, - UNICODE_RANGES_COMBINED, - UNICODE_SECONDARY_RANGE_KEYWORD, - UTF8_MAXIMAL_ALLOCATION, - COMMON_CJK_CHARACTERS, - _LATIN, - _CJK, - _HANGUL, - _KATAKANA, - _HIRAGANA, - _THAI, - _ARABIC, - _ARABIC_ISOLATED_FORM, - _ACCENT_KEYWORDS, - _ACCENTUATED, -) - - -@lru_cache(maxsize=UTF8_MAXIMAL_ALLOCATION) -def _character_flags(character: str) -> int: - """Compute all name-based classification flags with a single unicodedata.name() call.""" - try: - desc: str = unicodedata.name(character) - except ValueError: - return 0 - - flags: int = 0 - - if "LATIN" in desc: - flags |= _LATIN - if "CJK" in desc: - flags |= _CJK - if "HANGUL" in desc: - flags |= _HANGUL - if "KATAKANA" in desc: - flags |= _KATAKANA - if "HIRAGANA" in desc: - flags |= _HIRAGANA - if "THAI" in desc: - flags |= _THAI - if "ARABIC" in desc: - flags |= _ARABIC - if "ISOLATED FORM" in desc: - flags |= _ARABIC_ISOLATED_FORM - - for kw in _ACCENT_KEYWORDS: - if kw in desc: - flags |= _ACCENTUATED - break - - return flags - - -@lru_cache(maxsize=UTF8_MAXIMAL_ALLOCATION) -def is_accentuated(character: str) -> bool: - return bool(_character_flags(character) & _ACCENTUATED) - - -@lru_cache(maxsize=UTF8_MAXIMAL_ALLOCATION) -def remove_accent(character: str) -> str: - decomposed: str = unicodedata.decomposition(character) - if not decomposed: - return character - - codes: list[str] = decomposed.split(" ") - - return chr(int(codes[0], 16)) - - -# Pre-built sorted lookup table for O(log n) binary search in unicode_range(). -# Each entry is (range_start, range_end_exclusive, range_name). -_UNICODE_RANGES_SORTED: list[tuple[int, int, str]] = sorted( - (ord_range.start, ord_range.stop, name) - for name, ord_range in UNICODE_RANGES_COMBINED.items() -) -_UNICODE_RANGE_STARTS: list[int] = [e[0] for e in _UNICODE_RANGES_SORTED] - - -@lru_cache(maxsize=UTF8_MAXIMAL_ALLOCATION) -def unicode_range(character: str) -> str | None: - """ - Retrieve the Unicode range official name from a single character. - """ - character_ord: int = ord(character) - - # Binary search: find the rightmost range whose start <= character_ord - idx = bisect_right(_UNICODE_RANGE_STARTS, character_ord) - 1 - if idx >= 0: - start, stop, name = _UNICODE_RANGES_SORTED[idx] - if character_ord < stop: - return name - - return None - - -@lru_cache(maxsize=UTF8_MAXIMAL_ALLOCATION) -def is_latin(character: str) -> bool: - return bool(_character_flags(character) & _LATIN) - - -@lru_cache(maxsize=UTF8_MAXIMAL_ALLOCATION) -def is_punctuation(character: str) -> bool: - character_category: str = unicodedata.category(character) - - if "P" in character_category: - return True - - character_range: str | None = unicode_range(character) - - if character_range is None: - return False - - return "Punctuation" in character_range - - -@lru_cache(maxsize=UTF8_MAXIMAL_ALLOCATION) -def is_symbol(character: str) -> bool: - character_category: str = unicodedata.category(character) - - if "S" in character_category or "N" in character_category: - return True - - character_range: str | None = unicode_range(character) - - if character_range is None: - return False - - return "Forms" in character_range and character_category != "Lo" - - -@lru_cache(maxsize=UTF8_MAXIMAL_ALLOCATION) -def is_emoticon(character: str) -> bool: - character_range: str | None = unicode_range(character) - - if character_range is None: - return False - - return "Emoticons" in character_range or "Pictographs" in character_range - - -@lru_cache(maxsize=UTF8_MAXIMAL_ALLOCATION) -def is_separator(character: str) -> bool: - if character.isspace() or character in {"|", "+", "<", ">"}: - return True - - character_category: str = unicodedata.category(character) - - return "Z" in character_category or character_category in {"Po", "Pd", "Pc"} - - -@lru_cache(maxsize=UTF8_MAXIMAL_ALLOCATION) -def is_case_variable(character: str) -> bool: - return character.islower() != character.isupper() - - -@lru_cache(maxsize=UTF8_MAXIMAL_ALLOCATION) -def is_cjk(character: str) -> bool: - return bool(_character_flags(character) & _CJK) - - -@lru_cache(maxsize=UTF8_MAXIMAL_ALLOCATION) -def is_hiragana(character: str) -> bool: - return bool(_character_flags(character) & _HIRAGANA) - - -@lru_cache(maxsize=UTF8_MAXIMAL_ALLOCATION) -def is_katakana(character: str) -> bool: - return bool(_character_flags(character) & _KATAKANA) - - -@lru_cache(maxsize=UTF8_MAXIMAL_ALLOCATION) -def is_hangul(character: str) -> bool: - return bool(_character_flags(character) & _HANGUL) - - -@lru_cache(maxsize=UTF8_MAXIMAL_ALLOCATION) -def is_thai(character: str) -> bool: - return bool(_character_flags(character) & _THAI) - - -@lru_cache(maxsize=UTF8_MAXIMAL_ALLOCATION) -def is_arabic(character: str) -> bool: - return bool(_character_flags(character) & _ARABIC) - - -@lru_cache(maxsize=UTF8_MAXIMAL_ALLOCATION) -def is_arabic_isolated_form(character: str) -> bool: - return bool(_character_flags(character) & _ARABIC_ISOLATED_FORM) - - -@lru_cache(maxsize=UTF8_MAXIMAL_ALLOCATION) -def is_cjk_uncommon(character: str) -> bool: - return character not in COMMON_CJK_CHARACTERS - - -@lru_cache(maxsize=len(UNICODE_RANGES_COMBINED)) -def is_unicode_range_secondary(range_name: str) -> bool: - return any(keyword in range_name for keyword in UNICODE_SECONDARY_RANGE_KEYWORD) - - -@lru_cache(maxsize=UTF8_MAXIMAL_ALLOCATION) -def is_unprintable(character: str) -> bool: - return ( - character.isspace() is False # includes \n \t \r \v - and character.isprintable() is False - and character != "\x1a" # Why? Its the ASCII substitute character. - and character != "\ufeff" # bug discovered in Python, - # Zero Width No-Break Space located in Arabic Presentation Forms-B, Unicode 1.1 not acknowledged as space. - ) - - -def any_specified_encoding( - sequence: bytes | bytearray, search_zone: int = 8192 -) -> str | None: - """ - Extract using ASCII-only decoder any specified encoding in the first n-bytes. - """ - if not isinstance(sequence, (bytes, bytearray)): - raise TypeError - - seq_len: int = len(sequence) - - results: list[str] = findall( - RE_POSSIBLE_ENCODING_INDICATION, - sequence[: min(seq_len, search_zone)].decode("ascii", errors="ignore"), - ) - - if len(results) == 0: - return None - - for specified_encoding in results: - specified_encoding = specified_encoding.lower().replace("-", "_") - - encoding_alias: str - encoding_iana: str - - for encoding_alias, encoding_iana in aliases.items(): - if encoding_alias == specified_encoding: - return encoding_iana - if encoding_iana == specified_encoding: - return encoding_iana - - return None - - -@lru_cache(maxsize=128) -def is_multi_byte_encoding(name: str) -> bool: - """ - Verify is a specific encoding is a multi byte one based on it IANA name - """ - return name in { - "utf_8", - "utf_8_sig", - "utf_16", - "utf_16_be", - "utf_16_le", - "utf_32", - "utf_32_le", - "utf_32_be", - "utf_7", - } or issubclass( - importlib.import_module(f"encodings.{name}").IncrementalDecoder, - MultibyteIncrementalDecoder, - ) - - -def identify_sig_or_bom(sequence: bytes | bytearray) -> tuple[str | None, bytes]: - """ - Identify and extract SIG/BOM in given sequence. - """ - - for iana_encoding in ENCODING_MARKS: - marks: bytes | list[bytes] = ENCODING_MARKS[iana_encoding] - - if isinstance(marks, bytes): - marks = [marks] - - for mark in marks: - if sequence.startswith(mark): - return iana_encoding, mark - - return None, b"" - - -def should_strip_sig_or_bom(iana_encoding: str) -> bool: - return iana_encoding not in {"utf_16", "utf_32"} - - -def iana_name(cp_name: str, strict: bool = True) -> str: - """Returns the Python normalized encoding name (Not the IANA official name).""" - cp_name = cp_name.lower().replace("-", "_") - - encoding_alias: str - encoding_iana: str - - for encoding_alias, encoding_iana in aliases.items(): - if cp_name in [encoding_alias, encoding_iana]: - return encoding_iana - - if strict: - raise ValueError(f"Unable to retrieve IANA for '{cp_name}'") - - return cp_name - - -def cp_similarity(iana_name_a: str, iana_name_b: str) -> float: - if is_multi_byte_encoding(iana_name_a) or is_multi_byte_encoding(iana_name_b): - return 0.0 - - decoder_a = importlib.import_module(f"encodings.{iana_name_a}").IncrementalDecoder - decoder_b = importlib.import_module(f"encodings.{iana_name_b}").IncrementalDecoder - - id_a: IncrementalDecoder = decoder_a(errors="ignore") - id_b: IncrementalDecoder = decoder_b(errors="ignore") - - character_match_count: int = 0 - - for i in range(256): - to_be_decoded: bytes = bytes([i]) - if id_a.decode(to_be_decoded) == id_b.decode(to_be_decoded): - character_match_count += 1 - - return character_match_count / 256 - - -def is_cp_similar(iana_name_a: str, iana_name_b: str) -> bool: - """ - Determine if two code page are at least 80% similar. IANA_SUPPORTED_SIMILAR dict was generated using - the function cp_similarity. - """ - return ( - iana_name_a in IANA_SUPPORTED_SIMILAR - and iana_name_b in IANA_SUPPORTED_SIMILAR[iana_name_a] - ) - - -def set_logging_handler( - name: str = "charset_normalizer", - level: int = logging.INFO, - format_string: str = "%(asctime)s | %(levelname)s | %(message)s", -) -> None: - logger = logging.getLogger(name) - logger.setLevel(level) - - handler = logging.StreamHandler() - handler.setFormatter(logging.Formatter(format_string)) - logger.addHandler(handler) - - -def cut_sequence_chunks( - sequences: bytes | bytearray, - encoding_iana: str, - offsets: range, - chunk_size: int, - bom_or_sig_available: bool, - strip_sig_or_bom: bool, - sig_payload: bytes, - is_multi_byte_decoder: bool, - decoded_payload: str | None = None, -) -> Generator[str, None, None]: - if decoded_payload and is_multi_byte_decoder is False: - for i in offsets: - chunk = decoded_payload[i : i + chunk_size] - if not chunk: - break - yield chunk - else: - for i in offsets: - chunk_end = i + chunk_size - if chunk_end > len(sequences) + 8: - continue - - cut_sequence = sequences[i : i + chunk_size] - - if bom_or_sig_available and strip_sig_or_bom is False: - cut_sequence = sig_payload + cut_sequence - - chunk = cut_sequence.decode( - encoding_iana, - errors="ignore" if is_multi_byte_decoder else "strict", - ) - - # multi-byte bad cutting detector and adjustment - # not the cleanest way to perform that fix but clever enough for now. - if is_multi_byte_decoder and i > 0: - chunk_partial_size_chk: int = min(chunk_size, 16) - - if ( - decoded_payload - and chunk[:chunk_partial_size_chk] not in decoded_payload - ): - for j in range(i, i - 4, -1): - cut_sequence = sequences[j:chunk_end] - - if bom_or_sig_available and strip_sig_or_bom is False: - cut_sequence = sig_payload + cut_sequence - - chunk = cut_sequence.decode(encoding_iana, errors="ignore") - - if chunk[:chunk_partial_size_chk] in decoded_payload: - break - - yield chunk diff --git a/venv/lib/python3.9/site-packages/charset_normalizer/version.py b/venv/lib/python3.9/site-packages/charset_normalizer/version.py deleted file mode 100644 index a93d367..0000000 --- a/venv/lib/python3.9/site-packages/charset_normalizer/version.py +++ /dev/null @@ -1,8 +0,0 @@ -""" -Expose version -""" - -from __future__ import annotations - -__version__ = "3.4.7" -VERSION = __version__.split(".") diff --git a/venv/lib/python3.9/site-packages/click-8.1.8.dist-info/INSTALLER b/venv/lib/python3.9/site-packages/click-8.1.8.dist-info/INSTALLER deleted file mode 100644 index a1b589e..0000000 --- a/venv/lib/python3.9/site-packages/click-8.1.8.dist-info/INSTALLER +++ /dev/null @@ -1 +0,0 @@ -pip diff --git a/venv/lib/python3.9/site-packages/click-8.1.8.dist-info/LICENSE.txt b/venv/lib/python3.9/site-packages/click-8.1.8.dist-info/LICENSE.txt deleted file mode 100644 index d12a849..0000000 --- a/venv/lib/python3.9/site-packages/click-8.1.8.dist-info/LICENSE.txt +++ /dev/null @@ -1,28 +0,0 @@ -Copyright 2014 Pallets - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - -1. Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - -2. Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - -3. Neither the name of the copyright holder nor the names of its - contributors may be used to endorse or promote products derived from - this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A -PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED -TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR -PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF -LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING -NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/venv/lib/python3.9/site-packages/click-8.1.8.dist-info/METADATA b/venv/lib/python3.9/site-packages/click-8.1.8.dist-info/METADATA deleted file mode 100644 index 366d1a7..0000000 --- a/venv/lib/python3.9/site-packages/click-8.1.8.dist-info/METADATA +++ /dev/null @@ -1,74 +0,0 @@ -Metadata-Version: 2.3 -Name: click -Version: 8.1.8 -Summary: Composable command line interface toolkit -Maintainer-email: Pallets -Requires-Python: >=3.7 -Description-Content-Type: text/markdown -Classifier: Development Status :: 5 - Production/Stable -Classifier: Intended Audience :: Developers -Classifier: License :: OSI Approved :: BSD License -Classifier: Operating System :: OS Independent -Classifier: Programming Language :: Python -Classifier: Typing :: Typed -Requires-Dist: colorama; platform_system == 'Windows' -Requires-Dist: importlib-metadata; python_version < '3.8' -Project-URL: Changes, https://click.palletsprojects.com/changes/ -Project-URL: Chat, https://discord.gg/pallets -Project-URL: Documentation, https://click.palletsprojects.com/ -Project-URL: Donate, https://palletsprojects.com/donate -Project-URL: Source, https://github.com/pallets/click/ - -# $ click_ - -Click is a Python package for creating beautiful command line interfaces -in a composable way with as little code as necessary. It's the "Command -Line Interface Creation Kit". It's highly configurable but comes with -sensible defaults out of the box. - -It aims to make the process of writing command line tools quick and fun -while also preventing any frustration caused by the inability to -implement an intended CLI API. - -Click in three points: - -- Arbitrary nesting of commands -- Automatic help page generation -- Supports lazy loading of subcommands at runtime - - -## A Simple Example - -```python -import click - -@click.command() -@click.option("--count", default=1, help="Number of greetings.") -@click.option("--name", prompt="Your name", help="The person to greet.") -def hello(count, name): - """Simple program that greets NAME for a total of COUNT times.""" - for _ in range(count): - click.echo(f"Hello, {name}!") - -if __name__ == '__main__': - hello() -``` - -``` -$ python hello.py --count=3 -Your name: Click -Hello, Click! -Hello, Click! -Hello, Click! -``` - - -## Donate - -The Pallets organization develops and supports Click and other popular -packages. In order to grow the community of contributors and users, and -allow the maintainers to devote more time to the projects, [please -donate today][]. - -[please donate today]: https://palletsprojects.com/donate - diff --git a/venv/lib/python3.9/site-packages/click-8.1.8.dist-info/RECORD b/venv/lib/python3.9/site-packages/click-8.1.8.dist-info/RECORD deleted file mode 100644 index ea71034..0000000 --- a/venv/lib/python3.9/site-packages/click-8.1.8.dist-info/RECORD +++ /dev/null @@ -1,38 +0,0 @@ -click-8.1.8.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 -click-8.1.8.dist-info/LICENSE.txt,sha256=morRBqOU6FO_4h9C9OctWSgZoigF2ZG18ydQKSkrZY0,1475 -click-8.1.8.dist-info/METADATA,sha256=WJtQ6uGS2ybLfvUE4vC0XIhIBr4yFGwjrMBR2fiCQ-Q,2263 -click-8.1.8.dist-info/RECORD,, -click-8.1.8.dist-info/WHEEL,sha256=CpUCUxeHQbRN5UGRQHYRJorO5Af-Qy_fHMctcQ8DSGI,82 -click/__init__.py,sha256=j1DJeCbga4ribkv5uyvIAzI0oFN13fW9mevDKShFelo,3188 -click/__pycache__/__init__.cpython-39.pyc,, -click/__pycache__/_compat.cpython-39.pyc,, -click/__pycache__/_termui_impl.cpython-39.pyc,, -click/__pycache__/_textwrap.cpython-39.pyc,, -click/__pycache__/_winconsole.cpython-39.pyc,, -click/__pycache__/core.cpython-39.pyc,, -click/__pycache__/decorators.cpython-39.pyc,, -click/__pycache__/exceptions.cpython-39.pyc,, -click/__pycache__/formatting.cpython-39.pyc,, -click/__pycache__/globals.cpython-39.pyc,, -click/__pycache__/parser.cpython-39.pyc,, -click/__pycache__/shell_completion.cpython-39.pyc,, -click/__pycache__/termui.cpython-39.pyc,, -click/__pycache__/testing.cpython-39.pyc,, -click/__pycache__/types.cpython-39.pyc,, -click/__pycache__/utils.cpython-39.pyc,, -click/_compat.py,sha256=IGKh_J5QdfKELitnRfTGHneejWxoCw_NX9tfMbdcg3w,18730 -click/_termui_impl.py,sha256=a5z7I9gOFeMmu7Gb6_RPyQ8GPuVP1EeblixcWSPSQPk,24783 -click/_textwrap.py,sha256=10fQ64OcBUMuK7mFvh8363_uoOxPlRItZBmKzRJDgoY,1353 -click/_winconsole.py,sha256=5ju3jQkcZD0W27WEMGqmEP4y_crUVzPCqsX_FYb7BO0,7860 -click/core.py,sha256=Q1nEVdctZwvIPOlt4vfHko0TYnHCeE40UEEul8Wpyvs,114748 -click/decorators.py,sha256=7t6F-QWowtLh6F_6l-4YV4Y4yNTcqFQEu9i37zIz68s,18925 -click/exceptions.py,sha256=V7zDT6emqJ8iNl0kF1P5kpFmLMWQ1T1L7aNNKM4YR0w,9600 -click/formatting.py,sha256=Frf0-5W33-loyY_i9qrwXR8-STnW3m5gvyxLVUdyxyk,9706 -click/globals.py,sha256=cuJ6Bbo073lgEEmhjr394PeM-QFmXM-Ci-wmfsd7H5g,1954 -click/parser.py,sha256=h4sndcpF5OHrZQN8vD8IWb5OByvW7ABbhRToxovrqS8,19067 -click/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 -click/shell_completion.py,sha256=TR0dXEGcvWb9Eo3aaQEXGhnvNS3FF4H4QcuLnvAvYo4,18636 -click/termui.py,sha256=dLxiS70UOvIYBda_nEEZaPAFOVDVmRs1sEPMuLDowQo,28310 -click/testing.py,sha256=3RA8anCf7TZ8-5RAF5it2Te-aWXBAL5VLasQnMiC2ZQ,16282 -click/types.py,sha256=BD5Qqq4h-8kawBmOIzJlmq4xzThAf4wCvaOLZSBDNx0,36422 -click/utils.py,sha256=ce-IrO9ilII76LGkU354pOdHbepM8UftfNH7SfMU_28,20330 diff --git a/venv/lib/python3.9/site-packages/click-8.1.8.dist-info/WHEEL b/venv/lib/python3.9/site-packages/click-8.1.8.dist-info/WHEEL deleted file mode 100644 index e3c6fee..0000000 --- a/venv/lib/python3.9/site-packages/click-8.1.8.dist-info/WHEEL +++ /dev/null @@ -1,4 +0,0 @@ -Wheel-Version: 1.0 -Generator: flit 3.10.1 -Root-Is-Purelib: true -Tag: py3-none-any diff --git a/venv/lib/python3.9/site-packages/click/__init__.py b/venv/lib/python3.9/site-packages/click/__init__.py deleted file mode 100644 index 2610d0e..0000000 --- a/venv/lib/python3.9/site-packages/click/__init__.py +++ /dev/null @@ -1,75 +0,0 @@ -""" -Click is a simple Python module inspired by the stdlib optparse to make -writing command line scripts fun. Unlike other modules, it's based -around a simple API that does not come with too much magic and is -composable. -""" - -from .core import Argument as Argument -from .core import BaseCommand as BaseCommand -from .core import Command as Command -from .core import CommandCollection as CommandCollection -from .core import Context as Context -from .core import Group as Group -from .core import MultiCommand as MultiCommand -from .core import Option as Option -from .core import Parameter as Parameter -from .decorators import argument as argument -from .decorators import command as command -from .decorators import confirmation_option as confirmation_option -from .decorators import group as group -from .decorators import help_option as help_option -from .decorators import HelpOption as HelpOption -from .decorators import make_pass_decorator as make_pass_decorator -from .decorators import option as option -from .decorators import pass_context as pass_context -from .decorators import pass_obj as pass_obj -from .decorators import password_option as password_option -from .decorators import version_option as version_option -from .exceptions import Abort as Abort -from .exceptions import BadArgumentUsage as BadArgumentUsage -from .exceptions import BadOptionUsage as BadOptionUsage -from .exceptions import BadParameter as BadParameter -from .exceptions import ClickException as ClickException -from .exceptions import FileError as FileError -from .exceptions import MissingParameter as MissingParameter -from .exceptions import NoSuchOption as NoSuchOption -from .exceptions import UsageError as UsageError -from .formatting import HelpFormatter as HelpFormatter -from .formatting import wrap_text as wrap_text -from .globals import get_current_context as get_current_context -from .parser import OptionParser as OptionParser -from .termui import clear as clear -from .termui import confirm as confirm -from .termui import echo_via_pager as echo_via_pager -from .termui import edit as edit -from .termui import getchar as getchar -from .termui import launch as launch -from .termui import pause as pause -from .termui import progressbar as progressbar -from .termui import prompt as prompt -from .termui import secho as secho -from .termui import style as style -from .termui import unstyle as unstyle -from .types import BOOL as BOOL -from .types import Choice as Choice -from .types import DateTime as DateTime -from .types import File as File -from .types import FLOAT as FLOAT -from .types import FloatRange as FloatRange -from .types import INT as INT -from .types import IntRange as IntRange -from .types import ParamType as ParamType -from .types import Path as Path -from .types import STRING as STRING -from .types import Tuple as Tuple -from .types import UNPROCESSED as UNPROCESSED -from .types import UUID as UUID -from .utils import echo as echo -from .utils import format_filename as format_filename -from .utils import get_app_dir as get_app_dir -from .utils import get_binary_stream as get_binary_stream -from .utils import get_text_stream as get_text_stream -from .utils import open_file as open_file - -__version__ = "8.1.8" diff --git a/venv/lib/python3.9/site-packages/click/_compat.py b/venv/lib/python3.9/site-packages/click/_compat.py deleted file mode 100644 index 9153d15..0000000 --- a/venv/lib/python3.9/site-packages/click/_compat.py +++ /dev/null @@ -1,623 +0,0 @@ -import codecs -import io -import os -import re -import sys -import typing as t -from weakref import WeakKeyDictionary - -CYGWIN = sys.platform.startswith("cygwin") -WIN = sys.platform.startswith("win") -auto_wrap_for_ansi: t.Optional[t.Callable[[t.TextIO], t.TextIO]] = None -_ansi_re = re.compile(r"\033\[[;?0-9]*[a-zA-Z]") - - -def _make_text_stream( - stream: t.BinaryIO, - encoding: t.Optional[str], - errors: t.Optional[str], - force_readable: bool = False, - force_writable: bool = False, -) -> t.TextIO: - if encoding is None: - encoding = get_best_encoding(stream) - if errors is None: - errors = "replace" - return _NonClosingTextIOWrapper( - stream, - encoding, - errors, - line_buffering=True, - force_readable=force_readable, - force_writable=force_writable, - ) - - -def is_ascii_encoding(encoding: str) -> bool: - """Checks if a given encoding is ascii.""" - try: - return codecs.lookup(encoding).name == "ascii" - except LookupError: - return False - - -def get_best_encoding(stream: t.IO[t.Any]) -> str: - """Returns the default stream encoding if not found.""" - rv = getattr(stream, "encoding", None) or sys.getdefaultencoding() - if is_ascii_encoding(rv): - return "utf-8" - return rv - - -class _NonClosingTextIOWrapper(io.TextIOWrapper): - def __init__( - self, - stream: t.BinaryIO, - encoding: t.Optional[str], - errors: t.Optional[str], - force_readable: bool = False, - force_writable: bool = False, - **extra: t.Any, - ) -> None: - self._stream = stream = t.cast( - t.BinaryIO, _FixupStream(stream, force_readable, force_writable) - ) - super().__init__(stream, encoding, errors, **extra) - - def __del__(self) -> None: - try: - self.detach() - except Exception: - pass - - def isatty(self) -> bool: - # https://bitbucket.org/pypy/pypy/issue/1803 - return self._stream.isatty() - - -class _FixupStream: - """The new io interface needs more from streams than streams - traditionally implement. As such, this fix-up code is necessary in - some circumstances. - - The forcing of readable and writable flags are there because some tools - put badly patched objects on sys (one such offender are certain version - of jupyter notebook). - """ - - def __init__( - self, - stream: t.BinaryIO, - force_readable: bool = False, - force_writable: bool = False, - ): - self._stream = stream - self._force_readable = force_readable - self._force_writable = force_writable - - def __getattr__(self, name: str) -> t.Any: - return getattr(self._stream, name) - - def read1(self, size: int) -> bytes: - f = getattr(self._stream, "read1", None) - - if f is not None: - return t.cast(bytes, f(size)) - - return self._stream.read(size) - - def readable(self) -> bool: - if self._force_readable: - return True - x = getattr(self._stream, "readable", None) - if x is not None: - return t.cast(bool, x()) - try: - self._stream.read(0) - except Exception: - return False - return True - - def writable(self) -> bool: - if self._force_writable: - return True - x = getattr(self._stream, "writable", None) - if x is not None: - return t.cast(bool, x()) - try: - self._stream.write("") # type: ignore - except Exception: - try: - self._stream.write(b"") - except Exception: - return False - return True - - def seekable(self) -> bool: - x = getattr(self._stream, "seekable", None) - if x is not None: - return t.cast(bool, x()) - try: - self._stream.seek(self._stream.tell()) - except Exception: - return False - return True - - -def _is_binary_reader(stream: t.IO[t.Any], default: bool = False) -> bool: - try: - return isinstance(stream.read(0), bytes) - except Exception: - return default - # This happens in some cases where the stream was already - # closed. In this case, we assume the default. - - -def _is_binary_writer(stream: t.IO[t.Any], default: bool = False) -> bool: - try: - stream.write(b"") - except Exception: - try: - stream.write("") - return False - except Exception: - pass - return default - return True - - -def _find_binary_reader(stream: t.IO[t.Any]) -> t.Optional[t.BinaryIO]: - # We need to figure out if the given stream is already binary. - # This can happen because the official docs recommend detaching - # the streams to get binary streams. Some code might do this, so - # we need to deal with this case explicitly. - if _is_binary_reader(stream, False): - return t.cast(t.BinaryIO, stream) - - buf = getattr(stream, "buffer", None) - - # Same situation here; this time we assume that the buffer is - # actually binary in case it's closed. - if buf is not None and _is_binary_reader(buf, True): - return t.cast(t.BinaryIO, buf) - - return None - - -def _find_binary_writer(stream: t.IO[t.Any]) -> t.Optional[t.BinaryIO]: - # We need to figure out if the given stream is already binary. - # This can happen because the official docs recommend detaching - # the streams to get binary streams. Some code might do this, so - # we need to deal with this case explicitly. - if _is_binary_writer(stream, False): - return t.cast(t.BinaryIO, stream) - - buf = getattr(stream, "buffer", None) - - # Same situation here; this time we assume that the buffer is - # actually binary in case it's closed. - if buf is not None and _is_binary_writer(buf, True): - return t.cast(t.BinaryIO, buf) - - return None - - -def _stream_is_misconfigured(stream: t.TextIO) -> bool: - """A stream is misconfigured if its encoding is ASCII.""" - # If the stream does not have an encoding set, we assume it's set - # to ASCII. This appears to happen in certain unittest - # environments. It's not quite clear what the correct behavior is - # but this at least will force Click to recover somehow. - return is_ascii_encoding(getattr(stream, "encoding", None) or "ascii") - - -def _is_compat_stream_attr(stream: t.TextIO, attr: str, value: t.Optional[str]) -> bool: - """A stream attribute is compatible if it is equal to the - desired value or the desired value is unset and the attribute - has a value. - """ - stream_value = getattr(stream, attr, None) - return stream_value == value or (value is None and stream_value is not None) - - -def _is_compatible_text_stream( - stream: t.TextIO, encoding: t.Optional[str], errors: t.Optional[str] -) -> bool: - """Check if a stream's encoding and errors attributes are - compatible with the desired values. - """ - return _is_compat_stream_attr( - stream, "encoding", encoding - ) and _is_compat_stream_attr(stream, "errors", errors) - - -def _force_correct_text_stream( - text_stream: t.IO[t.Any], - encoding: t.Optional[str], - errors: t.Optional[str], - is_binary: t.Callable[[t.IO[t.Any], bool], bool], - find_binary: t.Callable[[t.IO[t.Any]], t.Optional[t.BinaryIO]], - force_readable: bool = False, - force_writable: bool = False, -) -> t.TextIO: - if is_binary(text_stream, False): - binary_reader = t.cast(t.BinaryIO, text_stream) - else: - text_stream = t.cast(t.TextIO, text_stream) - # If the stream looks compatible, and won't default to a - # misconfigured ascii encoding, return it as-is. - if _is_compatible_text_stream(text_stream, encoding, errors) and not ( - encoding is None and _stream_is_misconfigured(text_stream) - ): - return text_stream - - # Otherwise, get the underlying binary reader. - possible_binary_reader = find_binary(text_stream) - - # If that's not possible, silently use the original reader - # and get mojibake instead of exceptions. - if possible_binary_reader is None: - return text_stream - - binary_reader = possible_binary_reader - - # Default errors to replace instead of strict in order to get - # something that works. - if errors is None: - errors = "replace" - - # Wrap the binary stream in a text stream with the correct - # encoding parameters. - return _make_text_stream( - binary_reader, - encoding, - errors, - force_readable=force_readable, - force_writable=force_writable, - ) - - -def _force_correct_text_reader( - text_reader: t.IO[t.Any], - encoding: t.Optional[str], - errors: t.Optional[str], - force_readable: bool = False, -) -> t.TextIO: - return _force_correct_text_stream( - text_reader, - encoding, - errors, - _is_binary_reader, - _find_binary_reader, - force_readable=force_readable, - ) - - -def _force_correct_text_writer( - text_writer: t.IO[t.Any], - encoding: t.Optional[str], - errors: t.Optional[str], - force_writable: bool = False, -) -> t.TextIO: - return _force_correct_text_stream( - text_writer, - encoding, - errors, - _is_binary_writer, - _find_binary_writer, - force_writable=force_writable, - ) - - -def get_binary_stdin() -> t.BinaryIO: - reader = _find_binary_reader(sys.stdin) - if reader is None: - raise RuntimeError("Was not able to determine binary stream for sys.stdin.") - return reader - - -def get_binary_stdout() -> t.BinaryIO: - writer = _find_binary_writer(sys.stdout) - if writer is None: - raise RuntimeError("Was not able to determine binary stream for sys.stdout.") - return writer - - -def get_binary_stderr() -> t.BinaryIO: - writer = _find_binary_writer(sys.stderr) - if writer is None: - raise RuntimeError("Was not able to determine binary stream for sys.stderr.") - return writer - - -def get_text_stdin( - encoding: t.Optional[str] = None, errors: t.Optional[str] = None -) -> t.TextIO: - rv = _get_windows_console_stream(sys.stdin, encoding, errors) - if rv is not None: - return rv - return _force_correct_text_reader(sys.stdin, encoding, errors, force_readable=True) - - -def get_text_stdout( - encoding: t.Optional[str] = None, errors: t.Optional[str] = None -) -> t.TextIO: - rv = _get_windows_console_stream(sys.stdout, encoding, errors) - if rv is not None: - return rv - return _force_correct_text_writer(sys.stdout, encoding, errors, force_writable=True) - - -def get_text_stderr( - encoding: t.Optional[str] = None, errors: t.Optional[str] = None -) -> t.TextIO: - rv = _get_windows_console_stream(sys.stderr, encoding, errors) - if rv is not None: - return rv - return _force_correct_text_writer(sys.stderr, encoding, errors, force_writable=True) - - -def _wrap_io_open( - file: t.Union[str, "os.PathLike[str]", int], - mode: str, - encoding: t.Optional[str], - errors: t.Optional[str], -) -> t.IO[t.Any]: - """Handles not passing ``encoding`` and ``errors`` in binary mode.""" - if "b" in mode: - return open(file, mode) - - return open(file, mode, encoding=encoding, errors=errors) - - -def open_stream( - filename: "t.Union[str, os.PathLike[str]]", - mode: str = "r", - encoding: t.Optional[str] = None, - errors: t.Optional[str] = "strict", - atomic: bool = False, -) -> t.Tuple[t.IO[t.Any], bool]: - binary = "b" in mode - filename = os.fspath(filename) - - # Standard streams first. These are simple because they ignore the - # atomic flag. Use fsdecode to handle Path("-"). - if os.fsdecode(filename) == "-": - if any(m in mode for m in ["w", "a", "x"]): - if binary: - return get_binary_stdout(), False - return get_text_stdout(encoding=encoding, errors=errors), False - if binary: - return get_binary_stdin(), False - return get_text_stdin(encoding=encoding, errors=errors), False - - # Non-atomic writes directly go out through the regular open functions. - if not atomic: - return _wrap_io_open(filename, mode, encoding, errors), True - - # Some usability stuff for atomic writes - if "a" in mode: - raise ValueError( - "Appending to an existing file is not supported, because that" - " would involve an expensive `copy`-operation to a temporary" - " file. Open the file in normal `w`-mode and copy explicitly" - " if that's what you're after." - ) - if "x" in mode: - raise ValueError("Use the `overwrite`-parameter instead.") - if "w" not in mode: - raise ValueError("Atomic writes only make sense with `w`-mode.") - - # Atomic writes are more complicated. They work by opening a file - # as a proxy in the same folder and then using the fdopen - # functionality to wrap it in a Python file. Then we wrap it in an - # atomic file that moves the file over on close. - import errno - import random - - try: - perm: t.Optional[int] = os.stat(filename).st_mode - except OSError: - perm = None - - flags = os.O_RDWR | os.O_CREAT | os.O_EXCL - - if binary: - flags |= getattr(os, "O_BINARY", 0) - - while True: - tmp_filename = os.path.join( - os.path.dirname(filename), - f".__atomic-write{random.randrange(1 << 32):08x}", - ) - try: - fd = os.open(tmp_filename, flags, 0o666 if perm is None else perm) - break - except OSError as e: - if e.errno == errno.EEXIST or ( - os.name == "nt" - and e.errno == errno.EACCES - and os.path.isdir(e.filename) - and os.access(e.filename, os.W_OK) - ): - continue - raise - - if perm is not None: - os.chmod(tmp_filename, perm) # in case perm includes bits in umask - - f = _wrap_io_open(fd, mode, encoding, errors) - af = _AtomicFile(f, tmp_filename, os.path.realpath(filename)) - return t.cast(t.IO[t.Any], af), True - - -class _AtomicFile: - def __init__(self, f: t.IO[t.Any], tmp_filename: str, real_filename: str) -> None: - self._f = f - self._tmp_filename = tmp_filename - self._real_filename = real_filename - self.closed = False - - @property - def name(self) -> str: - return self._real_filename - - def close(self, delete: bool = False) -> None: - if self.closed: - return - self._f.close() - os.replace(self._tmp_filename, self._real_filename) - self.closed = True - - def __getattr__(self, name: str) -> t.Any: - return getattr(self._f, name) - - def __enter__(self) -> "_AtomicFile": - return self - - def __exit__(self, exc_type: t.Optional[t.Type[BaseException]], *_: t.Any) -> None: - self.close(delete=exc_type is not None) - - def __repr__(self) -> str: - return repr(self._f) - - -def strip_ansi(value: str) -> str: - return _ansi_re.sub("", value) - - -def _is_jupyter_kernel_output(stream: t.IO[t.Any]) -> bool: - while isinstance(stream, (_FixupStream, _NonClosingTextIOWrapper)): - stream = stream._stream - - return stream.__class__.__module__.startswith("ipykernel.") - - -def should_strip_ansi( - stream: t.Optional[t.IO[t.Any]] = None, color: t.Optional[bool] = None -) -> bool: - if color is None: - if stream is None: - stream = sys.stdin - return not isatty(stream) and not _is_jupyter_kernel_output(stream) - return not color - - -# On Windows, wrap the output streams with colorama to support ANSI -# color codes. -# NOTE: double check is needed so mypy does not analyze this on Linux -if sys.platform.startswith("win") and WIN: - from ._winconsole import _get_windows_console_stream - - def _get_argv_encoding() -> str: - import locale - - return locale.getpreferredencoding() - - _ansi_stream_wrappers: t.MutableMapping[t.TextIO, t.TextIO] = WeakKeyDictionary() - - def auto_wrap_for_ansi( - stream: t.TextIO, color: t.Optional[bool] = None - ) -> t.TextIO: - """Support ANSI color and style codes on Windows by wrapping a - stream with colorama. - """ - try: - cached = _ansi_stream_wrappers.get(stream) - except Exception: - cached = None - - if cached is not None: - return cached - - import colorama - - strip = should_strip_ansi(stream, color) - ansi_wrapper = colorama.AnsiToWin32(stream, strip=strip) - rv = t.cast(t.TextIO, ansi_wrapper.stream) - _write = rv.write - - def _safe_write(s): - try: - return _write(s) - except BaseException: - ansi_wrapper.reset_all() - raise - - rv.write = _safe_write - - try: - _ansi_stream_wrappers[stream] = rv - except Exception: - pass - - return rv - -else: - - def _get_argv_encoding() -> str: - return getattr(sys.stdin, "encoding", None) or sys.getfilesystemencoding() - - def _get_windows_console_stream( - f: t.TextIO, encoding: t.Optional[str], errors: t.Optional[str] - ) -> t.Optional[t.TextIO]: - return None - - -def term_len(x: str) -> int: - return len(strip_ansi(x)) - - -def isatty(stream: t.IO[t.Any]) -> bool: - try: - return stream.isatty() - except Exception: - return False - - -def _make_cached_stream_func( - src_func: t.Callable[[], t.Optional[t.TextIO]], - wrapper_func: t.Callable[[], t.TextIO], -) -> t.Callable[[], t.Optional[t.TextIO]]: - cache: t.MutableMapping[t.TextIO, t.TextIO] = WeakKeyDictionary() - - def func() -> t.Optional[t.TextIO]: - stream = src_func() - - if stream is None: - return None - - try: - rv = cache.get(stream) - except Exception: - rv = None - if rv is not None: - return rv - rv = wrapper_func() - try: - cache[stream] = rv - except Exception: - pass - return rv - - return func - - -_default_text_stdin = _make_cached_stream_func(lambda: sys.stdin, get_text_stdin) -_default_text_stdout = _make_cached_stream_func(lambda: sys.stdout, get_text_stdout) -_default_text_stderr = _make_cached_stream_func(lambda: sys.stderr, get_text_stderr) - - -binary_streams: t.Mapping[str, t.Callable[[], t.BinaryIO]] = { - "stdin": get_binary_stdin, - "stdout": get_binary_stdout, - "stderr": get_binary_stderr, -} - -text_streams: t.Mapping[ - str, t.Callable[[t.Optional[str], t.Optional[str]], t.TextIO] -] = { - "stdin": get_text_stdin, - "stdout": get_text_stdout, - "stderr": get_text_stderr, -} diff --git a/venv/lib/python3.9/site-packages/click/_termui_impl.py b/venv/lib/python3.9/site-packages/click/_termui_impl.py deleted file mode 100644 index ad9f8f6..0000000 --- a/venv/lib/python3.9/site-packages/click/_termui_impl.py +++ /dev/null @@ -1,788 +0,0 @@ -""" -This module contains implementations for the termui module. To keep the -import time of Click down, some infrequently used functionality is -placed in this module and only imported as needed. -""" - -import contextlib -import math -import os -import sys -import time -import typing as t -from gettext import gettext as _ -from io import StringIO -from shutil import which -from types import TracebackType - -from ._compat import _default_text_stdout -from ._compat import CYGWIN -from ._compat import get_best_encoding -from ._compat import isatty -from ._compat import open_stream -from ._compat import strip_ansi -from ._compat import term_len -from ._compat import WIN -from .exceptions import ClickException -from .utils import echo - -V = t.TypeVar("V") - -if os.name == "nt": - BEFORE_BAR = "\r" - AFTER_BAR = "\n" -else: - BEFORE_BAR = "\r\033[?25l" - AFTER_BAR = "\033[?25h\n" - - -class ProgressBar(t.Generic[V]): - def __init__( - self, - iterable: t.Optional[t.Iterable[V]], - length: t.Optional[int] = None, - fill_char: str = "#", - empty_char: str = " ", - bar_template: str = "%(bar)s", - info_sep: str = " ", - show_eta: bool = True, - show_percent: t.Optional[bool] = None, - show_pos: bool = False, - item_show_func: t.Optional[t.Callable[[t.Optional[V]], t.Optional[str]]] = None, - label: t.Optional[str] = None, - file: t.Optional[t.TextIO] = None, - color: t.Optional[bool] = None, - update_min_steps: int = 1, - width: int = 30, - ) -> None: - self.fill_char = fill_char - self.empty_char = empty_char - self.bar_template = bar_template - self.info_sep = info_sep - self.show_eta = show_eta - self.show_percent = show_percent - self.show_pos = show_pos - self.item_show_func = item_show_func - self.label: str = label or "" - - if file is None: - file = _default_text_stdout() - - # There are no standard streams attached to write to. For example, - # pythonw on Windows. - if file is None: - file = StringIO() - - self.file = file - self.color = color - self.update_min_steps = update_min_steps - self._completed_intervals = 0 - self.width: int = width - self.autowidth: bool = width == 0 - - if length is None: - from operator import length_hint - - length = length_hint(iterable, -1) - - if length == -1: - length = None - if iterable is None: - if length is None: - raise TypeError("iterable or length is required") - iterable = t.cast(t.Iterable[V], range(length)) - self.iter: t.Iterable[V] = iter(iterable) - self.length = length - self.pos = 0 - self.avg: t.List[float] = [] - self.last_eta: float - self.start: float - self.start = self.last_eta = time.time() - self.eta_known: bool = False - self.finished: bool = False - self.max_width: t.Optional[int] = None - self.entered: bool = False - self.current_item: t.Optional[V] = None - self.is_hidden: bool = not isatty(self.file) - self._last_line: t.Optional[str] = None - - def __enter__(self) -> "ProgressBar[V]": - self.entered = True - self.render_progress() - return self - - def __exit__( - self, - exc_type: t.Optional[t.Type[BaseException]], - exc_value: t.Optional[BaseException], - tb: t.Optional[TracebackType], - ) -> None: - self.render_finish() - - def __iter__(self) -> t.Iterator[V]: - if not self.entered: - raise RuntimeError("You need to use progress bars in a with block.") - self.render_progress() - return self.generator() - - def __next__(self) -> V: - # Iteration is defined in terms of a generator function, - # returned by iter(self); use that to define next(). This works - # because `self.iter` is an iterable consumed by that generator, - # so it is re-entry safe. Calling `next(self.generator())` - # twice works and does "what you want". - return next(iter(self)) - - def render_finish(self) -> None: - if self.is_hidden: - return - self.file.write(AFTER_BAR) - self.file.flush() - - @property - def pct(self) -> float: - if self.finished: - return 1.0 - return min(self.pos / (float(self.length or 1) or 1), 1.0) - - @property - def time_per_iteration(self) -> float: - if not self.avg: - return 0.0 - return sum(self.avg) / float(len(self.avg)) - - @property - def eta(self) -> float: - if self.length is not None and not self.finished: - return self.time_per_iteration * (self.length - self.pos) - return 0.0 - - def format_eta(self) -> str: - if self.eta_known: - t = int(self.eta) - seconds = t % 60 - t //= 60 - minutes = t % 60 - t //= 60 - hours = t % 24 - t //= 24 - if t > 0: - return f"{t}d {hours:02}:{minutes:02}:{seconds:02}" - else: - return f"{hours:02}:{minutes:02}:{seconds:02}" - return "" - - def format_pos(self) -> str: - pos = str(self.pos) - if self.length is not None: - pos += f"/{self.length}" - return pos - - def format_pct(self) -> str: - return f"{int(self.pct * 100): 4}%"[1:] - - def format_bar(self) -> str: - if self.length is not None: - bar_length = int(self.pct * self.width) - bar = self.fill_char * bar_length - bar += self.empty_char * (self.width - bar_length) - elif self.finished: - bar = self.fill_char * self.width - else: - chars = list(self.empty_char * (self.width or 1)) - if self.time_per_iteration != 0: - chars[ - int( - (math.cos(self.pos * self.time_per_iteration) / 2.0 + 0.5) - * self.width - ) - ] = self.fill_char - bar = "".join(chars) - return bar - - def format_progress_line(self) -> str: - show_percent = self.show_percent - - info_bits = [] - if self.length is not None and show_percent is None: - show_percent = not self.show_pos - - if self.show_pos: - info_bits.append(self.format_pos()) - if show_percent: - info_bits.append(self.format_pct()) - if self.show_eta and self.eta_known and not self.finished: - info_bits.append(self.format_eta()) - if self.item_show_func is not None: - item_info = self.item_show_func(self.current_item) - if item_info is not None: - info_bits.append(item_info) - - return ( - self.bar_template - % { - "label": self.label, - "bar": self.format_bar(), - "info": self.info_sep.join(info_bits), - } - ).rstrip() - - def render_progress(self) -> None: - import shutil - - if self.is_hidden: - # Only output the label as it changes if the output is not a - # TTY. Use file=stderr if you expect to be piping stdout. - if self._last_line != self.label: - self._last_line = self.label - echo(self.label, file=self.file, color=self.color) - - return - - buf = [] - # Update width in case the terminal has been resized - if self.autowidth: - old_width = self.width - self.width = 0 - clutter_length = term_len(self.format_progress_line()) - new_width = max(0, shutil.get_terminal_size().columns - clutter_length) - if new_width < old_width: - buf.append(BEFORE_BAR) - buf.append(" " * self.max_width) # type: ignore - self.max_width = new_width - self.width = new_width - - clear_width = self.width - if self.max_width is not None: - clear_width = self.max_width - - buf.append(BEFORE_BAR) - line = self.format_progress_line() - line_len = term_len(line) - if self.max_width is None or self.max_width < line_len: - self.max_width = line_len - - buf.append(line) - buf.append(" " * (clear_width - line_len)) - line = "".join(buf) - # Render the line only if it changed. - - if line != self._last_line: - self._last_line = line - echo(line, file=self.file, color=self.color, nl=False) - self.file.flush() - - def make_step(self, n_steps: int) -> None: - self.pos += n_steps - if self.length is not None and self.pos >= self.length: - self.finished = True - - if (time.time() - self.last_eta) < 1.0: - return - - self.last_eta = time.time() - - # self.avg is a rolling list of length <= 7 of steps where steps are - # defined as time elapsed divided by the total progress through - # self.length. - if self.pos: - step = (time.time() - self.start) / self.pos - else: - step = time.time() - self.start - - self.avg = self.avg[-6:] + [step] - - self.eta_known = self.length is not None - - def update(self, n_steps: int, current_item: t.Optional[V] = None) -> None: - """Update the progress bar by advancing a specified number of - steps, and optionally set the ``current_item`` for this new - position. - - :param n_steps: Number of steps to advance. - :param current_item: Optional item to set as ``current_item`` - for the updated position. - - .. versionchanged:: 8.0 - Added the ``current_item`` optional parameter. - - .. versionchanged:: 8.0 - Only render when the number of steps meets the - ``update_min_steps`` threshold. - """ - if current_item is not None: - self.current_item = current_item - - self._completed_intervals += n_steps - - if self._completed_intervals >= self.update_min_steps: - self.make_step(self._completed_intervals) - self.render_progress() - self._completed_intervals = 0 - - def finish(self) -> None: - self.eta_known = False - self.current_item = None - self.finished = True - - def generator(self) -> t.Iterator[V]: - """Return a generator which yields the items added to the bar - during construction, and updates the progress bar *after* the - yielded block returns. - """ - # WARNING: the iterator interface for `ProgressBar` relies on - # this and only works because this is a simple generator which - # doesn't create or manage additional state. If this function - # changes, the impact should be evaluated both against - # `iter(bar)` and `next(bar)`. `next()` in particular may call - # `self.generator()` repeatedly, and this must remain safe in - # order for that interface to work. - if not self.entered: - raise RuntimeError("You need to use progress bars in a with block.") - - if self.is_hidden: - yield from self.iter - else: - for rv in self.iter: - self.current_item = rv - - # This allows show_item_func to be updated before the - # item is processed. Only trigger at the beginning of - # the update interval. - if self._completed_intervals == 0: - self.render_progress() - - yield rv - self.update(1) - - self.finish() - self.render_progress() - - -def pager(generator: t.Iterable[str], color: t.Optional[bool] = None) -> None: - """Decide what method to use for paging through text.""" - stdout = _default_text_stdout() - - # There are no standard streams attached to write to. For example, - # pythonw on Windows. - if stdout is None: - stdout = StringIO() - - if not isatty(sys.stdin) or not isatty(stdout): - return _nullpager(stdout, generator, color) - pager_cmd = (os.environ.get("PAGER", None) or "").strip() - if pager_cmd: - if WIN: - if _tempfilepager(generator, pager_cmd, color): - return - elif _pipepager(generator, pager_cmd, color): - return - if os.environ.get("TERM") in ("dumb", "emacs"): - return _nullpager(stdout, generator, color) - if (WIN or sys.platform.startswith("os2")) and _tempfilepager( - generator, "more", color - ): - return - if _pipepager(generator, "less", color): - return - - import tempfile - - fd, filename = tempfile.mkstemp() - os.close(fd) - try: - if _pipepager(generator, "more", color): - return - return _nullpager(stdout, generator, color) - finally: - os.unlink(filename) - - -def _pipepager(generator: t.Iterable[str], cmd: str, color: t.Optional[bool]) -> bool: - """Page through text by feeding it to another program. Invoking a - pager through this might support colors. - - Returns True if the command was found, False otherwise and thus another - pager should be attempted. - """ - cmd_absolute = which(cmd) - if cmd_absolute is None: - return False - - import subprocess - - env = dict(os.environ) - - # If we're piping to less we might support colors under the - # condition that - cmd_detail = cmd.rsplit("/", 1)[-1].split() - if color is None and cmd_detail[0] == "less": - less_flags = f"{os.environ.get('LESS', '')}{' '.join(cmd_detail[1:])}" - if not less_flags: - env["LESS"] = "-R" - color = True - elif "r" in less_flags or "R" in less_flags: - color = True - - c = subprocess.Popen( - [cmd_absolute], - shell=True, - stdin=subprocess.PIPE, - env=env, - errors="replace", - text=True, - ) - assert c.stdin is not None - try: - for text in generator: - if not color: - text = strip_ansi(text) - - c.stdin.write(text) - except (OSError, KeyboardInterrupt): - pass - else: - c.stdin.close() - - # Less doesn't respect ^C, but catches it for its own UI purposes (aborting - # search or other commands inside less). - # - # That means when the user hits ^C, the parent process (click) terminates, - # but less is still alive, paging the output and messing up the terminal. - # - # If the user wants to make the pager exit on ^C, they should set - # `LESS='-K'`. It's not our decision to make. - while True: - try: - c.wait() - except KeyboardInterrupt: - pass - else: - break - - return True - - -def _tempfilepager( - generator: t.Iterable[str], - cmd: str, - color: t.Optional[bool], -) -> bool: - """Page through text by invoking a program on a temporary file. - - Returns True if the command was found, False otherwise and thus another - pager should be attempted. - """ - # Which is necessary for Windows, it is also recommended in the Popen docs. - cmd_absolute = which(cmd) - if cmd_absolute is None: - return False - - import subprocess - import tempfile - - fd, filename = tempfile.mkstemp() - # TODO: This never terminates if the passed generator never terminates. - text = "".join(generator) - if not color: - text = strip_ansi(text) - encoding = get_best_encoding(sys.stdout) - with open_stream(filename, "wb")[0] as f: - f.write(text.encode(encoding)) - try: - subprocess.call([cmd_absolute, filename]) - except OSError: - # Command not found - pass - finally: - os.close(fd) - os.unlink(filename) - - return True - - -def _nullpager( - stream: t.TextIO, generator: t.Iterable[str], color: t.Optional[bool] -) -> None: - """Simply print unformatted text. This is the ultimate fallback.""" - for text in generator: - if not color: - text = strip_ansi(text) - stream.write(text) - - -class Editor: - def __init__( - self, - editor: t.Optional[str] = None, - env: t.Optional[t.Mapping[str, str]] = None, - require_save: bool = True, - extension: str = ".txt", - ) -> None: - self.editor = editor - self.env = env - self.require_save = require_save - self.extension = extension - - def get_editor(self) -> str: - if self.editor is not None: - return self.editor - for key in "VISUAL", "EDITOR": - rv = os.environ.get(key) - if rv: - return rv - if WIN: - return "notepad" - for editor in "sensible-editor", "vim", "nano": - if which(editor) is not None: - return editor - return "vi" - - def edit_file(self, filename: str) -> None: - import subprocess - - editor = self.get_editor() - environ: t.Optional[t.Dict[str, str]] = None - - if self.env: - environ = os.environ.copy() - environ.update(self.env) - - try: - c = subprocess.Popen(f'{editor} "{filename}"', env=environ, shell=True) - exit_code = c.wait() - if exit_code != 0: - raise ClickException( - _("{editor}: Editing failed").format(editor=editor) - ) - except OSError as e: - raise ClickException( - _("{editor}: Editing failed: {e}").format(editor=editor, e=e) - ) from e - - def edit(self, text: t.Optional[t.AnyStr]) -> t.Optional[t.AnyStr]: - import tempfile - - if not text: - data = b"" - elif isinstance(text, (bytes, bytearray)): - data = text - else: - if text and not text.endswith("\n"): - text += "\n" - - if WIN: - data = text.replace("\n", "\r\n").encode("utf-8-sig") - else: - data = text.encode("utf-8") - - fd, name = tempfile.mkstemp(prefix="editor-", suffix=self.extension) - f: t.BinaryIO - - try: - with os.fdopen(fd, "wb") as f: - f.write(data) - - # If the filesystem resolution is 1 second, like Mac OS - # 10.12 Extended, or 2 seconds, like FAT32, and the editor - # closes very fast, require_save can fail. Set the modified - # time to be 2 seconds in the past to work around this. - os.utime(name, (os.path.getatime(name), os.path.getmtime(name) - 2)) - # Depending on the resolution, the exact value might not be - # recorded, so get the new recorded value. - timestamp = os.path.getmtime(name) - - self.edit_file(name) - - if self.require_save and os.path.getmtime(name) == timestamp: - return None - - with open(name, "rb") as f: - rv = f.read() - - if isinstance(text, (bytes, bytearray)): - return rv - - return rv.decode("utf-8-sig").replace("\r\n", "\n") # type: ignore - finally: - os.unlink(name) - - -def open_url(url: str, wait: bool = False, locate: bool = False) -> int: - import subprocess - - def _unquote_file(url: str) -> str: - from urllib.parse import unquote - - if url.startswith("file://"): - url = unquote(url[7:]) - - return url - - if sys.platform == "darwin": - args = ["open"] - if wait: - args.append("-W") - if locate: - args.append("-R") - args.append(_unquote_file(url)) - null = open("/dev/null", "w") - try: - return subprocess.Popen(args, stderr=null).wait() - finally: - null.close() - elif WIN: - if locate: - url = _unquote_file(url) - args = ["explorer", f"/select,{url}"] - else: - args = ["start"] - if wait: - args.append("/WAIT") - args.append("") - args.append(url) - try: - return subprocess.call(args) - except OSError: - # Command not found - return 127 - elif CYGWIN: - if locate: - url = _unquote_file(url) - args = ["cygstart", os.path.dirname(url)] - else: - args = ["cygstart"] - if wait: - args.append("-w") - args.append(url) - try: - return subprocess.call(args) - except OSError: - # Command not found - return 127 - - try: - if locate: - url = os.path.dirname(_unquote_file(url)) or "." - else: - url = _unquote_file(url) - c = subprocess.Popen(["xdg-open", url]) - if wait: - return c.wait() - return 0 - except OSError: - if url.startswith(("http://", "https://")) and not locate and not wait: - import webbrowser - - webbrowser.open(url) - return 0 - return 1 - - -def _translate_ch_to_exc(ch: str) -> t.Optional[BaseException]: - if ch == "\x03": - raise KeyboardInterrupt() - - if ch == "\x04" and not WIN: # Unix-like, Ctrl+D - raise EOFError() - - if ch == "\x1a" and WIN: # Windows, Ctrl+Z - raise EOFError() - - return None - - -if WIN: - import msvcrt - - @contextlib.contextmanager - def raw_terminal() -> t.Iterator[int]: - yield -1 - - def getchar(echo: bool) -> str: - # The function `getch` will return a bytes object corresponding to - # the pressed character. Since Windows 10 build 1803, it will also - # return \x00 when called a second time after pressing a regular key. - # - # `getwch` does not share this probably-bugged behavior. Moreover, it - # returns a Unicode object by default, which is what we want. - # - # Either of these functions will return \x00 or \xe0 to indicate - # a special key, and you need to call the same function again to get - # the "rest" of the code. The fun part is that \u00e0 is - # "latin small letter a with grave", so if you type that on a French - # keyboard, you _also_ get a \xe0. - # E.g., consider the Up arrow. This returns \xe0 and then \x48. The - # resulting Unicode string reads as "a with grave" + "capital H". - # This is indistinguishable from when the user actually types - # "a with grave" and then "capital H". - # - # When \xe0 is returned, we assume it's part of a special-key sequence - # and call `getwch` again, but that means that when the user types - # the \u00e0 character, `getchar` doesn't return until a second - # character is typed. - # The alternative is returning immediately, but that would mess up - # cross-platform handling of arrow keys and others that start with - # \xe0. Another option is using `getch`, but then we can't reliably - # read non-ASCII characters, because return values of `getch` are - # limited to the current 8-bit codepage. - # - # Anyway, Click doesn't claim to do this Right(tm), and using `getwch` - # is doing the right thing in more situations than with `getch`. - func: t.Callable[[], str] - - if echo: - func = msvcrt.getwche # type: ignore - else: - func = msvcrt.getwch # type: ignore - - rv = func() - - if rv in ("\x00", "\xe0"): - # \x00 and \xe0 are control characters that indicate special key, - # see above. - rv += func() - - _translate_ch_to_exc(rv) - return rv - -else: - import termios - import tty - - @contextlib.contextmanager - def raw_terminal() -> t.Iterator[int]: - f: t.Optional[t.TextIO] - fd: int - - if not isatty(sys.stdin): - f = open("/dev/tty") - fd = f.fileno() - else: - fd = sys.stdin.fileno() - f = None - - try: - old_settings = termios.tcgetattr(fd) - - try: - tty.setraw(fd) - yield fd - finally: - termios.tcsetattr(fd, termios.TCSADRAIN, old_settings) - sys.stdout.flush() - - if f is not None: - f.close() - except termios.error: - pass - - def getchar(echo: bool) -> str: - with raw_terminal() as fd: - ch = os.read(fd, 32).decode(get_best_encoding(sys.stdin), "replace") - - if echo and isatty(sys.stdout): - sys.stdout.write(ch) - - _translate_ch_to_exc(ch) - return ch diff --git a/venv/lib/python3.9/site-packages/click/_textwrap.py b/venv/lib/python3.9/site-packages/click/_textwrap.py deleted file mode 100644 index b47dcbd..0000000 --- a/venv/lib/python3.9/site-packages/click/_textwrap.py +++ /dev/null @@ -1,49 +0,0 @@ -import textwrap -import typing as t -from contextlib import contextmanager - - -class TextWrapper(textwrap.TextWrapper): - def _handle_long_word( - self, - reversed_chunks: t.List[str], - cur_line: t.List[str], - cur_len: int, - width: int, - ) -> None: - space_left = max(width - cur_len, 1) - - if self.break_long_words: - last = reversed_chunks[-1] - cut = last[:space_left] - res = last[space_left:] - cur_line.append(cut) - reversed_chunks[-1] = res - elif not cur_line: - cur_line.append(reversed_chunks.pop()) - - @contextmanager - def extra_indent(self, indent: str) -> t.Iterator[None]: - old_initial_indent = self.initial_indent - old_subsequent_indent = self.subsequent_indent - self.initial_indent += indent - self.subsequent_indent += indent - - try: - yield - finally: - self.initial_indent = old_initial_indent - self.subsequent_indent = old_subsequent_indent - - def indent_only(self, text: str) -> str: - rv = [] - - for idx, line in enumerate(text.splitlines()): - indent = self.initial_indent - - if idx > 0: - indent = self.subsequent_indent - - rv.append(f"{indent}{line}") - - return "\n".join(rv) diff --git a/venv/lib/python3.9/site-packages/click/_winconsole.py b/venv/lib/python3.9/site-packages/click/_winconsole.py deleted file mode 100644 index 6b20df3..0000000 --- a/venv/lib/python3.9/site-packages/click/_winconsole.py +++ /dev/null @@ -1,279 +0,0 @@ -# This module is based on the excellent work by Adam Bartoš who -# provided a lot of what went into the implementation here in -# the discussion to issue1602 in the Python bug tracker. -# -# There are some general differences in regards to how this works -# compared to the original patches as we do not need to patch -# the entire interpreter but just work in our little world of -# echo and prompt. -import io -import sys -import time -import typing as t -from ctypes import byref -from ctypes import c_char -from ctypes import c_char_p -from ctypes import c_int -from ctypes import c_ssize_t -from ctypes import c_ulong -from ctypes import c_void_p -from ctypes import POINTER -from ctypes import py_object -from ctypes import Structure -from ctypes.wintypes import DWORD -from ctypes.wintypes import HANDLE -from ctypes.wintypes import LPCWSTR -from ctypes.wintypes import LPWSTR - -from ._compat import _NonClosingTextIOWrapper - -assert sys.platform == "win32" -import msvcrt # noqa: E402 -from ctypes import windll # noqa: E402 -from ctypes import WINFUNCTYPE # noqa: E402 - -c_ssize_p = POINTER(c_ssize_t) - -kernel32 = windll.kernel32 -GetStdHandle = kernel32.GetStdHandle -ReadConsoleW = kernel32.ReadConsoleW -WriteConsoleW = kernel32.WriteConsoleW -GetConsoleMode = kernel32.GetConsoleMode -GetLastError = kernel32.GetLastError -GetCommandLineW = WINFUNCTYPE(LPWSTR)(("GetCommandLineW", windll.kernel32)) -CommandLineToArgvW = WINFUNCTYPE(POINTER(LPWSTR), LPCWSTR, POINTER(c_int))( - ("CommandLineToArgvW", windll.shell32) -) -LocalFree = WINFUNCTYPE(c_void_p, c_void_p)(("LocalFree", windll.kernel32)) - -STDIN_HANDLE = GetStdHandle(-10) -STDOUT_HANDLE = GetStdHandle(-11) -STDERR_HANDLE = GetStdHandle(-12) - -PyBUF_SIMPLE = 0 -PyBUF_WRITABLE = 1 - -ERROR_SUCCESS = 0 -ERROR_NOT_ENOUGH_MEMORY = 8 -ERROR_OPERATION_ABORTED = 995 - -STDIN_FILENO = 0 -STDOUT_FILENO = 1 -STDERR_FILENO = 2 - -EOF = b"\x1a" -MAX_BYTES_WRITTEN = 32767 - -try: - from ctypes import pythonapi -except ImportError: - # On PyPy we cannot get buffers so our ability to operate here is - # severely limited. - get_buffer = None -else: - - class Py_buffer(Structure): - _fields_ = [ - ("buf", c_void_p), - ("obj", py_object), - ("len", c_ssize_t), - ("itemsize", c_ssize_t), - ("readonly", c_int), - ("ndim", c_int), - ("format", c_char_p), - ("shape", c_ssize_p), - ("strides", c_ssize_p), - ("suboffsets", c_ssize_p), - ("internal", c_void_p), - ] - - PyObject_GetBuffer = pythonapi.PyObject_GetBuffer - PyBuffer_Release = pythonapi.PyBuffer_Release - - def get_buffer(obj, writable=False): - buf = Py_buffer() - flags = PyBUF_WRITABLE if writable else PyBUF_SIMPLE - PyObject_GetBuffer(py_object(obj), byref(buf), flags) - - try: - buffer_type = c_char * buf.len - return buffer_type.from_address(buf.buf) - finally: - PyBuffer_Release(byref(buf)) - - -class _WindowsConsoleRawIOBase(io.RawIOBase): - def __init__(self, handle): - self.handle = handle - - def isatty(self): - super().isatty() - return True - - -class _WindowsConsoleReader(_WindowsConsoleRawIOBase): - def readable(self): - return True - - def readinto(self, b): - bytes_to_be_read = len(b) - if not bytes_to_be_read: - return 0 - elif bytes_to_be_read % 2: - raise ValueError( - "cannot read odd number of bytes from UTF-16-LE encoded console" - ) - - buffer = get_buffer(b, writable=True) - code_units_to_be_read = bytes_to_be_read // 2 - code_units_read = c_ulong() - - rv = ReadConsoleW( - HANDLE(self.handle), - buffer, - code_units_to_be_read, - byref(code_units_read), - None, - ) - if GetLastError() == ERROR_OPERATION_ABORTED: - # wait for KeyboardInterrupt - time.sleep(0.1) - if not rv: - raise OSError(f"Windows error: {GetLastError()}") - - if buffer[0] == EOF: - return 0 - return 2 * code_units_read.value - - -class _WindowsConsoleWriter(_WindowsConsoleRawIOBase): - def writable(self): - return True - - @staticmethod - def _get_error_message(errno): - if errno == ERROR_SUCCESS: - return "ERROR_SUCCESS" - elif errno == ERROR_NOT_ENOUGH_MEMORY: - return "ERROR_NOT_ENOUGH_MEMORY" - return f"Windows error {errno}" - - def write(self, b): - bytes_to_be_written = len(b) - buf = get_buffer(b) - code_units_to_be_written = min(bytes_to_be_written, MAX_BYTES_WRITTEN) // 2 - code_units_written = c_ulong() - - WriteConsoleW( - HANDLE(self.handle), - buf, - code_units_to_be_written, - byref(code_units_written), - None, - ) - bytes_written = 2 * code_units_written.value - - if bytes_written == 0 and bytes_to_be_written > 0: - raise OSError(self._get_error_message(GetLastError())) - return bytes_written - - -class ConsoleStream: - def __init__(self, text_stream: t.TextIO, byte_stream: t.BinaryIO) -> None: - self._text_stream = text_stream - self.buffer = byte_stream - - @property - def name(self) -> str: - return self.buffer.name - - def write(self, x: t.AnyStr) -> int: - if isinstance(x, str): - return self._text_stream.write(x) - try: - self.flush() - except Exception: - pass - return self.buffer.write(x) - - def writelines(self, lines: t.Iterable[t.AnyStr]) -> None: - for line in lines: - self.write(line) - - def __getattr__(self, name: str) -> t.Any: - return getattr(self._text_stream, name) - - def isatty(self) -> bool: - return self.buffer.isatty() - - def __repr__(self): - return f"" - - -def _get_text_stdin(buffer_stream: t.BinaryIO) -> t.TextIO: - text_stream = _NonClosingTextIOWrapper( - io.BufferedReader(_WindowsConsoleReader(STDIN_HANDLE)), - "utf-16-le", - "strict", - line_buffering=True, - ) - return t.cast(t.TextIO, ConsoleStream(text_stream, buffer_stream)) - - -def _get_text_stdout(buffer_stream: t.BinaryIO) -> t.TextIO: - text_stream = _NonClosingTextIOWrapper( - io.BufferedWriter(_WindowsConsoleWriter(STDOUT_HANDLE)), - "utf-16-le", - "strict", - line_buffering=True, - ) - return t.cast(t.TextIO, ConsoleStream(text_stream, buffer_stream)) - - -def _get_text_stderr(buffer_stream: t.BinaryIO) -> t.TextIO: - text_stream = _NonClosingTextIOWrapper( - io.BufferedWriter(_WindowsConsoleWriter(STDERR_HANDLE)), - "utf-16-le", - "strict", - line_buffering=True, - ) - return t.cast(t.TextIO, ConsoleStream(text_stream, buffer_stream)) - - -_stream_factories: t.Mapping[int, t.Callable[[t.BinaryIO], t.TextIO]] = { - 0: _get_text_stdin, - 1: _get_text_stdout, - 2: _get_text_stderr, -} - - -def _is_console(f: t.TextIO) -> bool: - if not hasattr(f, "fileno"): - return False - - try: - fileno = f.fileno() - except (OSError, io.UnsupportedOperation): - return False - - handle = msvcrt.get_osfhandle(fileno) - return bool(GetConsoleMode(handle, byref(DWORD()))) - - -def _get_windows_console_stream( - f: t.TextIO, encoding: t.Optional[str], errors: t.Optional[str] -) -> t.Optional[t.TextIO]: - if ( - get_buffer is not None - and encoding in {"utf-16-le", None} - and errors in {"strict", None} - and _is_console(f) - ): - func = _stream_factories.get(f.fileno()) - if func is not None: - b = getattr(f, "buffer", None) - - if b is None: - return None - - return func(b) diff --git a/venv/lib/python3.9/site-packages/click/core.py b/venv/lib/python3.9/site-packages/click/core.py deleted file mode 100644 index e630501..0000000 --- a/venv/lib/python3.9/site-packages/click/core.py +++ /dev/null @@ -1,3047 +0,0 @@ -import enum -import errno -import inspect -import os -import sys -import typing as t -from collections import abc -from contextlib import contextmanager -from contextlib import ExitStack -from functools import update_wrapper -from gettext import gettext as _ -from gettext import ngettext -from itertools import repeat -from types import TracebackType - -from . import types -from .exceptions import Abort -from .exceptions import BadParameter -from .exceptions import ClickException -from .exceptions import Exit -from .exceptions import MissingParameter -from .exceptions import UsageError -from .formatting import HelpFormatter -from .formatting import join_options -from .globals import pop_context -from .globals import push_context -from .parser import _flag_needs_value -from .parser import OptionParser -from .parser import split_opt -from .termui import confirm -from .termui import prompt -from .termui import style -from .utils import _detect_program_name -from .utils import _expand_args -from .utils import echo -from .utils import make_default_short_help -from .utils import make_str -from .utils import PacifyFlushWrapper - -if t.TYPE_CHECKING: - import typing_extensions as te - - from .decorators import HelpOption - from .shell_completion import CompletionItem - -F = t.TypeVar("F", bound=t.Callable[..., t.Any]) -V = t.TypeVar("V") - - -def _complete_visible_commands( - ctx: "Context", incomplete: str -) -> t.Iterator[t.Tuple[str, "Command"]]: - """List all the subcommands of a group that start with the - incomplete value and aren't hidden. - - :param ctx: Invocation context for the group. - :param incomplete: Value being completed. May be empty. - """ - multi = t.cast(MultiCommand, ctx.command) - - for name in multi.list_commands(ctx): - if name.startswith(incomplete): - command = multi.get_command(ctx, name) - - if command is not None and not command.hidden: - yield name, command - - -def _check_multicommand( - base_command: "MultiCommand", cmd_name: str, cmd: "Command", register: bool = False -) -> None: - if not base_command.chain or not isinstance(cmd, MultiCommand): - return - if register: - hint = ( - "It is not possible to add multi commands as children to" - " another multi command that is in chain mode." - ) - else: - hint = ( - "Found a multi command as subcommand to a multi command" - " that is in chain mode. This is not supported." - ) - raise RuntimeError( - f"{hint}. Command {base_command.name!r} is set to chain and" - f" {cmd_name!r} was added as a subcommand but it in itself is a" - f" multi command. ({cmd_name!r} is a {type(cmd).__name__}" - f" within a chained {type(base_command).__name__} named" - f" {base_command.name!r})." - ) - - -def batch(iterable: t.Iterable[V], batch_size: int) -> t.List[t.Tuple[V, ...]]: - return list(zip(*repeat(iter(iterable), batch_size))) - - -@contextmanager -def augment_usage_errors( - ctx: "Context", param: t.Optional["Parameter"] = None -) -> t.Iterator[None]: - """Context manager that attaches extra information to exceptions.""" - try: - yield - except BadParameter as e: - if e.ctx is None: - e.ctx = ctx - if param is not None and e.param is None: - e.param = param - raise - except UsageError as e: - if e.ctx is None: - e.ctx = ctx - raise - - -def iter_params_for_processing( - invocation_order: t.Sequence["Parameter"], - declaration_order: t.Sequence["Parameter"], -) -> t.List["Parameter"]: - """Returns all declared parameters in the order they should be processed. - - The declared parameters are re-shuffled depending on the order in which - they were invoked, as well as the eagerness of each parameters. - - The invocation order takes precedence over the declaration order. I.e. the - order in which the user provided them to the CLI is respected. - - This behavior and its effect on callback evaluation is detailed at: - https://click.palletsprojects.com/en/stable/advanced/#callback-evaluation-order - """ - - def sort_key(item: "Parameter") -> t.Tuple[bool, float]: - try: - idx: float = invocation_order.index(item) - except ValueError: - idx = float("inf") - - return not item.is_eager, idx - - return sorted(declaration_order, key=sort_key) - - -class ParameterSource(enum.Enum): - """This is an :class:`~enum.Enum` that indicates the source of a - parameter's value. - - Use :meth:`click.Context.get_parameter_source` to get the - source for a parameter by name. - - .. versionchanged:: 8.0 - Use :class:`~enum.Enum` and drop the ``validate`` method. - - .. versionchanged:: 8.0 - Added the ``PROMPT`` value. - """ - - COMMANDLINE = enum.auto() - """The value was provided by the command line args.""" - ENVIRONMENT = enum.auto() - """The value was provided with an environment variable.""" - DEFAULT = enum.auto() - """Used the default specified by the parameter.""" - DEFAULT_MAP = enum.auto() - """Used a default provided by :attr:`Context.default_map`.""" - PROMPT = enum.auto() - """Used a prompt to confirm a default or provide a value.""" - - -class Context: - """The context is a special internal object that holds state relevant - for the script execution at every single level. It's normally invisible - to commands unless they opt-in to getting access to it. - - The context is useful as it can pass internal objects around and can - control special execution features such as reading data from - environment variables. - - A context can be used as context manager in which case it will call - :meth:`close` on teardown. - - :param command: the command class for this context. - :param parent: the parent context. - :param info_name: the info name for this invocation. Generally this - is the most descriptive name for the script or - command. For the toplevel script it is usually - the name of the script, for commands below it it's - the name of the script. - :param obj: an arbitrary object of user data. - :param auto_envvar_prefix: the prefix to use for automatic environment - variables. If this is `None` then reading - from environment variables is disabled. This - does not affect manually set environment - variables which are always read. - :param default_map: a dictionary (like object) with default values - for parameters. - :param terminal_width: the width of the terminal. The default is - inherit from parent context. If no context - defines the terminal width then auto - detection will be applied. - :param max_content_width: the maximum width for content rendered by - Click (this currently only affects help - pages). This defaults to 80 characters if - not overridden. In other words: even if the - terminal is larger than that, Click will not - format things wider than 80 characters by - default. In addition to that, formatters might - add some safety mapping on the right. - :param resilient_parsing: if this flag is enabled then Click will - parse without any interactivity or callback - invocation. Default values will also be - ignored. This is useful for implementing - things such as completion support. - :param allow_extra_args: if this is set to `True` then extra arguments - at the end will not raise an error and will be - kept on the context. The default is to inherit - from the command. - :param allow_interspersed_args: if this is set to `False` then options - and arguments cannot be mixed. The - default is to inherit from the command. - :param ignore_unknown_options: instructs click to ignore options it does - not know and keeps them for later - processing. - :param help_option_names: optionally a list of strings that define how - the default help parameter is named. The - default is ``['--help']``. - :param token_normalize_func: an optional function that is used to - normalize tokens (options, choices, - etc.). This for instance can be used to - implement case insensitive behavior. - :param color: controls if the terminal supports ANSI colors or not. The - default is autodetection. This is only needed if ANSI - codes are used in texts that Click prints which is by - default not the case. This for instance would affect - help output. - :param show_default: Show the default value for commands. If this - value is not set, it defaults to the value from the parent - context. ``Command.show_default`` overrides this default for the - specific command. - - .. versionchanged:: 8.1 - The ``show_default`` parameter is overridden by - ``Command.show_default``, instead of the other way around. - - .. versionchanged:: 8.0 - The ``show_default`` parameter defaults to the value from the - parent context. - - .. versionchanged:: 7.1 - Added the ``show_default`` parameter. - - .. versionchanged:: 4.0 - Added the ``color``, ``ignore_unknown_options``, and - ``max_content_width`` parameters. - - .. versionchanged:: 3.0 - Added the ``allow_extra_args`` and ``allow_interspersed_args`` - parameters. - - .. versionchanged:: 2.0 - Added the ``resilient_parsing``, ``help_option_names``, and - ``token_normalize_func`` parameters. - """ - - #: The formatter class to create with :meth:`make_formatter`. - #: - #: .. versionadded:: 8.0 - formatter_class: t.Type["HelpFormatter"] = HelpFormatter - - def __init__( - self, - command: "Command", - parent: t.Optional["Context"] = None, - info_name: t.Optional[str] = None, - obj: t.Optional[t.Any] = None, - auto_envvar_prefix: t.Optional[str] = None, - default_map: t.Optional[t.MutableMapping[str, t.Any]] = None, - terminal_width: t.Optional[int] = None, - max_content_width: t.Optional[int] = None, - resilient_parsing: bool = False, - allow_extra_args: t.Optional[bool] = None, - allow_interspersed_args: t.Optional[bool] = None, - ignore_unknown_options: t.Optional[bool] = None, - help_option_names: t.Optional[t.List[str]] = None, - token_normalize_func: t.Optional[t.Callable[[str], str]] = None, - color: t.Optional[bool] = None, - show_default: t.Optional[bool] = None, - ) -> None: - #: the parent context or `None` if none exists. - self.parent = parent - #: the :class:`Command` for this context. - self.command = command - #: the descriptive information name - self.info_name = info_name - #: Map of parameter names to their parsed values. Parameters - #: with ``expose_value=False`` are not stored. - self.params: t.Dict[str, t.Any] = {} - #: the leftover arguments. - self.args: t.List[str] = [] - #: protected arguments. These are arguments that are prepended - #: to `args` when certain parsing scenarios are encountered but - #: must be never propagated to another arguments. This is used - #: to implement nested parsing. - self.protected_args: t.List[str] = [] - #: the collected prefixes of the command's options. - self._opt_prefixes: t.Set[str] = set(parent._opt_prefixes) if parent else set() - - if obj is None and parent is not None: - obj = parent.obj - - #: the user object stored. - self.obj: t.Any = obj - self._meta: t.Dict[str, t.Any] = getattr(parent, "meta", {}) - - #: A dictionary (-like object) with defaults for parameters. - if ( - default_map is None - and info_name is not None - and parent is not None - and parent.default_map is not None - ): - default_map = parent.default_map.get(info_name) - - self.default_map: t.Optional[t.MutableMapping[str, t.Any]] = default_map - - #: This flag indicates if a subcommand is going to be executed. A - #: group callback can use this information to figure out if it's - #: being executed directly or because the execution flow passes - #: onwards to a subcommand. By default it's None, but it can be - #: the name of the subcommand to execute. - #: - #: If chaining is enabled this will be set to ``'*'`` in case - #: any commands are executed. It is however not possible to - #: figure out which ones. If you require this knowledge you - #: should use a :func:`result_callback`. - self.invoked_subcommand: t.Optional[str] = None - - if terminal_width is None and parent is not None: - terminal_width = parent.terminal_width - - #: The width of the terminal (None is autodetection). - self.terminal_width: t.Optional[int] = terminal_width - - if max_content_width is None and parent is not None: - max_content_width = parent.max_content_width - - #: The maximum width of formatted content (None implies a sensible - #: default which is 80 for most things). - self.max_content_width: t.Optional[int] = max_content_width - - if allow_extra_args is None: - allow_extra_args = command.allow_extra_args - - #: Indicates if the context allows extra args or if it should - #: fail on parsing. - #: - #: .. versionadded:: 3.0 - self.allow_extra_args = allow_extra_args - - if allow_interspersed_args is None: - allow_interspersed_args = command.allow_interspersed_args - - #: Indicates if the context allows mixing of arguments and - #: options or not. - #: - #: .. versionadded:: 3.0 - self.allow_interspersed_args: bool = allow_interspersed_args - - if ignore_unknown_options is None: - ignore_unknown_options = command.ignore_unknown_options - - #: Instructs click to ignore options that a command does not - #: understand and will store it on the context for later - #: processing. This is primarily useful for situations where you - #: want to call into external programs. Generally this pattern is - #: strongly discouraged because it's not possibly to losslessly - #: forward all arguments. - #: - #: .. versionadded:: 4.0 - self.ignore_unknown_options: bool = ignore_unknown_options - - if help_option_names is None: - if parent is not None: - help_option_names = parent.help_option_names - else: - help_option_names = ["--help"] - - #: The names for the help options. - self.help_option_names: t.List[str] = help_option_names - - if token_normalize_func is None and parent is not None: - token_normalize_func = parent.token_normalize_func - - #: An optional normalization function for tokens. This is - #: options, choices, commands etc. - self.token_normalize_func: t.Optional[t.Callable[[str], str]] = ( - token_normalize_func - ) - - #: Indicates if resilient parsing is enabled. In that case Click - #: will do its best to not cause any failures and default values - #: will be ignored. Useful for completion. - self.resilient_parsing: bool = resilient_parsing - - # If there is no envvar prefix yet, but the parent has one and - # the command on this level has a name, we can expand the envvar - # prefix automatically. - if auto_envvar_prefix is None: - if ( - parent is not None - and parent.auto_envvar_prefix is not None - and self.info_name is not None - ): - auto_envvar_prefix = ( - f"{parent.auto_envvar_prefix}_{self.info_name.upper()}" - ) - else: - auto_envvar_prefix = auto_envvar_prefix.upper() - - if auto_envvar_prefix is not None: - auto_envvar_prefix = auto_envvar_prefix.replace("-", "_") - - self.auto_envvar_prefix: t.Optional[str] = auto_envvar_prefix - - if color is None and parent is not None: - color = parent.color - - #: Controls if styling output is wanted or not. - self.color: t.Optional[bool] = color - - if show_default is None and parent is not None: - show_default = parent.show_default - - #: Show option default values when formatting help text. - self.show_default: t.Optional[bool] = show_default - - self._close_callbacks: t.List[t.Callable[[], t.Any]] = [] - self._depth = 0 - self._parameter_source: t.Dict[str, ParameterSource] = {} - self._exit_stack = ExitStack() - - def to_info_dict(self) -> t.Dict[str, t.Any]: - """Gather information that could be useful for a tool generating - user-facing documentation. This traverses the entire CLI - structure. - - .. code-block:: python - - with Context(cli) as ctx: - info = ctx.to_info_dict() - - .. versionadded:: 8.0 - """ - return { - "command": self.command.to_info_dict(self), - "info_name": self.info_name, - "allow_extra_args": self.allow_extra_args, - "allow_interspersed_args": self.allow_interspersed_args, - "ignore_unknown_options": self.ignore_unknown_options, - "auto_envvar_prefix": self.auto_envvar_prefix, - } - - def __enter__(self) -> "Context": - self._depth += 1 - push_context(self) - return self - - def __exit__( - self, - exc_type: t.Optional[t.Type[BaseException]], - exc_value: t.Optional[BaseException], - tb: t.Optional[TracebackType], - ) -> None: - self._depth -= 1 - if self._depth == 0: - self.close() - pop_context() - - @contextmanager - def scope(self, cleanup: bool = True) -> t.Iterator["Context"]: - """This helper method can be used with the context object to promote - it to the current thread local (see :func:`get_current_context`). - The default behavior of this is to invoke the cleanup functions which - can be disabled by setting `cleanup` to `False`. The cleanup - functions are typically used for things such as closing file handles. - - If the cleanup is intended the context object can also be directly - used as a context manager. - - Example usage:: - - with ctx.scope(): - assert get_current_context() is ctx - - This is equivalent:: - - with ctx: - assert get_current_context() is ctx - - .. versionadded:: 5.0 - - :param cleanup: controls if the cleanup functions should be run or - not. The default is to run these functions. In - some situations the context only wants to be - temporarily pushed in which case this can be disabled. - Nested pushes automatically defer the cleanup. - """ - if not cleanup: - self._depth += 1 - try: - with self as rv: - yield rv - finally: - if not cleanup: - self._depth -= 1 - - @property - def meta(self) -> t.Dict[str, t.Any]: - """This is a dictionary which is shared with all the contexts - that are nested. It exists so that click utilities can store some - state here if they need to. It is however the responsibility of - that code to manage this dictionary well. - - The keys are supposed to be unique dotted strings. For instance - module paths are a good choice for it. What is stored in there is - irrelevant for the operation of click. However what is important is - that code that places data here adheres to the general semantics of - the system. - - Example usage:: - - LANG_KEY = f'{__name__}.lang' - - def set_language(value): - ctx = get_current_context() - ctx.meta[LANG_KEY] = value - - def get_language(): - return get_current_context().meta.get(LANG_KEY, 'en_US') - - .. versionadded:: 5.0 - """ - return self._meta - - def make_formatter(self) -> HelpFormatter: - """Creates the :class:`~click.HelpFormatter` for the help and - usage output. - - To quickly customize the formatter class used without overriding - this method, set the :attr:`formatter_class` attribute. - - .. versionchanged:: 8.0 - Added the :attr:`formatter_class` attribute. - """ - return self.formatter_class( - width=self.terminal_width, max_width=self.max_content_width - ) - - def with_resource(self, context_manager: t.ContextManager[V]) -> V: - """Register a resource as if it were used in a ``with`` - statement. The resource will be cleaned up when the context is - popped. - - Uses :meth:`contextlib.ExitStack.enter_context`. It calls the - resource's ``__enter__()`` method and returns the result. When - the context is popped, it closes the stack, which calls the - resource's ``__exit__()`` method. - - To register a cleanup function for something that isn't a - context manager, use :meth:`call_on_close`. Or use something - from :mod:`contextlib` to turn it into a context manager first. - - .. code-block:: python - - @click.group() - @click.option("--name") - @click.pass_context - def cli(ctx): - ctx.obj = ctx.with_resource(connect_db(name)) - - :param context_manager: The context manager to enter. - :return: Whatever ``context_manager.__enter__()`` returns. - - .. versionadded:: 8.0 - """ - return self._exit_stack.enter_context(context_manager) - - def call_on_close(self, f: t.Callable[..., t.Any]) -> t.Callable[..., t.Any]: - """Register a function to be called when the context tears down. - - This can be used to close resources opened during the script - execution. Resources that support Python's context manager - protocol which would be used in a ``with`` statement should be - registered with :meth:`with_resource` instead. - - :param f: The function to execute on teardown. - """ - return self._exit_stack.callback(f) - - def close(self) -> None: - """Invoke all close callbacks registered with - :meth:`call_on_close`, and exit all context managers entered - with :meth:`with_resource`. - """ - self._exit_stack.close() - # In case the context is reused, create a new exit stack. - self._exit_stack = ExitStack() - - @property - def command_path(self) -> str: - """The computed command path. This is used for the ``usage`` - information on the help page. It's automatically created by - combining the info names of the chain of contexts to the root. - """ - rv = "" - if self.info_name is not None: - rv = self.info_name - if self.parent is not None: - parent_command_path = [self.parent.command_path] - - if isinstance(self.parent.command, Command): - for param in self.parent.command.get_params(self): - parent_command_path.extend(param.get_usage_pieces(self)) - - rv = f"{' '.join(parent_command_path)} {rv}" - return rv.lstrip() - - def find_root(self) -> "Context": - """Finds the outermost context.""" - node = self - while node.parent is not None: - node = node.parent - return node - - def find_object(self, object_type: t.Type[V]) -> t.Optional[V]: - """Finds the closest object of a given type.""" - node: t.Optional[Context] = self - - while node is not None: - if isinstance(node.obj, object_type): - return node.obj - - node = node.parent - - return None - - def ensure_object(self, object_type: t.Type[V]) -> V: - """Like :meth:`find_object` but sets the innermost object to a - new instance of `object_type` if it does not exist. - """ - rv = self.find_object(object_type) - if rv is None: - self.obj = rv = object_type() - return rv - - @t.overload - def lookup_default( - self, name: str, call: "te.Literal[True]" = True - ) -> t.Optional[t.Any]: ... - - @t.overload - def lookup_default( - self, name: str, call: "te.Literal[False]" = ... - ) -> t.Optional[t.Union[t.Any, t.Callable[[], t.Any]]]: ... - - def lookup_default(self, name: str, call: bool = True) -> t.Optional[t.Any]: - """Get the default for a parameter from :attr:`default_map`. - - :param name: Name of the parameter. - :param call: If the default is a callable, call it. Disable to - return the callable instead. - - .. versionchanged:: 8.0 - Added the ``call`` parameter. - """ - if self.default_map is not None: - value = self.default_map.get(name) - - if call and callable(value): - return value() - - return value - - return None - - def fail(self, message: str) -> "te.NoReturn": - """Aborts the execution of the program with a specific error - message. - - :param message: the error message to fail with. - """ - raise UsageError(message, self) - - def abort(self) -> "te.NoReturn": - """Aborts the script.""" - raise Abort() - - def exit(self, code: int = 0) -> "te.NoReturn": - """Exits the application with a given exit code.""" - raise Exit(code) - - def get_usage(self) -> str: - """Helper method to get formatted usage string for the current - context and command. - """ - return self.command.get_usage(self) - - def get_help(self) -> str: - """Helper method to get formatted help page for the current - context and command. - """ - return self.command.get_help(self) - - def _make_sub_context(self, command: "Command") -> "Context": - """Create a new context of the same type as this context, but - for a new command. - - :meta private: - """ - return type(self)(command, info_name=command.name, parent=self) - - @t.overload - def invoke( - __self, - __callback: "t.Callable[..., V]", - *args: t.Any, - **kwargs: t.Any, - ) -> V: ... - - @t.overload - def invoke( - __self, - __callback: "Command", - *args: t.Any, - **kwargs: t.Any, - ) -> t.Any: ... - - def invoke( - __self, - __callback: t.Union["Command", "t.Callable[..., V]"], - *args: t.Any, - **kwargs: t.Any, - ) -> t.Union[t.Any, V]: - """Invokes a command callback in exactly the way it expects. There - are two ways to invoke this method: - - 1. the first argument can be a callback and all other arguments and - keyword arguments are forwarded directly to the function. - 2. the first argument is a click command object. In that case all - arguments are forwarded as well but proper click parameters - (options and click arguments) must be keyword arguments and Click - will fill in defaults. - - Note that before Click 3.2 keyword arguments were not properly filled - in against the intention of this code and no context was created. For - more information about this change and why it was done in a bugfix - release see :ref:`upgrade-to-3.2`. - - .. versionchanged:: 8.0 - All ``kwargs`` are tracked in :attr:`params` so they will be - passed if :meth:`forward` is called at multiple levels. - """ - if isinstance(__callback, Command): - other_cmd = __callback - - if other_cmd.callback is None: - raise TypeError( - "The given command does not have a callback that can be invoked." - ) - else: - __callback = t.cast("t.Callable[..., V]", other_cmd.callback) - - ctx = __self._make_sub_context(other_cmd) - - for param in other_cmd.params: - if param.name not in kwargs and param.expose_value: - kwargs[param.name] = param.type_cast_value( # type: ignore - ctx, param.get_default(ctx) - ) - - # Track all kwargs as params, so that forward() will pass - # them on in subsequent calls. - ctx.params.update(kwargs) - else: - ctx = __self - - with augment_usage_errors(__self): - with ctx: - return __callback(*args, **kwargs) - - def forward(__self, __cmd: "Command", *args: t.Any, **kwargs: t.Any) -> t.Any: - """Similar to :meth:`invoke` but fills in default keyword - arguments from the current context if the other command expects - it. This cannot invoke callbacks directly, only other commands. - - .. versionchanged:: 8.0 - All ``kwargs`` are tracked in :attr:`params` so they will be - passed if ``forward`` is called at multiple levels. - """ - # Can only forward to other commands, not direct callbacks. - if not isinstance(__cmd, Command): - raise TypeError("Callback is not a command.") - - for param in __self.params: - if param not in kwargs: - kwargs[param] = __self.params[param] - - return __self.invoke(__cmd, *args, **kwargs) - - def set_parameter_source(self, name: str, source: ParameterSource) -> None: - """Set the source of a parameter. This indicates the location - from which the value of the parameter was obtained. - - :param name: The name of the parameter. - :param source: A member of :class:`~click.core.ParameterSource`. - """ - self._parameter_source[name] = source - - def get_parameter_source(self, name: str) -> t.Optional[ParameterSource]: - """Get the source of a parameter. This indicates the location - from which the value of the parameter was obtained. - - This can be useful for determining when a user specified a value - on the command line that is the same as the default value. It - will be :attr:`~click.core.ParameterSource.DEFAULT` only if the - value was actually taken from the default. - - :param name: The name of the parameter. - :rtype: ParameterSource - - .. versionchanged:: 8.0 - Returns ``None`` if the parameter was not provided from any - source. - """ - return self._parameter_source.get(name) - - -class BaseCommand: - """The base command implements the minimal API contract of commands. - Most code will never use this as it does not implement a lot of useful - functionality but it can act as the direct subclass of alternative - parsing methods that do not depend on the Click parser. - - For instance, this can be used to bridge Click and other systems like - argparse or docopt. - - Because base commands do not implement a lot of the API that other - parts of Click take for granted, they are not supported for all - operations. For instance, they cannot be used with the decorators - usually and they have no built-in callback system. - - .. versionchanged:: 2.0 - Added the `context_settings` parameter. - - :param name: the name of the command to use unless a group overrides it. - :param context_settings: an optional dictionary with defaults that are - passed to the context object. - """ - - #: The context class to create with :meth:`make_context`. - #: - #: .. versionadded:: 8.0 - context_class: t.Type[Context] = Context - #: the default for the :attr:`Context.allow_extra_args` flag. - allow_extra_args = False - #: the default for the :attr:`Context.allow_interspersed_args` flag. - allow_interspersed_args = True - #: the default for the :attr:`Context.ignore_unknown_options` flag. - ignore_unknown_options = False - - def __init__( - self, - name: t.Optional[str], - context_settings: t.Optional[t.MutableMapping[str, t.Any]] = None, - ) -> None: - #: the name the command thinks it has. Upon registering a command - #: on a :class:`Group` the group will default the command name - #: with this information. You should instead use the - #: :class:`Context`\'s :attr:`~Context.info_name` attribute. - self.name = name - - if context_settings is None: - context_settings = {} - - #: an optional dictionary with defaults passed to the context. - self.context_settings: t.MutableMapping[str, t.Any] = context_settings - - def to_info_dict(self, ctx: Context) -> t.Dict[str, t.Any]: - """Gather information that could be useful for a tool generating - user-facing documentation. This traverses the entire structure - below this command. - - Use :meth:`click.Context.to_info_dict` to traverse the entire - CLI structure. - - :param ctx: A :class:`Context` representing this command. - - .. versionadded:: 8.0 - """ - return {"name": self.name} - - def __repr__(self) -> str: - return f"<{self.__class__.__name__} {self.name}>" - - def get_usage(self, ctx: Context) -> str: - raise NotImplementedError("Base commands cannot get usage") - - def get_help(self, ctx: Context) -> str: - raise NotImplementedError("Base commands cannot get help") - - def make_context( - self, - info_name: t.Optional[str], - args: t.List[str], - parent: t.Optional[Context] = None, - **extra: t.Any, - ) -> Context: - """This function when given an info name and arguments will kick - off the parsing and create a new :class:`Context`. It does not - invoke the actual command callback though. - - To quickly customize the context class used without overriding - this method, set the :attr:`context_class` attribute. - - :param info_name: the info name for this invocation. Generally this - is the most descriptive name for the script or - command. For the toplevel script it's usually - the name of the script, for commands below it's - the name of the command. - :param args: the arguments to parse as list of strings. - :param parent: the parent context if available. - :param extra: extra keyword arguments forwarded to the context - constructor. - - .. versionchanged:: 8.0 - Added the :attr:`context_class` attribute. - """ - for key, value in self.context_settings.items(): - if key not in extra: - extra[key] = value - - ctx = self.context_class( - self, # type: ignore[arg-type] - info_name=info_name, - parent=parent, - **extra, - ) - - with ctx.scope(cleanup=False): - self.parse_args(ctx, args) - return ctx - - def parse_args(self, ctx: Context, args: t.List[str]) -> t.List[str]: - """Given a context and a list of arguments this creates the parser - and parses the arguments, then modifies the context as necessary. - This is automatically invoked by :meth:`make_context`. - """ - raise NotImplementedError("Base commands do not know how to parse arguments.") - - def invoke(self, ctx: Context) -> t.Any: - """Given a context, this invokes the command. The default - implementation is raising a not implemented error. - """ - raise NotImplementedError("Base commands are not invocable by default") - - def shell_complete(self, ctx: Context, incomplete: str) -> t.List["CompletionItem"]: - """Return a list of completions for the incomplete value. Looks - at the names of chained multi-commands. - - Any command could be part of a chained multi-command, so sibling - commands are valid at any point during command completion. Other - command classes will return more completions. - - :param ctx: Invocation context for this command. - :param incomplete: Value being completed. May be empty. - - .. versionadded:: 8.0 - """ - from click.shell_completion import CompletionItem - - results: t.List[CompletionItem] = [] - - while ctx.parent is not None: - ctx = ctx.parent - - if isinstance(ctx.command, MultiCommand) and ctx.command.chain: - results.extend( - CompletionItem(name, help=command.get_short_help_str()) - for name, command in _complete_visible_commands(ctx, incomplete) - if name not in ctx.protected_args - ) - - return results - - @t.overload - def main( - self, - args: t.Optional[t.Sequence[str]] = None, - prog_name: t.Optional[str] = None, - complete_var: t.Optional[str] = None, - standalone_mode: "te.Literal[True]" = True, - **extra: t.Any, - ) -> "te.NoReturn": ... - - @t.overload - def main( - self, - args: t.Optional[t.Sequence[str]] = None, - prog_name: t.Optional[str] = None, - complete_var: t.Optional[str] = None, - standalone_mode: bool = ..., - **extra: t.Any, - ) -> t.Any: ... - - def main( - self, - args: t.Optional[t.Sequence[str]] = None, - prog_name: t.Optional[str] = None, - complete_var: t.Optional[str] = None, - standalone_mode: bool = True, - windows_expand_args: bool = True, - **extra: t.Any, - ) -> t.Any: - """This is the way to invoke a script with all the bells and - whistles as a command line application. This will always terminate - the application after a call. If this is not wanted, ``SystemExit`` - needs to be caught. - - This method is also available by directly calling the instance of - a :class:`Command`. - - :param args: the arguments that should be used for parsing. If not - provided, ``sys.argv[1:]`` is used. - :param prog_name: the program name that should be used. By default - the program name is constructed by taking the file - name from ``sys.argv[0]``. - :param complete_var: the environment variable that controls the - bash completion support. The default is - ``"__COMPLETE"`` with prog_name in - uppercase. - :param standalone_mode: the default behavior is to invoke the script - in standalone mode. Click will then - handle exceptions and convert them into - error messages and the function will never - return but shut down the interpreter. If - this is set to `False` they will be - propagated to the caller and the return - value of this function is the return value - of :meth:`invoke`. - :param windows_expand_args: Expand glob patterns, user dir, and - env vars in command line args on Windows. - :param extra: extra keyword arguments are forwarded to the context - constructor. See :class:`Context` for more information. - - .. versionchanged:: 8.0.1 - Added the ``windows_expand_args`` parameter to allow - disabling command line arg expansion on Windows. - - .. versionchanged:: 8.0 - When taking arguments from ``sys.argv`` on Windows, glob - patterns, user dir, and env vars are expanded. - - .. versionchanged:: 3.0 - Added the ``standalone_mode`` parameter. - """ - if args is None: - args = sys.argv[1:] - - if os.name == "nt" and windows_expand_args: - args = _expand_args(args) - else: - args = list(args) - - if prog_name is None: - prog_name = _detect_program_name() - - # Process shell completion requests and exit early. - self._main_shell_completion(extra, prog_name, complete_var) - - try: - try: - with self.make_context(prog_name, args, **extra) as ctx: - rv = self.invoke(ctx) - if not standalone_mode: - return rv - # it's not safe to `ctx.exit(rv)` here! - # note that `rv` may actually contain data like "1" which - # has obvious effects - # more subtle case: `rv=[None, None]` can come out of - # chained commands which all returned `None` -- so it's not - # even always obvious that `rv` indicates success/failure - # by its truthiness/falsiness - ctx.exit() - except (EOFError, KeyboardInterrupt) as e: - echo(file=sys.stderr) - raise Abort() from e - except ClickException as e: - if not standalone_mode: - raise - e.show() - sys.exit(e.exit_code) - except OSError as e: - if e.errno == errno.EPIPE: - sys.stdout = t.cast(t.TextIO, PacifyFlushWrapper(sys.stdout)) - sys.stderr = t.cast(t.TextIO, PacifyFlushWrapper(sys.stderr)) - sys.exit(1) - else: - raise - except Exit as e: - if standalone_mode: - sys.exit(e.exit_code) - else: - # in non-standalone mode, return the exit code - # note that this is only reached if `self.invoke` above raises - # an Exit explicitly -- thus bypassing the check there which - # would return its result - # the results of non-standalone execution may therefore be - # somewhat ambiguous: if there are codepaths which lead to - # `ctx.exit(1)` and to `return 1`, the caller won't be able to - # tell the difference between the two - return e.exit_code - except Abort: - if not standalone_mode: - raise - echo(_("Aborted!"), file=sys.stderr) - sys.exit(1) - - def _main_shell_completion( - self, - ctx_args: t.MutableMapping[str, t.Any], - prog_name: str, - complete_var: t.Optional[str] = None, - ) -> None: - """Check if the shell is asking for tab completion, process - that, then exit early. Called from :meth:`main` before the - program is invoked. - - :param prog_name: Name of the executable in the shell. - :param complete_var: Name of the environment variable that holds - the completion instruction. Defaults to - ``_{PROG_NAME}_COMPLETE``. - - .. versionchanged:: 8.2.0 - Dots (``.``) in ``prog_name`` are replaced with underscores (``_``). - """ - if complete_var is None: - complete_name = prog_name.replace("-", "_").replace(".", "_") - complete_var = f"_{complete_name}_COMPLETE".upper() - - instruction = os.environ.get(complete_var) - - if not instruction: - return - - from .shell_completion import shell_complete - - rv = shell_complete(self, ctx_args, prog_name, complete_var, instruction) - sys.exit(rv) - - def __call__(self, *args: t.Any, **kwargs: t.Any) -> t.Any: - """Alias for :meth:`main`.""" - return self.main(*args, **kwargs) - - -class Command(BaseCommand): - """Commands are the basic building block of command line interfaces in - Click. A basic command handles command line parsing and might dispatch - more parsing to commands nested below it. - - :param name: the name of the command to use unless a group overrides it. - :param context_settings: an optional dictionary with defaults that are - passed to the context object. - :param callback: the callback to invoke. This is optional. - :param params: the parameters to register with this command. This can - be either :class:`Option` or :class:`Argument` objects. - :param help: the help string to use for this command. - :param epilog: like the help string but it's printed at the end of the - help page after everything else. - :param short_help: the short help to use for this command. This is - shown on the command listing of the parent command. - :param add_help_option: by default each command registers a ``--help`` - option. This can be disabled by this parameter. - :param no_args_is_help: this controls what happens if no arguments are - provided. This option is disabled by default. - If enabled this will add ``--help`` as argument - if no arguments are passed - :param hidden: hide this command from help outputs. - - :param deprecated: issues a message indicating that - the command is deprecated. - - .. versionchanged:: 8.1 - ``help``, ``epilog``, and ``short_help`` are stored unprocessed, - all formatting is done when outputting help text, not at init, - and is done even if not using the ``@command`` decorator. - - .. versionchanged:: 8.0 - Added a ``repr`` showing the command name. - - .. versionchanged:: 7.1 - Added the ``no_args_is_help`` parameter. - - .. versionchanged:: 2.0 - Added the ``context_settings`` parameter. - """ - - def __init__( - self, - name: t.Optional[str], - context_settings: t.Optional[t.MutableMapping[str, t.Any]] = None, - callback: t.Optional[t.Callable[..., t.Any]] = None, - params: t.Optional[t.List["Parameter"]] = None, - help: t.Optional[str] = None, - epilog: t.Optional[str] = None, - short_help: t.Optional[str] = None, - options_metavar: t.Optional[str] = "[OPTIONS]", - add_help_option: bool = True, - no_args_is_help: bool = False, - hidden: bool = False, - deprecated: bool = False, - ) -> None: - super().__init__(name, context_settings) - #: the callback to execute when the command fires. This might be - #: `None` in which case nothing happens. - self.callback = callback - #: the list of parameters for this command in the order they - #: should show up in the help page and execute. Eager parameters - #: will automatically be handled before non eager ones. - self.params: t.List[Parameter] = params or [] - self.help = help - self.epilog = epilog - self.options_metavar = options_metavar - self.short_help = short_help - self.add_help_option = add_help_option - self._help_option: t.Optional[HelpOption] = None - self.no_args_is_help = no_args_is_help - self.hidden = hidden - self.deprecated = deprecated - - def to_info_dict(self, ctx: Context) -> t.Dict[str, t.Any]: - info_dict = super().to_info_dict(ctx) - info_dict.update( - params=[param.to_info_dict() for param in self.get_params(ctx)], - help=self.help, - epilog=self.epilog, - short_help=self.short_help, - hidden=self.hidden, - deprecated=self.deprecated, - ) - return info_dict - - def get_usage(self, ctx: Context) -> str: - """Formats the usage line into a string and returns it. - - Calls :meth:`format_usage` internally. - """ - formatter = ctx.make_formatter() - self.format_usage(ctx, formatter) - return formatter.getvalue().rstrip("\n") - - def get_params(self, ctx: Context) -> t.List["Parameter"]: - rv = self.params - help_option = self.get_help_option(ctx) - - if help_option is not None: - rv = [*rv, help_option] - - return rv - - def format_usage(self, ctx: Context, formatter: HelpFormatter) -> None: - """Writes the usage line into the formatter. - - This is a low-level method called by :meth:`get_usage`. - """ - pieces = self.collect_usage_pieces(ctx) - formatter.write_usage(ctx.command_path, " ".join(pieces)) - - def collect_usage_pieces(self, ctx: Context) -> t.List[str]: - """Returns all the pieces that go into the usage line and returns - it as a list of strings. - """ - rv = [self.options_metavar] if self.options_metavar else [] - - for param in self.get_params(ctx): - rv.extend(param.get_usage_pieces(ctx)) - - return rv - - def get_help_option_names(self, ctx: Context) -> t.List[str]: - """Returns the names for the help option.""" - all_names = set(ctx.help_option_names) - for param in self.params: - all_names.difference_update(param.opts) - all_names.difference_update(param.secondary_opts) - return list(all_names) - - def get_help_option(self, ctx: Context) -> t.Optional["Option"]: - """Returns the help option object. - - Unless ``add_help_option`` is ``False``. - - .. versionchanged:: 8.1.8 - The help option is now cached to avoid creating it multiple times. - """ - help_options = self.get_help_option_names(ctx) - - if not help_options or not self.add_help_option: - return None - - # Cache the help option object in private _help_option attribute to - # avoid creating it multiple times. Not doing this will break the - # callback odering by iter_params_for_processing(), which relies on - # object comparison. - if self._help_option is None: - # Avoid circular import. - from .decorators import HelpOption - - self._help_option = HelpOption(help_options) - - return self._help_option - - def make_parser(self, ctx: Context) -> OptionParser: - """Creates the underlying option parser for this command.""" - parser = OptionParser(ctx) - for param in self.get_params(ctx): - param.add_to_parser(parser, ctx) - return parser - - def get_help(self, ctx: Context) -> str: - """Formats the help into a string and returns it. - - Calls :meth:`format_help` internally. - """ - formatter = ctx.make_formatter() - self.format_help(ctx, formatter) - return formatter.getvalue().rstrip("\n") - - def get_short_help_str(self, limit: int = 45) -> str: - """Gets short help for the command or makes it by shortening the - long help string. - """ - if self.short_help: - text = inspect.cleandoc(self.short_help) - elif self.help: - text = make_default_short_help(self.help, limit) - else: - text = "" - - if self.deprecated: - text = _("(Deprecated) {text}").format(text=text) - - return text.strip() - - def format_help(self, ctx: Context, formatter: HelpFormatter) -> None: - """Writes the help into the formatter if it exists. - - This is a low-level method called by :meth:`get_help`. - - This calls the following methods: - - - :meth:`format_usage` - - :meth:`format_help_text` - - :meth:`format_options` - - :meth:`format_epilog` - """ - self.format_usage(ctx, formatter) - self.format_help_text(ctx, formatter) - self.format_options(ctx, formatter) - self.format_epilog(ctx, formatter) - - def format_help_text(self, ctx: Context, formatter: HelpFormatter) -> None: - """Writes the help text to the formatter if it exists.""" - if self.help is not None: - # truncate the help text to the first form feed - text = inspect.cleandoc(self.help).partition("\f")[0] - else: - text = "" - - if self.deprecated: - text = _("(Deprecated) {text}").format(text=text) - - if text: - formatter.write_paragraph() - - with formatter.indentation(): - formatter.write_text(text) - - def format_options(self, ctx: Context, formatter: HelpFormatter) -> None: - """Writes all the options into the formatter if they exist.""" - opts = [] - for param in self.get_params(ctx): - rv = param.get_help_record(ctx) - if rv is not None: - opts.append(rv) - - if opts: - with formatter.section(_("Options")): - formatter.write_dl(opts) - - def format_epilog(self, ctx: Context, formatter: HelpFormatter) -> None: - """Writes the epilog into the formatter if it exists.""" - if self.epilog: - epilog = inspect.cleandoc(self.epilog) - formatter.write_paragraph() - - with formatter.indentation(): - formatter.write_text(epilog) - - def parse_args(self, ctx: Context, args: t.List[str]) -> t.List[str]: - if not args and self.no_args_is_help and not ctx.resilient_parsing: - echo(ctx.get_help(), color=ctx.color) - ctx.exit() - - parser = self.make_parser(ctx) - opts, args, param_order = parser.parse_args(args=args) - - for param in iter_params_for_processing(param_order, self.get_params(ctx)): - value, args = param.handle_parse_result(ctx, opts, args) - - if args and not ctx.allow_extra_args and not ctx.resilient_parsing: - ctx.fail( - ngettext( - "Got unexpected extra argument ({args})", - "Got unexpected extra arguments ({args})", - len(args), - ).format(args=" ".join(map(str, args))) - ) - - ctx.args = args - ctx._opt_prefixes.update(parser._opt_prefixes) - return args - - def invoke(self, ctx: Context) -> t.Any: - """Given a context, this invokes the attached callback (if it exists) - in the right way. - """ - if self.deprecated: - message = _( - "DeprecationWarning: The command {name!r} is deprecated." - ).format(name=self.name) - echo(style(message, fg="red"), err=True) - - if self.callback is not None: - return ctx.invoke(self.callback, **ctx.params) - - def shell_complete(self, ctx: Context, incomplete: str) -> t.List["CompletionItem"]: - """Return a list of completions for the incomplete value. Looks - at the names of options and chained multi-commands. - - :param ctx: Invocation context for this command. - :param incomplete: Value being completed. May be empty. - - .. versionadded:: 8.0 - """ - from click.shell_completion import CompletionItem - - results: t.List[CompletionItem] = [] - - if incomplete and not incomplete[0].isalnum(): - for param in self.get_params(ctx): - if ( - not isinstance(param, Option) - or param.hidden - or ( - not param.multiple - and ctx.get_parameter_source(param.name) # type: ignore - is ParameterSource.COMMANDLINE - ) - ): - continue - - results.extend( - CompletionItem(name, help=param.help) - for name in [*param.opts, *param.secondary_opts] - if name.startswith(incomplete) - ) - - results.extend(super().shell_complete(ctx, incomplete)) - return results - - -class MultiCommand(Command): - """A multi command is the basic implementation of a command that - dispatches to subcommands. The most common version is the - :class:`Group`. - - :param invoke_without_command: this controls how the multi command itself - is invoked. By default it's only invoked - if a subcommand is provided. - :param no_args_is_help: this controls what happens if no arguments are - provided. This option is enabled by default if - `invoke_without_command` is disabled or disabled - if it's enabled. If enabled this will add - ``--help`` as argument if no arguments are - passed. - :param subcommand_metavar: the string that is used in the documentation - to indicate the subcommand place. - :param chain: if this is set to `True` chaining of multiple subcommands - is enabled. This restricts the form of commands in that - they cannot have optional arguments but it allows - multiple commands to be chained together. - :param result_callback: The result callback to attach to this multi - command. This can be set or changed later with the - :meth:`result_callback` decorator. - :param attrs: Other command arguments described in :class:`Command`. - """ - - allow_extra_args = True - allow_interspersed_args = False - - def __init__( - self, - name: t.Optional[str] = None, - invoke_without_command: bool = False, - no_args_is_help: t.Optional[bool] = None, - subcommand_metavar: t.Optional[str] = None, - chain: bool = False, - result_callback: t.Optional[t.Callable[..., t.Any]] = None, - **attrs: t.Any, - ) -> None: - super().__init__(name, **attrs) - - if no_args_is_help is None: - no_args_is_help = not invoke_without_command - - self.no_args_is_help = no_args_is_help - self.invoke_without_command = invoke_without_command - - if subcommand_metavar is None: - if chain: - subcommand_metavar = "COMMAND1 [ARGS]... [COMMAND2 [ARGS]...]..." - else: - subcommand_metavar = "COMMAND [ARGS]..." - - self.subcommand_metavar = subcommand_metavar - self.chain = chain - # The result callback that is stored. This can be set or - # overridden with the :func:`result_callback` decorator. - self._result_callback = result_callback - - if self.chain: - for param in self.params: - if isinstance(param, Argument) and not param.required: - raise RuntimeError( - "Multi commands in chain mode cannot have" - " optional arguments." - ) - - def to_info_dict(self, ctx: Context) -> t.Dict[str, t.Any]: - info_dict = super().to_info_dict(ctx) - commands = {} - - for name in self.list_commands(ctx): - command = self.get_command(ctx, name) - - if command is None: - continue - - sub_ctx = ctx._make_sub_context(command) - - with sub_ctx.scope(cleanup=False): - commands[name] = command.to_info_dict(sub_ctx) - - info_dict.update(commands=commands, chain=self.chain) - return info_dict - - def collect_usage_pieces(self, ctx: Context) -> t.List[str]: - rv = super().collect_usage_pieces(ctx) - rv.append(self.subcommand_metavar) - return rv - - def format_options(self, ctx: Context, formatter: HelpFormatter) -> None: - super().format_options(ctx, formatter) - self.format_commands(ctx, formatter) - - def result_callback(self, replace: bool = False) -> t.Callable[[F], F]: - """Adds a result callback to the command. By default if a - result callback is already registered this will chain them but - this can be disabled with the `replace` parameter. The result - callback is invoked with the return value of the subcommand - (or the list of return values from all subcommands if chaining - is enabled) as well as the parameters as they would be passed - to the main callback. - - Example:: - - @click.group() - @click.option('-i', '--input', default=23) - def cli(input): - return 42 - - @cli.result_callback() - def process_result(result, input): - return result + input - - :param replace: if set to `True` an already existing result - callback will be removed. - - .. versionchanged:: 8.0 - Renamed from ``resultcallback``. - - .. versionadded:: 3.0 - """ - - def decorator(f: F) -> F: - old_callback = self._result_callback - - if old_callback is None or replace: - self._result_callback = f - return f - - def function(__value, *args, **kwargs): # type: ignore - inner = old_callback(__value, *args, **kwargs) - return f(inner, *args, **kwargs) - - self._result_callback = rv = update_wrapper(t.cast(F, function), f) - return rv # type: ignore[return-value] - - return decorator - - def format_commands(self, ctx: Context, formatter: HelpFormatter) -> None: - """Extra format methods for multi methods that adds all the commands - after the options. - """ - commands = [] - for subcommand in self.list_commands(ctx): - cmd = self.get_command(ctx, subcommand) - # What is this, the tool lied about a command. Ignore it - if cmd is None: - continue - if cmd.hidden: - continue - - commands.append((subcommand, cmd)) - - # allow for 3 times the default spacing - if len(commands): - limit = formatter.width - 6 - max(len(cmd[0]) for cmd in commands) - - rows = [] - for subcommand, cmd in commands: - help = cmd.get_short_help_str(limit) - rows.append((subcommand, help)) - - if rows: - with formatter.section(_("Commands")): - formatter.write_dl(rows) - - def parse_args(self, ctx: Context, args: t.List[str]) -> t.List[str]: - if not args and self.no_args_is_help and not ctx.resilient_parsing: - echo(ctx.get_help(), color=ctx.color) - ctx.exit() - - rest = super().parse_args(ctx, args) - - if self.chain: - ctx.protected_args = rest - ctx.args = [] - elif rest: - ctx.protected_args, ctx.args = rest[:1], rest[1:] - - return ctx.args - - def invoke(self, ctx: Context) -> t.Any: - def _process_result(value: t.Any) -> t.Any: - if self._result_callback is not None: - value = ctx.invoke(self._result_callback, value, **ctx.params) - return value - - if not ctx.protected_args: - if self.invoke_without_command: - # No subcommand was invoked, so the result callback is - # invoked with the group return value for regular - # groups, or an empty list for chained groups. - with ctx: - rv = super().invoke(ctx) - return _process_result([] if self.chain else rv) - ctx.fail(_("Missing command.")) - - # Fetch args back out - args = [*ctx.protected_args, *ctx.args] - ctx.args = [] - ctx.protected_args = [] - - # If we're not in chain mode, we only allow the invocation of a - # single command but we also inform the current context about the - # name of the command to invoke. - if not self.chain: - # Make sure the context is entered so we do not clean up - # resources until the result processor has worked. - with ctx: - cmd_name, cmd, args = self.resolve_command(ctx, args) - assert cmd is not None - ctx.invoked_subcommand = cmd_name - super().invoke(ctx) - sub_ctx = cmd.make_context(cmd_name, args, parent=ctx) - with sub_ctx: - return _process_result(sub_ctx.command.invoke(sub_ctx)) - - # In chain mode we create the contexts step by step, but after the - # base command has been invoked. Because at that point we do not - # know the subcommands yet, the invoked subcommand attribute is - # set to ``*`` to inform the command that subcommands are executed - # but nothing else. - with ctx: - ctx.invoked_subcommand = "*" if args else None - super().invoke(ctx) - - # Otherwise we make every single context and invoke them in a - # chain. In that case the return value to the result processor - # is the list of all invoked subcommand's results. - contexts = [] - while args: - cmd_name, cmd, args = self.resolve_command(ctx, args) - assert cmd is not None - sub_ctx = cmd.make_context( - cmd_name, - args, - parent=ctx, - allow_extra_args=True, - allow_interspersed_args=False, - ) - contexts.append(sub_ctx) - args, sub_ctx.args = sub_ctx.args, [] - - rv = [] - for sub_ctx in contexts: - with sub_ctx: - rv.append(sub_ctx.command.invoke(sub_ctx)) - return _process_result(rv) - - def resolve_command( - self, ctx: Context, args: t.List[str] - ) -> t.Tuple[t.Optional[str], t.Optional[Command], t.List[str]]: - cmd_name = make_str(args[0]) - original_cmd_name = cmd_name - - # Get the command - cmd = self.get_command(ctx, cmd_name) - - # If we can't find the command but there is a normalization - # function available, we try with that one. - if cmd is None and ctx.token_normalize_func is not None: - cmd_name = ctx.token_normalize_func(cmd_name) - cmd = self.get_command(ctx, cmd_name) - - # If we don't find the command we want to show an error message - # to the user that it was not provided. However, there is - # something else we should do: if the first argument looks like - # an option we want to kick off parsing again for arguments to - # resolve things like --help which now should go to the main - # place. - if cmd is None and not ctx.resilient_parsing: - if split_opt(cmd_name)[0]: - self.parse_args(ctx, ctx.args) - ctx.fail(_("No such command {name!r}.").format(name=original_cmd_name)) - return cmd_name if cmd else None, cmd, args[1:] - - def get_command(self, ctx: Context, cmd_name: str) -> t.Optional[Command]: - """Given a context and a command name, this returns a - :class:`Command` object if it exists or returns `None`. - """ - raise NotImplementedError - - def list_commands(self, ctx: Context) -> t.List[str]: - """Returns a list of subcommand names in the order they should - appear. - """ - return [] - - def shell_complete(self, ctx: Context, incomplete: str) -> t.List["CompletionItem"]: - """Return a list of completions for the incomplete value. Looks - at the names of options, subcommands, and chained - multi-commands. - - :param ctx: Invocation context for this command. - :param incomplete: Value being completed. May be empty. - - .. versionadded:: 8.0 - """ - from click.shell_completion import CompletionItem - - results = [ - CompletionItem(name, help=command.get_short_help_str()) - for name, command in _complete_visible_commands(ctx, incomplete) - ] - results.extend(super().shell_complete(ctx, incomplete)) - return results - - -class Group(MultiCommand): - """A group allows a command to have subcommands attached. This is - the most common way to implement nesting in Click. - - :param name: The name of the group command. - :param commands: A dict mapping names to :class:`Command` objects. - Can also be a list of :class:`Command`, which will use - :attr:`Command.name` to create the dict. - :param attrs: Other command arguments described in - :class:`MultiCommand`, :class:`Command`, and - :class:`BaseCommand`. - - .. versionchanged:: 8.0 - The ``commands`` argument can be a list of command objects. - """ - - #: If set, this is used by the group's :meth:`command` decorator - #: as the default :class:`Command` class. This is useful to make all - #: subcommands use a custom command class. - #: - #: .. versionadded:: 8.0 - command_class: t.Optional[t.Type[Command]] = None - - #: If set, this is used by the group's :meth:`group` decorator - #: as the default :class:`Group` class. This is useful to make all - #: subgroups use a custom group class. - #: - #: If set to the special value :class:`type` (literally - #: ``group_class = type``), this group's class will be used as the - #: default class. This makes a custom group class continue to make - #: custom groups. - #: - #: .. versionadded:: 8.0 - group_class: t.Optional[t.Union[t.Type["Group"], t.Type[type]]] = None - # Literal[type] isn't valid, so use Type[type] - - def __init__( - self, - name: t.Optional[str] = None, - commands: t.Optional[ - t.Union[t.MutableMapping[str, Command], t.Sequence[Command]] - ] = None, - **attrs: t.Any, - ) -> None: - super().__init__(name, **attrs) - - if commands is None: - commands = {} - elif isinstance(commands, abc.Sequence): - commands = {c.name: c for c in commands if c.name is not None} - - #: The registered subcommands by their exported names. - self.commands: t.MutableMapping[str, Command] = commands - - def add_command(self, cmd: Command, name: t.Optional[str] = None) -> None: - """Registers another :class:`Command` with this group. If the name - is not provided, the name of the command is used. - """ - name = name or cmd.name - if name is None: - raise TypeError("Command has no name.") - _check_multicommand(self, name, cmd, register=True) - self.commands[name] = cmd - - @t.overload - def command(self, __func: t.Callable[..., t.Any]) -> Command: ... - - @t.overload - def command( - self, *args: t.Any, **kwargs: t.Any - ) -> t.Callable[[t.Callable[..., t.Any]], Command]: ... - - def command( - self, *args: t.Any, **kwargs: t.Any - ) -> t.Union[t.Callable[[t.Callable[..., t.Any]], Command], Command]: - """A shortcut decorator for declaring and attaching a command to - the group. This takes the same arguments as :func:`command` and - immediately registers the created command with this group by - calling :meth:`add_command`. - - To customize the command class used, set the - :attr:`command_class` attribute. - - .. versionchanged:: 8.1 - This decorator can be applied without parentheses. - - .. versionchanged:: 8.0 - Added the :attr:`command_class` attribute. - """ - from .decorators import command - - func: t.Optional[t.Callable[..., t.Any]] = None - - if args and callable(args[0]): - assert ( - len(args) == 1 and not kwargs - ), "Use 'command(**kwargs)(callable)' to provide arguments." - (func,) = args - args = () - - if self.command_class and kwargs.get("cls") is None: - kwargs["cls"] = self.command_class - - def decorator(f: t.Callable[..., t.Any]) -> Command: - cmd: Command = command(*args, **kwargs)(f) - self.add_command(cmd) - return cmd - - if func is not None: - return decorator(func) - - return decorator - - @t.overload - def group(self, __func: t.Callable[..., t.Any]) -> "Group": ... - - @t.overload - def group( - self, *args: t.Any, **kwargs: t.Any - ) -> t.Callable[[t.Callable[..., t.Any]], "Group"]: ... - - def group( - self, *args: t.Any, **kwargs: t.Any - ) -> t.Union[t.Callable[[t.Callable[..., t.Any]], "Group"], "Group"]: - """A shortcut decorator for declaring and attaching a group to - the group. This takes the same arguments as :func:`group` and - immediately registers the created group with this group by - calling :meth:`add_command`. - - To customize the group class used, set the :attr:`group_class` - attribute. - - .. versionchanged:: 8.1 - This decorator can be applied without parentheses. - - .. versionchanged:: 8.0 - Added the :attr:`group_class` attribute. - """ - from .decorators import group - - func: t.Optional[t.Callable[..., t.Any]] = None - - if args and callable(args[0]): - assert ( - len(args) == 1 and not kwargs - ), "Use 'group(**kwargs)(callable)' to provide arguments." - (func,) = args - args = () - - if self.group_class is not None and kwargs.get("cls") is None: - if self.group_class is type: - kwargs["cls"] = type(self) - else: - kwargs["cls"] = self.group_class - - def decorator(f: t.Callable[..., t.Any]) -> "Group": - cmd: Group = group(*args, **kwargs)(f) - self.add_command(cmd) - return cmd - - if func is not None: - return decorator(func) - - return decorator - - def get_command(self, ctx: Context, cmd_name: str) -> t.Optional[Command]: - return self.commands.get(cmd_name) - - def list_commands(self, ctx: Context) -> t.List[str]: - return sorted(self.commands) - - -class CommandCollection(MultiCommand): - """A command collection is a multi command that merges multiple multi - commands together into one. This is a straightforward implementation - that accepts a list of different multi commands as sources and - provides all the commands for each of them. - - See :class:`MultiCommand` and :class:`Command` for the description of - ``name`` and ``attrs``. - """ - - def __init__( - self, - name: t.Optional[str] = None, - sources: t.Optional[t.List[MultiCommand]] = None, - **attrs: t.Any, - ) -> None: - super().__init__(name, **attrs) - #: The list of registered multi commands. - self.sources: t.List[MultiCommand] = sources or [] - - def add_source(self, multi_cmd: MultiCommand) -> None: - """Adds a new multi command to the chain dispatcher.""" - self.sources.append(multi_cmd) - - def get_command(self, ctx: Context, cmd_name: str) -> t.Optional[Command]: - for source in self.sources: - rv = source.get_command(ctx, cmd_name) - - if rv is not None: - if self.chain: - _check_multicommand(self, cmd_name, rv) - - return rv - - return None - - def list_commands(self, ctx: Context) -> t.List[str]: - rv: t.Set[str] = set() - - for source in self.sources: - rv.update(source.list_commands(ctx)) - - return sorted(rv) - - -def _check_iter(value: t.Any) -> t.Iterator[t.Any]: - """Check if the value is iterable but not a string. Raises a type - error, or return an iterator over the value. - """ - if isinstance(value, str): - raise TypeError - - return iter(value) - - -class Parameter: - r"""A parameter to a command comes in two versions: they are either - :class:`Option`\s or :class:`Argument`\s. Other subclasses are currently - not supported by design as some of the internals for parsing are - intentionally not finalized. - - Some settings are supported by both options and arguments. - - :param param_decls: the parameter declarations for this option or - argument. This is a list of flags or argument - names. - :param type: the type that should be used. Either a :class:`ParamType` - or a Python type. The latter is converted into the former - automatically if supported. - :param required: controls if this is optional or not. - :param default: the default value if omitted. This can also be a callable, - in which case it's invoked when the default is needed - without any arguments. - :param callback: A function to further process or validate the value - after type conversion. It is called as ``f(ctx, param, value)`` - and must return the value. It is called for all sources, - including prompts. - :param nargs: the number of arguments to match. If not ``1`` the return - value is a tuple instead of single value. The default for - nargs is ``1`` (except if the type is a tuple, then it's - the arity of the tuple). If ``nargs=-1``, all remaining - parameters are collected. - :param metavar: how the value is represented in the help page. - :param expose_value: if this is `True` then the value is passed onwards - to the command callback and stored on the context, - otherwise it's skipped. - :param is_eager: eager values are processed before non eager ones. This - should not be set for arguments or it will inverse the - order of processing. - :param envvar: a string or list of strings that are environment variables - that should be checked. - :param shell_complete: A function that returns custom shell - completions. Used instead of the param's type completion if - given. Takes ``ctx, param, incomplete`` and must return a list - of :class:`~click.shell_completion.CompletionItem` or a list of - strings. - - .. versionchanged:: 8.0 - ``process_value`` validates required parameters and bounded - ``nargs``, and invokes the parameter callback before returning - the value. This allows the callback to validate prompts. - ``full_process_value`` is removed. - - .. versionchanged:: 8.0 - ``autocompletion`` is renamed to ``shell_complete`` and has new - semantics described above. The old name is deprecated and will - be removed in 8.1, until then it will be wrapped to match the - new requirements. - - .. versionchanged:: 8.0 - For ``multiple=True, nargs>1``, the default must be a list of - tuples. - - .. versionchanged:: 8.0 - Setting a default is no longer required for ``nargs>1``, it will - default to ``None``. ``multiple=True`` or ``nargs=-1`` will - default to ``()``. - - .. versionchanged:: 7.1 - Empty environment variables are ignored rather than taking the - empty string value. This makes it possible for scripts to clear - variables if they can't unset them. - - .. versionchanged:: 2.0 - Changed signature for parameter callback to also be passed the - parameter. The old callback format will still work, but it will - raise a warning to give you a chance to migrate the code easier. - """ - - param_type_name = "parameter" - - def __init__( - self, - param_decls: t.Optional[t.Sequence[str]] = None, - type: t.Optional[t.Union[types.ParamType, t.Any]] = None, - required: bool = False, - default: t.Optional[t.Union[t.Any, t.Callable[[], t.Any]]] = None, - callback: t.Optional[t.Callable[[Context, "Parameter", t.Any], t.Any]] = None, - nargs: t.Optional[int] = None, - multiple: bool = False, - metavar: t.Optional[str] = None, - expose_value: bool = True, - is_eager: bool = False, - envvar: t.Optional[t.Union[str, t.Sequence[str]]] = None, - shell_complete: t.Optional[ - t.Callable[ - [Context, "Parameter", str], - t.Union[t.List["CompletionItem"], t.List[str]], - ] - ] = None, - ) -> None: - self.name: t.Optional[str] - self.opts: t.List[str] - self.secondary_opts: t.List[str] - self.name, self.opts, self.secondary_opts = self._parse_decls( - param_decls or (), expose_value - ) - self.type: types.ParamType = types.convert_type(type, default) - - # Default nargs to what the type tells us if we have that - # information available. - if nargs is None: - if self.type.is_composite: - nargs = self.type.arity - else: - nargs = 1 - - self.required = required - self.callback = callback - self.nargs = nargs - self.multiple = multiple - self.expose_value = expose_value - self.default = default - self.is_eager = is_eager - self.metavar = metavar - self.envvar = envvar - self._custom_shell_complete = shell_complete - - if __debug__: - if self.type.is_composite and nargs != self.type.arity: - raise ValueError( - f"'nargs' must be {self.type.arity} (or None) for" - f" type {self.type!r}, but it was {nargs}." - ) - - # Skip no default or callable default. - check_default = default if not callable(default) else None - - if check_default is not None: - if multiple: - try: - # Only check the first value against nargs. - check_default = next(_check_iter(check_default), None) - except TypeError: - raise ValueError( - "'default' must be a list when 'multiple' is true." - ) from None - - # Can be None for multiple with empty default. - if nargs != 1 and check_default is not None: - try: - _check_iter(check_default) - except TypeError: - if multiple: - message = ( - "'default' must be a list of lists when 'multiple' is" - " true and 'nargs' != 1." - ) - else: - message = "'default' must be a list when 'nargs' != 1." - - raise ValueError(message) from None - - if nargs > 1 and len(check_default) != nargs: - subject = "item length" if multiple else "length" - raise ValueError( - f"'default' {subject} must match nargs={nargs}." - ) - - def to_info_dict(self) -> t.Dict[str, t.Any]: - """Gather information that could be useful for a tool generating - user-facing documentation. - - Use :meth:`click.Context.to_info_dict` to traverse the entire - CLI structure. - - .. versionadded:: 8.0 - """ - return { - "name": self.name, - "param_type_name": self.param_type_name, - "opts": self.opts, - "secondary_opts": self.secondary_opts, - "type": self.type.to_info_dict(), - "required": self.required, - "nargs": self.nargs, - "multiple": self.multiple, - "default": self.default, - "envvar": self.envvar, - } - - def __repr__(self) -> str: - return f"<{self.__class__.__name__} {self.name}>" - - def _parse_decls( - self, decls: t.Sequence[str], expose_value: bool - ) -> t.Tuple[t.Optional[str], t.List[str], t.List[str]]: - raise NotImplementedError() - - @property - def human_readable_name(self) -> str: - """Returns the human readable name of this parameter. This is the - same as the name for options, but the metavar for arguments. - """ - return self.name # type: ignore - - def make_metavar(self) -> str: - if self.metavar is not None: - return self.metavar - - metavar = self.type.get_metavar(self) - - if metavar is None: - metavar = self.type.name.upper() - - if self.nargs != 1: - metavar += "..." - - return metavar - - @t.overload - def get_default( - self, ctx: Context, call: "te.Literal[True]" = True - ) -> t.Optional[t.Any]: ... - - @t.overload - def get_default( - self, ctx: Context, call: bool = ... - ) -> t.Optional[t.Union[t.Any, t.Callable[[], t.Any]]]: ... - - def get_default( - self, ctx: Context, call: bool = True - ) -> t.Optional[t.Union[t.Any, t.Callable[[], t.Any]]]: - """Get the default for the parameter. Tries - :meth:`Context.lookup_default` first, then the local default. - - :param ctx: Current context. - :param call: If the default is a callable, call it. Disable to - return the callable instead. - - .. versionchanged:: 8.0.2 - Type casting is no longer performed when getting a default. - - .. versionchanged:: 8.0.1 - Type casting can fail in resilient parsing mode. Invalid - defaults will not prevent showing help text. - - .. versionchanged:: 8.0 - Looks at ``ctx.default_map`` first. - - .. versionchanged:: 8.0 - Added the ``call`` parameter. - """ - value = ctx.lookup_default(self.name, call=False) # type: ignore - - if value is None: - value = self.default - - if call and callable(value): - value = value() - - return value - - def add_to_parser(self, parser: OptionParser, ctx: Context) -> None: - raise NotImplementedError() - - def consume_value( - self, ctx: Context, opts: t.Mapping[str, t.Any] - ) -> t.Tuple[t.Any, ParameterSource]: - value = opts.get(self.name) # type: ignore - source = ParameterSource.COMMANDLINE - - if value is None: - value = self.value_from_envvar(ctx) - source = ParameterSource.ENVIRONMENT - - if value is None: - value = ctx.lookup_default(self.name) # type: ignore - source = ParameterSource.DEFAULT_MAP - - if value is None: - value = self.get_default(ctx) - source = ParameterSource.DEFAULT - - return value, source - - def type_cast_value(self, ctx: Context, value: t.Any) -> t.Any: - """Convert and validate a value against the option's - :attr:`type`, :attr:`multiple`, and :attr:`nargs`. - """ - if value is None: - return () if self.multiple or self.nargs == -1 else None - - def check_iter(value: t.Any) -> t.Iterator[t.Any]: - try: - return _check_iter(value) - except TypeError: - # This should only happen when passing in args manually, - # the parser should construct an iterable when parsing - # the command line. - raise BadParameter( - _("Value must be an iterable."), ctx=ctx, param=self - ) from None - - if self.nargs == 1 or self.type.is_composite: - - def convert(value: t.Any) -> t.Any: - return self.type(value, param=self, ctx=ctx) - - elif self.nargs == -1: - - def convert(value: t.Any) -> t.Any: # t.Tuple[t.Any, ...] - return tuple(self.type(x, self, ctx) for x in check_iter(value)) - - else: # nargs > 1 - - def convert(value: t.Any) -> t.Any: # t.Tuple[t.Any, ...] - value = tuple(check_iter(value)) - - if len(value) != self.nargs: - raise BadParameter( - ngettext( - "Takes {nargs} values but 1 was given.", - "Takes {nargs} values but {len} were given.", - len(value), - ).format(nargs=self.nargs, len=len(value)), - ctx=ctx, - param=self, - ) - - return tuple(self.type(x, self, ctx) for x in value) - - if self.multiple: - return tuple(convert(x) for x in check_iter(value)) - - return convert(value) - - def value_is_missing(self, value: t.Any) -> bool: - if value is None: - return True - - if (self.nargs != 1 or self.multiple) and value == (): - return True - - return False - - def process_value(self, ctx: Context, value: t.Any) -> t.Any: - value = self.type_cast_value(ctx, value) - - if self.required and self.value_is_missing(value): - raise MissingParameter(ctx=ctx, param=self) - - if self.callback is not None: - value = self.callback(ctx, self, value) - - return value - - def resolve_envvar_value(self, ctx: Context) -> t.Optional[str]: - if self.envvar is None: - return None - - if isinstance(self.envvar, str): - rv = os.environ.get(self.envvar) - - if rv: - return rv - else: - for envvar in self.envvar: - rv = os.environ.get(envvar) - - if rv: - return rv - - return None - - def value_from_envvar(self, ctx: Context) -> t.Optional[t.Any]: - rv: t.Optional[t.Any] = self.resolve_envvar_value(ctx) - - if rv is not None and self.nargs != 1: - rv = self.type.split_envvar_value(rv) - - return rv - - def handle_parse_result( - self, ctx: Context, opts: t.Mapping[str, t.Any], args: t.List[str] - ) -> t.Tuple[t.Any, t.List[str]]: - with augment_usage_errors(ctx, param=self): - value, source = self.consume_value(ctx, opts) - ctx.set_parameter_source(self.name, source) # type: ignore - - try: - value = self.process_value(ctx, value) - except Exception: - if not ctx.resilient_parsing: - raise - - value = None - - if self.expose_value: - ctx.params[self.name] = value # type: ignore - - return value, args - - def get_help_record(self, ctx: Context) -> t.Optional[t.Tuple[str, str]]: - pass - - def get_usage_pieces(self, ctx: Context) -> t.List[str]: - return [] - - def get_error_hint(self, ctx: Context) -> str: - """Get a stringified version of the param for use in error messages to - indicate which param caused the error. - """ - hint_list = self.opts or [self.human_readable_name] - return " / ".join(f"'{x}'" for x in hint_list) - - def shell_complete(self, ctx: Context, incomplete: str) -> t.List["CompletionItem"]: - """Return a list of completions for the incomplete value. If a - ``shell_complete`` function was given during init, it is used. - Otherwise, the :attr:`type` - :meth:`~click.types.ParamType.shell_complete` function is used. - - :param ctx: Invocation context for this command. - :param incomplete: Value being completed. May be empty. - - .. versionadded:: 8.0 - """ - if self._custom_shell_complete is not None: - results = self._custom_shell_complete(ctx, self, incomplete) - - if results and isinstance(results[0], str): - from click.shell_completion import CompletionItem - - results = [CompletionItem(c) for c in results] - - return t.cast(t.List["CompletionItem"], results) - - return self.type.shell_complete(ctx, self, incomplete) - - -class Option(Parameter): - """Options are usually optional values on the command line and - have some extra features that arguments don't have. - - All other parameters are passed onwards to the parameter constructor. - - :param show_default: Show the default value for this option in its - help text. Values are not shown by default, unless - :attr:`Context.show_default` is ``True``. If this value is a - string, it shows that string in parentheses instead of the - actual value. This is particularly useful for dynamic options. - For single option boolean flags, the default remains hidden if - its value is ``False``. - :param show_envvar: Controls if an environment variable should be - shown on the help page. Normally, environment variables are not - shown. - :param prompt: If set to ``True`` or a non empty string then the - user will be prompted for input. If set to ``True`` the prompt - will be the option name capitalized. - :param confirmation_prompt: Prompt a second time to confirm the - value if it was prompted for. Can be set to a string instead of - ``True`` to customize the message. - :param prompt_required: If set to ``False``, the user will be - prompted for input only when the option was specified as a flag - without a value. - :param hide_input: If this is ``True`` then the input on the prompt - will be hidden from the user. This is useful for password input. - :param is_flag: forces this option to act as a flag. The default is - auto detection. - :param flag_value: which value should be used for this flag if it's - enabled. This is set to a boolean automatically if - the option string contains a slash to mark two options. - :param multiple: if this is set to `True` then the argument is accepted - multiple times and recorded. This is similar to ``nargs`` - in how it works but supports arbitrary number of - arguments. - :param count: this flag makes an option increment an integer. - :param allow_from_autoenv: if this is enabled then the value of this - parameter will be pulled from an environment - variable in case a prefix is defined on the - context. - :param help: the help string. - :param hidden: hide this option from help outputs. - :param attrs: Other command arguments described in :class:`Parameter`. - - .. versionchanged:: 8.1.0 - Help text indentation is cleaned here instead of only in the - ``@option`` decorator. - - .. versionchanged:: 8.1.0 - The ``show_default`` parameter overrides - ``Context.show_default``. - - .. versionchanged:: 8.1.0 - The default of a single option boolean flag is not shown if the - default value is ``False``. - - .. versionchanged:: 8.0.1 - ``type`` is detected from ``flag_value`` if given. - """ - - param_type_name = "option" - - def __init__( - self, - param_decls: t.Optional[t.Sequence[str]] = None, - show_default: t.Union[bool, str, None] = None, - prompt: t.Union[bool, str] = False, - confirmation_prompt: t.Union[bool, str] = False, - prompt_required: bool = True, - hide_input: bool = False, - is_flag: t.Optional[bool] = None, - flag_value: t.Optional[t.Any] = None, - multiple: bool = False, - count: bool = False, - allow_from_autoenv: bool = True, - type: t.Optional[t.Union[types.ParamType, t.Any]] = None, - help: t.Optional[str] = None, - hidden: bool = False, - show_choices: bool = True, - show_envvar: bool = False, - **attrs: t.Any, - ) -> None: - if help: - help = inspect.cleandoc(help) - - default_is_missing = "default" not in attrs - super().__init__(param_decls, type=type, multiple=multiple, **attrs) - - if prompt is True: - if self.name is None: - raise TypeError("'name' is required with 'prompt=True'.") - - prompt_text: t.Optional[str] = self.name.replace("_", " ").capitalize() - elif prompt is False: - prompt_text = None - else: - prompt_text = prompt - - self.prompt = prompt_text - self.confirmation_prompt = confirmation_prompt - self.prompt_required = prompt_required - self.hide_input = hide_input - self.hidden = hidden - - # If prompt is enabled but not required, then the option can be - # used as a flag to indicate using prompt or flag_value. - self._flag_needs_value = self.prompt is not None and not self.prompt_required - - if is_flag is None: - if flag_value is not None: - # Implicitly a flag because flag_value was set. - is_flag = True - elif self._flag_needs_value: - # Not a flag, but when used as a flag it shows a prompt. - is_flag = False - else: - # Implicitly a flag because flag options were given. - is_flag = bool(self.secondary_opts) - elif is_flag is False and not self._flag_needs_value: - # Not a flag, and prompt is not enabled, can be used as a - # flag if flag_value is set. - self._flag_needs_value = flag_value is not None - - self.default: t.Union[t.Any, t.Callable[[], t.Any]] - - if is_flag and default_is_missing and not self.required: - if multiple: - self.default = () - else: - self.default = False - - if flag_value is None: - flag_value = not self.default - - self.type: types.ParamType - if is_flag and type is None: - # Re-guess the type from the flag value instead of the - # default. - self.type = types.convert_type(None, flag_value) - - self.is_flag: bool = is_flag - self.is_bool_flag: bool = is_flag and isinstance(self.type, types.BoolParamType) - self.flag_value: t.Any = flag_value - - # Counting - self.count = count - if count: - if type is None: - self.type = types.IntRange(min=0) - if default_is_missing: - self.default = 0 - - self.allow_from_autoenv = allow_from_autoenv - self.help = help - self.show_default = show_default - self.show_choices = show_choices - self.show_envvar = show_envvar - - if __debug__: - if self.nargs == -1: - raise TypeError("nargs=-1 is not supported for options.") - - if self.prompt and self.is_flag and not self.is_bool_flag: - raise TypeError("'prompt' is not valid for non-boolean flag.") - - if not self.is_bool_flag and self.secondary_opts: - raise TypeError("Secondary flag is not valid for non-boolean flag.") - - if self.is_bool_flag and self.hide_input and self.prompt is not None: - raise TypeError( - "'prompt' with 'hide_input' is not valid for boolean flag." - ) - - if self.count: - if self.multiple: - raise TypeError("'count' is not valid with 'multiple'.") - - if self.is_flag: - raise TypeError("'count' is not valid with 'is_flag'.") - - def to_info_dict(self) -> t.Dict[str, t.Any]: - info_dict = super().to_info_dict() - info_dict.update( - help=self.help, - prompt=self.prompt, - is_flag=self.is_flag, - flag_value=self.flag_value, - count=self.count, - hidden=self.hidden, - ) - return info_dict - - def _parse_decls( - self, decls: t.Sequence[str], expose_value: bool - ) -> t.Tuple[t.Optional[str], t.List[str], t.List[str]]: - opts = [] - secondary_opts = [] - name = None - possible_names = [] - - for decl in decls: - if decl.isidentifier(): - if name is not None: - raise TypeError(f"Name '{name}' defined twice") - name = decl - else: - split_char = ";" if decl[:1] == "/" else "/" - if split_char in decl: - first, second = decl.split(split_char, 1) - first = first.rstrip() - if first: - possible_names.append(split_opt(first)) - opts.append(first) - second = second.lstrip() - if second: - secondary_opts.append(second.lstrip()) - if first == second: - raise ValueError( - f"Boolean option {decl!r} cannot use the" - " same flag for true/false." - ) - else: - possible_names.append(split_opt(decl)) - opts.append(decl) - - if name is None and possible_names: - possible_names.sort(key=lambda x: -len(x[0])) # group long options first - name = possible_names[0][1].replace("-", "_").lower() - if not name.isidentifier(): - name = None - - if name is None: - if not expose_value: - return None, opts, secondary_opts - raise TypeError( - f"Could not determine name for option with declarations {decls!r}" - ) - - if not opts and not secondary_opts: - raise TypeError( - f"No options defined but a name was passed ({name})." - " Did you mean to declare an argument instead? Did" - f" you mean to pass '--{name}'?" - ) - - return name, opts, secondary_opts - - def add_to_parser(self, parser: OptionParser, ctx: Context) -> None: - if self.multiple: - action = "append" - elif self.count: - action = "count" - else: - action = "store" - - if self.is_flag: - action = f"{action}_const" - - if self.is_bool_flag and self.secondary_opts: - parser.add_option( - obj=self, opts=self.opts, dest=self.name, action=action, const=True - ) - parser.add_option( - obj=self, - opts=self.secondary_opts, - dest=self.name, - action=action, - const=False, - ) - else: - parser.add_option( - obj=self, - opts=self.opts, - dest=self.name, - action=action, - const=self.flag_value, - ) - else: - parser.add_option( - obj=self, - opts=self.opts, - dest=self.name, - action=action, - nargs=self.nargs, - ) - - def get_help_record(self, ctx: Context) -> t.Optional[t.Tuple[str, str]]: - if self.hidden: - return None - - any_prefix_is_slash = False - - def _write_opts(opts: t.Sequence[str]) -> str: - nonlocal any_prefix_is_slash - - rv, any_slashes = join_options(opts) - - if any_slashes: - any_prefix_is_slash = True - - if not self.is_flag and not self.count: - rv += f" {self.make_metavar()}" - - return rv - - rv = [_write_opts(self.opts)] - - if self.secondary_opts: - rv.append(_write_opts(self.secondary_opts)) - - help = self.help or "" - extra = [] - - if self.show_envvar: - envvar = self.envvar - - if envvar is None: - if ( - self.allow_from_autoenv - and ctx.auto_envvar_prefix is not None - and self.name is not None - ): - envvar = f"{ctx.auto_envvar_prefix}_{self.name.upper()}" - - if envvar is not None: - var_str = ( - envvar - if isinstance(envvar, str) - else ", ".join(str(d) for d in envvar) - ) - extra.append(_("env var: {var}").format(var=var_str)) - - # Temporarily enable resilient parsing to avoid type casting - # failing for the default. Might be possible to extend this to - # help formatting in general. - resilient = ctx.resilient_parsing - ctx.resilient_parsing = True - - try: - default_value = self.get_default(ctx, call=False) - finally: - ctx.resilient_parsing = resilient - - show_default = False - show_default_is_str = False - - if self.show_default is not None: - if isinstance(self.show_default, str): - show_default_is_str = show_default = True - else: - show_default = self.show_default - elif ctx.show_default is not None: - show_default = ctx.show_default - - if show_default_is_str or (show_default and (default_value is not None)): - if show_default_is_str: - default_string = f"({self.show_default})" - elif isinstance(default_value, (list, tuple)): - default_string = ", ".join(str(d) for d in default_value) - elif inspect.isfunction(default_value): - default_string = _("(dynamic)") - elif self.is_bool_flag and self.secondary_opts: - # For boolean flags that have distinct True/False opts, - # use the opt without prefix instead of the value. - default_string = split_opt( - (self.opts if default_value else self.secondary_opts)[0] - )[1] - elif self.is_bool_flag and not self.secondary_opts and not default_value: - default_string = "" - elif default_value == "": - default_string = '""' - else: - default_string = str(default_value) - - if default_string: - extra.append(_("default: {default}").format(default=default_string)) - - if ( - isinstance(self.type, types._NumberRangeBase) - # skip count with default range type - and not (self.count and self.type.min == 0 and self.type.max is None) - ): - range_str = self.type._describe_range() - - if range_str: - extra.append(range_str) - - if self.required: - extra.append(_("required")) - - if extra: - extra_str = "; ".join(extra) - help = f"{help} [{extra_str}]" if help else f"[{extra_str}]" - - return ("; " if any_prefix_is_slash else " / ").join(rv), help - - @t.overload - def get_default( - self, ctx: Context, call: "te.Literal[True]" = True - ) -> t.Optional[t.Any]: ... - - @t.overload - def get_default( - self, ctx: Context, call: bool = ... - ) -> t.Optional[t.Union[t.Any, t.Callable[[], t.Any]]]: ... - - def get_default( - self, ctx: Context, call: bool = True - ) -> t.Optional[t.Union[t.Any, t.Callable[[], t.Any]]]: - # If we're a non boolean flag our default is more complex because - # we need to look at all flags in the same group to figure out - # if we're the default one in which case we return the flag - # value as default. - if self.is_flag and not self.is_bool_flag: - for param in ctx.command.params: - if param.name == self.name and param.default: - return t.cast(Option, param).flag_value - - return None - - return super().get_default(ctx, call=call) - - def prompt_for_value(self, ctx: Context) -> t.Any: - """This is an alternative flow that can be activated in the full - value processing if a value does not exist. It will prompt the - user until a valid value exists and then returns the processed - value as result. - """ - assert self.prompt is not None - - # Calculate the default before prompting anything to be stable. - default = self.get_default(ctx) - - # If this is a prompt for a flag we need to handle this - # differently. - if self.is_bool_flag: - return confirm(self.prompt, default) - - return prompt( - self.prompt, - default=default, - type=self.type, - hide_input=self.hide_input, - show_choices=self.show_choices, - confirmation_prompt=self.confirmation_prompt, - value_proc=lambda x: self.process_value(ctx, x), - ) - - def resolve_envvar_value(self, ctx: Context) -> t.Optional[str]: - rv = super().resolve_envvar_value(ctx) - - if rv is not None: - return rv - - if ( - self.allow_from_autoenv - and ctx.auto_envvar_prefix is not None - and self.name is not None - ): - envvar = f"{ctx.auto_envvar_prefix}_{self.name.upper()}" - rv = os.environ.get(envvar) - - if rv: - return rv - - return None - - def value_from_envvar(self, ctx: Context) -> t.Optional[t.Any]: - rv: t.Optional[t.Any] = self.resolve_envvar_value(ctx) - - if rv is None: - return None - - value_depth = (self.nargs != 1) + bool(self.multiple) - - if value_depth > 0: - rv = self.type.split_envvar_value(rv) - - if self.multiple and self.nargs != 1: - rv = batch(rv, self.nargs) - - return rv - - def consume_value( - self, ctx: Context, opts: t.Mapping[str, "Parameter"] - ) -> t.Tuple[t.Any, ParameterSource]: - value, source = super().consume_value(ctx, opts) - - # The parser will emit a sentinel value if the option can be - # given as a flag without a value. This is different from None - # to distinguish from the flag not being given at all. - if value is _flag_needs_value: - if self.prompt is not None and not ctx.resilient_parsing: - value = self.prompt_for_value(ctx) - source = ParameterSource.PROMPT - else: - value = self.flag_value - source = ParameterSource.COMMANDLINE - - elif ( - self.multiple - and value is not None - and any(v is _flag_needs_value for v in value) - ): - value = [self.flag_value if v is _flag_needs_value else v for v in value] - source = ParameterSource.COMMANDLINE - - # The value wasn't set, or used the param's default, prompt if - # prompting is enabled. - elif ( - source in {None, ParameterSource.DEFAULT} - and self.prompt is not None - and (self.required or self.prompt_required) - and not ctx.resilient_parsing - ): - value = self.prompt_for_value(ctx) - source = ParameterSource.PROMPT - - return value, source - - -class Argument(Parameter): - """Arguments are positional parameters to a command. They generally - provide fewer features than options but can have infinite ``nargs`` - and are required by default. - - All parameters are passed onwards to the constructor of :class:`Parameter`. - """ - - param_type_name = "argument" - - def __init__( - self, - param_decls: t.Sequence[str], - required: t.Optional[bool] = None, - **attrs: t.Any, - ) -> None: - if required is None: - if attrs.get("default") is not None: - required = False - else: - required = attrs.get("nargs", 1) > 0 - - if "multiple" in attrs: - raise TypeError("__init__() got an unexpected keyword argument 'multiple'.") - - super().__init__(param_decls, required=required, **attrs) - - if __debug__: - if self.default is not None and self.nargs == -1: - raise TypeError("'default' is not supported for nargs=-1.") - - @property - def human_readable_name(self) -> str: - if self.metavar is not None: - return self.metavar - return self.name.upper() # type: ignore - - def make_metavar(self) -> str: - if self.metavar is not None: - return self.metavar - var = self.type.get_metavar(self) - if not var: - var = self.name.upper() # type: ignore - if not self.required: - var = f"[{var}]" - if self.nargs != 1: - var += "..." - return var - - def _parse_decls( - self, decls: t.Sequence[str], expose_value: bool - ) -> t.Tuple[t.Optional[str], t.List[str], t.List[str]]: - if not decls: - if not expose_value: - return None, [], [] - raise TypeError("Argument is marked as exposed, but does not have a name.") - if len(decls) == 1: - name = arg = decls[0] - name = name.replace("-", "_").lower() - else: - raise TypeError( - "Arguments take exactly one parameter declaration, got" - f" {len(decls)}." - ) - return name, [arg], [] - - def get_usage_pieces(self, ctx: Context) -> t.List[str]: - return [self.make_metavar()] - - def get_error_hint(self, ctx: Context) -> str: - return f"'{self.make_metavar()}'" - - def add_to_parser(self, parser: OptionParser, ctx: Context) -> None: - parser.add_argument(dest=self.name, nargs=self.nargs, obj=self) diff --git a/venv/lib/python3.9/site-packages/click/decorators.py b/venv/lib/python3.9/site-packages/click/decorators.py deleted file mode 100644 index bcf8906..0000000 --- a/venv/lib/python3.9/site-packages/click/decorators.py +++ /dev/null @@ -1,562 +0,0 @@ -import inspect -import types -import typing as t -from functools import update_wrapper -from gettext import gettext as _ - -from .core import Argument -from .core import Command -from .core import Context -from .core import Group -from .core import Option -from .core import Parameter -from .globals import get_current_context -from .utils import echo - -if t.TYPE_CHECKING: - import typing_extensions as te - - P = te.ParamSpec("P") - -R = t.TypeVar("R") -T = t.TypeVar("T") -_AnyCallable = t.Callable[..., t.Any] -FC = t.TypeVar("FC", bound=t.Union[_AnyCallable, Command]) - - -def pass_context(f: "t.Callable[te.Concatenate[Context, P], R]") -> "t.Callable[P, R]": - """Marks a callback as wanting to receive the current context - object as first argument. - """ - - def new_func(*args: "P.args", **kwargs: "P.kwargs") -> "R": - return f(get_current_context(), *args, **kwargs) - - return update_wrapper(new_func, f) - - -def pass_obj(f: "t.Callable[te.Concatenate[t.Any, P], R]") -> "t.Callable[P, R]": - """Similar to :func:`pass_context`, but only pass the object on the - context onwards (:attr:`Context.obj`). This is useful if that object - represents the state of a nested system. - """ - - def new_func(*args: "P.args", **kwargs: "P.kwargs") -> "R": - return f(get_current_context().obj, *args, **kwargs) - - return update_wrapper(new_func, f) - - -def make_pass_decorator( - object_type: t.Type[T], ensure: bool = False -) -> t.Callable[["t.Callable[te.Concatenate[T, P], R]"], "t.Callable[P, R]"]: - """Given an object type this creates a decorator that will work - similar to :func:`pass_obj` but instead of passing the object of the - current context, it will find the innermost context of type - :func:`object_type`. - - This generates a decorator that works roughly like this:: - - from functools import update_wrapper - - def decorator(f): - @pass_context - def new_func(ctx, *args, **kwargs): - obj = ctx.find_object(object_type) - return ctx.invoke(f, obj, *args, **kwargs) - return update_wrapper(new_func, f) - return decorator - - :param object_type: the type of the object to pass. - :param ensure: if set to `True`, a new object will be created and - remembered on the context if it's not there yet. - """ - - def decorator(f: "t.Callable[te.Concatenate[T, P], R]") -> "t.Callable[P, R]": - def new_func(*args: "P.args", **kwargs: "P.kwargs") -> "R": - ctx = get_current_context() - - obj: t.Optional[T] - if ensure: - obj = ctx.ensure_object(object_type) - else: - obj = ctx.find_object(object_type) - - if obj is None: - raise RuntimeError( - "Managed to invoke callback without a context" - f" object of type {object_type.__name__!r}" - " existing." - ) - - return ctx.invoke(f, obj, *args, **kwargs) - - return update_wrapper(new_func, f) - - return decorator - - -def pass_meta_key( - key: str, *, doc_description: t.Optional[str] = None -) -> "t.Callable[[t.Callable[te.Concatenate[t.Any, P], R]], t.Callable[P, R]]": - """Create a decorator that passes a key from - :attr:`click.Context.meta` as the first argument to the decorated - function. - - :param key: Key in ``Context.meta`` to pass. - :param doc_description: Description of the object being passed, - inserted into the decorator's docstring. Defaults to "the 'key' - key from Context.meta". - - .. versionadded:: 8.0 - """ - - def decorator(f: "t.Callable[te.Concatenate[t.Any, P], R]") -> "t.Callable[P, R]": - def new_func(*args: "P.args", **kwargs: "P.kwargs") -> R: - ctx = get_current_context() - obj = ctx.meta[key] - return ctx.invoke(f, obj, *args, **kwargs) - - return update_wrapper(new_func, f) - - if doc_description is None: - doc_description = f"the {key!r} key from :attr:`click.Context.meta`" - - decorator.__doc__ = ( - f"Decorator that passes {doc_description} as the first argument" - " to the decorated function." - ) - return decorator - - -CmdType = t.TypeVar("CmdType", bound=Command) - - -# variant: no call, directly as decorator for a function. -@t.overload -def command(name: _AnyCallable) -> Command: ... - - -# variant: with positional name and with positional or keyword cls argument: -# @command(namearg, CommandCls, ...) or @command(namearg, cls=CommandCls, ...) -@t.overload -def command( - name: t.Optional[str], - cls: t.Type[CmdType], - **attrs: t.Any, -) -> t.Callable[[_AnyCallable], CmdType]: ... - - -# variant: name omitted, cls _must_ be a keyword argument, @command(cls=CommandCls, ...) -@t.overload -def command( - name: None = None, - *, - cls: t.Type[CmdType], - **attrs: t.Any, -) -> t.Callable[[_AnyCallable], CmdType]: ... - - -# variant: with optional string name, no cls argument provided. -@t.overload -def command( - name: t.Optional[str] = ..., cls: None = None, **attrs: t.Any -) -> t.Callable[[_AnyCallable], Command]: ... - - -def command( - name: t.Union[t.Optional[str], _AnyCallable] = None, - cls: t.Optional[t.Type[CmdType]] = None, - **attrs: t.Any, -) -> t.Union[Command, t.Callable[[_AnyCallable], t.Union[Command, CmdType]]]: - r"""Creates a new :class:`Command` and uses the decorated function as - callback. This will also automatically attach all decorated - :func:`option`\s and :func:`argument`\s as parameters to the command. - - The name of the command defaults to the name of the function with - underscores replaced by dashes. If you want to change that, you can - pass the intended name as the first argument. - - All keyword arguments are forwarded to the underlying command class. - For the ``params`` argument, any decorated params are appended to - the end of the list. - - Once decorated the function turns into a :class:`Command` instance - that can be invoked as a command line utility or be attached to a - command :class:`Group`. - - :param name: the name of the command. This defaults to the function - name with underscores replaced by dashes. - :param cls: the command class to instantiate. This defaults to - :class:`Command`. - - .. versionchanged:: 8.1 - This decorator can be applied without parentheses. - - .. versionchanged:: 8.1 - The ``params`` argument can be used. Decorated params are - appended to the end of the list. - """ - - func: t.Optional[t.Callable[[_AnyCallable], t.Any]] = None - - if callable(name): - func = name - name = None - assert cls is None, "Use 'command(cls=cls)(callable)' to specify a class." - assert not attrs, "Use 'command(**kwargs)(callable)' to provide arguments." - - if cls is None: - cls = t.cast(t.Type[CmdType], Command) - - def decorator(f: _AnyCallable) -> CmdType: - if isinstance(f, Command): - raise TypeError("Attempted to convert a callback into a command twice.") - - attr_params = attrs.pop("params", None) - params = attr_params if attr_params is not None else [] - - try: - decorator_params = f.__click_params__ # type: ignore - except AttributeError: - pass - else: - del f.__click_params__ # type: ignore - params.extend(reversed(decorator_params)) - - if attrs.get("help") is None: - attrs["help"] = f.__doc__ - - if t.TYPE_CHECKING: - assert cls is not None - assert not callable(name) - - cmd = cls( - name=name or f.__name__.lower().replace("_", "-"), - callback=f, - params=params, - **attrs, - ) - cmd.__doc__ = f.__doc__ - return cmd - - if func is not None: - return decorator(func) - - return decorator - - -GrpType = t.TypeVar("GrpType", bound=Group) - - -# variant: no call, directly as decorator for a function. -@t.overload -def group(name: _AnyCallable) -> Group: ... - - -# variant: with positional name and with positional or keyword cls argument: -# @group(namearg, GroupCls, ...) or @group(namearg, cls=GroupCls, ...) -@t.overload -def group( - name: t.Optional[str], - cls: t.Type[GrpType], - **attrs: t.Any, -) -> t.Callable[[_AnyCallable], GrpType]: ... - - -# variant: name omitted, cls _must_ be a keyword argument, @group(cmd=GroupCls, ...) -@t.overload -def group( - name: None = None, - *, - cls: t.Type[GrpType], - **attrs: t.Any, -) -> t.Callable[[_AnyCallable], GrpType]: ... - - -# variant: with optional string name, no cls argument provided. -@t.overload -def group( - name: t.Optional[str] = ..., cls: None = None, **attrs: t.Any -) -> t.Callable[[_AnyCallable], Group]: ... - - -def group( - name: t.Union[str, _AnyCallable, None] = None, - cls: t.Optional[t.Type[GrpType]] = None, - **attrs: t.Any, -) -> t.Union[Group, t.Callable[[_AnyCallable], t.Union[Group, GrpType]]]: - """Creates a new :class:`Group` with a function as callback. This - works otherwise the same as :func:`command` just that the `cls` - parameter is set to :class:`Group`. - - .. versionchanged:: 8.1 - This decorator can be applied without parentheses. - """ - if cls is None: - cls = t.cast(t.Type[GrpType], Group) - - if callable(name): - return command(cls=cls, **attrs)(name) - - return command(name, cls, **attrs) - - -def _param_memo(f: t.Callable[..., t.Any], param: Parameter) -> None: - if isinstance(f, Command): - f.params.append(param) - else: - if not hasattr(f, "__click_params__"): - f.__click_params__ = [] # type: ignore - - f.__click_params__.append(param) # type: ignore - - -def argument( - *param_decls: str, cls: t.Optional[t.Type[Argument]] = None, **attrs: t.Any -) -> t.Callable[[FC], FC]: - """Attaches an argument to the command. All positional arguments are - passed as parameter declarations to :class:`Argument`; all keyword - arguments are forwarded unchanged (except ``cls``). - This is equivalent to creating an :class:`Argument` instance manually - and attaching it to the :attr:`Command.params` list. - - For the default argument class, refer to :class:`Argument` and - :class:`Parameter` for descriptions of parameters. - - :param cls: the argument class to instantiate. This defaults to - :class:`Argument`. - :param param_decls: Passed as positional arguments to the constructor of - ``cls``. - :param attrs: Passed as keyword arguments to the constructor of ``cls``. - """ - if cls is None: - cls = Argument - - def decorator(f: FC) -> FC: - _param_memo(f, cls(param_decls, **attrs)) - return f - - return decorator - - -def option( - *param_decls: str, cls: t.Optional[t.Type[Option]] = None, **attrs: t.Any -) -> t.Callable[[FC], FC]: - """Attaches an option to the command. All positional arguments are - passed as parameter declarations to :class:`Option`; all keyword - arguments are forwarded unchanged (except ``cls``). - This is equivalent to creating an :class:`Option` instance manually - and attaching it to the :attr:`Command.params` list. - - For the default option class, refer to :class:`Option` and - :class:`Parameter` for descriptions of parameters. - - :param cls: the option class to instantiate. This defaults to - :class:`Option`. - :param param_decls: Passed as positional arguments to the constructor of - ``cls``. - :param attrs: Passed as keyword arguments to the constructor of ``cls``. - """ - if cls is None: - cls = Option - - def decorator(f: FC) -> FC: - _param_memo(f, cls(param_decls, **attrs)) - return f - - return decorator - - -def confirmation_option(*param_decls: str, **kwargs: t.Any) -> t.Callable[[FC], FC]: - """Add a ``--yes`` option which shows a prompt before continuing if - not passed. If the prompt is declined, the program will exit. - - :param param_decls: One or more option names. Defaults to the single - value ``"--yes"``. - :param kwargs: Extra arguments are passed to :func:`option`. - """ - - def callback(ctx: Context, param: Parameter, value: bool) -> None: - if not value: - ctx.abort() - - if not param_decls: - param_decls = ("--yes",) - - kwargs.setdefault("is_flag", True) - kwargs.setdefault("callback", callback) - kwargs.setdefault("expose_value", False) - kwargs.setdefault("prompt", "Do you want to continue?") - kwargs.setdefault("help", "Confirm the action without prompting.") - return option(*param_decls, **kwargs) - - -def password_option(*param_decls: str, **kwargs: t.Any) -> t.Callable[[FC], FC]: - """Add a ``--password`` option which prompts for a password, hiding - input and asking to enter the value again for confirmation. - - :param param_decls: One or more option names. Defaults to the single - value ``"--password"``. - :param kwargs: Extra arguments are passed to :func:`option`. - """ - if not param_decls: - param_decls = ("--password",) - - kwargs.setdefault("prompt", True) - kwargs.setdefault("confirmation_prompt", True) - kwargs.setdefault("hide_input", True) - return option(*param_decls, **kwargs) - - -def version_option( - version: t.Optional[str] = None, - *param_decls: str, - package_name: t.Optional[str] = None, - prog_name: t.Optional[str] = None, - message: t.Optional[str] = None, - **kwargs: t.Any, -) -> t.Callable[[FC], FC]: - """Add a ``--version`` option which immediately prints the version - number and exits the program. - - If ``version`` is not provided, Click will try to detect it using - :func:`importlib.metadata.version` to get the version for the - ``package_name``. On Python < 3.8, the ``importlib_metadata`` - backport must be installed. - - If ``package_name`` is not provided, Click will try to detect it by - inspecting the stack frames. This will be used to detect the - version, so it must match the name of the installed package. - - :param version: The version number to show. If not provided, Click - will try to detect it. - :param param_decls: One or more option names. Defaults to the single - value ``"--version"``. - :param package_name: The package name to detect the version from. If - not provided, Click will try to detect it. - :param prog_name: The name of the CLI to show in the message. If not - provided, it will be detected from the command. - :param message: The message to show. The values ``%(prog)s``, - ``%(package)s``, and ``%(version)s`` are available. Defaults to - ``"%(prog)s, version %(version)s"``. - :param kwargs: Extra arguments are passed to :func:`option`. - :raise RuntimeError: ``version`` could not be detected. - - .. versionchanged:: 8.0 - Add the ``package_name`` parameter, and the ``%(package)s`` - value for messages. - - .. versionchanged:: 8.0 - Use :mod:`importlib.metadata` instead of ``pkg_resources``. The - version is detected based on the package name, not the entry - point name. The Python package name must match the installed - package name, or be passed with ``package_name=``. - """ - if message is None: - message = _("%(prog)s, version %(version)s") - - if version is None and package_name is None: - frame = inspect.currentframe() - f_back = frame.f_back if frame is not None else None - f_globals = f_back.f_globals if f_back is not None else None - # break reference cycle - # https://docs.python.org/3/library/inspect.html#the-interpreter-stack - del frame - - if f_globals is not None: - package_name = f_globals.get("__name__") - - if package_name == "__main__": - package_name = f_globals.get("__package__") - - if package_name: - package_name = package_name.partition(".")[0] - - def callback(ctx: Context, param: Parameter, value: bool) -> None: - if not value or ctx.resilient_parsing: - return - - nonlocal prog_name - nonlocal version - - if prog_name is None: - prog_name = ctx.find_root().info_name - - if version is None and package_name is not None: - metadata: t.Optional[types.ModuleType] - - try: - from importlib import metadata - except ImportError: - # Python < 3.8 - import importlib_metadata as metadata # type: ignore - - try: - version = metadata.version(package_name) # type: ignore - except metadata.PackageNotFoundError: # type: ignore - raise RuntimeError( - f"{package_name!r} is not installed. Try passing" - " 'package_name' instead." - ) from None - - if version is None: - raise RuntimeError( - f"Could not determine the version for {package_name!r} automatically." - ) - - echo( - message % {"prog": prog_name, "package": package_name, "version": version}, - color=ctx.color, - ) - ctx.exit() - - if not param_decls: - param_decls = ("--version",) - - kwargs.setdefault("is_flag", True) - kwargs.setdefault("expose_value", False) - kwargs.setdefault("is_eager", True) - kwargs.setdefault("help", _("Show the version and exit.")) - kwargs["callback"] = callback - return option(*param_decls, **kwargs) - - -class HelpOption(Option): - """Pre-configured ``--help`` option which immediately prints the help page - and exits the program. - """ - - def __init__( - self, - param_decls: t.Optional[t.Sequence[str]] = None, - **kwargs: t.Any, - ) -> None: - if not param_decls: - param_decls = ("--help",) - - kwargs.setdefault("is_flag", True) - kwargs.setdefault("expose_value", False) - kwargs.setdefault("is_eager", True) - kwargs.setdefault("help", _("Show this message and exit.")) - kwargs.setdefault("callback", self.show_help) - - super().__init__(param_decls, **kwargs) - - @staticmethod - def show_help(ctx: Context, param: Parameter, value: bool) -> None: - """Callback that print the help page on ```` and exits.""" - if value and not ctx.resilient_parsing: - echo(ctx.get_help(), color=ctx.color) - ctx.exit() - - -def help_option(*param_decls: str, **kwargs: t.Any) -> t.Callable[[FC], FC]: - """Decorator for the pre-configured ``--help`` option defined above. - - :param param_decls: One or more option names. Defaults to the single - value ``"--help"``. - :param kwargs: Extra arguments are passed to :func:`option`. - """ - kwargs.setdefault("cls", HelpOption) - return option(*param_decls, **kwargs) diff --git a/venv/lib/python3.9/site-packages/click/exceptions.py b/venv/lib/python3.9/site-packages/click/exceptions.py deleted file mode 100644 index 0b83151..0000000 --- a/venv/lib/python3.9/site-packages/click/exceptions.py +++ /dev/null @@ -1,296 +0,0 @@ -import typing as t -from gettext import gettext as _ -from gettext import ngettext - -from ._compat import get_text_stderr -from .globals import resolve_color_default -from .utils import echo -from .utils import format_filename - -if t.TYPE_CHECKING: - from .core import Command - from .core import Context - from .core import Parameter - - -def _join_param_hints( - param_hint: t.Optional[t.Union[t.Sequence[str], str]], -) -> t.Optional[str]: - if param_hint is not None and not isinstance(param_hint, str): - return " / ".join(repr(x) for x in param_hint) - - return param_hint - - -class ClickException(Exception): - """An exception that Click can handle and show to the user.""" - - #: The exit code for this exception. - exit_code = 1 - - def __init__(self, message: str) -> None: - super().__init__(message) - # The context will be removed by the time we print the message, so cache - # the color settings here to be used later on (in `show`) - self.show_color: t.Optional[bool] = resolve_color_default() - self.message = message - - def format_message(self) -> str: - return self.message - - def __str__(self) -> str: - return self.message - - def show(self, file: t.Optional[t.IO[t.Any]] = None) -> None: - if file is None: - file = get_text_stderr() - - echo( - _("Error: {message}").format(message=self.format_message()), - file=file, - color=self.show_color, - ) - - -class UsageError(ClickException): - """An internal exception that signals a usage error. This typically - aborts any further handling. - - :param message: the error message to display. - :param ctx: optionally the context that caused this error. Click will - fill in the context automatically in some situations. - """ - - exit_code = 2 - - def __init__(self, message: str, ctx: t.Optional["Context"] = None) -> None: - super().__init__(message) - self.ctx = ctx - self.cmd: t.Optional[Command] = self.ctx.command if self.ctx else None - - def show(self, file: t.Optional[t.IO[t.Any]] = None) -> None: - if file is None: - file = get_text_stderr() - color = None - hint = "" - if ( - self.ctx is not None - and self.ctx.command.get_help_option(self.ctx) is not None - ): - hint = _("Try '{command} {option}' for help.").format( - command=self.ctx.command_path, option=self.ctx.help_option_names[0] - ) - hint = f"{hint}\n" - if self.ctx is not None: - color = self.ctx.color - echo(f"{self.ctx.get_usage()}\n{hint}", file=file, color=color) - echo( - _("Error: {message}").format(message=self.format_message()), - file=file, - color=color, - ) - - -class BadParameter(UsageError): - """An exception that formats out a standardized error message for a - bad parameter. This is useful when thrown from a callback or type as - Click will attach contextual information to it (for instance, which - parameter it is). - - .. versionadded:: 2.0 - - :param param: the parameter object that caused this error. This can - be left out, and Click will attach this info itself - if possible. - :param param_hint: a string that shows up as parameter name. This - can be used as alternative to `param` in cases - where custom validation should happen. If it is - a string it's used as such, if it's a list then - each item is quoted and separated. - """ - - def __init__( - self, - message: str, - ctx: t.Optional["Context"] = None, - param: t.Optional["Parameter"] = None, - param_hint: t.Optional[str] = None, - ) -> None: - super().__init__(message, ctx) - self.param = param - self.param_hint = param_hint - - def format_message(self) -> str: - if self.param_hint is not None: - param_hint = self.param_hint - elif self.param is not None: - param_hint = self.param.get_error_hint(self.ctx) # type: ignore - else: - return _("Invalid value: {message}").format(message=self.message) - - return _("Invalid value for {param_hint}: {message}").format( - param_hint=_join_param_hints(param_hint), message=self.message - ) - - -class MissingParameter(BadParameter): - """Raised if click required an option or argument but it was not - provided when invoking the script. - - .. versionadded:: 4.0 - - :param param_type: a string that indicates the type of the parameter. - The default is to inherit the parameter type from - the given `param`. Valid values are ``'parameter'``, - ``'option'`` or ``'argument'``. - """ - - def __init__( - self, - message: t.Optional[str] = None, - ctx: t.Optional["Context"] = None, - param: t.Optional["Parameter"] = None, - param_hint: t.Optional[str] = None, - param_type: t.Optional[str] = None, - ) -> None: - super().__init__(message or "", ctx, param, param_hint) - self.param_type = param_type - - def format_message(self) -> str: - if self.param_hint is not None: - param_hint: t.Optional[str] = self.param_hint - elif self.param is not None: - param_hint = self.param.get_error_hint(self.ctx) # type: ignore - else: - param_hint = None - - param_hint = _join_param_hints(param_hint) - param_hint = f" {param_hint}" if param_hint else "" - - param_type = self.param_type - if param_type is None and self.param is not None: - param_type = self.param.param_type_name - - msg = self.message - if self.param is not None: - msg_extra = self.param.type.get_missing_message(self.param) - if msg_extra: - if msg: - msg += f". {msg_extra}" - else: - msg = msg_extra - - msg = f" {msg}" if msg else "" - - # Translate param_type for known types. - if param_type == "argument": - missing = _("Missing argument") - elif param_type == "option": - missing = _("Missing option") - elif param_type == "parameter": - missing = _("Missing parameter") - else: - missing = _("Missing {param_type}").format(param_type=param_type) - - return f"{missing}{param_hint}.{msg}" - - def __str__(self) -> str: - if not self.message: - param_name = self.param.name if self.param else None - return _("Missing parameter: {param_name}").format(param_name=param_name) - else: - return self.message - - -class NoSuchOption(UsageError): - """Raised if click attempted to handle an option that does not - exist. - - .. versionadded:: 4.0 - """ - - def __init__( - self, - option_name: str, - message: t.Optional[str] = None, - possibilities: t.Optional[t.Sequence[str]] = None, - ctx: t.Optional["Context"] = None, - ) -> None: - if message is None: - message = _("No such option: {name}").format(name=option_name) - - super().__init__(message, ctx) - self.option_name = option_name - self.possibilities = possibilities - - def format_message(self) -> str: - if not self.possibilities: - return self.message - - possibility_str = ", ".join(sorted(self.possibilities)) - suggest = ngettext( - "Did you mean {possibility}?", - "(Possible options: {possibilities})", - len(self.possibilities), - ).format(possibility=possibility_str, possibilities=possibility_str) - return f"{self.message} {suggest}" - - -class BadOptionUsage(UsageError): - """Raised if an option is generally supplied but the use of the option - was incorrect. This is for instance raised if the number of arguments - for an option is not correct. - - .. versionadded:: 4.0 - - :param option_name: the name of the option being used incorrectly. - """ - - def __init__( - self, option_name: str, message: str, ctx: t.Optional["Context"] = None - ) -> None: - super().__init__(message, ctx) - self.option_name = option_name - - -class BadArgumentUsage(UsageError): - """Raised if an argument is generally supplied but the use of the argument - was incorrect. This is for instance raised if the number of values - for an argument is not correct. - - .. versionadded:: 6.0 - """ - - -class FileError(ClickException): - """Raised if a file cannot be opened.""" - - def __init__(self, filename: str, hint: t.Optional[str] = None) -> None: - if hint is None: - hint = _("unknown error") - - super().__init__(hint) - self.ui_filename: str = format_filename(filename) - self.filename = filename - - def format_message(self) -> str: - return _("Could not open file {filename!r}: {message}").format( - filename=self.ui_filename, message=self.message - ) - - -class Abort(RuntimeError): - """An internal signalling exception that signals Click to abort.""" - - -class Exit(RuntimeError): - """An exception that indicates that the application should exit with some - status code. - - :param code: the status code to exit with. - """ - - __slots__ = ("exit_code",) - - def __init__(self, code: int = 0) -> None: - self.exit_code: int = code diff --git a/venv/lib/python3.9/site-packages/click/formatting.py b/venv/lib/python3.9/site-packages/click/formatting.py deleted file mode 100644 index ddd2a2f..0000000 --- a/venv/lib/python3.9/site-packages/click/formatting.py +++ /dev/null @@ -1,301 +0,0 @@ -import typing as t -from contextlib import contextmanager -from gettext import gettext as _ - -from ._compat import term_len -from .parser import split_opt - -# Can force a width. This is used by the test system -FORCED_WIDTH: t.Optional[int] = None - - -def measure_table(rows: t.Iterable[t.Tuple[str, str]]) -> t.Tuple[int, ...]: - widths: t.Dict[int, int] = {} - - for row in rows: - for idx, col in enumerate(row): - widths[idx] = max(widths.get(idx, 0), term_len(col)) - - return tuple(y for x, y in sorted(widths.items())) - - -def iter_rows( - rows: t.Iterable[t.Tuple[str, str]], col_count: int -) -> t.Iterator[t.Tuple[str, ...]]: - for row in rows: - yield row + ("",) * (col_count - len(row)) - - -def wrap_text( - text: str, - width: int = 78, - initial_indent: str = "", - subsequent_indent: str = "", - preserve_paragraphs: bool = False, -) -> str: - """A helper function that intelligently wraps text. By default, it - assumes that it operates on a single paragraph of text but if the - `preserve_paragraphs` parameter is provided it will intelligently - handle paragraphs (defined by two empty lines). - - If paragraphs are handled, a paragraph can be prefixed with an empty - line containing the ``\\b`` character (``\\x08``) to indicate that - no rewrapping should happen in that block. - - :param text: the text that should be rewrapped. - :param width: the maximum width for the text. - :param initial_indent: the initial indent that should be placed on the - first line as a string. - :param subsequent_indent: the indent string that should be placed on - each consecutive line. - :param preserve_paragraphs: if this flag is set then the wrapping will - intelligently handle paragraphs. - """ - from ._textwrap import TextWrapper - - text = text.expandtabs() - wrapper = TextWrapper( - width, - initial_indent=initial_indent, - subsequent_indent=subsequent_indent, - replace_whitespace=False, - ) - if not preserve_paragraphs: - return wrapper.fill(text) - - p: t.List[t.Tuple[int, bool, str]] = [] - buf: t.List[str] = [] - indent = None - - def _flush_par() -> None: - if not buf: - return - if buf[0].strip() == "\b": - p.append((indent or 0, True, "\n".join(buf[1:]))) - else: - p.append((indent or 0, False, " ".join(buf))) - del buf[:] - - for line in text.splitlines(): - if not line: - _flush_par() - indent = None - else: - if indent is None: - orig_len = term_len(line) - line = line.lstrip() - indent = orig_len - term_len(line) - buf.append(line) - _flush_par() - - rv = [] - for indent, raw, text in p: - with wrapper.extra_indent(" " * indent): - if raw: - rv.append(wrapper.indent_only(text)) - else: - rv.append(wrapper.fill(text)) - - return "\n\n".join(rv) - - -class HelpFormatter: - """This class helps with formatting text-based help pages. It's - usually just needed for very special internal cases, but it's also - exposed so that developers can write their own fancy outputs. - - At present, it always writes into memory. - - :param indent_increment: the additional increment for each level. - :param width: the width for the text. This defaults to the terminal - width clamped to a maximum of 78. - """ - - def __init__( - self, - indent_increment: int = 2, - width: t.Optional[int] = None, - max_width: t.Optional[int] = None, - ) -> None: - import shutil - - self.indent_increment = indent_increment - if max_width is None: - max_width = 80 - if width is None: - width = FORCED_WIDTH - if width is None: - width = max(min(shutil.get_terminal_size().columns, max_width) - 2, 50) - self.width = width - self.current_indent = 0 - self.buffer: t.List[str] = [] - - def write(self, string: str) -> None: - """Writes a unicode string into the internal buffer.""" - self.buffer.append(string) - - def indent(self) -> None: - """Increases the indentation.""" - self.current_indent += self.indent_increment - - def dedent(self) -> None: - """Decreases the indentation.""" - self.current_indent -= self.indent_increment - - def write_usage( - self, prog: str, args: str = "", prefix: t.Optional[str] = None - ) -> None: - """Writes a usage line into the buffer. - - :param prog: the program name. - :param args: whitespace separated list of arguments. - :param prefix: The prefix for the first line. Defaults to - ``"Usage: "``. - """ - if prefix is None: - prefix = f"{_('Usage:')} " - - usage_prefix = f"{prefix:>{self.current_indent}}{prog} " - text_width = self.width - self.current_indent - - if text_width >= (term_len(usage_prefix) + 20): - # The arguments will fit to the right of the prefix. - indent = " " * term_len(usage_prefix) - self.write( - wrap_text( - args, - text_width, - initial_indent=usage_prefix, - subsequent_indent=indent, - ) - ) - else: - # The prefix is too long, put the arguments on the next line. - self.write(usage_prefix) - self.write("\n") - indent = " " * (max(self.current_indent, term_len(prefix)) + 4) - self.write( - wrap_text( - args, text_width, initial_indent=indent, subsequent_indent=indent - ) - ) - - self.write("\n") - - def write_heading(self, heading: str) -> None: - """Writes a heading into the buffer.""" - self.write(f"{'':>{self.current_indent}}{heading}:\n") - - def write_paragraph(self) -> None: - """Writes a paragraph into the buffer.""" - if self.buffer: - self.write("\n") - - def write_text(self, text: str) -> None: - """Writes re-indented text into the buffer. This rewraps and - preserves paragraphs. - """ - indent = " " * self.current_indent - self.write( - wrap_text( - text, - self.width, - initial_indent=indent, - subsequent_indent=indent, - preserve_paragraphs=True, - ) - ) - self.write("\n") - - def write_dl( - self, - rows: t.Sequence[t.Tuple[str, str]], - col_max: int = 30, - col_spacing: int = 2, - ) -> None: - """Writes a definition list into the buffer. This is how options - and commands are usually formatted. - - :param rows: a list of two item tuples for the terms and values. - :param col_max: the maximum width of the first column. - :param col_spacing: the number of spaces between the first and - second column. - """ - rows = list(rows) - widths = measure_table(rows) - if len(widths) != 2: - raise TypeError("Expected two columns for definition list") - - first_col = min(widths[0], col_max) + col_spacing - - for first, second in iter_rows(rows, len(widths)): - self.write(f"{'':>{self.current_indent}}{first}") - if not second: - self.write("\n") - continue - if term_len(first) <= first_col - col_spacing: - self.write(" " * (first_col - term_len(first))) - else: - self.write("\n") - self.write(" " * (first_col + self.current_indent)) - - text_width = max(self.width - first_col - 2, 10) - wrapped_text = wrap_text(second, text_width, preserve_paragraphs=True) - lines = wrapped_text.splitlines() - - if lines: - self.write(f"{lines[0]}\n") - - for line in lines[1:]: - self.write(f"{'':>{first_col + self.current_indent}}{line}\n") - else: - self.write("\n") - - @contextmanager - def section(self, name: str) -> t.Iterator[None]: - """Helpful context manager that writes a paragraph, a heading, - and the indents. - - :param name: the section name that is written as heading. - """ - self.write_paragraph() - self.write_heading(name) - self.indent() - try: - yield - finally: - self.dedent() - - @contextmanager - def indentation(self) -> t.Iterator[None]: - """A context manager that increases the indentation.""" - self.indent() - try: - yield - finally: - self.dedent() - - def getvalue(self) -> str: - """Returns the buffer contents.""" - return "".join(self.buffer) - - -def join_options(options: t.Sequence[str]) -> t.Tuple[str, bool]: - """Given a list of option strings this joins them in the most appropriate - way and returns them in the form ``(formatted_string, - any_prefix_is_slash)`` where the second item in the tuple is a flag that - indicates if any of the option prefixes was a slash. - """ - rv = [] - any_prefix_is_slash = False - - for opt in options: - prefix = split_opt(opt)[0] - - if prefix == "/": - any_prefix_is_slash = True - - rv.append((len(prefix), opt)) - - rv.sort(key=lambda x: x[0]) - return ", ".join(x[1] for x in rv), any_prefix_is_slash diff --git a/venv/lib/python3.9/site-packages/click/globals.py b/venv/lib/python3.9/site-packages/click/globals.py deleted file mode 100644 index 191e712..0000000 --- a/venv/lib/python3.9/site-packages/click/globals.py +++ /dev/null @@ -1,67 +0,0 @@ -import typing as t -from threading import local - -if t.TYPE_CHECKING: - import typing_extensions as te - - from .core import Context - -_local = local() - - -@t.overload -def get_current_context(silent: "te.Literal[False]" = False) -> "Context": ... - - -@t.overload -def get_current_context(silent: bool = ...) -> t.Optional["Context"]: ... - - -def get_current_context(silent: bool = False) -> t.Optional["Context"]: - """Returns the current click context. This can be used as a way to - access the current context object from anywhere. This is a more implicit - alternative to the :func:`pass_context` decorator. This function is - primarily useful for helpers such as :func:`echo` which might be - interested in changing its behavior based on the current context. - - To push the current context, :meth:`Context.scope` can be used. - - .. versionadded:: 5.0 - - :param silent: if set to `True` the return value is `None` if no context - is available. The default behavior is to raise a - :exc:`RuntimeError`. - """ - try: - return t.cast("Context", _local.stack[-1]) - except (AttributeError, IndexError) as e: - if not silent: - raise RuntimeError("There is no active click context.") from e - - return None - - -def push_context(ctx: "Context") -> None: - """Pushes a new context to the current stack.""" - _local.__dict__.setdefault("stack", []).append(ctx) - - -def pop_context() -> None: - """Removes the top level from the stack.""" - _local.stack.pop() - - -def resolve_color_default(color: t.Optional[bool] = None) -> t.Optional[bool]: - """Internal helper to get the default value of the color flag. If a - value is passed it's returned unchanged, otherwise it's looked up from - the current context. - """ - if color is not None: - return color - - ctx = get_current_context(silent=True) - - if ctx is not None: - return ctx.color - - return None diff --git a/venv/lib/python3.9/site-packages/click/parser.py b/venv/lib/python3.9/site-packages/click/parser.py deleted file mode 100644 index 600b843..0000000 --- a/venv/lib/python3.9/site-packages/click/parser.py +++ /dev/null @@ -1,531 +0,0 @@ -""" -This module started out as largely a copy paste from the stdlib's -optparse module with the features removed that we do not need from -optparse because we implement them in Click on a higher level (for -instance type handling, help formatting and a lot more). - -The plan is to remove more and more from here over time. - -The reason this is a different module and not optparse from the stdlib -is that there are differences in 2.x and 3.x about the error messages -generated and optparse in the stdlib uses gettext for no good reason -and might cause us issues. - -Click uses parts of optparse written by Gregory P. Ward and maintained -by the Python Software Foundation. This is limited to code in parser.py. - -Copyright 2001-2006 Gregory P. Ward. All rights reserved. -Copyright 2002-2006 Python Software Foundation. All rights reserved. -""" - -# This code uses parts of optparse written by Gregory P. Ward and -# maintained by the Python Software Foundation. -# Copyright 2001-2006 Gregory P. Ward -# Copyright 2002-2006 Python Software Foundation -import typing as t -from collections import deque -from gettext import gettext as _ -from gettext import ngettext - -from .exceptions import BadArgumentUsage -from .exceptions import BadOptionUsage -from .exceptions import NoSuchOption -from .exceptions import UsageError - -if t.TYPE_CHECKING: - import typing_extensions as te - - from .core import Argument as CoreArgument - from .core import Context - from .core import Option as CoreOption - from .core import Parameter as CoreParameter - -V = t.TypeVar("V") - -# Sentinel value that indicates an option was passed as a flag without a -# value but is not a flag option. Option.consume_value uses this to -# prompt or use the flag_value. -_flag_needs_value = object() - - -def _unpack_args( - args: t.Sequence[str], nargs_spec: t.Sequence[int] -) -> t.Tuple[t.Sequence[t.Union[str, t.Sequence[t.Optional[str]], None]], t.List[str]]: - """Given an iterable of arguments and an iterable of nargs specifications, - it returns a tuple with all the unpacked arguments at the first index - and all remaining arguments as the second. - - The nargs specification is the number of arguments that should be consumed - or `-1` to indicate that this position should eat up all the remainders. - - Missing items are filled with `None`. - """ - args = deque(args) - nargs_spec = deque(nargs_spec) - rv: t.List[t.Union[str, t.Tuple[t.Optional[str], ...], None]] = [] - spos: t.Optional[int] = None - - def _fetch(c: "te.Deque[V]") -> t.Optional[V]: - try: - if spos is None: - return c.popleft() - else: - return c.pop() - except IndexError: - return None - - while nargs_spec: - nargs = _fetch(nargs_spec) - - if nargs is None: - continue - - if nargs == 1: - rv.append(_fetch(args)) - elif nargs > 1: - x = [_fetch(args) for _ in range(nargs)] - - # If we're reversed, we're pulling in the arguments in reverse, - # so we need to turn them around. - if spos is not None: - x.reverse() - - rv.append(tuple(x)) - elif nargs < 0: - if spos is not None: - raise TypeError("Cannot have two nargs < 0") - - spos = len(rv) - rv.append(None) - - # spos is the position of the wildcard (star). If it's not `None`, - # we fill it with the remainder. - if spos is not None: - rv[spos] = tuple(args) - args = [] - rv[spos + 1 :] = reversed(rv[spos + 1 :]) - - return tuple(rv), list(args) - - -def split_opt(opt: str) -> t.Tuple[str, str]: - first = opt[:1] - if first.isalnum(): - return "", opt - if opt[1:2] == first: - return opt[:2], opt[2:] - return first, opt[1:] - - -def normalize_opt(opt: str, ctx: t.Optional["Context"]) -> str: - if ctx is None or ctx.token_normalize_func is None: - return opt - prefix, opt = split_opt(opt) - return f"{prefix}{ctx.token_normalize_func(opt)}" - - -def split_arg_string(string: str) -> t.List[str]: - """Split an argument string as with :func:`shlex.split`, but don't - fail if the string is incomplete. Ignores a missing closing quote or - incomplete escape sequence and uses the partial token as-is. - - .. code-block:: python - - split_arg_string("example 'my file") - ["example", "my file"] - - split_arg_string("example my\\") - ["example", "my"] - - :param string: String to split. - """ - import shlex - - lex = shlex.shlex(string, posix=True) - lex.whitespace_split = True - lex.commenters = "" - out = [] - - try: - for token in lex: - out.append(token) - except ValueError: - # Raised when end-of-string is reached in an invalid state. Use - # the partial token as-is. The quote or escape character is in - # lex.state, not lex.token. - out.append(lex.token) - - return out - - -class Option: - def __init__( - self, - obj: "CoreOption", - opts: t.Sequence[str], - dest: t.Optional[str], - action: t.Optional[str] = None, - nargs: int = 1, - const: t.Optional[t.Any] = None, - ): - self._short_opts = [] - self._long_opts = [] - self.prefixes: t.Set[str] = set() - - for opt in opts: - prefix, value = split_opt(opt) - if not prefix: - raise ValueError(f"Invalid start character for option ({opt})") - self.prefixes.add(prefix[0]) - if len(prefix) == 1 and len(value) == 1: - self._short_opts.append(opt) - else: - self._long_opts.append(opt) - self.prefixes.add(prefix) - - if action is None: - action = "store" - - self.dest = dest - self.action = action - self.nargs = nargs - self.const = const - self.obj = obj - - @property - def takes_value(self) -> bool: - return self.action in ("store", "append") - - def process(self, value: t.Any, state: "ParsingState") -> None: - if self.action == "store": - state.opts[self.dest] = value # type: ignore - elif self.action == "store_const": - state.opts[self.dest] = self.const # type: ignore - elif self.action == "append": - state.opts.setdefault(self.dest, []).append(value) # type: ignore - elif self.action == "append_const": - state.opts.setdefault(self.dest, []).append(self.const) # type: ignore - elif self.action == "count": - state.opts[self.dest] = state.opts.get(self.dest, 0) + 1 # type: ignore - else: - raise ValueError(f"unknown action '{self.action}'") - state.order.append(self.obj) - - -class Argument: - def __init__(self, obj: "CoreArgument", dest: t.Optional[str], nargs: int = 1): - self.dest = dest - self.nargs = nargs - self.obj = obj - - def process( - self, - value: t.Union[t.Optional[str], t.Sequence[t.Optional[str]]], - state: "ParsingState", - ) -> None: - if self.nargs > 1: - assert value is not None - holes = sum(1 for x in value if x is None) - if holes == len(value): - value = None - elif holes != 0: - raise BadArgumentUsage( - _("Argument {name!r} takes {nargs} values.").format( - name=self.dest, nargs=self.nargs - ) - ) - - if self.nargs == -1 and self.obj.envvar is not None and value == (): - # Replace empty tuple with None so that a value from the - # environment may be tried. - value = None - - state.opts[self.dest] = value # type: ignore - state.order.append(self.obj) - - -class ParsingState: - def __init__(self, rargs: t.List[str]) -> None: - self.opts: t.Dict[str, t.Any] = {} - self.largs: t.List[str] = [] - self.rargs = rargs - self.order: t.List[CoreParameter] = [] - - -class OptionParser: - """The option parser is an internal class that is ultimately used to - parse options and arguments. It's modelled after optparse and brings - a similar but vastly simplified API. It should generally not be used - directly as the high level Click classes wrap it for you. - - It's not nearly as extensible as optparse or argparse as it does not - implement features that are implemented on a higher level (such as - types or defaults). - - :param ctx: optionally the :class:`~click.Context` where this parser - should go with. - """ - - def __init__(self, ctx: t.Optional["Context"] = None) -> None: - #: The :class:`~click.Context` for this parser. This might be - #: `None` for some advanced use cases. - self.ctx = ctx - #: This controls how the parser deals with interspersed arguments. - #: If this is set to `False`, the parser will stop on the first - #: non-option. Click uses this to implement nested subcommands - #: safely. - self.allow_interspersed_args: bool = True - #: This tells the parser how to deal with unknown options. By - #: default it will error out (which is sensible), but there is a - #: second mode where it will ignore it and continue processing - #: after shifting all the unknown options into the resulting args. - self.ignore_unknown_options: bool = False - - if ctx is not None: - self.allow_interspersed_args = ctx.allow_interspersed_args - self.ignore_unknown_options = ctx.ignore_unknown_options - - self._short_opt: t.Dict[str, Option] = {} - self._long_opt: t.Dict[str, Option] = {} - self._opt_prefixes = {"-", "--"} - self._args: t.List[Argument] = [] - - def add_option( - self, - obj: "CoreOption", - opts: t.Sequence[str], - dest: t.Optional[str], - action: t.Optional[str] = None, - nargs: int = 1, - const: t.Optional[t.Any] = None, - ) -> None: - """Adds a new option named `dest` to the parser. The destination - is not inferred (unlike with optparse) and needs to be explicitly - provided. Action can be any of ``store``, ``store_const``, - ``append``, ``append_const`` or ``count``. - - The `obj` can be used to identify the option in the order list - that is returned from the parser. - """ - opts = [normalize_opt(opt, self.ctx) for opt in opts] - option = Option(obj, opts, dest, action=action, nargs=nargs, const=const) - self._opt_prefixes.update(option.prefixes) - for opt in option._short_opts: - self._short_opt[opt] = option - for opt in option._long_opts: - self._long_opt[opt] = option - - def add_argument( - self, obj: "CoreArgument", dest: t.Optional[str], nargs: int = 1 - ) -> None: - """Adds a positional argument named `dest` to the parser. - - The `obj` can be used to identify the option in the order list - that is returned from the parser. - """ - self._args.append(Argument(obj, dest=dest, nargs=nargs)) - - def parse_args( - self, args: t.List[str] - ) -> t.Tuple[t.Dict[str, t.Any], t.List[str], t.List["CoreParameter"]]: - """Parses positional arguments and returns ``(values, args, order)`` - for the parsed options and arguments as well as the leftover - arguments if there are any. The order is a list of objects as they - appear on the command line. If arguments appear multiple times they - will be memorized multiple times as well. - """ - state = ParsingState(args) - try: - self._process_args_for_options(state) - self._process_args_for_args(state) - except UsageError: - if self.ctx is None or not self.ctx.resilient_parsing: - raise - return state.opts, state.largs, state.order - - def _process_args_for_args(self, state: ParsingState) -> None: - pargs, args = _unpack_args( - state.largs + state.rargs, [x.nargs for x in self._args] - ) - - for idx, arg in enumerate(self._args): - arg.process(pargs[idx], state) - - state.largs = args - state.rargs = [] - - def _process_args_for_options(self, state: ParsingState) -> None: - while state.rargs: - arg = state.rargs.pop(0) - arglen = len(arg) - # Double dashes always handled explicitly regardless of what - # prefixes are valid. - if arg == "--": - return - elif arg[:1] in self._opt_prefixes and arglen > 1: - self._process_opts(arg, state) - elif self.allow_interspersed_args: - state.largs.append(arg) - else: - state.rargs.insert(0, arg) - return - - # Say this is the original argument list: - # [arg0, arg1, ..., arg(i-1), arg(i), arg(i+1), ..., arg(N-1)] - # ^ - # (we are about to process arg(i)). - # - # Then rargs is [arg(i), ..., arg(N-1)] and largs is a *subset* of - # [arg0, ..., arg(i-1)] (any options and their arguments will have - # been removed from largs). - # - # The while loop will usually consume 1 or more arguments per pass. - # If it consumes 1 (eg. arg is an option that takes no arguments), - # then after _process_arg() is done the situation is: - # - # largs = subset of [arg0, ..., arg(i)] - # rargs = [arg(i+1), ..., arg(N-1)] - # - # If allow_interspersed_args is false, largs will always be - # *empty* -- still a subset of [arg0, ..., arg(i-1)], but - # not a very interesting subset! - - def _match_long_opt( - self, opt: str, explicit_value: t.Optional[str], state: ParsingState - ) -> None: - if opt not in self._long_opt: - from difflib import get_close_matches - - possibilities = get_close_matches(opt, self._long_opt) - raise NoSuchOption(opt, possibilities=possibilities, ctx=self.ctx) - - option = self._long_opt[opt] - if option.takes_value: - # At this point it's safe to modify rargs by injecting the - # explicit value, because no exception is raised in this - # branch. This means that the inserted value will be fully - # consumed. - if explicit_value is not None: - state.rargs.insert(0, explicit_value) - - value = self._get_value_from_state(opt, option, state) - - elif explicit_value is not None: - raise BadOptionUsage( - opt, _("Option {name!r} does not take a value.").format(name=opt) - ) - - else: - value = None - - option.process(value, state) - - def _match_short_opt(self, arg: str, state: ParsingState) -> None: - stop = False - i = 1 - prefix = arg[0] - unknown_options = [] - - for ch in arg[1:]: - opt = normalize_opt(f"{prefix}{ch}", self.ctx) - option = self._short_opt.get(opt) - i += 1 - - if not option: - if self.ignore_unknown_options: - unknown_options.append(ch) - continue - raise NoSuchOption(opt, ctx=self.ctx) - if option.takes_value: - # Any characters left in arg? Pretend they're the - # next arg, and stop consuming characters of arg. - if i < len(arg): - state.rargs.insert(0, arg[i:]) - stop = True - - value = self._get_value_from_state(opt, option, state) - - else: - value = None - - option.process(value, state) - - if stop: - break - - # If we got any unknown options we recombine the string of the - # remaining options and re-attach the prefix, then report that - # to the state as new larg. This way there is basic combinatorics - # that can be achieved while still ignoring unknown arguments. - if self.ignore_unknown_options and unknown_options: - state.largs.append(f"{prefix}{''.join(unknown_options)}") - - def _get_value_from_state( - self, option_name: str, option: Option, state: ParsingState - ) -> t.Any: - nargs = option.nargs - - if len(state.rargs) < nargs: - if option.obj._flag_needs_value: - # Option allows omitting the value. - value = _flag_needs_value - else: - raise BadOptionUsage( - option_name, - ngettext( - "Option {name!r} requires an argument.", - "Option {name!r} requires {nargs} arguments.", - nargs, - ).format(name=option_name, nargs=nargs), - ) - elif nargs == 1: - next_rarg = state.rargs[0] - - if ( - option.obj._flag_needs_value - and isinstance(next_rarg, str) - and next_rarg[:1] in self._opt_prefixes - and len(next_rarg) > 1 - ): - # The next arg looks like the start of an option, don't - # use it as the value if omitting the value is allowed. - value = _flag_needs_value - else: - value = state.rargs.pop(0) - else: - value = tuple(state.rargs[:nargs]) - del state.rargs[:nargs] - - return value - - def _process_opts(self, arg: str, state: ParsingState) -> None: - explicit_value = None - # Long option handling happens in two parts. The first part is - # supporting explicitly attached values. In any case, we will try - # to long match the option first. - if "=" in arg: - long_opt, explicit_value = arg.split("=", 1) - else: - long_opt = arg - norm_long_opt = normalize_opt(long_opt, self.ctx) - - # At this point we will match the (assumed) long option through - # the long option matching code. Note that this allows options - # like "-foo" to be matched as long options. - try: - self._match_long_opt(norm_long_opt, explicit_value, state) - except NoSuchOption: - # At this point the long option matching failed, and we need - # to try with short options. However there is a special rule - # which says, that if we have a two character options prefix - # (applies to "--foo" for instance), we do not dispatch to the - # short option code and will instead raise the no option - # error. - if arg[:2] not in self._opt_prefixes: - self._match_short_opt(arg, state) - return - - if not self.ignore_unknown_options: - raise - - state.largs.append(arg) diff --git a/venv/lib/python3.9/site-packages/click/py.typed b/venv/lib/python3.9/site-packages/click/py.typed deleted file mode 100644 index e69de29..0000000 diff --git a/venv/lib/python3.9/site-packages/click/shell_completion.py b/venv/lib/python3.9/site-packages/click/shell_completion.py deleted file mode 100644 index 07d0f09..0000000 --- a/venv/lib/python3.9/site-packages/click/shell_completion.py +++ /dev/null @@ -1,603 +0,0 @@ -import os -import re -import typing as t -from gettext import gettext as _ - -from .core import Argument -from .core import BaseCommand -from .core import Context -from .core import MultiCommand -from .core import Option -from .core import Parameter -from .core import ParameterSource -from .parser import split_arg_string -from .utils import echo - - -def shell_complete( - cli: BaseCommand, - ctx_args: t.MutableMapping[str, t.Any], - prog_name: str, - complete_var: str, - instruction: str, -) -> int: - """Perform shell completion for the given CLI program. - - :param cli: Command being called. - :param ctx_args: Extra arguments to pass to - ``cli.make_context``. - :param prog_name: Name of the executable in the shell. - :param complete_var: Name of the environment variable that holds - the completion instruction. - :param instruction: Value of ``complete_var`` with the completion - instruction and shell, in the form ``instruction_shell``. - :return: Status code to exit with. - """ - shell, _, instruction = instruction.partition("_") - comp_cls = get_completion_class(shell) - - if comp_cls is None: - return 1 - - comp = comp_cls(cli, ctx_args, prog_name, complete_var) - - if instruction == "source": - echo(comp.source()) - return 0 - - if instruction == "complete": - echo(comp.complete()) - return 0 - - return 1 - - -class CompletionItem: - """Represents a completion value and metadata about the value. The - default metadata is ``type`` to indicate special shell handling, - and ``help`` if a shell supports showing a help string next to the - value. - - Arbitrary parameters can be passed when creating the object, and - accessed using ``item.attr``. If an attribute wasn't passed, - accessing it returns ``None``. - - :param value: The completion suggestion. - :param type: Tells the shell script to provide special completion - support for the type. Click uses ``"dir"`` and ``"file"``. - :param help: String shown next to the value if supported. - :param kwargs: Arbitrary metadata. The built-in implementations - don't use this, but custom type completions paired with custom - shell support could use it. - """ - - __slots__ = ("value", "type", "help", "_info") - - def __init__( - self, - value: t.Any, - type: str = "plain", - help: t.Optional[str] = None, - **kwargs: t.Any, - ) -> None: - self.value: t.Any = value - self.type: str = type - self.help: t.Optional[str] = help - self._info = kwargs - - def __getattr__(self, name: str) -> t.Any: - return self._info.get(name) - - -# Only Bash >= 4.4 has the nosort option. -_SOURCE_BASH = """\ -%(complete_func)s() { - local IFS=$'\\n' - local response - - response=$(env COMP_WORDS="${COMP_WORDS[*]}" COMP_CWORD=$COMP_CWORD \ -%(complete_var)s=bash_complete $1) - - for completion in $response; do - IFS=',' read type value <<< "$completion" - - if [[ $type == 'dir' ]]; then - COMPREPLY=() - compopt -o dirnames - elif [[ $type == 'file' ]]; then - COMPREPLY=() - compopt -o default - elif [[ $type == 'plain' ]]; then - COMPREPLY+=($value) - fi - done - - return 0 -} - -%(complete_func)s_setup() { - complete -o nosort -F %(complete_func)s %(prog_name)s -} - -%(complete_func)s_setup; -""" - -_SOURCE_ZSH = """\ -#compdef %(prog_name)s - -%(complete_func)s() { - local -a completions - local -a completions_with_descriptions - local -a response - (( ! $+commands[%(prog_name)s] )) && return 1 - - response=("${(@f)$(env COMP_WORDS="${words[*]}" COMP_CWORD=$((CURRENT-1)) \ -%(complete_var)s=zsh_complete %(prog_name)s)}") - - for type key descr in ${response}; do - if [[ "$type" == "plain" ]]; then - if [[ "$descr" == "_" ]]; then - completions+=("$key") - else - completions_with_descriptions+=("$key":"$descr") - fi - elif [[ "$type" == "dir" ]]; then - _path_files -/ - elif [[ "$type" == "file" ]]; then - _path_files -f - fi - done - - if [ -n "$completions_with_descriptions" ]; then - _describe -V unsorted completions_with_descriptions -U - fi - - if [ -n "$completions" ]; then - compadd -U -V unsorted -a completions - fi -} - -if [[ $zsh_eval_context[-1] == loadautofunc ]]; then - # autoload from fpath, call function directly - %(complete_func)s "$@" -else - # eval/source/. command, register function for later - compdef %(complete_func)s %(prog_name)s -fi -""" - -_SOURCE_FISH = """\ -function %(complete_func)s; - set -l response (env %(complete_var)s=fish_complete COMP_WORDS=(commandline -cp) \ -COMP_CWORD=(commandline -t) %(prog_name)s); - - for completion in $response; - set -l metadata (string split "," $completion); - - if test $metadata[1] = "dir"; - __fish_complete_directories $metadata[2]; - else if test $metadata[1] = "file"; - __fish_complete_path $metadata[2]; - else if test $metadata[1] = "plain"; - echo $metadata[2]; - end; - end; -end; - -complete --no-files --command %(prog_name)s --arguments \ -"(%(complete_func)s)"; -""" - - -class ShellComplete: - """Base class for providing shell completion support. A subclass for - a given shell will override attributes and methods to implement the - completion instructions (``source`` and ``complete``). - - :param cli: Command being called. - :param prog_name: Name of the executable in the shell. - :param complete_var: Name of the environment variable that holds - the completion instruction. - - .. versionadded:: 8.0 - """ - - name: t.ClassVar[str] - """Name to register the shell as with :func:`add_completion_class`. - This is used in completion instructions (``{name}_source`` and - ``{name}_complete``). - """ - - source_template: t.ClassVar[str] - """Completion script template formatted by :meth:`source`. This must - be provided by subclasses. - """ - - def __init__( - self, - cli: BaseCommand, - ctx_args: t.MutableMapping[str, t.Any], - prog_name: str, - complete_var: str, - ) -> None: - self.cli = cli - self.ctx_args = ctx_args - self.prog_name = prog_name - self.complete_var = complete_var - - @property - def func_name(self) -> str: - """The name of the shell function defined by the completion - script. - """ - safe_name = re.sub(r"\W*", "", self.prog_name.replace("-", "_"), flags=re.ASCII) - return f"_{safe_name}_completion" - - def source_vars(self) -> t.Dict[str, t.Any]: - """Vars for formatting :attr:`source_template`. - - By default this provides ``complete_func``, ``complete_var``, - and ``prog_name``. - """ - return { - "complete_func": self.func_name, - "complete_var": self.complete_var, - "prog_name": self.prog_name, - } - - def source(self) -> str: - """Produce the shell script that defines the completion - function. By default this ``%``-style formats - :attr:`source_template` with the dict returned by - :meth:`source_vars`. - """ - return self.source_template % self.source_vars() - - def get_completion_args(self) -> t.Tuple[t.List[str], str]: - """Use the env vars defined by the shell script to return a - tuple of ``args, incomplete``. This must be implemented by - subclasses. - """ - raise NotImplementedError - - def get_completions( - self, args: t.List[str], incomplete: str - ) -> t.List[CompletionItem]: - """Determine the context and last complete command or parameter - from the complete args. Call that object's ``shell_complete`` - method to get the completions for the incomplete value. - - :param args: List of complete args before the incomplete value. - :param incomplete: Value being completed. May be empty. - """ - ctx = _resolve_context(self.cli, self.ctx_args, self.prog_name, args) - obj, incomplete = _resolve_incomplete(ctx, args, incomplete) - return obj.shell_complete(ctx, incomplete) - - def format_completion(self, item: CompletionItem) -> str: - """Format a completion item into the form recognized by the - shell script. This must be implemented by subclasses. - - :param item: Completion item to format. - """ - raise NotImplementedError - - def complete(self) -> str: - """Produce the completion data to send back to the shell. - - By default this calls :meth:`get_completion_args`, gets the - completions, then calls :meth:`format_completion` for each - completion. - """ - args, incomplete = self.get_completion_args() - completions = self.get_completions(args, incomplete) - out = [self.format_completion(item) for item in completions] - return "\n".join(out) - - -class BashComplete(ShellComplete): - """Shell completion for Bash.""" - - name = "bash" - source_template = _SOURCE_BASH - - @staticmethod - def _check_version() -> None: - import shutil - import subprocess - - bash_exe = shutil.which("bash") - - if bash_exe is None: - match = None - else: - output = subprocess.run( - [bash_exe, "--norc", "-c", 'echo "${BASH_VERSION}"'], - stdout=subprocess.PIPE, - ) - match = re.search(r"^(\d+)\.(\d+)\.\d+", output.stdout.decode()) - - if match is not None: - major, minor = match.groups() - - if major < "4" or major == "4" and minor < "4": - echo( - _( - "Shell completion is not supported for Bash" - " versions older than 4.4." - ), - err=True, - ) - else: - echo( - _("Couldn't detect Bash version, shell completion is not supported."), - err=True, - ) - - def source(self) -> str: - self._check_version() - return super().source() - - def get_completion_args(self) -> t.Tuple[t.List[str], str]: - cwords = split_arg_string(os.environ["COMP_WORDS"]) - cword = int(os.environ["COMP_CWORD"]) - args = cwords[1:cword] - - try: - incomplete = cwords[cword] - except IndexError: - incomplete = "" - - return args, incomplete - - def format_completion(self, item: CompletionItem) -> str: - return f"{item.type},{item.value}" - - -class ZshComplete(ShellComplete): - """Shell completion for Zsh.""" - - name = "zsh" - source_template = _SOURCE_ZSH - - def get_completion_args(self) -> t.Tuple[t.List[str], str]: - cwords = split_arg_string(os.environ["COMP_WORDS"]) - cword = int(os.environ["COMP_CWORD"]) - args = cwords[1:cword] - - try: - incomplete = cwords[cword] - except IndexError: - incomplete = "" - - return args, incomplete - - def format_completion(self, item: CompletionItem) -> str: - return f"{item.type}\n{item.value}\n{item.help if item.help else '_'}" - - -class FishComplete(ShellComplete): - """Shell completion for Fish.""" - - name = "fish" - source_template = _SOURCE_FISH - - def get_completion_args(self) -> t.Tuple[t.List[str], str]: - cwords = split_arg_string(os.environ["COMP_WORDS"]) - incomplete = os.environ["COMP_CWORD"] - args = cwords[1:] - - # Fish stores the partial word in both COMP_WORDS and - # COMP_CWORD, remove it from complete args. - if incomplete and args and args[-1] == incomplete: - args.pop() - - return args, incomplete - - def format_completion(self, item: CompletionItem) -> str: - if item.help: - return f"{item.type},{item.value}\t{item.help}" - - return f"{item.type},{item.value}" - - -ShellCompleteType = t.TypeVar("ShellCompleteType", bound=t.Type[ShellComplete]) - - -_available_shells: t.Dict[str, t.Type[ShellComplete]] = { - "bash": BashComplete, - "fish": FishComplete, - "zsh": ZshComplete, -} - - -def add_completion_class( - cls: ShellCompleteType, name: t.Optional[str] = None -) -> ShellCompleteType: - """Register a :class:`ShellComplete` subclass under the given name. - The name will be provided by the completion instruction environment - variable during completion. - - :param cls: The completion class that will handle completion for the - shell. - :param name: Name to register the class under. Defaults to the - class's ``name`` attribute. - """ - if name is None: - name = cls.name - - _available_shells[name] = cls - - return cls - - -def get_completion_class(shell: str) -> t.Optional[t.Type[ShellComplete]]: - """Look up a registered :class:`ShellComplete` subclass by the name - provided by the completion instruction environment variable. If the - name isn't registered, returns ``None``. - - :param shell: Name the class is registered under. - """ - return _available_shells.get(shell) - - -def _is_incomplete_argument(ctx: Context, param: Parameter) -> bool: - """Determine if the given parameter is an argument that can still - accept values. - - :param ctx: Invocation context for the command represented by the - parsed complete args. - :param param: Argument object being checked. - """ - if not isinstance(param, Argument): - return False - - assert param.name is not None - # Will be None if expose_value is False. - value = ctx.params.get(param.name) - return ( - param.nargs == -1 - or ctx.get_parameter_source(param.name) is not ParameterSource.COMMANDLINE - or ( - param.nargs > 1 - and isinstance(value, (tuple, list)) - and len(value) < param.nargs - ) - ) - - -def _start_of_option(ctx: Context, value: str) -> bool: - """Check if the value looks like the start of an option.""" - if not value: - return False - - c = value[0] - return c in ctx._opt_prefixes - - -def _is_incomplete_option(ctx: Context, args: t.List[str], param: Parameter) -> bool: - """Determine if the given parameter is an option that needs a value. - - :param args: List of complete args before the incomplete value. - :param param: Option object being checked. - """ - if not isinstance(param, Option): - return False - - if param.is_flag or param.count: - return False - - last_option = None - - for index, arg in enumerate(reversed(args)): - if index + 1 > param.nargs: - break - - if _start_of_option(ctx, arg): - last_option = arg - - return last_option is not None and last_option in param.opts - - -def _resolve_context( - cli: BaseCommand, - ctx_args: t.MutableMapping[str, t.Any], - prog_name: str, - args: t.List[str], -) -> Context: - """Produce the context hierarchy starting with the command and - traversing the complete arguments. This only follows the commands, - it doesn't trigger input prompts or callbacks. - - :param cli: Command being called. - :param prog_name: Name of the executable in the shell. - :param args: List of complete args before the incomplete value. - """ - ctx_args["resilient_parsing"] = True - ctx = cli.make_context(prog_name, args.copy(), **ctx_args) - args = ctx.protected_args + ctx.args - - while args: - command = ctx.command - - if isinstance(command, MultiCommand): - if not command.chain: - name, cmd, args = command.resolve_command(ctx, args) - - if cmd is None: - return ctx - - ctx = cmd.make_context(name, args, parent=ctx, resilient_parsing=True) - args = ctx.protected_args + ctx.args - else: - sub_ctx = ctx - - while args: - name, cmd, args = command.resolve_command(ctx, args) - - if cmd is None: - return ctx - - sub_ctx = cmd.make_context( - name, - args, - parent=ctx, - allow_extra_args=True, - allow_interspersed_args=False, - resilient_parsing=True, - ) - args = sub_ctx.args - - ctx = sub_ctx - args = [*sub_ctx.protected_args, *sub_ctx.args] - else: - break - - return ctx - - -def _resolve_incomplete( - ctx: Context, args: t.List[str], incomplete: str -) -> t.Tuple[t.Union[BaseCommand, Parameter], str]: - """Find the Click object that will handle the completion of the - incomplete value. Return the object and the incomplete value. - - :param ctx: Invocation context for the command represented by - the parsed complete args. - :param args: List of complete args before the incomplete value. - :param incomplete: Value being completed. May be empty. - """ - # Different shells treat an "=" between a long option name and - # value differently. Might keep the value joined, return the "=" - # as a separate item, or return the split name and value. Always - # split and discard the "=" to make completion easier. - if incomplete == "=": - incomplete = "" - elif "=" in incomplete and _start_of_option(ctx, incomplete): - name, _, incomplete = incomplete.partition("=") - args.append(name) - - # The "--" marker tells Click to stop treating values as options - # even if they start with the option character. If it hasn't been - # given and the incomplete arg looks like an option, the current - # command will provide option name completions. - if "--" not in args and _start_of_option(ctx, incomplete): - return ctx.command, incomplete - - params = ctx.command.get_params(ctx) - - # If the last complete arg is an option name with an incomplete - # value, the option will provide value completions. - for param in params: - if _is_incomplete_option(ctx, args, param): - return param, incomplete - - # It's not an option name or value. The first argument without a - # parsed value will provide value completions. - for param in params: - if _is_incomplete_argument(ctx, param): - return param, incomplete - - # There were no unparsed arguments, the command may be a group that - # will provide command name completions. - return ctx.command, incomplete diff --git a/venv/lib/python3.9/site-packages/click/termui.py b/venv/lib/python3.9/site-packages/click/termui.py deleted file mode 100644 index c084f19..0000000 --- a/venv/lib/python3.9/site-packages/click/termui.py +++ /dev/null @@ -1,784 +0,0 @@ -import inspect -import io -import itertools -import sys -import typing as t -from gettext import gettext as _ - -from ._compat import isatty -from ._compat import strip_ansi -from .exceptions import Abort -from .exceptions import UsageError -from .globals import resolve_color_default -from .types import Choice -from .types import convert_type -from .types import ParamType -from .utils import echo -from .utils import LazyFile - -if t.TYPE_CHECKING: - from ._termui_impl import ProgressBar - -V = t.TypeVar("V") - -# The prompt functions to use. The doc tools currently override these -# functions to customize how they work. -visible_prompt_func: t.Callable[[str], str] = input - -_ansi_colors = { - "black": 30, - "red": 31, - "green": 32, - "yellow": 33, - "blue": 34, - "magenta": 35, - "cyan": 36, - "white": 37, - "reset": 39, - "bright_black": 90, - "bright_red": 91, - "bright_green": 92, - "bright_yellow": 93, - "bright_blue": 94, - "bright_magenta": 95, - "bright_cyan": 96, - "bright_white": 97, -} -_ansi_reset_all = "\033[0m" - - -def hidden_prompt_func(prompt: str) -> str: - import getpass - - return getpass.getpass(prompt) - - -def _build_prompt( - text: str, - suffix: str, - show_default: bool = False, - default: t.Optional[t.Any] = None, - show_choices: bool = True, - type: t.Optional[ParamType] = None, -) -> str: - prompt = text - if type is not None and show_choices and isinstance(type, Choice): - prompt += f" ({', '.join(map(str, type.choices))})" - if default is not None and show_default: - prompt = f"{prompt} [{_format_default(default)}]" - return f"{prompt}{suffix}" - - -def _format_default(default: t.Any) -> t.Any: - if isinstance(default, (io.IOBase, LazyFile)) and hasattr(default, "name"): - return default.name - - return default - - -def prompt( - text: str, - default: t.Optional[t.Any] = None, - hide_input: bool = False, - confirmation_prompt: t.Union[bool, str] = False, - type: t.Optional[t.Union[ParamType, t.Any]] = None, - value_proc: t.Optional[t.Callable[[str], t.Any]] = None, - prompt_suffix: str = ": ", - show_default: bool = True, - err: bool = False, - show_choices: bool = True, -) -> t.Any: - """Prompts a user for input. This is a convenience function that can - be used to prompt a user for input later. - - If the user aborts the input by sending an interrupt signal, this - function will catch it and raise a :exc:`Abort` exception. - - :param text: the text to show for the prompt. - :param default: the default value to use if no input happens. If this - is not given it will prompt until it's aborted. - :param hide_input: if this is set to true then the input value will - be hidden. - :param confirmation_prompt: Prompt a second time to confirm the - value. Can be set to a string instead of ``True`` to customize - the message. - :param type: the type to use to check the value against. - :param value_proc: if this parameter is provided it's a function that - is invoked instead of the type conversion to - convert a value. - :param prompt_suffix: a suffix that should be added to the prompt. - :param show_default: shows or hides the default value in the prompt. - :param err: if set to true the file defaults to ``stderr`` instead of - ``stdout``, the same as with echo. - :param show_choices: Show or hide choices if the passed type is a Choice. - For example if type is a Choice of either day or week, - show_choices is true and text is "Group by" then the - prompt will be "Group by (day, week): ". - - .. versionadded:: 8.0 - ``confirmation_prompt`` can be a custom string. - - .. versionadded:: 7.0 - Added the ``show_choices`` parameter. - - .. versionadded:: 6.0 - Added unicode support for cmd.exe on Windows. - - .. versionadded:: 4.0 - Added the `err` parameter. - - """ - - def prompt_func(text: str) -> str: - f = hidden_prompt_func if hide_input else visible_prompt_func - try: - # Write the prompt separately so that we get nice - # coloring through colorama on Windows - echo(text.rstrip(" "), nl=False, err=err) - # Echo a space to stdout to work around an issue where - # readline causes backspace to clear the whole line. - return f(" ") - except (KeyboardInterrupt, EOFError): - # getpass doesn't print a newline if the user aborts input with ^C. - # Allegedly this behavior is inherited from getpass(3). - # A doc bug has been filed at https://bugs.python.org/issue24711 - if hide_input: - echo(None, err=err) - raise Abort() from None - - if value_proc is None: - value_proc = convert_type(type, default) - - prompt = _build_prompt( - text, prompt_suffix, show_default, default, show_choices, type - ) - - if confirmation_prompt: - if confirmation_prompt is True: - confirmation_prompt = _("Repeat for confirmation") - - confirmation_prompt = _build_prompt(confirmation_prompt, prompt_suffix) - - while True: - while True: - value = prompt_func(prompt) - if value: - break - elif default is not None: - value = default - break - try: - result = value_proc(value) - except UsageError as e: - if hide_input: - echo(_("Error: The value you entered was invalid."), err=err) - else: - echo(_("Error: {e.message}").format(e=e), err=err) - continue - if not confirmation_prompt: - return result - while True: - value2 = prompt_func(confirmation_prompt) - is_empty = not value and not value2 - if value2 or is_empty: - break - if value == value2: - return result - echo(_("Error: The two entered values do not match."), err=err) - - -def confirm( - text: str, - default: t.Optional[bool] = False, - abort: bool = False, - prompt_suffix: str = ": ", - show_default: bool = True, - err: bool = False, -) -> bool: - """Prompts for confirmation (yes/no question). - - If the user aborts the input by sending a interrupt signal this - function will catch it and raise a :exc:`Abort` exception. - - :param text: the question to ask. - :param default: The default value to use when no input is given. If - ``None``, repeat until input is given. - :param abort: if this is set to `True` a negative answer aborts the - exception by raising :exc:`Abort`. - :param prompt_suffix: a suffix that should be added to the prompt. - :param show_default: shows or hides the default value in the prompt. - :param err: if set to true the file defaults to ``stderr`` instead of - ``stdout``, the same as with echo. - - .. versionchanged:: 8.0 - Repeat until input is given if ``default`` is ``None``. - - .. versionadded:: 4.0 - Added the ``err`` parameter. - """ - prompt = _build_prompt( - text, - prompt_suffix, - show_default, - "y/n" if default is None else ("Y/n" if default else "y/N"), - ) - - while True: - try: - # Write the prompt separately so that we get nice - # coloring through colorama on Windows - echo(prompt.rstrip(" "), nl=False, err=err) - # Echo a space to stdout to work around an issue where - # readline causes backspace to clear the whole line. - value = visible_prompt_func(" ").lower().strip() - except (KeyboardInterrupt, EOFError): - raise Abort() from None - if value in ("y", "yes"): - rv = True - elif value in ("n", "no"): - rv = False - elif default is not None and value == "": - rv = default - else: - echo(_("Error: invalid input"), err=err) - continue - break - if abort and not rv: - raise Abort() - return rv - - -def echo_via_pager( - text_or_generator: t.Union[t.Iterable[str], t.Callable[[], t.Iterable[str]], str], - color: t.Optional[bool] = None, -) -> None: - """This function takes a text and shows it via an environment specific - pager on stdout. - - .. versionchanged:: 3.0 - Added the `color` flag. - - :param text_or_generator: the text to page, or alternatively, a - generator emitting the text to page. - :param color: controls if the pager supports ANSI colors or not. The - default is autodetection. - """ - color = resolve_color_default(color) - - if inspect.isgeneratorfunction(text_or_generator): - i = t.cast(t.Callable[[], t.Iterable[str]], text_or_generator)() - elif isinstance(text_or_generator, str): - i = [text_or_generator] - else: - i = iter(t.cast(t.Iterable[str], text_or_generator)) - - # convert every element of i to a text type if necessary - text_generator = (el if isinstance(el, str) else str(el) for el in i) - - from ._termui_impl import pager - - return pager(itertools.chain(text_generator, "\n"), color) - - -def progressbar( - iterable: t.Optional[t.Iterable[V]] = None, - length: t.Optional[int] = None, - label: t.Optional[str] = None, - show_eta: bool = True, - show_percent: t.Optional[bool] = None, - show_pos: bool = False, - item_show_func: t.Optional[t.Callable[[t.Optional[V]], t.Optional[str]]] = None, - fill_char: str = "#", - empty_char: str = "-", - bar_template: str = "%(label)s [%(bar)s] %(info)s", - info_sep: str = " ", - width: int = 36, - file: t.Optional[t.TextIO] = None, - color: t.Optional[bool] = None, - update_min_steps: int = 1, -) -> "ProgressBar[V]": - """This function creates an iterable context manager that can be used - to iterate over something while showing a progress bar. It will - either iterate over the `iterable` or `length` items (that are counted - up). While iteration happens, this function will print a rendered - progress bar to the given `file` (defaults to stdout) and will attempt - to calculate remaining time and more. By default, this progress bar - will not be rendered if the file is not a terminal. - - The context manager creates the progress bar. When the context - manager is entered the progress bar is already created. With every - iteration over the progress bar, the iterable passed to the bar is - advanced and the bar is updated. When the context manager exits, - a newline is printed and the progress bar is finalized on screen. - - Note: The progress bar is currently designed for use cases where the - total progress can be expected to take at least several seconds. - Because of this, the ProgressBar class object won't display - progress that is considered too fast, and progress where the time - between steps is less than a second. - - No printing must happen or the progress bar will be unintentionally - destroyed. - - Example usage:: - - with progressbar(items) as bar: - for item in bar: - do_something_with(item) - - Alternatively, if no iterable is specified, one can manually update the - progress bar through the `update()` method instead of directly - iterating over the progress bar. The update method accepts the number - of steps to increment the bar with:: - - with progressbar(length=chunks.total_bytes) as bar: - for chunk in chunks: - process_chunk(chunk) - bar.update(chunks.bytes) - - The ``update()`` method also takes an optional value specifying the - ``current_item`` at the new position. This is useful when used - together with ``item_show_func`` to customize the output for each - manual step:: - - with click.progressbar( - length=total_size, - label='Unzipping archive', - item_show_func=lambda a: a.filename - ) as bar: - for archive in zip_file: - archive.extract() - bar.update(archive.size, archive) - - :param iterable: an iterable to iterate over. If not provided the length - is required. - :param length: the number of items to iterate over. By default the - progressbar will attempt to ask the iterator about its - length, which might or might not work. If an iterable is - also provided this parameter can be used to override the - length. If an iterable is not provided the progress bar - will iterate over a range of that length. - :param label: the label to show next to the progress bar. - :param show_eta: enables or disables the estimated time display. This is - automatically disabled if the length cannot be - determined. - :param show_percent: enables or disables the percentage display. The - default is `True` if the iterable has a length or - `False` if not. - :param show_pos: enables or disables the absolute position display. The - default is `False`. - :param item_show_func: A function called with the current item which - can return a string to show next to the progress bar. If the - function returns ``None`` nothing is shown. The current item can - be ``None``, such as when entering and exiting the bar. - :param fill_char: the character to use to show the filled part of the - progress bar. - :param empty_char: the character to use to show the non-filled part of - the progress bar. - :param bar_template: the format string to use as template for the bar. - The parameters in it are ``label`` for the label, - ``bar`` for the progress bar and ``info`` for the - info section. - :param info_sep: the separator between multiple info items (eta etc.) - :param width: the width of the progress bar in characters, 0 means full - terminal width - :param file: The file to write to. If this is not a terminal then - only the label is printed. - :param color: controls if the terminal supports ANSI colors or not. The - default is autodetection. This is only needed if ANSI - codes are included anywhere in the progress bar output - which is not the case by default. - :param update_min_steps: Render only when this many updates have - completed. This allows tuning for very fast iterators. - - .. versionchanged:: 8.0 - Output is shown even if execution time is less than 0.5 seconds. - - .. versionchanged:: 8.0 - ``item_show_func`` shows the current item, not the previous one. - - .. versionchanged:: 8.0 - Labels are echoed if the output is not a TTY. Reverts a change - in 7.0 that removed all output. - - .. versionadded:: 8.0 - Added the ``update_min_steps`` parameter. - - .. versionchanged:: 4.0 - Added the ``color`` parameter. Added the ``update`` method to - the object. - - .. versionadded:: 2.0 - """ - from ._termui_impl import ProgressBar - - color = resolve_color_default(color) - return ProgressBar( - iterable=iterable, - length=length, - show_eta=show_eta, - show_percent=show_percent, - show_pos=show_pos, - item_show_func=item_show_func, - fill_char=fill_char, - empty_char=empty_char, - bar_template=bar_template, - info_sep=info_sep, - file=file, - label=label, - width=width, - color=color, - update_min_steps=update_min_steps, - ) - - -def clear() -> None: - """Clears the terminal screen. This will have the effect of clearing - the whole visible space of the terminal and moving the cursor to the - top left. This does not do anything if not connected to a terminal. - - .. versionadded:: 2.0 - """ - if not isatty(sys.stdout): - return - - # ANSI escape \033[2J clears the screen, \033[1;1H moves the cursor - echo("\033[2J\033[1;1H", nl=False) - - -def _interpret_color( - color: t.Union[int, t.Tuple[int, int, int], str], offset: int = 0 -) -> str: - if isinstance(color, int): - return f"{38 + offset};5;{color:d}" - - if isinstance(color, (tuple, list)): - r, g, b = color - return f"{38 + offset};2;{r:d};{g:d};{b:d}" - - return str(_ansi_colors[color] + offset) - - -def style( - text: t.Any, - fg: t.Optional[t.Union[int, t.Tuple[int, int, int], str]] = None, - bg: t.Optional[t.Union[int, t.Tuple[int, int, int], str]] = None, - bold: t.Optional[bool] = None, - dim: t.Optional[bool] = None, - underline: t.Optional[bool] = None, - overline: t.Optional[bool] = None, - italic: t.Optional[bool] = None, - blink: t.Optional[bool] = None, - reverse: t.Optional[bool] = None, - strikethrough: t.Optional[bool] = None, - reset: bool = True, -) -> str: - """Styles a text with ANSI styles and returns the new string. By - default the styling is self contained which means that at the end - of the string a reset code is issued. This can be prevented by - passing ``reset=False``. - - Examples:: - - click.echo(click.style('Hello World!', fg='green')) - click.echo(click.style('ATTENTION!', blink=True)) - click.echo(click.style('Some things', reverse=True, fg='cyan')) - click.echo(click.style('More colors', fg=(255, 12, 128), bg=117)) - - Supported color names: - - * ``black`` (might be a gray) - * ``red`` - * ``green`` - * ``yellow`` (might be an orange) - * ``blue`` - * ``magenta`` - * ``cyan`` - * ``white`` (might be light gray) - * ``bright_black`` - * ``bright_red`` - * ``bright_green`` - * ``bright_yellow`` - * ``bright_blue`` - * ``bright_magenta`` - * ``bright_cyan`` - * ``bright_white`` - * ``reset`` (reset the color code only) - - If the terminal supports it, color may also be specified as: - - - An integer in the interval [0, 255]. The terminal must support - 8-bit/256-color mode. - - An RGB tuple of three integers in [0, 255]. The terminal must - support 24-bit/true-color mode. - - See https://en.wikipedia.org/wiki/ANSI_color and - https://gist.github.com/XVilka/8346728 for more information. - - :param text: the string to style with ansi codes. - :param fg: if provided this will become the foreground color. - :param bg: if provided this will become the background color. - :param bold: if provided this will enable or disable bold mode. - :param dim: if provided this will enable or disable dim mode. This is - badly supported. - :param underline: if provided this will enable or disable underline. - :param overline: if provided this will enable or disable overline. - :param italic: if provided this will enable or disable italic. - :param blink: if provided this will enable or disable blinking. - :param reverse: if provided this will enable or disable inverse - rendering (foreground becomes background and the - other way round). - :param strikethrough: if provided this will enable or disable - striking through text. - :param reset: by default a reset-all code is added at the end of the - string which means that styles do not carry over. This - can be disabled to compose styles. - - .. versionchanged:: 8.0 - A non-string ``message`` is converted to a string. - - .. versionchanged:: 8.0 - Added support for 256 and RGB color codes. - - .. versionchanged:: 8.0 - Added the ``strikethrough``, ``italic``, and ``overline`` - parameters. - - .. versionchanged:: 7.0 - Added support for bright colors. - - .. versionadded:: 2.0 - """ - if not isinstance(text, str): - text = str(text) - - bits = [] - - if fg: - try: - bits.append(f"\033[{_interpret_color(fg)}m") - except KeyError: - raise TypeError(f"Unknown color {fg!r}") from None - - if bg: - try: - bits.append(f"\033[{_interpret_color(bg, 10)}m") - except KeyError: - raise TypeError(f"Unknown color {bg!r}") from None - - if bold is not None: - bits.append(f"\033[{1 if bold else 22}m") - if dim is not None: - bits.append(f"\033[{2 if dim else 22}m") - if underline is not None: - bits.append(f"\033[{4 if underline else 24}m") - if overline is not None: - bits.append(f"\033[{53 if overline else 55}m") - if italic is not None: - bits.append(f"\033[{3 if italic else 23}m") - if blink is not None: - bits.append(f"\033[{5 if blink else 25}m") - if reverse is not None: - bits.append(f"\033[{7 if reverse else 27}m") - if strikethrough is not None: - bits.append(f"\033[{9 if strikethrough else 29}m") - bits.append(text) - if reset: - bits.append(_ansi_reset_all) - return "".join(bits) - - -def unstyle(text: str) -> str: - """Removes ANSI styling information from a string. Usually it's not - necessary to use this function as Click's echo function will - automatically remove styling if necessary. - - .. versionadded:: 2.0 - - :param text: the text to remove style information from. - """ - return strip_ansi(text) - - -def secho( - message: t.Optional[t.Any] = None, - file: t.Optional[t.IO[t.AnyStr]] = None, - nl: bool = True, - err: bool = False, - color: t.Optional[bool] = None, - **styles: t.Any, -) -> None: - """This function combines :func:`echo` and :func:`style` into one - call. As such the following two calls are the same:: - - click.secho('Hello World!', fg='green') - click.echo(click.style('Hello World!', fg='green')) - - All keyword arguments are forwarded to the underlying functions - depending on which one they go with. - - Non-string types will be converted to :class:`str`. However, - :class:`bytes` are passed directly to :meth:`echo` without applying - style. If you want to style bytes that represent text, call - :meth:`bytes.decode` first. - - .. versionchanged:: 8.0 - A non-string ``message`` is converted to a string. Bytes are - passed through without style applied. - - .. versionadded:: 2.0 - """ - if message is not None and not isinstance(message, (bytes, bytearray)): - message = style(message, **styles) - - return echo(message, file=file, nl=nl, err=err, color=color) - - -def edit( - text: t.Optional[t.AnyStr] = None, - editor: t.Optional[str] = None, - env: t.Optional[t.Mapping[str, str]] = None, - require_save: bool = True, - extension: str = ".txt", - filename: t.Optional[str] = None, -) -> t.Optional[t.AnyStr]: - r"""Edits the given text in the defined editor. If an editor is given - (should be the full path to the executable but the regular operating - system search path is used for finding the executable) it overrides - the detected editor. Optionally, some environment variables can be - used. If the editor is closed without changes, `None` is returned. In - case a file is edited directly the return value is always `None` and - `require_save` and `extension` are ignored. - - If the editor cannot be opened a :exc:`UsageError` is raised. - - Note for Windows: to simplify cross-platform usage, the newlines are - automatically converted from POSIX to Windows and vice versa. As such, - the message here will have ``\n`` as newline markers. - - :param text: the text to edit. - :param editor: optionally the editor to use. Defaults to automatic - detection. - :param env: environment variables to forward to the editor. - :param require_save: if this is true, then not saving in the editor - will make the return value become `None`. - :param extension: the extension to tell the editor about. This defaults - to `.txt` but changing this might change syntax - highlighting. - :param filename: if provided it will edit this file instead of the - provided text contents. It will not use a temporary - file as an indirection in that case. - """ - from ._termui_impl import Editor - - ed = Editor(editor=editor, env=env, require_save=require_save, extension=extension) - - if filename is None: - return ed.edit(text) - - ed.edit_file(filename) - return None - - -def launch(url: str, wait: bool = False, locate: bool = False) -> int: - """This function launches the given URL (or filename) in the default - viewer application for this file type. If this is an executable, it - might launch the executable in a new session. The return value is - the exit code of the launched application. Usually, ``0`` indicates - success. - - Examples:: - - click.launch('https://click.palletsprojects.com/') - click.launch('/my/downloaded/file', locate=True) - - .. versionadded:: 2.0 - - :param url: URL or filename of the thing to launch. - :param wait: Wait for the program to exit before returning. This - only works if the launched program blocks. In particular, - ``xdg-open`` on Linux does not block. - :param locate: if this is set to `True` then instead of launching the - application associated with the URL it will attempt to - launch a file manager with the file located. This - might have weird effects if the URL does not point to - the filesystem. - """ - from ._termui_impl import open_url - - return open_url(url, wait=wait, locate=locate) - - -# If this is provided, getchar() calls into this instead. This is used -# for unittesting purposes. -_getchar: t.Optional[t.Callable[[bool], str]] = None - - -def getchar(echo: bool = False) -> str: - """Fetches a single character from the terminal and returns it. This - will always return a unicode character and under certain rare - circumstances this might return more than one character. The - situations which more than one character is returned is when for - whatever reason multiple characters end up in the terminal buffer or - standard input was not actually a terminal. - - Note that this will always read from the terminal, even if something - is piped into the standard input. - - Note for Windows: in rare cases when typing non-ASCII characters, this - function might wait for a second character and then return both at once. - This is because certain Unicode characters look like special-key markers. - - .. versionadded:: 2.0 - - :param echo: if set to `True`, the character read will also show up on - the terminal. The default is to not show it. - """ - global _getchar - - if _getchar is None: - from ._termui_impl import getchar as f - - _getchar = f - - return _getchar(echo) - - -def raw_terminal() -> t.ContextManager[int]: - from ._termui_impl import raw_terminal as f - - return f() - - -def pause(info: t.Optional[str] = None, err: bool = False) -> None: - """This command stops execution and waits for the user to press any - key to continue. This is similar to the Windows batch "pause" - command. If the program is not run through a terminal, this command - will instead do nothing. - - .. versionadded:: 2.0 - - .. versionadded:: 4.0 - Added the `err` parameter. - - :param info: The message to print before pausing. Defaults to - ``"Press any key to continue..."``. - :param err: if set to message goes to ``stderr`` instead of - ``stdout``, the same as with echo. - """ - if not isatty(sys.stdin) or not isatty(sys.stdout): - return - - if info is None: - info = _("Press any key to continue...") - - try: - if info: - echo(info, nl=False, err=err) - try: - getchar() - except (KeyboardInterrupt, EOFError): - pass - finally: - if info: - echo(err=err) diff --git a/venv/lib/python3.9/site-packages/click/testing.py b/venv/lib/python3.9/site-packages/click/testing.py deleted file mode 100644 index 772b215..0000000 --- a/venv/lib/python3.9/site-packages/click/testing.py +++ /dev/null @@ -1,483 +0,0 @@ -import contextlib -import io -import os -import shlex -import shutil -import sys -import tempfile -import typing as t -from types import TracebackType - -from . import _compat -from . import formatting -from . import termui -from . import utils -from ._compat import _find_binary_reader - -if t.TYPE_CHECKING: - from .core import BaseCommand - - -class EchoingStdin: - def __init__(self, input: t.BinaryIO, output: t.BinaryIO) -> None: - self._input = input - self._output = output - self._paused = False - - def __getattr__(self, x: str) -> t.Any: - return getattr(self._input, x) - - def _echo(self, rv: bytes) -> bytes: - if not self._paused: - self._output.write(rv) - - return rv - - def read(self, n: int = -1) -> bytes: - return self._echo(self._input.read(n)) - - def read1(self, n: int = -1) -> bytes: - return self._echo(self._input.read1(n)) # type: ignore - - def readline(self, n: int = -1) -> bytes: - return self._echo(self._input.readline(n)) - - def readlines(self) -> t.List[bytes]: - return [self._echo(x) for x in self._input.readlines()] - - def __iter__(self) -> t.Iterator[bytes]: - return iter(self._echo(x) for x in self._input) - - def __repr__(self) -> str: - return repr(self._input) - - -@contextlib.contextmanager -def _pause_echo(stream: t.Optional[EchoingStdin]) -> t.Iterator[None]: - if stream is None: - yield - else: - stream._paused = True - yield - stream._paused = False - - -class _NamedTextIOWrapper(io.TextIOWrapper): - def __init__( - self, buffer: t.BinaryIO, name: str, mode: str, **kwargs: t.Any - ) -> None: - super().__init__(buffer, **kwargs) - self._name = name - self._mode = mode - - @property - def name(self) -> str: - return self._name - - @property - def mode(self) -> str: - return self._mode - - -def make_input_stream( - input: t.Optional[t.Union[str, bytes, t.IO[t.Any]]], charset: str -) -> t.BinaryIO: - # Is already an input stream. - if hasattr(input, "read"): - rv = _find_binary_reader(t.cast(t.IO[t.Any], input)) - - if rv is not None: - return rv - - raise TypeError("Could not find binary reader for input stream.") - - if input is None: - input = b"" - elif isinstance(input, str): - input = input.encode(charset) - - return io.BytesIO(input) - - -class Result: - """Holds the captured result of an invoked CLI script.""" - - def __init__( - self, - runner: "CliRunner", - stdout_bytes: bytes, - stderr_bytes: t.Optional[bytes], - return_value: t.Any, - exit_code: int, - exception: t.Optional[BaseException], - exc_info: t.Optional[ - t.Tuple[t.Type[BaseException], BaseException, TracebackType] - ] = None, - ): - #: The runner that created the result - self.runner = runner - #: The standard output as bytes. - self.stdout_bytes = stdout_bytes - #: The standard error as bytes, or None if not available - self.stderr_bytes = stderr_bytes - #: The value returned from the invoked command. - #: - #: .. versionadded:: 8.0 - self.return_value = return_value - #: The exit code as integer. - self.exit_code = exit_code - #: The exception that happened if one did. - self.exception = exception - #: The traceback - self.exc_info = exc_info - - @property - def output(self) -> str: - """The (standard) output as unicode string.""" - return self.stdout - - @property - def stdout(self) -> str: - """The standard output as unicode string.""" - return self.stdout_bytes.decode(self.runner.charset, "replace").replace( - "\r\n", "\n" - ) - - @property - def stderr(self) -> str: - """The standard error as unicode string.""" - if self.stderr_bytes is None: - raise ValueError("stderr not separately captured") - return self.stderr_bytes.decode(self.runner.charset, "replace").replace( - "\r\n", "\n" - ) - - def __repr__(self) -> str: - exc_str = repr(self.exception) if self.exception else "okay" - return f"<{type(self).__name__} {exc_str}>" - - -class CliRunner: - """The CLI runner provides functionality to invoke a Click command line - script for unittesting purposes in a isolated environment. This only - works in single-threaded systems without any concurrency as it changes the - global interpreter state. - - :param charset: the character set for the input and output data. - :param env: a dictionary with environment variables for overriding. - :param echo_stdin: if this is set to `True`, then reading from stdin writes - to stdout. This is useful for showing examples in - some circumstances. Note that regular prompts - will automatically echo the input. - :param mix_stderr: if this is set to `False`, then stdout and stderr are - preserved as independent streams. This is useful for - Unix-philosophy apps that have predictable stdout and - noisy stderr, such that each may be measured - independently - """ - - def __init__( - self, - charset: str = "utf-8", - env: t.Optional[t.Mapping[str, t.Optional[str]]] = None, - echo_stdin: bool = False, - mix_stderr: bool = True, - ) -> None: - self.charset = charset - self.env: t.Mapping[str, t.Optional[str]] = env or {} - self.echo_stdin = echo_stdin - self.mix_stderr = mix_stderr - - def get_default_prog_name(self, cli: "BaseCommand") -> str: - """Given a command object it will return the default program name - for it. The default is the `name` attribute or ``"root"`` if not - set. - """ - return cli.name or "root" - - def make_env( - self, overrides: t.Optional[t.Mapping[str, t.Optional[str]]] = None - ) -> t.Mapping[str, t.Optional[str]]: - """Returns the environment overrides for invoking a script.""" - rv = dict(self.env) - if overrides: - rv.update(overrides) - return rv - - @contextlib.contextmanager - def isolation( - self, - input: t.Optional[t.Union[str, bytes, t.IO[t.Any]]] = None, - env: t.Optional[t.Mapping[str, t.Optional[str]]] = None, - color: bool = False, - ) -> t.Iterator[t.Tuple[io.BytesIO, t.Optional[io.BytesIO]]]: - """A context manager that sets up the isolation for invoking of a - command line tool. This sets up stdin with the given input data - and `os.environ` with the overrides from the given dictionary. - This also rebinds some internals in Click to be mocked (like the - prompt functionality). - - This is automatically done in the :meth:`invoke` method. - - :param input: the input stream to put into sys.stdin. - :param env: the environment overrides as dictionary. - :param color: whether the output should contain color codes. The - application can still override this explicitly. - - .. versionchanged:: 8.0 - ``stderr`` is opened with ``errors="backslashreplace"`` - instead of the default ``"strict"``. - - .. versionchanged:: 4.0 - Added the ``color`` parameter. - """ - bytes_input = make_input_stream(input, self.charset) - echo_input = None - - old_stdin = sys.stdin - old_stdout = sys.stdout - old_stderr = sys.stderr - old_forced_width = formatting.FORCED_WIDTH - formatting.FORCED_WIDTH = 80 - - env = self.make_env(env) - - bytes_output = io.BytesIO() - - if self.echo_stdin: - bytes_input = echo_input = t.cast( - t.BinaryIO, EchoingStdin(bytes_input, bytes_output) - ) - - sys.stdin = text_input = _NamedTextIOWrapper( - bytes_input, encoding=self.charset, name="", mode="r" - ) - - if self.echo_stdin: - # Force unbuffered reads, otherwise TextIOWrapper reads a - # large chunk which is echoed early. - text_input._CHUNK_SIZE = 1 # type: ignore - - sys.stdout = _NamedTextIOWrapper( - bytes_output, encoding=self.charset, name="", mode="w" - ) - - bytes_error = None - if self.mix_stderr: - sys.stderr = sys.stdout - else: - bytes_error = io.BytesIO() - sys.stderr = _NamedTextIOWrapper( - bytes_error, - encoding=self.charset, - name="", - mode="w", - errors="backslashreplace", - ) - - @_pause_echo(echo_input) # type: ignore - def visible_input(prompt: t.Optional[str] = None) -> str: - sys.stdout.write(prompt or "") - val = text_input.readline().rstrip("\r\n") - sys.stdout.write(f"{val}\n") - sys.stdout.flush() - return val - - @_pause_echo(echo_input) # type: ignore - def hidden_input(prompt: t.Optional[str] = None) -> str: - sys.stdout.write(f"{prompt or ''}\n") - sys.stdout.flush() - return text_input.readline().rstrip("\r\n") - - @_pause_echo(echo_input) # type: ignore - def _getchar(echo: bool) -> str: - char = sys.stdin.read(1) - - if echo: - sys.stdout.write(char) - - sys.stdout.flush() - return char - - default_color = color - - def should_strip_ansi( - stream: t.Optional[t.IO[t.Any]] = None, color: t.Optional[bool] = None - ) -> bool: - if color is None: - return not default_color - return not color - - old_visible_prompt_func = termui.visible_prompt_func - old_hidden_prompt_func = termui.hidden_prompt_func - old__getchar_func = termui._getchar - old_should_strip_ansi = utils.should_strip_ansi # type: ignore - old__compat_should_strip_ansi = _compat.should_strip_ansi - termui.visible_prompt_func = visible_input - termui.hidden_prompt_func = hidden_input - termui._getchar = _getchar - utils.should_strip_ansi = should_strip_ansi # type: ignore - _compat.should_strip_ansi = should_strip_ansi - - old_env = {} - try: - for key, value in env.items(): - old_env[key] = os.environ.get(key) - if value is None: - try: - del os.environ[key] - except Exception: - pass - else: - os.environ[key] = value - yield (bytes_output, bytes_error) - finally: - for key, value in old_env.items(): - if value is None: - try: - del os.environ[key] - except Exception: - pass - else: - os.environ[key] = value - sys.stdout = old_stdout - sys.stderr = old_stderr - sys.stdin = old_stdin - termui.visible_prompt_func = old_visible_prompt_func - termui.hidden_prompt_func = old_hidden_prompt_func - termui._getchar = old__getchar_func - utils.should_strip_ansi = old_should_strip_ansi # type: ignore - _compat.should_strip_ansi = old__compat_should_strip_ansi - formatting.FORCED_WIDTH = old_forced_width - - def invoke( - self, - cli: "BaseCommand", - args: t.Optional[t.Union[str, t.Sequence[str]]] = None, - input: t.Optional[t.Union[str, bytes, t.IO[t.Any]]] = None, - env: t.Optional[t.Mapping[str, t.Optional[str]]] = None, - catch_exceptions: bool = True, - color: bool = False, - **extra: t.Any, - ) -> Result: - """Invokes a command in an isolated environment. The arguments are - forwarded directly to the command line script, the `extra` keyword - arguments are passed to the :meth:`~clickpkg.Command.main` function of - the command. - - This returns a :class:`Result` object. - - :param cli: the command to invoke - :param args: the arguments to invoke. It may be given as an iterable - or a string. When given as string it will be interpreted - as a Unix shell command. More details at - :func:`shlex.split`. - :param input: the input data for `sys.stdin`. - :param env: the environment overrides. - :param catch_exceptions: Whether to catch any other exceptions than - ``SystemExit``. - :param extra: the keyword arguments to pass to :meth:`main`. - :param color: whether the output should contain color codes. The - application can still override this explicitly. - - .. versionchanged:: 8.0 - The result object has the ``return_value`` attribute with - the value returned from the invoked command. - - .. versionchanged:: 4.0 - Added the ``color`` parameter. - - .. versionchanged:: 3.0 - Added the ``catch_exceptions`` parameter. - - .. versionchanged:: 3.0 - The result object has the ``exc_info`` attribute with the - traceback if available. - """ - exc_info = None - with self.isolation(input=input, env=env, color=color) as outstreams: - return_value = None - exception: t.Optional[BaseException] = None - exit_code = 0 - - if isinstance(args, str): - args = shlex.split(args) - - try: - prog_name = extra.pop("prog_name") - except KeyError: - prog_name = self.get_default_prog_name(cli) - - try: - return_value = cli.main(args=args or (), prog_name=prog_name, **extra) - except SystemExit as e: - exc_info = sys.exc_info() - e_code = t.cast(t.Optional[t.Union[int, t.Any]], e.code) - - if e_code is None: - e_code = 0 - - if e_code != 0: - exception = e - - if not isinstance(e_code, int): - sys.stdout.write(str(e_code)) - sys.stdout.write("\n") - e_code = 1 - - exit_code = e_code - - except Exception as e: - if not catch_exceptions: - raise - exception = e - exit_code = 1 - exc_info = sys.exc_info() - finally: - sys.stdout.flush() - stdout = outstreams[0].getvalue() - if self.mix_stderr: - stderr = None - else: - stderr = outstreams[1].getvalue() # type: ignore - - return Result( - runner=self, - stdout_bytes=stdout, - stderr_bytes=stderr, - return_value=return_value, - exit_code=exit_code, - exception=exception, - exc_info=exc_info, # type: ignore - ) - - @contextlib.contextmanager - def isolated_filesystem( - self, temp_dir: t.Optional[t.Union[str, "os.PathLike[str]"]] = None - ) -> t.Iterator[str]: - """A context manager that creates a temporary directory and - changes the current working directory to it. This isolates tests - that affect the contents of the CWD to prevent them from - interfering with each other. - - :param temp_dir: Create the temporary directory under this - directory. If given, the created directory is not removed - when exiting. - - .. versionchanged:: 8.0 - Added the ``temp_dir`` parameter. - """ - cwd = os.getcwd() - dt = tempfile.mkdtemp(dir=temp_dir) - os.chdir(dt) - - try: - yield dt - finally: - os.chdir(cwd) - - if temp_dir is None: - try: - shutil.rmtree(dt) - except OSError: - pass diff --git a/venv/lib/python3.9/site-packages/click/types.py b/venv/lib/python3.9/site-packages/click/types.py deleted file mode 100644 index a70fd58..0000000 --- a/venv/lib/python3.9/site-packages/click/types.py +++ /dev/null @@ -1,1093 +0,0 @@ -import os -import stat -import sys -import typing as t -from datetime import datetime -from gettext import gettext as _ -from gettext import ngettext - -from ._compat import _get_argv_encoding -from ._compat import open_stream -from .exceptions import BadParameter -from .utils import format_filename -from .utils import LazyFile -from .utils import safecall - -if t.TYPE_CHECKING: - import typing_extensions as te - - from .core import Context - from .core import Parameter - from .shell_completion import CompletionItem - - -class ParamType: - """Represents the type of a parameter. Validates and converts values - from the command line or Python into the correct type. - - To implement a custom type, subclass and implement at least the - following: - - - The :attr:`name` class attribute must be set. - - Calling an instance of the type with ``None`` must return - ``None``. This is already implemented by default. - - :meth:`convert` must convert string values to the correct type. - - :meth:`convert` must accept values that are already the correct - type. - - It must be able to convert a value if the ``ctx`` and ``param`` - arguments are ``None``. This can occur when converting prompt - input. - """ - - is_composite: t.ClassVar[bool] = False - arity: t.ClassVar[int] = 1 - - #: the descriptive name of this type - name: str - - #: if a list of this type is expected and the value is pulled from a - #: string environment variable, this is what splits it up. `None` - #: means any whitespace. For all parameters the general rule is that - #: whitespace splits them up. The exception are paths and files which - #: are split by ``os.path.pathsep`` by default (":" on Unix and ";" on - #: Windows). - envvar_list_splitter: t.ClassVar[t.Optional[str]] = None - - def to_info_dict(self) -> t.Dict[str, t.Any]: - """Gather information that could be useful for a tool generating - user-facing documentation. - - Use :meth:`click.Context.to_info_dict` to traverse the entire - CLI structure. - - .. versionadded:: 8.0 - """ - # The class name without the "ParamType" suffix. - param_type = type(self).__name__.partition("ParamType")[0] - param_type = param_type.partition("ParameterType")[0] - - # Custom subclasses might not remember to set a name. - if hasattr(self, "name"): - name = self.name - else: - name = param_type - - return {"param_type": param_type, "name": name} - - def __call__( - self, - value: t.Any, - param: t.Optional["Parameter"] = None, - ctx: t.Optional["Context"] = None, - ) -> t.Any: - if value is not None: - return self.convert(value, param, ctx) - - def get_metavar(self, param: "Parameter") -> t.Optional[str]: - """Returns the metavar default for this param if it provides one.""" - - def get_missing_message(self, param: "Parameter") -> t.Optional[str]: - """Optionally might return extra information about a missing - parameter. - - .. versionadded:: 2.0 - """ - - def convert( - self, value: t.Any, param: t.Optional["Parameter"], ctx: t.Optional["Context"] - ) -> t.Any: - """Convert the value to the correct type. This is not called if - the value is ``None`` (the missing value). - - This must accept string values from the command line, as well as - values that are already the correct type. It may also convert - other compatible types. - - The ``param`` and ``ctx`` arguments may be ``None`` in certain - situations, such as when converting prompt input. - - If the value cannot be converted, call :meth:`fail` with a - descriptive message. - - :param value: The value to convert. - :param param: The parameter that is using this type to convert - its value. May be ``None``. - :param ctx: The current context that arrived at this value. May - be ``None``. - """ - return value - - def split_envvar_value(self, rv: str) -> t.Sequence[str]: - """Given a value from an environment variable this splits it up - into small chunks depending on the defined envvar list splitter. - - If the splitter is set to `None`, which means that whitespace splits, - then leading and trailing whitespace is ignored. Otherwise, leading - and trailing splitters usually lead to empty items being included. - """ - return (rv or "").split(self.envvar_list_splitter) - - def fail( - self, - message: str, - param: t.Optional["Parameter"] = None, - ctx: t.Optional["Context"] = None, - ) -> "t.NoReturn": - """Helper method to fail with an invalid value message.""" - raise BadParameter(message, ctx=ctx, param=param) - - def shell_complete( - self, ctx: "Context", param: "Parameter", incomplete: str - ) -> t.List["CompletionItem"]: - """Return a list of - :class:`~click.shell_completion.CompletionItem` objects for the - incomplete value. Most types do not provide completions, but - some do, and this allows custom types to provide custom - completions as well. - - :param ctx: Invocation context for this command. - :param param: The parameter that is requesting completion. - :param incomplete: Value being completed. May be empty. - - .. versionadded:: 8.0 - """ - return [] - - -class CompositeParamType(ParamType): - is_composite = True - - @property - def arity(self) -> int: # type: ignore - raise NotImplementedError() - - -class FuncParamType(ParamType): - def __init__(self, func: t.Callable[[t.Any], t.Any]) -> None: - self.name: str = func.__name__ - self.func = func - - def to_info_dict(self) -> t.Dict[str, t.Any]: - info_dict = super().to_info_dict() - info_dict["func"] = self.func - return info_dict - - def convert( - self, value: t.Any, param: t.Optional["Parameter"], ctx: t.Optional["Context"] - ) -> t.Any: - try: - return self.func(value) - except ValueError: - try: - value = str(value) - except UnicodeError: - value = value.decode("utf-8", "replace") - - self.fail(value, param, ctx) - - -class UnprocessedParamType(ParamType): - name = "text" - - def convert( - self, value: t.Any, param: t.Optional["Parameter"], ctx: t.Optional["Context"] - ) -> t.Any: - return value - - def __repr__(self) -> str: - return "UNPROCESSED" - - -class StringParamType(ParamType): - name = "text" - - def convert( - self, value: t.Any, param: t.Optional["Parameter"], ctx: t.Optional["Context"] - ) -> t.Any: - if isinstance(value, bytes): - enc = _get_argv_encoding() - try: - value = value.decode(enc) - except UnicodeError: - fs_enc = sys.getfilesystemencoding() - if fs_enc != enc: - try: - value = value.decode(fs_enc) - except UnicodeError: - value = value.decode("utf-8", "replace") - else: - value = value.decode("utf-8", "replace") - return value - return str(value) - - def __repr__(self) -> str: - return "STRING" - - -class Choice(ParamType): - """The choice type allows a value to be checked against a fixed set - of supported values. All of these values have to be strings. - - You should only pass a list or tuple of choices. Other iterables - (like generators) may lead to surprising results. - - The resulting value will always be one of the originally passed choices - regardless of ``case_sensitive`` or any ``ctx.token_normalize_func`` - being specified. - - See :ref:`choice-opts` for an example. - - :param case_sensitive: Set to false to make choices case - insensitive. Defaults to true. - """ - - name = "choice" - - def __init__(self, choices: t.Sequence[str], case_sensitive: bool = True) -> None: - self.choices = choices - self.case_sensitive = case_sensitive - - def to_info_dict(self) -> t.Dict[str, t.Any]: - info_dict = super().to_info_dict() - info_dict["choices"] = self.choices - info_dict["case_sensitive"] = self.case_sensitive - return info_dict - - def get_metavar(self, param: "Parameter") -> str: - choices_str = "|".join(self.choices) - - # Use curly braces to indicate a required argument. - if param.required and param.param_type_name == "argument": - return f"{{{choices_str}}}" - - # Use square braces to indicate an option or optional argument. - return f"[{choices_str}]" - - def get_missing_message(self, param: "Parameter") -> str: - return _("Choose from:\n\t{choices}").format(choices=",\n\t".join(self.choices)) - - def convert( - self, value: t.Any, param: t.Optional["Parameter"], ctx: t.Optional["Context"] - ) -> t.Any: - # Match through normalization and case sensitivity - # first do token_normalize_func, then lowercase - # preserve original `value` to produce an accurate message in - # `self.fail` - normed_value = value - normed_choices = {choice: choice for choice in self.choices} - - if ctx is not None and ctx.token_normalize_func is not None: - normed_value = ctx.token_normalize_func(value) - normed_choices = { - ctx.token_normalize_func(normed_choice): original - for normed_choice, original in normed_choices.items() - } - - if not self.case_sensitive: - normed_value = normed_value.casefold() - normed_choices = { - normed_choice.casefold(): original - for normed_choice, original in normed_choices.items() - } - - if normed_value in normed_choices: - return normed_choices[normed_value] - - choices_str = ", ".join(map(repr, self.choices)) - self.fail( - ngettext( - "{value!r} is not {choice}.", - "{value!r} is not one of {choices}.", - len(self.choices), - ).format(value=value, choice=choices_str, choices=choices_str), - param, - ctx, - ) - - def __repr__(self) -> str: - return f"Choice({list(self.choices)})" - - def shell_complete( - self, ctx: "Context", param: "Parameter", incomplete: str - ) -> t.List["CompletionItem"]: - """Complete choices that start with the incomplete value. - - :param ctx: Invocation context for this command. - :param param: The parameter that is requesting completion. - :param incomplete: Value being completed. May be empty. - - .. versionadded:: 8.0 - """ - from click.shell_completion import CompletionItem - - str_choices = map(str, self.choices) - - if self.case_sensitive: - matched = (c for c in str_choices if c.startswith(incomplete)) - else: - incomplete = incomplete.lower() - matched = (c for c in str_choices if c.lower().startswith(incomplete)) - - return [CompletionItem(c) for c in matched] - - -class DateTime(ParamType): - """The DateTime type converts date strings into `datetime` objects. - - The format strings which are checked are configurable, but default to some - common (non-timezone aware) ISO 8601 formats. - - When specifying *DateTime* formats, you should only pass a list or a tuple. - Other iterables, like generators, may lead to surprising results. - - The format strings are processed using ``datetime.strptime``, and this - consequently defines the format strings which are allowed. - - Parsing is tried using each format, in order, and the first format which - parses successfully is used. - - :param formats: A list or tuple of date format strings, in the order in - which they should be tried. Defaults to - ``'%Y-%m-%d'``, ``'%Y-%m-%dT%H:%M:%S'``, - ``'%Y-%m-%d %H:%M:%S'``. - """ - - name = "datetime" - - def __init__(self, formats: t.Optional[t.Sequence[str]] = None): - self.formats: t.Sequence[str] = formats or [ - "%Y-%m-%d", - "%Y-%m-%dT%H:%M:%S", - "%Y-%m-%d %H:%M:%S", - ] - - def to_info_dict(self) -> t.Dict[str, t.Any]: - info_dict = super().to_info_dict() - info_dict["formats"] = self.formats - return info_dict - - def get_metavar(self, param: "Parameter") -> str: - return f"[{'|'.join(self.formats)}]" - - def _try_to_convert_date(self, value: t.Any, format: str) -> t.Optional[datetime]: - try: - return datetime.strptime(value, format) - except ValueError: - return None - - def convert( - self, value: t.Any, param: t.Optional["Parameter"], ctx: t.Optional["Context"] - ) -> t.Any: - if isinstance(value, datetime): - return value - - for format in self.formats: - converted = self._try_to_convert_date(value, format) - - if converted is not None: - return converted - - formats_str = ", ".join(map(repr, self.formats)) - self.fail( - ngettext( - "{value!r} does not match the format {format}.", - "{value!r} does not match the formats {formats}.", - len(self.formats), - ).format(value=value, format=formats_str, formats=formats_str), - param, - ctx, - ) - - def __repr__(self) -> str: - return "DateTime" - - -class _NumberParamTypeBase(ParamType): - _number_class: t.ClassVar[t.Type[t.Any]] - - def convert( - self, value: t.Any, param: t.Optional["Parameter"], ctx: t.Optional["Context"] - ) -> t.Any: - try: - return self._number_class(value) - except ValueError: - self.fail( - _("{value!r} is not a valid {number_type}.").format( - value=value, number_type=self.name - ), - param, - ctx, - ) - - -class _NumberRangeBase(_NumberParamTypeBase): - def __init__( - self, - min: t.Optional[float] = None, - max: t.Optional[float] = None, - min_open: bool = False, - max_open: bool = False, - clamp: bool = False, - ) -> None: - self.min = min - self.max = max - self.min_open = min_open - self.max_open = max_open - self.clamp = clamp - - def to_info_dict(self) -> t.Dict[str, t.Any]: - info_dict = super().to_info_dict() - info_dict.update( - min=self.min, - max=self.max, - min_open=self.min_open, - max_open=self.max_open, - clamp=self.clamp, - ) - return info_dict - - def convert( - self, value: t.Any, param: t.Optional["Parameter"], ctx: t.Optional["Context"] - ) -> t.Any: - import operator - - rv = super().convert(value, param, ctx) - lt_min: bool = self.min is not None and ( - operator.le if self.min_open else operator.lt - )(rv, self.min) - gt_max: bool = self.max is not None and ( - operator.ge if self.max_open else operator.gt - )(rv, self.max) - - if self.clamp: - if lt_min: - return self._clamp(self.min, 1, self.min_open) # type: ignore - - if gt_max: - return self._clamp(self.max, -1, self.max_open) # type: ignore - - if lt_min or gt_max: - self.fail( - _("{value} is not in the range {range}.").format( - value=rv, range=self._describe_range() - ), - param, - ctx, - ) - - return rv - - def _clamp(self, bound: float, dir: "te.Literal[1, -1]", open: bool) -> float: - """Find the valid value to clamp to bound in the given - direction. - - :param bound: The boundary value. - :param dir: 1 or -1 indicating the direction to move. - :param open: If true, the range does not include the bound. - """ - raise NotImplementedError - - def _describe_range(self) -> str: - """Describe the range for use in help text.""" - if self.min is None: - op = "<" if self.max_open else "<=" - return f"x{op}{self.max}" - - if self.max is None: - op = ">" if self.min_open else ">=" - return f"x{op}{self.min}" - - lop = "<" if self.min_open else "<=" - rop = "<" if self.max_open else "<=" - return f"{self.min}{lop}x{rop}{self.max}" - - def __repr__(self) -> str: - clamp = " clamped" if self.clamp else "" - return f"<{type(self).__name__} {self._describe_range()}{clamp}>" - - -class IntParamType(_NumberParamTypeBase): - name = "integer" - _number_class = int - - def __repr__(self) -> str: - return "INT" - - -class IntRange(_NumberRangeBase, IntParamType): - """Restrict an :data:`click.INT` value to a range of accepted - values. See :ref:`ranges`. - - If ``min`` or ``max`` are not passed, any value is accepted in that - direction. If ``min_open`` or ``max_open`` are enabled, the - corresponding boundary is not included in the range. - - If ``clamp`` is enabled, a value outside the range is clamped to the - boundary instead of failing. - - .. versionchanged:: 8.0 - Added the ``min_open`` and ``max_open`` parameters. - """ - - name = "integer range" - - def _clamp( # type: ignore - self, bound: int, dir: "te.Literal[1, -1]", open: bool - ) -> int: - if not open: - return bound - - return bound + dir - - -class FloatParamType(_NumberParamTypeBase): - name = "float" - _number_class = float - - def __repr__(self) -> str: - return "FLOAT" - - -class FloatRange(_NumberRangeBase, FloatParamType): - """Restrict a :data:`click.FLOAT` value to a range of accepted - values. See :ref:`ranges`. - - If ``min`` or ``max`` are not passed, any value is accepted in that - direction. If ``min_open`` or ``max_open`` are enabled, the - corresponding boundary is not included in the range. - - If ``clamp`` is enabled, a value outside the range is clamped to the - boundary instead of failing. This is not supported if either - boundary is marked ``open``. - - .. versionchanged:: 8.0 - Added the ``min_open`` and ``max_open`` parameters. - """ - - name = "float range" - - def __init__( - self, - min: t.Optional[float] = None, - max: t.Optional[float] = None, - min_open: bool = False, - max_open: bool = False, - clamp: bool = False, - ) -> None: - super().__init__( - min=min, max=max, min_open=min_open, max_open=max_open, clamp=clamp - ) - - if (min_open or max_open) and clamp: - raise TypeError("Clamping is not supported for open bounds.") - - def _clamp(self, bound: float, dir: "te.Literal[1, -1]", open: bool) -> float: - if not open: - return bound - - # Could use Python 3.9's math.nextafter here, but clamping an - # open float range doesn't seem to be particularly useful. It's - # left up to the user to write a callback to do it if needed. - raise RuntimeError("Clamping is not supported for open bounds.") - - -class BoolParamType(ParamType): - name = "boolean" - - def convert( - self, value: t.Any, param: t.Optional["Parameter"], ctx: t.Optional["Context"] - ) -> t.Any: - if value in {False, True}: - return bool(value) - - norm = value.strip().lower() - - if norm in {"1", "true", "t", "yes", "y", "on"}: - return True - - if norm in {"0", "false", "f", "no", "n", "off"}: - return False - - self.fail( - _("{value!r} is not a valid boolean.").format(value=value), param, ctx - ) - - def __repr__(self) -> str: - return "BOOL" - - -class UUIDParameterType(ParamType): - name = "uuid" - - def convert( - self, value: t.Any, param: t.Optional["Parameter"], ctx: t.Optional["Context"] - ) -> t.Any: - import uuid - - if isinstance(value, uuid.UUID): - return value - - value = value.strip() - - try: - return uuid.UUID(value) - except ValueError: - self.fail( - _("{value!r} is not a valid UUID.").format(value=value), param, ctx - ) - - def __repr__(self) -> str: - return "UUID" - - -class File(ParamType): - """Declares a parameter to be a file for reading or writing. The file - is automatically closed once the context tears down (after the command - finished working). - - Files can be opened for reading or writing. The special value ``-`` - indicates stdin or stdout depending on the mode. - - By default, the file is opened for reading text data, but it can also be - opened in binary mode or for writing. The encoding parameter can be used - to force a specific encoding. - - The `lazy` flag controls if the file should be opened immediately or upon - first IO. The default is to be non-lazy for standard input and output - streams as well as files opened for reading, `lazy` otherwise. When opening a - file lazily for reading, it is still opened temporarily for validation, but - will not be held open until first IO. lazy is mainly useful when opening - for writing to avoid creating the file until it is needed. - - Files can also be opened atomically in which case all writes go into a - separate file in the same folder and upon completion the file will - be moved over to the original location. This is useful if a file - regularly read by other users is modified. - - See :ref:`file-args` for more information. - - .. versionchanged:: 2.0 - Added the ``atomic`` parameter. - """ - - name = "filename" - envvar_list_splitter: t.ClassVar[str] = os.path.pathsep - - def __init__( - self, - mode: str = "r", - encoding: t.Optional[str] = None, - errors: t.Optional[str] = "strict", - lazy: t.Optional[bool] = None, - atomic: bool = False, - ) -> None: - self.mode = mode - self.encoding = encoding - self.errors = errors - self.lazy = lazy - self.atomic = atomic - - def to_info_dict(self) -> t.Dict[str, t.Any]: - info_dict = super().to_info_dict() - info_dict.update(mode=self.mode, encoding=self.encoding) - return info_dict - - def resolve_lazy_flag(self, value: "t.Union[str, os.PathLike[str]]") -> bool: - if self.lazy is not None: - return self.lazy - if os.fspath(value) == "-": - return False - elif "w" in self.mode: - return True - return False - - def convert( - self, - value: t.Union[str, "os.PathLike[str]", t.IO[t.Any]], - param: t.Optional["Parameter"], - ctx: t.Optional["Context"], - ) -> t.IO[t.Any]: - if _is_file_like(value): - return value - - value = t.cast("t.Union[str, os.PathLike[str]]", value) - - try: - lazy = self.resolve_lazy_flag(value) - - if lazy: - lf = LazyFile( - value, self.mode, self.encoding, self.errors, atomic=self.atomic - ) - - if ctx is not None: - ctx.call_on_close(lf.close_intelligently) - - return t.cast(t.IO[t.Any], lf) - - f, should_close = open_stream( - value, self.mode, self.encoding, self.errors, atomic=self.atomic - ) - - # If a context is provided, we automatically close the file - # at the end of the context execution (or flush out). If a - # context does not exist, it's the caller's responsibility to - # properly close the file. This for instance happens when the - # type is used with prompts. - if ctx is not None: - if should_close: - ctx.call_on_close(safecall(f.close)) - else: - ctx.call_on_close(safecall(f.flush)) - - return f - except OSError as e: - self.fail(f"'{format_filename(value)}': {e.strerror}", param, ctx) - - def shell_complete( - self, ctx: "Context", param: "Parameter", incomplete: str - ) -> t.List["CompletionItem"]: - """Return a special completion marker that tells the completion - system to use the shell to provide file path completions. - - :param ctx: Invocation context for this command. - :param param: The parameter that is requesting completion. - :param incomplete: Value being completed. May be empty. - - .. versionadded:: 8.0 - """ - from click.shell_completion import CompletionItem - - return [CompletionItem(incomplete, type="file")] - - -def _is_file_like(value: t.Any) -> "te.TypeGuard[t.IO[t.Any]]": - return hasattr(value, "read") or hasattr(value, "write") - - -class Path(ParamType): - """The ``Path`` type is similar to the :class:`File` type, but - returns the filename instead of an open file. Various checks can be - enabled to validate the type of file and permissions. - - :param exists: The file or directory needs to exist for the value to - be valid. If this is not set to ``True``, and the file does not - exist, then all further checks are silently skipped. - :param file_okay: Allow a file as a value. - :param dir_okay: Allow a directory as a value. - :param readable: if true, a readable check is performed. - :param writable: if true, a writable check is performed. - :param executable: if true, an executable check is performed. - :param resolve_path: Make the value absolute and resolve any - symlinks. A ``~`` is not expanded, as this is supposed to be - done by the shell only. - :param allow_dash: Allow a single dash as a value, which indicates - a standard stream (but does not open it). Use - :func:`~click.open_file` to handle opening this value. - :param path_type: Convert the incoming path value to this type. If - ``None``, keep Python's default, which is ``str``. Useful to - convert to :class:`pathlib.Path`. - - .. versionchanged:: 8.1 - Added the ``executable`` parameter. - - .. versionchanged:: 8.0 - Allow passing ``path_type=pathlib.Path``. - - .. versionchanged:: 6.0 - Added the ``allow_dash`` parameter. - """ - - envvar_list_splitter: t.ClassVar[str] = os.path.pathsep - - def __init__( - self, - exists: bool = False, - file_okay: bool = True, - dir_okay: bool = True, - writable: bool = False, - readable: bool = True, - resolve_path: bool = False, - allow_dash: bool = False, - path_type: t.Optional[t.Type[t.Any]] = None, - executable: bool = False, - ): - self.exists = exists - self.file_okay = file_okay - self.dir_okay = dir_okay - self.readable = readable - self.writable = writable - self.executable = executable - self.resolve_path = resolve_path - self.allow_dash = allow_dash - self.type = path_type - - if self.file_okay and not self.dir_okay: - self.name: str = _("file") - elif self.dir_okay and not self.file_okay: - self.name = _("directory") - else: - self.name = _("path") - - def to_info_dict(self) -> t.Dict[str, t.Any]: - info_dict = super().to_info_dict() - info_dict.update( - exists=self.exists, - file_okay=self.file_okay, - dir_okay=self.dir_okay, - writable=self.writable, - readable=self.readable, - allow_dash=self.allow_dash, - ) - return info_dict - - def coerce_path_result( - self, value: "t.Union[str, os.PathLike[str]]" - ) -> "t.Union[str, bytes, os.PathLike[str]]": - if self.type is not None and not isinstance(value, self.type): - if self.type is str: - return os.fsdecode(value) - elif self.type is bytes: - return os.fsencode(value) - else: - return t.cast("os.PathLike[str]", self.type(value)) - - return value - - def convert( - self, - value: "t.Union[str, os.PathLike[str]]", - param: t.Optional["Parameter"], - ctx: t.Optional["Context"], - ) -> "t.Union[str, bytes, os.PathLike[str]]": - rv = value - - is_dash = self.file_okay and self.allow_dash and rv in (b"-", "-") - - if not is_dash: - if self.resolve_path: - # os.path.realpath doesn't resolve symlinks on Windows - # until Python 3.8. Use pathlib for now. - import pathlib - - rv = os.fsdecode(pathlib.Path(rv).resolve()) - - try: - st = os.stat(rv) - except OSError: - if not self.exists: - return self.coerce_path_result(rv) - self.fail( - _("{name} {filename!r} does not exist.").format( - name=self.name.title(), filename=format_filename(value) - ), - param, - ctx, - ) - - if not self.file_okay and stat.S_ISREG(st.st_mode): - self.fail( - _("{name} {filename!r} is a file.").format( - name=self.name.title(), filename=format_filename(value) - ), - param, - ctx, - ) - if not self.dir_okay and stat.S_ISDIR(st.st_mode): - self.fail( - _("{name} {filename!r} is a directory.").format( - name=self.name.title(), filename=format_filename(value) - ), - param, - ctx, - ) - - if self.readable and not os.access(rv, os.R_OK): - self.fail( - _("{name} {filename!r} is not readable.").format( - name=self.name.title(), filename=format_filename(value) - ), - param, - ctx, - ) - - if self.writable and not os.access(rv, os.W_OK): - self.fail( - _("{name} {filename!r} is not writable.").format( - name=self.name.title(), filename=format_filename(value) - ), - param, - ctx, - ) - - if self.executable and not os.access(value, os.X_OK): - self.fail( - _("{name} {filename!r} is not executable.").format( - name=self.name.title(), filename=format_filename(value) - ), - param, - ctx, - ) - - return self.coerce_path_result(rv) - - def shell_complete( - self, ctx: "Context", param: "Parameter", incomplete: str - ) -> t.List["CompletionItem"]: - """Return a special completion marker that tells the completion - system to use the shell to provide path completions for only - directories or any paths. - - :param ctx: Invocation context for this command. - :param param: The parameter that is requesting completion. - :param incomplete: Value being completed. May be empty. - - .. versionadded:: 8.0 - """ - from click.shell_completion import CompletionItem - - type = "dir" if self.dir_okay and not self.file_okay else "file" - return [CompletionItem(incomplete, type=type)] - - -class Tuple(CompositeParamType): - """The default behavior of Click is to apply a type on a value directly. - This works well in most cases, except for when `nargs` is set to a fixed - count and different types should be used for different items. In this - case the :class:`Tuple` type can be used. This type can only be used - if `nargs` is set to a fixed number. - - For more information see :ref:`tuple-type`. - - This can be selected by using a Python tuple literal as a type. - - :param types: a list of types that should be used for the tuple items. - """ - - def __init__(self, types: t.Sequence[t.Union[t.Type[t.Any], ParamType]]) -> None: - self.types: t.Sequence[ParamType] = [convert_type(ty) for ty in types] - - def to_info_dict(self) -> t.Dict[str, t.Any]: - info_dict = super().to_info_dict() - info_dict["types"] = [t.to_info_dict() for t in self.types] - return info_dict - - @property - def name(self) -> str: # type: ignore - return f"<{' '.join(ty.name for ty in self.types)}>" - - @property - def arity(self) -> int: # type: ignore - return len(self.types) - - def convert( - self, value: t.Any, param: t.Optional["Parameter"], ctx: t.Optional["Context"] - ) -> t.Any: - len_type = len(self.types) - len_value = len(value) - - if len_value != len_type: - self.fail( - ngettext( - "{len_type} values are required, but {len_value} was given.", - "{len_type} values are required, but {len_value} were given.", - len_value, - ).format(len_type=len_type, len_value=len_value), - param=param, - ctx=ctx, - ) - - return tuple(ty(x, param, ctx) for ty, x in zip(self.types, value)) - - -def convert_type(ty: t.Optional[t.Any], default: t.Optional[t.Any] = None) -> ParamType: - """Find the most appropriate :class:`ParamType` for the given Python - type. If the type isn't provided, it can be inferred from a default - value. - """ - guessed_type = False - - if ty is None and default is not None: - if isinstance(default, (tuple, list)): - # If the default is empty, ty will remain None and will - # return STRING. - if default: - item = default[0] - - # A tuple of tuples needs to detect the inner types. - # Can't call convert recursively because that would - # incorrectly unwind the tuple to a single type. - if isinstance(item, (tuple, list)): - ty = tuple(map(type, item)) - else: - ty = type(item) - else: - ty = type(default) - - guessed_type = True - - if isinstance(ty, tuple): - return Tuple(ty) - - if isinstance(ty, ParamType): - return ty - - if ty is str or ty is None: - return STRING - - if ty is int: - return INT - - if ty is float: - return FLOAT - - if ty is bool: - return BOOL - - if guessed_type: - return STRING - - if __debug__: - try: - if issubclass(ty, ParamType): - raise AssertionError( - f"Attempted to use an uninstantiated parameter type ({ty})." - ) - except TypeError: - # ty is an instance (correct), so issubclass fails. - pass - - return FuncParamType(ty) - - -#: A dummy parameter type that just does nothing. From a user's -#: perspective this appears to just be the same as `STRING` but -#: internally no string conversion takes place if the input was bytes. -#: This is usually useful when working with file paths as they can -#: appear in bytes and unicode. -#: -#: For path related uses the :class:`Path` type is a better choice but -#: there are situations where an unprocessed type is useful which is why -#: it is is provided. -#: -#: .. versionadded:: 4.0 -UNPROCESSED = UnprocessedParamType() - -#: A unicode string parameter type which is the implicit default. This -#: can also be selected by using ``str`` as type. -STRING = StringParamType() - -#: An integer parameter. This can also be selected by using ``int`` as -#: type. -INT = IntParamType() - -#: A floating point value parameter. This can also be selected by using -#: ``float`` as type. -FLOAT = FloatParamType() - -#: A boolean parameter. This is the default for boolean flags. This can -#: also be selected by using ``bool`` as a type. -BOOL = BoolParamType() - -#: A UUID parameter. -UUID = UUIDParameterType() diff --git a/venv/lib/python3.9/site-packages/click/utils.py b/venv/lib/python3.9/site-packages/click/utils.py deleted file mode 100644 index 836c6f2..0000000 --- a/venv/lib/python3.9/site-packages/click/utils.py +++ /dev/null @@ -1,624 +0,0 @@ -import os -import re -import sys -import typing as t -from functools import update_wrapper -from types import ModuleType -from types import TracebackType - -from ._compat import _default_text_stderr -from ._compat import _default_text_stdout -from ._compat import _find_binary_writer -from ._compat import auto_wrap_for_ansi -from ._compat import binary_streams -from ._compat import open_stream -from ._compat import should_strip_ansi -from ._compat import strip_ansi -from ._compat import text_streams -from ._compat import WIN -from .globals import resolve_color_default - -if t.TYPE_CHECKING: - import typing_extensions as te - - P = te.ParamSpec("P") - -R = t.TypeVar("R") - - -def _posixify(name: str) -> str: - return "-".join(name.split()).lower() - - -def safecall(func: "t.Callable[P, R]") -> "t.Callable[P, t.Optional[R]]": - """Wraps a function so that it swallows exceptions.""" - - def wrapper(*args: "P.args", **kwargs: "P.kwargs") -> t.Optional[R]: - try: - return func(*args, **kwargs) - except Exception: - pass - return None - - return update_wrapper(wrapper, func) - - -def make_str(value: t.Any) -> str: - """Converts a value into a valid string.""" - if isinstance(value, bytes): - try: - return value.decode(sys.getfilesystemencoding()) - except UnicodeError: - return value.decode("utf-8", "replace") - return str(value) - - -def make_default_short_help(help: str, max_length: int = 45) -> str: - """Returns a condensed version of help string.""" - # Consider only the first paragraph. - paragraph_end = help.find("\n\n") - - if paragraph_end != -1: - help = help[:paragraph_end] - - # Collapse newlines, tabs, and spaces. - words = help.split() - - if not words: - return "" - - # The first paragraph started with a "no rewrap" marker, ignore it. - if words[0] == "\b": - words = words[1:] - - total_length = 0 - last_index = len(words) - 1 - - for i, word in enumerate(words): - total_length += len(word) + (i > 0) - - if total_length > max_length: # too long, truncate - break - - if word[-1] == ".": # sentence end, truncate without "..." - return " ".join(words[: i + 1]) - - if total_length == max_length and i != last_index: - break # not at sentence end, truncate with "..." - else: - return " ".join(words) # no truncation needed - - # Account for the length of the suffix. - total_length += len("...") - - # remove words until the length is short enough - while i > 0: - total_length -= len(words[i]) + (i > 0) - - if total_length <= max_length: - break - - i -= 1 - - return " ".join(words[:i]) + "..." - - -class LazyFile: - """A lazy file works like a regular file but it does not fully open - the file but it does perform some basic checks early to see if the - filename parameter does make sense. This is useful for safely opening - files for writing. - """ - - def __init__( - self, - filename: t.Union[str, "os.PathLike[str]"], - mode: str = "r", - encoding: t.Optional[str] = None, - errors: t.Optional[str] = "strict", - atomic: bool = False, - ): - self.name: str = os.fspath(filename) - self.mode = mode - self.encoding = encoding - self.errors = errors - self.atomic = atomic - self._f: t.Optional[t.IO[t.Any]] - self.should_close: bool - - if self.name == "-": - self._f, self.should_close = open_stream(filename, mode, encoding, errors) - else: - if "r" in mode: - # Open and close the file in case we're opening it for - # reading so that we can catch at least some errors in - # some cases early. - open(filename, mode).close() - self._f = None - self.should_close = True - - def __getattr__(self, name: str) -> t.Any: - return getattr(self.open(), name) - - def __repr__(self) -> str: - if self._f is not None: - return repr(self._f) - return f"" - - def open(self) -> t.IO[t.Any]: - """Opens the file if it's not yet open. This call might fail with - a :exc:`FileError`. Not handling this error will produce an error - that Click shows. - """ - if self._f is not None: - return self._f - try: - rv, self.should_close = open_stream( - self.name, self.mode, self.encoding, self.errors, atomic=self.atomic - ) - except OSError as e: - from .exceptions import FileError - - raise FileError(self.name, hint=e.strerror) from e - self._f = rv - return rv - - def close(self) -> None: - """Closes the underlying file, no matter what.""" - if self._f is not None: - self._f.close() - - def close_intelligently(self) -> None: - """This function only closes the file if it was opened by the lazy - file wrapper. For instance this will never close stdin. - """ - if self.should_close: - self.close() - - def __enter__(self) -> "LazyFile": - return self - - def __exit__( - self, - exc_type: t.Optional[t.Type[BaseException]], - exc_value: t.Optional[BaseException], - tb: t.Optional[TracebackType], - ) -> None: - self.close_intelligently() - - def __iter__(self) -> t.Iterator[t.AnyStr]: - self.open() - return iter(self._f) # type: ignore - - -class KeepOpenFile: - def __init__(self, file: t.IO[t.Any]) -> None: - self._file: t.IO[t.Any] = file - - def __getattr__(self, name: str) -> t.Any: - return getattr(self._file, name) - - def __enter__(self) -> "KeepOpenFile": - return self - - def __exit__( - self, - exc_type: t.Optional[t.Type[BaseException]], - exc_value: t.Optional[BaseException], - tb: t.Optional[TracebackType], - ) -> None: - pass - - def __repr__(self) -> str: - return repr(self._file) - - def __iter__(self) -> t.Iterator[t.AnyStr]: - return iter(self._file) - - -def echo( - message: t.Optional[t.Any] = None, - file: t.Optional[t.IO[t.Any]] = None, - nl: bool = True, - err: bool = False, - color: t.Optional[bool] = None, -) -> None: - """Print a message and newline to stdout or a file. This should be - used instead of :func:`print` because it provides better support - for different data, files, and environments. - - Compared to :func:`print`, this does the following: - - - Ensures that the output encoding is not misconfigured on Linux. - - Supports Unicode in the Windows console. - - Supports writing to binary outputs, and supports writing bytes - to text outputs. - - Supports colors and styles on Windows. - - Removes ANSI color and style codes if the output does not look - like an interactive terminal. - - Always flushes the output. - - :param message: The string or bytes to output. Other objects are - converted to strings. - :param file: The file to write to. Defaults to ``stdout``. - :param err: Write to ``stderr`` instead of ``stdout``. - :param nl: Print a newline after the message. Enabled by default. - :param color: Force showing or hiding colors and other styles. By - default Click will remove color if the output does not look like - an interactive terminal. - - .. versionchanged:: 6.0 - Support Unicode output on the Windows console. Click does not - modify ``sys.stdout``, so ``sys.stdout.write()`` and ``print()`` - will still not support Unicode. - - .. versionchanged:: 4.0 - Added the ``color`` parameter. - - .. versionadded:: 3.0 - Added the ``err`` parameter. - - .. versionchanged:: 2.0 - Support colors on Windows if colorama is installed. - """ - if file is None: - if err: - file = _default_text_stderr() - else: - file = _default_text_stdout() - - # There are no standard streams attached to write to. For example, - # pythonw on Windows. - if file is None: - return - - # Convert non bytes/text into the native string type. - if message is not None and not isinstance(message, (str, bytes, bytearray)): - out: t.Optional[t.Union[str, bytes]] = str(message) - else: - out = message - - if nl: - out = out or "" - if isinstance(out, str): - out += "\n" - else: - out += b"\n" - - if not out: - file.flush() - return - - # If there is a message and the value looks like bytes, we manually - # need to find the binary stream and write the message in there. - # This is done separately so that most stream types will work as you - # would expect. Eg: you can write to StringIO for other cases. - if isinstance(out, (bytes, bytearray)): - binary_file = _find_binary_writer(file) - - if binary_file is not None: - file.flush() - binary_file.write(out) - binary_file.flush() - return - - # ANSI style code support. For no message or bytes, nothing happens. - # When outputting to a file instead of a terminal, strip codes. - else: - color = resolve_color_default(color) - - if should_strip_ansi(file, color): - out = strip_ansi(out) - elif WIN: - if auto_wrap_for_ansi is not None: - file = auto_wrap_for_ansi(file, color) # type: ignore - elif not color: - out = strip_ansi(out) - - file.write(out) # type: ignore - file.flush() - - -def get_binary_stream(name: "te.Literal['stdin', 'stdout', 'stderr']") -> t.BinaryIO: - """Returns a system stream for byte processing. - - :param name: the name of the stream to open. Valid names are ``'stdin'``, - ``'stdout'`` and ``'stderr'`` - """ - opener = binary_streams.get(name) - if opener is None: - raise TypeError(f"Unknown standard stream '{name}'") - return opener() - - -def get_text_stream( - name: "te.Literal['stdin', 'stdout', 'stderr']", - encoding: t.Optional[str] = None, - errors: t.Optional[str] = "strict", -) -> t.TextIO: - """Returns a system stream for text processing. This usually returns - a wrapped stream around a binary stream returned from - :func:`get_binary_stream` but it also can take shortcuts for already - correctly configured streams. - - :param name: the name of the stream to open. Valid names are ``'stdin'``, - ``'stdout'`` and ``'stderr'`` - :param encoding: overrides the detected default encoding. - :param errors: overrides the default error mode. - """ - opener = text_streams.get(name) - if opener is None: - raise TypeError(f"Unknown standard stream '{name}'") - return opener(encoding, errors) - - -def open_file( - filename: t.Union[str, "os.PathLike[str]"], - mode: str = "r", - encoding: t.Optional[str] = None, - errors: t.Optional[str] = "strict", - lazy: bool = False, - atomic: bool = False, -) -> t.IO[t.Any]: - """Open a file, with extra behavior to handle ``'-'`` to indicate - a standard stream, lazy open on write, and atomic write. Similar to - the behavior of the :class:`~click.File` param type. - - If ``'-'`` is given to open ``stdout`` or ``stdin``, the stream is - wrapped so that using it in a context manager will not close it. - This makes it possible to use the function without accidentally - closing a standard stream: - - .. code-block:: python - - with open_file(filename) as f: - ... - - :param filename: The name or Path of the file to open, or ``'-'`` for - ``stdin``/``stdout``. - :param mode: The mode in which to open the file. - :param encoding: The encoding to decode or encode a file opened in - text mode. - :param errors: The error handling mode. - :param lazy: Wait to open the file until it is accessed. For read - mode, the file is temporarily opened to raise access errors - early, then closed until it is read again. - :param atomic: Write to a temporary file and replace the given file - on close. - - .. versionadded:: 3.0 - """ - if lazy: - return t.cast( - t.IO[t.Any], LazyFile(filename, mode, encoding, errors, atomic=atomic) - ) - - f, should_close = open_stream(filename, mode, encoding, errors, atomic=atomic) - - if not should_close: - f = t.cast(t.IO[t.Any], KeepOpenFile(f)) - - return f - - -def format_filename( - filename: "t.Union[str, bytes, os.PathLike[str], os.PathLike[bytes]]", - shorten: bool = False, -) -> str: - """Format a filename as a string for display. Ensures the filename can be - displayed by replacing any invalid bytes or surrogate escapes in the name - with the replacement character ``�``. - - Invalid bytes or surrogate escapes will raise an error when written to a - stream with ``errors="strict"``. This will typically happen with ``stdout`` - when the locale is something like ``en_GB.UTF-8``. - - Many scenarios *are* safe to write surrogates though, due to PEP 538 and - PEP 540, including: - - - Writing to ``stderr``, which uses ``errors="backslashreplace"``. - - The system has ``LANG=C.UTF-8``, ``C``, or ``POSIX``. Python opens - stdout and stderr with ``errors="surrogateescape"``. - - None of ``LANG/LC_*`` are set. Python assumes ``LANG=C.UTF-8``. - - Python is started in UTF-8 mode with ``PYTHONUTF8=1`` or ``-X utf8``. - Python opens stdout and stderr with ``errors="surrogateescape"``. - - :param filename: formats a filename for UI display. This will also convert - the filename into unicode without failing. - :param shorten: this optionally shortens the filename to strip of the - path that leads up to it. - """ - if shorten: - filename = os.path.basename(filename) - else: - filename = os.fspath(filename) - - if isinstance(filename, bytes): - filename = filename.decode(sys.getfilesystemencoding(), "replace") - else: - filename = filename.encode("utf-8", "surrogateescape").decode( - "utf-8", "replace" - ) - - return filename - - -def get_app_dir(app_name: str, roaming: bool = True, force_posix: bool = False) -> str: - r"""Returns the config folder for the application. The default behavior - is to return whatever is most appropriate for the operating system. - - To give you an idea, for an app called ``"Foo Bar"``, something like - the following folders could be returned: - - Mac OS X: - ``~/Library/Application Support/Foo Bar`` - Mac OS X (POSIX): - ``~/.foo-bar`` - Unix: - ``~/.config/foo-bar`` - Unix (POSIX): - ``~/.foo-bar`` - Windows (roaming): - ``C:\Users\\AppData\Roaming\Foo Bar`` - Windows (not roaming): - ``C:\Users\\AppData\Local\Foo Bar`` - - .. versionadded:: 2.0 - - :param app_name: the application name. This should be properly capitalized - and can contain whitespace. - :param roaming: controls if the folder should be roaming or not on Windows. - Has no effect otherwise. - :param force_posix: if this is set to `True` then on any POSIX system the - folder will be stored in the home folder with a leading - dot instead of the XDG config home or darwin's - application support folder. - """ - if WIN: - key = "APPDATA" if roaming else "LOCALAPPDATA" - folder = os.environ.get(key) - if folder is None: - folder = os.path.expanduser("~") - return os.path.join(folder, app_name) - if force_posix: - return os.path.join(os.path.expanduser(f"~/.{_posixify(app_name)}")) - if sys.platform == "darwin": - return os.path.join( - os.path.expanduser("~/Library/Application Support"), app_name - ) - return os.path.join( - os.environ.get("XDG_CONFIG_HOME", os.path.expanduser("~/.config")), - _posixify(app_name), - ) - - -class PacifyFlushWrapper: - """This wrapper is used to catch and suppress BrokenPipeErrors resulting - from ``.flush()`` being called on broken pipe during the shutdown/final-GC - of the Python interpreter. Notably ``.flush()`` is always called on - ``sys.stdout`` and ``sys.stderr``. So as to have minimal impact on any - other cleanup code, and the case where the underlying file is not a broken - pipe, all calls and attributes are proxied. - """ - - def __init__(self, wrapped: t.IO[t.Any]) -> None: - self.wrapped = wrapped - - def flush(self) -> None: - try: - self.wrapped.flush() - except OSError as e: - import errno - - if e.errno != errno.EPIPE: - raise - - def __getattr__(self, attr: str) -> t.Any: - return getattr(self.wrapped, attr) - - -def _detect_program_name( - path: t.Optional[str] = None, _main: t.Optional[ModuleType] = None -) -> str: - """Determine the command used to run the program, for use in help - text. If a file or entry point was executed, the file name is - returned. If ``python -m`` was used to execute a module or package, - ``python -m name`` is returned. - - This doesn't try to be too precise, the goal is to give a concise - name for help text. Files are only shown as their name without the - path. ``python`` is only shown for modules, and the full path to - ``sys.executable`` is not shown. - - :param path: The Python file being executed. Python puts this in - ``sys.argv[0]``, which is used by default. - :param _main: The ``__main__`` module. This should only be passed - during internal testing. - - .. versionadded:: 8.0 - Based on command args detection in the Werkzeug reloader. - - :meta private: - """ - if _main is None: - _main = sys.modules["__main__"] - - if not path: - path = sys.argv[0] - - # The value of __package__ indicates how Python was called. It may - # not exist if a setuptools script is installed as an egg. It may be - # set incorrectly for entry points created with pip on Windows. - # It is set to "" inside a Shiv or PEX zipapp. - if getattr(_main, "__package__", None) in {None, ""} or ( - os.name == "nt" - and _main.__package__ == "" - and not os.path.exists(path) - and os.path.exists(f"{path}.exe") - ): - # Executed a file, like "python app.py". - return os.path.basename(path) - - # Executed a module, like "python -m example". - # Rewritten by Python from "-m script" to "/path/to/script.py". - # Need to look at main module to determine how it was executed. - py_module = t.cast(str, _main.__package__) - name = os.path.splitext(os.path.basename(path))[0] - - # A submodule like "example.cli". - if name != "__main__": - py_module = f"{py_module}.{name}" - - return f"python -m {py_module.lstrip('.')}" - - -def _expand_args( - args: t.Iterable[str], - *, - user: bool = True, - env: bool = True, - glob_recursive: bool = True, -) -> t.List[str]: - """Simulate Unix shell expansion with Python functions. - - See :func:`glob.glob`, :func:`os.path.expanduser`, and - :func:`os.path.expandvars`. - - This is intended for use on Windows, where the shell does not do any - expansion. It may not exactly match what a Unix shell would do. - - :param args: List of command line arguments to expand. - :param user: Expand user home directory. - :param env: Expand environment variables. - :param glob_recursive: ``**`` matches directories recursively. - - .. versionchanged:: 8.1 - Invalid glob patterns are treated as empty expansions rather - than raising an error. - - .. versionadded:: 8.0 - - :meta private: - """ - from glob import glob - - out = [] - - for arg in args: - if user: - arg = os.path.expanduser(arg) - - if env: - arg = os.path.expandvars(arg) - - try: - matches = glob(arg, recursive=glob_recursive) - except re.error: - matches = [] - - if not matches: - out.append(arg) - else: - out.extend(matches) - - return out diff --git a/venv/lib/python3.9/site-packages/cryptography-47.0.0.dist-info/INSTALLER b/venv/lib/python3.9/site-packages/cryptography-47.0.0.dist-info/INSTALLER deleted file mode 100644 index a1b589e..0000000 --- a/venv/lib/python3.9/site-packages/cryptography-47.0.0.dist-info/INSTALLER +++ /dev/null @@ -1 +0,0 @@ -pip diff --git a/venv/lib/python3.9/site-packages/cryptography-47.0.0.dist-info/METADATA b/venv/lib/python3.9/site-packages/cryptography-47.0.0.dist-info/METADATA deleted file mode 100644 index 4c5602f..0000000 --- a/venv/lib/python3.9/site-packages/cryptography-47.0.0.dist-info/METADATA +++ /dev/null @@ -1,112 +0,0 @@ -Metadata-Version: 2.4 -Name: cryptography -Version: 47.0.0 -Classifier: Development Status :: 5 - Production/Stable -Classifier: Intended Audience :: Developers -Classifier: Natural Language :: English -Classifier: Operating System :: MacOS :: MacOS X -Classifier: Operating System :: POSIX -Classifier: Operating System :: POSIX :: BSD -Classifier: Operating System :: POSIX :: Linux -Classifier: Operating System :: Microsoft :: Windows -Classifier: Programming Language :: Python -Classifier: Programming Language :: Python :: 3 -Classifier: Programming Language :: Python :: 3 :: Only -Classifier: Programming Language :: Python :: 3.8 -Classifier: Programming Language :: Python :: 3.9 -Classifier: Programming Language :: Python :: 3.10 -Classifier: Programming Language :: Python :: 3.11 -Classifier: Programming Language :: Python :: 3.12 -Classifier: Programming Language :: Python :: 3.13 -Classifier: Programming Language :: Python :: 3.14 -Classifier: Programming Language :: Python :: Implementation :: CPython -Classifier: Programming Language :: Python :: Implementation :: PyPy -Classifier: Programming Language :: Python :: Free Threading :: 3 - Stable -Classifier: Topic :: Security :: Cryptography -Requires-Dist: cffi>=1.14 ; python_full_version == '3.8.*' and platform_python_implementation != 'PyPy' -Requires-Dist: cffi>=2.0.0 ; python_full_version >= '3.9' and platform_python_implementation != 'PyPy' -Requires-Dist: typing-extensions>=4.13.2 ; python_full_version < '3.11' -Requires-Dist: bcrypt>=3.1.5 ; extra == 'ssh' -Provides-Extra: ssh -License-File: LICENSE -License-File: LICENSE.APACHE -License-File: LICENSE.BSD -Summary: cryptography is a package which provides cryptographic recipes and primitives to Python developers. -Author-email: The Python Cryptographic Authority and individual contributors -License-Expression: Apache-2.0 OR BSD-3-Clause -Requires-Python: >=3.8, !=3.9.0, !=3.9.1 -Description-Content-Type: text/x-rst; charset=UTF-8 -Project-URL: changelog, https://cryptography.io/en/latest/changelog/ -Project-URL: documentation, https://cryptography.io/ -Project-URL: homepage, https://github.com/pyca/cryptography -Project-URL: issues, https://github.com/pyca/cryptography/issues -Project-URL: source, https://github.com/pyca/cryptography/ - -pyca/cryptography -================= - -.. image:: https://img.shields.io/pypi/v/cryptography.svg - :target: https://pypi.org/project/cryptography/ - :alt: Latest Version - -.. image:: https://readthedocs.org/projects/cryptography/badge/?version=latest - :target: https://cryptography.io - :alt: Latest Docs - -.. image:: https://github.com/pyca/cryptography/actions/workflows/ci.yml/badge.svg - :target: https://github.com/pyca/cryptography/actions/workflows/ci.yml?query=branch%3Amain - -``cryptography`` is a package which provides cryptographic recipes and -primitives to Python developers. Our goal is for it to be your "cryptographic -standard library". It supports Python 3.8+ and PyPy3 7.3.11+. - -``cryptography`` includes both high level recipes and low level interfaces to -common cryptographic algorithms such as symmetric ciphers, message digests, and -key derivation functions. For example, to encrypt something with -``cryptography``'s high level symmetric encryption recipe: - -.. code-block:: pycon - - >>> from cryptography.fernet import Fernet - >>> # Put this somewhere safe! - >>> key = Fernet.generate_key() - >>> f = Fernet(key) - >>> token = f.encrypt(b"A really secret message. Not for prying eyes.") - >>> token - b'...' - >>> f.decrypt(token) - b'A really secret message. Not for prying eyes.' - -You can find more information in the `documentation`_. - -You can install ``cryptography`` with: - -.. code-block:: console - - $ pip install cryptography - -For full details see `the installation documentation`_. - -Discussion -~~~~~~~~~~ - -If you run into bugs, you can file them in our `issue tracker`_. - -We maintain a `cryptography-dev`_ mailing list for development discussion. - -You can also join ``#pyca`` on ``irc.libera.chat`` to ask questions or get -involved. - -Security -~~~~~~~~ - -Need to report a security issue? Please consult our `security reporting`_ -documentation. - - -.. _`documentation`: https://cryptography.io/ -.. _`the installation documentation`: https://cryptography.io/en/latest/installation/ -.. _`issue tracker`: https://github.com/pyca/cryptography/issues -.. _`cryptography-dev`: https://mail.python.org/mailman/listinfo/cryptography-dev -.. _`security reporting`: https://cryptography.io/en/latest/security/ - diff --git a/venv/lib/python3.9/site-packages/cryptography-47.0.0.dist-info/RECORD b/venv/lib/python3.9/site-packages/cryptography-47.0.0.dist-info/RECORD deleted file mode 100644 index 5cc47da..0000000 --- a/venv/lib/python3.9/site-packages/cryptography-47.0.0.dist-info/RECORD +++ /dev/null @@ -1,195 +0,0 @@ -cryptography-47.0.0.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 -cryptography-47.0.0.dist-info/METADATA,sha256=spA0qph4_Uul5FvzBHdM7gCN9zlQ7Ifh-Az_byXIdt0,4530 -cryptography-47.0.0.dist-info/RECORD,, -cryptography-47.0.0.dist-info/WHEEL,sha256=-iKa_lvJNlSbyUjxkTBN8abWl7pGEY8A5QN_6ltdYAo,108 -cryptography-47.0.0.dist-info/licenses/LICENSE,sha256=Pgx8CRqUi4JTO6mP18u0BDLW8amsv4X1ki0vmak65rs,197 -cryptography-47.0.0.dist-info/licenses/LICENSE.APACHE,sha256=qsc7MUj20dcRHbyjIJn2jSbGRMaBOuHk8F9leaomY_4,11360 -cryptography-47.0.0.dist-info/licenses/LICENSE.BSD,sha256=YCxMdILeZHndLpeTzaJ15eY9dz2s0eymiSMqtwCPtPs,1532 -cryptography-47.0.0.dist-info/sboms/cryptography-rust.cyclonedx.json,sha256=P-zdudRpzBj1Ak-ep5-X52pbPOQWOxruSVFSH9iYY3M,45695 -cryptography-47.0.0.dist-info/sboms/sbom.json,sha256=8Y1rx6HzDpNelLFfUd5Z4DYa614U0MQBphDf3RH7E2w,1206 -cryptography/__about__.py,sha256=YLscbQ4_C8LtY_R1ZAKbYckhIxyZ9kOSbGPsThdJwrY,445 -cryptography/__init__.py,sha256=7lfTn2kedUixiEdXgtdkhoMRgqJGBrETA1Rihx87LO0,762 -cryptography/__pycache__/__about__.cpython-39.pyc,, -cryptography/__pycache__/__init__.cpython-39.pyc,, -cryptography/__pycache__/exceptions.cpython-39.pyc,, -cryptography/__pycache__/fernet.cpython-39.pyc,, -cryptography/__pycache__/utils.cpython-39.pyc,, -cryptography/exceptions.py,sha256=835EWILc2fwxw-gyFMriciC2SqhViETB10LBSytnDIc,1087 -cryptography/fernet.py,sha256=3Cvxkh0KJSbX8HbnCHu4wfCW7U0GgfUA3v_qQ8a8iWc,6963 -cryptography/hazmat/__init__.py,sha256=5IwrLWrVp0AjEr_4FdWG_V057NSJGY_W4egNNsuct0g,455 -cryptography/hazmat/__pycache__/__init__.cpython-39.pyc,, -cryptography/hazmat/__pycache__/_oid.cpython-39.pyc,, -cryptography/hazmat/_oid.py,sha256=p8ThjwJB56Ci_rAIrjyJ1f8VjgD6e39es2dh8JIUBOw,17240 -cryptography/hazmat/asn1/__init__.py,sha256=AZVmLA09Q9-bq27G8fYr3dof-iRkh5KSX3zEPmNb-9w,744 -cryptography/hazmat/asn1/__pycache__/__init__.cpython-39.pyc,, -cryptography/hazmat/asn1/__pycache__/asn1.cpython-39.pyc,, -cryptography/hazmat/asn1/asn1.py,sha256=ldCLBAAEvzWNnTGdSFBh1STfIsl33VdArH421FqyI8o,15465 -cryptography/hazmat/backends/__init__.py,sha256=O5jvKFQdZnXhKeqJ-HtulaEL9Ni7mr1mDzZY5kHlYhI,361 -cryptography/hazmat/backends/__pycache__/__init__.cpython-39.pyc,, -cryptography/hazmat/backends/openssl/__init__.py,sha256=p3jmJfnCag9iE5sdMrN6VvVEu55u46xaS_IjoI0SrmA,305 -cryptography/hazmat/backends/openssl/__pycache__/__init__.cpython-39.pyc,, -cryptography/hazmat/backends/openssl/__pycache__/backend.cpython-39.pyc,, -cryptography/hazmat/backends/openssl/backend.py,sha256=MI08Kthlz5uJlf1x045VdNEw1zYdGRONqFqloYAbLQY,10392 -cryptography/hazmat/bindings/__init__.py,sha256=s9oKCQ2ycFdXoERdS1imafueSkBsL9kvbyfghaauZ9Y,180 -cryptography/hazmat/bindings/__pycache__/__init__.cpython-39.pyc,, -cryptography/hazmat/bindings/_rust.abi3.so,sha256=PF3QtAmwvdZ8uXkABobz6uqn5wAFMctet1Dm3lyLDZY,13621264 -cryptography/hazmat/bindings/_rust/__init__.pyi,sha256=uUnnvOq_uameYnBNpmsv3SRAVO0WQGpjI58aR1lL4Kw,2285 -cryptography/hazmat/bindings/_rust/_openssl.pyi,sha256=T_5TpYO8bghIPjAQ3BtAABqw-CcYskHp92wm5PNY6dc,228 -cryptography/hazmat/bindings/_rust/asn1.pyi,sha256=BrGjC8J6nwuS-r3EVcdXJB8ndotfY9mbQYOfpbPG0HA,354 -cryptography/hazmat/bindings/_rust/declarative_asn1.pyi,sha256=iSeRyyd3hN0VIUKg_p424AzQ-b7hW1b_53Yx50yniYY,3661 -cryptography/hazmat/bindings/_rust/exceptions.pyi,sha256=exXr2xw_0pB1kk93cYbM3MohbzoUkjOms1ZMUi0uQZE,640 -cryptography/hazmat/bindings/_rust/ocsp.pyi,sha256=VPVWuKHI9EMs09ZLRYAGvR0Iz0mCMmEzXAkgJHovpoM,4020 -cryptography/hazmat/bindings/_rust/openssl/__init__.pyi,sha256=JDCef29vXnrEMvF13JH9z1-W9ahiTZQAk5xhu_KH6po,1550 -cryptography/hazmat/bindings/_rust/openssl/aead.pyi,sha256=7d--xdc0vuzRe4S2uuQaGm-9GGKv4NcSLQcLyWcaD6s,4582 -cryptography/hazmat/bindings/_rust/openssl/ciphers.pyi,sha256=LhPzHWSXJq4grAJXn6zSvSSdV-aYIIscHDwIPlJGGPs,1315 -cryptography/hazmat/bindings/_rust/openssl/cmac.pyi,sha256=nPH0X57RYpsAkRowVpjQiHE566ThUTx7YXrsadmrmHk,564 -cryptography/hazmat/bindings/_rust/openssl/dh.pyi,sha256=Z3TC-G04-THtSdAOPLM1h2G7ml5bda1ElZUcn5wpuhk,1564 -cryptography/hazmat/bindings/_rust/openssl/dsa.pyi,sha256=qBtkgj2albt2qFcnZ9UDrhzoNhCVO7HTby5VSf1EXMI,1299 -cryptography/hazmat/bindings/_rust/openssl/ec.pyi,sha256=zJy0pRa5n-_p2dm45PxECB_-B6SVZyNKfjxFDpPqT38,1691 -cryptography/hazmat/bindings/_rust/openssl/ed25519.pyi,sha256=VXfXd5G6hUivg399R1DYdmW3eTb0EebzDTqjRC2gaRw,532 -cryptography/hazmat/bindings/_rust/openssl/ed448.pyi,sha256=Yx49lqdnjsD7bxiDV1kcaMrDktug5evi5a6zerMiy2s,514 -cryptography/hazmat/bindings/_rust/openssl/hashes.pyi,sha256=bFe3T13UeyRInUJMD-R5ArGTGLqWDiWo2Lv2KGzUbf4,1076 -cryptography/hazmat/bindings/_rust/openssl/hmac.pyi,sha256=BXZn7NDjL3JAbYW0SQ8pg1iyC5DbQXVhUAiwsi8DFR8,702 -cryptography/hazmat/bindings/_rust/openssl/hpke.pyi,sha256=wrz8c12gBNBAItz9jorr_W4s8rFYDE1Yel1z2I-Wd2s,2877 -cryptography/hazmat/bindings/_rust/openssl/kdf.pyi,sha256=HiiLdEB9nqMsTvMwiFppQpfPz6fHUz9_gpjEB_XAOXA,6619 -cryptography/hazmat/bindings/_rust/openssl/keys.pyi,sha256=teIt8M6ZEMJrn4s3W0UnW0DZ-30Jd68WnSsKKG124l0,912 -cryptography/hazmat/bindings/_rust/openssl/mldsa.pyi,sha256=HChNsjW0C_vO9OVD4FhEZrXO3_FiEq2ZTF59hlfcEdM,1073 -cryptography/hazmat/bindings/_rust/openssl/mlkem.pyi,sha256=byoeus4-lIOlWlEiRQdCc00qCkXpOB5peBY6yo9ik8s,835 -cryptography/hazmat/bindings/_rust/openssl/poly1305.pyi,sha256=_SW9NtQ5FDlAbdclFtWpT4lGmxKIKHpN-4j8J2BzYfQ,585 -cryptography/hazmat/bindings/_rust/openssl/rsa.pyi,sha256=2OQCNSXkxgc-3uw1xiCCloIQTV6p9_kK79Yu0rhZgPc,1364 -cryptography/hazmat/bindings/_rust/openssl/x25519.pyi,sha256=ewn4GpQyb7zPwE-ni7GtyQgMC0A1mLuqYsSyqv6nI_s,523 -cryptography/hazmat/bindings/_rust/openssl/x448.pyi,sha256=juTZTmli8jO_5Vcufg-vHvx_tCyezmSLIh_9PU3TczI,505 -cryptography/hazmat/bindings/_rust/pkcs12.pyi,sha256=vEEd5wDiZvb8ZGFaziLCaWLzAwoG_tvPUxLQw5_uOl8,1605 -cryptography/hazmat/bindings/_rust/pkcs7.pyi,sha256=txGBJijqZshEcqra6byPNbnisIdlxzOSIHP2hl9arPs,1601 -cryptography/hazmat/bindings/_rust/test_support.pyi,sha256=PPhld-WkO743iXFPebeG0LtgK0aTzGdjcIsay1Gm5GE,757 -cryptography/hazmat/bindings/_rust/x509.pyi,sha256=rmt4enscdvDQ7lBEHb2cASwN0d3TP3ymEVZcEJ-Rf3A,10152 -cryptography/hazmat/bindings/openssl/__init__.py,sha256=s9oKCQ2ycFdXoERdS1imafueSkBsL9kvbyfghaauZ9Y,180 -cryptography/hazmat/bindings/openssl/__pycache__/__init__.cpython-39.pyc,, -cryptography/hazmat/bindings/openssl/__pycache__/_conditional.cpython-39.pyc,, -cryptography/hazmat/bindings/openssl/__pycache__/binding.cpython-39.pyc,, -cryptography/hazmat/bindings/openssl/_conditional.py,sha256=vfzi-xHdStAcJQjLqqOlSos94L8D_tqFtBe7Ovw-KtY,5611 -cryptography/hazmat/bindings/openssl/binding.py,sha256=GnoZLYvCzXbKf4KldUXec-oz-hdVSa_sinZnqXgdS2s,4096 -cryptography/hazmat/decrepit/__init__.py,sha256=wHCbWfaefa-fk6THSw9th9fJUsStJo7245wfFBqmduA,216 -cryptography/hazmat/decrepit/__pycache__/__init__.cpython-39.pyc,, -cryptography/hazmat/decrepit/ciphers/__init__.py,sha256=wHCbWfaefa-fk6THSw9th9fJUsStJo7245wfFBqmduA,216 -cryptography/hazmat/decrepit/ciphers/__pycache__/__init__.cpython-39.pyc,, -cryptography/hazmat/decrepit/ciphers/__pycache__/algorithms.cpython-39.pyc,, -cryptography/hazmat/decrepit/ciphers/__pycache__/modes.cpython-39.pyc,, -cryptography/hazmat/decrepit/ciphers/algorithms.py,sha256=yqHt7k5OzF_KuvO8M9vTlNLtG7EotbvShyYKIaUJqhg,3566 -cryptography/hazmat/decrepit/ciphers/modes.py,sha256=Oq_PEwCke5OLczOfr_vzAOJ6wPx-rlsvHAXPBuh5b9o,1649 -cryptography/hazmat/primitives/__init__.py,sha256=s9oKCQ2ycFdXoERdS1imafueSkBsL9kvbyfghaauZ9Y,180 -cryptography/hazmat/primitives/__pycache__/__init__.cpython-39.pyc,, -cryptography/hazmat/primitives/__pycache__/_asymmetric.cpython-39.pyc,, -cryptography/hazmat/primitives/__pycache__/_cipheralgorithm.cpython-39.pyc,, -cryptography/hazmat/primitives/__pycache__/_modes.cpython-39.pyc,, -cryptography/hazmat/primitives/__pycache__/_serialization.cpython-39.pyc,, -cryptography/hazmat/primitives/__pycache__/cmac.cpython-39.pyc,, -cryptography/hazmat/primitives/__pycache__/constant_time.cpython-39.pyc,, -cryptography/hazmat/primitives/__pycache__/hashes.cpython-39.pyc,, -cryptography/hazmat/primitives/__pycache__/hmac.cpython-39.pyc,, -cryptography/hazmat/primitives/__pycache__/hpke.cpython-39.pyc,, -cryptography/hazmat/primitives/__pycache__/keywrap.cpython-39.pyc,, -cryptography/hazmat/primitives/__pycache__/padding.cpython-39.pyc,, -cryptography/hazmat/primitives/__pycache__/poly1305.cpython-39.pyc,, -cryptography/hazmat/primitives/_asymmetric.py,sha256=RhgcouUB6HTiFDBrR1LxqkMjpUxIiNvQ1r_zJjRG6qQ,532 -cryptography/hazmat/primitives/_cipheralgorithm.py,sha256=Eh3i7lwedHfi0eLSsH93PZxQKzY9I6lkK67vL4V5tOc,1522 -cryptography/hazmat/primitives/_modes.py,sha256=_EiAOD8Jb6WpFXluwkcUT3ECz_TH8xjGvbQlGkNm59Q,3075 -cryptography/hazmat/primitives/_serialization.py,sha256=hi0xJblBAZ8pmZx2lWa-lruphxvvvG3g9DNK0G8Odfs,4440 -cryptography/hazmat/primitives/asymmetric/__init__.py,sha256=s9oKCQ2ycFdXoERdS1imafueSkBsL9kvbyfghaauZ9Y,180 -cryptography/hazmat/primitives/asymmetric/__pycache__/__init__.cpython-39.pyc,, -cryptography/hazmat/primitives/asymmetric/__pycache__/dh.cpython-39.pyc,, -cryptography/hazmat/primitives/asymmetric/__pycache__/dsa.cpython-39.pyc,, -cryptography/hazmat/primitives/asymmetric/__pycache__/ec.cpython-39.pyc,, -cryptography/hazmat/primitives/asymmetric/__pycache__/ed25519.cpython-39.pyc,, -cryptography/hazmat/primitives/asymmetric/__pycache__/ed448.cpython-39.pyc,, -cryptography/hazmat/primitives/asymmetric/__pycache__/mldsa.cpython-39.pyc,, -cryptography/hazmat/primitives/asymmetric/__pycache__/mlkem.cpython-39.pyc,, -cryptography/hazmat/primitives/asymmetric/__pycache__/padding.cpython-39.pyc,, -cryptography/hazmat/primitives/asymmetric/__pycache__/rsa.cpython-39.pyc,, -cryptography/hazmat/primitives/asymmetric/__pycache__/types.cpython-39.pyc,, -cryptography/hazmat/primitives/asymmetric/__pycache__/utils.cpython-39.pyc,, -cryptography/hazmat/primitives/asymmetric/__pycache__/x25519.cpython-39.pyc,, -cryptography/hazmat/primitives/asymmetric/__pycache__/x448.cpython-39.pyc,, -cryptography/hazmat/primitives/asymmetric/dh.py,sha256=klvHVaxAFkUyaWXLytqYjBTh81Zx1ByCJNZVRcSDYX8,3912 -cryptography/hazmat/primitives/asymmetric/dsa.py,sha256=kQzTViqAI9PiELNOBco_n6MfP3N9ehIPkSduOpupt0M,4482 -cryptography/hazmat/primitives/asymmetric/ec.py,sha256=LklVCLLxbbQzqiE6HRaYTRauLMphYUw3tE6c8oBIxYQ,10183 -cryptography/hazmat/primitives/asymmetric/ed25519.py,sha256=mbffLvs-3PgCDeg1rQXVXh7GLntlVL4ATjkIEc4pt5M,2998 -cryptography/hazmat/primitives/asymmetric/ed448.py,sha256=n0dK6y-VLxuw-zvrDxuPT4598hymgX-1Ry_jq9aUQhE,4002 -cryptography/hazmat/primitives/asymmetric/mldsa.py,sha256=49DPIhoHEyfGVwL6DRc3WlJ20Rinq-ldtjsp91NpyMM,12226 -cryptography/hazmat/primitives/asymmetric/mlkem.py,sha256=wvVkeFT-4of-VcUAER2-zI_5hXT6rwTJPMCQ8gF9GTA,7901 -cryptography/hazmat/primitives/asymmetric/padding.py,sha256=vQ6l6gOg9HqcbOsvHrSiJRVLdEj9L4m4HkRGYziTyFA,2854 -cryptography/hazmat/primitives/asymmetric/rsa.py,sha256=GfFpxwFoYfMhIPEd_1V4y7awu0HTMEozZ9xWfYPtiPc,8640 -cryptography/hazmat/primitives/asymmetric/types.py,sha256=q3glpax4EHgNpkRSEXlhK43a07F3Dsk-rQ3bbjL9ZnM,3309 -cryptography/hazmat/primitives/asymmetric/utils.py,sha256=Qs8Re9GFPjW_tNp_73IeJEjPCf0slOIsWOxo6qymT6k,821 -cryptography/hazmat/primitives/asymmetric/x25519.py,sha256=lQcgUk-Piubj8ynFNWQeYme3tYZMgHQqkRKkIDOHLzo,3888 -cryptography/hazmat/primitives/asymmetric/x448.py,sha256=b37ig7k7poG6SJDry42j-ElCj5q4eQ0X5CFmN0Sn8z8,3913 -cryptography/hazmat/primitives/ciphers/__init__.py,sha256=eyEXmjk6_CZXaOPYDr7vAYGXr29QvzgWL2-4CSolLFs,680 -cryptography/hazmat/primitives/ciphers/__pycache__/__init__.cpython-39.pyc,, -cryptography/hazmat/primitives/ciphers/__pycache__/aead.cpython-39.pyc,, -cryptography/hazmat/primitives/ciphers/__pycache__/algorithms.cpython-39.pyc,, -cryptography/hazmat/primitives/ciphers/__pycache__/base.cpython-39.pyc,, -cryptography/hazmat/primitives/ciphers/__pycache__/modes.cpython-39.pyc,, -cryptography/hazmat/primitives/ciphers/aead.py,sha256=Fzlyx7w8KYQakzDp1zWgJnIr62zgZrgVh1u2h4exB54,634 -cryptography/hazmat/primitives/ciphers/algorithms.py,sha256=IGfCycYJOh1TvoI34rfw8KfJ_xmt1p_DpBht2Fghceo,3496 -cryptography/hazmat/primitives/ciphers/base.py,sha256=aBC7HHBBoixebmparVr0UlODs3VD0A7B6oz_AaRjDv8,4253 -cryptography/hazmat/primitives/ciphers/modes.py,sha256=pNI0cSLCLxr7lz7ApfUpVpFH5q_bzOpKW-QggmgQB74,6007 -cryptography/hazmat/primitives/cmac.py,sha256=sz_s6H_cYnOvx-VNWdIKhRhe3Ymp8z8J0D3CBqOX3gg,338 -cryptography/hazmat/primitives/constant_time.py,sha256=xdunWT0nf8OvKdcqUhhlFKayGp4_PgVJRU2W1wLSr_A,422 -cryptography/hazmat/primitives/hashes.py,sha256=M8BrlKB3U6DEtHvWTV5VRjpteHv1kS3Zxm_Bsk04cr8,5184 -cryptography/hazmat/primitives/hmac.py,sha256=RpB3z9z5skirCQrm7zQbtnp9pLMnAjrlTUvKqF5aDDc,423 -cryptography/hazmat/primitives/hpke.py,sha256=RsHissC5l-dTPn1p2JbcrIrAnDBrLqM5ugBFSGpmKu4,865 -cryptography/hazmat/primitives/kdf/__init__.py,sha256=v3yiYBGU272EojNXbwfYZdbbfI9cVOCCG3nXhTDda3k,1037 -cryptography/hazmat/primitives/kdf/__pycache__/__init__.cpython-39.pyc,, -cryptography/hazmat/primitives/kdf/__pycache__/argon2.cpython-39.pyc,, -cryptography/hazmat/primitives/kdf/__pycache__/concatkdf.cpython-39.pyc,, -cryptography/hazmat/primitives/kdf/__pycache__/hkdf.cpython-39.pyc,, -cryptography/hazmat/primitives/kdf/__pycache__/kbkdf.cpython-39.pyc,, -cryptography/hazmat/primitives/kdf/__pycache__/pbkdf2.cpython-39.pyc,, -cryptography/hazmat/primitives/kdf/__pycache__/scrypt.cpython-39.pyc,, -cryptography/hazmat/primitives/kdf/__pycache__/x963kdf.cpython-39.pyc,, -cryptography/hazmat/primitives/kdf/argon2.py,sha256=ZJx-enUlAA4o7b46C1wlzG_XAQQW0wIkFgUKkrM_wA8,632 -cryptography/hazmat/primitives/kdf/concatkdf.py,sha256=BFnOKS72txKF0yQvASr0Na7uhzvLHpUCckK5iNAC_aQ,591 -cryptography/hazmat/primitives/kdf/hkdf.py,sha256=M0lAEfRoc4kpp4-nwDj9yB-vNZukIOYEQrUlWsBNn9o,543 -cryptography/hazmat/primitives/kdf/kbkdf.py,sha256=C3w99vjFqhqzAxzFOH4zzvVoHkb5AC6Lz6AEQGV7d_g,737 -cryptography/hazmat/primitives/kdf/pbkdf2.py,sha256=Xchkk99s-Mk6b6KSCouqdk8FVyiNVOSFIenmnW3tLgQ,468 -cryptography/hazmat/primitives/kdf/scrypt.py,sha256=XyWUdUUmhuI9V6TqAPOvujCSMGv1XQdg0a21IWCmO-U,590 -cryptography/hazmat/primitives/kdf/x963kdf.py,sha256=QKjhRehuTsAstL384bKfvjuv1yfdamAHVhsBRWen2Vw,456 -cryptography/hazmat/primitives/keywrap.py,sha256=UI-0UESQxBXTKU1HrrRoUwDiFsrWif81qyXlV1e7kyY,5776 -cryptography/hazmat/primitives/padding.py,sha256=QT-U-NvV2eQGO1wVPbDiNGNSc9keRDS-ig5cQOrLz0E,1865 -cryptography/hazmat/primitives/poly1305.py,sha256=P5EPQV-RB_FJPahpg01u0Ts4S_PnAmsroxIGXbGeRRo,355 -cryptography/hazmat/primitives/serialization/__init__.py,sha256=Q7uTgDlt7n3WfsMT6jYwutC6DIg_7SEeoAm1GHZ5B5E,1705 -cryptography/hazmat/primitives/serialization/__pycache__/__init__.cpython-39.pyc,, -cryptography/hazmat/primitives/serialization/__pycache__/base.cpython-39.pyc,, -cryptography/hazmat/primitives/serialization/__pycache__/pkcs12.cpython-39.pyc,, -cryptography/hazmat/primitives/serialization/__pycache__/pkcs7.cpython-39.pyc,, -cryptography/hazmat/primitives/serialization/__pycache__/ssh.cpython-39.pyc,, -cryptography/hazmat/primitives/serialization/base.py,sha256=ikq5MJIwp_oUnjiaBco_PmQwOTYuGi-XkYUYHKy8Vo0,615 -cryptography/hazmat/primitives/serialization/pkcs12.py,sha256=mS9cFNG4afzvseoc5e1MWoY2VskfL8N8Y_OFjl67luY,5104 -cryptography/hazmat/primitives/serialization/pkcs7.py,sha256=wJoAz3yW98E2L2SMWugrkdqIFUVWWltNMRbyk0bylpM,14012 -cryptography/hazmat/primitives/serialization/ssh.py,sha256=HV6ZqIjqNNaNUL6M4gQyNJJtZ75EsiSZs6yxddqBrWI,53789 -cryptography/hazmat/primitives/twofactor/__init__.py,sha256=tmMZGB-g4IU1r7lIFqASU019zr0uPp_wEBYcwdDCKCA,258 -cryptography/hazmat/primitives/twofactor/__pycache__/__init__.cpython-39.pyc,, -cryptography/hazmat/primitives/twofactor/__pycache__/hotp.cpython-39.pyc,, -cryptography/hazmat/primitives/twofactor/__pycache__/totp.cpython-39.pyc,, -cryptography/hazmat/primitives/twofactor/hotp.py,sha256=ivZo5BrcCGWLsqql4nZV0XXCjyGPi_iHfDFltGlOJwk,3256 -cryptography/hazmat/primitives/twofactor/totp.py,sha256=m5LPpRL00kp4zY8gTjr55Hfz9aMlPS53kHmVkSQCmdY,1652 -cryptography/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 -cryptography/utils.py,sha256=arFzed6V2Llsmt8Uog1ywpxye6ntYd12Mq6WTU_38sQ,4353 -cryptography/x509/__init__.py,sha256=zciyadRgnCp2DNPPm6ujEKd6EX-8_zOnwtCjJbZBatg,8273 -cryptography/x509/__pycache__/__init__.cpython-39.pyc,, -cryptography/x509/__pycache__/base.cpython-39.pyc,, -cryptography/x509/__pycache__/certificate_transparency.cpython-39.pyc,, -cryptography/x509/__pycache__/extensions.cpython-39.pyc,, -cryptography/x509/__pycache__/general_name.cpython-39.pyc,, -cryptography/x509/__pycache__/name.cpython-39.pyc,, -cryptography/x509/__pycache__/ocsp.cpython-39.pyc,, -cryptography/x509/__pycache__/oid.cpython-39.pyc,, -cryptography/x509/__pycache__/verification.cpython-39.pyc,, -cryptography/x509/base.py,sha256=8322G4opJ1a2juXU14Qi2y-G1V-cQHaudo7gAFbTPlM,25998 -cryptography/x509/certificate_transparency.py,sha256=JqoOIDhlwInrYMFW6IFn77WJ0viF-PB_rlZV3vs9MYc,797 -cryptography/x509/extensions.py,sha256=0AUgutLe26SLg1KaxSeo0fG7fUBAyK2tEgJl9c_AQRM,77968 -cryptography/x509/general_name.py,sha256=sP_rV11Qlpsk4x3XXGJY_Mv0Q_s9dtjeLckHsjpLQoQ,7836 -cryptography/x509/name.py,sha256=WyW7n9vkcLhz43Im2klKF1-wXALdj9wr6WOIJRxyszc,15363 -cryptography/x509/ocsp.py,sha256=Yey6NdFV1MPjop24Mj_VenjEpg3kUaMopSWOK0AbeBs,12699 -cryptography/x509/oid.py,sha256=BUzgXXGVWilkBkdKPTm9R4qElE9gAGHgdYPMZAp7PJo,931 -cryptography/x509/verification.py,sha256=gR2C2c-XZQtblZhT5T5vjSKOtCb74ef2alPVmEcwFlM,958 diff --git a/venv/lib/python3.9/site-packages/cryptography-47.0.0.dist-info/WHEEL b/venv/lib/python3.9/site-packages/cryptography-47.0.0.dist-info/WHEEL deleted file mode 100644 index 7c76b98..0000000 --- a/venv/lib/python3.9/site-packages/cryptography-47.0.0.dist-info/WHEEL +++ /dev/null @@ -1,5 +0,0 @@ -Wheel-Version: 1.0 -Generator: maturin (1.13.1) -Root-Is-Purelib: false -Tag: cp38-abi3-manylinux_2_28_x86_64 - diff --git a/venv/lib/python3.9/site-packages/cryptography-47.0.0.dist-info/licenses/LICENSE b/venv/lib/python3.9/site-packages/cryptography-47.0.0.dist-info/licenses/LICENSE deleted file mode 100644 index b11f379..0000000 --- a/venv/lib/python3.9/site-packages/cryptography-47.0.0.dist-info/licenses/LICENSE +++ /dev/null @@ -1,3 +0,0 @@ -This software is made available under the terms of *either* of the licenses -found in LICENSE.APACHE or LICENSE.BSD. Contributions to cryptography are made -under the terms of *both* these licenses. diff --git a/venv/lib/python3.9/site-packages/cryptography-47.0.0.dist-info/licenses/LICENSE.APACHE b/venv/lib/python3.9/site-packages/cryptography-47.0.0.dist-info/licenses/LICENSE.APACHE deleted file mode 100644 index 62589ed..0000000 --- a/venv/lib/python3.9/site-packages/cryptography-47.0.0.dist-info/licenses/LICENSE.APACHE +++ /dev/null @@ -1,202 +0,0 @@ - - Apache License - Version 2.0, January 2004 - https://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - https://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. diff --git a/venv/lib/python3.9/site-packages/cryptography-47.0.0.dist-info/licenses/LICENSE.BSD b/venv/lib/python3.9/site-packages/cryptography-47.0.0.dist-info/licenses/LICENSE.BSD deleted file mode 100644 index ec1a29d..0000000 --- a/venv/lib/python3.9/site-packages/cryptography-47.0.0.dist-info/licenses/LICENSE.BSD +++ /dev/null @@ -1,27 +0,0 @@ -Copyright (c) Individual contributors. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - - 3. Neither the name of PyCA Cryptography nor the names of its contributors - may be used to endorse or promote products derived from this software - without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR -ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON -ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/venv/lib/python3.9/site-packages/cryptography-47.0.0.dist-info/sboms/cryptography-rust.cyclonedx.json b/venv/lib/python3.9/site-packages/cryptography-47.0.0.dist-info/sboms/cryptography-rust.cyclonedx.json deleted file mode 100644 index 6a2f415..0000000 --- a/venv/lib/python3.9/site-packages/cryptography-47.0.0.dist-info/sboms/cryptography-rust.cyclonedx.json +++ /dev/null @@ -1,1363 +0,0 @@ -{ - "bomFormat": "CycloneDX", - "specVersion": "1.5", - "version": 1, - "serialNumber": "urn:uuid:98211b3c-5581-4c78-a325-55202a96d30c", - "metadata": { - "timestamp": "2026-04-24T19:48:10.692455991Z", - "tools": [ - { - "vendor": "CycloneDX", - "name": "cargo-cyclonedx", - "version": "0.5.9" - } - ], - "authors": [ - { - "name": "The cryptography developers", - "email": "cryptography-dev@python.org" - } - ], - "component": { - "type": "library", - "bom-ref": "path+file:///__w/cryptography/cryptography/tmpwheelhouse/.tmpyLMvqZ/cryptography-47.0.0/src/rust#cryptography-rust@0.1.0", - "author": "The cryptography developers ", - "name": "cryptography-rust", - "version": "0.1.0", - "scope": "required", - "licenses": [ - { - "expression": "Apache-2.0 OR BSD-3-Clause" - } - ], - "purl": "pkg:cargo/cryptography-rust@0.1.0?download_url=file://.", - "components": [ - { - "type": "library", - "bom-ref": "path+file:///__w/cryptography/cryptography/tmpwheelhouse/.tmpyLMvqZ/cryptography-47.0.0/src/rust#cryptography-rust@0.1.0 bin-target-0", - "name": "cryptography_rust", - "version": "0.1.0", - "purl": "pkg:cargo/cryptography-rust@0.1.0?download_url=file://.#src/lib.rs" - } - ] - }, - "properties": [ - { - "name": "cdx:rustc:sbom:target:all_targets", - "value": "true" - } - ] - }, - "components": [ - { - "type": "library", - "bom-ref": "path+file:///__w/cryptography/cryptography/tmpwheelhouse/.tmpyLMvqZ/cryptography-47.0.0/src/rust/cryptography-cffi#0.1.0", - "author": "The cryptography developers ", - "name": "cryptography-cffi", - "version": "0.1.0", - "scope": "required", - "licenses": [ - { - "expression": "Apache-2.0 OR BSD-3-Clause" - } - ], - "purl": "pkg:cargo/cryptography-cffi@0.1.0?download_url=file://cryptography-cffi" - }, - { - "type": "library", - "bom-ref": "path+file:///__w/cryptography/cryptography/tmpwheelhouse/.tmpyLMvqZ/cryptography-47.0.0/src/rust/cryptography-crypto#0.1.0", - "author": "The cryptography developers ", - "name": "cryptography-crypto", - "version": "0.1.0", - "scope": "required", - "licenses": [ - { - "expression": "Apache-2.0 OR BSD-3-Clause" - } - ], - "purl": "pkg:cargo/cryptography-crypto@0.1.0?download_url=file://cryptography-crypto" - }, - { - "type": "library", - "bom-ref": "path+file:///__w/cryptography/cryptography/tmpwheelhouse/.tmpyLMvqZ/cryptography-47.0.0/src/rust/cryptography-keepalive#0.1.0", - "author": "The cryptography developers ", - "name": "cryptography-keepalive", - "version": "0.1.0", - "scope": "required", - "licenses": [ - { - "expression": "Apache-2.0 OR BSD-3-Clause" - } - ], - "purl": "pkg:cargo/cryptography-keepalive@0.1.0?download_url=file://cryptography-keepalive" - }, - { - "type": "library", - "bom-ref": "path+file:///__w/cryptography/cryptography/tmpwheelhouse/.tmpyLMvqZ/cryptography-47.0.0/src/rust/cryptography-key-parsing#0.1.0", - "author": "The cryptography developers ", - "name": "cryptography-key-parsing", - "version": "0.1.0", - "scope": "required", - "licenses": [ - { - "expression": "Apache-2.0 OR BSD-3-Clause" - } - ], - "purl": "pkg:cargo/cryptography-key-parsing@0.1.0?download_url=file://cryptography-key-parsing" - }, - { - "type": "library", - "bom-ref": "path+file:///__w/cryptography/cryptography/tmpwheelhouse/.tmpyLMvqZ/cryptography-47.0.0/src/rust/cryptography-openssl#0.1.0", - "author": "The cryptography developers ", - "name": "cryptography-openssl", - "version": "0.1.0", - "scope": "required", - "licenses": [ - { - "expression": "Apache-2.0 OR BSD-3-Clause" - } - ], - "purl": "pkg:cargo/cryptography-openssl@0.1.0?download_url=file://cryptography-openssl" - }, - { - "type": "library", - "bom-ref": "path+file:///__w/cryptography/cryptography/tmpwheelhouse/.tmpyLMvqZ/cryptography-47.0.0/src/rust/cryptography-x509#0.1.0", - "author": "The cryptography developers ", - "name": "cryptography-x509", - "version": "0.1.0", - "scope": "required", - "licenses": [ - { - "expression": "Apache-2.0 OR BSD-3-Clause" - } - ], - "purl": "pkg:cargo/cryptography-x509@0.1.0?download_url=file://cryptography-x509" - }, - { - "type": "library", - "bom-ref": "path+file:///__w/cryptography/cryptography/tmpwheelhouse/.tmpyLMvqZ/cryptography-47.0.0/src/rust/cryptography-x509-verification#0.1.0", - "author": "The cryptography developers ", - "name": "cryptography-x509-verification", - "version": "0.1.0", - "scope": "required", - "licenses": [ - { - "expression": "Apache-2.0 OR BSD-3-Clause" - } - ], - "purl": "pkg:cargo/cryptography-x509-verification@0.1.0?download_url=file://cryptography-x509-verification" - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#asn1@0.24.1", - "author": "Alex Gaynor ", - "name": "asn1", - "version": "0.24.1", - "description": "ASN.1 (DER) parser and writer for Rust.", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "c9795210620c0cb3f9a7ce4f882808c38e1ef7b347c90591dceae0886e031fb1" - } - ], - "licenses": [ - { - "expression": "BSD-3-Clause" - } - ], - "purl": "pkg:cargo/asn1@0.24.1", - "externalReferences": [ - { - "type": "vcs", - "url": "https://github.com/alex/rust-asn1" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#asn1_derive@0.24.1", - "author": "Alex Gaynor ", - "name": "asn1_derive", - "version": "0.24.1", - "description": "#[derive] support for asn1", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "909e307f1cc32bb8bccbd98f446e6d1bf03fa30f7b53a4337da7181ad30fa11a" - } - ], - "licenses": [ - { - "expression": "BSD-3-Clause" - } - ], - "purl": "pkg:cargo/asn1_derive@0.24.1", - "externalReferences": [ - { - "type": "vcs", - "url": "https://github.com/alex/rust-asn1" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#base64@0.22.1", - "author": "Marshall Pierce ", - "name": "base64", - "version": "0.22.1", - "description": "encodes and decodes base64 as bytes or utf8", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" - } - ], - "licenses": [ - { - "expression": "MIT OR Apache-2.0" - } - ], - "purl": "pkg:cargo/base64@0.22.1", - "externalReferences": [ - { - "type": "documentation", - "url": "https://docs.rs/base64" - }, - { - "type": "vcs", - "url": "https://github.com/marshallpierce/rust-base64" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#bitflags@2.11.1", - "author": "The Rust Project Developers", - "name": "bitflags", - "version": "2.11.1", - "description": "A macro to generate structures which behave like bitflags. ", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "c4512299f36f043ab09a583e57bceb5a5aab7a73db1805848e8fef3c9e8c78b3" - } - ], - "licenses": [ - { - "expression": "MIT OR Apache-2.0" - } - ], - "purl": "pkg:cargo/bitflags@2.11.1", - "externalReferences": [ - { - "type": "documentation", - "url": "https://docs.rs/bitflags" - }, - { - "type": "website", - "url": "https://github.com/bitflags/bitflags" - }, - { - "type": "vcs", - "url": "https://github.com/bitflags/bitflags" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#cc@1.2.60", - "author": "Alex Crichton ", - "name": "cc", - "version": "1.2.60", - "description": "A build-time dependency for Cargo build scripts to assist in invoking the native C compiler to compile native C code into a static archive to be linked into Rust code. ", - "scope": "excluded", - "hashes": [ - { - "alg": "SHA-256", - "content": "43c5703da9466b66a946814e1adf53ea2c90f10063b86290cc9eb67ce3478a20" - } - ], - "licenses": [ - { - "expression": "MIT OR Apache-2.0" - } - ], - "purl": "pkg:cargo/cc@1.2.60", - "externalReferences": [ - { - "type": "documentation", - "url": "https://docs.rs/cc" - }, - { - "type": "website", - "url": "https://github.com/rust-lang/cc-rs" - }, - { - "type": "vcs", - "url": "https://github.com/rust-lang/cc-rs" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#cfg-if@1.0.4", - "author": "Alex Crichton ", - "name": "cfg-if", - "version": "1.0.4", - "description": "A macro to ergonomically define an item depending on a large number of #[cfg] parameters. Structured like an if-else chain, the first matching branch is the item that gets emitted. ", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" - } - ], - "licenses": [ - { - "expression": "MIT OR Apache-2.0" - } - ], - "purl": "pkg:cargo/cfg-if@1.0.4", - "externalReferences": [ - { - "type": "vcs", - "url": "https://github.com/rust-lang/cfg-if" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#find-msvc-tools@0.1.9", - "name": "find-msvc-tools", - "version": "0.1.9", - "description": "Find windows-specific tools, read MSVC versions from the registry and from COM interfaces", - "scope": "excluded", - "hashes": [ - { - "alg": "SHA-256", - "content": "5baebc0774151f905a1a2cc41989300b1e6fbb29aff0ceffa1064fdd3088d582" - } - ], - "licenses": [ - { - "expression": "MIT OR Apache-2.0" - } - ], - "purl": "pkg:cargo/find-msvc-tools@0.1.9", - "externalReferences": [ - { - "type": "documentation", - "url": "https://docs.rs/find-msvc-tools" - }, - { - "type": "vcs", - "url": "https://github.com/rust-lang/cc-rs" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#foreign-types-shared@0.1.1", - "author": "Steven Fackler ", - "name": "foreign-types-shared", - "version": "0.1.1", - "description": "An internal crate used by foreign-types", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" - } - ], - "licenses": [ - { - "expression": "MIT OR Apache-2.0" - } - ], - "purl": "pkg:cargo/foreign-types-shared@0.1.1", - "externalReferences": [ - { - "type": "vcs", - "url": "https://github.com/sfackler/foreign-types" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#foreign-types@0.3.2", - "author": "Steven Fackler ", - "name": "foreign-types", - "version": "0.3.2", - "description": "A framework for Rust wrappers over C APIs", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" - } - ], - "licenses": [ - { - "expression": "MIT OR Apache-2.0" - } - ], - "purl": "pkg:cargo/foreign-types@0.3.2", - "externalReferences": [ - { - "type": "vcs", - "url": "https://github.com/sfackler/foreign-types" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#heck@0.5.0", - "name": "heck", - "version": "0.5.0", - "description": "heck is a case conversion library.", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" - } - ], - "licenses": [ - { - "expression": "MIT OR Apache-2.0" - } - ], - "purl": "pkg:cargo/heck@0.5.0", - "externalReferences": [ - { - "type": "vcs", - "url": "https://github.com/withoutboats/heck" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#itoa@1.0.18", - "author": "David Tolnay ", - "name": "itoa", - "version": "1.0.18", - "description": "Fast integer primitive to string conversion", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" - } - ], - "licenses": [ - { - "expression": "MIT OR Apache-2.0" - } - ], - "purl": "pkg:cargo/itoa@1.0.18", - "externalReferences": [ - { - "type": "documentation", - "url": "https://docs.rs/itoa" - }, - { - "type": "vcs", - "url": "https://github.com/dtolnay/itoa" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#libc@0.2.186", - "author": "The Rust Project Developers", - "name": "libc", - "version": "0.2.186", - "description": "Raw FFI bindings to platform libraries like libc.", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "68ab91017fe16c622486840e4c83c9a37afeff978bd239b5293d61ece587de66" - } - ], - "licenses": [ - { - "expression": "MIT OR Apache-2.0" - } - ], - "purl": "pkg:cargo/libc@0.2.186", - "externalReferences": [ - { - "type": "vcs", - "url": "https://github.com/rust-lang/libc" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#once_cell@1.21.4", - "author": "Aleksey Kladov ", - "name": "once_cell", - "version": "1.21.4", - "description": "Single assignment cells and lazy values.", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50" - } - ], - "licenses": [ - { - "expression": "MIT OR Apache-2.0" - } - ], - "purl": "pkg:cargo/once_cell@1.21.4", - "externalReferences": [ - { - "type": "documentation", - "url": "https://docs.rs/once_cell" - }, - { - "type": "vcs", - "url": "https://github.com/matklad/once_cell" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#openssl-macros@0.1.1", - "name": "openssl-macros", - "version": "0.1.1", - "description": "Internal macros used by the openssl crate.", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" - } - ], - "licenses": [ - { - "expression": "MIT OR Apache-2.0" - } - ], - "purl": "pkg:cargo/openssl-macros@0.1.1" - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#openssl-sys@0.9.114", - "author": "Alex Crichton , Steven Fackler ", - "name": "openssl-sys", - "version": "0.9.114", - "description": "FFI bindings to OpenSSL", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "13ce1245cd07fcc4cfdb438f7507b0c7e4f3849a69fd84d52374c66d83741bb6" - } - ], - "licenses": [ - { - "expression": "MIT" - } - ], - "purl": "pkg:cargo/openssl-sys@0.9.114", - "externalReferences": [ - { - "type": "other", - "url": "openssl" - }, - { - "type": "vcs", - "url": "https://github.com/rust-openssl/rust-openssl" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#openssl@0.10.78", - "author": "Steven Fackler ", - "name": "openssl", - "version": "0.10.78", - "description": "OpenSSL bindings", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "f38c4372413cdaaf3cc79dd92d29d7d9f5ab09b51b10dded508fb90bb70b9222" - } - ], - "licenses": [ - { - "expression": "Apache-2.0" - } - ], - "purl": "pkg:cargo/openssl@0.10.78", - "externalReferences": [ - { - "type": "vcs", - "url": "https://github.com/rust-openssl/rust-openssl" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#pem@3.0.6", - "author": "Jonathan Creekmore ", - "name": "pem", - "version": "3.0.6", - "description": "Parse and encode PEM-encoded data.", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "1d30c53c26bc5b31a98cd02d20f25a7c8567146caf63ed593a9d87b2775291be" - } - ], - "licenses": [ - { - "expression": "MIT" - } - ], - "purl": "pkg:cargo/pem@3.0.6", - "externalReferences": [ - { - "type": "documentation", - "url": "https://docs.rs/pem/" - }, - { - "type": "website", - "url": "https://github.com/jcreekmore/pem-rs.git" - }, - { - "type": "vcs", - "url": "https://github.com/jcreekmore/pem-rs.git" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#pkg-config@0.3.33", - "author": "Alex Crichton ", - "name": "pkg-config", - "version": "0.3.33", - "description": "A library to run the pkg-config system tool at build time in order to be used in Cargo build scripts. ", - "scope": "excluded", - "hashes": [ - { - "alg": "SHA-256", - "content": "19f132c84eca552bf34cab8ec81f1c1dcc229b811638f9d283dceabe58c5569e" - } - ], - "licenses": [ - { - "expression": "MIT OR Apache-2.0" - } - ], - "purl": "pkg:cargo/pkg-config@0.3.33", - "externalReferences": [ - { - "type": "documentation", - "url": "https://docs.rs/pkg-config" - }, - { - "type": "vcs", - "url": "https://github.com/rust-lang/pkg-config-rs" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#portable-atomic@1.13.1", - "name": "portable-atomic", - "version": "1.13.1", - "description": "Portable atomic types including support for 128-bit atomics, atomic float, etc. ", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "c33a9471896f1c69cecef8d20cbe2f7accd12527ce60845ff44c153bb2a21b49" - } - ], - "licenses": [ - { - "expression": "Apache-2.0 OR MIT" - } - ], - "purl": "pkg:cargo/portable-atomic@1.13.1", - "externalReferences": [ - { - "type": "vcs", - "url": "https://github.com/taiki-e/portable-atomic" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#proc-macro2@1.0.106", - "author": "David Tolnay , Alex Crichton ", - "name": "proc-macro2", - "version": "1.0.106", - "description": "A substitute implementation of the compiler's `proc_macro` API to decouple token-based libraries from the procedural macro use case.", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934" - } - ], - "licenses": [ - { - "expression": "MIT OR Apache-2.0" - } - ], - "purl": "pkg:cargo/proc-macro2@1.0.106", - "externalReferences": [ - { - "type": "documentation", - "url": "https://docs.rs/proc-macro2" - }, - { - "type": "vcs", - "url": "https://github.com/dtolnay/proc-macro2" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#pyo3-build-config@0.28.3", - "author": "PyO3 Project and Contributors ", - "name": "pyo3-build-config", - "version": "0.28.3", - "description": "Build configuration for the PyO3 ecosystem", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "e368e7ddfdeb98c9bca7f8383be1648fd84ab466bf2bc015e94008db6d35611e" - } - ], - "licenses": [ - { - "expression": "MIT OR Apache-2.0" - } - ], - "purl": "pkg:cargo/pyo3-build-config@0.28.3", - "externalReferences": [ - { - "type": "website", - "url": "https://github.com/pyo3/pyo3" - }, - { - "type": "vcs", - "url": "https://github.com/pyo3/pyo3" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#pyo3-ffi@0.28.3", - "author": "PyO3 Project and Contributors ", - "name": "pyo3-ffi", - "version": "0.28.3", - "description": "Python-API bindings for the PyO3 ecosystem", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "7f29e10af80b1f7ccaf7f69eace800a03ecd13e883acfacc1e5d0988605f651e" - } - ], - "licenses": [ - { - "expression": "MIT OR Apache-2.0" - } - ], - "purl": "pkg:cargo/pyo3-ffi@0.28.3", - "externalReferences": [ - { - "type": "website", - "url": "https://github.com/pyo3/pyo3" - }, - { - "type": "other", - "url": "python" - }, - { - "type": "vcs", - "url": "https://github.com/pyo3/pyo3" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#pyo3-macros-backend@0.28.3", - "author": "PyO3 Project and Contributors ", - "name": "pyo3-macros-backend", - "version": "0.28.3", - "description": "Code generation for PyO3 package", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "c4cdc218d835738f81c2338f822078af45b4afdf8b2e33cbb5916f108b813acb" - } - ], - "licenses": [ - { - "expression": "MIT OR Apache-2.0" - } - ], - "purl": "pkg:cargo/pyo3-macros-backend@0.28.3", - "externalReferences": [ - { - "type": "website", - "url": "https://github.com/pyo3/pyo3" - }, - { - "type": "vcs", - "url": "https://github.com/pyo3/pyo3" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#pyo3-macros@0.28.3", - "author": "PyO3 Project and Contributors ", - "name": "pyo3-macros", - "version": "0.28.3", - "description": "Proc macros for PyO3 package", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "df6e520eff47c45997d2fc7dd8214b25dd1310918bbb2642156ef66a67f29813" - } - ], - "licenses": [ - { - "expression": "MIT OR Apache-2.0" - } - ], - "purl": "pkg:cargo/pyo3-macros@0.28.3", - "externalReferences": [ - { - "type": "website", - "url": "https://github.com/pyo3/pyo3" - }, - { - "type": "vcs", - "url": "https://github.com/pyo3/pyo3" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#pyo3@0.28.3", - "author": "PyO3 Project and Contributors ", - "name": "pyo3", - "version": "0.28.3", - "description": "Bindings to Python interpreter", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "91fd8e38a3b50ed1167fb981cd6fd60147e091784c427b8f7183a7ee32c31c12" - } - ], - "licenses": [ - { - "expression": "MIT OR Apache-2.0" - } - ], - "purl": "pkg:cargo/pyo3@0.28.3", - "externalReferences": [ - { - "type": "documentation", - "url": "https://docs.rs/crate/pyo3/" - }, - { - "type": "website", - "url": "https://github.com/pyo3/pyo3" - }, - { - "type": "vcs", - "url": "https://github.com/pyo3/pyo3" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#quote@1.0.45", - "author": "David Tolnay ", - "name": "quote", - "version": "1.0.45", - "description": "Quasi-quoting macro quote!(...)", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "41f2619966050689382d2b44f664f4bc593e129785a36d6ee376ddf37259b924" - } - ], - "licenses": [ - { - "expression": "MIT OR Apache-2.0" - } - ], - "purl": "pkg:cargo/quote@1.0.45", - "externalReferences": [ - { - "type": "documentation", - "url": "https://docs.rs/quote/" - }, - { - "type": "vcs", - "url": "https://github.com/dtolnay/quote" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#self_cell@1.2.2", - "author": "Lukas Bergdoll ", - "name": "self_cell", - "version": "1.2.2", - "description": "Safe-to-use proc-macro-free self-referential structs in stable Rust.", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "b12e76d157a900eb52e81bc6e9f3069344290341720e9178cde2407113ac8d89" - } - ], - "licenses": [ - { - "expression": "Apache-2.0 OR GPL-2.0-only" - } - ], - "purl": "pkg:cargo/self_cell@1.2.2", - "externalReferences": [ - { - "type": "documentation", - "url": "https://docs.rs/self_cell" - }, - { - "type": "vcs", - "url": "https://github.com/Voultapher/self_cell" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#shlex@1.3.0", - "author": "comex , Fenhl , Adrian Taylor , Alex Touchet , Daniel Parks , Garrett Berg ", - "name": "shlex", - "version": "1.3.0", - "description": "Split a string into shell words, like Python's shlex.", - "scope": "excluded", - "hashes": [ - { - "alg": "SHA-256", - "content": "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" - } - ], - "licenses": [ - { - "expression": "MIT OR Apache-2.0" - } - ], - "purl": "pkg:cargo/shlex@1.3.0", - "externalReferences": [ - { - "type": "vcs", - "url": "https://github.com/comex/rust-shlex" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#syn@2.0.117", - "author": "David Tolnay ", - "name": "syn", - "version": "2.0.117", - "description": "Parser for Rust source code", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "e665b8803e7b1d2a727f4023456bbbbe74da67099c585258af0ad9c5013b9b99" - } - ], - "licenses": [ - { - "expression": "MIT OR Apache-2.0" - } - ], - "purl": "pkg:cargo/syn@2.0.117", - "externalReferences": [ - { - "type": "documentation", - "url": "https://docs.rs/syn" - }, - { - "type": "vcs", - "url": "https://github.com/dtolnay/syn" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#target-lexicon@0.13.5", - "author": "Dan Gohman ", - "name": "target-lexicon", - "version": "0.13.5", - "description": "LLVM target triple types", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "adb6935a6f5c20170eeceb1a3835a49e12e19d792f6dd344ccc76a985ca5a6ca" - } - ], - "licenses": [ - { - "expression": "Apache-2.0 WITH LLVM-exception" - } - ], - "purl": "pkg:cargo/target-lexicon@0.13.5", - "externalReferences": [ - { - "type": "documentation", - "url": "https://docs.rs/target-lexicon/" - }, - { - "type": "vcs", - "url": "https://github.com/bytecodealliance/target-lexicon" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#unicode-ident@1.0.24", - "author": "David Tolnay ", - "name": "unicode-ident", - "version": "1.0.24", - "description": "Determine whether characters have the XID_Start or XID_Continue properties according to Unicode Standard Annex #31", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" - } - ], - "licenses": [ - { - "expression": "(MIT OR Apache-2.0) AND Unicode-3.0" - } - ], - "purl": "pkg:cargo/unicode-ident@1.0.24", - "externalReferences": [ - { - "type": "documentation", - "url": "https://docs.rs/unicode-ident" - }, - { - "type": "vcs", - "url": "https://github.com/dtolnay/unicode-ident" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#vcpkg@0.2.15", - "author": "Jim McGrath ", - "name": "vcpkg", - "version": "0.2.15", - "description": "A library to find native dependencies in a vcpkg tree at build time in order to be used in Cargo build scripts. ", - "scope": "excluded", - "hashes": [ - { - "alg": "SHA-256", - "content": "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" - } - ], - "licenses": [ - { - "expression": "MIT OR Apache-2.0" - } - ], - "purl": "pkg:cargo/vcpkg@0.2.15", - "externalReferences": [ - { - "type": "documentation", - "url": "https://docs.rs/vcpkg" - }, - { - "type": "vcs", - "url": "https://github.com/mcgoo/vcpkg-rs" - } - ] - } - ], - "dependencies": [ - { - "ref": "path+file:///__w/cryptography/cryptography/tmpwheelhouse/.tmpyLMvqZ/cryptography-47.0.0/src/rust#cryptography-rust@0.1.0", - "dependsOn": [ - "registry+https://github.com/rust-lang/crates.io-index#asn1@0.24.1", - "registry+https://github.com/rust-lang/crates.io-index#base64@0.22.1", - "registry+https://github.com/rust-lang/crates.io-index#cfg-if@1.0.4", - "path+file:///__w/cryptography/cryptography/tmpwheelhouse/.tmpyLMvqZ/cryptography-47.0.0/src/rust/cryptography-cffi#0.1.0", - "path+file:///__w/cryptography/cryptography/tmpwheelhouse/.tmpyLMvqZ/cryptography-47.0.0/src/rust/cryptography-crypto#0.1.0", - "path+file:///__w/cryptography/cryptography/tmpwheelhouse/.tmpyLMvqZ/cryptography-47.0.0/src/rust/cryptography-keepalive#0.1.0", - "path+file:///__w/cryptography/cryptography/tmpwheelhouse/.tmpyLMvqZ/cryptography-47.0.0/src/rust/cryptography-key-parsing#0.1.0", - "path+file:///__w/cryptography/cryptography/tmpwheelhouse/.tmpyLMvqZ/cryptography-47.0.0/src/rust/cryptography-openssl#0.1.0", - "path+file:///__w/cryptography/cryptography/tmpwheelhouse/.tmpyLMvqZ/cryptography-47.0.0/src/rust/cryptography-x509#0.1.0", - "path+file:///__w/cryptography/cryptography/tmpwheelhouse/.tmpyLMvqZ/cryptography-47.0.0/src/rust/cryptography-x509-verification#0.1.0", - "registry+https://github.com/rust-lang/crates.io-index#foreign-types-shared@0.1.1", - "registry+https://github.com/rust-lang/crates.io-index#openssl@0.10.78", - "registry+https://github.com/rust-lang/crates.io-index#openssl-sys@0.9.114", - "registry+https://github.com/rust-lang/crates.io-index#pem@3.0.6", - "registry+https://github.com/rust-lang/crates.io-index#pyo3@0.28.3", - "registry+https://github.com/rust-lang/crates.io-index#pyo3-build-config@0.28.3", - "registry+https://github.com/rust-lang/crates.io-index#self_cell@1.2.2" - ] - }, - { - "ref": "path+file:///__w/cryptography/cryptography/tmpwheelhouse/.tmpyLMvqZ/cryptography-47.0.0/src/rust/cryptography-cffi#0.1.0", - "dependsOn": [ - "registry+https://github.com/rust-lang/crates.io-index#cc@1.2.60", - "registry+https://github.com/rust-lang/crates.io-index#openssl-sys@0.9.114", - "registry+https://github.com/rust-lang/crates.io-index#pyo3@0.28.3" - ] - }, - { - "ref": "path+file:///__w/cryptography/cryptography/tmpwheelhouse/.tmpyLMvqZ/cryptography-47.0.0/src/rust/cryptography-crypto#0.1.0", - "dependsOn": [ - "registry+https://github.com/rust-lang/crates.io-index#openssl@0.10.78" - ] - }, - { - "ref": "path+file:///__w/cryptography/cryptography/tmpwheelhouse/.tmpyLMvqZ/cryptography-47.0.0/src/rust/cryptography-keepalive#0.1.0", - "dependsOn": [ - "registry+https://github.com/rust-lang/crates.io-index#pyo3@0.28.3" - ] - }, - { - "ref": "path+file:///__w/cryptography/cryptography/tmpwheelhouse/.tmpyLMvqZ/cryptography-47.0.0/src/rust/cryptography-key-parsing#0.1.0", - "dependsOn": [ - "registry+https://github.com/rust-lang/crates.io-index#asn1@0.24.1", - "registry+https://github.com/rust-lang/crates.io-index#cfg-if@1.0.4", - "path+file:///__w/cryptography/cryptography/tmpwheelhouse/.tmpyLMvqZ/cryptography-47.0.0/src/rust/cryptography-crypto#0.1.0", - "path+file:///__w/cryptography/cryptography/tmpwheelhouse/.tmpyLMvqZ/cryptography-47.0.0/src/rust/cryptography-openssl#0.1.0", - "path+file:///__w/cryptography/cryptography/tmpwheelhouse/.tmpyLMvqZ/cryptography-47.0.0/src/rust/cryptography-x509#0.1.0", - "registry+https://github.com/rust-lang/crates.io-index#openssl@0.10.78", - "registry+https://github.com/rust-lang/crates.io-index#openssl-sys@0.9.114", - "registry+https://github.com/rust-lang/crates.io-index#pem@3.0.6" - ] - }, - { - "ref": "path+file:///__w/cryptography/cryptography/tmpwheelhouse/.tmpyLMvqZ/cryptography-47.0.0/src/rust/cryptography-openssl#0.1.0", - "dependsOn": [ - "registry+https://github.com/rust-lang/crates.io-index#cfg-if@1.0.4", - "registry+https://github.com/rust-lang/crates.io-index#foreign-types@0.3.2", - "registry+https://github.com/rust-lang/crates.io-index#foreign-types-shared@0.1.1", - "registry+https://github.com/rust-lang/crates.io-index#openssl@0.10.78", - "registry+https://github.com/rust-lang/crates.io-index#openssl-sys@0.9.114" - ] - }, - { - "ref": "path+file:///__w/cryptography/cryptography/tmpwheelhouse/.tmpyLMvqZ/cryptography-47.0.0/src/rust/cryptography-x509#0.1.0", - "dependsOn": [ - "registry+https://github.com/rust-lang/crates.io-index#asn1@0.24.1" - ] - }, - { - "ref": "path+file:///__w/cryptography/cryptography/tmpwheelhouse/.tmpyLMvqZ/cryptography-47.0.0/src/rust/cryptography-x509-verification#0.1.0", - "dependsOn": [ - "registry+https://github.com/rust-lang/crates.io-index#asn1@0.24.1", - "path+file:///__w/cryptography/cryptography/tmpwheelhouse/.tmpyLMvqZ/cryptography-47.0.0/src/rust/cryptography-x509#0.1.0" - ] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#asn1@0.24.1", - "dependsOn": [ - "registry+https://github.com/rust-lang/crates.io-index#asn1_derive@0.24.1", - "registry+https://github.com/rust-lang/crates.io-index#itoa@1.0.18" - ] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#asn1_derive@0.24.1", - "dependsOn": [ - "registry+https://github.com/rust-lang/crates.io-index#proc-macro2@1.0.106", - "registry+https://github.com/rust-lang/crates.io-index#quote@1.0.45", - "registry+https://github.com/rust-lang/crates.io-index#syn@2.0.117" - ] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#base64@0.22.1" - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#bitflags@2.11.1" - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#cc@1.2.60", - "dependsOn": [ - "registry+https://github.com/rust-lang/crates.io-index#find-msvc-tools@0.1.9", - "registry+https://github.com/rust-lang/crates.io-index#shlex@1.3.0" - ] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#cfg-if@1.0.4" - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#find-msvc-tools@0.1.9" - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#foreign-types-shared@0.1.1" - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#foreign-types@0.3.2", - "dependsOn": [ - "registry+https://github.com/rust-lang/crates.io-index#foreign-types-shared@0.1.1" - ] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#heck@0.5.0" - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#itoa@1.0.18" - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#libc@0.2.186" - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#once_cell@1.21.4" - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#openssl-macros@0.1.1", - "dependsOn": [ - "registry+https://github.com/rust-lang/crates.io-index#proc-macro2@1.0.106", - "registry+https://github.com/rust-lang/crates.io-index#quote@1.0.45", - "registry+https://github.com/rust-lang/crates.io-index#syn@2.0.117" - ] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#openssl-sys@0.9.114", - "dependsOn": [ - "registry+https://github.com/rust-lang/crates.io-index#cc@1.2.60", - "registry+https://github.com/rust-lang/crates.io-index#libc@0.2.186", - "registry+https://github.com/rust-lang/crates.io-index#pkg-config@0.3.33", - "registry+https://github.com/rust-lang/crates.io-index#vcpkg@0.2.15" - ] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#openssl@0.10.78", - "dependsOn": [ - "registry+https://github.com/rust-lang/crates.io-index#bitflags@2.11.1", - "registry+https://github.com/rust-lang/crates.io-index#cfg-if@1.0.4", - "registry+https://github.com/rust-lang/crates.io-index#foreign-types@0.3.2", - "registry+https://github.com/rust-lang/crates.io-index#libc@0.2.186", - "registry+https://github.com/rust-lang/crates.io-index#once_cell@1.21.4", - "registry+https://github.com/rust-lang/crates.io-index#openssl-macros@0.1.1", - "registry+https://github.com/rust-lang/crates.io-index#openssl-sys@0.9.114" - ] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#pem@3.0.6", - "dependsOn": [ - "registry+https://github.com/rust-lang/crates.io-index#base64@0.22.1" - ] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#pkg-config@0.3.33" - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#portable-atomic@1.13.1" - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#proc-macro2@1.0.106", - "dependsOn": [ - "registry+https://github.com/rust-lang/crates.io-index#unicode-ident@1.0.24" - ] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#pyo3-build-config@0.28.3", - "dependsOn": [ - "registry+https://github.com/rust-lang/crates.io-index#target-lexicon@0.13.5" - ] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#pyo3-ffi@0.28.3", - "dependsOn": [ - "registry+https://github.com/rust-lang/crates.io-index#libc@0.2.186", - "registry+https://github.com/rust-lang/crates.io-index#pyo3-build-config@0.28.3" - ] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#pyo3-macros-backend@0.28.3", - "dependsOn": [ - "registry+https://github.com/rust-lang/crates.io-index#heck@0.5.0", - "registry+https://github.com/rust-lang/crates.io-index#proc-macro2@1.0.106", - "registry+https://github.com/rust-lang/crates.io-index#pyo3-build-config@0.28.3", - "registry+https://github.com/rust-lang/crates.io-index#quote@1.0.45", - "registry+https://github.com/rust-lang/crates.io-index#syn@2.0.117" - ] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#pyo3-macros@0.28.3", - "dependsOn": [ - "registry+https://github.com/rust-lang/crates.io-index#proc-macro2@1.0.106", - "registry+https://github.com/rust-lang/crates.io-index#pyo3-macros-backend@0.28.3", - "registry+https://github.com/rust-lang/crates.io-index#quote@1.0.45", - "registry+https://github.com/rust-lang/crates.io-index#syn@2.0.117" - ] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#pyo3@0.28.3", - "dependsOn": [ - "registry+https://github.com/rust-lang/crates.io-index#libc@0.2.186", - "registry+https://github.com/rust-lang/crates.io-index#once_cell@1.21.4", - "registry+https://github.com/rust-lang/crates.io-index#portable-atomic@1.13.1", - "registry+https://github.com/rust-lang/crates.io-index#pyo3-build-config@0.28.3", - "registry+https://github.com/rust-lang/crates.io-index#pyo3-ffi@0.28.3", - "registry+https://github.com/rust-lang/crates.io-index#pyo3-macros@0.28.3" - ] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#quote@1.0.45", - "dependsOn": [ - "registry+https://github.com/rust-lang/crates.io-index#proc-macro2@1.0.106" - ] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#self_cell@1.2.2" - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#shlex@1.3.0" - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#syn@2.0.117", - "dependsOn": [ - "registry+https://github.com/rust-lang/crates.io-index#proc-macro2@1.0.106", - "registry+https://github.com/rust-lang/crates.io-index#quote@1.0.45", - "registry+https://github.com/rust-lang/crates.io-index#unicode-ident@1.0.24" - ] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#target-lexicon@0.13.5" - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#unicode-ident@1.0.24" - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#vcpkg@0.2.15" - } - ] -} \ No newline at end of file diff --git a/venv/lib/python3.9/site-packages/cryptography-47.0.0.dist-info/sboms/sbom.json b/venv/lib/python3.9/site-packages/cryptography-47.0.0.dist-info/sboms/sbom.json deleted file mode 100644 index 18d2a1b..0000000 --- a/venv/lib/python3.9/site-packages/cryptography-47.0.0.dist-info/sboms/sbom.json +++ /dev/null @@ -1,43 +0,0 @@ -{ - "bomFormat": "CycloneDX", - "specVersion": "1.5", - "version": 1, - "serialNumber": "urn:uuid:b5f772cd-86a5-4c2f-891d-743d5ad4aadb", - "metadata": { - "timestamp": "2026-04-24T19:12:44Z" - }, - "components": [ - { - "type": "library", - "name": "openssl", - "version": "4.0.0", - "purl": "pkg:generic/openssl@4.0.0?download_url=https://github.com/openssl/openssl/releases/download/openssl-4.0.0/openssl-4.0.0.tar.gz", - "hashes": [ - { - "alg": "SHA-256", - "content": "c32cf49a959c4f345f9606982dd36e7d28f7c58b19c2e25d75624d2b3d2f79ac" - } - ], - "externalReferences": [ - { - "type": "distribution", - "url": "https://github.com/openssl/openssl/releases/download/openssl-4.0.0/openssl-4.0.0.tar.gz" - } - ], - "properties": [ - { - "name": "build:operating-system", - "value": "linux" - }, - { - "name": "build:architecture", - "value": "x86_64" - }, - { - "name": "build:flags", - "value": "no-zlib no-shared no-module no-comp no-apps no-docs no-sm2-precomp no-atexit enable-ec_nistp_64_gcc_128" - } - ] - } - ] -} diff --git a/venv/lib/python3.9/site-packages/cryptography/__about__.py b/venv/lib/python3.9/site-packages/cryptography/__about__.py deleted file mode 100644 index 17fefda..0000000 --- a/venv/lib/python3.9/site-packages/cryptography/__about__.py +++ /dev/null @@ -1,17 +0,0 @@ -# This file is dual licensed under the terms of the Apache License, Version -# 2.0, and the BSD License. See the LICENSE file in the root of this repository -# for complete details. - -from __future__ import annotations - -__all__ = [ - "__author__", - "__copyright__", - "__version__", -] - -__version__ = "47.0.0" - - -__author__ = "The Python Cryptographic Authority and individual contributors" -__copyright__ = f"Copyright 2013-2026 {__author__}" diff --git a/venv/lib/python3.9/site-packages/cryptography/__init__.py b/venv/lib/python3.9/site-packages/cryptography/__init__.py deleted file mode 100644 index 530bb8f..0000000 --- a/venv/lib/python3.9/site-packages/cryptography/__init__.py +++ /dev/null @@ -1,26 +0,0 @@ -# This file is dual licensed under the terms of the Apache License, Version -# 2.0, and the BSD License. See the LICENSE file in the root of this repository -# for complete details. - -from __future__ import annotations - -import sys -import warnings - -from cryptography import utils -from cryptography.__about__ import __author__, __copyright__, __version__ - -__all__ = [ - "__author__", - "__copyright__", - "__version__", -] - -if sys.version_info[:2] == (3, 8): - warnings.warn( - "Python 3.8 is no longer supported by the Python core team " - "and support for it is deprecated in cryptography. The next " - "release of cryptography will remove support for Python 3.8.", - utils.CryptographyDeprecationWarning, - stacklevel=2, - ) diff --git a/venv/lib/python3.9/site-packages/cryptography/exceptions.py b/venv/lib/python3.9/site-packages/cryptography/exceptions.py deleted file mode 100644 index fe125ea..0000000 --- a/venv/lib/python3.9/site-packages/cryptography/exceptions.py +++ /dev/null @@ -1,52 +0,0 @@ -# This file is dual licensed under the terms of the Apache License, Version -# 2.0, and the BSD License. See the LICENSE file in the root of this repository -# for complete details. - -from __future__ import annotations - -import typing - -from cryptography.hazmat.bindings._rust import exceptions as rust_exceptions - -if typing.TYPE_CHECKING: - from cryptography.hazmat.bindings._rust import openssl as rust_openssl - -_Reasons = rust_exceptions._Reasons - - -class UnsupportedAlgorithm(Exception): - def __init__(self, message: str, reason: _Reasons | None = None) -> None: - super().__init__(message) - self._reason = reason - - -class AlreadyFinalized(Exception): - pass - - -class AlreadyUpdated(Exception): - pass - - -class NotYetFinalized(Exception): - pass - - -class InvalidTag(Exception): - pass - - -class InvalidSignature(Exception): - pass - - -class InternalError(Exception): - def __init__( - self, msg: str, err_code: list[rust_openssl.OpenSSLError] - ) -> None: - super().__init__(msg) - self.err_code = err_code - - -class InvalidKey(Exception): - pass diff --git a/venv/lib/python3.9/site-packages/cryptography/fernet.py b/venv/lib/python3.9/site-packages/cryptography/fernet.py deleted file mode 100644 index c6744ae..0000000 --- a/venv/lib/python3.9/site-packages/cryptography/fernet.py +++ /dev/null @@ -1,224 +0,0 @@ -# This file is dual licensed under the terms of the Apache License, Version -# 2.0, and the BSD License. See the LICENSE file in the root of this repository -# for complete details. - -from __future__ import annotations - -import base64 -import binascii -import os -import time -import typing -from collections.abc import Iterable - -from cryptography import utils -from cryptography.exceptions import InvalidSignature -from cryptography.hazmat.primitives import hashes, padding -from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes -from cryptography.hazmat.primitives.hmac import HMAC - - -class InvalidToken(Exception): - pass - - -_MAX_CLOCK_SKEW = 60 - - -class Fernet: - def __init__( - self, - key: bytes | str, - backend: typing.Any = None, - ) -> None: - try: - key = base64.urlsafe_b64decode(key) - except binascii.Error as exc: - raise ValueError( - "Fernet key must be 32 url-safe base64-encoded bytes." - ) from exc - if len(key) != 32: - raise ValueError( - "Fernet key must be 32 url-safe base64-encoded bytes." - ) - - self._signing_key = key[:16] - self._encryption_key = key[16:] - - @classmethod - def generate_key(cls) -> bytes: - return base64.urlsafe_b64encode(os.urandom(32)) - - def encrypt(self, data: bytes) -> bytes: - return self.encrypt_at_time(data, int(time.time())) - - def encrypt_at_time(self, data: bytes, current_time: int) -> bytes: - iv = os.urandom(16) - return self._encrypt_from_parts(data, current_time, iv) - - def _encrypt_from_parts( - self, data: bytes, current_time: int, iv: bytes - ) -> bytes: - utils._check_bytes("data", data) - - padder = padding.PKCS7(algorithms.AES.block_size).padder() - padded_data = padder.update(data) + padder.finalize() - encryptor = Cipher( - algorithms.AES(self._encryption_key), - modes.CBC(iv), - ).encryptor() - ciphertext = encryptor.update(padded_data) + encryptor.finalize() - - basic_parts = ( - b"\x80" - + current_time.to_bytes(length=8, byteorder="big") - + iv - + ciphertext - ) - - h = HMAC(self._signing_key, hashes.SHA256()) - h.update(basic_parts) - hmac = h.finalize() - return base64.urlsafe_b64encode(basic_parts + hmac) - - def decrypt(self, token: bytes | str, ttl: int | None = None) -> bytes: - timestamp, data = Fernet._get_unverified_token_data(token) - if ttl is None: - time_info = None - else: - time_info = (ttl, int(time.time())) - return self._decrypt_data(data, timestamp, time_info) - - def decrypt_at_time( - self, token: bytes | str, ttl: int, current_time: int - ) -> bytes: - if ttl is None: - raise ValueError( - "decrypt_at_time() can only be used with a non-None ttl" - ) - timestamp, data = Fernet._get_unverified_token_data(token) - return self._decrypt_data(data, timestamp, (ttl, current_time)) - - def extract_timestamp(self, token: bytes | str) -> int: - timestamp, data = Fernet._get_unverified_token_data(token) - # Verify the token was not tampered with. - self._verify_signature(data) - return timestamp - - @staticmethod - def _get_unverified_token_data(token: bytes | str) -> tuple[int, bytes]: - if not isinstance(token, (str, bytes)): - raise TypeError("token must be bytes or str") - - try: - data = base64.urlsafe_b64decode(token) - except (TypeError, binascii.Error): - raise InvalidToken - - if not data or data[0] != 0x80: - raise InvalidToken - - if len(data) < 9: - raise InvalidToken - - timestamp = int.from_bytes(data[1:9], byteorder="big") - return timestamp, data - - def _verify_signature(self, data: bytes) -> None: - h = HMAC(self._signing_key, hashes.SHA256()) - h.update(data[:-32]) - try: - h.verify(data[-32:]) - except InvalidSignature: - raise InvalidToken - - def _decrypt_data( - self, - data: bytes, - timestamp: int, - time_info: tuple[int, int] | None, - ) -> bytes: - if time_info is not None: - ttl, current_time = time_info - if timestamp + ttl < current_time: - raise InvalidToken - - if current_time + _MAX_CLOCK_SKEW < timestamp: - raise InvalidToken - - self._verify_signature(data) - - iv = data[9:25] - ciphertext = data[25:-32] - decryptor = Cipher( - algorithms.AES(self._encryption_key), modes.CBC(iv) - ).decryptor() - plaintext_padded = decryptor.update(ciphertext) - try: - plaintext_padded += decryptor.finalize() - except ValueError: - raise InvalidToken - unpadder = padding.PKCS7(algorithms.AES.block_size).unpadder() - - unpadded = unpadder.update(plaintext_padded) - try: - unpadded += unpadder.finalize() - except ValueError: - raise InvalidToken - return unpadded - - -class MultiFernet: - def __init__(self, fernets: Iterable[Fernet]): - fernets = list(fernets) - if not fernets: - raise ValueError( - "MultiFernet requires at least one Fernet instance" - ) - self._fernets = fernets - - def encrypt(self, msg: bytes) -> bytes: - return self.encrypt_at_time(msg, int(time.time())) - - def encrypt_at_time(self, msg: bytes, current_time: int) -> bytes: - return self._fernets[0].encrypt_at_time(msg, current_time) - - def rotate(self, msg: bytes | str) -> bytes: - timestamp, data = Fernet._get_unverified_token_data(msg) - for f in self._fernets: - try: - p = f._decrypt_data(data, timestamp, None) - break - except InvalidToken: - pass - else: - raise InvalidToken - - iv = os.urandom(16) - return self._fernets[0]._encrypt_from_parts(p, timestamp, iv) - - def decrypt(self, msg: bytes | str, ttl: int | None = None) -> bytes: - for f in self._fernets: - try: - return f.decrypt(msg, ttl) - except InvalidToken: - pass - raise InvalidToken - - def decrypt_at_time( - self, msg: bytes | str, ttl: int, current_time: int - ) -> bytes: - for f in self._fernets: - try: - return f.decrypt_at_time(msg, ttl, current_time) - except InvalidToken: - pass - raise InvalidToken - - def extract_timestamp(self, msg: bytes | str) -> int: - for f in self._fernets: - try: - return f.extract_timestamp(msg) - except InvalidToken: - pass - raise InvalidToken diff --git a/venv/lib/python3.9/site-packages/cryptography/hazmat/__init__.py b/venv/lib/python3.9/site-packages/cryptography/hazmat/__init__.py deleted file mode 100644 index b9f1187..0000000 --- a/venv/lib/python3.9/site-packages/cryptography/hazmat/__init__.py +++ /dev/null @@ -1,13 +0,0 @@ -# This file is dual licensed under the terms of the Apache License, Version -# 2.0, and the BSD License. See the LICENSE file in the root of this repository -# for complete details. - -from __future__ import annotations - -""" -Hazardous Materials - -This is a "Hazardous Materials" module. You should ONLY use it if you're -100% absolutely sure that you know what you're doing because this module -is full of land mines, dragons, and dinosaurs with laser guns. -""" diff --git a/venv/lib/python3.9/site-packages/cryptography/hazmat/_oid.py b/venv/lib/python3.9/site-packages/cryptography/hazmat/_oid.py deleted file mode 100644 index 4bf138d..0000000 --- a/venv/lib/python3.9/site-packages/cryptography/hazmat/_oid.py +++ /dev/null @@ -1,356 +0,0 @@ -# This file is dual licensed under the terms of the Apache License, Version -# 2.0, and the BSD License. See the LICENSE file in the root of this repository -# for complete details. - -from __future__ import annotations - -from cryptography.hazmat.bindings._rust import ( - ObjectIdentifier as ObjectIdentifier, -) -from cryptography.hazmat.primitives import hashes - - -class ExtensionOID: - SUBJECT_DIRECTORY_ATTRIBUTES = ObjectIdentifier("2.5.29.9") - SUBJECT_KEY_IDENTIFIER = ObjectIdentifier("2.5.29.14") - KEY_USAGE = ObjectIdentifier("2.5.29.15") - PRIVATE_KEY_USAGE_PERIOD = ObjectIdentifier("2.5.29.16") - SUBJECT_ALTERNATIVE_NAME = ObjectIdentifier("2.5.29.17") - ISSUER_ALTERNATIVE_NAME = ObjectIdentifier("2.5.29.18") - BASIC_CONSTRAINTS = ObjectIdentifier("2.5.29.19") - NAME_CONSTRAINTS = ObjectIdentifier("2.5.29.30") - CRL_DISTRIBUTION_POINTS = ObjectIdentifier("2.5.29.31") - CERTIFICATE_POLICIES = ObjectIdentifier("2.5.29.32") - POLICY_MAPPINGS = ObjectIdentifier("2.5.29.33") - AUTHORITY_KEY_IDENTIFIER = ObjectIdentifier("2.5.29.35") - POLICY_CONSTRAINTS = ObjectIdentifier("2.5.29.36") - EXTENDED_KEY_USAGE = ObjectIdentifier("2.5.29.37") - FRESHEST_CRL = ObjectIdentifier("2.5.29.46") - INHIBIT_ANY_POLICY = ObjectIdentifier("2.5.29.54") - ISSUING_DISTRIBUTION_POINT = ObjectIdentifier("2.5.29.28") - AUTHORITY_INFORMATION_ACCESS = ObjectIdentifier("1.3.6.1.5.5.7.1.1") - SUBJECT_INFORMATION_ACCESS = ObjectIdentifier("1.3.6.1.5.5.7.1.11") - OCSP_NO_CHECK = ObjectIdentifier("1.3.6.1.5.5.7.48.1.5") - TLS_FEATURE = ObjectIdentifier("1.3.6.1.5.5.7.1.24") - CRL_NUMBER = ObjectIdentifier("2.5.29.20") - DELTA_CRL_INDICATOR = ObjectIdentifier("2.5.29.27") - PRECERT_SIGNED_CERTIFICATE_TIMESTAMPS = ObjectIdentifier( - "1.3.6.1.4.1.11129.2.4.2" - ) - PRECERT_POISON = ObjectIdentifier("1.3.6.1.4.1.11129.2.4.3") - SIGNED_CERTIFICATE_TIMESTAMPS = ObjectIdentifier("1.3.6.1.4.1.11129.2.4.5") - MS_CERTIFICATE_TEMPLATE = ObjectIdentifier("1.3.6.1.4.1.311.21.7") - ADMISSIONS = ObjectIdentifier("1.3.36.8.3.3") - - -class OCSPExtensionOID: - NONCE = ObjectIdentifier("1.3.6.1.5.5.7.48.1.2") - ACCEPTABLE_RESPONSES = ObjectIdentifier("1.3.6.1.5.5.7.48.1.4") - - -class CRLEntryExtensionOID: - CERTIFICATE_ISSUER = ObjectIdentifier("2.5.29.29") - CRL_REASON = ObjectIdentifier("2.5.29.21") - INVALIDITY_DATE = ObjectIdentifier("2.5.29.24") - - -class NameOID: - COMMON_NAME = ObjectIdentifier("2.5.4.3") - COUNTRY_NAME = ObjectIdentifier("2.5.4.6") - LOCALITY_NAME = ObjectIdentifier("2.5.4.7") - STATE_OR_PROVINCE_NAME = ObjectIdentifier("2.5.4.8") - STREET_ADDRESS = ObjectIdentifier("2.5.4.9") - ORGANIZATION_IDENTIFIER = ObjectIdentifier("2.5.4.97") - ORGANIZATION_NAME = ObjectIdentifier("2.5.4.10") - ORGANIZATIONAL_UNIT_NAME = ObjectIdentifier("2.5.4.11") - SERIAL_NUMBER = ObjectIdentifier("2.5.4.5") - SURNAME = ObjectIdentifier("2.5.4.4") - GIVEN_NAME = ObjectIdentifier("2.5.4.42") - TITLE = ObjectIdentifier("2.5.4.12") - INITIALS = ObjectIdentifier("2.5.4.43") - GENERATION_QUALIFIER = ObjectIdentifier("2.5.4.44") - X500_UNIQUE_IDENTIFIER = ObjectIdentifier("2.5.4.45") - DN_QUALIFIER = ObjectIdentifier("2.5.4.46") - PSEUDONYM = ObjectIdentifier("2.5.4.65") - USER_ID = ObjectIdentifier("0.9.2342.19200300.100.1.1") - DOMAIN_COMPONENT = ObjectIdentifier("0.9.2342.19200300.100.1.25") - EMAIL_ADDRESS = ObjectIdentifier("1.2.840.113549.1.9.1") - JURISDICTION_COUNTRY_NAME = ObjectIdentifier("1.3.6.1.4.1.311.60.2.1.3") - JURISDICTION_LOCALITY_NAME = ObjectIdentifier("1.3.6.1.4.1.311.60.2.1.1") - JURISDICTION_STATE_OR_PROVINCE_NAME = ObjectIdentifier( - "1.3.6.1.4.1.311.60.2.1.2" - ) - BUSINESS_CATEGORY = ObjectIdentifier("2.5.4.15") - POSTAL_ADDRESS = ObjectIdentifier("2.5.4.16") - POSTAL_CODE = ObjectIdentifier("2.5.4.17") - INN = ObjectIdentifier("1.2.643.3.131.1.1") - OGRN = ObjectIdentifier("1.2.643.100.1") - SNILS = ObjectIdentifier("1.2.643.100.3") - UNSTRUCTURED_NAME = ObjectIdentifier("1.2.840.113549.1.9.2") - - -class SignatureAlgorithmOID: - RSA_WITH_MD5 = ObjectIdentifier("1.2.840.113549.1.1.4") - RSA_WITH_SHA1 = ObjectIdentifier("1.2.840.113549.1.1.5") - # This is an alternate OID for RSA with SHA1 that is occasionally seen - _RSA_WITH_SHA1 = ObjectIdentifier("1.3.14.3.2.29") - RSA_WITH_SHA224 = ObjectIdentifier("1.2.840.113549.1.1.14") - RSA_WITH_SHA256 = ObjectIdentifier("1.2.840.113549.1.1.11") - RSA_WITH_SHA384 = ObjectIdentifier("1.2.840.113549.1.1.12") - RSA_WITH_SHA512 = ObjectIdentifier("1.2.840.113549.1.1.13") - RSA_WITH_SHA3_224 = ObjectIdentifier("2.16.840.1.101.3.4.3.13") - RSA_WITH_SHA3_256 = ObjectIdentifier("2.16.840.1.101.3.4.3.14") - RSA_WITH_SHA3_384 = ObjectIdentifier("2.16.840.1.101.3.4.3.15") - RSA_WITH_SHA3_512 = ObjectIdentifier("2.16.840.1.101.3.4.3.16") - RSASSA_PSS = ObjectIdentifier("1.2.840.113549.1.1.10") - ECDSA_WITH_SHA1 = ObjectIdentifier("1.2.840.10045.4.1") - ECDSA_WITH_SHA224 = ObjectIdentifier("1.2.840.10045.4.3.1") - ECDSA_WITH_SHA256 = ObjectIdentifier("1.2.840.10045.4.3.2") - ECDSA_WITH_SHA384 = ObjectIdentifier("1.2.840.10045.4.3.3") - ECDSA_WITH_SHA512 = ObjectIdentifier("1.2.840.10045.4.3.4") - ECDSA_WITH_SHA3_224 = ObjectIdentifier("2.16.840.1.101.3.4.3.9") - ECDSA_WITH_SHA3_256 = ObjectIdentifier("2.16.840.1.101.3.4.3.10") - ECDSA_WITH_SHA3_384 = ObjectIdentifier("2.16.840.1.101.3.4.3.11") - ECDSA_WITH_SHA3_512 = ObjectIdentifier("2.16.840.1.101.3.4.3.12") - DSA_WITH_SHA1 = ObjectIdentifier("1.2.840.10040.4.3") - DSA_WITH_SHA224 = ObjectIdentifier("2.16.840.1.101.3.4.3.1") - DSA_WITH_SHA256 = ObjectIdentifier("2.16.840.1.101.3.4.3.2") - DSA_WITH_SHA384 = ObjectIdentifier("2.16.840.1.101.3.4.3.3") - DSA_WITH_SHA512 = ObjectIdentifier("2.16.840.1.101.3.4.3.4") - ED25519 = ObjectIdentifier("1.3.101.112") - ED448 = ObjectIdentifier("1.3.101.113") - GOSTR3411_94_WITH_3410_2001 = ObjectIdentifier("1.2.643.2.2.3") - GOSTR3410_2012_WITH_3411_2012_256 = ObjectIdentifier("1.2.643.7.1.1.3.2") - GOSTR3410_2012_WITH_3411_2012_512 = ObjectIdentifier("1.2.643.7.1.1.3.3") - - -_SIG_OIDS_TO_HASH: dict[ObjectIdentifier, hashes.HashAlgorithm | None] = { - SignatureAlgorithmOID.RSA_WITH_MD5: hashes.MD5(), - SignatureAlgorithmOID.RSA_WITH_SHA1: hashes.SHA1(), - SignatureAlgorithmOID._RSA_WITH_SHA1: hashes.SHA1(), - SignatureAlgorithmOID.RSA_WITH_SHA224: hashes.SHA224(), - SignatureAlgorithmOID.RSA_WITH_SHA256: hashes.SHA256(), - SignatureAlgorithmOID.RSA_WITH_SHA384: hashes.SHA384(), - SignatureAlgorithmOID.RSA_WITH_SHA512: hashes.SHA512(), - SignatureAlgorithmOID.RSA_WITH_SHA3_224: hashes.SHA3_224(), - SignatureAlgorithmOID.RSA_WITH_SHA3_256: hashes.SHA3_256(), - SignatureAlgorithmOID.RSA_WITH_SHA3_384: hashes.SHA3_384(), - SignatureAlgorithmOID.RSA_WITH_SHA3_512: hashes.SHA3_512(), - SignatureAlgorithmOID.ECDSA_WITH_SHA1: hashes.SHA1(), - SignatureAlgorithmOID.ECDSA_WITH_SHA224: hashes.SHA224(), - SignatureAlgorithmOID.ECDSA_WITH_SHA256: hashes.SHA256(), - SignatureAlgorithmOID.ECDSA_WITH_SHA384: hashes.SHA384(), - SignatureAlgorithmOID.ECDSA_WITH_SHA512: hashes.SHA512(), - SignatureAlgorithmOID.ECDSA_WITH_SHA3_224: hashes.SHA3_224(), - SignatureAlgorithmOID.ECDSA_WITH_SHA3_256: hashes.SHA3_256(), - SignatureAlgorithmOID.ECDSA_WITH_SHA3_384: hashes.SHA3_384(), - SignatureAlgorithmOID.ECDSA_WITH_SHA3_512: hashes.SHA3_512(), - SignatureAlgorithmOID.DSA_WITH_SHA1: hashes.SHA1(), - SignatureAlgorithmOID.DSA_WITH_SHA224: hashes.SHA224(), - SignatureAlgorithmOID.DSA_WITH_SHA256: hashes.SHA256(), - SignatureAlgorithmOID.ED25519: None, - SignatureAlgorithmOID.ED448: None, - SignatureAlgorithmOID.GOSTR3411_94_WITH_3410_2001: None, - SignatureAlgorithmOID.GOSTR3410_2012_WITH_3411_2012_256: None, - SignatureAlgorithmOID.GOSTR3410_2012_WITH_3411_2012_512: None, -} - - -class HashAlgorithmOID: - SHA1 = ObjectIdentifier("1.3.14.3.2.26") - SHA224 = ObjectIdentifier("2.16.840.1.101.3.4.2.4") - SHA256 = ObjectIdentifier("2.16.840.1.101.3.4.2.1") - SHA384 = ObjectIdentifier("2.16.840.1.101.3.4.2.2") - SHA512 = ObjectIdentifier("2.16.840.1.101.3.4.2.3") - SHA3_224 = ObjectIdentifier("1.3.6.1.4.1.37476.3.2.1.99.7.224") - SHA3_256 = ObjectIdentifier("1.3.6.1.4.1.37476.3.2.1.99.7.256") - SHA3_384 = ObjectIdentifier("1.3.6.1.4.1.37476.3.2.1.99.7.384") - SHA3_512 = ObjectIdentifier("1.3.6.1.4.1.37476.3.2.1.99.7.512") - SHA3_224_NIST = ObjectIdentifier("2.16.840.1.101.3.4.2.7") - SHA3_256_NIST = ObjectIdentifier("2.16.840.1.101.3.4.2.8") - SHA3_384_NIST = ObjectIdentifier("2.16.840.1.101.3.4.2.9") - SHA3_512_NIST = ObjectIdentifier("2.16.840.1.101.3.4.2.10") - - -class PublicKeyAlgorithmOID: - DSA = ObjectIdentifier("1.2.840.10040.4.1") - EC_PUBLIC_KEY = ObjectIdentifier("1.2.840.10045.2.1") - RSAES_PKCS1_v1_5 = ObjectIdentifier("1.2.840.113549.1.1.1") - RSASSA_PSS = ObjectIdentifier("1.2.840.113549.1.1.10") - X25519 = ObjectIdentifier("1.3.101.110") - X448 = ObjectIdentifier("1.3.101.111") - ED25519 = ObjectIdentifier("1.3.101.112") - ED448 = ObjectIdentifier("1.3.101.113") - - -class ExtendedKeyUsageOID: - SERVER_AUTH = ObjectIdentifier("1.3.6.1.5.5.7.3.1") - CLIENT_AUTH = ObjectIdentifier("1.3.6.1.5.5.7.3.2") - CODE_SIGNING = ObjectIdentifier("1.3.6.1.5.5.7.3.3") - EMAIL_PROTECTION = ObjectIdentifier("1.3.6.1.5.5.7.3.4") - TIME_STAMPING = ObjectIdentifier("1.3.6.1.5.5.7.3.8") - OCSP_SIGNING = ObjectIdentifier("1.3.6.1.5.5.7.3.9") - ANY_EXTENDED_KEY_USAGE = ObjectIdentifier("2.5.29.37.0") - SMARTCARD_LOGON = ObjectIdentifier("1.3.6.1.4.1.311.20.2.2") - KERBEROS_PKINIT_KDC = ObjectIdentifier("1.3.6.1.5.2.3.5") - IPSEC_IKE = ObjectIdentifier("1.3.6.1.5.5.7.3.17") - BUNDLE_SECURITY = ObjectIdentifier("1.3.6.1.5.5.7.3.35") - CERTIFICATE_TRANSPARENCY = ObjectIdentifier("1.3.6.1.4.1.11129.2.4.4") - - -class OtherNameFormOID: - PERMANENT_IDENTIFIER = ObjectIdentifier("1.3.6.1.5.5.7.8.3") - HW_MODULE_NAME = ObjectIdentifier("1.3.6.1.5.5.7.8.4") - DNS_SRV = ObjectIdentifier("1.3.6.1.5.5.7.8.7") - NAI_REALM = ObjectIdentifier("1.3.6.1.5.5.7.8.8") - SMTP_UTF8_MAILBOX = ObjectIdentifier("1.3.6.1.5.5.7.8.9") - ACP_NODE_NAME = ObjectIdentifier("1.3.6.1.5.5.7.8.10") - BUNDLE_EID = ObjectIdentifier("1.3.6.1.5.5.7.8.11") - - -class AuthorityInformationAccessOID: - CA_ISSUERS = ObjectIdentifier("1.3.6.1.5.5.7.48.2") - OCSP = ObjectIdentifier("1.3.6.1.5.5.7.48.1") - - -class SubjectInformationAccessOID: - CA_REPOSITORY = ObjectIdentifier("1.3.6.1.5.5.7.48.5") - - -class CertificatePoliciesOID: - CPS_QUALIFIER = ObjectIdentifier("1.3.6.1.5.5.7.2.1") - CPS_USER_NOTICE = ObjectIdentifier("1.3.6.1.5.5.7.2.2") - ANY_POLICY = ObjectIdentifier("2.5.29.32.0") - - -class AttributeOID: - CHALLENGE_PASSWORD = ObjectIdentifier("1.2.840.113549.1.9.7") - UNSTRUCTURED_NAME = ObjectIdentifier("1.2.840.113549.1.9.2") - - -_OID_NAMES = { - NameOID.COMMON_NAME: "commonName", - NameOID.COUNTRY_NAME: "countryName", - NameOID.LOCALITY_NAME: "localityName", - NameOID.STATE_OR_PROVINCE_NAME: "stateOrProvinceName", - NameOID.STREET_ADDRESS: "streetAddress", - NameOID.ORGANIZATION_NAME: "organizationName", - NameOID.ORGANIZATIONAL_UNIT_NAME: "organizationalUnitName", - NameOID.SERIAL_NUMBER: "serialNumber", - NameOID.SURNAME: "surname", - NameOID.GIVEN_NAME: "givenName", - NameOID.TITLE: "title", - NameOID.GENERATION_QUALIFIER: "generationQualifier", - NameOID.X500_UNIQUE_IDENTIFIER: "x500UniqueIdentifier", - NameOID.DN_QUALIFIER: "dnQualifier", - NameOID.PSEUDONYM: "pseudonym", - NameOID.USER_ID: "userID", - NameOID.DOMAIN_COMPONENT: "domainComponent", - NameOID.EMAIL_ADDRESS: "emailAddress", - NameOID.JURISDICTION_COUNTRY_NAME: "jurisdictionCountryName", - NameOID.JURISDICTION_LOCALITY_NAME: "jurisdictionLocalityName", - NameOID.JURISDICTION_STATE_OR_PROVINCE_NAME: ( - "jurisdictionStateOrProvinceName" - ), - NameOID.BUSINESS_CATEGORY: "businessCategory", - NameOID.POSTAL_ADDRESS: "postalAddress", - NameOID.POSTAL_CODE: "postalCode", - NameOID.INN: "INN", - NameOID.OGRN: "OGRN", - NameOID.SNILS: "SNILS", - NameOID.UNSTRUCTURED_NAME: "unstructuredName", - SignatureAlgorithmOID.RSA_WITH_MD5: "md5WithRSAEncryption", - SignatureAlgorithmOID.RSA_WITH_SHA1: "sha1WithRSAEncryption", - SignatureAlgorithmOID.RSA_WITH_SHA224: "sha224WithRSAEncryption", - SignatureAlgorithmOID.RSA_WITH_SHA256: "sha256WithRSAEncryption", - SignatureAlgorithmOID.RSA_WITH_SHA384: "sha384WithRSAEncryption", - SignatureAlgorithmOID.RSA_WITH_SHA512: "sha512WithRSAEncryption", - SignatureAlgorithmOID.RSASSA_PSS: "rsassaPss", - SignatureAlgorithmOID.ECDSA_WITH_SHA1: "ecdsa-with-SHA1", - SignatureAlgorithmOID.ECDSA_WITH_SHA224: "ecdsa-with-SHA224", - SignatureAlgorithmOID.ECDSA_WITH_SHA256: "ecdsa-with-SHA256", - SignatureAlgorithmOID.ECDSA_WITH_SHA384: "ecdsa-with-SHA384", - SignatureAlgorithmOID.ECDSA_WITH_SHA512: "ecdsa-with-SHA512", - SignatureAlgorithmOID.DSA_WITH_SHA1: "dsa-with-sha1", - SignatureAlgorithmOID.DSA_WITH_SHA224: "dsa-with-sha224", - SignatureAlgorithmOID.DSA_WITH_SHA256: "dsa-with-sha256", - SignatureAlgorithmOID.ED25519: "ed25519", - SignatureAlgorithmOID.ED448: "ed448", - SignatureAlgorithmOID.GOSTR3411_94_WITH_3410_2001: ( - "GOST R 34.11-94 with GOST R 34.10-2001" - ), - SignatureAlgorithmOID.GOSTR3410_2012_WITH_3411_2012_256: ( - "GOST R 34.10-2012 with GOST R 34.11-2012 (256 bit)" - ), - SignatureAlgorithmOID.GOSTR3410_2012_WITH_3411_2012_512: ( - "GOST R 34.10-2012 with GOST R 34.11-2012 (512 bit)" - ), - HashAlgorithmOID.SHA1: "sha1", - HashAlgorithmOID.SHA224: "sha224", - HashAlgorithmOID.SHA256: "sha256", - HashAlgorithmOID.SHA384: "sha384", - HashAlgorithmOID.SHA512: "sha512", - HashAlgorithmOID.SHA3_224: "sha3_224", - HashAlgorithmOID.SHA3_256: "sha3_256", - HashAlgorithmOID.SHA3_384: "sha3_384", - HashAlgorithmOID.SHA3_512: "sha3_512", - HashAlgorithmOID.SHA3_224_NIST: "sha3_224", - HashAlgorithmOID.SHA3_256_NIST: "sha3_256", - HashAlgorithmOID.SHA3_384_NIST: "sha3_384", - HashAlgorithmOID.SHA3_512_NIST: "sha3_512", - PublicKeyAlgorithmOID.DSA: "dsaEncryption", - PublicKeyAlgorithmOID.EC_PUBLIC_KEY: "id-ecPublicKey", - PublicKeyAlgorithmOID.RSAES_PKCS1_v1_5: "rsaEncryption", - PublicKeyAlgorithmOID.X25519: "X25519", - PublicKeyAlgorithmOID.X448: "X448", - ExtendedKeyUsageOID.SERVER_AUTH: "serverAuth", - ExtendedKeyUsageOID.CLIENT_AUTH: "clientAuth", - ExtendedKeyUsageOID.CODE_SIGNING: "codeSigning", - ExtendedKeyUsageOID.EMAIL_PROTECTION: "emailProtection", - ExtendedKeyUsageOID.TIME_STAMPING: "timeStamping", - ExtendedKeyUsageOID.OCSP_SIGNING: "OCSPSigning", - ExtendedKeyUsageOID.SMARTCARD_LOGON: "msSmartcardLogin", - ExtendedKeyUsageOID.KERBEROS_PKINIT_KDC: "pkInitKDC", - ExtensionOID.SUBJECT_DIRECTORY_ATTRIBUTES: "subjectDirectoryAttributes", - ExtensionOID.SUBJECT_KEY_IDENTIFIER: "subjectKeyIdentifier", - ExtensionOID.KEY_USAGE: "keyUsage", - ExtensionOID.PRIVATE_KEY_USAGE_PERIOD: "privateKeyUsagePeriod", - ExtensionOID.SUBJECT_ALTERNATIVE_NAME: "subjectAltName", - ExtensionOID.ISSUER_ALTERNATIVE_NAME: "issuerAltName", - ExtensionOID.BASIC_CONSTRAINTS: "basicConstraints", - ExtensionOID.PRECERT_SIGNED_CERTIFICATE_TIMESTAMPS: ( - "signedCertificateTimestampList" - ), - ExtensionOID.SIGNED_CERTIFICATE_TIMESTAMPS: ( - "signedCertificateTimestampList" - ), - ExtensionOID.PRECERT_POISON: "ctPoison", - ExtensionOID.MS_CERTIFICATE_TEMPLATE: "msCertificateTemplate", - ExtensionOID.ADMISSIONS: "Admissions", - CRLEntryExtensionOID.CRL_REASON: "cRLReason", - CRLEntryExtensionOID.INVALIDITY_DATE: "invalidityDate", - CRLEntryExtensionOID.CERTIFICATE_ISSUER: "certificateIssuer", - ExtensionOID.NAME_CONSTRAINTS: "nameConstraints", - ExtensionOID.CRL_DISTRIBUTION_POINTS: "cRLDistributionPoints", - ExtensionOID.CERTIFICATE_POLICIES: "certificatePolicies", - ExtensionOID.POLICY_MAPPINGS: "policyMappings", - ExtensionOID.AUTHORITY_KEY_IDENTIFIER: "authorityKeyIdentifier", - ExtensionOID.POLICY_CONSTRAINTS: "policyConstraints", - ExtensionOID.EXTENDED_KEY_USAGE: "extendedKeyUsage", - ExtensionOID.FRESHEST_CRL: "freshestCRL", - ExtensionOID.INHIBIT_ANY_POLICY: "inhibitAnyPolicy", - ExtensionOID.ISSUING_DISTRIBUTION_POINT: "issuingDistributionPoint", - ExtensionOID.AUTHORITY_INFORMATION_ACCESS: "authorityInfoAccess", - ExtensionOID.SUBJECT_INFORMATION_ACCESS: "subjectInfoAccess", - ExtensionOID.OCSP_NO_CHECK: "OCSPNoCheck", - ExtensionOID.CRL_NUMBER: "cRLNumber", - ExtensionOID.DELTA_CRL_INDICATOR: "deltaCRLIndicator", - ExtensionOID.TLS_FEATURE: "TLSFeature", - AuthorityInformationAccessOID.OCSP: "OCSP", - AuthorityInformationAccessOID.CA_ISSUERS: "caIssuers", - SubjectInformationAccessOID.CA_REPOSITORY: "caRepository", - CertificatePoliciesOID.CPS_QUALIFIER: "id-qt-cps", - CertificatePoliciesOID.CPS_USER_NOTICE: "id-qt-unotice", - OCSPExtensionOID.NONCE: "OCSPNonce", - AttributeOID.CHALLENGE_PASSWORD: "challengePassword", -} diff --git a/venv/lib/python3.9/site-packages/cryptography/hazmat/asn1/__init__.py b/venv/lib/python3.9/site-packages/cryptography/hazmat/asn1/__init__.py deleted file mode 100644 index ac3d4bd..0000000 --- a/venv/lib/python3.9/site-packages/cryptography/hazmat/asn1/__init__.py +++ /dev/null @@ -1,43 +0,0 @@ -# This file is dual licensed under the terms of the Apache License, Version -# 2.0, and the BSD License. See the LICENSE file in the root of this repository -# for complete details. - -from cryptography.hazmat.asn1.asn1 import ( - TLV, - BitString, - Default, - Explicit, - GeneralizedTime, - IA5String, - Implicit, - Null, - PrintableString, - SetOf, - Size, - UTCTime, - Variant, - decode_der, - encode_der, - sequence, - set, -) - -__all__ = [ - "TLV", - "BitString", - "Default", - "Explicit", - "GeneralizedTime", - "IA5String", - "Implicit", - "Null", - "PrintableString", - "SetOf", - "Size", - "UTCTime", - "Variant", - "decode_der", - "encode_der", - "sequence", - "set", -] diff --git a/venv/lib/python3.9/site-packages/cryptography/hazmat/asn1/asn1.py b/venv/lib/python3.9/site-packages/cryptography/hazmat/asn1/asn1.py deleted file mode 100644 index dde7e10..0000000 --- a/venv/lib/python3.9/site-packages/cryptography/hazmat/asn1/asn1.py +++ /dev/null @@ -1,439 +0,0 @@ -# This file is dual licensed under the terms of the Apache License, Version -# 2.0, and the BSD License. See the LICENSE file in the root of this repository -# for complete details. - -from __future__ import annotations - -import builtins -import dataclasses -import sys -import types -import typing - -if sys.version_info < (3, 11): - import typing_extensions - - LiteralString = typing_extensions.LiteralString - - # We use the `include_extras` parameter of `get_type_hints`, which was - # added in Python 3.9. This can be replaced by the `typing` version - # once the min version is >= 3.9 - if sys.version_info < (3, 9): - get_type_hints = typing_extensions.get_type_hints - get_type_args = typing_extensions.get_args - get_type_origin = typing_extensions.get_origin - Annotated = typing_extensions.Annotated - else: - get_type_hints = typing.get_type_hints - get_type_args = typing.get_args - get_type_origin = typing.get_origin - Annotated = typing.Annotated -else: - get_type_hints = typing.get_type_hints - get_type_args = typing.get_args - get_type_origin = typing.get_origin - Annotated = typing.Annotated - LiteralString = typing.LiteralString - -if sys.version_info < (3, 10): - NoneType = type(None) -else: - NoneType = types.NoneType # type: ignore[nonetype-type] - -from cryptography.hazmat.bindings._rust import declarative_asn1 - -T = typing.TypeVar("T", covariant=True) -U = typing.TypeVar("U") -Tag = typing.TypeVar("Tag", bound=LiteralString) - - -@dataclasses.dataclass(frozen=True) -class Variant(typing.Generic[U, Tag]): - """ - A tagged variant for CHOICE fields with the same underlying type. - - Use this when you have multiple CHOICE alternatives with the same type - and need to distinguish between them: - - foo: ( - Annotated[Variant[int, typing.Literal["IntA"]], Implicit(0)] - | Annotated[Variant[int, typing.Literal["IntB"]], Implicit(1)] - ) - - Usage: - example = Example(foo=Variant(5, "IntA")) - decoded.foo.value # The int value - decoded.foo.tag # "IntA" or "IntB" - """ - - value: U - tag: str - - -decode_der = declarative_asn1.decode_der -encode_der = declarative_asn1.encode_der - - -def _is_union(field_type: type) -> bool: - # NOTE: types.UnionType for `T | U`, typing.Union for `Union[T, U]`. - # TODO: Drop the `hasattr()` once the minimum supported Python version - # is >= 3.10. - union_types = ( - (types.UnionType, typing.Union) - if hasattr(types, "UnionType") - else (typing.Union,) - ) - return get_type_origin(field_type) in union_types - - -def _extract_annotation( - metadata: tuple, field_name: str -) -> declarative_asn1.Annotation: - default = None - encoding = None - size = None - for raw_annotation in metadata: - if isinstance(raw_annotation, Default): - if default is not None: - raise TypeError( - f"multiple DEFAULT annotations found in field " - f"'{field_name}'" - ) - default = raw_annotation.value - elif isinstance(raw_annotation, declarative_asn1.Encoding): - if encoding is not None: - raise TypeError( - f"multiple IMPLICIT/EXPLICIT annotations found in field " - f"'{field_name}'" - ) - encoding = raw_annotation - elif isinstance(raw_annotation, declarative_asn1.Size): - if size is not None: - raise TypeError( - f"multiple SIZE annotations found in field '{field_name}'" - ) - size = raw_annotation - else: - raise TypeError(f"unsupported annotation: {raw_annotation}") - - return declarative_asn1.Annotation( - default=default, encoding=encoding, size=size - ) - - -def _normalize_field_type( - field_type: typing.Any, field_name: str -) -> declarative_asn1.AnnotatedType: - # Strip the `Annotated[...]` off, and populate the annotation - # from it if it exists. - if get_type_origin(field_type) is Annotated: - annotation = _extract_annotation(field_type.__metadata__, field_name) - field_type, *_ = get_type_args(field_type) - else: - annotation = declarative_asn1.Annotation() - - if annotation.size is not None and ( - get_type_origin(field_type) not in (builtins.list, SetOf) - and field_type - not in ( - builtins.bytes, - builtins.str, - BitString, - IA5String, - PrintableString, - ) - ): - raise TypeError( - f"field '{field_name}' has a SIZE annotation, but SIZE " - "annotations are only supported for fields of types: " - "[SEQUENCE OF, SET OF, BIT STRING, OCTET STRING, UTF8String, " - "PrintableString, IA5String]" - ) - - if field_type is TLV: - if isinstance(annotation.encoding, Implicit): - raise TypeError( - f"field '{field_name}' has an IMPLICIT annotation, but " - "IMPLICIT annotations are not supported for TLV types." - ) - elif annotation.default is not None: - raise TypeError( - f"field '{field_name}' has a DEFAULT annotation, but " - "DEFAULT annotations are not supported for TLV types." - ) - - if hasattr(field_type, "__asn1_root__"): - root_type = field_type.__asn1_root__ - if not isinstance( - root_type, - (declarative_asn1.Type.Sequence, declarative_asn1.Type.Set), - ): - raise TypeError(f"unsupported root type: {root_type}") - return declarative_asn1.AnnotatedType( - typing.cast(declarative_asn1.Type, root_type), annotation - ) - elif _is_union(field_type): - union_args = get_type_args(field_type) - if len(union_args) == 2 and NoneType in union_args: - # A Union between a type and None is an OPTIONAL - optional_type = ( - union_args[0] if union_args[1] is type(None) else union_args[1] - ) - if optional_type is TLV: - raise TypeError( - "optional TLV types (`TLV | None`) are not " - "currently supported" - ) - annotated_type = _normalize_field_type(optional_type, field_name) - - if not annotated_type.annotation.is_empty(): - raise TypeError( - "optional (`X | None`) types cannot have `X` " - "annotated: annotations must apply to the union " - "(i.e: `Annotated[X | None, annotation]`)" - ) - - if annotation.default is not None: - raise TypeError( - "optional (`X | None`) types should not have a DEFAULT " - "annotation" - ) - - rust_field_type = declarative_asn1.Type.Option(annotated_type) - - else: - # Otherwise, the Union is a CHOICE - if isinstance(annotation.encoding, Implicit): - # CHOICEs cannot be IMPLICIT. See X.680 section 31.2.9. - raise TypeError( - "CHOICE (`X | Y | ...`) types should not have an IMPLICIT " - "annotation" - ) - variants = [ - _type_to_variant(arg, field_name) - for arg in union_args - if arg is not type(None) - ] - - # Union types should either be all Variants - # (`Variant[..] | Variant[..] | etc`) or all non Variants - are_union_types_tagged = variants[0].tag_name is not None - if any( - (v.tag_name is not None) != are_union_types_tagged - for v in variants - ): - raise TypeError( - "When using `asn1.Variant` in a union, all the other " - "types in the union must also be `asn1.Variant`" - ) - - if are_union_types_tagged: - tags = {v.tag_name for v in variants} - if len(variants) != len(tags): - raise TypeError( - "When using `asn1.Variant` in a union, the tags used " - "must be unique" - ) - - rust_choice_type = declarative_asn1.Type.Choice(variants) - # If None is part of the union types, this is an OPTIONAL CHOICE - rust_field_type = ( - declarative_asn1.Type.Option( - declarative_asn1.AnnotatedType( - rust_choice_type, declarative_asn1.Annotation() - ) - ) - if NoneType in union_args - else rust_choice_type - ) - - elif get_type_origin(field_type) is builtins.list: - inner_type = _normalize_field_type( - get_type_args(field_type)[0], field_name - ) - rust_field_type = declarative_asn1.Type.SequenceOf(inner_type) - elif get_type_origin(field_type) is SetOf: - inner_type = _normalize_field_type( - get_type_args(field_type)[0], field_name - ) - rust_field_type = declarative_asn1.Type.SetOf(inner_type) - else: - rust_field_type = declarative_asn1.non_root_python_to_rust(field_type) - - return declarative_asn1.AnnotatedType(rust_field_type, annotation) - - -# Convert a type to a Variant. Used with types inside Union -# annotations (T1, T2, etc in `Union[T1, T2, ...]`). -def _type_to_variant( - t: typing.Any, field_name: str -) -> declarative_asn1.Variant: - is_annotated = get_type_origin(t) is Annotated - inner_type = get_type_args(t)[0] if is_annotated else t - - # Check if this is a Variant[T, Tag] type - if get_type_origin(inner_type) is Variant: - value_type, tag_literal = get_type_args(inner_type) - if get_type_origin(tag_literal) is not typing.Literal: - raise TypeError( - "When using `asn1.Variant` in a type annotation, the second " - "type parameter must be a `typing.Literal` type. E.g: " - '`Variant[int, typing.Literal["MyInt"]]`.' - ) - tag_name = get_type_args(tag_literal)[0] - - if hasattr(value_type, "__asn1_root__"): - rust_type = value_type.__asn1_root__ - else: - rust_type = declarative_asn1.non_root_python_to_rust(value_type) - - if is_annotated: - ann_type = declarative_asn1.AnnotatedType( - rust_type, - _extract_annotation(t.__metadata__, field_name), - ) - else: - ann_type = declarative_asn1.AnnotatedType( - rust_type, - declarative_asn1.Annotation(), - ) - - return declarative_asn1.Variant(Variant, ann_type, tag_name) - else: - # Plain type (not a tagged Variant) - return declarative_asn1.Variant( - inner_type, - _normalize_field_type(t, field_name), - None, - ) - - -def _annotate_fields( - raw_fields: dict[str, type], -) -> dict[str, declarative_asn1.AnnotatedType]: - fields = {} - for field_name, field_type in raw_fields.items(): - # Recursively normalize the field type into something that the - # Rust code can understand. - annotated_field_type = _normalize_field_type(field_type, field_name) - fields[field_name] = annotated_field_type - - return fields - - -def _register_asn1_sequence(cls: type[U]) -> None: - raw_fields = get_type_hints(cls, include_extras=True) - root = declarative_asn1.Type.Sequence(cls, _annotate_fields(raw_fields)) - - setattr(cls, "__asn1_root__", root) - - -def _register_asn1_set(cls: type[U]) -> None: - raw_fields = get_type_hints(cls, include_extras=True) - root = declarative_asn1.Type.Set(cls, _annotate_fields(raw_fields)) - - setattr(cls, "__asn1_root__", root) - - -# Due to https://github.com/python/mypy/issues/19731, we can't define an alias -# for `dataclass_transform` that conditionally points to `typing` or -# `typing_extensions` depending on the Python version (like we do for -# `get_type_hints`). -# We work around it by making the whole decorated class conditional on the -# Python version. -if sys.version_info < (3, 11): - - @typing_extensions.dataclass_transform(kw_only_default=True) - def sequence(cls: type[U]) -> type[U]: - # We use `dataclasses.dataclass` to add an __init__ method - # to the class with keyword-only parameters. - if sys.version_info >= (3, 10): - dataclass_cls = dataclasses.dataclass( - repr=False, - eq=False, - # `match_args` was added in Python 3.10 and defaults - # to True - match_args=False, - # `kw_only` was added in Python 3.10 and defaults to - # False - kw_only=True, - )(cls) - else: - dataclass_cls = dataclasses.dataclass( - repr=False, - eq=False, - )(cls) - _register_asn1_sequence(dataclass_cls) - return dataclass_cls - - @typing_extensions.dataclass_transform(kw_only_default=True) - def set(cls: type[U]) -> type[U]: - # We use `dataclasses.dataclass` to add an __init__ method - # to the class with keyword-only parameters. - if sys.version_info >= (3, 10): - dataclass_cls = dataclasses.dataclass( - repr=False, - eq=False, - # `match_args` was added in Python 3.10 and defaults - # to True - match_args=False, - # `kw_only` was added in Python 3.10 and defaults to - # False - kw_only=True, - )(cls) - else: - dataclass_cls = dataclasses.dataclass( - repr=False, - eq=False, - )(cls) - _register_asn1_set(dataclass_cls) - return dataclass_cls - -else: - - @typing.dataclass_transform(kw_only_default=True) - def sequence(cls: type[U]) -> type[U]: - # Only add an __init__ method, with keyword-only - # parameters. - dataclass_cls = dataclasses.dataclass( - repr=False, - eq=False, - match_args=False, - kw_only=True, - )(cls) - _register_asn1_sequence(dataclass_cls) - return dataclass_cls - - @typing.dataclass_transform(kw_only_default=True) - def set(cls: type[U]) -> type[U]: - # Only add an __init__ method, with keyword-only - # parameters. - dataclass_cls = dataclasses.dataclass( - repr=False, - eq=False, - match_args=False, - kw_only=True, - )(cls) - _register_asn1_set(dataclass_cls) - return dataclass_cls - - -# TODO: replace with `Default[U]` once the min Python version is >= 3.12 -@dataclasses.dataclass(frozen=True) -class Default(typing.Generic[U]): - value: U - - -SetOf = declarative_asn1.SetOf - -Explicit = declarative_asn1.Encoding.Explicit -Implicit = declarative_asn1.Encoding.Implicit -Size = declarative_asn1.Size - -PrintableString = declarative_asn1.PrintableString -IA5String = declarative_asn1.IA5String -UTCTime = declarative_asn1.UTCTime -GeneralizedTime = declarative_asn1.GeneralizedTime -BitString = declarative_asn1.BitString -TLV = declarative_asn1.Tlv -Null = declarative_asn1.Null diff --git a/venv/lib/python3.9/site-packages/cryptography/hazmat/backends/__init__.py b/venv/lib/python3.9/site-packages/cryptography/hazmat/backends/__init__.py deleted file mode 100644 index b4400aa..0000000 --- a/venv/lib/python3.9/site-packages/cryptography/hazmat/backends/__init__.py +++ /dev/null @@ -1,13 +0,0 @@ -# This file is dual licensed under the terms of the Apache License, Version -# 2.0, and the BSD License. See the LICENSE file in the root of this repository -# for complete details. - -from __future__ import annotations - -from typing import Any - - -def default_backend() -> Any: - from cryptography.hazmat.backends.openssl.backend import backend - - return backend diff --git a/venv/lib/python3.9/site-packages/cryptography/hazmat/backends/openssl/__init__.py b/venv/lib/python3.9/site-packages/cryptography/hazmat/backends/openssl/__init__.py deleted file mode 100644 index 51b0447..0000000 --- a/venv/lib/python3.9/site-packages/cryptography/hazmat/backends/openssl/__init__.py +++ /dev/null @@ -1,9 +0,0 @@ -# This file is dual licensed under the terms of the Apache License, Version -# 2.0, and the BSD License. See the LICENSE file in the root of this repository -# for complete details. - -from __future__ import annotations - -from cryptography.hazmat.backends.openssl.backend import backend - -__all__ = ["backend"] diff --git a/venv/lib/python3.9/site-packages/cryptography/hazmat/backends/openssl/backend.py b/venv/lib/python3.9/site-packages/cryptography/hazmat/backends/openssl/backend.py deleted file mode 100644 index d245a42..0000000 --- a/venv/lib/python3.9/site-packages/cryptography/hazmat/backends/openssl/backend.py +++ /dev/null @@ -1,310 +0,0 @@ -# This file is dual licensed under the terms of the Apache License, Version -# 2.0, and the BSD License. See the LICENSE file in the root of this repository -# for complete details. - -from __future__ import annotations - -from cryptography.hazmat.bindings._rust import openssl as rust_openssl -from cryptography.hazmat.bindings.openssl import binding -from cryptography.hazmat.primitives import hashes -from cryptography.hazmat.primitives._asymmetric import AsymmetricPadding -from cryptography.hazmat.primitives.asymmetric import ec -from cryptography.hazmat.primitives.asymmetric import utils as asym_utils -from cryptography.hazmat.primitives.asymmetric.padding import ( - MGF1, - OAEP, - PSS, - PKCS1v15, -) -from cryptography.hazmat.primitives.ciphers import ( - CipherAlgorithm, -) -from cryptography.hazmat.primitives.ciphers.algorithms import ( - AES, -) -from cryptography.hazmat.primitives.ciphers.modes import ( - CBC, - Mode, -) - - -class Backend: - """ - OpenSSL API binding interfaces. - """ - - name = "openssl" - - # TripleDES encryption is disallowed/deprecated throughout 2023 in - # FIPS 140-3. To keep it simple we denylist any use of TripleDES (TDEA). - _fips_ciphers = (AES,) - # Sometimes SHA1 is still permissible. That logic is contained - # within the various *_supported methods. - _fips_hashes = ( - hashes.SHA224, - hashes.SHA256, - hashes.SHA384, - hashes.SHA512, - hashes.SHA512_224, - hashes.SHA512_256, - hashes.SHA3_224, - hashes.SHA3_256, - hashes.SHA3_384, - hashes.SHA3_512, - hashes.SHAKE128, - hashes.SHAKE256, - ) - _fips_ecdh_curves = ( - ec.SECP224R1, - ec.SECP256R1, - ec.SECP384R1, - ec.SECP521R1, - ) - _fips_rsa_min_key_size = 2048 - _fips_rsa_min_public_exponent = 65537 - _fips_dsa_min_modulus = 1 << 2048 - _fips_dh_min_key_size = 2048 - _fips_dh_min_modulus = 1 << _fips_dh_min_key_size - - def __init__(self) -> None: - self._binding = binding.Binding() - self._ffi = self._binding.ffi - self._lib = self._binding.lib - self._fips_enabled = rust_openssl.is_fips_enabled() - - def __repr__(self) -> str: - return ( - f"" - ) - - def openssl_assert(self, ok: bool) -> None: - return binding._openssl_assert(ok) - - def _enable_fips(self) -> None: - # This function enables FIPS mode for OpenSSL 3.0.0 on installs that - # have the FIPS provider installed properly. - rust_openssl.enable_fips(rust_openssl._providers) - assert rust_openssl.is_fips_enabled() - self._fips_enabled = rust_openssl.is_fips_enabled() - - def openssl_version_text(self) -> str: - """ - Friendly string name of the loaded OpenSSL library. This is not - necessarily the same version as it was compiled against. - - Example: OpenSSL 3.2.1 30 Jan 2024 - """ - return rust_openssl.openssl_version_text() - - def openssl_version_number(self) -> int: - return rust_openssl.openssl_version() - - def hash_supported(self, algorithm: hashes.HashAlgorithm) -> bool: - if self._fips_enabled and not isinstance(algorithm, self._fips_hashes): - return False - - return rust_openssl.hashes.hash_supported(algorithm) - - def signature_hash_supported( - self, algorithm: hashes.HashAlgorithm - ) -> bool: - # Dedicated check for hashing algorithm use in message digest for - # signatures, e.g. RSA PKCS#1 v1.5 SHA1 (sha1WithRSAEncryption). - if self._fips_enabled and isinstance(algorithm, hashes.SHA1): - return False - return self.hash_supported(algorithm) - - def scrypt_supported(self) -> bool: - if self._fips_enabled: - return False - else: - return hasattr(rust_openssl.kdf.Scrypt, "derive") - - def argon2_supported(self) -> bool: - if self._fips_enabled: - return False - else: - return hasattr(rust_openssl.kdf.Argon2id, "derive") - - def hmac_supported(self, algorithm: hashes.HashAlgorithm) -> bool: - # FIPS mode still allows SHA1 for HMAC - if self._fips_enabled and isinstance(algorithm, hashes.SHA1): - return True - if rust_openssl.CRYPTOGRAPHY_IS_AWSLC: - return isinstance( - algorithm, - ( - hashes.MD5, - hashes.SHA1, - hashes.SHA224, - hashes.SHA256, - hashes.SHA384, - hashes.SHA512, - hashes.SHA512_224, - hashes.SHA512_256, - ), - ) - return self.hash_supported(algorithm) - - def cipher_supported(self, cipher: CipherAlgorithm, mode: Mode) -> bool: - if self._fips_enabled: - # FIPS mode requires AES. TripleDES is disallowed/deprecated in - # FIPS 140-3. - if not isinstance(cipher, self._fips_ciphers): - return False - - return rust_openssl.ciphers.cipher_supported(cipher, mode) - - def pbkdf2_hmac_supported(self, algorithm: hashes.HashAlgorithm) -> bool: - return self.hmac_supported(algorithm) - - def _consume_errors(self) -> list[rust_openssl.OpenSSLError]: - return rust_openssl.capture_error_stack() - - def _oaep_hash_supported(self, algorithm: hashes.HashAlgorithm) -> bool: - if self._fips_enabled and isinstance(algorithm, hashes.SHA1): - return False - - return isinstance( - algorithm, - ( - hashes.SHA1, - hashes.SHA224, - hashes.SHA256, - hashes.SHA384, - hashes.SHA512, - ), - ) - - def rsa_padding_supported(self, padding: AsymmetricPadding) -> bool: - if isinstance(padding, PKCS1v15): - return True - elif isinstance(padding, PSS) and isinstance(padding._mgf, MGF1): - # FIPS 186-4 only allows salt length == digest length for PSS - # It is technically acceptable to set an explicit salt length - # equal to the digest length and this will incorrectly fail, but - # since we don't do that in the tests and this method is - # private, we'll ignore that until we need to do otherwise. - if ( - self._fips_enabled - and padding._salt_length != PSS.DIGEST_LENGTH - ): - return False - return self.hash_supported(padding._mgf._algorithm) - elif isinstance(padding, OAEP) and isinstance(padding._mgf, MGF1): - return self._oaep_hash_supported( - padding._mgf._algorithm - ) and self._oaep_hash_supported(padding._algorithm) - else: - return False - - def rsa_encryption_supported(self, padding: AsymmetricPadding) -> bool: - if self._fips_enabled and isinstance(padding, PKCS1v15): - return False - else: - return self.rsa_padding_supported(padding) - - def dsa_supported(self) -> bool: - return ( - not rust_openssl.CRYPTOGRAPHY_IS_BORINGSSL - and not self._fips_enabled - ) - - def dsa_hash_supported(self, algorithm: hashes.HashAlgorithm) -> bool: - if not self.dsa_supported(): - return False - return self.signature_hash_supported(algorithm) - - def cmac_algorithm_supported(self, algorithm) -> bool: - return self.cipher_supported( - algorithm, CBC(b"\x00" * algorithm.block_size) - ) - - def elliptic_curve_supported(self, curve: ec.EllipticCurve) -> bool: - if self._fips_enabled and not isinstance( - curve, self._fips_ecdh_curves - ): - return False - - return rust_openssl.ec.curve_supported(curve) - - def elliptic_curve_signature_algorithm_supported( - self, - signature_algorithm: ec.EllipticCurveSignatureAlgorithm, - curve: ec.EllipticCurve, - ) -> bool: - # We only support ECDSA right now. - if not isinstance(signature_algorithm, ec.ECDSA): - return False - - return self.elliptic_curve_supported(curve) and ( - isinstance(signature_algorithm.algorithm, asym_utils.Prehashed) - or self.hash_supported(signature_algorithm.algorithm) - ) - - def elliptic_curve_exchange_algorithm_supported( - self, algorithm: ec.ECDH, curve: ec.EllipticCurve - ) -> bool: - return self.elliptic_curve_supported(curve) and isinstance( - algorithm, ec.ECDH - ) - - def dh_supported(self) -> bool: - return ( - not rust_openssl.CRYPTOGRAPHY_IS_BORINGSSL - and not rust_openssl.CRYPTOGRAPHY_IS_AWSLC - ) - - def dh_x942_serialization_supported(self) -> bool: - return self._lib.Cryptography_HAS_EVP_PKEY_DHX == 1 - - def x25519_supported(self) -> bool: - return not self._fips_enabled - - def x448_supported(self) -> bool: - if self._fips_enabled: - return False - return ( - not rust_openssl.CRYPTOGRAPHY_IS_LIBRESSL - and not rust_openssl.CRYPTOGRAPHY_IS_BORINGSSL - and not rust_openssl.CRYPTOGRAPHY_IS_AWSLC - ) - - def mlkem_supported(self) -> bool: - return ( - rust_openssl.CRYPTOGRAPHY_IS_AWSLC - or rust_openssl.CRYPTOGRAPHY_IS_BORINGSSL - ) - - def mldsa_supported(self) -> bool: - return ( - rust_openssl.CRYPTOGRAPHY_IS_AWSLC - or rust_openssl.CRYPTOGRAPHY_IS_BORINGSSL - ) - - def ed25519_supported(self) -> bool: - return True - - def ed448_supported(self) -> bool: - return ( - not rust_openssl.CRYPTOGRAPHY_IS_LIBRESSL - and not rust_openssl.CRYPTOGRAPHY_IS_BORINGSSL - and not rust_openssl.CRYPTOGRAPHY_IS_AWSLC - ) - - def ecdsa_deterministic_supported(self) -> bool: - return ( - rust_openssl.CRYPTOGRAPHY_OPENSSL_320_OR_GREATER - and not self._fips_enabled - ) - - def poly1305_supported(self) -> bool: - return not self._fips_enabled - - def pkcs7_supported(self) -> bool: - return True - - -backend = Backend() diff --git a/venv/lib/python3.9/site-packages/cryptography/hazmat/bindings/__init__.py b/venv/lib/python3.9/site-packages/cryptography/hazmat/bindings/__init__.py deleted file mode 100644 index b509336..0000000 --- a/venv/lib/python3.9/site-packages/cryptography/hazmat/bindings/__init__.py +++ /dev/null @@ -1,3 +0,0 @@ -# This file is dual licensed under the terms of the Apache License, Version -# 2.0, and the BSD License. See the LICENSE file in the root of this repository -# for complete details. diff --git a/venv/lib/python3.9/site-packages/cryptography/hazmat/bindings/_rust.abi3.so b/venv/lib/python3.9/site-packages/cryptography/hazmat/bindings/_rust.abi3.so deleted file mode 100755 index 0082e9a..0000000 Binary files a/venv/lib/python3.9/site-packages/cryptography/hazmat/bindings/_rust.abi3.so and /dev/null differ diff --git a/venv/lib/python3.9/site-packages/cryptography/hazmat/bindings/_rust/__init__.pyi b/venv/lib/python3.9/site-packages/cryptography/hazmat/bindings/_rust/__init__.pyi deleted file mode 100644 index c3148f1..0000000 --- a/venv/lib/python3.9/site-packages/cryptography/hazmat/bindings/_rust/__init__.pyi +++ /dev/null @@ -1,67 +0,0 @@ -# This file is dual licensed under the terms of the Apache License, Version -# 2.0, and the BSD License. See the LICENSE file in the root of this repository -# for complete details. - -import typing - -from cryptography.hazmat.primitives import padding -from cryptography.hazmat.primitives._serialization import ( - KeySerializationEncryptionBuilder, -) -from cryptography.utils import Buffer - -class PKCS7PaddingContext(padding.PaddingContext): - def __init__(self, block_size: int) -> None: ... - def update(self, data: Buffer) -> bytes: ... - def finalize(self) -> bytes: ... - -class ANSIX923PaddingContext(padding.PaddingContext): - def __init__(self, block_size: int) -> None: ... - def update(self, data: Buffer) -> bytes: ... - def finalize(self) -> bytes: ... - -class PKCS7UnpaddingContext(padding.PaddingContext): - def __init__(self, block_size: int) -> None: ... - def update(self, data: Buffer) -> bytes: ... - def finalize(self) -> bytes: ... - -class ANSIX923UnpaddingContext(padding.PaddingContext): - def __init__(self, block_size: int) -> None: ... - def update(self, data: Buffer) -> bytes: ... - def finalize(self) -> bytes: ... - -class Encoding: - PEM: typing.ClassVar[Encoding] - DER: typing.ClassVar[Encoding] - OpenSSH: typing.ClassVar[Encoding] - Raw: typing.ClassVar[Encoding] - X962: typing.ClassVar[Encoding] - SMIME: typing.ClassVar[Encoding] - -class PrivateFormat: - PKCS8: typing.ClassVar[PrivateFormat] - TraditionalOpenSSL: typing.ClassVar[PrivateFormat] - Raw: typing.ClassVar[PrivateFormat] - OpenSSH: typing.ClassVar[PrivateFormat] - PKCS12: typing.ClassVar[PrivateFormat] - def encryption_builder(self) -> KeySerializationEncryptionBuilder: ... - -class PublicFormat: - SubjectPublicKeyInfo: typing.ClassVar[PublicFormat] - PKCS1: typing.ClassVar[PublicFormat] - OpenSSH: typing.ClassVar[PublicFormat] - Raw: typing.ClassVar[PublicFormat] - CompressedPoint: typing.ClassVar[PublicFormat] - UncompressedPoint: typing.ClassVar[PublicFormat] - -class ParameterFormat: - PKCS3: typing.ClassVar[ParameterFormat] - -class ObjectIdentifier: - def __init__(self, value: str) -> None: ... - @property - def dotted_string(self) -> str: ... - @property - def _name(self) -> str: ... - -T = typing.TypeVar("T") diff --git a/venv/lib/python3.9/site-packages/cryptography/hazmat/bindings/_rust/_openssl.pyi b/venv/lib/python3.9/site-packages/cryptography/hazmat/bindings/_rust/_openssl.pyi deleted file mode 100644 index 3d4ea4e..0000000 --- a/venv/lib/python3.9/site-packages/cryptography/hazmat/bindings/_rust/_openssl.pyi +++ /dev/null @@ -1,8 +0,0 @@ -# This file is dual licensed under the terms of the Apache License, Version -# 2.0, and the BSD License. See the LICENSE file in the root of this repository -# for complete details. - -import typing - -lib: typing.Any -ffi: typing.Any diff --git a/venv/lib/python3.9/site-packages/cryptography/hazmat/bindings/_rust/asn1.pyi b/venv/lib/python3.9/site-packages/cryptography/hazmat/bindings/_rust/asn1.pyi deleted file mode 100644 index 3b5f208..0000000 --- a/venv/lib/python3.9/site-packages/cryptography/hazmat/bindings/_rust/asn1.pyi +++ /dev/null @@ -1,7 +0,0 @@ -# This file is dual licensed under the terms of the Apache License, Version -# 2.0, and the BSD License. See the LICENSE file in the root of this repository -# for complete details. - -def decode_dss_signature(signature: bytes) -> tuple[int, int]: ... -def encode_dss_signature(r: int, s: int) -> bytes: ... -def parse_spki_for_data(data: bytes) -> bytes: ... diff --git a/venv/lib/python3.9/site-packages/cryptography/hazmat/bindings/_rust/declarative_asn1.pyi b/venv/lib/python3.9/site-packages/cryptography/hazmat/bindings/_rust/declarative_asn1.pyi deleted file mode 100644 index a4c0cb6..0000000 --- a/venv/lib/python3.9/site-packages/cryptography/hazmat/bindings/_rust/declarative_asn1.pyi +++ /dev/null @@ -1,127 +0,0 @@ -# This file is dual licensed under the terms of the Apache License, Version -# 2.0, and the BSD License. See the LICENSE file in the root of this repository -# for complete details. - -import datetime -import typing - -def decode_der(cls: type, value: bytes) -> typing.Any: ... -def encode_der(value: typing.Any) -> bytes: ... -def non_root_python_to_rust(cls: type) -> Type: ... - -# Type is a Rust enum with tuple variants. For now, we express the type -# annotations like this: -class Type: - Sequence: typing.ClassVar[type] - SequenceOf: typing.ClassVar[type] - Set: typing.ClassVar[type] - SetOf: typing.ClassVar[type] - Option: typing.ClassVar[type] - Choice: typing.ClassVar[type] - PyBool: typing.ClassVar[type] - PyInt: typing.ClassVar[type] - PyBytes: typing.ClassVar[type] - PyStr: typing.ClassVar[type] - -class Annotation: - default: typing.Any | None - encoding: Encoding | None - size: Size | None - def __new__( - cls, - default: typing.Any | None = None, - encoding: Encoding | None = None, - size: Size | None = None, - ) -> Annotation: ... - def is_empty(self) -> bool: ... - -# Encoding is a Rust enum with tuple variants. For now, we express the type -# annotations like this: -class Encoding: - Implicit: typing.ClassVar[type] - Explicit: typing.ClassVar[type] - -class Size: - min: int - max: int | None - - def __new__(cls, min: int, max: int | None) -> Size: ... - @staticmethod - def exact(n: int) -> Size: ... - -class AnnotatedType: - inner: Type - annotation: Annotation - - def __new__(cls, inner: Type, annotation: Annotation) -> AnnotatedType: ... - -class AnnotatedTypeObject: - annotated_type: AnnotatedType - value: typing.Any - - def __new__( - cls, annotated_type: AnnotatedType, value: typing.Any - ) -> AnnotatedTypeObject: ... - -class Variant: - python_class: type - ann_type: AnnotatedType - tag_name: str | None - - def __new__( - cls, - python_class: type, - ann_type: AnnotatedType, - tag_name: str | None, - ) -> Variant: ... - -class PrintableString: - def __new__(cls, inner: str) -> PrintableString: ... - def __repr__(self) -> str: ... - def __eq__(self, other: object) -> bool: ... - def as_str(self) -> str: ... - -class IA5String: - def __new__(cls, inner: str) -> IA5String: ... - def __repr__(self) -> str: ... - def __eq__(self, other: object) -> bool: ... - def as_str(self) -> str: ... - -class UTCTime: - def __new__(cls, inner: datetime.datetime) -> UTCTime: ... - def __repr__(self) -> str: ... - def __eq__(self, other: object) -> bool: ... - def as_datetime(self) -> datetime.datetime: ... - -class GeneralizedTime: - def __new__(cls, inner: datetime.datetime) -> GeneralizedTime: ... - def __repr__(self) -> str: ... - def __eq__(self, other: object) -> bool: ... - def as_datetime(self) -> datetime.datetime: ... - -class BitString: - def __new__(cls, data: bytes, padding_bits: int) -> BitString: ... - def __repr__(self) -> str: ... - def __eq__(self, other: object) -> bool: ... - def as_bytes(self) -> bytes: ... - def padding_bits(self) -> int: ... - -class Tlv: - @property - def tag_bytes(self) -> bytes: ... - @property - def data(self) -> memoryview: ... - def parse(self, cls: type): ... - -T = typing.TypeVar("T") - -class SetOf(typing.Generic[T]): - def __new__(cls, inner: list[T]) -> SetOf[T]: ... - def as_list(self) -> list[T]: ... - def __eq__(self, other: object) -> bool: ... - def __repr__(self) -> str: ... - -class Null: - def __new__(cls) -> Null: ... - def __repr__(self) -> str: ... - def __eq__(self, other: object) -> bool: ... diff --git a/venv/lib/python3.9/site-packages/cryptography/hazmat/bindings/_rust/exceptions.pyi b/venv/lib/python3.9/site-packages/cryptography/hazmat/bindings/_rust/exceptions.pyi deleted file mode 100644 index 09f46b1..0000000 --- a/venv/lib/python3.9/site-packages/cryptography/hazmat/bindings/_rust/exceptions.pyi +++ /dev/null @@ -1,17 +0,0 @@ -# This file is dual licensed under the terms of the Apache License, Version -# 2.0, and the BSD License. See the LICENSE file in the root of this repository -# for complete details. - -class _Reasons: - BACKEND_MISSING_INTERFACE: _Reasons - UNSUPPORTED_HASH: _Reasons - UNSUPPORTED_CIPHER: _Reasons - UNSUPPORTED_PADDING: _Reasons - UNSUPPORTED_MGF: _Reasons - UNSUPPORTED_PUBLIC_KEY_ALGORITHM: _Reasons - UNSUPPORTED_ELLIPTIC_CURVE: _Reasons - UNSUPPORTED_SERIALIZATION: _Reasons - UNSUPPORTED_X509: _Reasons - UNSUPPORTED_EXCHANGE_ALGORITHM: _Reasons - UNSUPPORTED_DIFFIE_HELLMAN: _Reasons - UNSUPPORTED_MAC: _Reasons diff --git a/venv/lib/python3.9/site-packages/cryptography/hazmat/bindings/_rust/ocsp.pyi b/venv/lib/python3.9/site-packages/cryptography/hazmat/bindings/_rust/ocsp.pyi deleted file mode 100644 index 103e96c..0000000 --- a/venv/lib/python3.9/site-packages/cryptography/hazmat/bindings/_rust/ocsp.pyi +++ /dev/null @@ -1,117 +0,0 @@ -# This file is dual licensed under the terms of the Apache License, Version -# 2.0, and the BSD License. See the LICENSE file in the root of this repository -# for complete details. - -import datetime -from collections.abc import Iterator - -from cryptography import x509 -from cryptography.hazmat.primitives import hashes, serialization -from cryptography.hazmat.primitives.asymmetric.types import PrivateKeyTypes -from cryptography.x509 import ocsp - -class OCSPRequest: - @property - def issuer_key_hash(self) -> bytes: ... - @property - def issuer_name_hash(self) -> bytes: ... - @property - def hash_algorithm(self) -> hashes.HashAlgorithm: ... - @property - def serial_number(self) -> int: ... - def public_bytes(self, encoding: serialization.Encoding) -> bytes: ... - @property - def extensions(self) -> x509.Extensions: ... - -class OCSPResponse: - @property - def responses(self) -> Iterator[OCSPSingleResponse]: ... - @property - def response_status(self) -> ocsp.OCSPResponseStatus: ... - @property - def signature_algorithm_oid(self) -> x509.ObjectIdentifier: ... - @property - def signature_hash_algorithm( - self, - ) -> hashes.HashAlgorithm | None: ... - @property - def signature(self) -> bytes: ... - @property - def tbs_response_bytes(self) -> bytes: ... - @property - def certificates(self) -> list[x509.Certificate]: ... - @property - def responder_key_hash(self) -> bytes | None: ... - @property - def responder_name(self) -> x509.Name | None: ... - @property - def produced_at(self) -> datetime.datetime: ... - @property - def produced_at_utc(self) -> datetime.datetime: ... - @property - def certificate_status(self) -> ocsp.OCSPCertStatus: ... - @property - def revocation_time(self) -> datetime.datetime | None: ... - @property - def revocation_time_utc(self) -> datetime.datetime | None: ... - @property - def revocation_reason(self) -> x509.ReasonFlags | None: ... - @property - def this_update(self) -> datetime.datetime: ... - @property - def this_update_utc(self) -> datetime.datetime: ... - @property - def next_update(self) -> datetime.datetime | None: ... - @property - def next_update_utc(self) -> datetime.datetime | None: ... - @property - def issuer_key_hash(self) -> bytes: ... - @property - def issuer_name_hash(self) -> bytes: ... - @property - def hash_algorithm(self) -> hashes.HashAlgorithm: ... - @property - def serial_number(self) -> int: ... - @property - def extensions(self) -> x509.Extensions: ... - @property - def single_extensions(self) -> x509.Extensions: ... - def public_bytes(self, encoding: serialization.Encoding) -> bytes: ... - -class OCSPSingleResponse: - @property - def certificate_status(self) -> ocsp.OCSPCertStatus: ... - @property - def revocation_time(self) -> datetime.datetime | None: ... - @property - def revocation_time_utc(self) -> datetime.datetime | None: ... - @property - def revocation_reason(self) -> x509.ReasonFlags | None: ... - @property - def this_update(self) -> datetime.datetime: ... - @property - def this_update_utc(self) -> datetime.datetime: ... - @property - def next_update(self) -> datetime.datetime | None: ... - @property - def next_update_utc(self) -> datetime.datetime | None: ... - @property - def issuer_key_hash(self) -> bytes: ... - @property - def issuer_name_hash(self) -> bytes: ... - @property - def hash_algorithm(self) -> hashes.HashAlgorithm: ... - @property - def serial_number(self) -> int: ... - -def load_der_ocsp_request(data: bytes) -> ocsp.OCSPRequest: ... -def load_der_ocsp_response(data: bytes) -> ocsp.OCSPResponse: ... -def create_ocsp_request( - builder: ocsp.OCSPRequestBuilder, -) -> ocsp.OCSPRequest: ... -def create_ocsp_response( - status: ocsp.OCSPResponseStatus, - builder: ocsp.OCSPResponseBuilder | None, - private_key: PrivateKeyTypes | None, - hash_algorithm: hashes.HashAlgorithm | None, -) -> ocsp.OCSPResponse: ... diff --git a/venv/lib/python3.9/site-packages/cryptography/hazmat/bindings/_rust/openssl/__init__.pyi b/venv/lib/python3.9/site-packages/cryptography/hazmat/bindings/_rust/openssl/__init__.pyi deleted file mode 100644 index 404a300..0000000 --- a/venv/lib/python3.9/site-packages/cryptography/hazmat/bindings/_rust/openssl/__init__.pyi +++ /dev/null @@ -1,80 +0,0 @@ -# This file is dual licensed under the terms of the Apache License, Version -# 2.0, and the BSD License. See the LICENSE file in the root of this repository -# for complete details. - -import typing - -from cryptography.hazmat.bindings._rust.openssl import ( - aead, - ciphers, - cmac, - dh, - dsa, - ec, - ed448, - ed25519, - hashes, - hmac, - hpke, - kdf, - keys, - mldsa, - mlkem, - poly1305, - rsa, - x448, - x25519, -) - -__all__ = [ - "aead", - "ciphers", - "cmac", - "dh", - "dsa", - "ec", - "ed448", - "ed25519", - "hashes", - "hmac", - "hpke", - "kdf", - "keys", - "mldsa", - "mlkem", - "openssl_version", - "openssl_version_text", - "poly1305", - "raise_openssl_error", - "rsa", - "x448", - "x25519", -] - -CRYPTOGRAPHY_IS_LIBRESSL: bool -CRYPTOGRAPHY_IS_BORINGSSL: bool -CRYPTOGRAPHY_IS_AWSLC: bool -CRYPTOGRAPHY_OPENSSL_309_OR_GREATER: bool -CRYPTOGRAPHY_OPENSSL_320_OR_GREATER: bool -CRYPTOGRAPHY_OPENSSL_330_OR_GREATER: bool -CRYPTOGRAPHY_OPENSSL_350_OR_GREATER: bool - -class Providers: ... - -_legacy_provider_loaded: bool -_providers: Providers - -def openssl_version() -> int: ... -def openssl_version_text() -> str: ... -def raise_openssl_error() -> typing.NoReturn: ... -def capture_error_stack() -> list[OpenSSLError]: ... -def is_fips_enabled() -> bool: ... -def enable_fips(providers: Providers) -> None: ... - -class OpenSSLError: - @property - def lib(self) -> int: ... - @property - def reason(self) -> int: ... - @property - def reason_text(self) -> bytes: ... diff --git a/venv/lib/python3.9/site-packages/cryptography/hazmat/bindings/_rust/openssl/aead.pyi b/venv/lib/python3.9/site-packages/cryptography/hazmat/bindings/_rust/openssl/aead.pyi deleted file mode 100644 index eb44608..0000000 --- a/venv/lib/python3.9/site-packages/cryptography/hazmat/bindings/_rust/openssl/aead.pyi +++ /dev/null @@ -1,189 +0,0 @@ -# This file is dual licensed under the terms of the Apache License, Version -# 2.0, and the BSD License. See the LICENSE file in the root of this repository -# for complete details. - -from collections.abc import Sequence - -from cryptography.utils import Buffer - -class AESGCM: - def __init__(self, key: Buffer) -> None: ... - @staticmethod - def generate_key(bit_length: int) -> bytes: ... - def encrypt( - self, - nonce: Buffer, - data: Buffer, - associated_data: Buffer | None, - ) -> bytes: ... - def decrypt( - self, - nonce: Buffer, - data: Buffer, - associated_data: Buffer | None, - ) -> bytes: ... - def encrypt_into( - self, - nonce: Buffer, - data: Buffer, - associated_data: Buffer | None, - buf: Buffer, - ) -> int: ... - def decrypt_into( - self, - nonce: Buffer, - data: Buffer, - associated_data: Buffer | None, - buf: Buffer, - ) -> int: ... - -class ChaCha20Poly1305: - def __init__(self, key: Buffer) -> None: ... - @staticmethod - def generate_key() -> bytes: ... - def encrypt( - self, - nonce: Buffer, - data: Buffer, - associated_data: Buffer | None, - ) -> bytes: ... - def encrypt_into( - self, - nonce: Buffer, - data: Buffer, - associated_data: Buffer | None, - buf: Buffer, - ) -> int: ... - def decrypt( - self, - nonce: Buffer, - data: Buffer, - associated_data: Buffer | None, - ) -> bytes: ... - def decrypt_into( - self, - nonce: Buffer, - data: Buffer, - associated_data: Buffer | None, - buf: Buffer, - ) -> int: ... - -class AESCCM: - def __init__(self, key: Buffer, tag_length: int = 16) -> None: ... - @staticmethod - def generate_key(bit_length: int) -> bytes: ... - def encrypt( - self, - nonce: Buffer, - data: Buffer, - associated_data: Buffer | None, - ) -> bytes: ... - def encrypt_into( - self, - nonce: Buffer, - data: Buffer, - associated_data: Buffer | None, - buf: Buffer, - ) -> int: ... - def decrypt( - self, - nonce: Buffer, - data: Buffer, - associated_data: Buffer | None, - ) -> bytes: ... - def decrypt_into( - self, - nonce: Buffer, - data: Buffer, - associated_data: Buffer | None, - buf: Buffer, - ) -> int: ... - -class AESSIV: - def __init__(self, key: Buffer) -> None: ... - @staticmethod - def generate_key(bit_length: int) -> bytes: ... - def encrypt( - self, - data: Buffer, - associated_data: Sequence[Buffer] | None, - ) -> bytes: ... - def encrypt_into( - self, - data: Buffer, - associated_data: Sequence[Buffer] | None, - buf: Buffer, - ) -> int: ... - def decrypt( - self, - data: Buffer, - associated_data: Sequence[Buffer] | None, - ) -> bytes: ... - def decrypt_into( - self, - data: Buffer, - associated_data: Sequence[Buffer] | None, - buf: Buffer, - ) -> int: ... - -class AESOCB3: - def __init__(self, key: Buffer) -> None: ... - @staticmethod - def generate_key(bit_length: int) -> bytes: ... - def encrypt( - self, - nonce: Buffer, - data: Buffer, - associated_data: Buffer | None, - ) -> bytes: ... - def encrypt_into( - self, - nonce: Buffer, - data: Buffer, - associated_data: Buffer | None, - buf: Buffer, - ) -> int: ... - def decrypt( - self, - nonce: Buffer, - data: Buffer, - associated_data: Buffer | None, - ) -> bytes: ... - def decrypt_into( - self, - nonce: Buffer, - data: Buffer, - associated_data: Buffer | None, - buf: Buffer, - ) -> int: ... - -class AESGCMSIV: - def __init__(self, key: Buffer) -> None: ... - @staticmethod - def generate_key(bit_length: int) -> bytes: ... - def encrypt( - self, - nonce: Buffer, - data: Buffer, - associated_data: Buffer | None, - ) -> bytes: ... - def encrypt_into( - self, - nonce: Buffer, - data: Buffer, - associated_data: Buffer | None, - buf: Buffer, - ) -> int: ... - def decrypt( - self, - nonce: Buffer, - data: Buffer, - associated_data: Buffer | None, - ) -> bytes: ... - def decrypt_into( - self, - nonce: Buffer, - data: Buffer, - associated_data: Buffer | None, - buf: Buffer, - ) -> int: ... diff --git a/venv/lib/python3.9/site-packages/cryptography/hazmat/bindings/_rust/openssl/ciphers.pyi b/venv/lib/python3.9/site-packages/cryptography/hazmat/bindings/_rust/openssl/ciphers.pyi deleted file mode 100644 index a48fb01..0000000 --- a/venv/lib/python3.9/site-packages/cryptography/hazmat/bindings/_rust/openssl/ciphers.pyi +++ /dev/null @@ -1,38 +0,0 @@ -# This file is dual licensed under the terms of the Apache License, Version -# 2.0, and the BSD License. See the LICENSE file in the root of this repository -# for complete details. - -import typing - -from cryptography.hazmat.primitives import ciphers -from cryptography.hazmat.primitives.ciphers import modes - -@typing.overload -def create_encryption_ctx( - algorithm: ciphers.CipherAlgorithm, mode: modes.ModeWithAuthenticationTag -) -> ciphers.AEADEncryptionContext: ... -@typing.overload -def create_encryption_ctx( - algorithm: ciphers.CipherAlgorithm, mode: modes.Mode | None -) -> ciphers.CipherContext: ... -@typing.overload -def create_decryption_ctx( - algorithm: ciphers.CipherAlgorithm, mode: modes.ModeWithAuthenticationTag -) -> ciphers.AEADDecryptionContext: ... -@typing.overload -def create_decryption_ctx( - algorithm: ciphers.CipherAlgorithm, mode: modes.Mode | None -) -> ciphers.CipherContext: ... -def cipher_supported( - algorithm: ciphers.CipherAlgorithm, mode: modes.Mode -) -> bool: ... -def _advance( - ctx: ciphers.AEADEncryptionContext | ciphers.AEADDecryptionContext, n: int -) -> None: ... -def _advance_aad( - ctx: ciphers.AEADEncryptionContext | ciphers.AEADDecryptionContext, n: int -) -> None: ... - -class CipherContext: ... -class AEADEncryptionContext: ... -class AEADDecryptionContext: ... diff --git a/venv/lib/python3.9/site-packages/cryptography/hazmat/bindings/_rust/openssl/cmac.pyi b/venv/lib/python3.9/site-packages/cryptography/hazmat/bindings/_rust/openssl/cmac.pyi deleted file mode 100644 index 9c03508..0000000 --- a/venv/lib/python3.9/site-packages/cryptography/hazmat/bindings/_rust/openssl/cmac.pyi +++ /dev/null @@ -1,18 +0,0 @@ -# This file is dual licensed under the terms of the Apache License, Version -# 2.0, and the BSD License. See the LICENSE file in the root of this repository -# for complete details. - -import typing - -from cryptography.hazmat.primitives import ciphers - -class CMAC: - def __init__( - self, - algorithm: ciphers.BlockCipherAlgorithm, - backend: typing.Any = None, - ) -> None: ... - def update(self, data: bytes) -> None: ... - def finalize(self) -> bytes: ... - def verify(self, signature: bytes) -> None: ... - def copy(self) -> CMAC: ... diff --git a/venv/lib/python3.9/site-packages/cryptography/hazmat/bindings/_rust/openssl/dh.pyi b/venv/lib/python3.9/site-packages/cryptography/hazmat/bindings/_rust/openssl/dh.pyi deleted file mode 100644 index 08733d7..0000000 --- a/venv/lib/python3.9/site-packages/cryptography/hazmat/bindings/_rust/openssl/dh.pyi +++ /dev/null @@ -1,51 +0,0 @@ -# This file is dual licensed under the terms of the Apache License, Version -# 2.0, and the BSD License. See the LICENSE file in the root of this repository -# for complete details. - -import typing - -from cryptography.hazmat.primitives.asymmetric import dh - -MIN_MODULUS_SIZE: int - -class DHPrivateKey: ... -class DHPublicKey: ... -class DHParameters: ... - -class DHPrivateNumbers: - def __init__(self, x: int, public_numbers: DHPublicNumbers) -> None: ... - def private_key(self, backend: typing.Any = None) -> dh.DHPrivateKey: ... - @property - def x(self) -> int: ... - @property - def public_numbers(self) -> DHPublicNumbers: ... - -class DHPublicNumbers: - def __init__( - self, y: int, parameter_numbers: DHParameterNumbers - ) -> None: ... - def public_key(self, backend: typing.Any = None) -> dh.DHPublicKey: ... - @property - def y(self) -> int: ... - @property - def parameter_numbers(self) -> DHParameterNumbers: ... - -class DHParameterNumbers: - def __init__(self, p: int, g: int, q: int | None = None) -> None: ... - def parameters(self, backend: typing.Any = None) -> dh.DHParameters: ... - @property - def p(self) -> int: ... - @property - def g(self) -> int: ... - @property - def q(self) -> int | None: ... - -def generate_parameters( - generator: int, key_size: int, backend: typing.Any = None -) -> dh.DHParameters: ... -def from_pem_parameters( - data: bytes, backend: typing.Any = None -) -> dh.DHParameters: ... -def from_der_parameters( - data: bytes, backend: typing.Any = None -) -> dh.DHParameters: ... diff --git a/venv/lib/python3.9/site-packages/cryptography/hazmat/bindings/_rust/openssl/dsa.pyi b/venv/lib/python3.9/site-packages/cryptography/hazmat/bindings/_rust/openssl/dsa.pyi deleted file mode 100644 index 0922a4c..0000000 --- a/venv/lib/python3.9/site-packages/cryptography/hazmat/bindings/_rust/openssl/dsa.pyi +++ /dev/null @@ -1,41 +0,0 @@ -# This file is dual licensed under the terms of the Apache License, Version -# 2.0, and the BSD License. See the LICENSE file in the root of this repository -# for complete details. - -import typing - -from cryptography.hazmat.primitives.asymmetric import dsa - -class DSAPrivateKey: ... -class DSAPublicKey: ... -class DSAParameters: ... - -class DSAPrivateNumbers: - def __init__(self, x: int, public_numbers: DSAPublicNumbers) -> None: ... - @property - def x(self) -> int: ... - @property - def public_numbers(self) -> DSAPublicNumbers: ... - def private_key(self, backend: typing.Any = None) -> dsa.DSAPrivateKey: ... - -class DSAPublicNumbers: - def __init__( - self, y: int, parameter_numbers: DSAParameterNumbers - ) -> None: ... - @property - def y(self) -> int: ... - @property - def parameter_numbers(self) -> DSAParameterNumbers: ... - def public_key(self, backend: typing.Any = None) -> dsa.DSAPublicKey: ... - -class DSAParameterNumbers: - def __init__(self, p: int, q: int, g: int) -> None: ... - @property - def p(self) -> int: ... - @property - def q(self) -> int: ... - @property - def g(self) -> int: ... - def parameters(self, backend: typing.Any = None) -> dsa.DSAParameters: ... - -def generate_parameters(key_size: int) -> dsa.DSAParameters: ... diff --git a/venv/lib/python3.9/site-packages/cryptography/hazmat/bindings/_rust/openssl/ec.pyi b/venv/lib/python3.9/site-packages/cryptography/hazmat/bindings/_rust/openssl/ec.pyi deleted file mode 100644 index 5c3b7bf..0000000 --- a/venv/lib/python3.9/site-packages/cryptography/hazmat/bindings/_rust/openssl/ec.pyi +++ /dev/null @@ -1,52 +0,0 @@ -# This file is dual licensed under the terms of the Apache License, Version -# 2.0, and the BSD License. See the LICENSE file in the root of this repository -# for complete details. - -import typing - -from cryptography.hazmat.primitives.asymmetric import ec - -class ECPrivateKey: ... -class ECPublicKey: ... - -class EllipticCurvePrivateNumbers: - def __init__( - self, private_value: int, public_numbers: EllipticCurvePublicNumbers - ) -> None: ... - def private_key( - self, backend: typing.Any = None - ) -> ec.EllipticCurvePrivateKey: ... - @property - def private_value(self) -> int: ... - @property - def public_numbers(self) -> EllipticCurvePublicNumbers: ... - -class EllipticCurvePublicNumbers: - def __init__(self, x: int, y: int, curve: ec.EllipticCurve) -> None: ... - def public_key( - self, backend: typing.Any = None - ) -> ec.EllipticCurvePublicKey: ... - @property - def x(self) -> int: ... - @property - def y(self) -> int: ... - @property - def curve(self) -> ec.EllipticCurve: ... - def __eq__(self, other: object) -> bool: ... - -def curve_supported(curve: ec.EllipticCurve) -> bool: ... -def generate_private_key( - curve: ec.EllipticCurve, backend: typing.Any = None -) -> ec.EllipticCurvePrivateKey: ... -def from_private_numbers( - numbers: ec.EllipticCurvePrivateNumbers, -) -> ec.EllipticCurvePrivateKey: ... -def from_public_numbers( - numbers: ec.EllipticCurvePublicNumbers, -) -> ec.EllipticCurvePublicKey: ... -def from_public_bytes( - curve: ec.EllipticCurve, data: bytes -) -> ec.EllipticCurvePublicKey: ... -def derive_private_key( - private_value: int, curve: ec.EllipticCurve -) -> ec.EllipticCurvePrivateKey: ... diff --git a/venv/lib/python3.9/site-packages/cryptography/hazmat/bindings/_rust/openssl/ed25519.pyi b/venv/lib/python3.9/site-packages/cryptography/hazmat/bindings/_rust/openssl/ed25519.pyi deleted file mode 100644 index f85b3d1..0000000 --- a/venv/lib/python3.9/site-packages/cryptography/hazmat/bindings/_rust/openssl/ed25519.pyi +++ /dev/null @@ -1,13 +0,0 @@ -# This file is dual licensed under the terms of the Apache License, Version -# 2.0, and the BSD License. See the LICENSE file in the root of this repository -# for complete details. - -from cryptography.hazmat.primitives.asymmetric import ed25519 -from cryptography.utils import Buffer - -class Ed25519PrivateKey: ... -class Ed25519PublicKey: ... - -def generate_key() -> ed25519.Ed25519PrivateKey: ... -def from_private_bytes(data: Buffer) -> ed25519.Ed25519PrivateKey: ... -def from_public_bytes(data: bytes) -> ed25519.Ed25519PublicKey: ... diff --git a/venv/lib/python3.9/site-packages/cryptography/hazmat/bindings/_rust/openssl/ed448.pyi b/venv/lib/python3.9/site-packages/cryptography/hazmat/bindings/_rust/openssl/ed448.pyi deleted file mode 100644 index c8ca0ec..0000000 --- a/venv/lib/python3.9/site-packages/cryptography/hazmat/bindings/_rust/openssl/ed448.pyi +++ /dev/null @@ -1,13 +0,0 @@ -# This file is dual licensed under the terms of the Apache License, Version -# 2.0, and the BSD License. See the LICENSE file in the root of this repository -# for complete details. - -from cryptography.hazmat.primitives.asymmetric import ed448 -from cryptography.utils import Buffer - -class Ed448PrivateKey: ... -class Ed448PublicKey: ... - -def generate_key() -> ed448.Ed448PrivateKey: ... -def from_private_bytes(data: Buffer) -> ed448.Ed448PrivateKey: ... -def from_public_bytes(data: bytes) -> ed448.Ed448PublicKey: ... diff --git a/venv/lib/python3.9/site-packages/cryptography/hazmat/bindings/_rust/openssl/hashes.pyi b/venv/lib/python3.9/site-packages/cryptography/hazmat/bindings/_rust/openssl/hashes.pyi deleted file mode 100644 index 106b531..0000000 --- a/venv/lib/python3.9/site-packages/cryptography/hazmat/bindings/_rust/openssl/hashes.pyi +++ /dev/null @@ -1,30 +0,0 @@ -# This file is dual licensed under the terms of the Apache License, Version -# 2.0, and the BSD License. See the LICENSE file in the root of this repository -# for complete details. - -import typing - -from cryptography.hazmat.primitives import hashes -from cryptography.utils import Buffer - -class Hash(hashes.HashContext): - def __init__( - self, algorithm: hashes.HashAlgorithm, backend: typing.Any = None - ) -> None: ... - @property - def algorithm(self) -> hashes.HashAlgorithm: ... - def update(self, data: Buffer) -> None: ... - def finalize(self) -> bytes: ... - def copy(self) -> Hash: ... - @staticmethod - def hash(algorithm: hashes.HashAlgorithm, data: Buffer) -> bytes: ... - -def hash_supported(algorithm: hashes.HashAlgorithm) -> bool: ... - -class XOFHash: - def __init__(self, algorithm: hashes.ExtendableOutputFunction) -> None: ... - @property - def algorithm(self) -> hashes.ExtendableOutputFunction: ... - def update(self, data: Buffer) -> None: ... - def squeeze(self, length: int) -> bytes: ... - def copy(self) -> XOFHash: ... diff --git a/venv/lib/python3.9/site-packages/cryptography/hazmat/bindings/_rust/openssl/hmac.pyi b/venv/lib/python3.9/site-packages/cryptography/hazmat/bindings/_rust/openssl/hmac.pyi deleted file mode 100644 index 3883d1b..0000000 --- a/venv/lib/python3.9/site-packages/cryptography/hazmat/bindings/_rust/openssl/hmac.pyi +++ /dev/null @@ -1,22 +0,0 @@ -# This file is dual licensed under the terms of the Apache License, Version -# 2.0, and the BSD License. See the LICENSE file in the root of this repository -# for complete details. - -import typing - -from cryptography.hazmat.primitives import hashes -from cryptography.utils import Buffer - -class HMAC(hashes.HashContext): - def __init__( - self, - key: Buffer, - algorithm: hashes.HashAlgorithm, - backend: typing.Any = None, - ) -> None: ... - @property - def algorithm(self) -> hashes.HashAlgorithm: ... - def update(self, data: Buffer) -> None: ... - def finalize(self) -> bytes: ... - def verify(self, signature: bytes) -> None: ... - def copy(self) -> HMAC: ... diff --git a/venv/lib/python3.9/site-packages/cryptography/hazmat/bindings/_rust/openssl/hpke.pyi b/venv/lib/python3.9/site-packages/cryptography/hazmat/bindings/_rust/openssl/hpke.pyi deleted file mode 100644 index a9d8a11..0000000 --- a/venv/lib/python3.9/site-packages/cryptography/hazmat/bindings/_rust/openssl/hpke.pyi +++ /dev/null @@ -1,108 +0,0 @@ -# This file is dual licensed under the terms of the Apache License, Version -# 2.0, and the BSD License. See the LICENSE file in the root of this repository -# for complete details. - -from cryptography.hazmat.primitives.asymmetric import ec, mlkem, x25519 -from cryptography.utils import Buffer - -class KEM: - X25519: KEM - P256: KEM - P384: KEM - P521: KEM - MLKEM768: KEM - MLKEM1024: KEM - MLKEM768_X25519: KEM - MLKEM1024_P384: KEM - -class KDF: - HKDF_SHA256: KDF - HKDF_SHA384: KDF - HKDF_SHA512: KDF - SHAKE128: KDF - SHAKE256: KDF - -class AEAD: - AES_128_GCM: AEAD - AES_256_GCM: AEAD - CHACHA20_POLY1305: AEAD - -class MLKEM768X25519PrivateKey: - def __init__( - self, - mlkem_key: mlkem.MLKEM768PrivateKey, - x25519_key: x25519.X25519PrivateKey, - ) -> None: ... - def public_key(self) -> MLKEM768X25519PublicKey: ... - -class MLKEM768X25519PublicKey: - def __init__( - self, - mlkem_key: mlkem.MLKEM768PublicKey, - x25519_key: x25519.X25519PublicKey, - ) -> None: ... - -class MLKEM1024P384PrivateKey: - def __init__( - self, - mlkem_key: mlkem.MLKEM1024PrivateKey, - p384_key: ec.EllipticCurvePrivateKey, - ) -> None: ... - def public_key(self) -> MLKEM1024P384PublicKey: ... - -class MLKEM1024P384PublicKey: - def __init__( - self, - mlkem_key: mlkem.MLKEM1024PublicKey, - p384_key: ec.EllipticCurvePublicKey, - ) -> None: ... - -class Suite: - def __init__(self, kem: KEM, kdf: KDF, aead: AEAD) -> None: ... - def encrypt( - self, - plaintext: Buffer, - public_key: x25519.X25519PublicKey - | ec.EllipticCurvePublicKey - | mlkem.MLKEM768PublicKey - | mlkem.MLKEM1024PublicKey - | MLKEM768X25519PublicKey - | MLKEM1024P384PublicKey, - info: Buffer | None = None, - ) -> bytes: ... - def decrypt( - self, - ciphertext: Buffer, - private_key: x25519.X25519PrivateKey - | ec.EllipticCurvePrivateKey - | mlkem.MLKEM768PrivateKey - | mlkem.MLKEM1024PrivateKey - | MLKEM768X25519PrivateKey - | MLKEM1024P384PrivateKey, - info: Buffer | None = None, - ) -> bytes: ... - -def _encrypt_with_aad( - suite: Suite, - plaintext: Buffer, - public_key: x25519.X25519PublicKey - | ec.EllipticCurvePublicKey - | mlkem.MLKEM768PublicKey - | mlkem.MLKEM1024PublicKey - | MLKEM768X25519PublicKey - | MLKEM1024P384PublicKey, - info: Buffer | None = None, - aad: Buffer | None = None, -) -> bytes: ... -def _decrypt_with_aad( - suite: Suite, - ciphertext: Buffer, - private_key: x25519.X25519PrivateKey - | ec.EllipticCurvePrivateKey - | mlkem.MLKEM768PrivateKey - | mlkem.MLKEM1024PrivateKey - | MLKEM768X25519PrivateKey - | MLKEM1024P384PrivateKey, - info: Buffer | None = None, - aad: Buffer | None = None, -) -> bytes: ... diff --git a/venv/lib/python3.9/site-packages/cryptography/hazmat/bindings/_rust/openssl/kdf.pyi b/venv/lib/python3.9/site-packages/cryptography/hazmat/bindings/_rust/openssl/kdf.pyi deleted file mode 100644 index bb37b96..0000000 --- a/venv/lib/python3.9/site-packages/cryptography/hazmat/bindings/_rust/openssl/kdf.pyi +++ /dev/null @@ -1,205 +0,0 @@ -# This file is dual licensed under the terms of the Apache License, Version -# 2.0, and the BSD License. See the LICENSE file in the root of this repository -# for complete details. - -import typing - -from cryptography.hazmat.primitives.hashes import HashAlgorithm -from cryptography.hazmat.primitives.kdf.kbkdf import CounterLocation, Mode -from cryptography.utils import Buffer - -class PBKDF2HMAC: - def __init__( - self, - algorithm: HashAlgorithm, - length: int, - salt: bytes, - iterations: int, - backend: typing.Any = None, - ) -> None: ... - def derive(self, key_material: Buffer) -> bytes: ... - def derive_into(self, key_material: Buffer, buffer: Buffer) -> int: ... - def verify(self, key_material: bytes, expected_key: bytes) -> None: ... - -class Scrypt: - def __init__( - self, - salt: bytes, - length: int, - n: int, - r: int, - p: int, - backend: typing.Any = None, - ) -> None: ... - def derive(self, key_material: Buffer) -> bytes: ... - def derive_into(self, key_material: Buffer, buffer: Buffer) -> int: ... - def verify(self, key_material: bytes, expected_key: bytes) -> None: ... - -class Argon2d: - def __init__( - self, - *, - salt: bytes, - length: int, - iterations: int, - lanes: int, - memory_cost: int, - ad: bytes | None = None, - secret: bytes | None = None, - ) -> None: ... - def derive(self, key_material: bytes) -> bytes: ... - def derive_into(self, key_material: bytes, buffer: Buffer) -> int: ... - def verify(self, key_material: bytes, expected_key: bytes) -> None: ... - def derive_phc_encoded(self, key_material: bytes) -> str: ... - @classmethod - def verify_phc_encoded( - cls, key_material: bytes, phc_encoded: str, secret: bytes | None = None - ) -> None: ... - -class Argon2i: - def __init__( - self, - *, - salt: bytes, - length: int, - iterations: int, - lanes: int, - memory_cost: int, - ad: bytes | None = None, - secret: bytes | None = None, - ) -> None: ... - def derive(self, key_material: bytes) -> bytes: ... - def derive_into(self, key_material: bytes, buffer: Buffer) -> int: ... - def verify(self, key_material: bytes, expected_key: bytes) -> None: ... - def derive_phc_encoded(self, key_material: bytes) -> str: ... - @classmethod - def verify_phc_encoded( - cls, key_material: bytes, phc_encoded: str, secret: bytes | None = None - ) -> None: ... - -class Argon2id: - def __init__( - self, - *, - salt: bytes, - length: int, - iterations: int, - lanes: int, - memory_cost: int, - ad: bytes | None = None, - secret: bytes | None = None, - ) -> None: ... - def derive(self, key_material: bytes) -> bytes: ... - def derive_into(self, key_material: bytes, buffer: Buffer) -> int: ... - def verify(self, key_material: bytes, expected_key: bytes) -> None: ... - def derive_phc_encoded(self, key_material: bytes) -> str: ... - @classmethod - def verify_phc_encoded( - cls, key_material: bytes, phc_encoded: str, secret: bytes | None = None - ) -> None: ... - -class HKDF: - def __init__( - self, - algorithm: HashAlgorithm, - length: int, - salt: bytes | None, - info: bytes | None, - backend: typing.Any = None, - ): ... - @staticmethod - def extract( - algorithm: HashAlgorithm, salt: bytes | None, key_material: Buffer - ) -> bytes: ... - def derive(self, key_material: Buffer) -> bytes: ... - def derive_into(self, key_material: Buffer, buffer: Buffer) -> int: ... - def verify(self, key_material: bytes, expected_key: bytes) -> None: ... - -class HKDFExpand: - def __init__( - self, - algorithm: HashAlgorithm, - length: int, - info: bytes | None, - backend: typing.Any = None, - ): ... - def derive(self, key_material: Buffer) -> bytes: ... - def derive_into(self, key_material: Buffer, buffer: Buffer) -> int: ... - def verify(self, key_material: bytes, expected_key: bytes) -> None: ... - -class X963KDF: - def __init__( - self, - algorithm: HashAlgorithm, - length: int, - sharedinfo: bytes | None, - backend: typing.Any = None, - ) -> None: ... - def derive(self, key_material: Buffer) -> bytes: ... - def derive_into(self, key_material: Buffer, buffer: Buffer) -> int: ... - def verify(self, key_material: bytes, expected_key: bytes) -> None: ... - -class ConcatKDFHash: - def __init__( - self, - algorithm: HashAlgorithm, - length: int, - otherinfo: bytes | None, - backend: typing.Any = None, - ) -> None: ... - def derive(self, key_material: Buffer) -> bytes: ... - def derive_into(self, key_material: Buffer, buffer: Buffer) -> int: ... - def verify(self, key_material: bytes, expected_key: bytes) -> None: ... - -class ConcatKDFHMAC: - def __init__( - self, - algorithm: HashAlgorithm, - length: int, - salt: bytes | None, - otherinfo: bytes | None, - backend: typing.Any = None, - ) -> None: ... - def derive(self, key_material: Buffer) -> bytes: ... - def derive_into(self, key_material: Buffer, buffer: Buffer) -> int: ... - def verify(self, key_material: bytes, expected_key: bytes) -> None: ... - -class KBKDFHMAC: - def __init__( - self, - algorithm: HashAlgorithm, - mode: Mode, - length: int, - rlen: int, - llen: int | None, - location: CounterLocation, - label: bytes | None, - context: bytes | None, - fixed: bytes | None, - backend: typing.Any = None, - *, - break_location: int | None = None, - ) -> None: ... - def derive(self, key_material: Buffer) -> bytes: ... - def derive_into(self, key_material: Buffer, buffer: Buffer) -> int: ... - def verify(self, key_material: bytes, expected_key: bytes) -> None: ... - -class KBKDFCMAC: - def __init__( - self, - algorithm: typing.Any, - mode: Mode, - length: int, - rlen: int, - llen: int | None, - location: CounterLocation, - label: bytes | None, - context: bytes | None, - fixed: bytes | None, - backend: typing.Any = None, - *, - break_location: int | None = None, - ) -> None: ... - def derive(self, key_material: Buffer) -> bytes: ... - def derive_into(self, key_material: Buffer, buffer: Buffer) -> int: ... - def verify(self, key_material: bytes, expected_key: bytes) -> None: ... diff --git a/venv/lib/python3.9/site-packages/cryptography/hazmat/bindings/_rust/openssl/keys.pyi b/venv/lib/python3.9/site-packages/cryptography/hazmat/bindings/_rust/openssl/keys.pyi deleted file mode 100644 index 404057e..0000000 --- a/venv/lib/python3.9/site-packages/cryptography/hazmat/bindings/_rust/openssl/keys.pyi +++ /dev/null @@ -1,34 +0,0 @@ -# This file is dual licensed under the terms of the Apache License, Version -# 2.0, and the BSD License. See the LICENSE file in the root of this repository -# for complete details. - -import typing - -from cryptography.hazmat.primitives.asymmetric.types import ( - PrivateKeyTypes, - PublicKeyTypes, -) -from cryptography.utils import Buffer - -def load_der_private_key( - data: Buffer, - password: bytes | None, - backend: typing.Any = None, - *, - unsafe_skip_rsa_key_validation: bool = False, -) -> PrivateKeyTypes: ... -def load_pem_private_key( - data: Buffer, - password: bytes | None, - backend: typing.Any = None, - *, - unsafe_skip_rsa_key_validation: bool = False, -) -> PrivateKeyTypes: ... -def load_der_public_key( - data: bytes, - backend: typing.Any = None, -) -> PublicKeyTypes: ... -def load_pem_public_key( - data: bytes, - backend: typing.Any = None, -) -> PublicKeyTypes: ... diff --git a/venv/lib/python3.9/site-packages/cryptography/hazmat/bindings/_rust/openssl/mldsa.pyi b/venv/lib/python3.9/site-packages/cryptography/hazmat/bindings/_rust/openssl/mldsa.pyi deleted file mode 100644 index 232469a..0000000 --- a/venv/lib/python3.9/site-packages/cryptography/hazmat/bindings/_rust/openssl/mldsa.pyi +++ /dev/null @@ -1,23 +0,0 @@ -# This file is dual licensed under the terms of the Apache License, Version -# 2.0, and the BSD License. See the LICENSE file in the root of this repository -# for complete details. - -from cryptography.hazmat.primitives.asymmetric import mldsa -from cryptography.utils import Buffer - -class MLDSA44PrivateKey: ... -class MLDSA44PublicKey: ... -class MLDSA65PrivateKey: ... -class MLDSA65PublicKey: ... -class MLDSA87PrivateKey: ... -class MLDSA87PublicKey: ... - -def generate_mldsa44_key() -> mldsa.MLDSA44PrivateKey: ... -def from_mldsa44_public_bytes(data: bytes) -> mldsa.MLDSA44PublicKey: ... -def from_mldsa44_seed_bytes(data: Buffer) -> mldsa.MLDSA44PrivateKey: ... -def generate_mldsa65_key() -> mldsa.MLDSA65PrivateKey: ... -def from_mldsa65_public_bytes(data: bytes) -> mldsa.MLDSA65PublicKey: ... -def from_mldsa65_seed_bytes(data: Buffer) -> mldsa.MLDSA65PrivateKey: ... -def generate_mldsa87_key() -> mldsa.MLDSA87PrivateKey: ... -def from_mldsa87_public_bytes(data: bytes) -> mldsa.MLDSA87PublicKey: ... -def from_mldsa87_seed_bytes(data: Buffer) -> mldsa.MLDSA87PrivateKey: ... diff --git a/venv/lib/python3.9/site-packages/cryptography/hazmat/bindings/_rust/openssl/mlkem.pyi b/venv/lib/python3.9/site-packages/cryptography/hazmat/bindings/_rust/openssl/mlkem.pyi deleted file mode 100644 index 768a340..0000000 --- a/venv/lib/python3.9/site-packages/cryptography/hazmat/bindings/_rust/openssl/mlkem.pyi +++ /dev/null @@ -1,18 +0,0 @@ -# This file is dual licensed under the terms of the Apache License, Version -# 2.0, and the BSD License. See the LICENSE file in the root of this repository -# for complete details. - -from cryptography.hazmat.primitives.asymmetric import mlkem -from cryptography.utils import Buffer - -class MLKEM768PrivateKey: ... -class MLKEM768PublicKey: ... -class MLKEM1024PrivateKey: ... -class MLKEM1024PublicKey: ... - -def generate_mlkem768_key() -> mlkem.MLKEM768PrivateKey: ... -def from_mlkem768_seed_bytes(data: Buffer) -> mlkem.MLKEM768PrivateKey: ... -def from_mlkem768_public_bytes(data: Buffer) -> mlkem.MLKEM768PublicKey: ... -def generate_mlkem1024_key() -> mlkem.MLKEM1024PrivateKey: ... -def from_mlkem1024_seed_bytes(data: Buffer) -> mlkem.MLKEM1024PrivateKey: ... -def from_mlkem1024_public_bytes(data: Buffer) -> mlkem.MLKEM1024PublicKey: ... diff --git a/venv/lib/python3.9/site-packages/cryptography/hazmat/bindings/_rust/openssl/poly1305.pyi b/venv/lib/python3.9/site-packages/cryptography/hazmat/bindings/_rust/openssl/poly1305.pyi deleted file mode 100644 index 45a2a39..0000000 --- a/venv/lib/python3.9/site-packages/cryptography/hazmat/bindings/_rust/openssl/poly1305.pyi +++ /dev/null @@ -1,15 +0,0 @@ -# This file is dual licensed under the terms of the Apache License, Version -# 2.0, and the BSD License. See the LICENSE file in the root of this repository -# for complete details. - -from cryptography.utils import Buffer - -class Poly1305: - def __init__(self, key: Buffer) -> None: ... - @staticmethod - def generate_tag(key: Buffer, data: Buffer) -> bytes: ... - @staticmethod - def verify_tag(key: Buffer, data: Buffer, tag: bytes) -> None: ... - def update(self, data: Buffer) -> None: ... - def finalize(self) -> bytes: ... - def verify(self, tag: bytes) -> None: ... diff --git a/venv/lib/python3.9/site-packages/cryptography/hazmat/bindings/_rust/openssl/rsa.pyi b/venv/lib/python3.9/site-packages/cryptography/hazmat/bindings/_rust/openssl/rsa.pyi deleted file mode 100644 index ef7752d..0000000 --- a/venv/lib/python3.9/site-packages/cryptography/hazmat/bindings/_rust/openssl/rsa.pyi +++ /dev/null @@ -1,55 +0,0 @@ -# This file is dual licensed under the terms of the Apache License, Version -# 2.0, and the BSD License. See the LICENSE file in the root of this repository -# for complete details. - -import typing - -from cryptography.hazmat.primitives.asymmetric import rsa - -class RSAPrivateKey: ... -class RSAPublicKey: ... - -class RSAPrivateNumbers: - def __init__( - self, - p: int, - q: int, - d: int, - dmp1: int, - dmq1: int, - iqmp: int, - public_numbers: RSAPublicNumbers, - ) -> None: ... - @property - def p(self) -> int: ... - @property - def q(self) -> int: ... - @property - def d(self) -> int: ... - @property - def dmp1(self) -> int: ... - @property - def dmq1(self) -> int: ... - @property - def iqmp(self) -> int: ... - @property - def public_numbers(self) -> RSAPublicNumbers: ... - def private_key( - self, - backend: typing.Any = None, - *, - unsafe_skip_rsa_key_validation: bool = False, - ) -> rsa.RSAPrivateKey: ... - -class RSAPublicNumbers: - def __init__(self, e: int, n: int) -> None: ... - @property - def n(self) -> int: ... - @property - def e(self) -> int: ... - def public_key(self, backend: typing.Any = None) -> rsa.RSAPublicKey: ... - -def generate_private_key( - public_exponent: int, - key_size: int, -) -> rsa.RSAPrivateKey: ... diff --git a/venv/lib/python3.9/site-packages/cryptography/hazmat/bindings/_rust/openssl/x25519.pyi b/venv/lib/python3.9/site-packages/cryptography/hazmat/bindings/_rust/openssl/x25519.pyi deleted file mode 100644 index 38d2add..0000000 --- a/venv/lib/python3.9/site-packages/cryptography/hazmat/bindings/_rust/openssl/x25519.pyi +++ /dev/null @@ -1,13 +0,0 @@ -# This file is dual licensed under the terms of the Apache License, Version -# 2.0, and the BSD License. See the LICENSE file in the root of this repository -# for complete details. - -from cryptography.hazmat.primitives.asymmetric import x25519 -from cryptography.utils import Buffer - -class X25519PrivateKey: ... -class X25519PublicKey: ... - -def generate_key() -> x25519.X25519PrivateKey: ... -def from_private_bytes(data: Buffer) -> x25519.X25519PrivateKey: ... -def from_public_bytes(data: bytes) -> x25519.X25519PublicKey: ... diff --git a/venv/lib/python3.9/site-packages/cryptography/hazmat/bindings/_rust/openssl/x448.pyi b/venv/lib/python3.9/site-packages/cryptography/hazmat/bindings/_rust/openssl/x448.pyi deleted file mode 100644 index 3ac0980..0000000 --- a/venv/lib/python3.9/site-packages/cryptography/hazmat/bindings/_rust/openssl/x448.pyi +++ /dev/null @@ -1,13 +0,0 @@ -# This file is dual licensed under the terms of the Apache License, Version -# 2.0, and the BSD License. See the LICENSE file in the root of this repository -# for complete details. - -from cryptography.hazmat.primitives.asymmetric import x448 -from cryptography.utils import Buffer - -class X448PrivateKey: ... -class X448PublicKey: ... - -def generate_key() -> x448.X448PrivateKey: ... -def from_private_bytes(data: Buffer) -> x448.X448PrivateKey: ... -def from_public_bytes(data: bytes) -> x448.X448PublicKey: ... diff --git a/venv/lib/python3.9/site-packages/cryptography/hazmat/bindings/_rust/pkcs12.pyi b/venv/lib/python3.9/site-packages/cryptography/hazmat/bindings/_rust/pkcs12.pyi deleted file mode 100644 index b25becb..0000000 --- a/venv/lib/python3.9/site-packages/cryptography/hazmat/bindings/_rust/pkcs12.pyi +++ /dev/null @@ -1,52 +0,0 @@ -# This file is dual licensed under the terms of the Apache License, Version -# 2.0, and the BSD License. See the LICENSE file in the root of this repository -# for complete details. - -import typing -from collections.abc import Iterable - -from cryptography import x509 -from cryptography.hazmat.primitives.asymmetric.types import PrivateKeyTypes -from cryptography.hazmat.primitives.serialization import ( - KeySerializationEncryption, -) -from cryptography.hazmat.primitives.serialization.pkcs12 import ( - PKCS12KeyAndCertificates, - PKCS12PrivateKeyTypes, -) -from cryptography.utils import Buffer - -class PKCS12Certificate: - def __init__( - self, cert: x509.Certificate, friendly_name: bytes | None - ) -> None: ... - @property - def friendly_name(self) -> bytes | None: ... - @property - def certificate(self) -> x509.Certificate: ... - -def load_key_and_certificates( - data: Buffer, - password: Buffer | None, - backend: typing.Any = None, -) -> tuple[ - PrivateKeyTypes | None, - x509.Certificate | None, - list[x509.Certificate], -]: ... -def load_pkcs12( - data: bytes, - password: bytes | None, - backend: typing.Any = None, -) -> PKCS12KeyAndCertificates: ... -def serialize_java_truststore( - certs: Iterable[PKCS12Certificate], - encryption_algorithm: KeySerializationEncryption, -) -> bytes: ... -def serialize_key_and_certificates( - name: bytes | None, - key: PKCS12PrivateKeyTypes | None, - cert: x509.Certificate | None, - cas: Iterable[x509.Certificate | PKCS12Certificate] | None, - encryption_algorithm: KeySerializationEncryption, -) -> bytes: ... diff --git a/venv/lib/python3.9/site-packages/cryptography/hazmat/bindings/_rust/pkcs7.pyi b/venv/lib/python3.9/site-packages/cryptography/hazmat/bindings/_rust/pkcs7.pyi deleted file mode 100644 index 358b135..0000000 --- a/venv/lib/python3.9/site-packages/cryptography/hazmat/bindings/_rust/pkcs7.pyi +++ /dev/null @@ -1,50 +0,0 @@ -# This file is dual licensed under the terms of the Apache License, Version -# 2.0, and the BSD License. See the LICENSE file in the root of this repository -# for complete details. - -from collections.abc import Iterable - -from cryptography import x509 -from cryptography.hazmat.primitives import serialization -from cryptography.hazmat.primitives.asymmetric import rsa -from cryptography.hazmat.primitives.serialization import pkcs7 - -def serialize_certificates( - certs: list[x509.Certificate], - encoding: serialization.Encoding, -) -> bytes: ... -def encrypt_and_serialize( - builder: pkcs7.PKCS7EnvelopeBuilder, - content_encryption_algorithm: pkcs7.ContentEncryptionAlgorithm, - encoding: serialization.Encoding, - options: Iterable[pkcs7.PKCS7Options], -) -> bytes: ... -def sign_and_serialize( - builder: pkcs7.PKCS7SignatureBuilder, - encoding: serialization.Encoding, - options: Iterable[pkcs7.PKCS7Options], -) -> bytes: ... -def decrypt_der( - data: bytes, - certificate: x509.Certificate, - private_key: rsa.RSAPrivateKey, - options: Iterable[pkcs7.PKCS7Options], -) -> bytes: ... -def decrypt_pem( - data: bytes, - certificate: x509.Certificate, - private_key: rsa.RSAPrivateKey, - options: Iterable[pkcs7.PKCS7Options], -) -> bytes: ... -def decrypt_smime( - data: bytes, - certificate: x509.Certificate, - private_key: rsa.RSAPrivateKey, - options: Iterable[pkcs7.PKCS7Options], -) -> bytes: ... -def load_pem_pkcs7_certificates( - data: bytes, -) -> list[x509.Certificate]: ... -def load_der_pkcs7_certificates( - data: bytes, -) -> list[x509.Certificate]: ... diff --git a/venv/lib/python3.9/site-packages/cryptography/hazmat/bindings/_rust/test_support.pyi b/venv/lib/python3.9/site-packages/cryptography/hazmat/bindings/_rust/test_support.pyi deleted file mode 100644 index c6c6d0b..0000000 --- a/venv/lib/python3.9/site-packages/cryptography/hazmat/bindings/_rust/test_support.pyi +++ /dev/null @@ -1,23 +0,0 @@ -# This file is dual licensed under the terms of the Apache License, Version -# 2.0, and the BSD License. See the LICENSE file in the root of this repository -# for complete details. - -from cryptography import x509 -from cryptography.hazmat.primitives import serialization -from cryptography.hazmat.primitives.serialization import pkcs7 -from cryptography.utils import Buffer - -class TestCertificate: - not_after_tag: int - not_before_tag: int - issuer_value_tags: list[int] - subject_value_tags: list[int] - -def test_parse_certificate(data: bytes) -> TestCertificate: ... -def pkcs7_verify( - encoding: serialization.Encoding, - sig: bytes, - msg: Buffer | None, - certs: list[x509.Certificate], - options: list[pkcs7.PKCS7Options], -) -> None: ... diff --git a/venv/lib/python3.9/site-packages/cryptography/hazmat/bindings/_rust/x509.pyi b/venv/lib/python3.9/site-packages/cryptography/hazmat/bindings/_rust/x509.pyi deleted file mode 100644 index 196a3c6..0000000 --- a/venv/lib/python3.9/site-packages/cryptography/hazmat/bindings/_rust/x509.pyi +++ /dev/null @@ -1,312 +0,0 @@ -# This file is dual licensed under the terms of the Apache License, Version -# 2.0, and the BSD License. See the LICENSE file in the root of this repository -# for complete details. - -import datetime -import typing -from collections.abc import Iterator - -from cryptography import x509 -from cryptography.hazmat.primitives import hashes, serialization -from cryptography.hazmat.primitives.asymmetric.ec import ECDSA -from cryptography.hazmat.primitives.asymmetric.padding import PSS, PKCS1v15 -from cryptography.hazmat.primitives.asymmetric.types import ( - CertificateIssuerPublicKeyTypes, - CertificatePublicKeyTypes, - PrivateKeyTypes, -) -from cryptography.x509 import certificate_transparency - -def load_pem_x509_certificate( - data: bytes, backend: typing.Any = None -) -> x509.Certificate: ... -def load_der_x509_certificate( - data: bytes, backend: typing.Any = None -) -> x509.Certificate: ... -def load_pem_x509_certificates( - data: bytes, -) -> list[x509.Certificate]: ... -def load_pem_x509_crl( - data: bytes, backend: typing.Any = None -) -> x509.CertificateRevocationList: ... -def load_der_x509_crl( - data: bytes, backend: typing.Any = None -) -> x509.CertificateRevocationList: ... -def load_pem_x509_csr( - data: bytes, backend: typing.Any = None -) -> x509.CertificateSigningRequest: ... -def load_der_x509_csr( - data: bytes, backend: typing.Any = None -) -> x509.CertificateSigningRequest: ... -def encode_name_bytes(name: x509.Name) -> bytes: ... -def encode_extension_value(extension: x509.ExtensionType) -> bytes: ... -def create_x509_certificate( - builder: x509.CertificateBuilder, - private_key: PrivateKeyTypes, - hash_algorithm: hashes.HashAlgorithm | None, - rsa_padding: PKCS1v15 | PSS | None, - ecdsa_deterministic: bool | None, -) -> x509.Certificate: ... -def create_x509_csr( - builder: x509.CertificateSigningRequestBuilder, - private_key: PrivateKeyTypes, - hash_algorithm: hashes.HashAlgorithm | None, - rsa_padding: PKCS1v15 | PSS | None, - ecdsa_deterministic: bool | None, -) -> x509.CertificateSigningRequest: ... -def create_revoked_certificate( - builder: x509.RevokedCertificateBuilder, -) -> x509.RevokedCertificate: ... -def create_x509_crl( - builder: x509.CertificateRevocationListBuilder, - private_key: PrivateKeyTypes, - hash_algorithm: hashes.HashAlgorithm | None, - rsa_padding: PKCS1v15 | PSS | None, - ecdsa_deterministic: bool | None, -) -> x509.CertificateRevocationList: ... - -class Sct: - @property - def version(self) -> certificate_transparency.Version: ... - @property - def log_id(self) -> bytes: ... - @property - def timestamp(self) -> datetime.datetime: ... - @property - def entry_type(self) -> certificate_transparency.LogEntryType: ... - @property - def signature_hash_algorithm(self) -> hashes.HashAlgorithm: ... - @property - def signature_algorithm( - self, - ) -> certificate_transparency.SignatureAlgorithm: ... - @property - def signature(self) -> bytes: ... - @property - def extension_bytes(self) -> bytes: ... - -class Certificate: - def fingerprint(self, algorithm: hashes.HashAlgorithm) -> bytes: ... - @property - def serial_number(self) -> int: ... - @property - def version(self) -> x509.Version: ... - def public_key(self) -> CertificatePublicKeyTypes: ... - @property - def public_key_algorithm_oid(self) -> x509.ObjectIdentifier: ... - @property - def not_valid_before(self) -> datetime.datetime: ... - @property - def not_valid_before_utc(self) -> datetime.datetime: ... - @property - def not_valid_after(self) -> datetime.datetime: ... - @property - def not_valid_after_utc(self) -> datetime.datetime: ... - @property - def issuer(self) -> x509.Name: ... - @property - def subject(self) -> x509.Name: ... - @property - def signature_hash_algorithm( - self, - ) -> hashes.HashAlgorithm | None: ... - @property - def signature_algorithm_oid(self) -> x509.ObjectIdentifier: ... - @property - def signature_algorithm_parameters( - self, - ) -> PSS | PKCS1v15 | ECDSA | None: ... - @property - def extensions(self) -> x509.Extensions: ... - @property - def signature(self) -> bytes: ... - @property - def tbs_certificate_bytes(self) -> bytes: ... - @property - def tbs_precertificate_bytes(self) -> bytes: ... - def __eq__(self, other: object) -> bool: ... - def __hash__(self) -> int: ... - def public_bytes(self, encoding: serialization.Encoding) -> bytes: ... - def verify_directly_issued_by(self, issuer: Certificate) -> None: ... - -class RevokedCertificate: - @property - def serial_number(self) -> int: ... - @property - def revocation_date(self) -> datetime.datetime: ... - @property - def revocation_date_utc(self) -> datetime.datetime: ... - @property - def extensions(self) -> x509.Extensions: ... - -class CertificateRevocationList: - def public_bytes(self, encoding: serialization.Encoding) -> bytes: ... - def fingerprint(self, algorithm: hashes.HashAlgorithm) -> bytes: ... - def get_revoked_certificate_by_serial_number( - self, serial_number: int - ) -> x509.RevokedCertificate | None: ... - @property - def signature_hash_algorithm( - self, - ) -> hashes.HashAlgorithm | None: ... - @property - def signature_algorithm_oid(self) -> x509.ObjectIdentifier: ... - @property - def signature_algorithm_parameters( - self, - ) -> PSS | PKCS1v15 | ECDSA | None: ... - @property - def issuer(self) -> x509.Name: ... - @property - def next_update(self) -> datetime.datetime | None: ... - @property - def next_update_utc(self) -> datetime.datetime | None: ... - @property - def last_update(self) -> datetime.datetime: ... - @property - def last_update_utc(self) -> datetime.datetime: ... - @property - def extensions(self) -> x509.Extensions: ... - @property - def signature(self) -> bytes: ... - @property - def tbs_certlist_bytes(self) -> bytes: ... - def __eq__(self, other: object) -> bool: ... - def __len__(self) -> int: ... - @typing.overload - def __getitem__(self, idx: int) -> x509.RevokedCertificate: ... - @typing.overload - def __getitem__(self, idx: slice) -> list[x509.RevokedCertificate]: ... - def __iter__(self) -> Iterator[x509.RevokedCertificate]: ... - def is_signature_valid( - self, public_key: CertificateIssuerPublicKeyTypes - ) -> bool: ... - -class CertificateSigningRequest: - def __eq__(self, other: object) -> bool: ... - def __hash__(self) -> int: ... - def public_key(self) -> CertificatePublicKeyTypes: ... - @property - def subject(self) -> x509.Name: ... - @property - def signature_hash_algorithm( - self, - ) -> hashes.HashAlgorithm | None: ... - @property - def signature_algorithm_oid(self) -> x509.ObjectIdentifier: ... - @property - def signature_algorithm_parameters( - self, - ) -> PSS | PKCS1v15 | ECDSA | None: ... - @property - def extensions(self) -> x509.Extensions: ... - @property - def attributes(self) -> x509.Attributes: ... - def public_bytes(self, encoding: serialization.Encoding) -> bytes: ... - @property - def signature(self) -> bytes: ... - @property - def tbs_certrequest_bytes(self) -> bytes: ... - @property - def is_signature_valid(self) -> bool: ... - -class PolicyBuilder: - def time(self, time: datetime.datetime) -> PolicyBuilder: ... - def store(self, store: Store) -> PolicyBuilder: ... - def max_chain_depth(self, max_chain_depth: int) -> PolicyBuilder: ... - def extension_policies( - self, *, ca_policy: ExtensionPolicy, ee_policy: ExtensionPolicy - ) -> PolicyBuilder: ... - def build_client_verifier(self) -> ClientVerifier: ... - def build_server_verifier( - self, subject: x509.verification.Subject - ) -> ServerVerifier: ... - -class Policy: - @property - def max_chain_depth(self) -> int: ... - @property - def subject(self) -> x509.verification.Subject | None: ... - @property - def validation_time(self) -> datetime.datetime: ... - @property - def extended_key_usage(self) -> x509.ObjectIdentifier: ... - @property - def minimum_rsa_modulus(self) -> int: ... - -class Criticality: - CRITICAL: Criticality - AGNOSTIC: Criticality - NON_CRITICAL: Criticality - -T = typing.TypeVar("T", contravariant=True, bound=x509.ExtensionType) - -MaybeExtensionValidatorCallback = typing.Callable[ - [ - Policy, - x509.Certificate, - T | None, - ], - None, -] - -PresentExtensionValidatorCallback = typing.Callable[ - [Policy, x509.Certificate, T], - None, -] - -class ExtensionPolicy: - @staticmethod - def permit_all() -> ExtensionPolicy: ... - @staticmethod - def webpki_defaults_ca() -> ExtensionPolicy: ... - @staticmethod - def webpki_defaults_ee() -> ExtensionPolicy: ... - def require_not_present( - self, extension_type: type[x509.ExtensionType] - ) -> ExtensionPolicy: ... - def may_be_present( - self, - extension_type: type[T], - criticality: Criticality, - validator: MaybeExtensionValidatorCallback[T] | None, - ) -> ExtensionPolicy: ... - def require_present( - self, - extension_type: type[T], - criticality: Criticality, - validator: PresentExtensionValidatorCallback[T] | None, - ) -> ExtensionPolicy: ... - -class VerifiedClient: - @property - def subjects(self) -> list[x509.GeneralName] | None: ... - @property - def chain(self) -> list[x509.Certificate]: ... - -class ClientVerifier: - @property - def policy(self) -> Policy: ... - @property - def store(self) -> Store: ... - def verify( - self, - leaf: x509.Certificate, - intermediates: list[x509.Certificate], - ) -> VerifiedClient: ... - -class ServerVerifier: - @property - def policy(self) -> Policy: ... - @property - def store(self) -> Store: ... - def verify( - self, - leaf: x509.Certificate, - intermediates: list[x509.Certificate], - ) -> list[x509.Certificate]: ... - -class Store: - def __init__(self, certs: list[x509.Certificate]) -> None: ... - -class VerificationError(Exception): ... diff --git a/venv/lib/python3.9/site-packages/cryptography/hazmat/bindings/openssl/__init__.py b/venv/lib/python3.9/site-packages/cryptography/hazmat/bindings/openssl/__init__.py deleted file mode 100644 index b509336..0000000 --- a/venv/lib/python3.9/site-packages/cryptography/hazmat/bindings/openssl/__init__.py +++ /dev/null @@ -1,3 +0,0 @@ -# This file is dual licensed under the terms of the Apache License, Version -# 2.0, and the BSD License. See the LICENSE file in the root of this repository -# for complete details. diff --git a/venv/lib/python3.9/site-packages/cryptography/hazmat/bindings/openssl/_conditional.py b/venv/lib/python3.9/site-packages/cryptography/hazmat/bindings/openssl/_conditional.py deleted file mode 100644 index 1e447a5..0000000 --- a/venv/lib/python3.9/site-packages/cryptography/hazmat/bindings/openssl/_conditional.py +++ /dev/null @@ -1,199 +0,0 @@ -# This file is dual licensed under the terms of the Apache License, Version -# 2.0, and the BSD License. See the LICENSE file in the root of this repository -# for complete details. - -from __future__ import annotations - - -def cryptography_has_set_cert_cb() -> list[str]: - return [ - "SSL_CTX_set_cert_cb", - "SSL_set_cert_cb", - ] - - -def cryptography_has_ssl_st() -> list[str]: - return [ - "SSL_ST_BEFORE", - "SSL_ST_OK", - "SSL_ST_INIT", - "SSL_ST_RENEGOTIATE", - ] - - -def cryptography_has_tls_st() -> list[str]: - return [ - "TLS_ST_BEFORE", - "TLS_ST_OK", - ] - - -def cryptography_has_ssl_sigalgs() -> list[str]: - return [ - "SSL_CTX_set1_sigalgs_list", - ] - - -def cryptography_has_psk() -> list[str]: - return [ - "SSL_CTX_use_psk_identity_hint", - "SSL_CTX_set_psk_server_callback", - "SSL_CTX_set_psk_client_callback", - ] - - -def cryptography_has_psk_tlsv13() -> list[str]: - return [ - "SSL_CTX_set_psk_find_session_callback", - "SSL_CTX_set_psk_use_session_callback", - "Cryptography_SSL_SESSION_new", - "SSL_CIPHER_find", - "SSL_SESSION_set1_master_key", - "SSL_SESSION_set_cipher", - "SSL_SESSION_set_protocol_version", - ] - - -def cryptography_has_custom_ext() -> list[str]: - return [ - "SSL_CTX_add_client_custom_ext", - "SSL_CTX_add_server_custom_ext", - "SSL_extension_supported", - ] - - -def cryptography_has_tlsv13_functions() -> list[str]: - return [ - "SSL_CTX_set_ciphersuites", - ] - - -def cryptography_has_tlsv13_hs_functions() -> list[str]: - return [ - "SSL_VERIFY_POST_HANDSHAKE", - "SSL_verify_client_post_handshake", - "SSL_CTX_set_post_handshake_auth", - "SSL_set_post_handshake_auth", - "SSL_SESSION_get_max_early_data", - "SSL_write_early_data", - "SSL_read_early_data", - "SSL_CTX_set_max_early_data", - ] - - -def cryptography_has_ssl_verify_client_post_handshake() -> list[str]: - return [ - "SSL_verify_client_post_handshake", - ] - - -def cryptography_has_engine() -> list[str]: - return [ - "ENGINE_by_id", - "ENGINE_init", - "ENGINE_finish", - "ENGINE_get_default_RAND", - "ENGINE_set_default_RAND", - "ENGINE_unregister_RAND", - "ENGINE_ctrl_cmd", - "ENGINE_free", - "ENGINE_get_name", - "ENGINE_ctrl_cmd_string", - "ENGINE_load_builtin_engines", - "ENGINE_load_private_key", - "ENGINE_load_public_key", - "SSL_CTX_set_client_cert_engine", - ] - - -def cryptography_has_verified_chain() -> list[str]: - return [ - "SSL_get0_verified_chain", - ] - - -def cryptography_has_srtp() -> list[str]: - return [ - "SSL_CTX_set_tlsext_use_srtp", - "SSL_set_tlsext_use_srtp", - "SSL_get_selected_srtp_profile", - ] - - -def cryptography_has_dtls_get_data_mtu() -> list[str]: - return [ - "DTLS_get_data_mtu", - ] - - -def cryptography_has_ssl_cookie() -> list[str]: - return [ - "SSL_OP_COOKIE_EXCHANGE", - "DTLS1_COOKIE_LENGTH", - "DTLSv1_listen", - "SSL_CTX_set_cookie_generate_cb", - "SSL_CTX_set_cookie_verify_cb", - ] - - -def cryptography_has_prime_checks() -> list[str]: - return [ - "BN_prime_checks_for_size", - ] - - -def cryptography_has_unexpected_eof_while_reading() -> list[str]: - return ["SSL_R_UNEXPECTED_EOF_WHILE_READING"] - - -def cryptography_has_ssl_op_ignore_unexpected_eof() -> list[str]: - return [ - "SSL_OP_IGNORE_UNEXPECTED_EOF", - ] - - -def cryptography_has_get_extms_support() -> list[str]: - return ["SSL_get_extms_support"] - - -def cryptography_has_ssl_get0_group_name() -> list[str]: - return ["SSL_get0_group_name"] - - -# This is a mapping of -# {condition: function-returning-names-dependent-on-that-condition} so we can -# loop over them and delete unsupported names at runtime. It will be removed -# when cffi supports #if in cdef. We use functions instead of just a dict of -# lists so we can use coverage to measure which are used. -CONDITIONAL_NAMES = { - "Cryptography_HAS_SET_CERT_CB": cryptography_has_set_cert_cb, - "Cryptography_HAS_SSL_ST": cryptography_has_ssl_st, - "Cryptography_HAS_TLS_ST": cryptography_has_tls_st, - "Cryptography_HAS_SIGALGS": cryptography_has_ssl_sigalgs, - "Cryptography_HAS_PSK": cryptography_has_psk, - "Cryptography_HAS_PSK_TLSv1_3": cryptography_has_psk_tlsv13, - "Cryptography_HAS_CUSTOM_EXT": cryptography_has_custom_ext, - "Cryptography_HAS_TLSv1_3_FUNCTIONS": cryptography_has_tlsv13_functions, - "Cryptography_HAS_TLSv1_3_HS_FUNCTIONS": ( - cryptography_has_tlsv13_hs_functions - ), - "Cryptography_HAS_SSL_VERIFY_CLIENT_POST_HANDSHAKE": ( - cryptography_has_ssl_verify_client_post_handshake - ), - "Cryptography_HAS_ENGINE": cryptography_has_engine, - "Cryptography_HAS_VERIFIED_CHAIN": cryptography_has_verified_chain, - "Cryptography_HAS_SRTP": cryptography_has_srtp, - "Cryptography_HAS_DTLS_GET_DATA_MTU": cryptography_has_dtls_get_data_mtu, - "Cryptography_HAS_SSL_COOKIE": cryptography_has_ssl_cookie, - "Cryptography_HAS_PRIME_CHECKS": cryptography_has_prime_checks, - "Cryptography_HAS_UNEXPECTED_EOF_WHILE_READING": ( - cryptography_has_unexpected_eof_while_reading - ), - "Cryptography_HAS_SSL_OP_IGNORE_UNEXPECTED_EOF": ( - cryptography_has_ssl_op_ignore_unexpected_eof - ), - "Cryptography_HAS_GET_EXTMS_SUPPORT": cryptography_has_get_extms_support, - "Cryptography_HAS_SSL_GET0_GROUP_NAME": ( - cryptography_has_ssl_get0_group_name - ), -} diff --git a/venv/lib/python3.9/site-packages/cryptography/hazmat/bindings/openssl/binding.py b/venv/lib/python3.9/site-packages/cryptography/hazmat/bindings/openssl/binding.py deleted file mode 100644 index 6a0cafd..0000000 --- a/venv/lib/python3.9/site-packages/cryptography/hazmat/bindings/openssl/binding.py +++ /dev/null @@ -1,122 +0,0 @@ -# This file is dual licensed under the terms of the Apache License, Version -# 2.0, and the BSD License. See the LICENSE file in the root of this repository -# for complete details. - -from __future__ import annotations - -import os -import sys -import threading -import types -import typing -import warnings -from collections.abc import Callable - -import cryptography -from cryptography.exceptions import InternalError -from cryptography.hazmat.bindings._rust import _openssl, openssl -from cryptography.hazmat.bindings.openssl._conditional import CONDITIONAL_NAMES - - -def _openssl_assert(ok: bool) -> None: - if not ok: - errors = openssl.capture_error_stack() - - raise InternalError( - "Unknown OpenSSL error. This error is commonly encountered when " - "another library is not cleaning up the OpenSSL error stack. If " - "you are using cryptography with another library that uses " - "OpenSSL try disabling it before reporting a bug. Otherwise " - "please file an issue at https://github.com/pyca/cryptography/" - "issues with information on how to reproduce " - f"this. ({errors!r})", - errors, - ) - - -def build_conditional_library( - lib: typing.Any, - conditional_names: dict[str, Callable[[], list[str]]], -) -> typing.Any: - conditional_lib = types.ModuleType("lib") - conditional_lib._original_lib = lib # type: ignore[attr-defined] - excluded_names = set() - for condition, names_cb in conditional_names.items(): - if not getattr(lib, condition): - excluded_names.update(names_cb()) - - for attr in dir(lib): - if attr not in excluded_names: - setattr(conditional_lib, attr, getattr(lib, attr)) - - return conditional_lib - - -class Binding: - """ - OpenSSL API wrapper. - """ - - lib: typing.ClassVar[typing.Any] = None - ffi: typing.Any = _openssl.ffi - _lib_loaded = False - _init_lock = threading.Lock() - - def __init__(self) -> None: - self._ensure_ffi_initialized() - - @classmethod - def _ensure_ffi_initialized(cls) -> None: - with cls._init_lock: - if not cls._lib_loaded: - cls.lib = build_conditional_library( - _openssl.lib, CONDITIONAL_NAMES - ) - cls._lib_loaded = True - - @classmethod - def init_static_locks(cls) -> None: - cls._ensure_ffi_initialized() - - -def _verify_package_version(version: str) -> None: - # Occasionally we run into situations where the version of the Python - # package does not match the version of the shared object that is loaded. - # This may occur in environments where multiple versions of cryptography - # are installed and available in the python path. To avoid errors cropping - # up later this code checks that the currently imported package and the - # shared object that were loaded have the same version and raise an - # ImportError if they do not - so_package_version = _openssl.ffi.string( - _openssl.lib.CRYPTOGRAPHY_PACKAGE_VERSION - ) - if version.encode("ascii") != so_package_version: - raise ImportError( - "The version of cryptography does not match the loaded " - "shared object. This can happen if you have multiple copies of " - "cryptography installed in your Python path. Please try creating " - "a new virtual environment to resolve this issue. " - f"Loaded python version: {version}, " - f"shared object version: {so_package_version}" - ) - - _openssl_assert( - _openssl.lib.OpenSSL_version_num() == openssl.openssl_version(), - ) - - -_verify_package_version(cryptography.__version__) - -Binding.init_static_locks() - -if ( - sys.platform == "win32" - and os.environ.get("PROCESSOR_ARCHITEW6432") is not None -): - warnings.warn( - "You are using cryptography on a 32-bit Python on a 64-bit Windows " - "Operating System. Cryptography will be significantly faster if you " - "switch to using a 64-bit Python.", - UserWarning, - stacklevel=2, - ) diff --git a/venv/lib/python3.9/site-packages/cryptography/hazmat/decrepit/__init__.py b/venv/lib/python3.9/site-packages/cryptography/hazmat/decrepit/__init__.py deleted file mode 100644 index 41d7318..0000000 --- a/venv/lib/python3.9/site-packages/cryptography/hazmat/decrepit/__init__.py +++ /dev/null @@ -1,5 +0,0 @@ -# This file is dual licensed under the terms of the Apache License, Version -# 2.0, and the BSD License. See the LICENSE file in the root of this repository -# for complete details. - -from __future__ import annotations diff --git a/venv/lib/python3.9/site-packages/cryptography/hazmat/decrepit/ciphers/__init__.py b/venv/lib/python3.9/site-packages/cryptography/hazmat/decrepit/ciphers/__init__.py deleted file mode 100644 index 41d7318..0000000 --- a/venv/lib/python3.9/site-packages/cryptography/hazmat/decrepit/ciphers/__init__.py +++ /dev/null @@ -1,5 +0,0 @@ -# This file is dual licensed under the terms of the Apache License, Version -# 2.0, and the BSD License. See the LICENSE file in the root of this repository -# for complete details. - -from __future__ import annotations diff --git a/venv/lib/python3.9/site-packages/cryptography/hazmat/decrepit/ciphers/algorithms.py b/venv/lib/python3.9/site-packages/cryptography/hazmat/decrepit/ciphers/algorithms.py deleted file mode 100644 index 703c8e4..0000000 --- a/venv/lib/python3.9/site-packages/cryptography/hazmat/decrepit/ciphers/algorithms.py +++ /dev/null @@ -1,142 +0,0 @@ -# This file is dual licensed under the terms of the Apache License, Version -# 2.0, and the BSD License. See the LICENSE file in the root of this repository -# for complete details. - -from __future__ import annotations - -import warnings - -from cryptography import utils -from cryptography.hazmat.primitives._cipheralgorithm import ( - BlockCipherAlgorithm, - CipherAlgorithm, - _verify_key_size, -) - - -class ARC4(CipherAlgorithm): - name = "RC4" - key_sizes = frozenset([40, 56, 64, 80, 128, 160, 192, 256]) - - def __init__(self, key: bytes): - self.key = _verify_key_size(self, key) - - @property - def key_size(self) -> int: - return len(self.key) * 8 - - -class TripleDES(BlockCipherAlgorithm): - name = "3DES" - block_size = 64 - key_sizes = frozenset([64, 128, 192]) - - def __init__(self, key: bytes): - if len(key) == 8: - warnings.warn( - "Single-key TripleDES (8-byte keys) is deprecated and " - "support will be removed in a future release. Use 24-byte " - "keys instead (e.g., key + key + key).", - utils.DeprecatedIn47, - stacklevel=2, - ) - key = key + key + key - elif len(key) == 16: - warnings.warn( - "Two-key TripleDES (16-byte keys) is deprecated and " - "support will be removed in a future release. Use 24-byte " - "keys instead (e.g., key + key[:8]).", - utils.DeprecatedIn47, - stacklevel=2, - ) - key = key + key[:8] - self.key = _verify_key_size(self, key) - - @property - def key_size(self) -> int: - return len(self.key) * 8 - - -# Not actually supported, marker for tests -class _DES: - key_size = 64 - - -class Blowfish(BlockCipherAlgorithm): - name = "Blowfish" - block_size = 64 - key_sizes = frozenset(range(32, 449, 8)) - - def __init__(self, key: bytes): - self.key = _verify_key_size(self, key) - - @property - def key_size(self) -> int: - return len(self.key) * 8 - - -class CAST5(BlockCipherAlgorithm): - name = "CAST5" - block_size = 64 - key_sizes = frozenset(range(40, 129, 8)) - - def __init__(self, key: bytes): - self.key = _verify_key_size(self, key) - - @property - def key_size(self) -> int: - return len(self.key) * 8 - - -class SEED(BlockCipherAlgorithm): - name = "SEED" - block_size = 128 - key_sizes = frozenset([128]) - - def __init__(self, key: bytes): - self.key = _verify_key_size(self, key) - - @property - def key_size(self) -> int: - return len(self.key) * 8 - - -class IDEA(BlockCipherAlgorithm): - name = "IDEA" - block_size = 64 - key_sizes = frozenset([128]) - - def __init__(self, key: bytes): - self.key = _verify_key_size(self, key) - - @property - def key_size(self) -> int: - return len(self.key) * 8 - - -class Camellia(BlockCipherAlgorithm): - name = "camellia" - block_size = 128 - key_sizes = frozenset([128, 192, 256]) - - def __init__(self, key: bytes): - self.key = _verify_key_size(self, key) - - @property - def key_size(self) -> int: - return len(self.key) * 8 - - -# This class only allows RC2 with a 128-bit key. No support for -# effective key bits or other key sizes is provided. -class RC2(BlockCipherAlgorithm): - name = "RC2" - block_size = 64 - key_sizes = frozenset([128]) - - def __init__(self, key: bytes): - self.key = _verify_key_size(self, key) - - @property - def key_size(self) -> int: - return len(self.key) * 8 diff --git a/venv/lib/python3.9/site-packages/cryptography/hazmat/decrepit/ciphers/modes.py b/venv/lib/python3.9/site-packages/cryptography/hazmat/decrepit/ciphers/modes.py deleted file mode 100644 index 1786bb0..0000000 --- a/venv/lib/python3.9/site-packages/cryptography/hazmat/decrepit/ciphers/modes.py +++ /dev/null @@ -1,53 +0,0 @@ -# This file is dual licensed under the terms of the Apache License, Version -# 2.0, and the BSD License. See the LICENSE file in the root of this repository -# for complete details. - -from __future__ import annotations - -from cryptography import utils -from cryptography.hazmat.primitives._modes import ( - ModeWithInitializationVector, - _check_iv_and_key_length, -) - - -class OFB(ModeWithInitializationVector): - name = "OFB" - - def __init__(self, initialization_vector: utils.Buffer): - utils._check_byteslike("initialization_vector", initialization_vector) - self._initialization_vector = initialization_vector - - @property - def initialization_vector(self) -> utils.Buffer: - return self._initialization_vector - - validate_for_algorithm = _check_iv_and_key_length - - -class CFB(ModeWithInitializationVector): - name = "CFB" - - def __init__(self, initialization_vector: utils.Buffer): - utils._check_byteslike("initialization_vector", initialization_vector) - self._initialization_vector = initialization_vector - - @property - def initialization_vector(self) -> utils.Buffer: - return self._initialization_vector - - validate_for_algorithm = _check_iv_and_key_length - - -class CFB8(ModeWithInitializationVector): - name = "CFB8" - - def __init__(self, initialization_vector: utils.Buffer): - utils._check_byteslike("initialization_vector", initialization_vector) - self._initialization_vector = initialization_vector - - @property - def initialization_vector(self) -> utils.Buffer: - return self._initialization_vector - - validate_for_algorithm = _check_iv_and_key_length diff --git a/venv/lib/python3.9/site-packages/cryptography/hazmat/primitives/__init__.py b/venv/lib/python3.9/site-packages/cryptography/hazmat/primitives/__init__.py deleted file mode 100644 index b509336..0000000 --- a/venv/lib/python3.9/site-packages/cryptography/hazmat/primitives/__init__.py +++ /dev/null @@ -1,3 +0,0 @@ -# This file is dual licensed under the terms of the Apache License, Version -# 2.0, and the BSD License. See the LICENSE file in the root of this repository -# for complete details. diff --git a/venv/lib/python3.9/site-packages/cryptography/hazmat/primitives/_asymmetric.py b/venv/lib/python3.9/site-packages/cryptography/hazmat/primitives/_asymmetric.py deleted file mode 100644 index ea55ffd..0000000 --- a/venv/lib/python3.9/site-packages/cryptography/hazmat/primitives/_asymmetric.py +++ /dev/null @@ -1,19 +0,0 @@ -# This file is dual licensed under the terms of the Apache License, Version -# 2.0, and the BSD License. See the LICENSE file in the root of this repository -# for complete details. - -from __future__ import annotations - -import abc - -# This exists to break an import cycle. It is normally accessible from the -# asymmetric padding module. - - -class AsymmetricPadding(metaclass=abc.ABCMeta): - @property - @abc.abstractmethod - def name(self) -> str: - """ - A string naming this padding (e.g. "PSS", "PKCS1"). - """ diff --git a/venv/lib/python3.9/site-packages/cryptography/hazmat/primitives/_cipheralgorithm.py b/venv/lib/python3.9/site-packages/cryptography/hazmat/primitives/_cipheralgorithm.py deleted file mode 100644 index 305a9fd..0000000 --- a/venv/lib/python3.9/site-packages/cryptography/hazmat/primitives/_cipheralgorithm.py +++ /dev/null @@ -1,60 +0,0 @@ -# This file is dual licensed under the terms of the Apache License, Version -# 2.0, and the BSD License. See the LICENSE file in the root of this repository -# for complete details. - -from __future__ import annotations - -import abc - -from cryptography import utils - -# This exists to break an import cycle. It is normally accessible from the -# ciphers module. - - -class CipherAlgorithm(metaclass=abc.ABCMeta): - @property - @abc.abstractmethod - def name(self) -> str: - """ - A string naming this mode (e.g. "AES", "Camellia"). - """ - - @property - @abc.abstractmethod - def key_sizes(self) -> frozenset[int]: - """ - Valid key sizes for this algorithm in bits - """ - - @property - @abc.abstractmethod - def key_size(self) -> int: - """ - The size of the key being used as an integer in bits (e.g. 128, 256). - """ - - -class BlockCipherAlgorithm(CipherAlgorithm): - key: utils.Buffer - - @property - @abc.abstractmethod - def block_size(self) -> int: - """ - The size of a block as an integer in bits (e.g. 64, 128). - """ - - -def _verify_key_size( - algorithm: CipherAlgorithm, key: utils.Buffer -) -> utils.Buffer: - # Verify that the key is instance of bytes - utils._check_byteslike("key", key) - - # Verify that the key size matches the expected key size - if len(key) * 8 not in algorithm.key_sizes: - raise ValueError( - f"Invalid key size ({len(key) * 8}) for {algorithm.name}." - ) - return key diff --git a/venv/lib/python3.9/site-packages/cryptography/hazmat/primitives/_modes.py b/venv/lib/python3.9/site-packages/cryptography/hazmat/primitives/_modes.py deleted file mode 100644 index deae8bc..0000000 --- a/venv/lib/python3.9/site-packages/cryptography/hazmat/primitives/_modes.py +++ /dev/null @@ -1,105 +0,0 @@ -# This file is dual licensed under the terms of the Apache License, Version -# 2.0, and the BSD License. See the LICENSE file in the root of this repository -# for complete details. - -from __future__ import annotations - -import abc - -from cryptography import utils -from cryptography.exceptions import UnsupportedAlgorithm, _Reasons -from cryptography.hazmat.primitives._cipheralgorithm import ( - BlockCipherAlgorithm, - CipherAlgorithm, -) - - -class Mode(metaclass=abc.ABCMeta): - @property - @abc.abstractmethod - def name(self) -> str: - """ - A string naming this mode (e.g. "ECB", "CBC"). - """ - - @abc.abstractmethod - def validate_for_algorithm(self, algorithm: CipherAlgorithm) -> None: - """ - Checks that all the necessary invariants of this (mode, algorithm) - combination are met. - """ - - -class ModeWithInitializationVector(Mode, metaclass=abc.ABCMeta): - @property - @abc.abstractmethod - def initialization_vector(self) -> utils.Buffer: - """ - The value of the initialization vector for this mode as bytes. - """ - - -class ModeWithTweak(Mode, metaclass=abc.ABCMeta): - @property - @abc.abstractmethod - def tweak(self) -> utils.Buffer: - """ - The value of the tweak for this mode as bytes. - """ - - -class ModeWithNonce(Mode, metaclass=abc.ABCMeta): - @property - @abc.abstractmethod - def nonce(self) -> utils.Buffer: - """ - The value of the nonce for this mode as bytes. - """ - - -class ModeWithAuthenticationTag(Mode, metaclass=abc.ABCMeta): - @property - @abc.abstractmethod - def tag(self) -> bytes | None: - """ - The value of the tag supplied to the constructor of this mode. - """ - - -def _check_aes_key_length(self: Mode, algorithm: CipherAlgorithm) -> None: - if algorithm.key_size > 256 and algorithm.name == "AES": - raise ValueError( - "Only 128, 192, and 256 bit keys are allowed for this AES mode" - ) - - -def _check_iv_length( - self: ModeWithInitializationVector, algorithm: BlockCipherAlgorithm -) -> None: - iv_len = len(self.initialization_vector) - if iv_len * 8 != algorithm.block_size: - raise ValueError(f"Invalid IV size ({iv_len}) for {self.name}.") - - -def _check_nonce_length( - nonce: utils.Buffer, name: str, algorithm: CipherAlgorithm -) -> None: - if not isinstance(algorithm, BlockCipherAlgorithm): - raise UnsupportedAlgorithm( - f"{name} requires a block cipher algorithm", - _Reasons.UNSUPPORTED_CIPHER, - ) - if len(nonce) * 8 != algorithm.block_size: - raise ValueError(f"Invalid nonce size ({len(nonce)}) for {name}.") - - -def _check_iv_and_key_length( - self: ModeWithInitializationVector, algorithm: CipherAlgorithm -) -> None: - if not isinstance(algorithm, BlockCipherAlgorithm): - raise UnsupportedAlgorithm( - f"{self} requires a block cipher algorithm", - _Reasons.UNSUPPORTED_CIPHER, - ) - _check_aes_key_length(self, algorithm) - _check_iv_length(self, algorithm) diff --git a/venv/lib/python3.9/site-packages/cryptography/hazmat/primitives/_serialization.py b/venv/lib/python3.9/site-packages/cryptography/hazmat/primitives/_serialization.py deleted file mode 100644 index 9c3c474..0000000 --- a/venv/lib/python3.9/site-packages/cryptography/hazmat/primitives/_serialization.py +++ /dev/null @@ -1,136 +0,0 @@ -# This file is dual licensed under the terms of the Apache License, Version -# 2.0, and the BSD License. See the LICENSE file in the root of this repository -# for complete details. - -from __future__ import annotations - -import abc - -from cryptography import utils -from cryptography.hazmat.bindings._rust import Encoding as Encoding -from cryptography.hazmat.bindings._rust import ( - ParameterFormat as ParameterFormat, -) -from cryptography.hazmat.bindings._rust import PrivateFormat as PrivateFormat -from cryptography.hazmat.bindings._rust import PublicFormat as PublicFormat -from cryptography.hazmat.primitives.hashes import HashAlgorithm - -# This exists to break an import cycle. These classes are normally accessible -# from the serialization module. - - -class PBES(utils.Enum): - PBESv1SHA1And3KeyTripleDESCBC = "PBESv1 using SHA1 and 3-Key TripleDES" - PBESv2SHA256AndAES256CBC = "PBESv2 using SHA256 PBKDF2 and AES256 CBC" - - -class KeySerializationEncryption(metaclass=abc.ABCMeta): - pass - - -class BestAvailableEncryption(KeySerializationEncryption): - def __init__(self, password: bytes): - if not isinstance(password, bytes) or len(password) == 0: - raise ValueError("Password must be 1 or more bytes.") - - self.password = password - - -class NoEncryption(KeySerializationEncryption): - pass - - -class KeySerializationEncryptionBuilder: - def __init__( - self, - format: PrivateFormat, - *, - _kdf_rounds: int | None = None, - _hmac_hash: HashAlgorithm | None = None, - _key_cert_algorithm: PBES | None = None, - ) -> None: - self._format = format - - self._kdf_rounds = _kdf_rounds - self._hmac_hash = _hmac_hash - self._key_cert_algorithm = _key_cert_algorithm - - def kdf_rounds(self, rounds: int) -> KeySerializationEncryptionBuilder: - if self._kdf_rounds is not None: - raise ValueError("kdf_rounds already set") - - if not isinstance(rounds, int): - raise TypeError("kdf_rounds must be an integer") - - if rounds < 1: - raise ValueError("kdf_rounds must be a positive integer") - - return KeySerializationEncryptionBuilder( - self._format, - _kdf_rounds=rounds, - _hmac_hash=self._hmac_hash, - _key_cert_algorithm=self._key_cert_algorithm, - ) - - def hmac_hash( - self, algorithm: HashAlgorithm - ) -> KeySerializationEncryptionBuilder: - if self._format is not PrivateFormat.PKCS12: - raise TypeError( - "hmac_hash only supported with PrivateFormat.PKCS12" - ) - - if self._hmac_hash is not None: - raise ValueError("hmac_hash already set") - return KeySerializationEncryptionBuilder( - self._format, - _kdf_rounds=self._kdf_rounds, - _hmac_hash=algorithm, - _key_cert_algorithm=self._key_cert_algorithm, - ) - - def key_cert_algorithm( - self, algorithm: PBES - ) -> KeySerializationEncryptionBuilder: - if self._format is not PrivateFormat.PKCS12: - raise TypeError( - "key_cert_algorithm only supported with PrivateFormat.PKCS12" - ) - if self._key_cert_algorithm is not None: - raise ValueError("key_cert_algorithm already set") - return KeySerializationEncryptionBuilder( - self._format, - _kdf_rounds=self._kdf_rounds, - _hmac_hash=self._hmac_hash, - _key_cert_algorithm=algorithm, - ) - - def build(self, password: bytes) -> KeySerializationEncryption: - if not isinstance(password, bytes) or len(password) == 0: - raise ValueError("Password must be 1 or more bytes.") - - return _KeySerializationEncryption( - self._format, - password, - kdf_rounds=self._kdf_rounds, - hmac_hash=self._hmac_hash, - key_cert_algorithm=self._key_cert_algorithm, - ) - - -class _KeySerializationEncryption(KeySerializationEncryption): - def __init__( - self, - format: PrivateFormat, - password: bytes, - *, - kdf_rounds: int | None, - hmac_hash: HashAlgorithm | None, - key_cert_algorithm: PBES | None, - ): - self._format = format - self.password = password - - self._kdf_rounds = kdf_rounds - self._hmac_hash = hmac_hash - self._key_cert_algorithm = key_cert_algorithm diff --git a/venv/lib/python3.9/site-packages/cryptography/hazmat/primitives/asymmetric/__init__.py b/venv/lib/python3.9/site-packages/cryptography/hazmat/primitives/asymmetric/__init__.py deleted file mode 100644 index b509336..0000000 --- a/venv/lib/python3.9/site-packages/cryptography/hazmat/primitives/asymmetric/__init__.py +++ /dev/null @@ -1,3 +0,0 @@ -# This file is dual licensed under the terms of the Apache License, Version -# 2.0, and the BSD License. See the LICENSE file in the root of this repository -# for complete details. diff --git a/venv/lib/python3.9/site-packages/cryptography/hazmat/primitives/asymmetric/dh.py b/venv/lib/python3.9/site-packages/cryptography/hazmat/primitives/asymmetric/dh.py deleted file mode 100644 index 2f6b834..0000000 --- a/venv/lib/python3.9/site-packages/cryptography/hazmat/primitives/asymmetric/dh.py +++ /dev/null @@ -1,159 +0,0 @@ -# This file is dual licensed under the terms of the Apache License, Version -# 2.0, and the BSD License. See the LICENSE file in the root of this repository -# for complete details. - -from __future__ import annotations - -import abc - -from cryptography.hazmat.bindings._rust import openssl as rust_openssl -from cryptography.hazmat.primitives import _serialization - -generate_parameters = rust_openssl.dh.generate_parameters - - -DHPrivateNumbers = rust_openssl.dh.DHPrivateNumbers -DHPublicNumbers = rust_openssl.dh.DHPublicNumbers -DHParameterNumbers = rust_openssl.dh.DHParameterNumbers - - -class DHParameters(metaclass=abc.ABCMeta): - @abc.abstractmethod - def generate_private_key(self) -> DHPrivateKey: - """ - Generates and returns a DHPrivateKey. - """ - - @abc.abstractmethod - def parameter_bytes( - self, - encoding: _serialization.Encoding, - format: _serialization.ParameterFormat, - ) -> bytes: - """ - Returns the parameters serialized as bytes. - """ - - @abc.abstractmethod - def parameter_numbers(self) -> DHParameterNumbers: - """ - Returns a DHParameterNumbers. - """ - - -DHParametersWithSerialization = DHParameters -DHParameters.register(rust_openssl.dh.DHParameters) - - -class DHPublicKey(metaclass=abc.ABCMeta): - @property - @abc.abstractmethod - def key_size(self) -> int: - """ - The bit length of the prime modulus. - """ - - @abc.abstractmethod - def parameters(self) -> DHParameters: - """ - The DHParameters object associated with this public key. - """ - - @abc.abstractmethod - def public_numbers(self) -> DHPublicNumbers: - """ - Returns a DHPublicNumbers. - """ - - @abc.abstractmethod - def public_bytes( - self, - encoding: _serialization.Encoding, - format: _serialization.PublicFormat, - ) -> bytes: - """ - Returns the key serialized as bytes. - """ - - @abc.abstractmethod - def __eq__(self, other: object) -> bool: - """ - Checks equality. - """ - - @abc.abstractmethod - def __copy__(self) -> DHPublicKey: - """ - Returns a copy. - """ - - @abc.abstractmethod - def __deepcopy__(self, memo: dict) -> DHPublicKey: - """ - Returns a deep copy. - """ - - -DHPublicKeyWithSerialization = DHPublicKey -DHPublicKey.register(rust_openssl.dh.DHPublicKey) - - -class DHPrivateKey(metaclass=abc.ABCMeta): - @property - @abc.abstractmethod - def key_size(self) -> int: - """ - The bit length of the prime modulus. - """ - - @abc.abstractmethod - def public_key(self) -> DHPublicKey: - """ - The DHPublicKey associated with this private key. - """ - - @abc.abstractmethod - def parameters(self) -> DHParameters: - """ - The DHParameters object associated with this private key. - """ - - @abc.abstractmethod - def exchange(self, peer_public_key: DHPublicKey) -> bytes: - """ - Given peer's DHPublicKey, carry out the key exchange and - return shared key as bytes. - """ - - @abc.abstractmethod - def private_numbers(self) -> DHPrivateNumbers: - """ - Returns a DHPrivateNumbers. - """ - - @abc.abstractmethod - def private_bytes( - self, - encoding: _serialization.Encoding, - format: _serialization.PrivateFormat, - encryption_algorithm: _serialization.KeySerializationEncryption, - ) -> bytes: - """ - Returns the key serialized as bytes. - """ - - @abc.abstractmethod - def __copy__(self) -> DHPrivateKey: - """ - Returns a copy. - """ - - @abc.abstractmethod - def __deepcopy__(self, memo: dict) -> DHPrivateKey: - """ - Returns a deep copy. - """ - - -DHPrivateKeyWithSerialization = DHPrivateKey -DHPrivateKey.register(rust_openssl.dh.DHPrivateKey) diff --git a/venv/lib/python3.9/site-packages/cryptography/hazmat/primitives/asymmetric/dsa.py b/venv/lib/python3.9/site-packages/cryptography/hazmat/primitives/asymmetric/dsa.py deleted file mode 100644 index f245557..0000000 --- a/venv/lib/python3.9/site-packages/cryptography/hazmat/primitives/asymmetric/dsa.py +++ /dev/null @@ -1,179 +0,0 @@ -# This file is dual licensed under the terms of the Apache License, Version -# 2.0, and the BSD License. See the LICENSE file in the root of this repository -# for complete details. - -from __future__ import annotations - -import abc -import typing - -from cryptography.hazmat.bindings._rust import openssl as rust_openssl -from cryptography.hazmat.primitives import _serialization, hashes -from cryptography.hazmat.primitives.asymmetric import utils as asym_utils -from cryptography.utils import Buffer - - -class DSAParameters(metaclass=abc.ABCMeta): - @abc.abstractmethod - def generate_private_key(self) -> DSAPrivateKey: - """ - Generates and returns a DSAPrivateKey. - """ - - @abc.abstractmethod - def parameter_numbers(self) -> DSAParameterNumbers: - """ - Returns a DSAParameterNumbers. - """ - - -DSAParametersWithNumbers = DSAParameters -DSAParameters.register(rust_openssl.dsa.DSAParameters) - - -class DSAPrivateKey(metaclass=abc.ABCMeta): - @property - @abc.abstractmethod - def key_size(self) -> int: - """ - The bit length of the prime modulus. - """ - - @abc.abstractmethod - def public_key(self) -> DSAPublicKey: - """ - The DSAPublicKey associated with this private key. - """ - - @abc.abstractmethod - def parameters(self) -> DSAParameters: - """ - The DSAParameters object associated with this private key. - """ - - @abc.abstractmethod - def sign( - self, - data: Buffer, - algorithm: asym_utils.Prehashed | hashes.HashAlgorithm, - ) -> bytes: - """ - Signs the data - """ - - @abc.abstractmethod - def private_numbers(self) -> DSAPrivateNumbers: - """ - Returns a DSAPrivateNumbers. - """ - - @abc.abstractmethod - def private_bytes( - self, - encoding: _serialization.Encoding, - format: _serialization.PrivateFormat, - encryption_algorithm: _serialization.KeySerializationEncryption, - ) -> bytes: - """ - Returns the key serialized as bytes. - """ - - @abc.abstractmethod - def __copy__(self) -> DSAPrivateKey: - """ - Returns a copy. - """ - - @abc.abstractmethod - def __deepcopy__(self, memo: dict) -> DSAPrivateKey: - """ - Returns a deep copy. - """ - - -DSAPrivateKeyWithSerialization = DSAPrivateKey -DSAPrivateKey.register(rust_openssl.dsa.DSAPrivateKey) - - -class DSAPublicKey(metaclass=abc.ABCMeta): - @property - @abc.abstractmethod - def key_size(self) -> int: - """ - The bit length of the prime modulus. - """ - - @abc.abstractmethod - def parameters(self) -> DSAParameters: - """ - The DSAParameters object associated with this public key. - """ - - @abc.abstractmethod - def public_numbers(self) -> DSAPublicNumbers: - """ - Returns a DSAPublicNumbers. - """ - - @abc.abstractmethod - def public_bytes( - self, - encoding: _serialization.Encoding, - format: _serialization.PublicFormat, - ) -> bytes: - """ - Returns the key serialized as bytes. - """ - - @abc.abstractmethod - def verify( - self, - signature: Buffer, - data: Buffer, - algorithm: asym_utils.Prehashed | hashes.HashAlgorithm, - ) -> None: - """ - Verifies the signature of the data. - """ - - @abc.abstractmethod - def __eq__(self, other: object) -> bool: - """ - Checks equality. - """ - - @abc.abstractmethod - def __copy__(self) -> DSAPublicKey: - """ - Returns a copy. - """ - - @abc.abstractmethod - def __deepcopy__(self, memo: dict) -> DSAPublicKey: - """ - Returns a deep copy. - """ - - -DSAPublicKeyWithSerialization = DSAPublicKey -DSAPublicKey.register(rust_openssl.dsa.DSAPublicKey) - -DSAPrivateNumbers = rust_openssl.dsa.DSAPrivateNumbers -DSAPublicNumbers = rust_openssl.dsa.DSAPublicNumbers -DSAParameterNumbers = rust_openssl.dsa.DSAParameterNumbers - - -def generate_parameters( - key_size: int, backend: typing.Any = None -) -> DSAParameters: - if key_size not in (1024, 2048, 3072, 4096): - raise ValueError("Key size must be 1024, 2048, 3072, or 4096 bits.") - - return rust_openssl.dsa.generate_parameters(key_size) - - -def generate_private_key( - key_size: int, backend: typing.Any = None -) -> DSAPrivateKey: - parameters = generate_parameters(key_size) - return parameters.generate_private_key() diff --git a/venv/lib/python3.9/site-packages/cryptography/hazmat/primitives/asymmetric/ec.py b/venv/lib/python3.9/site-packages/cryptography/hazmat/primitives/asymmetric/ec.py deleted file mode 100644 index 39e6751..0000000 --- a/venv/lib/python3.9/site-packages/cryptography/hazmat/primitives/asymmetric/ec.py +++ /dev/null @@ -1,369 +0,0 @@ -# This file is dual licensed under the terms of the Apache License, Version -# 2.0, and the BSD License. See the LICENSE file in the root of this repository -# for complete details. - -from __future__ import annotations - -import abc -import typing - -from cryptography import utils -from cryptography.exceptions import UnsupportedAlgorithm, _Reasons -from cryptography.hazmat._oid import ObjectIdentifier -from cryptography.hazmat.bindings._rust import openssl as rust_openssl -from cryptography.hazmat.primitives import _serialization, hashes -from cryptography.hazmat.primitives.asymmetric import utils as asym_utils - - -class EllipticCurveOID: - SECP192R1 = ObjectIdentifier("1.2.840.10045.3.1.1") - SECP224R1 = ObjectIdentifier("1.3.132.0.33") - SECP256K1 = ObjectIdentifier("1.3.132.0.10") - SECP256R1 = ObjectIdentifier("1.2.840.10045.3.1.7") - SECP384R1 = ObjectIdentifier("1.3.132.0.34") - SECP521R1 = ObjectIdentifier("1.3.132.0.35") - BRAINPOOLP256R1 = ObjectIdentifier("1.3.36.3.3.2.8.1.1.7") - BRAINPOOLP384R1 = ObjectIdentifier("1.3.36.3.3.2.8.1.1.11") - BRAINPOOLP512R1 = ObjectIdentifier("1.3.36.3.3.2.8.1.1.13") - - -class EllipticCurve(metaclass=abc.ABCMeta): - @property - @abc.abstractmethod - def name(self) -> str: - """ - The name of the curve. e.g. secp256r1. - """ - - @property - @abc.abstractmethod - def key_size(self) -> int: - """ - Bit size of a secret scalar for the curve. - """ - - @property - @abc.abstractmethod - def group_order(self) -> int: - """ - The order of the curve's group. - """ - - -class EllipticCurveSignatureAlgorithm(metaclass=abc.ABCMeta): - @property - @abc.abstractmethod - def algorithm( - self, - ) -> asym_utils.Prehashed | hashes.HashAlgorithm: - """ - The digest algorithm used with this signature. - """ - - -class EllipticCurvePrivateKey(metaclass=abc.ABCMeta): - @abc.abstractmethod - def exchange( - self, algorithm: ECDH, peer_public_key: EllipticCurvePublicKey - ) -> bytes: - """ - Performs a key exchange operation using the provided algorithm with the - provided peer's public key. - """ - - @abc.abstractmethod - def public_key(self) -> EllipticCurvePublicKey: - """ - The EllipticCurvePublicKey for this private key. - """ - - @property - @abc.abstractmethod - def curve(self) -> EllipticCurve: - """ - The EllipticCurve that this key is on. - """ - - @property - @abc.abstractmethod - def key_size(self) -> int: - """ - Bit size of a secret scalar for the curve. - """ - - @abc.abstractmethod - def sign( - self, - data: utils.Buffer, - signature_algorithm: EllipticCurveSignatureAlgorithm, - ) -> bytes: - """ - Signs the data - """ - - @abc.abstractmethod - def private_numbers(self) -> EllipticCurvePrivateNumbers: - """ - Returns an EllipticCurvePrivateNumbers. - """ - - @abc.abstractmethod - def private_bytes( - self, - encoding: _serialization.Encoding, - format: _serialization.PrivateFormat, - encryption_algorithm: _serialization.KeySerializationEncryption, - ) -> bytes: - """ - Returns the key serialized as bytes. - """ - - @abc.abstractmethod - def __copy__(self) -> EllipticCurvePrivateKey: - """ - Returns a copy. - """ - - @abc.abstractmethod - def __deepcopy__(self, memo: dict) -> EllipticCurvePrivateKey: - """ - Returns a deep copy. - """ - - -EllipticCurvePrivateKeyWithSerialization = EllipticCurvePrivateKey -EllipticCurvePrivateKey.register(rust_openssl.ec.ECPrivateKey) - - -class EllipticCurvePublicKey(metaclass=abc.ABCMeta): - @property - @abc.abstractmethod - def curve(self) -> EllipticCurve: - """ - The EllipticCurve that this key is on. - """ - - @property - @abc.abstractmethod - def key_size(self) -> int: - """ - Bit size of a secret scalar for the curve. - """ - - @abc.abstractmethod - def public_numbers(self) -> EllipticCurvePublicNumbers: - """ - Returns an EllipticCurvePublicNumbers. - """ - - @abc.abstractmethod - def public_bytes( - self, - encoding: _serialization.Encoding, - format: _serialization.PublicFormat, - ) -> bytes: - """ - Returns the key serialized as bytes. - """ - - @abc.abstractmethod - def verify( - self, - signature: utils.Buffer, - data: utils.Buffer, - signature_algorithm: EllipticCurveSignatureAlgorithm, - ) -> None: - """ - Verifies the signature of the data. - """ - - @classmethod - def from_encoded_point( - cls, curve: EllipticCurve, data: bytes - ) -> EllipticCurvePublicKey: - utils._check_bytes("data", data) - - if len(data) == 0: - raise ValueError("data must not be an empty byte string") - - if data[0] not in [0x02, 0x03, 0x04]: - raise ValueError("Unsupported elliptic curve point type") - - return rust_openssl.ec.from_public_bytes(curve, data) - - @abc.abstractmethod - def __eq__(self, other: object) -> bool: - """ - Checks equality. - """ - - @abc.abstractmethod - def __copy__(self) -> EllipticCurvePublicKey: - """ - Returns a copy. - """ - - @abc.abstractmethod - def __deepcopy__(self, memo: dict) -> EllipticCurvePublicKey: - """ - Returns a deep copy. - """ - - -EllipticCurvePublicKeyWithSerialization = EllipticCurvePublicKey -EllipticCurvePublicKey.register(rust_openssl.ec.ECPublicKey) - -EllipticCurvePrivateNumbers = rust_openssl.ec.EllipticCurvePrivateNumbers -EllipticCurvePublicNumbers = rust_openssl.ec.EllipticCurvePublicNumbers - - -class SECP521R1(EllipticCurve): - name = "secp521r1" - key_size = 521 - group_order = 0x1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA51868783BF2F966B7FCC0148F709A5D03BB5C9B8899C47AEBB6FB71E91386409 # noqa: E501 - - -class SECP384R1(EllipticCurve): - name = "secp384r1" - key_size = 384 - group_order = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC7634D81F4372DDF581A0DB248B0A77AECEC196ACCC52973 # noqa: E501 - - -class SECP256R1(EllipticCurve): - name = "secp256r1" - key_size = 256 - group_order = ( - 0xFFFFFFFF00000000FFFFFFFFFFFFFFFFBCE6FAADA7179E84F3B9CAC2FC632551 - ) - - -class SECP256K1(EllipticCurve): - name = "secp256k1" - key_size = 256 - group_order = ( - 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - ) - - -class SECP224R1(EllipticCurve): - name = "secp224r1" - key_size = 224 - group_order = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFF16A2E0B8F03E13DD29455C5C2A3D - - -class SECP192R1(EllipticCurve): - name = "secp192r1" - key_size = 192 - group_order = 0xFFFFFFFFFFFFFFFFFFFFFFFF99DEF836146BC9B1B4D22831 - - -class BrainpoolP256R1(EllipticCurve): - name = "brainpoolP256r1" - key_size = 256 - group_order = ( - 0xA9FB57DBA1EEA9BC3E660A909D838D718C397AA3B561A6F7901E0E82974856A7 - ) - - -class BrainpoolP384R1(EllipticCurve): - name = "brainpoolP384r1" - key_size = 384 - group_order = 0x8CB91E82A3386D280F5D6F7E50E641DF152F7109ED5456B31F166E6CAC0425A7CF3AB6AF6B7FC3103B883202E9046565 # noqa: E501 - - -class BrainpoolP512R1(EllipticCurve): - name = "brainpoolP512r1" - key_size = 512 - group_order = 0xAADD9DB8DBE9C48B3FD4E6AE33C9FC07CB308DB3B3C9D20ED6639CCA70330870553E5C414CA92619418661197FAC10471DB1D381085DDADDB58796829CA90069 # noqa: E501 - - -_CURVE_TYPES: dict[str, EllipticCurve] = { - "prime192v1": SECP192R1(), - "prime256v1": SECP256R1(), - "secp192r1": SECP192R1(), - "secp224r1": SECP224R1(), - "secp256r1": SECP256R1(), - "secp384r1": SECP384R1(), - "secp521r1": SECP521R1(), - "secp256k1": SECP256K1(), - "brainpoolP256r1": BrainpoolP256R1(), - "brainpoolP384r1": BrainpoolP384R1(), - "brainpoolP512r1": BrainpoolP512R1(), -} - - -class ECDSA(EllipticCurveSignatureAlgorithm): - def __init__( - self, - algorithm: asym_utils.Prehashed | hashes.HashAlgorithm, - deterministic_signing: bool = False, - ): - from cryptography.hazmat.backends.openssl.backend import backend - - if ( - deterministic_signing - and not backend.ecdsa_deterministic_supported() - ): - raise UnsupportedAlgorithm( - "ECDSA with deterministic signature (RFC 6979) is not " - "supported by this version of OpenSSL.", - _Reasons.UNSUPPORTED_PUBLIC_KEY_ALGORITHM, - ) - self._algorithm = algorithm - self._deterministic_signing = deterministic_signing - - @property - def algorithm( - self, - ) -> asym_utils.Prehashed | hashes.HashAlgorithm: - return self._algorithm - - @property - def deterministic_signing( - self, - ) -> bool: - return self._deterministic_signing - - -generate_private_key = rust_openssl.ec.generate_private_key - - -def derive_private_key( - private_value: int, - curve: EllipticCurve, - backend: typing.Any = None, -) -> EllipticCurvePrivateKey: - if not isinstance(private_value, int): - raise TypeError("private_value must be an integer type.") - - if private_value <= 0: - raise ValueError("private_value must be a positive integer.") - - return rust_openssl.ec.derive_private_key(private_value, curve) - - -class ECDH: - pass - - -_OID_TO_CURVE = { - EllipticCurveOID.SECP192R1: SECP192R1, - EllipticCurveOID.SECP224R1: SECP224R1, - EllipticCurveOID.SECP256K1: SECP256K1, - EllipticCurveOID.SECP256R1: SECP256R1, - EllipticCurveOID.SECP384R1: SECP384R1, - EllipticCurveOID.SECP521R1: SECP521R1, - EllipticCurveOID.BRAINPOOLP256R1: BrainpoolP256R1, - EllipticCurveOID.BRAINPOOLP384R1: BrainpoolP384R1, - EllipticCurveOID.BRAINPOOLP512R1: BrainpoolP512R1, -} - - -def get_curve_for_oid(oid: ObjectIdentifier) -> type[EllipticCurve]: - try: - return _OID_TO_CURVE[oid] - except KeyError: - raise LookupError( - "The provided object identifier has no matching elliptic " - "curve class" - ) diff --git a/venv/lib/python3.9/site-packages/cryptography/hazmat/primitives/asymmetric/ed25519.py b/venv/lib/python3.9/site-packages/cryptography/hazmat/primitives/asymmetric/ed25519.py deleted file mode 100644 index 70aec5b..0000000 --- a/venv/lib/python3.9/site-packages/cryptography/hazmat/primitives/asymmetric/ed25519.py +++ /dev/null @@ -1,116 +0,0 @@ -# This file is dual licensed under the terms of the Apache License, Version -# 2.0, and the BSD License. See the LICENSE file in the root of this repository -# for complete details. - -from __future__ import annotations - -import abc - -from cryptography.hazmat.bindings._rust import openssl as rust_openssl -from cryptography.hazmat.primitives import _serialization -from cryptography.utils import Buffer - - -class Ed25519PublicKey(metaclass=abc.ABCMeta): - @classmethod - def from_public_bytes(cls, data: bytes) -> Ed25519PublicKey: - return rust_openssl.ed25519.from_public_bytes(data) - - @abc.abstractmethod - def public_bytes( - self, - encoding: _serialization.Encoding, - format: _serialization.PublicFormat, - ) -> bytes: - """ - The serialized bytes of the public key. - """ - - @abc.abstractmethod - def public_bytes_raw(self) -> bytes: - """ - The raw bytes of the public key. - Equivalent to public_bytes(Raw, Raw). - """ - - @abc.abstractmethod - def verify(self, signature: Buffer, data: Buffer) -> None: - """ - Verify the signature. - """ - - @abc.abstractmethod - def __eq__(self, other: object) -> bool: - """ - Checks equality. - """ - - @abc.abstractmethod - def __copy__(self) -> Ed25519PublicKey: - """ - Returns a copy. - """ - - @abc.abstractmethod - def __deepcopy__(self, memo: dict) -> Ed25519PublicKey: - """ - Returns a deep copy. - """ - - -Ed25519PublicKey.register(rust_openssl.ed25519.Ed25519PublicKey) - - -class Ed25519PrivateKey(metaclass=abc.ABCMeta): - @classmethod - def generate(cls) -> Ed25519PrivateKey: - return rust_openssl.ed25519.generate_key() - - @classmethod - def from_private_bytes(cls, data: Buffer) -> Ed25519PrivateKey: - return rust_openssl.ed25519.from_private_bytes(data) - - @abc.abstractmethod - def public_key(self) -> Ed25519PublicKey: - """ - The Ed25519PublicKey derived from the private key. - """ - - @abc.abstractmethod - def private_bytes( - self, - encoding: _serialization.Encoding, - format: _serialization.PrivateFormat, - encryption_algorithm: _serialization.KeySerializationEncryption, - ) -> bytes: - """ - The serialized bytes of the private key. - """ - - @abc.abstractmethod - def private_bytes_raw(self) -> bytes: - """ - The raw bytes of the private key. - Equivalent to private_bytes(Raw, Raw, NoEncryption()). - """ - - @abc.abstractmethod - def sign(self, data: Buffer) -> bytes: - """ - Signs the data. - """ - - @abc.abstractmethod - def __copy__(self) -> Ed25519PrivateKey: - """ - Returns a copy. - """ - - @abc.abstractmethod - def __deepcopy__(self, memo: dict) -> Ed25519PrivateKey: - """ - Returns a deep copy. - """ - - -Ed25519PrivateKey.register(rust_openssl.ed25519.Ed25519PrivateKey) diff --git a/venv/lib/python3.9/site-packages/cryptography/hazmat/primitives/asymmetric/ed448.py b/venv/lib/python3.9/site-packages/cryptography/hazmat/primitives/asymmetric/ed448.py deleted file mode 100644 index 9ecb478..0000000 --- a/venv/lib/python3.9/site-packages/cryptography/hazmat/primitives/asymmetric/ed448.py +++ /dev/null @@ -1,143 +0,0 @@ -# This file is dual licensed under the terms of the Apache License, Version -# 2.0, and the BSD License. See the LICENSE file in the root of this repository -# for complete details. - -from __future__ import annotations - -import abc - -from cryptography.exceptions import UnsupportedAlgorithm, _Reasons -from cryptography.hazmat.bindings._rust import openssl as rust_openssl -from cryptography.hazmat.primitives import _serialization -from cryptography.utils import Buffer - - -class Ed448PublicKey(metaclass=abc.ABCMeta): - @classmethod - def from_public_bytes(cls, data: bytes) -> Ed448PublicKey: - from cryptography.hazmat.backends.openssl.backend import backend - - if not backend.ed448_supported(): - raise UnsupportedAlgorithm( - "ed448 is not supported by this version of OpenSSL.", - _Reasons.UNSUPPORTED_PUBLIC_KEY_ALGORITHM, - ) - - return rust_openssl.ed448.from_public_bytes(data) - - @abc.abstractmethod - def public_bytes( - self, - encoding: _serialization.Encoding, - format: _serialization.PublicFormat, - ) -> bytes: - """ - The serialized bytes of the public key. - """ - - @abc.abstractmethod - def public_bytes_raw(self) -> bytes: - """ - The raw bytes of the public key. - Equivalent to public_bytes(Raw, Raw). - """ - - @abc.abstractmethod - def verify(self, signature: Buffer, data: Buffer) -> None: - """ - Verify the signature. - """ - - @abc.abstractmethod - def __eq__(self, other: object) -> bool: - """ - Checks equality. - """ - - @abc.abstractmethod - def __copy__(self) -> Ed448PublicKey: - """ - Returns a copy. - """ - - @abc.abstractmethod - def __deepcopy__(self, memo: dict) -> Ed448PublicKey: - """ - Returns a deep copy. - """ - - -if hasattr(rust_openssl, "ed448"): - Ed448PublicKey.register(rust_openssl.ed448.Ed448PublicKey) - - -class Ed448PrivateKey(metaclass=abc.ABCMeta): - @classmethod - def generate(cls) -> Ed448PrivateKey: - from cryptography.hazmat.backends.openssl.backend import backend - - if not backend.ed448_supported(): - raise UnsupportedAlgorithm( - "ed448 is not supported by this version of OpenSSL.", - _Reasons.UNSUPPORTED_PUBLIC_KEY_ALGORITHM, - ) - - return rust_openssl.ed448.generate_key() - - @classmethod - def from_private_bytes(cls, data: Buffer) -> Ed448PrivateKey: - from cryptography.hazmat.backends.openssl.backend import backend - - if not backend.ed448_supported(): - raise UnsupportedAlgorithm( - "ed448 is not supported by this version of OpenSSL.", - _Reasons.UNSUPPORTED_PUBLIC_KEY_ALGORITHM, - ) - - return rust_openssl.ed448.from_private_bytes(data) - - @abc.abstractmethod - def public_key(self) -> Ed448PublicKey: - """ - The Ed448PublicKey derived from the private key. - """ - - @abc.abstractmethod - def sign(self, data: Buffer) -> bytes: - """ - Signs the data. - """ - - @abc.abstractmethod - def private_bytes( - self, - encoding: _serialization.Encoding, - format: _serialization.PrivateFormat, - encryption_algorithm: _serialization.KeySerializationEncryption, - ) -> bytes: - """ - The serialized bytes of the private key. - """ - - @abc.abstractmethod - def private_bytes_raw(self) -> bytes: - """ - The raw bytes of the private key. - Equivalent to private_bytes(Raw, Raw, NoEncryption()). - """ - - @abc.abstractmethod - def __copy__(self) -> Ed448PrivateKey: - """ - Returns a copy. - """ - - @abc.abstractmethod - def __deepcopy__(self, memo: dict) -> Ed448PrivateKey: - """ - Returns a deep copy. - """ - - -if hasattr(rust_openssl, "x448"): - Ed448PrivateKey.register(rust_openssl.ed448.Ed448PrivateKey) diff --git a/venv/lib/python3.9/site-packages/cryptography/hazmat/primitives/asymmetric/mldsa.py b/venv/lib/python3.9/site-packages/cryptography/hazmat/primitives/asymmetric/mldsa.py deleted file mode 100644 index 0bd9684..0000000 --- a/venv/lib/python3.9/site-packages/cryptography/hazmat/primitives/asymmetric/mldsa.py +++ /dev/null @@ -1,441 +0,0 @@ -# This file is dual licensed under the terms of the Apache License, Version -# 2.0, and the BSD License. See the LICENSE file in the root of this repository -# for complete details. - -from __future__ import annotations - -import abc - -from cryptography.exceptions import UnsupportedAlgorithm, _Reasons -from cryptography.hazmat.bindings._rust import openssl as rust_openssl -from cryptography.hazmat.primitives import _serialization -from cryptography.utils import Buffer - - -class MLDSA44PublicKey(metaclass=abc.ABCMeta): - @classmethod - def from_public_bytes(cls, data: bytes) -> MLDSA44PublicKey: - from cryptography.hazmat.backends.openssl.backend import backend - - if not backend.mldsa_supported(): - raise UnsupportedAlgorithm( - "ML-DSA-44 is not supported by this backend.", - _Reasons.UNSUPPORTED_PUBLIC_KEY_ALGORITHM, - ) - - return rust_openssl.mldsa.from_mldsa44_public_bytes(data) - - @abc.abstractmethod - def public_bytes( - self, - encoding: _serialization.Encoding, - format: _serialization.PublicFormat, - ) -> bytes: - """ - The serialized bytes of the public key. - """ - - @abc.abstractmethod - def public_bytes_raw(self) -> bytes: - """ - The raw bytes of the public key. - Equivalent to public_bytes(Raw, Raw). - - The public key is 1,312 bytes for MLDSA-44. - """ - - @abc.abstractmethod - def verify( - self, - signature: Buffer, - data: Buffer, - context: Buffer | None = None, - ) -> None: - """ - Verify the signature. - """ - - @abc.abstractmethod - def __eq__(self, other: object) -> bool: - """ - Checks equality. - """ - - @abc.abstractmethod - def __copy__(self) -> MLDSA44PublicKey: - """ - Returns a copy. - """ - - @abc.abstractmethod - def __deepcopy__(self, memo: dict) -> MLDSA44PublicKey: - """ - Returns a deep copy. - """ - - -if hasattr(rust_openssl, "mldsa"): - MLDSA44PublicKey.register(rust_openssl.mldsa.MLDSA44PublicKey) - - -class MLDSA44PrivateKey(metaclass=abc.ABCMeta): - @classmethod - def generate(cls) -> MLDSA44PrivateKey: - from cryptography.hazmat.backends.openssl.backend import backend - - if not backend.mldsa_supported(): - raise UnsupportedAlgorithm( - "ML-DSA-44 is not supported by this backend.", - _Reasons.UNSUPPORTED_PUBLIC_KEY_ALGORITHM, - ) - - return rust_openssl.mldsa.generate_mldsa44_key() - - @classmethod - def from_seed_bytes(cls, data: Buffer) -> MLDSA44PrivateKey: - from cryptography.hazmat.backends.openssl.backend import backend - - if not backend.mldsa_supported(): - raise UnsupportedAlgorithm( - "ML-DSA-44 is not supported by this backend.", - _Reasons.UNSUPPORTED_PUBLIC_KEY_ALGORITHM, - ) - - return rust_openssl.mldsa.from_mldsa44_seed_bytes(data) - - @abc.abstractmethod - def public_key(self) -> MLDSA44PublicKey: - """ - The MLDSA44PublicKey derived from the private key. - """ - - @abc.abstractmethod - def private_bytes( - self, - encoding: _serialization.Encoding, - format: _serialization.PrivateFormat, - encryption_algorithm: _serialization.KeySerializationEncryption, - ) -> bytes: - """ - The serialized bytes of the private key. - - This method only returns the serialization of the seed form of the - private key, never the expanded one. - """ - - @abc.abstractmethod - def private_bytes_raw(self) -> bytes: - """ - The raw bytes of the private key. - Equivalent to private_bytes(Raw, Raw, NoEncryption()). - - This method only returns the seed form of the private key (32 bytes). - """ - - @abc.abstractmethod - def sign(self, data: Buffer, context: Buffer | None = None) -> bytes: - """ - Signs the data. - """ - - @abc.abstractmethod - def __copy__(self) -> MLDSA44PrivateKey: - """ - Returns a copy. - """ - - @abc.abstractmethod - def __deepcopy__(self, memo: dict) -> MLDSA44PrivateKey: - """ - Returns a deep copy. - """ - - -if hasattr(rust_openssl, "mldsa"): - MLDSA44PrivateKey.register(rust_openssl.mldsa.MLDSA44PrivateKey) - - -class MLDSA65PublicKey(metaclass=abc.ABCMeta): - @classmethod - def from_public_bytes(cls, data: bytes) -> MLDSA65PublicKey: - from cryptography.hazmat.backends.openssl.backend import backend - - if not backend.mldsa_supported(): - raise UnsupportedAlgorithm( - "ML-DSA-65 is not supported by this backend.", - _Reasons.UNSUPPORTED_PUBLIC_KEY_ALGORITHM, - ) - - return rust_openssl.mldsa.from_mldsa65_public_bytes(data) - - @abc.abstractmethod - def public_bytes( - self, - encoding: _serialization.Encoding, - format: _serialization.PublicFormat, - ) -> bytes: - """ - The serialized bytes of the public key. - """ - - @abc.abstractmethod - def public_bytes_raw(self) -> bytes: - """ - The raw bytes of the public key. - Equivalent to public_bytes(Raw, Raw). - - The public key is 1,952 bytes for MLDSA-65. - """ - - @abc.abstractmethod - def verify( - self, - signature: Buffer, - data: Buffer, - context: Buffer | None = None, - ) -> None: - """ - Verify the signature. - """ - - @abc.abstractmethod - def __eq__(self, other: object) -> bool: - """ - Checks equality. - """ - - @abc.abstractmethod - def __copy__(self) -> MLDSA65PublicKey: - """ - Returns a copy. - """ - - @abc.abstractmethod - def __deepcopy__(self, memo: dict) -> MLDSA65PublicKey: - """ - Returns a deep copy. - """ - - -if hasattr(rust_openssl, "mldsa"): - MLDSA65PublicKey.register(rust_openssl.mldsa.MLDSA65PublicKey) - - -class MLDSA65PrivateKey(metaclass=abc.ABCMeta): - @classmethod - def generate(cls) -> MLDSA65PrivateKey: - from cryptography.hazmat.backends.openssl.backend import backend - - if not backend.mldsa_supported(): - raise UnsupportedAlgorithm( - "ML-DSA-65 is not supported by this backend.", - _Reasons.UNSUPPORTED_PUBLIC_KEY_ALGORITHM, - ) - - return rust_openssl.mldsa.generate_mldsa65_key() - - @classmethod - def from_seed_bytes(cls, data: Buffer) -> MLDSA65PrivateKey: - from cryptography.hazmat.backends.openssl.backend import backend - - if not backend.mldsa_supported(): - raise UnsupportedAlgorithm( - "ML-DSA-65 is not supported by this backend.", - _Reasons.UNSUPPORTED_PUBLIC_KEY_ALGORITHM, - ) - - return rust_openssl.mldsa.from_mldsa65_seed_bytes(data) - - @abc.abstractmethod - def public_key(self) -> MLDSA65PublicKey: - """ - The MLDSA65PublicKey derived from the private key. - """ - - @abc.abstractmethod - def private_bytes( - self, - encoding: _serialization.Encoding, - format: _serialization.PrivateFormat, - encryption_algorithm: _serialization.KeySerializationEncryption, - ) -> bytes: - """ - The serialized bytes of the private key. - - This method only returns the serialization of the seed form of the - private key, never the expanded one. - """ - - @abc.abstractmethod - def private_bytes_raw(self) -> bytes: - """ - The raw bytes of the private key. - Equivalent to private_bytes(Raw, Raw, NoEncryption()). - - This method only returns the seed form of the private key (32 bytes). - """ - - @abc.abstractmethod - def sign(self, data: Buffer, context: Buffer | None = None) -> bytes: - """ - Signs the data. - """ - - @abc.abstractmethod - def __copy__(self) -> MLDSA65PrivateKey: - """ - Returns a copy. - """ - - @abc.abstractmethod - def __deepcopy__(self, memo: dict) -> MLDSA65PrivateKey: - """ - Returns a deep copy. - """ - - -if hasattr(rust_openssl, "mldsa"): - MLDSA65PrivateKey.register(rust_openssl.mldsa.MLDSA65PrivateKey) - - -class MLDSA87PublicKey(metaclass=abc.ABCMeta): - @classmethod - def from_public_bytes(cls, data: bytes) -> MLDSA87PublicKey: - from cryptography.hazmat.backends.openssl.backend import backend - - if not backend.mldsa_supported(): - raise UnsupportedAlgorithm( - "ML-DSA-87 is not supported by this backend.", - _Reasons.UNSUPPORTED_PUBLIC_KEY_ALGORITHM, - ) - - return rust_openssl.mldsa.from_mldsa87_public_bytes(data) - - @abc.abstractmethod - def public_bytes( - self, - encoding: _serialization.Encoding, - format: _serialization.PublicFormat, - ) -> bytes: - """ - The serialized bytes of the public key. - """ - - @abc.abstractmethod - def public_bytes_raw(self) -> bytes: - """ - The raw bytes of the public key. - Equivalent to public_bytes(Raw, Raw). - - The public key is 2,592 bytes for MLDSA-87. - """ - - @abc.abstractmethod - def verify( - self, - signature: Buffer, - data: Buffer, - context: Buffer | None = None, - ) -> None: - """ - Verify the signature. - """ - - @abc.abstractmethod - def __eq__(self, other: object) -> bool: - """ - Checks equality. - """ - - @abc.abstractmethod - def __copy__(self) -> MLDSA87PublicKey: - """ - Returns a copy. - """ - - @abc.abstractmethod - def __deepcopy__(self, memo: dict) -> MLDSA87PublicKey: - """ - Returns a deep copy. - """ - - -if hasattr(rust_openssl, "mldsa"): - MLDSA87PublicKey.register(rust_openssl.mldsa.MLDSA87PublicKey) - - -class MLDSA87PrivateKey(metaclass=abc.ABCMeta): - @classmethod - def generate(cls) -> MLDSA87PrivateKey: - from cryptography.hazmat.backends.openssl.backend import backend - - if not backend.mldsa_supported(): - raise UnsupportedAlgorithm( - "ML-DSA-87 is not supported by this backend.", - _Reasons.UNSUPPORTED_PUBLIC_KEY_ALGORITHM, - ) - - return rust_openssl.mldsa.generate_mldsa87_key() - - @classmethod - def from_seed_bytes(cls, data: Buffer) -> MLDSA87PrivateKey: - from cryptography.hazmat.backends.openssl.backend import backend - - if not backend.mldsa_supported(): - raise UnsupportedAlgorithm( - "ML-DSA-87 is not supported by this backend.", - _Reasons.UNSUPPORTED_PUBLIC_KEY_ALGORITHM, - ) - - return rust_openssl.mldsa.from_mldsa87_seed_bytes(data) - - @abc.abstractmethod - def public_key(self) -> MLDSA87PublicKey: - """ - The MLDSA87PublicKey derived from the private key. - """ - - @abc.abstractmethod - def private_bytes( - self, - encoding: _serialization.Encoding, - format: _serialization.PrivateFormat, - encryption_algorithm: _serialization.KeySerializationEncryption, - ) -> bytes: - """ - The serialized bytes of the private key. - - This method only returns the serialization of the seed form of the - private key, never the expanded one. - """ - - @abc.abstractmethod - def private_bytes_raw(self) -> bytes: - """ - The raw bytes of the private key. - Equivalent to private_bytes(Raw, Raw, NoEncryption()). - - This method only returns the seed form of the private key (32 bytes). - """ - - @abc.abstractmethod - def sign(self, data: Buffer, context: Buffer | None = None) -> bytes: - """ - Signs the data. - """ - - @abc.abstractmethod - def __copy__(self) -> MLDSA87PrivateKey: - """ - Returns a copy. - """ - - @abc.abstractmethod - def __deepcopy__(self, memo: dict) -> MLDSA87PrivateKey: - """ - Returns a deep copy. - """ - - -if hasattr(rust_openssl, "mldsa"): - MLDSA87PrivateKey.register(rust_openssl.mldsa.MLDSA87PrivateKey) diff --git a/venv/lib/python3.9/site-packages/cryptography/hazmat/primitives/asymmetric/mlkem.py b/venv/lib/python3.9/site-packages/cryptography/hazmat/primitives/asymmetric/mlkem.py deleted file mode 100644 index 64bca11..0000000 --- a/venv/lib/python3.9/site-packages/cryptography/hazmat/primitives/asymmetric/mlkem.py +++ /dev/null @@ -1,278 +0,0 @@ -# This file is dual licensed under the terms of the Apache License, Version -# 2.0, and the BSD License. See the LICENSE file in the root of this repository -# for complete details. - -from __future__ import annotations - -import abc - -from cryptography.exceptions import UnsupportedAlgorithm, _Reasons -from cryptography.hazmat.bindings._rust import openssl as rust_openssl -from cryptography.hazmat.primitives import _serialization -from cryptography.utils import Buffer - - -class MLKEM768PublicKey(metaclass=abc.ABCMeta): - @classmethod - def from_public_bytes(cls, data: Buffer) -> MLKEM768PublicKey: - from cryptography.hazmat.backends.openssl.backend import backend - - if not backend.mlkem_supported(): - raise UnsupportedAlgorithm( - "ML-KEM-768 is not supported by this backend.", - _Reasons.UNSUPPORTED_PUBLIC_KEY_ALGORITHM, - ) - - return rust_openssl.mlkem.from_mlkem768_public_bytes(data) - - @abc.abstractmethod - def encapsulate(self) -> tuple[bytes, bytes]: - """ - Encapsulate: returns (shared_secret, ciphertext). - """ - - @abc.abstractmethod - def public_bytes( - self, - encoding: _serialization.Encoding, - format: _serialization.PublicFormat, - ) -> bytes: - """ - The serialized bytes of the public key. - """ - - @abc.abstractmethod - def public_bytes_raw(self) -> bytes: - """ - The raw bytes of the public key. - Equivalent to public_bytes(Raw, Raw). - - The public key is 1,184 bytes for ML-KEM-768. - """ - - @abc.abstractmethod - def __eq__(self, other: object) -> bool: - """ - Checks equality. - """ - - @abc.abstractmethod - def __copy__(self) -> MLKEM768PublicKey: - """ - Returns a copy. - """ - - @abc.abstractmethod - def __deepcopy__(self, memo: dict) -> MLKEM768PublicKey: - """ - Returns a deep copy. - """ - - -if hasattr(rust_openssl, "mlkem"): - MLKEM768PublicKey.register(rust_openssl.mlkem.MLKEM768PublicKey) - - -class MLKEM768PrivateKey(metaclass=abc.ABCMeta): - @classmethod - def generate(cls) -> MLKEM768PrivateKey: - from cryptography.hazmat.backends.openssl.backend import backend - - if not backend.mlkem_supported(): - raise UnsupportedAlgorithm( - "ML-KEM-768 is not supported by this backend.", - _Reasons.UNSUPPORTED_PUBLIC_KEY_ALGORITHM, - ) - - return rust_openssl.mlkem.generate_mlkem768_key() - - @classmethod - def from_seed_bytes(cls, data: Buffer) -> MLKEM768PrivateKey: - from cryptography.hazmat.backends.openssl.backend import backend - - if not backend.mlkem_supported(): - raise UnsupportedAlgorithm( - "ML-KEM-768 is not supported by this backend.", - _Reasons.UNSUPPORTED_PUBLIC_KEY_ALGORITHM, - ) - - return rust_openssl.mlkem.from_mlkem768_seed_bytes(data) - - @abc.abstractmethod - def decapsulate(self, ciphertext: Buffer) -> bytes: - """ - Decapsulate: returns shared_secret. - """ - - @abc.abstractmethod - def public_key(self) -> MLKEM768PublicKey: - """ - The MLKEM768PublicKey derived from this private key. - """ - - @abc.abstractmethod - def private_bytes( - self, - encoding: _serialization.Encoding, - format: _serialization.PrivateFormat, - encryption_algorithm: _serialization.KeySerializationEncryption, - ) -> bytes: - """ - The serialized bytes of the private key. - """ - - @abc.abstractmethod - def private_bytes_raw(self) -> bytes: - """ - The raw bytes of the private key (64-byte seed). - Equivalent to private_bytes(Raw, Raw, NoEncryption()). - """ - - @abc.abstractmethod - def __copy__(self) -> MLKEM768PrivateKey: - """ - Returns a copy. - """ - - @abc.abstractmethod - def __deepcopy__(self, memo: dict) -> MLKEM768PrivateKey: - """ - Returns a deep copy. - """ - - -if hasattr(rust_openssl, "mlkem"): - MLKEM768PrivateKey.register(rust_openssl.mlkem.MLKEM768PrivateKey) - - -class MLKEM1024PublicKey(metaclass=abc.ABCMeta): - @classmethod - def from_public_bytes(cls, data: Buffer) -> MLKEM1024PublicKey: - from cryptography.hazmat.backends.openssl.backend import backend - - if not backend.mlkem_supported(): - raise UnsupportedAlgorithm( - "ML-KEM-1024 is not supported by this backend.", - _Reasons.UNSUPPORTED_PUBLIC_KEY_ALGORITHM, - ) - - return rust_openssl.mlkem.from_mlkem1024_public_bytes(data) - - @abc.abstractmethod - def encapsulate(self) -> tuple[bytes, bytes]: - """ - Encapsulate: returns (shared_secret, ciphertext). - """ - - @abc.abstractmethod - def public_bytes( - self, - encoding: _serialization.Encoding, - format: _serialization.PublicFormat, - ) -> bytes: - """ - The serialized bytes of the public key. - """ - - @abc.abstractmethod - def public_bytes_raw(self) -> bytes: - """ - The raw bytes of the public key. - Equivalent to public_bytes(Raw, Raw). - - The public key is 1,568 bytes for ML-KEM-1024. - """ - - @abc.abstractmethod - def __eq__(self, other: object) -> bool: - """ - Checks equality. - """ - - @abc.abstractmethod - def __copy__(self) -> MLKEM1024PublicKey: - """ - Returns a copy. - """ - - @abc.abstractmethod - def __deepcopy__(self, memo: dict) -> MLKEM1024PublicKey: - """ - Returns a deep copy. - """ - - -if hasattr(rust_openssl, "mlkem"): - MLKEM1024PublicKey.register(rust_openssl.mlkem.MLKEM1024PublicKey) - - -class MLKEM1024PrivateKey(metaclass=abc.ABCMeta): - @classmethod - def generate(cls) -> MLKEM1024PrivateKey: - from cryptography.hazmat.backends.openssl.backend import backend - - if not backend.mlkem_supported(): - raise UnsupportedAlgorithm( - "ML-KEM-1024 is not supported by this backend.", - _Reasons.UNSUPPORTED_PUBLIC_KEY_ALGORITHM, - ) - - return rust_openssl.mlkem.generate_mlkem1024_key() - - @classmethod - def from_seed_bytes(cls, data: Buffer) -> MLKEM1024PrivateKey: - from cryptography.hazmat.backends.openssl.backend import backend - - if not backend.mlkem_supported(): - raise UnsupportedAlgorithm( - "ML-KEM-1024 is not supported by this backend.", - _Reasons.UNSUPPORTED_PUBLIC_KEY_ALGORITHM, - ) - - return rust_openssl.mlkem.from_mlkem1024_seed_bytes(data) - - @abc.abstractmethod - def decapsulate(self, ciphertext: Buffer) -> bytes: - """ - Decapsulate: returns shared_secret. - """ - - @abc.abstractmethod - def public_key(self) -> MLKEM1024PublicKey: - """ - The MLKEM1024PublicKey derived from this private key. - """ - - @abc.abstractmethod - def private_bytes( - self, - encoding: _serialization.Encoding, - format: _serialization.PrivateFormat, - encryption_algorithm: _serialization.KeySerializationEncryption, - ) -> bytes: - """ - The serialized bytes of the private key. - """ - - @abc.abstractmethod - def private_bytes_raw(self) -> bytes: - """ - The raw bytes of the private key (64-byte seed). - Equivalent to private_bytes(Raw, Raw, NoEncryption()). - """ - - @abc.abstractmethod - def __copy__(self) -> MLKEM1024PrivateKey: - """ - Returns a copy. - """ - - @abc.abstractmethod - def __deepcopy__(self, memo: dict) -> MLKEM1024PrivateKey: - """ - Returns a deep copy. - """ - - -if hasattr(rust_openssl, "mlkem"): - MLKEM1024PrivateKey.register(rust_openssl.mlkem.MLKEM1024PrivateKey) diff --git a/venv/lib/python3.9/site-packages/cryptography/hazmat/primitives/asymmetric/padding.py b/venv/lib/python3.9/site-packages/cryptography/hazmat/primitives/asymmetric/padding.py deleted file mode 100644 index 5121a28..0000000 --- a/venv/lib/python3.9/site-packages/cryptography/hazmat/primitives/asymmetric/padding.py +++ /dev/null @@ -1,111 +0,0 @@ -# This file is dual licensed under the terms of the Apache License, Version -# 2.0, and the BSD License. See the LICENSE file in the root of this repository -# for complete details. - -from __future__ import annotations - -import abc - -from cryptography.hazmat.primitives import hashes -from cryptography.hazmat.primitives._asymmetric import ( - AsymmetricPadding as AsymmetricPadding, -) -from cryptography.hazmat.primitives.asymmetric import rsa - - -class PKCS1v15(AsymmetricPadding): - name = "EMSA-PKCS1-v1_5" - - -class _MaxLength: - "Sentinel value for `MAX_LENGTH`." - - -class _Auto: - "Sentinel value for `AUTO`." - - -class _DigestLength: - "Sentinel value for `DIGEST_LENGTH`." - - -class PSS(AsymmetricPadding): - MAX_LENGTH = _MaxLength() - AUTO = _Auto() - DIGEST_LENGTH = _DigestLength() - name = "EMSA-PSS" - _salt_length: int | _MaxLength | _Auto | _DigestLength - - def __init__( - self, - mgf: MGF, - salt_length: int | _MaxLength | _Auto | _DigestLength, - ) -> None: - self._mgf = mgf - - if not isinstance( - salt_length, (int, _MaxLength, _Auto, _DigestLength) - ): - raise TypeError( - "salt_length must be an integer, MAX_LENGTH, " - "DIGEST_LENGTH, or AUTO" - ) - - if isinstance(salt_length, int) and salt_length < 0: - raise ValueError("salt_length must be zero or greater.") - - self._salt_length = salt_length - - @property - def mgf(self) -> MGF: - return self._mgf - - -class OAEP(AsymmetricPadding): - name = "EME-OAEP" - - def __init__( - self, - mgf: MGF, - algorithm: hashes.HashAlgorithm, - label: bytes | None, - ): - if not isinstance(algorithm, hashes.HashAlgorithm): - raise TypeError("Expected instance of hashes.HashAlgorithm.") - - self._mgf = mgf - self._algorithm = algorithm - self._label = label - - @property - def algorithm(self) -> hashes.HashAlgorithm: - return self._algorithm - - @property - def mgf(self) -> MGF: - return self._mgf - - -class MGF(metaclass=abc.ABCMeta): - _algorithm: hashes.HashAlgorithm - - -class MGF1(MGF): - def __init__(self, algorithm: hashes.HashAlgorithm): - if not isinstance(algorithm, hashes.HashAlgorithm): - raise TypeError("Expected instance of hashes.HashAlgorithm.") - - self._algorithm = algorithm - - -def calculate_max_pss_salt_length( - key: rsa.RSAPrivateKey | rsa.RSAPublicKey, - hash_algorithm: hashes.HashAlgorithm, -) -> int: - if not isinstance(key, (rsa.RSAPrivateKey, rsa.RSAPublicKey)): - raise TypeError("key must be an RSA public or private key") - # bit length - 1 per RFC 3447 - emlen = (key.key_size + 6) // 8 - salt_length = emlen - hash_algorithm.digest_size - 2 - assert salt_length >= 0 - return salt_length diff --git a/venv/lib/python3.9/site-packages/cryptography/hazmat/primitives/asymmetric/rsa.py b/venv/lib/python3.9/site-packages/cryptography/hazmat/primitives/asymmetric/rsa.py deleted file mode 100644 index a85a02b..0000000 --- a/venv/lib/python3.9/site-packages/cryptography/hazmat/primitives/asymmetric/rsa.py +++ /dev/null @@ -1,299 +0,0 @@ -# This file is dual licensed under the terms of the Apache License, Version -# 2.0, and the BSD License. See the LICENSE file in the root of this repository -# for complete details. - -from __future__ import annotations - -import abc -import random -import typing -from math import gcd - -from cryptography.hazmat.bindings._rust import openssl as rust_openssl -from cryptography.hazmat.primitives import _serialization, hashes -from cryptography.hazmat.primitives._asymmetric import AsymmetricPadding -from cryptography.hazmat.primitives.asymmetric import utils as asym_utils - - -class RSAPrivateKey(metaclass=abc.ABCMeta): - @abc.abstractmethod - def decrypt(self, ciphertext: bytes, padding: AsymmetricPadding) -> bytes: - """ - Decrypts the provided ciphertext. - """ - - @property - @abc.abstractmethod - def key_size(self) -> int: - """ - The bit length of the public modulus. - """ - - @abc.abstractmethod - def public_key(self) -> RSAPublicKey: - """ - The RSAPublicKey associated with this private key. - """ - - @abc.abstractmethod - def sign( - self, - data: bytes, - padding: AsymmetricPadding, - algorithm: asym_utils.Prehashed - | hashes.HashAlgorithm - | asym_utils.NoDigestInfo, - ) -> bytes: - """ - Signs the data. - """ - - @abc.abstractmethod - def private_numbers(self) -> RSAPrivateNumbers: - """ - Returns an RSAPrivateNumbers. - """ - - @abc.abstractmethod - def private_bytes( - self, - encoding: _serialization.Encoding, - format: _serialization.PrivateFormat, - encryption_algorithm: _serialization.KeySerializationEncryption, - ) -> bytes: - """ - Returns the key serialized as bytes. - """ - - @abc.abstractmethod - def __copy__(self) -> RSAPrivateKey: - """ - Returns a copy. - """ - - @abc.abstractmethod - def __deepcopy__(self, memo: dict) -> RSAPrivateKey: - """ - Returns a deep copy. - """ - - -RSAPrivateKeyWithSerialization = RSAPrivateKey -RSAPrivateKey.register(rust_openssl.rsa.RSAPrivateKey) - - -class RSAPublicKey(metaclass=abc.ABCMeta): - @abc.abstractmethod - def encrypt(self, plaintext: bytes, padding: AsymmetricPadding) -> bytes: - """ - Encrypts the given plaintext. - """ - - @property - @abc.abstractmethod - def key_size(self) -> int: - """ - The bit length of the public modulus. - """ - - @abc.abstractmethod - def public_numbers(self) -> RSAPublicNumbers: - """ - Returns an RSAPublicNumbers - """ - - @abc.abstractmethod - def public_bytes( - self, - encoding: _serialization.Encoding, - format: _serialization.PublicFormat, - ) -> bytes: - """ - Returns the key serialized as bytes. - """ - - @abc.abstractmethod - def verify( - self, - signature: bytes, - data: bytes, - padding: AsymmetricPadding, - algorithm: asym_utils.Prehashed | hashes.HashAlgorithm, - ) -> None: - """ - Verifies the signature of the data. - """ - - @abc.abstractmethod - def recover_data_from_signature( - self, - signature: bytes, - padding: AsymmetricPadding, - algorithm: hashes.HashAlgorithm | asym_utils.NoDigestInfo | None, - ) -> bytes: - """ - Recovers the original data from the signature. - """ - - @abc.abstractmethod - def __eq__(self, other: object) -> bool: - """ - Checks equality. - """ - - @abc.abstractmethod - def __copy__(self) -> RSAPublicKey: - """ - Returns a copy. - """ - - @abc.abstractmethod - def __deepcopy__(self, memo: dict) -> RSAPublicKey: - """ - Returns a deep copy. - """ - - -RSAPublicKeyWithSerialization = RSAPublicKey -RSAPublicKey.register(rust_openssl.rsa.RSAPublicKey) - -RSAPrivateNumbers = rust_openssl.rsa.RSAPrivateNumbers -RSAPublicNumbers = rust_openssl.rsa.RSAPublicNumbers - - -def generate_private_key( - public_exponent: int, - key_size: int, - backend: typing.Any = None, -) -> RSAPrivateKey: - _verify_rsa_parameters(public_exponent, key_size) - return rust_openssl.rsa.generate_private_key(public_exponent, key_size) - - -def _verify_rsa_parameters(public_exponent: int, key_size: int) -> None: - if public_exponent not in (3, 65537): - raise ValueError( - "public_exponent must be either 3 (for legacy compatibility) or " - "65537. Almost everyone should choose 65537 here!" - ) - - if key_size < 1024: - raise ValueError("key_size must be at least 1024-bits.") - - -def _modinv(e: int, m: int) -> int: - """ - Modular Multiplicative Inverse. Returns x such that: (x*e) mod m == 1 - """ - x1, x2 = 1, 0 - a, b = e, m - while b > 0: - q, r = divmod(a, b) - xn = x1 - q * x2 - a, b, x1, x2 = b, r, x2, xn - return x1 % m - - -def rsa_crt_iqmp(p: int, q: int) -> int: - """ - Compute the CRT (q ** -1) % p value from RSA primes p and q. - """ - if p <= 1 or q <= 1: - raise ValueError("Values can't be <= 1") - return _modinv(q, p) - - -def rsa_crt_dmp1(private_exponent: int, p: int) -> int: - """ - Compute the CRT private_exponent % (p - 1) value from the RSA - private_exponent (d) and p. - """ - if private_exponent <= 1 or p <= 1: - raise ValueError("Values can't be <= 1") - return private_exponent % (p - 1) - - -def rsa_crt_dmq1(private_exponent: int, q: int) -> int: - """ - Compute the CRT private_exponent % (q - 1) value from the RSA - private_exponent (d) and q. - """ - if private_exponent <= 1 or q <= 1: - raise ValueError("Values can't be <= 1") - return private_exponent % (q - 1) - - -def rsa_recover_private_exponent(e: int, p: int, q: int) -> int: - """ - Compute the RSA private_exponent (d) given the public exponent (e) - and the RSA primes p and q. - - This uses the Carmichael totient function to generate the - smallest possible working value of the private exponent. - """ - # This lambda_n is the Carmichael totient function. - # The original RSA paper uses the Euler totient function - # here: phi_n = (p - 1) * (q - 1) - # Either version of the private exponent will work, but the - # one generated by the older formulation may be larger - # than necessary. (lambda_n always divides phi_n) - # - # TODO: Replace with lcm(p - 1, q - 1) once the minimum - # supported Python version is >= 3.9. - if e <= 1 or p <= 1 or q <= 1: - raise ValueError("Values can't be <= 1") - lambda_n = (p - 1) * (q - 1) // gcd(p - 1, q - 1) - return _modinv(e, lambda_n) - - -# Controls the number of iterations rsa_recover_prime_factors will perform -# to obtain the prime factors. -_MAX_RECOVERY_ATTEMPTS = 500 - - -def rsa_recover_prime_factors(n: int, e: int, d: int) -> tuple[int, int]: - """ - Compute factors p and q from the private exponent d. We assume that n has - no more than two factors. This function is adapted from code in PyCrypto. - """ - # reject invalid values early - if d <= 1 or e <= 1: - raise ValueError("d, e can't be <= 1") - if 17 != pow(17, e * d, n): - raise ValueError("n, d, e don't match") - # See 8.2.2(i) in Handbook of Applied Cryptography. - ktot = d * e - 1 - # The quantity d*e-1 is a multiple of phi(n), even, - # and can be represented as t*2^s. - t = ktot - while t % 2 == 0: - t = t // 2 - # Cycle through all multiplicative inverses in Zn. - # The algorithm is non-deterministic, but there is a 50% chance - # any candidate a leads to successful factoring. - # See "Digitalized Signatures and Public Key Functions as Intractable - # as Factorization", M. Rabin, 1979 - spotted = False - tries = 0 - while not spotted and tries < _MAX_RECOVERY_ATTEMPTS: - a = random.randint(2, n - 1) - tries += 1 - k = t - # Cycle through all values a^{t*2^i}=a^k - while k < ktot: - cand = pow(a, k, n) - # Check if a^k is a non-trivial root of unity (mod n) - if cand != 1 and cand != (n - 1) and pow(cand, 2, n) == 1: - # We have found a number such that (cand-1)(cand+1)=0 (mod n). - # Either of the terms divides n. - p = gcd(cand + 1, n) - spotted = True - break - k *= 2 - if not spotted: - raise ValueError("Unable to compute factors p and q from exponent d.") - # Found ! - q, r = divmod(n, p) - assert r == 0 - p, q = sorted((p, q), reverse=True) - return (p, q) diff --git a/venv/lib/python3.9/site-packages/cryptography/hazmat/primitives/asymmetric/types.py b/venv/lib/python3.9/site-packages/cryptography/hazmat/primitives/asymmetric/types.py deleted file mode 100644 index dfd12ce..0000000 --- a/venv/lib/python3.9/site-packages/cryptography/hazmat/primitives/asymmetric/types.py +++ /dev/null @@ -1,123 +0,0 @@ -# This file is dual licensed under the terms of the Apache License, Version -# 2.0, and the BSD License. See the LICENSE file in the root of this repository -# for complete details. - -from __future__ import annotations - -import typing - -from cryptography import utils -from cryptography.hazmat.primitives.asymmetric import ( - dh, - dsa, - ec, - ed448, - ed25519, - mldsa, - mlkem, - rsa, - x448, - x25519, -) - -# Every asymmetric key type -PublicKeyTypes = typing.Union[ - dh.DHPublicKey, - dsa.DSAPublicKey, - rsa.RSAPublicKey, - ec.EllipticCurvePublicKey, - ed25519.Ed25519PublicKey, - ed448.Ed448PublicKey, - mldsa.MLDSA44PublicKey, - mldsa.MLDSA65PublicKey, - mldsa.MLDSA87PublicKey, - mlkem.MLKEM768PublicKey, - mlkem.MLKEM1024PublicKey, - x25519.X25519PublicKey, - x448.X448PublicKey, -] -PUBLIC_KEY_TYPES = PublicKeyTypes -utils.deprecated( - PUBLIC_KEY_TYPES, - __name__, - "Use PublicKeyTypes instead", - utils.DeprecatedIn40, - name="PUBLIC_KEY_TYPES", -) -# Every asymmetric key type -PrivateKeyTypes = typing.Union[ - dh.DHPrivateKey, - ed25519.Ed25519PrivateKey, - ed448.Ed448PrivateKey, - mldsa.MLDSA44PrivateKey, - mldsa.MLDSA65PrivateKey, - mldsa.MLDSA87PrivateKey, - mlkem.MLKEM768PrivateKey, - mlkem.MLKEM1024PrivateKey, - rsa.RSAPrivateKey, - dsa.DSAPrivateKey, - ec.EllipticCurvePrivateKey, - x25519.X25519PrivateKey, - x448.X448PrivateKey, -] -PRIVATE_KEY_TYPES = PrivateKeyTypes -utils.deprecated( - PRIVATE_KEY_TYPES, - __name__, - "Use PrivateKeyTypes instead", - utils.DeprecatedIn40, - name="PRIVATE_KEY_TYPES", -) -# Just the key types we allow to be used for x509 signing. This mirrors -# the certificate public key types -CertificateIssuerPrivateKeyTypes = typing.Union[ - ed25519.Ed25519PrivateKey, - ed448.Ed448PrivateKey, - rsa.RSAPrivateKey, - dsa.DSAPrivateKey, - ec.EllipticCurvePrivateKey, -] -CERTIFICATE_PRIVATE_KEY_TYPES = CertificateIssuerPrivateKeyTypes -utils.deprecated( - CERTIFICATE_PRIVATE_KEY_TYPES, - __name__, - "Use CertificateIssuerPrivateKeyTypes instead", - utils.DeprecatedIn40, - name="CERTIFICATE_PRIVATE_KEY_TYPES", -) -# Just the key types we allow to be used for x509 signing. This mirrors -# the certificate private key types -CertificateIssuerPublicKeyTypes = typing.Union[ - dsa.DSAPublicKey, - rsa.RSAPublicKey, - ec.EllipticCurvePublicKey, - ed25519.Ed25519PublicKey, - ed448.Ed448PublicKey, -] -CERTIFICATE_ISSUER_PUBLIC_KEY_TYPES = CertificateIssuerPublicKeyTypes -utils.deprecated( - CERTIFICATE_ISSUER_PUBLIC_KEY_TYPES, - __name__, - "Use CertificateIssuerPublicKeyTypes instead", - utils.DeprecatedIn40, - name="CERTIFICATE_ISSUER_PUBLIC_KEY_TYPES", -) -# This type removes DHPublicKey. x448/x25519 can be a public key -# but cannot be used in signing so they are allowed here. -CertificatePublicKeyTypes = typing.Union[ - dsa.DSAPublicKey, - rsa.RSAPublicKey, - ec.EllipticCurvePublicKey, - ed25519.Ed25519PublicKey, - ed448.Ed448PublicKey, - x25519.X25519PublicKey, - x448.X448PublicKey, -] -CERTIFICATE_PUBLIC_KEY_TYPES = CertificatePublicKeyTypes -utils.deprecated( - CERTIFICATE_PUBLIC_KEY_TYPES, - __name__, - "Use CertificatePublicKeyTypes instead", - utils.DeprecatedIn40, - name="CERTIFICATE_PUBLIC_KEY_TYPES", -) diff --git a/venv/lib/python3.9/site-packages/cryptography/hazmat/primitives/asymmetric/utils.py b/venv/lib/python3.9/site-packages/cryptography/hazmat/primitives/asymmetric/utils.py deleted file mode 100644 index c01c342..0000000 --- a/venv/lib/python3.9/site-packages/cryptography/hazmat/primitives/asymmetric/utils.py +++ /dev/null @@ -1,28 +0,0 @@ -# This file is dual licensed under the terms of the Apache License, Version -# 2.0, and the BSD License. See the LICENSE file in the root of this repository -# for complete details. - -from __future__ import annotations - -from cryptography.hazmat.bindings._rust import asn1 -from cryptography.hazmat.primitives import hashes - -decode_dss_signature = asn1.decode_dss_signature -encode_dss_signature = asn1.encode_dss_signature - - -class NoDigestInfo: - pass - - -class Prehashed: - def __init__(self, algorithm: hashes.HashAlgorithm): - if not isinstance(algorithm, hashes.HashAlgorithm): - raise TypeError("Expected instance of HashAlgorithm.") - - self._algorithm = algorithm - self._digest_size = algorithm.digest_size - - @property - def digest_size(self) -> int: - return self._digest_size diff --git a/venv/lib/python3.9/site-packages/cryptography/hazmat/primitives/asymmetric/x25519.py b/venv/lib/python3.9/site-packages/cryptography/hazmat/primitives/asymmetric/x25519.py deleted file mode 100644 index 7498998..0000000 --- a/venv/lib/python3.9/site-packages/cryptography/hazmat/primitives/asymmetric/x25519.py +++ /dev/null @@ -1,134 +0,0 @@ -# This file is dual licensed under the terms of the Apache License, Version -# 2.0, and the BSD License. See the LICENSE file in the root of this repository -# for complete details. - -from __future__ import annotations - -import abc - -from cryptography.exceptions import UnsupportedAlgorithm, _Reasons -from cryptography.hazmat.bindings._rust import openssl as rust_openssl -from cryptography.hazmat.primitives import _serialization -from cryptography.utils import Buffer - - -class X25519PublicKey(metaclass=abc.ABCMeta): - @classmethod - def from_public_bytes(cls, data: bytes) -> X25519PublicKey: - from cryptography.hazmat.backends.openssl.backend import backend - - if not backend.x25519_supported(): - raise UnsupportedAlgorithm( - "X25519 is not supported by this version of OpenSSL.", - _Reasons.UNSUPPORTED_EXCHANGE_ALGORITHM, - ) - - return rust_openssl.x25519.from_public_bytes(data) - - @abc.abstractmethod - def public_bytes( - self, - encoding: _serialization.Encoding, - format: _serialization.PublicFormat, - ) -> bytes: - """ - The serialized bytes of the public key. - """ - - @abc.abstractmethod - def public_bytes_raw(self) -> bytes: - """ - The raw bytes of the public key. - Equivalent to public_bytes(Raw, Raw). - """ - - @abc.abstractmethod - def __eq__(self, other: object) -> bool: - """ - Checks equality. - """ - - @abc.abstractmethod - def __copy__(self) -> X25519PublicKey: - """ - Returns a copy. - """ - - @abc.abstractmethod - def __deepcopy__(self, memo: dict) -> X25519PublicKey: - """ - Returns a deep copy. - """ - - -X25519PublicKey.register(rust_openssl.x25519.X25519PublicKey) - - -class X25519PrivateKey(metaclass=abc.ABCMeta): - @classmethod - def generate(cls) -> X25519PrivateKey: - from cryptography.hazmat.backends.openssl.backend import backend - - if not backend.x25519_supported(): - raise UnsupportedAlgorithm( - "X25519 is not supported by this version of OpenSSL.", - _Reasons.UNSUPPORTED_EXCHANGE_ALGORITHM, - ) - return rust_openssl.x25519.generate_key() - - @classmethod - def from_private_bytes(cls, data: Buffer) -> X25519PrivateKey: - from cryptography.hazmat.backends.openssl.backend import backend - - if not backend.x25519_supported(): - raise UnsupportedAlgorithm( - "X25519 is not supported by this version of OpenSSL.", - _Reasons.UNSUPPORTED_EXCHANGE_ALGORITHM, - ) - - return rust_openssl.x25519.from_private_bytes(data) - - @abc.abstractmethod - def public_key(self) -> X25519PublicKey: - """ - Returns the public key associated with this private key - """ - - @abc.abstractmethod - def private_bytes( - self, - encoding: _serialization.Encoding, - format: _serialization.PrivateFormat, - encryption_algorithm: _serialization.KeySerializationEncryption, - ) -> bytes: - """ - The serialized bytes of the private key. - """ - - @abc.abstractmethod - def private_bytes_raw(self) -> bytes: - """ - The raw bytes of the private key. - Equivalent to private_bytes(Raw, Raw, NoEncryption()). - """ - - @abc.abstractmethod - def exchange(self, peer_public_key: X25519PublicKey) -> bytes: - """ - Performs a key exchange operation using the provided peer's public key. - """ - - @abc.abstractmethod - def __copy__(self) -> X25519PrivateKey: - """ - Returns a copy. - """ - - @abc.abstractmethod - def __deepcopy__(self, memo: dict) -> X25519PrivateKey: - """ - Returns a deep copy. - """ - - -X25519PrivateKey.register(rust_openssl.x25519.X25519PrivateKey) diff --git a/venv/lib/python3.9/site-packages/cryptography/hazmat/primitives/asymmetric/x448.py b/venv/lib/python3.9/site-packages/cryptography/hazmat/primitives/asymmetric/x448.py deleted file mode 100644 index b9dc826..0000000 --- a/venv/lib/python3.9/site-packages/cryptography/hazmat/primitives/asymmetric/x448.py +++ /dev/null @@ -1,137 +0,0 @@ -# This file is dual licensed under the terms of the Apache License, Version -# 2.0, and the BSD License. See the LICENSE file in the root of this repository -# for complete details. - -from __future__ import annotations - -import abc - -from cryptography.exceptions import UnsupportedAlgorithm, _Reasons -from cryptography.hazmat.bindings._rust import openssl as rust_openssl -from cryptography.hazmat.primitives import _serialization -from cryptography.utils import Buffer - - -class X448PublicKey(metaclass=abc.ABCMeta): - @classmethod - def from_public_bytes(cls, data: bytes) -> X448PublicKey: - from cryptography.hazmat.backends.openssl.backend import backend - - if not backend.x448_supported(): - raise UnsupportedAlgorithm( - "X448 is not supported by this version of OpenSSL.", - _Reasons.UNSUPPORTED_EXCHANGE_ALGORITHM, - ) - - return rust_openssl.x448.from_public_bytes(data) - - @abc.abstractmethod - def public_bytes( - self, - encoding: _serialization.Encoding, - format: _serialization.PublicFormat, - ) -> bytes: - """ - The serialized bytes of the public key. - """ - - @abc.abstractmethod - def public_bytes_raw(self) -> bytes: - """ - The raw bytes of the public key. - Equivalent to public_bytes(Raw, Raw). - """ - - @abc.abstractmethod - def __eq__(self, other: object) -> bool: - """ - Checks equality. - """ - - @abc.abstractmethod - def __copy__(self) -> X448PublicKey: - """ - Returns a copy. - """ - - @abc.abstractmethod - def __deepcopy__(self, memo: dict) -> X448PublicKey: - """ - Returns a deep copy. - """ - - -if hasattr(rust_openssl, "x448"): - X448PublicKey.register(rust_openssl.x448.X448PublicKey) - - -class X448PrivateKey(metaclass=abc.ABCMeta): - @classmethod - def generate(cls) -> X448PrivateKey: - from cryptography.hazmat.backends.openssl.backend import backend - - if not backend.x448_supported(): - raise UnsupportedAlgorithm( - "X448 is not supported by this version of OpenSSL.", - _Reasons.UNSUPPORTED_EXCHANGE_ALGORITHM, - ) - - return rust_openssl.x448.generate_key() - - @classmethod - def from_private_bytes(cls, data: Buffer) -> X448PrivateKey: - from cryptography.hazmat.backends.openssl.backend import backend - - if not backend.x448_supported(): - raise UnsupportedAlgorithm( - "X448 is not supported by this version of OpenSSL.", - _Reasons.UNSUPPORTED_EXCHANGE_ALGORITHM, - ) - - return rust_openssl.x448.from_private_bytes(data) - - @abc.abstractmethod - def public_key(self) -> X448PublicKey: - """ - Returns the public key associated with this private key - """ - - @abc.abstractmethod - def private_bytes( - self, - encoding: _serialization.Encoding, - format: _serialization.PrivateFormat, - encryption_algorithm: _serialization.KeySerializationEncryption, - ) -> bytes: - """ - The serialized bytes of the private key. - """ - - @abc.abstractmethod - def private_bytes_raw(self) -> bytes: - """ - The raw bytes of the private key. - Equivalent to private_bytes(Raw, Raw, NoEncryption()). - """ - - @abc.abstractmethod - def exchange(self, peer_public_key: X448PublicKey) -> bytes: - """ - Performs a key exchange operation using the provided peer's public key. - """ - - @abc.abstractmethod - def __copy__(self) -> X448PrivateKey: - """ - Returns a copy. - """ - - @abc.abstractmethod - def __deepcopy__(self, memo: dict) -> X448PrivateKey: - """ - Returns a deep copy. - """ - - -if hasattr(rust_openssl, "x448"): - X448PrivateKey.register(rust_openssl.x448.X448PrivateKey) diff --git a/venv/lib/python3.9/site-packages/cryptography/hazmat/primitives/ciphers/__init__.py b/venv/lib/python3.9/site-packages/cryptography/hazmat/primitives/ciphers/__init__.py deleted file mode 100644 index 10c15d0..0000000 --- a/venv/lib/python3.9/site-packages/cryptography/hazmat/primitives/ciphers/__init__.py +++ /dev/null @@ -1,27 +0,0 @@ -# This file is dual licensed under the terms of the Apache License, Version -# 2.0, and the BSD License. See the LICENSE file in the root of this repository -# for complete details. - -from __future__ import annotations - -from cryptography.hazmat.primitives._cipheralgorithm import ( - BlockCipherAlgorithm, - CipherAlgorithm, -) -from cryptography.hazmat.primitives.ciphers.base import ( - AEADCipherContext, - AEADDecryptionContext, - AEADEncryptionContext, - Cipher, - CipherContext, -) - -__all__ = [ - "AEADCipherContext", - "AEADDecryptionContext", - "AEADEncryptionContext", - "BlockCipherAlgorithm", - "Cipher", - "CipherAlgorithm", - "CipherContext", -] diff --git a/venv/lib/python3.9/site-packages/cryptography/hazmat/primitives/ciphers/aead.py b/venv/lib/python3.9/site-packages/cryptography/hazmat/primitives/ciphers/aead.py deleted file mode 100644 index c8a582d..0000000 --- a/venv/lib/python3.9/site-packages/cryptography/hazmat/primitives/ciphers/aead.py +++ /dev/null @@ -1,23 +0,0 @@ -# This file is dual licensed under the terms of the Apache License, Version -# 2.0, and the BSD License. See the LICENSE file in the root of this repository -# for complete details. - -from __future__ import annotations - -from cryptography.hazmat.bindings._rust import openssl as rust_openssl - -__all__ = [ - "AESCCM", - "AESGCM", - "AESGCMSIV", - "AESOCB3", - "AESSIV", - "ChaCha20Poly1305", -] - -AESGCM = rust_openssl.aead.AESGCM -ChaCha20Poly1305 = rust_openssl.aead.ChaCha20Poly1305 -AESCCM = rust_openssl.aead.AESCCM -AESSIV = rust_openssl.aead.AESSIV -AESOCB3 = rust_openssl.aead.AESOCB3 -AESGCMSIV = rust_openssl.aead.AESGCMSIV diff --git a/venv/lib/python3.9/site-packages/cryptography/hazmat/primitives/ciphers/algorithms.py b/venv/lib/python3.9/site-packages/cryptography/hazmat/primitives/ciphers/algorithms.py deleted file mode 100644 index 6b20dd5..0000000 --- a/venv/lib/python3.9/site-packages/cryptography/hazmat/primitives/ciphers/algorithms.py +++ /dev/null @@ -1,138 +0,0 @@ -# This file is dual licensed under the terms of the Apache License, Version -# 2.0, and the BSD License. See the LICENSE file in the root of this repository -# for complete details. - -from __future__ import annotations - -from cryptography import utils -from cryptography.hazmat.decrepit.ciphers.algorithms import ( - ARC4 as ARC4, -) -from cryptography.hazmat.decrepit.ciphers.algorithms import ( - CAST5 as CAST5, -) -from cryptography.hazmat.decrepit.ciphers.algorithms import ( - IDEA as IDEA, -) -from cryptography.hazmat.decrepit.ciphers.algorithms import ( - SEED as SEED, -) -from cryptography.hazmat.decrepit.ciphers.algorithms import ( - Blowfish as Blowfish, -) -from cryptography.hazmat.decrepit.ciphers.algorithms import ( - Camellia as Camellia, -) -from cryptography.hazmat.decrepit.ciphers.algorithms import ( - TripleDES as TripleDES, -) -from cryptography.hazmat.primitives._cipheralgorithm import _verify_key_size -from cryptography.hazmat.primitives.ciphers import ( - BlockCipherAlgorithm, - CipherAlgorithm, -) - - -class AES(BlockCipherAlgorithm): - name = "AES" - block_size = 128 - # 512 added to support AES-256-XTS, which uses 512-bit keys - key_sizes = frozenset([128, 192, 256, 512]) - - def __init__(self, key: utils.Buffer): - self.key = _verify_key_size(self, key) - - @property - def key_size(self) -> int: - return len(self.key) * 8 - - -class AES128(BlockCipherAlgorithm): - name = "AES" - block_size = 128 - key_sizes = frozenset([128]) - key_size = 128 - - def __init__(self, key: utils.Buffer): - self.key = _verify_key_size(self, key) - - -class AES256(BlockCipherAlgorithm): - name = "AES" - block_size = 128 - key_sizes = frozenset([256]) - key_size = 256 - - def __init__(self, key: utils.Buffer): - self.key = _verify_key_size(self, key) - - -utils.deprecated( - Camellia, - __name__, - "Camellia has been moved to " - "cryptography.hazmat.decrepit.ciphers.algorithms.Camellia and " - "will be removed from " - "cryptography.hazmat.primitives.ciphers.algorithms in 49.0.0.", - utils.DeprecatedIn43, - name="Camellia", -) - - -utils.deprecated( - ARC4, - __name__, - "ARC4 has been moved to " - "cryptography.hazmat.decrepit.ciphers.algorithms.ARC4 and " - "will be removed from " - "cryptography.hazmat.primitives.ciphers.algorithms in 48.0.0.", - utils.DeprecatedIn43, - name="ARC4", -) - - -utils.deprecated( - TripleDES, - __name__, - "TripleDES has been moved to " - "cryptography.hazmat.decrepit.ciphers.algorithms.TripleDES and " - "will be removed from " - "cryptography.hazmat.primitives.ciphers.algorithms in 48.0.0.", - utils.DeprecatedIn43, - name="TripleDES", -) - - -class ChaCha20(CipherAlgorithm): - name = "ChaCha20" - key_sizes = frozenset([256]) - - def __init__(self, key: utils.Buffer, nonce: utils.Buffer): - self.key = _verify_key_size(self, key) - utils._check_byteslike("nonce", nonce) - - if len(nonce) != 16: - raise ValueError("nonce must be 128-bits (16 bytes)") - - self._nonce = nonce - - @property - def nonce(self) -> utils.Buffer: - return self._nonce - - @property - def key_size(self) -> int: - return len(self.key) * 8 - - -class SM4(BlockCipherAlgorithm): - name = "SM4" - block_size = 128 - key_sizes = frozenset([128]) - - def __init__(self, key: bytes): - self.key = _verify_key_size(self, key) - - @property - def key_size(self) -> int: - return len(self.key) * 8 diff --git a/venv/lib/python3.9/site-packages/cryptography/hazmat/primitives/ciphers/base.py b/venv/lib/python3.9/site-packages/cryptography/hazmat/primitives/ciphers/base.py deleted file mode 100644 index 24fceea..0000000 --- a/venv/lib/python3.9/site-packages/cryptography/hazmat/primitives/ciphers/base.py +++ /dev/null @@ -1,146 +0,0 @@ -# This file is dual licensed under the terms of the Apache License, Version -# 2.0, and the BSD License. See the LICENSE file in the root of this repository -# for complete details. - -from __future__ import annotations - -import abc -import typing - -from cryptography.hazmat.bindings._rust import openssl as rust_openssl -from cryptography.hazmat.primitives._cipheralgorithm import CipherAlgorithm -from cryptography.hazmat.primitives.ciphers import modes -from cryptography.utils import Buffer - - -class CipherContext(metaclass=abc.ABCMeta): - @abc.abstractmethod - def update(self, data: Buffer) -> bytes: - """ - Processes the provided bytes through the cipher and returns the results - as bytes. - """ - - @abc.abstractmethod - def update_into(self, data: Buffer, buf: Buffer) -> int: - """ - Processes the provided bytes and writes the resulting data into the - provided buffer. Returns the number of bytes written. - """ - - @abc.abstractmethod - def finalize(self) -> bytes: - """ - Returns the results of processing the final block as bytes. - """ - - @abc.abstractmethod - def reset_nonce(self, nonce: bytes) -> None: - """ - Resets the nonce for the cipher context to the provided value. - Raises an exception if it does not support reset or if the - provided nonce does not have a valid length. - """ - - -class AEADCipherContext(CipherContext, metaclass=abc.ABCMeta): - @abc.abstractmethod - def authenticate_additional_data(self, data: Buffer) -> None: - """ - Authenticates the provided bytes. - """ - - -class AEADDecryptionContext(AEADCipherContext, metaclass=abc.ABCMeta): - @abc.abstractmethod - def finalize_with_tag(self, tag: bytes) -> bytes: - """ - Returns the results of processing the final block as bytes and allows - delayed passing of the authentication tag. - """ - - -class AEADEncryptionContext(AEADCipherContext, metaclass=abc.ABCMeta): - @property - @abc.abstractmethod - def tag(self) -> bytes: - """ - Returns tag bytes. This is only available after encryption is - finalized. - """ - - -Mode = typing.TypeVar( - "Mode", bound=typing.Optional[modes.Mode], covariant=True -) - - -class Cipher(typing.Generic[Mode]): - def __init__( - self, - algorithm: CipherAlgorithm, - mode: Mode, - backend: typing.Any = None, - ) -> None: - if not isinstance(algorithm, CipherAlgorithm): - raise TypeError("Expected interface of CipherAlgorithm.") - - if mode is not None: - # mypy needs this assert to narrow the type from our generic - # type. Maybe it won't some time in the future. - assert isinstance(mode, modes.Mode) - mode.validate_for_algorithm(algorithm) - - self.algorithm = algorithm - self.mode = mode - - @typing.overload - def encryptor( - self: Cipher[modes.ModeWithAuthenticationTag], - ) -> AEADEncryptionContext: ... - - @typing.overload - def encryptor( - self: _CIPHER_TYPE, - ) -> CipherContext: ... - - def encryptor(self): - if isinstance(self.mode, modes.ModeWithAuthenticationTag): - if self.mode.tag is not None: - raise ValueError( - "Authentication tag must be None when encrypting." - ) - - return rust_openssl.ciphers.create_encryption_ctx( - self.algorithm, self.mode - ) - - @typing.overload - def decryptor( - self: Cipher[modes.ModeWithAuthenticationTag], - ) -> AEADDecryptionContext: ... - - @typing.overload - def decryptor( - self: _CIPHER_TYPE, - ) -> CipherContext: ... - - def decryptor(self): - return rust_openssl.ciphers.create_decryption_ctx( - self.algorithm, self.mode - ) - - -_CIPHER_TYPE = Cipher[ - typing.Union[ - modes.ModeWithNonce, - modes.ModeWithTweak, - modes.ECB, - modes.ModeWithInitializationVector, - None, - ] -] - -CipherContext.register(rust_openssl.ciphers.CipherContext) -AEADEncryptionContext.register(rust_openssl.ciphers.AEADEncryptionContext) -AEADDecryptionContext.register(rust_openssl.ciphers.AEADDecryptionContext) diff --git a/venv/lib/python3.9/site-packages/cryptography/hazmat/primitives/ciphers/modes.py b/venv/lib/python3.9/site-packages/cryptography/hazmat/primitives/ciphers/modes.py deleted file mode 100644 index 0f1c217..0000000 --- a/venv/lib/python3.9/site-packages/cryptography/hazmat/primitives/ciphers/modes.py +++ /dev/null @@ -1,192 +0,0 @@ -# This file is dual licensed under the terms of the Apache License, Version -# 2.0, and the BSD License. See the LICENSE file in the root of this repository -# for complete details. - -from __future__ import annotations - -from cryptography import utils -from cryptography.exceptions import UnsupportedAlgorithm, _Reasons -from cryptography.hazmat.decrepit.ciphers.modes import CFB as CFB -from cryptography.hazmat.decrepit.ciphers.modes import CFB8 as CFB8 -from cryptography.hazmat.decrepit.ciphers.modes import OFB as OFB -from cryptography.hazmat.primitives._cipheralgorithm import ( - BlockCipherAlgorithm, - CipherAlgorithm, -) -from cryptography.hazmat.primitives._modes import ( - Mode as Mode, -) -from cryptography.hazmat.primitives._modes import ( - ModeWithAuthenticationTag as ModeWithAuthenticationTag, -) -from cryptography.hazmat.primitives._modes import ( - ModeWithInitializationVector as ModeWithInitializationVector, -) -from cryptography.hazmat.primitives._modes import ( - ModeWithNonce as ModeWithNonce, -) -from cryptography.hazmat.primitives._modes import ( - ModeWithTweak as ModeWithTweak, -) -from cryptography.hazmat.primitives._modes import ( - _check_aes_key_length, - _check_iv_and_key_length, - _check_nonce_length, -) -from cryptography.hazmat.primitives.ciphers import algorithms - - -class CBC(ModeWithInitializationVector): - name = "CBC" - - def __init__(self, initialization_vector: utils.Buffer): - utils._check_byteslike("initialization_vector", initialization_vector) - self._initialization_vector = initialization_vector - - @property - def initialization_vector(self) -> utils.Buffer: - return self._initialization_vector - - validate_for_algorithm = _check_iv_and_key_length - - -class XTS(ModeWithTweak): - name = "XTS" - - def __init__(self, tweak: utils.Buffer): - utils._check_byteslike("tweak", tweak) - - if len(tweak) != 16: - raise ValueError("tweak must be 128-bits (16 bytes)") - - self._tweak = tweak - - @property - def tweak(self) -> utils.Buffer: - return self._tweak - - def validate_for_algorithm(self, algorithm: CipherAlgorithm) -> None: - if isinstance(algorithm, (algorithms.AES128, algorithms.AES256)): - raise TypeError( - "The AES128 and AES256 classes do not support XTS, please use " - "the standard AES class instead." - ) - - if algorithm.key_size not in (256, 512): - raise ValueError( - "The XTS specification requires a 256-bit key for AES-128-XTS" - " and 512-bit key for AES-256-XTS" - ) - - -class ECB(Mode): - name = "ECB" - - validate_for_algorithm = _check_aes_key_length - - -class CTR(ModeWithNonce): - name = "CTR" - - def __init__(self, nonce: utils.Buffer): - utils._check_byteslike("nonce", nonce) - self._nonce = nonce - - @property - def nonce(self) -> utils.Buffer: - return self._nonce - - def validate_for_algorithm(self, algorithm: CipherAlgorithm) -> None: - _check_aes_key_length(self, algorithm) - _check_nonce_length(self.nonce, self.name, algorithm) - - -class GCM(ModeWithInitializationVector, ModeWithAuthenticationTag): - name = "GCM" - _MAX_ENCRYPTED_BYTES = (2**39 - 256) // 8 - _MAX_AAD_BYTES = (2**64) // 8 - - def __init__( - self, - initialization_vector: utils.Buffer, - tag: bytes | None = None, - min_tag_length: int = 16, - ): - # OpenSSL 3.0.0 constrains GCM IVs to [64, 1024] bits inclusive - # This is a sane limit anyway so we'll enforce it here. - utils._check_byteslike("initialization_vector", initialization_vector) - if len(initialization_vector) < 8 or len(initialization_vector) > 128: - raise ValueError( - "initialization_vector must be between 8 and 128 bytes (64 " - "and 1024 bits)." - ) - self._initialization_vector = initialization_vector - if tag is not None: - utils._check_bytes("tag", tag) - if min_tag_length < 4: - raise ValueError("min_tag_length must be >= 4") - if len(tag) < min_tag_length: - raise ValueError( - f"Authentication tag must be {min_tag_length} bytes or " - "longer." - ) - self._tag = tag - self._min_tag_length = min_tag_length - - @property - def tag(self) -> bytes | None: - return self._tag - - @property - def initialization_vector(self) -> utils.Buffer: - return self._initialization_vector - - def validate_for_algorithm(self, algorithm: CipherAlgorithm) -> None: - _check_aes_key_length(self, algorithm) - if not isinstance(algorithm, BlockCipherAlgorithm): - raise UnsupportedAlgorithm( - "GCM requires a block cipher algorithm", - _Reasons.UNSUPPORTED_CIPHER, - ) - block_size_bytes = algorithm.block_size // 8 - if self._tag is not None and len(self._tag) > block_size_bytes: - raise ValueError( - f"Authentication tag cannot be more than {block_size_bytes} " - "bytes." - ) - - -utils.deprecated( - OFB, - __name__, - "OFB has been moved to " - "cryptography.hazmat.decrepit.ciphers.modes.OFB and " - "will be removed from " - "cryptography.hazmat.primitives.ciphers.modes in 49.0.0.", - utils.DeprecatedIn47, - name="OFB", -) - - -utils.deprecated( - CFB, - __name__, - "CFB has been moved to " - "cryptography.hazmat.decrepit.ciphers.modes.CFB and " - "will be removed from " - "cryptography.hazmat.primitives.ciphers.modes in 49.0.0.", - utils.DeprecatedIn47, - name="CFB", -) - - -utils.deprecated( - CFB8, - __name__, - "CFB8 has been moved to " - "cryptography.hazmat.decrepit.ciphers.modes.CFB8 and " - "will be removed from " - "cryptography.hazmat.primitives.ciphers.modes in 49.0.0.", - utils.DeprecatedIn47, - name="CFB8", -) diff --git a/venv/lib/python3.9/site-packages/cryptography/hazmat/primitives/cmac.py b/venv/lib/python3.9/site-packages/cryptography/hazmat/primitives/cmac.py deleted file mode 100644 index 2c67ce2..0000000 --- a/venv/lib/python3.9/site-packages/cryptography/hazmat/primitives/cmac.py +++ /dev/null @@ -1,10 +0,0 @@ -# This file is dual licensed under the terms of the Apache License, Version -# 2.0, and the BSD License. See the LICENSE file in the root of this repository -# for complete details. - -from __future__ import annotations - -from cryptography.hazmat.bindings._rust import openssl as rust_openssl - -__all__ = ["CMAC"] -CMAC = rust_openssl.cmac.CMAC diff --git a/venv/lib/python3.9/site-packages/cryptography/hazmat/primitives/constant_time.py b/venv/lib/python3.9/site-packages/cryptography/hazmat/primitives/constant_time.py deleted file mode 100644 index 3975c71..0000000 --- a/venv/lib/python3.9/site-packages/cryptography/hazmat/primitives/constant_time.py +++ /dev/null @@ -1,14 +0,0 @@ -# This file is dual licensed under the terms of the Apache License, Version -# 2.0, and the BSD License. See the LICENSE file in the root of this repository -# for complete details. - -from __future__ import annotations - -import hmac - - -def bytes_eq(a: bytes, b: bytes) -> bool: - if not isinstance(a, bytes) or not isinstance(b, bytes): - raise TypeError("a and b must be bytes.") - - return hmac.compare_digest(a, b) diff --git a/venv/lib/python3.9/site-packages/cryptography/hazmat/primitives/hashes.py b/venv/lib/python3.9/site-packages/cryptography/hazmat/primitives/hashes.py deleted file mode 100644 index 4b55ec3..0000000 --- a/venv/lib/python3.9/site-packages/cryptography/hazmat/primitives/hashes.py +++ /dev/null @@ -1,246 +0,0 @@ -# This file is dual licensed under the terms of the Apache License, Version -# 2.0, and the BSD License. See the LICENSE file in the root of this repository -# for complete details. - -from __future__ import annotations - -import abc - -from cryptography.hazmat.bindings._rust import openssl as rust_openssl -from cryptography.utils import Buffer - -__all__ = [ - "MD5", - "SHA1", - "SHA3_224", - "SHA3_256", - "SHA3_384", - "SHA3_512", - "SHA224", - "SHA256", - "SHA384", - "SHA512", - "SHA512_224", - "SHA512_256", - "SHAKE128", - "SHAKE256", - "SM3", - "BLAKE2b", - "BLAKE2s", - "ExtendableOutputFunction", - "Hash", - "HashAlgorithm", - "HashContext", - "XOFHash", -] - - -class HashAlgorithm(metaclass=abc.ABCMeta): - @property - @abc.abstractmethod - def name(self) -> str: - """ - A string naming this algorithm (e.g. "sha256", "md5"). - """ - - @property - @abc.abstractmethod - def digest_size(self) -> int: - """ - The size of the resulting digest in bytes. - """ - - @property - @abc.abstractmethod - def block_size(self) -> int | None: - """ - The internal block size of the hash function, or None if the hash - function does not use blocks internally (e.g. SHA3). - """ - - -class HashContext(metaclass=abc.ABCMeta): - @property - @abc.abstractmethod - def algorithm(self) -> HashAlgorithm: - """ - A HashAlgorithm that will be used by this context. - """ - - @abc.abstractmethod - def update(self, data: Buffer) -> None: - """ - Processes the provided bytes through the hash. - """ - - @abc.abstractmethod - def finalize(self) -> bytes: - """ - Finalizes the hash context and returns the hash digest as bytes. - """ - - @abc.abstractmethod - def copy(self) -> HashContext: - """ - Return a HashContext that is a copy of the current context. - """ - - -Hash = rust_openssl.hashes.Hash -HashContext.register(Hash) - -XOFHash = rust_openssl.hashes.XOFHash - - -class ExtendableOutputFunction(metaclass=abc.ABCMeta): - """ - An interface for extendable output functions. - """ - - -class SHA1(HashAlgorithm): - name = "sha1" - digest_size = 20 - block_size = 64 - - -class SHA512_224(HashAlgorithm): # noqa: N801 - name = "sha512-224" - digest_size = 28 - block_size = 128 - - -class SHA512_256(HashAlgorithm): # noqa: N801 - name = "sha512-256" - digest_size = 32 - block_size = 128 - - -class SHA224(HashAlgorithm): - name = "sha224" - digest_size = 28 - block_size = 64 - - -class SHA256(HashAlgorithm): - name = "sha256" - digest_size = 32 - block_size = 64 - - -class SHA384(HashAlgorithm): - name = "sha384" - digest_size = 48 - block_size = 128 - - -class SHA512(HashAlgorithm): - name = "sha512" - digest_size = 64 - block_size = 128 - - -class SHA3_224(HashAlgorithm): # noqa: N801 - name = "sha3-224" - digest_size = 28 - block_size = None - - -class SHA3_256(HashAlgorithm): # noqa: N801 - name = "sha3-256" - digest_size = 32 - block_size = None - - -class SHA3_384(HashAlgorithm): # noqa: N801 - name = "sha3-384" - digest_size = 48 - block_size = None - - -class SHA3_512(HashAlgorithm): # noqa: N801 - name = "sha3-512" - digest_size = 64 - block_size = None - - -class SHAKE128(HashAlgorithm, ExtendableOutputFunction): - name = "shake128" - block_size = None - - def __init__(self, digest_size: int): - if not isinstance(digest_size, int): - raise TypeError("digest_size must be an integer") - - if digest_size < 1: - raise ValueError("digest_size must be a positive integer") - - self._digest_size = digest_size - - @property - def digest_size(self) -> int: - return self._digest_size - - -class SHAKE256(HashAlgorithm, ExtendableOutputFunction): - name = "shake256" - block_size = None - - def __init__(self, digest_size: int): - if not isinstance(digest_size, int): - raise TypeError("digest_size must be an integer") - - if digest_size < 1: - raise ValueError("digest_size must be a positive integer") - - self._digest_size = digest_size - - @property - def digest_size(self) -> int: - return self._digest_size - - -class MD5(HashAlgorithm): - name = "md5" - digest_size = 16 - block_size = 64 - - -class BLAKE2b(HashAlgorithm): - name = "blake2b" - _max_digest_size = 64 - _min_digest_size = 1 - block_size = 128 - - def __init__(self, digest_size: int): - if digest_size != 64: - raise ValueError("Digest size must be 64") - - self._digest_size = digest_size - - @property - def digest_size(self) -> int: - return self._digest_size - - -class BLAKE2s(HashAlgorithm): - name = "blake2s" - block_size = 64 - _max_digest_size = 32 - _min_digest_size = 1 - - def __init__(self, digest_size: int): - if digest_size != 32: - raise ValueError("Digest size must be 32") - - self._digest_size = digest_size - - @property - def digest_size(self) -> int: - return self._digest_size - - -class SM3(HashAlgorithm): - name = "sm3" - digest_size = 32 - block_size = 64 diff --git a/venv/lib/python3.9/site-packages/cryptography/hazmat/primitives/hmac.py b/venv/lib/python3.9/site-packages/cryptography/hazmat/primitives/hmac.py deleted file mode 100644 index a9442d5..0000000 --- a/venv/lib/python3.9/site-packages/cryptography/hazmat/primitives/hmac.py +++ /dev/null @@ -1,13 +0,0 @@ -# This file is dual licensed under the terms of the Apache License, Version -# 2.0, and the BSD License. See the LICENSE file in the root of this repository -# for complete details. - -from __future__ import annotations - -from cryptography.hazmat.bindings._rust import openssl as rust_openssl -from cryptography.hazmat.primitives import hashes - -__all__ = ["HMAC"] - -HMAC = rust_openssl.hmac.HMAC -hashes.HashContext.register(HMAC) diff --git a/venv/lib/python3.9/site-packages/cryptography/hazmat/primitives/hpke.py b/venv/lib/python3.9/site-packages/cryptography/hazmat/primitives/hpke.py deleted file mode 100644 index c802808..0000000 --- a/venv/lib/python3.9/site-packages/cryptography/hazmat/primitives/hpke.py +++ /dev/null @@ -1,27 +0,0 @@ -# This file is dual licensed under the terms of the Apache License, Version -# 2.0, and the BSD License. See the LICENSE file in the root of this repository -# for complete details. - -from __future__ import annotations - -from cryptography.hazmat.bindings._rust import openssl as rust_openssl - -AEAD = rust_openssl.hpke.AEAD -KDF = rust_openssl.hpke.KDF -KEM = rust_openssl.hpke.KEM -MLKEM768X25519PrivateKey = rust_openssl.hpke.MLKEM768X25519PrivateKey -MLKEM768X25519PublicKey = rust_openssl.hpke.MLKEM768X25519PublicKey -MLKEM1024P384PrivateKey = rust_openssl.hpke.MLKEM1024P384PrivateKey -MLKEM1024P384PublicKey = rust_openssl.hpke.MLKEM1024P384PublicKey -Suite = rust_openssl.hpke.Suite - -__all__ = [ - "AEAD", - "KDF", - "KEM", - "MLKEM768X25519PrivateKey", - "MLKEM768X25519PublicKey", - "MLKEM1024P384PrivateKey", - "MLKEM1024P384PublicKey", - "Suite", -] diff --git a/venv/lib/python3.9/site-packages/cryptography/hazmat/primitives/kdf/__init__.py b/venv/lib/python3.9/site-packages/cryptography/hazmat/primitives/kdf/__init__.py deleted file mode 100644 index 26c45bd..0000000 --- a/venv/lib/python3.9/site-packages/cryptography/hazmat/primitives/kdf/__init__.py +++ /dev/null @@ -1,32 +0,0 @@ -# This file is dual licensed under the terms of the Apache License, Version -# 2.0, and the BSD License. See the LICENSE file in the root of this repository -# for complete details. - -from __future__ import annotations - -import abc - -from cryptography.utils import Buffer - - -class KeyDerivationFunction(metaclass=abc.ABCMeta): - @abc.abstractmethod - def derive(self, key_material: bytes) -> bytes: - """ - Deterministically generates and returns a new key based on the existing - key material. - """ - - @abc.abstractmethod - def derive_into(self, key_material: bytes, buffer: Buffer) -> None: - """ - Deterministically generates a new key based on the existing key - material and stores it in the provided buffer. - """ - - @abc.abstractmethod - def verify(self, key_material: bytes, expected_key: bytes) -> None: - """ - Checks whether the key generated by the key material matches the - expected derived key. Raises an exception if they do not match. - """ diff --git a/venv/lib/python3.9/site-packages/cryptography/hazmat/primitives/kdf/argon2.py b/venv/lib/python3.9/site-packages/cryptography/hazmat/primitives/kdf/argon2.py deleted file mode 100644 index 03e84d4..0000000 --- a/venv/lib/python3.9/site-packages/cryptography/hazmat/primitives/kdf/argon2.py +++ /dev/null @@ -1,17 +0,0 @@ -# This file is dual licensed under the terms of the Apache License, Version -# 2.0, and the BSD License. See the LICENSE file in the root of this repository -# for complete details. - -from __future__ import annotations - -from cryptography.hazmat.bindings._rust import openssl as rust_openssl -from cryptography.hazmat.primitives.kdf import KeyDerivationFunction - -Argon2d = rust_openssl.kdf.Argon2d -Argon2i = rust_openssl.kdf.Argon2i -Argon2id = rust_openssl.kdf.Argon2id -KeyDerivationFunction.register(Argon2d) -KeyDerivationFunction.register(Argon2i) -KeyDerivationFunction.register(Argon2id) - -__all__ = ["Argon2d", "Argon2i", "Argon2id"] diff --git a/venv/lib/python3.9/site-packages/cryptography/hazmat/primitives/kdf/concatkdf.py b/venv/lib/python3.9/site-packages/cryptography/hazmat/primitives/kdf/concatkdf.py deleted file mode 100644 index 398dc5d..0000000 --- a/venv/lib/python3.9/site-packages/cryptography/hazmat/primitives/kdf/concatkdf.py +++ /dev/null @@ -1,16 +0,0 @@ -# This file is dual licensed under the terms of the Apache License, Version -# 2.0, and the BSD License. See the LICENSE file in the root of this repository -# for complete details. - -from __future__ import annotations - -from cryptography.hazmat.bindings._rust import openssl as rust_openssl -from cryptography.hazmat.primitives.kdf import KeyDerivationFunction - -ConcatKDFHash = rust_openssl.kdf.ConcatKDFHash -ConcatKDFHMAC = rust_openssl.kdf.ConcatKDFHMAC - -KeyDerivationFunction.register(ConcatKDFHash) -KeyDerivationFunction.register(ConcatKDFHMAC) - -__all__ = ["ConcatKDFHMAC", "ConcatKDFHash"] diff --git a/venv/lib/python3.9/site-packages/cryptography/hazmat/primitives/kdf/hkdf.py b/venv/lib/python3.9/site-packages/cryptography/hazmat/primitives/kdf/hkdf.py deleted file mode 100644 index 1e162d9..0000000 --- a/venv/lib/python3.9/site-packages/cryptography/hazmat/primitives/kdf/hkdf.py +++ /dev/null @@ -1,16 +0,0 @@ -# This file is dual licensed under the terms of the Apache License, Version -# 2.0, and the BSD License. See the LICENSE file in the root of this repository -# for complete details. - -from __future__ import annotations - -from cryptography.hazmat.bindings._rust import openssl as rust_openssl -from cryptography.hazmat.primitives.kdf import KeyDerivationFunction - -HKDF = rust_openssl.kdf.HKDF -HKDFExpand = rust_openssl.kdf.HKDFExpand - -KeyDerivationFunction.register(HKDF) -KeyDerivationFunction.register(HKDFExpand) - -__all__ = ["HKDF", "HKDFExpand"] diff --git a/venv/lib/python3.9/site-packages/cryptography/hazmat/primitives/kdf/kbkdf.py b/venv/lib/python3.9/site-packages/cryptography/hazmat/primitives/kdf/kbkdf.py deleted file mode 100644 index e559df8..0000000 --- a/venv/lib/python3.9/site-packages/cryptography/hazmat/primitives/kdf/kbkdf.py +++ /dev/null @@ -1,26 +0,0 @@ -# This file is dual licensed under the terms of the Apache License, Version -# 2.0, and the BSD License. See the LICENSE file in the root of this repository -# for complete details. - -from __future__ import annotations - -from cryptography import utils -from cryptography.hazmat.bindings._rust import openssl as rust_openssl -from cryptography.hazmat.primitives.kdf import KeyDerivationFunction - - -class Mode(utils.Enum): - CounterMode = "ctr" - - -class CounterLocation(utils.Enum): - BeforeFixed = "before_fixed" - AfterFixed = "after_fixed" - MiddleFixed = "middle_fixed" - - -KBKDFHMAC = rust_openssl.kdf.KBKDFHMAC -KeyDerivationFunction.register(KBKDFHMAC) - -KBKDFCMAC = rust_openssl.kdf.KBKDFCMAC -KeyDerivationFunction.register(KBKDFCMAC) diff --git a/venv/lib/python3.9/site-packages/cryptography/hazmat/primitives/kdf/pbkdf2.py b/venv/lib/python3.9/site-packages/cryptography/hazmat/primitives/kdf/pbkdf2.py deleted file mode 100644 index 771d80d..0000000 --- a/venv/lib/python3.9/site-packages/cryptography/hazmat/primitives/kdf/pbkdf2.py +++ /dev/null @@ -1,13 +0,0 @@ -# This file is dual licensed under the terms of the Apache License, Version -# 2.0, and the BSD License. See the LICENSE file in the root of this repository -# for complete details. - -from __future__ import annotations - -from cryptography.hazmat.bindings._rust import openssl as rust_openssl -from cryptography.hazmat.primitives.kdf import KeyDerivationFunction - -PBKDF2HMAC = rust_openssl.kdf.PBKDF2HMAC -KeyDerivationFunction.register(PBKDF2HMAC) - -__all__ = ["PBKDF2HMAC"] diff --git a/venv/lib/python3.9/site-packages/cryptography/hazmat/primitives/kdf/scrypt.py b/venv/lib/python3.9/site-packages/cryptography/hazmat/primitives/kdf/scrypt.py deleted file mode 100644 index f791cee..0000000 --- a/venv/lib/python3.9/site-packages/cryptography/hazmat/primitives/kdf/scrypt.py +++ /dev/null @@ -1,19 +0,0 @@ -# This file is dual licensed under the terms of the Apache License, Version -# 2.0, and the BSD License. See the LICENSE file in the root of this repository -# for complete details. - -from __future__ import annotations - -import sys - -from cryptography.hazmat.bindings._rust import openssl as rust_openssl -from cryptography.hazmat.primitives.kdf import KeyDerivationFunction - -# This is used by the scrypt tests to skip tests that require more memory -# than the MEM_LIMIT -_MEM_LIMIT = sys.maxsize // 2 - -Scrypt = rust_openssl.kdf.Scrypt -KeyDerivationFunction.register(Scrypt) - -__all__ = ["Scrypt"] diff --git a/venv/lib/python3.9/site-packages/cryptography/hazmat/primitives/kdf/x963kdf.py b/venv/lib/python3.9/site-packages/cryptography/hazmat/primitives/kdf/x963kdf.py deleted file mode 100644 index 8c4e2d3..0000000 --- a/venv/lib/python3.9/site-packages/cryptography/hazmat/primitives/kdf/x963kdf.py +++ /dev/null @@ -1,13 +0,0 @@ -# This file is dual licensed under the terms of the Apache License, Version -# 2.0, and the BSD License. See the LICENSE file in the root of this repository -# for complete details. - -from __future__ import annotations - -from cryptography.hazmat.bindings._rust import openssl as rust_openssl -from cryptography.hazmat.primitives.kdf import KeyDerivationFunction - -X963KDF = rust_openssl.kdf.X963KDF -KeyDerivationFunction.register(X963KDF) - -__all__ = ["X963KDF"] diff --git a/venv/lib/python3.9/site-packages/cryptography/hazmat/primitives/keywrap.py b/venv/lib/python3.9/site-packages/cryptography/hazmat/primitives/keywrap.py deleted file mode 100644 index a3e56b9..0000000 --- a/venv/lib/python3.9/site-packages/cryptography/hazmat/primitives/keywrap.py +++ /dev/null @@ -1,180 +0,0 @@ -# This file is dual licensed under the terms of the Apache License, Version -# 2.0, and the BSD License. See the LICENSE file in the root of this repository -# for complete details. - -from __future__ import annotations - -import typing - -from cryptography.hazmat.primitives.ciphers import Cipher -from cryptography.hazmat.primitives.ciphers.algorithms import AES -from cryptography.hazmat.primitives.ciphers.modes import ECB -from cryptography.hazmat.primitives.constant_time import bytes_eq - - -def _wrap_core( - wrapping_key: bytes, - a: bytes, - r: list[bytes], -) -> bytes: - # RFC 3394 Key Wrap - 2.2.1 (index method) - encryptor = Cipher(AES(wrapping_key), ECB()).encryptor() - n = len(r) - for j in range(6): - for i in range(n): - # every encryption operation is a discrete 16 byte chunk (because - # AES has a 128-bit block size) and since we're using ECB it is - # safe to reuse the encryptor for the entire operation - b = encryptor.update(a + r[i]) - a = ( - int.from_bytes(b[:8], byteorder="big") ^ ((n * j) + i + 1) - ).to_bytes(length=8, byteorder="big") - r[i] = b[-8:] - - assert encryptor.finalize() == b"" - - return a + b"".join(r) - - -def aes_key_wrap( - wrapping_key: bytes, - key_to_wrap: bytes, - backend: typing.Any = None, -) -> bytes: - if len(wrapping_key) not in [16, 24, 32]: - raise ValueError("The wrapping key must be a valid AES key length") - - if len(key_to_wrap) < 16: - raise ValueError("The key to wrap must be at least 16 bytes") - - if len(key_to_wrap) % 8 != 0: - raise ValueError("The key to wrap must be a multiple of 8 bytes") - - a = b"\xa6\xa6\xa6\xa6\xa6\xa6\xa6\xa6" - r = [key_to_wrap[i : i + 8] for i in range(0, len(key_to_wrap), 8)] - return _wrap_core(wrapping_key, a, r) - - -def _unwrap_core( - wrapping_key: bytes, - a: bytes, - r: list[bytes], -) -> tuple[bytes, list[bytes]]: - # Implement RFC 3394 Key Unwrap - 2.2.2 (index method) - decryptor = Cipher(AES(wrapping_key), ECB()).decryptor() - n = len(r) - for j in reversed(range(6)): - for i in reversed(range(n)): - atr = ( - int.from_bytes(a, byteorder="big") ^ ((n * j) + i + 1) - ).to_bytes(length=8, byteorder="big") + r[i] - # every decryption operation is a discrete 16 byte chunk so - # it is safe to reuse the decryptor for the entire operation - b = decryptor.update(atr) - a = b[:8] - r[i] = b[-8:] - - assert decryptor.finalize() == b"" - return a, r - - -def aes_key_wrap_with_padding( - wrapping_key: bytes, - key_to_wrap: bytes, - backend: typing.Any = None, -) -> bytes: - if len(wrapping_key) not in [16, 24, 32]: - raise ValueError("The wrapping key must be a valid AES key length") - - if not key_to_wrap or len(key_to_wrap) > 2**32: - raise ValueError("key_to_wrap must be between 1 and 2^32 bytes") - - aiv = b"\xa6\x59\x59\xa6" + len(key_to_wrap).to_bytes( - length=4, byteorder="big" - ) - # pad the key to wrap if necessary - pad = (8 - (len(key_to_wrap) % 8)) % 8 - key_to_wrap = key_to_wrap + b"\x00" * pad - if len(key_to_wrap) == 8: - # RFC 5649 - 4.1 - exactly 8 octets after padding - encryptor = Cipher(AES(wrapping_key), ECB()).encryptor() - b = encryptor.update(aiv + key_to_wrap) - assert encryptor.finalize() == b"" - return b - else: - r = [key_to_wrap[i : i + 8] for i in range(0, len(key_to_wrap), 8)] - return _wrap_core(wrapping_key, aiv, r) - - -def aes_key_unwrap_with_padding( - wrapping_key: bytes, - wrapped_key: bytes, - backend: typing.Any = None, -) -> bytes: - if len(wrapped_key) < 16: - raise InvalidUnwrap("Must be at least 16 bytes") - - if len(wrapping_key) not in [16, 24, 32]: - raise ValueError("The wrapping key must be a valid AES key length") - - if len(wrapped_key) == 16: - # RFC 5649 - 4.2 - exactly two 64-bit blocks - decryptor = Cipher(AES(wrapping_key), ECB()).decryptor() - out = decryptor.update(wrapped_key) - assert decryptor.finalize() == b"" - a = out[:8] - data = out[8:] - n = 1 - else: - r = [wrapped_key[i : i + 8] for i in range(0, len(wrapped_key), 8)] - encrypted_aiv = r.pop(0) - n = len(r) - a, r = _unwrap_core(wrapping_key, encrypted_aiv, r) - data = b"".join(r) - - # 1) Check that MSB(32,A) = A65959A6. - # 2) Check that 8*(n-1) < LSB(32,A) <= 8*n. If so, let - # MLI = LSB(32,A). - # 3) Let b = (8*n)-MLI, and then check that the rightmost b octets of - # the output data are zero. - mli = int.from_bytes(a[4:], byteorder="big") - b = (8 * n) - mli - if ( - not bytes_eq(a[:4], b"\xa6\x59\x59\xa6") - or not 8 * (n - 1) < mli <= 8 * n - or (b != 0 and not bytes_eq(data[-b:], b"\x00" * b)) - ): - raise InvalidUnwrap() - - if b == 0: - return data - else: - return data[:-b] - - -def aes_key_unwrap( - wrapping_key: bytes, - wrapped_key: bytes, - backend: typing.Any = None, -) -> bytes: - if len(wrapped_key) < 24: - raise InvalidUnwrap("Must be at least 24 bytes") - - if len(wrapped_key) % 8 != 0: - raise InvalidUnwrap("The wrapped key must be a multiple of 8 bytes") - - if len(wrapping_key) not in [16, 24, 32]: - raise ValueError("The wrapping key must be a valid AES key length") - - aiv = b"\xa6\xa6\xa6\xa6\xa6\xa6\xa6\xa6" - r = [wrapped_key[i : i + 8] for i in range(0, len(wrapped_key), 8)] - a = r.pop(0) - a, r = _unwrap_core(wrapping_key, a, r) - if not bytes_eq(a, aiv): - raise InvalidUnwrap() - - return b"".join(r) - - -class InvalidUnwrap(Exception): - pass diff --git a/venv/lib/python3.9/site-packages/cryptography/hazmat/primitives/padding.py b/venv/lib/python3.9/site-packages/cryptography/hazmat/primitives/padding.py deleted file mode 100644 index f9cd1f1..0000000 --- a/venv/lib/python3.9/site-packages/cryptography/hazmat/primitives/padding.py +++ /dev/null @@ -1,69 +0,0 @@ -# This file is dual licensed under the terms of the Apache License, Version -# 2.0, and the BSD License. See the LICENSE file in the root of this repository -# for complete details. - -from __future__ import annotations - -import abc - -from cryptography import utils -from cryptography.hazmat.bindings._rust import ( - ANSIX923PaddingContext, - ANSIX923UnpaddingContext, - PKCS7PaddingContext, - PKCS7UnpaddingContext, -) - - -class PaddingContext(metaclass=abc.ABCMeta): - @abc.abstractmethod - def update(self, data: utils.Buffer) -> bytes: - """ - Pads the provided bytes and returns any available data as bytes. - """ - - @abc.abstractmethod - def finalize(self) -> bytes: - """ - Finalize the padding, returns bytes. - """ - - -def _byte_padding_check(block_size: int) -> None: - if not (0 <= block_size <= 2040): - raise ValueError("block_size must be in range(0, 2041).") - - if block_size % 8 != 0: - raise ValueError("block_size must be a multiple of 8.") - - -class PKCS7: - def __init__(self, block_size: int): - _byte_padding_check(block_size) - self.block_size = block_size - - def padder(self) -> PaddingContext: - return PKCS7PaddingContext(self.block_size) - - def unpadder(self) -> PaddingContext: - return PKCS7UnpaddingContext(self.block_size) - - -PaddingContext.register(PKCS7PaddingContext) -PaddingContext.register(PKCS7UnpaddingContext) - - -class ANSIX923: - def __init__(self, block_size: int): - _byte_padding_check(block_size) - self.block_size = block_size - - def padder(self) -> PaddingContext: - return ANSIX923PaddingContext(self.block_size) - - def unpadder(self) -> PaddingContext: - return ANSIX923UnpaddingContext(self.block_size) - - -PaddingContext.register(ANSIX923PaddingContext) -PaddingContext.register(ANSIX923UnpaddingContext) diff --git a/venv/lib/python3.9/site-packages/cryptography/hazmat/primitives/poly1305.py b/venv/lib/python3.9/site-packages/cryptography/hazmat/primitives/poly1305.py deleted file mode 100644 index 7f5a77a..0000000 --- a/venv/lib/python3.9/site-packages/cryptography/hazmat/primitives/poly1305.py +++ /dev/null @@ -1,11 +0,0 @@ -# This file is dual licensed under the terms of the Apache License, Version -# 2.0, and the BSD License. See the LICENSE file in the root of this repository -# for complete details. - -from __future__ import annotations - -from cryptography.hazmat.bindings._rust import openssl as rust_openssl - -__all__ = ["Poly1305"] - -Poly1305 = rust_openssl.poly1305.Poly1305 diff --git a/venv/lib/python3.9/site-packages/cryptography/hazmat/primitives/serialization/__init__.py b/venv/lib/python3.9/site-packages/cryptography/hazmat/primitives/serialization/__init__.py deleted file mode 100644 index 62283cc..0000000 --- a/venv/lib/python3.9/site-packages/cryptography/hazmat/primitives/serialization/__init__.py +++ /dev/null @@ -1,65 +0,0 @@ -# This file is dual licensed under the terms of the Apache License, Version -# 2.0, and the BSD License. See the LICENSE file in the root of this repository -# for complete details. - -from __future__ import annotations - -from cryptography.hazmat.primitives._serialization import ( - BestAvailableEncryption, - Encoding, - KeySerializationEncryption, - NoEncryption, - ParameterFormat, - PrivateFormat, - PublicFormat, - _KeySerializationEncryption, -) -from cryptography.hazmat.primitives.serialization.base import ( - load_der_parameters, - load_der_private_key, - load_der_public_key, - load_pem_parameters, - load_pem_private_key, - load_pem_public_key, -) -from cryptography.hazmat.primitives.serialization.ssh import ( - SSHCertificate, - SSHCertificateBuilder, - SSHCertificateType, - SSHCertPrivateKeyTypes, - SSHCertPublicKeyTypes, - SSHPrivateKeyTypes, - SSHPublicKeyTypes, - load_ssh_private_key, - load_ssh_public_identity, - load_ssh_public_key, - ssh_key_fingerprint, -) - -__all__ = [ - "BestAvailableEncryption", - "Encoding", - "KeySerializationEncryption", - "NoEncryption", - "ParameterFormat", - "PrivateFormat", - "PublicFormat", - "SSHCertPrivateKeyTypes", - "SSHCertPublicKeyTypes", - "SSHCertificate", - "SSHCertificateBuilder", - "SSHCertificateType", - "SSHPrivateKeyTypes", - "SSHPublicKeyTypes", - "_KeySerializationEncryption", - "load_der_parameters", - "load_der_private_key", - "load_der_public_key", - "load_pem_parameters", - "load_pem_private_key", - "load_pem_public_key", - "load_ssh_private_key", - "load_ssh_public_identity", - "load_ssh_public_key", - "ssh_key_fingerprint", -] diff --git a/venv/lib/python3.9/site-packages/cryptography/hazmat/primitives/serialization/base.py b/venv/lib/python3.9/site-packages/cryptography/hazmat/primitives/serialization/base.py deleted file mode 100644 index e7c998b..0000000 --- a/venv/lib/python3.9/site-packages/cryptography/hazmat/primitives/serialization/base.py +++ /dev/null @@ -1,14 +0,0 @@ -# This file is dual licensed under the terms of the Apache License, Version -# 2.0, and the BSD License. See the LICENSE file in the root of this repository -# for complete details. - -from cryptography.hazmat.bindings._rust import openssl as rust_openssl - -load_pem_private_key = rust_openssl.keys.load_pem_private_key -load_der_private_key = rust_openssl.keys.load_der_private_key - -load_pem_public_key = rust_openssl.keys.load_pem_public_key -load_der_public_key = rust_openssl.keys.load_der_public_key - -load_pem_parameters = rust_openssl.dh.from_pem_parameters -load_der_parameters = rust_openssl.dh.from_der_parameters diff --git a/venv/lib/python3.9/site-packages/cryptography/hazmat/primitives/serialization/pkcs12.py b/venv/lib/python3.9/site-packages/cryptography/hazmat/primitives/serialization/pkcs12.py deleted file mode 100644 index 58884ff..0000000 --- a/venv/lib/python3.9/site-packages/cryptography/hazmat/primitives/serialization/pkcs12.py +++ /dev/null @@ -1,176 +0,0 @@ -# This file is dual licensed under the terms of the Apache License, Version -# 2.0, and the BSD License. See the LICENSE file in the root of this repository -# for complete details. - -from __future__ import annotations - -import typing -from collections.abc import Iterable - -from cryptography import x509 -from cryptography.hazmat.bindings._rust import pkcs12 as rust_pkcs12 -from cryptography.hazmat.primitives import serialization -from cryptography.hazmat.primitives._serialization import PBES as PBES -from cryptography.hazmat.primitives.asymmetric import ( - dsa, - ec, - ed448, - ed25519, - rsa, -) -from cryptography.hazmat.primitives.asymmetric.types import PrivateKeyTypes - -__all__ = [ - "PBES", - "PKCS12Certificate", - "PKCS12KeyAndCertificates", - "PKCS12PrivateKeyTypes", - "load_key_and_certificates", - "load_pkcs12", - "serialize_java_truststore", - "serialize_key_and_certificates", -] - -PKCS12PrivateKeyTypes = typing.Union[ - rsa.RSAPrivateKey, - dsa.DSAPrivateKey, - ec.EllipticCurvePrivateKey, - ed25519.Ed25519PrivateKey, - ed448.Ed448PrivateKey, -] - - -PKCS12Certificate = rust_pkcs12.PKCS12Certificate - - -class PKCS12KeyAndCertificates: - def __init__( - self, - key: PrivateKeyTypes | None, - cert: PKCS12Certificate | None, - additional_certs: list[PKCS12Certificate], - ): - if key is not None and not isinstance( - key, - ( - rsa.RSAPrivateKey, - dsa.DSAPrivateKey, - ec.EllipticCurvePrivateKey, - ed25519.Ed25519PrivateKey, - ed448.Ed448PrivateKey, - ), - ): - raise TypeError( - "Key must be RSA, DSA, EllipticCurve, ED25519, or ED448" - " private key, or None." - ) - if cert is not None and not isinstance(cert, PKCS12Certificate): - raise TypeError("cert must be a PKCS12Certificate object or None") - if not all( - isinstance(add_cert, PKCS12Certificate) - for add_cert in additional_certs - ): - raise TypeError( - "all values in additional_certs must be PKCS12Certificate" - " objects" - ) - self._key = key - self._cert = cert - self._additional_certs = additional_certs - - @property - def key(self) -> PrivateKeyTypes | None: - return self._key - - @property - def cert(self) -> PKCS12Certificate | None: - return self._cert - - @property - def additional_certs(self) -> list[PKCS12Certificate]: - return self._additional_certs - - def __eq__(self, other: object) -> bool: - if not isinstance(other, PKCS12KeyAndCertificates): - return NotImplemented - - return ( - self.key == other.key - and self.cert == other.cert - and self.additional_certs == other.additional_certs - ) - - def __hash__(self) -> int: - return hash((self.key, self.cert, tuple(self.additional_certs))) - - def __repr__(self) -> str: - fmt = ( - "" - ) - return fmt.format(self.key, self.cert, self.additional_certs) - - -load_key_and_certificates = rust_pkcs12.load_key_and_certificates -load_pkcs12 = rust_pkcs12.load_pkcs12 - - -_PKCS12CATypes = typing.Union[ - x509.Certificate, - PKCS12Certificate, -] - - -def serialize_java_truststore( - certs: Iterable[PKCS12Certificate], - encryption_algorithm: serialization.KeySerializationEncryption, -) -> bytes: - if not certs: - raise ValueError("You must supply at least one cert") - - if not isinstance( - encryption_algorithm, serialization.KeySerializationEncryption - ): - raise TypeError( - "Key encryption algorithm must be a " - "KeySerializationEncryption instance" - ) - - return rust_pkcs12.serialize_java_truststore(certs, encryption_algorithm) - - -def serialize_key_and_certificates( - name: bytes | None, - key: PKCS12PrivateKeyTypes | None, - cert: x509.Certificate | None, - cas: Iterable[_PKCS12CATypes] | None, - encryption_algorithm: serialization.KeySerializationEncryption, -) -> bytes: - if key is not None and not isinstance( - key, - ( - rsa.RSAPrivateKey, - dsa.DSAPrivateKey, - ec.EllipticCurvePrivateKey, - ed25519.Ed25519PrivateKey, - ed448.Ed448PrivateKey, - ), - ): - raise TypeError( - "Key must be RSA, DSA, EllipticCurve, ED25519, or ED448" - " private key, or None." - ) - - if not isinstance( - encryption_algorithm, serialization.KeySerializationEncryption - ): - raise TypeError( - "Key encryption algorithm must be a " - "KeySerializationEncryption instance" - ) - - if key is None and cert is None and not cas: - raise ValueError("You must supply at least one of key, cert, or cas") - - return rust_pkcs12.serialize_key_and_certificates( - name, key, cert, cas, encryption_algorithm - ) diff --git a/venv/lib/python3.9/site-packages/cryptography/hazmat/primitives/serialization/pkcs7.py b/venv/lib/python3.9/site-packages/cryptography/hazmat/primitives/serialization/pkcs7.py deleted file mode 100644 index 4fac500..0000000 --- a/venv/lib/python3.9/site-packages/cryptography/hazmat/primitives/serialization/pkcs7.py +++ /dev/null @@ -1,412 +0,0 @@ -# This file is dual licensed under the terms of the Apache License, Version -# 2.0, and the BSD License. See the LICENSE file in the root of this repository -# for complete details. - -from __future__ import annotations - -import email.base64mime -import email.generator -import email.message -import email.policy -import io -import typing -from collections.abc import Iterable - -from cryptography import utils, x509 -from cryptography.exceptions import UnsupportedAlgorithm, _Reasons -from cryptography.hazmat.bindings._rust import pkcs7 as rust_pkcs7 -from cryptography.hazmat.primitives import hashes, serialization -from cryptography.hazmat.primitives.asymmetric import ec, padding, rsa -from cryptography.hazmat.primitives.ciphers import ( - algorithms, -) -from cryptography.utils import _check_byteslike - -load_pem_pkcs7_certificates = rust_pkcs7.load_pem_pkcs7_certificates - -load_der_pkcs7_certificates = rust_pkcs7.load_der_pkcs7_certificates - -serialize_certificates = rust_pkcs7.serialize_certificates - -PKCS7HashTypes = typing.Union[ - hashes.SHA224, - hashes.SHA256, - hashes.SHA384, - hashes.SHA512, -] - -PKCS7PrivateKeyTypes = typing.Union[ - rsa.RSAPrivateKey, ec.EllipticCurvePrivateKey -] - -ContentEncryptionAlgorithm = typing.Union[ - typing.Type[algorithms.AES128], typing.Type[algorithms.AES256] -] - - -class PKCS7Options(utils.Enum): - Text = "Add text/plain MIME type" - Binary = "Don't translate input data into canonical MIME format" - DetachedSignature = "Don't embed data in the PKCS7 structure" - NoCapabilities = "Don't embed SMIME capabilities" - NoAttributes = "Don't embed authenticatedAttributes" - NoCerts = "Don't embed signer certificate" - - -class PKCS7SignatureBuilder: - def __init__( - self, - data: utils.Buffer | None = None, - signers: list[ - tuple[ - x509.Certificate, - PKCS7PrivateKeyTypes, - PKCS7HashTypes, - padding.PSS | padding.PKCS1v15 | None, - ] - ] = [], - additional_certs: list[x509.Certificate] = [], - ): - self._data = data - self._signers = signers - self._additional_certs = additional_certs - - def set_data(self, data: utils.Buffer) -> PKCS7SignatureBuilder: - _check_byteslike("data", data) - if self._data is not None: - raise ValueError("data may only be set once") - - return PKCS7SignatureBuilder(data, self._signers) - - def add_signer( - self, - certificate: x509.Certificate, - private_key: PKCS7PrivateKeyTypes, - hash_algorithm: PKCS7HashTypes, - *, - rsa_padding: padding.PSS | padding.PKCS1v15 | None = None, - ) -> PKCS7SignatureBuilder: - if not isinstance( - hash_algorithm, - ( - hashes.SHA224, - hashes.SHA256, - hashes.SHA384, - hashes.SHA512, - ), - ): - raise TypeError( - "hash_algorithm must be one of hashes.SHA224, " - "SHA256, SHA384, or SHA512" - ) - if not isinstance(certificate, x509.Certificate): - raise TypeError("certificate must be a x509.Certificate") - - if not isinstance( - private_key, (rsa.RSAPrivateKey, ec.EllipticCurvePrivateKey) - ): - raise TypeError("Only RSA & EC keys are supported at this time.") - - if rsa_padding is not None: - if not isinstance(rsa_padding, (padding.PSS, padding.PKCS1v15)): - raise TypeError("Padding must be PSS or PKCS1v15") - if not isinstance(private_key, rsa.RSAPrivateKey): - raise TypeError("Padding is only supported for RSA keys") - - return PKCS7SignatureBuilder( - self._data, - [ - *self._signers, - (certificate, private_key, hash_algorithm, rsa_padding), - ], - ) - - def add_certificate( - self, certificate: x509.Certificate - ) -> PKCS7SignatureBuilder: - if not isinstance(certificate, x509.Certificate): - raise TypeError("certificate must be a x509.Certificate") - - return PKCS7SignatureBuilder( - self._data, self._signers, [*self._additional_certs, certificate] - ) - - def sign( - self, - encoding: serialization.Encoding, - options: Iterable[PKCS7Options], - backend: typing.Any = None, - ) -> bytes: - if len(self._signers) == 0: - raise ValueError("Must have at least one signer") - if self._data is None: - raise ValueError("You must add data to sign") - options = list(options) - if not all(isinstance(x, PKCS7Options) for x in options): - raise ValueError("options must be from the PKCS7Options enum") - if encoding not in ( - serialization.Encoding.PEM, - serialization.Encoding.DER, - serialization.Encoding.SMIME, - ): - raise ValueError( - "Must be PEM, DER, or SMIME from the Encoding enum" - ) - - # Text is a meaningless option unless it is accompanied by - # DetachedSignature - if ( - PKCS7Options.Text in options - and PKCS7Options.DetachedSignature not in options - ): - raise ValueError( - "When passing the Text option you must also pass " - "DetachedSignature" - ) - - if PKCS7Options.Text in options and encoding in ( - serialization.Encoding.DER, - serialization.Encoding.PEM, - ): - raise ValueError( - "The Text option is only available for SMIME serialization" - ) - - # No attributes implies no capabilities so we'll error if you try to - # pass both. - if ( - PKCS7Options.NoAttributes in options - and PKCS7Options.NoCapabilities in options - ): - raise ValueError( - "NoAttributes is a superset of NoCapabilities. Do not pass " - "both values." - ) - - return rust_pkcs7.sign_and_serialize(self, encoding, options) - - -class PKCS7EnvelopeBuilder: - def __init__( - self, - *, - _data: bytes | None = None, - _recipients: list[x509.Certificate] | None = None, - _content_encryption_algorithm: ContentEncryptionAlgorithm - | None = None, - ): - from cryptography.hazmat.backends.openssl.backend import ( - backend as ossl, - ) - - if not ossl.rsa_encryption_supported(padding=padding.PKCS1v15()): - raise UnsupportedAlgorithm( - "RSA with PKCS1 v1.5 padding is not supported by this version" - " of OpenSSL.", - _Reasons.UNSUPPORTED_PADDING, - ) - self._data = _data - self._recipients = _recipients if _recipients is not None else [] - self._content_encryption_algorithm = _content_encryption_algorithm - - def set_data(self, data: bytes) -> PKCS7EnvelopeBuilder: - _check_byteslike("data", data) - if self._data is not None: - raise ValueError("data may only be set once") - - return PKCS7EnvelopeBuilder( - _data=data, - _recipients=self._recipients, - _content_encryption_algorithm=self._content_encryption_algorithm, - ) - - def add_recipient( - self, - certificate: x509.Certificate, - ) -> PKCS7EnvelopeBuilder: - if not isinstance(certificate, x509.Certificate): - raise TypeError("certificate must be a x509.Certificate") - - if not isinstance(certificate.public_key(), rsa.RSAPublicKey): - raise TypeError("Only RSA keys are supported at this time.") - - return PKCS7EnvelopeBuilder( - _data=self._data, - _recipients=[ - *self._recipients, - certificate, - ], - _content_encryption_algorithm=self._content_encryption_algorithm, - ) - - def set_content_encryption_algorithm( - self, content_encryption_algorithm: ContentEncryptionAlgorithm - ) -> PKCS7EnvelopeBuilder: - if self._content_encryption_algorithm is not None: - raise ValueError("Content encryption algo may only be set once") - if content_encryption_algorithm not in { - algorithms.AES128, - algorithms.AES256, - }: - raise TypeError("Only AES128 and AES256 are supported") - - return PKCS7EnvelopeBuilder( - _data=self._data, - _recipients=self._recipients, - _content_encryption_algorithm=content_encryption_algorithm, - ) - - def encrypt( - self, - encoding: serialization.Encoding, - options: Iterable[PKCS7Options], - ) -> bytes: - if len(self._recipients) == 0: - raise ValueError("Must have at least one recipient") - if self._data is None: - raise ValueError("You must add data to encrypt") - - # The default content encryption algorithm is AES-128-CBC, which the - # S/MIME v3.2 RFC specifies as MUST support (https://datatracker.ietf.org/doc/html/rfc5751#section-2.7) - # however rest of S/MIME v3.2 is not currently supported - content_encryption_algorithm = ( - self._content_encryption_algorithm or algorithms.AES128 - ) - - options = list(options) - if not all(isinstance(x, PKCS7Options) for x in options): - raise ValueError("options must be from the PKCS7Options enum") - if encoding not in ( - serialization.Encoding.PEM, - serialization.Encoding.DER, - serialization.Encoding.SMIME, - ): - raise ValueError( - "Must be PEM, DER, or SMIME from the Encoding enum" - ) - - # Only allow options that make sense for encryption - if any( - opt not in [PKCS7Options.Text, PKCS7Options.Binary] - for opt in options - ): - raise ValueError( - "Only the following options are supported for encryption: " - "Text, Binary" - ) - elif PKCS7Options.Text in options and PKCS7Options.Binary in options: - # OpenSSL accepts both options at the same time, but ignores Text. - # We fail defensively to avoid unexpected outputs. - raise ValueError( - "Cannot use Binary and Text options at the same time" - ) - - return rust_pkcs7.encrypt_and_serialize( - self, content_encryption_algorithm, encoding, options - ) - - -pkcs7_decrypt_der = rust_pkcs7.decrypt_der -pkcs7_decrypt_pem = rust_pkcs7.decrypt_pem -pkcs7_decrypt_smime = rust_pkcs7.decrypt_smime - - -def _smime_signed_encode( - data: bytes, signature: bytes, micalg: str, text_mode: bool -) -> bytes: - # This function works pretty hard to replicate what OpenSSL does - # precisely. For good and for ill. - - m = email.message.Message() - m.add_header("MIME-Version", "1.0") - m.add_header( - "Content-Type", - "multipart/signed", - protocol="application/x-pkcs7-signature", - micalg=micalg, - ) - - m.preamble = "This is an S/MIME signed message\n" - - msg_part = OpenSSLMimePart() - msg_part.set_payload(data) - if text_mode: - msg_part.add_header("Content-Type", "text/plain") - m.attach(msg_part) - - sig_part = email.message.MIMEPart() - sig_part.add_header( - "Content-Type", "application/x-pkcs7-signature", name="smime.p7s" - ) - sig_part.add_header("Content-Transfer-Encoding", "base64") - sig_part.add_header( - "Content-Disposition", "attachment", filename="smime.p7s" - ) - sig_part.set_payload( - email.base64mime.body_encode(signature, maxlinelen=65) - ) - del sig_part["MIME-Version"] - m.attach(sig_part) - - fp = io.BytesIO() - g = email.generator.BytesGenerator( - fp, - maxheaderlen=0, - mangle_from_=False, - policy=m.policy.clone(linesep="\r\n"), - ) - g.flatten(m) - return fp.getvalue() - - -def _smime_enveloped_encode(data: bytes) -> bytes: - m = email.message.Message() - m.add_header("MIME-Version", "1.0") - m.add_header("Content-Disposition", "attachment", filename="smime.p7m") - m.add_header( - "Content-Type", - "application/pkcs7-mime", - smime_type="enveloped-data", - name="smime.p7m", - ) - m.add_header("Content-Transfer-Encoding", "base64") - - m.set_payload(email.base64mime.body_encode(data, maxlinelen=65)) - - return m.as_bytes(policy=m.policy.clone(linesep="\n", max_line_length=0)) - - -def _smime_enveloped_decode(data: bytes) -> bytes: - m = email.message_from_bytes(data) - if m.get_content_type() not in { - "application/x-pkcs7-mime", - "application/pkcs7-mime", - }: - raise ValueError("Not an S/MIME enveloped message") - return bytes(m.get_payload(decode=True)) - - -def _smime_remove_text_headers(data: bytes) -> bytes: - m = email.message_from_bytes(data) - # Using get() instead of get_content_type() since it has None as default, - # where the latter has "text/plain". Both methods are case-insensitive. - content_type = m.get("content-type") - if content_type is None: - raise ValueError( - "Decrypted MIME data has no 'Content-Type' header. " - "Please remove the 'Text' option to parse it manually." - ) - if "text/plain" not in content_type: - raise ValueError( - f"Decrypted MIME data content type is '{content_type}', not " - "'text/plain'. Remove the 'Text' option to parse it manually." - ) - return bytes(m.get_payload(decode=True)) - - -class OpenSSLMimePart(email.message.MIMEPart): - # A MIMEPart subclass that replicates OpenSSL's behavior of not including - # a newline if there are no headers. - def _write_headers(self, generator) -> None: - if list(self.raw_items()): - generator._write_headers(self) diff --git a/venv/lib/python3.9/site-packages/cryptography/hazmat/primitives/serialization/ssh.py b/venv/lib/python3.9/site-packages/cryptography/hazmat/primitives/serialization/ssh.py deleted file mode 100644 index 411113b..0000000 --- a/venv/lib/python3.9/site-packages/cryptography/hazmat/primitives/serialization/ssh.py +++ /dev/null @@ -1,1621 +0,0 @@ -# This file is dual licensed under the terms of the Apache License, Version -# 2.0, and the BSD License. See the LICENSE file in the root of this repository -# for complete details. - -from __future__ import annotations - -import binascii -import enum -import os -import re -import typing -import warnings -from base64 import encodebytes as _base64_encode -from dataclasses import dataclass - -from cryptography import utils -from cryptography.exceptions import UnsupportedAlgorithm -from cryptography.hazmat.primitives import hashes -from cryptography.hazmat.primitives.asymmetric import ( - dsa, - ec, - ed25519, - padding, - rsa, -) -from cryptography.hazmat.primitives.asymmetric import utils as asym_utils -from cryptography.hazmat.primitives.ciphers import ( - AEADDecryptionContext, - Cipher, - algorithms, - modes, -) -from cryptography.hazmat.primitives.serialization import ( - Encoding, - KeySerializationEncryption, - NoEncryption, - PrivateFormat, - PublicFormat, - _KeySerializationEncryption, -) - -try: - from bcrypt import kdf as _bcrypt_kdf - - _bcrypt_supported = True -except ImportError: - _bcrypt_supported = False - - def _bcrypt_kdf( - password: bytes, - salt: bytes, - desired_key_bytes: int, - rounds: int, - ignore_few_rounds: bool = False, - ) -> bytes: - raise UnsupportedAlgorithm("Need bcrypt module") - - -_SSH_ED25519 = b"ssh-ed25519" -_SSH_RSA = b"ssh-rsa" -_SSH_DSA = b"ssh-dss" -_ECDSA_NISTP256 = b"ecdsa-sha2-nistp256" -_ECDSA_NISTP384 = b"ecdsa-sha2-nistp384" -_ECDSA_NISTP521 = b"ecdsa-sha2-nistp521" -_CERT_SUFFIX = b"-cert-v01@openssh.com" - -# U2F application string suffixed pubkey -_SK_SSH_ED25519 = b"sk-ssh-ed25519@openssh.com" -_SK_SSH_ECDSA_NISTP256 = b"sk-ecdsa-sha2-nistp256@openssh.com" - -# These are not key types, only algorithms, so they cannot appear -# as a public key type -_SSH_RSA_SHA256 = b"rsa-sha2-256" -_SSH_RSA_SHA512 = b"rsa-sha2-512" - -_SSH_PUBKEY_RC = re.compile(rb"\A(\S+)[ \t]+(\S+)") -_SK_MAGIC = b"openssh-key-v1\0" -_SK_START = b"-----BEGIN OPENSSH PRIVATE KEY-----" -_SK_END = b"-----END OPENSSH PRIVATE KEY-----" -_BCRYPT = b"bcrypt" -_NONE = b"none" -_DEFAULT_CIPHER = b"aes256-ctr" -_DEFAULT_ROUNDS = 16 - -# re is only way to work on bytes-like data -_PEM_RC = re.compile(_SK_START + b"(.*?)" + _SK_END, re.DOTALL) - -# padding for max blocksize -_PADDING = memoryview(bytearray(range(1, 1 + 16))) - - -@dataclass -class _SSHCipher: - alg: type[algorithms.AES] - key_len: int - mode: type[modes.CTR] | type[modes.CBC] | type[modes.GCM] - block_len: int - iv_len: int - tag_len: int | None - is_aead: bool - - -# ciphers that are actually used in key wrapping -_SSH_CIPHERS: dict[bytes, _SSHCipher] = { - b"aes256-ctr": _SSHCipher( - alg=algorithms.AES, - key_len=32, - mode=modes.CTR, - block_len=16, - iv_len=16, - tag_len=None, - is_aead=False, - ), - b"aes256-cbc": _SSHCipher( - alg=algorithms.AES, - key_len=32, - mode=modes.CBC, - block_len=16, - iv_len=16, - tag_len=None, - is_aead=False, - ), - b"aes256-gcm@openssh.com": _SSHCipher( - alg=algorithms.AES, - key_len=32, - mode=modes.GCM, - block_len=16, - iv_len=12, - tag_len=16, - is_aead=True, - ), -} - -# map local curve name to key type -_ECDSA_KEY_TYPE = { - "secp256r1": _ECDSA_NISTP256, - "secp384r1": _ECDSA_NISTP384, - "secp521r1": _ECDSA_NISTP521, -} - - -def _get_ssh_key_type(key: SSHPrivateKeyTypes | SSHPublicKeyTypes) -> bytes: - if isinstance(key, ec.EllipticCurvePrivateKey): - key_type = _ecdsa_key_type(key.public_key()) - elif isinstance(key, ec.EllipticCurvePublicKey): - key_type = _ecdsa_key_type(key) - elif isinstance(key, (rsa.RSAPrivateKey, rsa.RSAPublicKey)): - key_type = _SSH_RSA - elif isinstance(key, (dsa.DSAPrivateKey, dsa.DSAPublicKey)): - key_type = _SSH_DSA - elif isinstance( - key, (ed25519.Ed25519PrivateKey, ed25519.Ed25519PublicKey) - ): - key_type = _SSH_ED25519 - else: - raise ValueError("Unsupported key type") - - return key_type - - -def _ecdsa_key_type(public_key: ec.EllipticCurvePublicKey) -> bytes: - """Return SSH key_type and curve_name for private key.""" - curve = public_key.curve - if curve.name not in _ECDSA_KEY_TYPE: - raise ValueError( - f"Unsupported curve for ssh private key: {curve.name!r}" - ) - return _ECDSA_KEY_TYPE[curve.name] - - -def _ssh_pem_encode( - data: utils.Buffer, - prefix: bytes = _SK_START + b"\n", - suffix: bytes = _SK_END + b"\n", -) -> bytes: - return b"".join([prefix, _base64_encode(data), suffix]) - - -def _check_block_size(data: utils.Buffer, block_len: int) -> None: - """Require data to be full blocks""" - if not data or len(data) % block_len != 0: - raise ValueError("Corrupt data: missing padding") - - -def _check_empty(data: utils.Buffer) -> None: - """All data should have been parsed.""" - if data: - raise ValueError("Corrupt data: unparsed data") - - -def _init_cipher( - ciphername: bytes, - password: bytes | None, - salt: bytes, - rounds: int, -) -> Cipher[modes.CBC | modes.CTR | modes.GCM]: - """Generate key + iv and return cipher.""" - if not password: - raise TypeError( - "Key is password-protected, but password was not provided." - ) - - ciph = _SSH_CIPHERS[ciphername] - seed = _bcrypt_kdf( - password, salt, ciph.key_len + ciph.iv_len, rounds, True - ) - return Cipher( - ciph.alg(seed[: ciph.key_len]), - ciph.mode(seed[ciph.key_len :]), - ) - - -def _get_u32(data: memoryview) -> tuple[int, memoryview]: - """Uint32""" - if len(data) < 4: - raise ValueError("Invalid data") - return int.from_bytes(data[:4], byteorder="big"), data[4:] - - -def _get_u64(data: memoryview) -> tuple[int, memoryview]: - """Uint64""" - if len(data) < 8: - raise ValueError("Invalid data") - return int.from_bytes(data[:8], byteorder="big"), data[8:] - - -def _get_sshstr(data: memoryview) -> tuple[memoryview, memoryview]: - """Bytes with u32 length prefix""" - n, data = _get_u32(data) - if n > len(data): - raise ValueError("Invalid data") - return data[:n], data[n:] - - -def _get_mpint(data: memoryview) -> tuple[int, memoryview]: - """Big integer.""" - val, data = _get_sshstr(data) - if val and val[0] > 0x7F: - raise ValueError("Invalid data") - return int.from_bytes(val, "big"), data - - -def _to_mpint(val: int) -> bytes: - """Storage format for signed bigint.""" - if val < 0: - raise ValueError("negative mpint not allowed") - if not val: - return b"" - nbytes = (val.bit_length() + 8) // 8 - return utils.int_to_bytes(val, nbytes) - - -class _FragList: - """Build recursive structure without data copy.""" - - flist: list[utils.Buffer] - - def __init__(self, init: list[utils.Buffer] | None = None) -> None: - self.flist = [] - if init: - self.flist.extend(init) - - def put_raw(self, val: utils.Buffer) -> None: - """Add plain bytes""" - self.flist.append(val) - - def put_u32(self, val: int) -> None: - """Big-endian uint32""" - self.flist.append(val.to_bytes(length=4, byteorder="big")) - - def put_u64(self, val: int) -> None: - """Big-endian uint64""" - self.flist.append(val.to_bytes(length=8, byteorder="big")) - - def put_sshstr(self, val: bytes | _FragList) -> None: - """Bytes prefixed with u32 length""" - if isinstance(val, (bytes, memoryview, bytearray)): - self.put_u32(len(val)) - self.flist.append(val) - else: - self.put_u32(val.size()) - self.flist.extend(val.flist) - - def put_mpint(self, val: int) -> None: - """Big-endian bigint prefixed with u32 length""" - self.put_sshstr(_to_mpint(val)) - - def size(self) -> int: - """Current number of bytes""" - return sum(map(len, self.flist)) - - def render(self, dstbuf: memoryview, pos: int = 0) -> int: - """Write into bytearray""" - for frag in self.flist: - flen = len(frag) - start, pos = pos, pos + flen - dstbuf[start:pos] = frag - return pos - - def tobytes(self) -> bytes: - """Return as bytes""" - buf = memoryview(bytearray(self.size())) - self.render(buf) - return buf.tobytes() - - -class _SSHFormatRSA: - """Format for RSA keys. - - Public: - mpint e, n - Private: - mpint n, e, d, iqmp, p, q - """ - - def get_public( - self, data: memoryview - ) -> tuple[tuple[int, int], memoryview]: - """RSA public fields""" - e, data = _get_mpint(data) - n, data = _get_mpint(data) - return (e, n), data - - def load_public( - self, data: memoryview - ) -> tuple[rsa.RSAPublicKey, memoryview]: - """Make RSA public key from data.""" - (e, n), data = self.get_public(data) - public_numbers = rsa.RSAPublicNumbers(e, n) - public_key = public_numbers.public_key() - return public_key, data - - def load_private( - self, data: memoryview, pubfields, unsafe_skip_rsa_key_validation: bool - ) -> tuple[rsa.RSAPrivateKey, memoryview]: - """Make RSA private key from data.""" - n, data = _get_mpint(data) - e, data = _get_mpint(data) - d, data = _get_mpint(data) - iqmp, data = _get_mpint(data) - p, data = _get_mpint(data) - q, data = _get_mpint(data) - - if (e, n) != pubfields: - raise ValueError("Corrupt data: rsa field mismatch") - dmp1 = rsa.rsa_crt_dmp1(d, p) - dmq1 = rsa.rsa_crt_dmq1(d, q) - public_numbers = rsa.RSAPublicNumbers(e, n) - private_numbers = rsa.RSAPrivateNumbers( - p, q, d, dmp1, dmq1, iqmp, public_numbers - ) - private_key = private_numbers.private_key( - unsafe_skip_rsa_key_validation=unsafe_skip_rsa_key_validation - ) - return private_key, data - - def encode_public( - self, public_key: rsa.RSAPublicKey, f_pub: _FragList - ) -> None: - """Write RSA public key""" - pubn = public_key.public_numbers() - f_pub.put_mpint(pubn.e) - f_pub.put_mpint(pubn.n) - - def encode_private( - self, private_key: rsa.RSAPrivateKey, f_priv: _FragList - ) -> None: - """Write RSA private key""" - private_numbers = private_key.private_numbers() - public_numbers = private_numbers.public_numbers - - f_priv.put_mpint(public_numbers.n) - f_priv.put_mpint(public_numbers.e) - - f_priv.put_mpint(private_numbers.d) - f_priv.put_mpint(private_numbers.iqmp) - f_priv.put_mpint(private_numbers.p) - f_priv.put_mpint(private_numbers.q) - - -class _SSHFormatDSA: - """Format for DSA keys. - - Public: - mpint p, q, g, y - Private: - mpint p, q, g, y, x - """ - - def get_public(self, data: memoryview) -> tuple[tuple, memoryview]: - """DSA public fields""" - p, data = _get_mpint(data) - q, data = _get_mpint(data) - g, data = _get_mpint(data) - y, data = _get_mpint(data) - return (p, q, g, y), data - - def load_public( - self, data: memoryview - ) -> tuple[dsa.DSAPublicKey, memoryview]: - """Make DSA public key from data.""" - (p, q, g, y), data = self.get_public(data) - parameter_numbers = dsa.DSAParameterNumbers(p, q, g) - public_numbers = dsa.DSAPublicNumbers(y, parameter_numbers) - self._validate(public_numbers) - public_key = public_numbers.public_key() - return public_key, data - - def load_private( - self, data: memoryview, pubfields, unsafe_skip_rsa_key_validation: bool - ) -> tuple[dsa.DSAPrivateKey, memoryview]: - """Make DSA private key from data.""" - (p, q, g, y), data = self.get_public(data) - x, data = _get_mpint(data) - - if (p, q, g, y) != pubfields: - raise ValueError("Corrupt data: dsa field mismatch") - parameter_numbers = dsa.DSAParameterNumbers(p, q, g) - public_numbers = dsa.DSAPublicNumbers(y, parameter_numbers) - self._validate(public_numbers) - private_numbers = dsa.DSAPrivateNumbers(x, public_numbers) - private_key = private_numbers.private_key() - return private_key, data - - def encode_public( - self, public_key: dsa.DSAPublicKey, f_pub: _FragList - ) -> None: - """Write DSA public key""" - public_numbers = public_key.public_numbers() - parameter_numbers = public_numbers.parameter_numbers - self._validate(public_numbers) - - f_pub.put_mpint(parameter_numbers.p) - f_pub.put_mpint(parameter_numbers.q) - f_pub.put_mpint(parameter_numbers.g) - f_pub.put_mpint(public_numbers.y) - - def encode_private( - self, private_key: dsa.DSAPrivateKey, f_priv: _FragList - ) -> None: - """Write DSA private key""" - self.encode_public(private_key.public_key(), f_priv) - f_priv.put_mpint(private_key.private_numbers().x) - - def _validate(self, public_numbers: dsa.DSAPublicNumbers) -> None: - parameter_numbers = public_numbers.parameter_numbers - if parameter_numbers.p.bit_length() != 1024: - raise ValueError("SSH supports only 1024 bit DSA keys") - - -class _SSHFormatECDSA: - """Format for ECDSA keys. - - Public: - str curve - bytes point - Private: - str curve - bytes point - mpint secret - """ - - def __init__(self, ssh_curve_name: bytes, curve: ec.EllipticCurve): - self.ssh_curve_name = ssh_curve_name - self.curve = curve - - def get_public( - self, data: memoryview - ) -> tuple[tuple[memoryview, memoryview], memoryview]: - """ECDSA public fields""" - curve, data = _get_sshstr(data) - point, data = _get_sshstr(data) - if curve != self.ssh_curve_name: - raise ValueError("Curve name mismatch") - if len(point) == 0: - raise ValueError("Invalid EC point: empty data") - if point[0] != 4: - raise NotImplementedError("Need uncompressed point") - return (curve, point), data - - def load_public( - self, data: memoryview - ) -> tuple[ec.EllipticCurvePublicKey, memoryview]: - """Make ECDSA public key from data.""" - (_, point), data = self.get_public(data) - public_key = ec.EllipticCurvePublicKey.from_encoded_point( - self.curve, point.tobytes() - ) - return public_key, data - - def load_private( - self, data: memoryview, pubfields, unsafe_skip_rsa_key_validation: bool - ) -> tuple[ec.EllipticCurvePrivateKey, memoryview]: - """Make ECDSA private key from data.""" - (curve_name, point), data = self.get_public(data) - secret, data = _get_mpint(data) - - if (curve_name, point) != pubfields: - raise ValueError("Corrupt data: ecdsa field mismatch") - private_key = ec.derive_private_key(secret, self.curve) - return private_key, data - - def encode_public( - self, public_key: ec.EllipticCurvePublicKey, f_pub: _FragList - ) -> None: - """Write ECDSA public key""" - point = public_key.public_bytes( - Encoding.X962, PublicFormat.UncompressedPoint - ) - f_pub.put_sshstr(self.ssh_curve_name) - f_pub.put_sshstr(point) - - def encode_private( - self, private_key: ec.EllipticCurvePrivateKey, f_priv: _FragList - ) -> None: - """Write ECDSA private key""" - public_key = private_key.public_key() - private_numbers = private_key.private_numbers() - - self.encode_public(public_key, f_priv) - f_priv.put_mpint(private_numbers.private_value) - - -class _SSHFormatEd25519: - """Format for Ed25519 keys. - - Public: - bytes point - Private: - bytes point - bytes secret_and_point - """ - - def get_public( - self, data: memoryview - ) -> tuple[tuple[memoryview], memoryview]: - """Ed25519 public fields""" - point, data = _get_sshstr(data) - return (point,), data - - def load_public( - self, data: memoryview - ) -> tuple[ed25519.Ed25519PublicKey, memoryview]: - """Make Ed25519 public key from data.""" - (point,), data = self.get_public(data) - public_key = ed25519.Ed25519PublicKey.from_public_bytes( - point.tobytes() - ) - return public_key, data - - def load_private( - self, data: memoryview, pubfields, unsafe_skip_rsa_key_validation: bool - ) -> tuple[ed25519.Ed25519PrivateKey, memoryview]: - """Make Ed25519 private key from data.""" - (point,), data = self.get_public(data) - keypair, data = _get_sshstr(data) - - secret = keypair[:32] - point2 = keypair[32:] - if point != point2 or (point,) != pubfields: - raise ValueError("Corrupt data: ed25519 field mismatch") - private_key = ed25519.Ed25519PrivateKey.from_private_bytes(secret) - return private_key, data - - def encode_public( - self, public_key: ed25519.Ed25519PublicKey, f_pub: _FragList - ) -> None: - """Write Ed25519 public key""" - raw_public_key = public_key.public_bytes( - Encoding.Raw, PublicFormat.Raw - ) - f_pub.put_sshstr(raw_public_key) - - def encode_private( - self, private_key: ed25519.Ed25519PrivateKey, f_priv: _FragList - ) -> None: - """Write Ed25519 private key""" - public_key = private_key.public_key() - raw_private_key = private_key.private_bytes( - Encoding.Raw, PrivateFormat.Raw, NoEncryption() - ) - raw_public_key = public_key.public_bytes( - Encoding.Raw, PublicFormat.Raw - ) - f_keypair = _FragList([raw_private_key, raw_public_key]) - - self.encode_public(public_key, f_priv) - f_priv.put_sshstr(f_keypair) - - -def load_application(data) -> tuple[memoryview, memoryview]: - """ - U2F application strings - """ - application, data = _get_sshstr(data) - if not application.tobytes().startswith(b"ssh:"): - raise ValueError( - "U2F application string does not start with b'ssh:' " - f"({application})" - ) - return application, data - - -class _SSHFormatSKEd25519: - """ - The format of a sk-ssh-ed25519@openssh.com public key is: - - string "sk-ssh-ed25519@openssh.com" - string public key - string application (user-specified, but typically "ssh:") - """ - - def load_public( - self, data: memoryview - ) -> tuple[ed25519.Ed25519PublicKey, memoryview]: - """Make Ed25519 public key from data.""" - public_key, data = _lookup_kformat(_SSH_ED25519).load_public(data) - _, data = load_application(data) - return public_key, data - - def get_public(self, data: memoryview) -> typing.NoReturn: - # Confusingly `get_public` is an entry point used by private key - # loading. - raise UnsupportedAlgorithm( - "sk-ssh-ed25519 private keys cannot be loaded" - ) - - -class _SSHFormatSKECDSA: - """ - The format of a sk-ecdsa-sha2-nistp256@openssh.com public key is: - - string "sk-ecdsa-sha2-nistp256@openssh.com" - string curve name - ec_point Q - string application (user-specified, but typically "ssh:") - """ - - def load_public( - self, data: memoryview - ) -> tuple[ec.EllipticCurvePublicKey, memoryview]: - """Make ECDSA public key from data.""" - public_key, data = _lookup_kformat(_ECDSA_NISTP256).load_public(data) - _, data = load_application(data) - return public_key, data - - def get_public(self, data: memoryview) -> typing.NoReturn: - # Confusingly `get_public` is an entry point used by private key - # loading. - raise UnsupportedAlgorithm( - "sk-ecdsa-sha2-nistp256 private keys cannot be loaded" - ) - - -_KEY_FORMATS = { - _SSH_RSA: _SSHFormatRSA(), - _SSH_DSA: _SSHFormatDSA(), - _SSH_ED25519: _SSHFormatEd25519(), - _ECDSA_NISTP256: _SSHFormatECDSA(b"nistp256", ec.SECP256R1()), - _ECDSA_NISTP384: _SSHFormatECDSA(b"nistp384", ec.SECP384R1()), - _ECDSA_NISTP521: _SSHFormatECDSA(b"nistp521", ec.SECP521R1()), - _SK_SSH_ED25519: _SSHFormatSKEd25519(), - _SK_SSH_ECDSA_NISTP256: _SSHFormatSKECDSA(), -} - - -def _lookup_kformat(key_type: utils.Buffer): - """Return valid format or throw error""" - if not isinstance(key_type, bytes): - key_type = memoryview(key_type).tobytes() - if key_type in _KEY_FORMATS: - return _KEY_FORMATS[key_type] - raise UnsupportedAlgorithm(f"Unsupported key type: {key_type!r}") - - -SSHPrivateKeyTypes = typing.Union[ - ec.EllipticCurvePrivateKey, - rsa.RSAPrivateKey, - dsa.DSAPrivateKey, - ed25519.Ed25519PrivateKey, -] - - -def load_ssh_private_key( - data: utils.Buffer, - password: bytes | None, - backend: typing.Any = None, - *, - unsafe_skip_rsa_key_validation: bool = False, -) -> SSHPrivateKeyTypes: - """Load private key from OpenSSH custom encoding.""" - utils._check_byteslike("data", data) - if password is not None: - utils._check_bytes("password", password) - - m = _PEM_RC.search(data) - if not m: - raise ValueError("Not OpenSSH private key format") - p1 = m.start(1) - p2 = m.end(1) - data = binascii.a2b_base64(memoryview(data)[p1:p2]) - if not data.startswith(_SK_MAGIC): - raise ValueError("Not OpenSSH private key format") - data = memoryview(data)[len(_SK_MAGIC) :] - - # parse header - ciphername, data = _get_sshstr(data) - kdfname, data = _get_sshstr(data) - kdfoptions, data = _get_sshstr(data) - nkeys, data = _get_u32(data) - if nkeys != 1: - raise ValueError("Only one key supported") - - # load public key data - pubdata, data = _get_sshstr(data) - pub_key_type, pubdata = _get_sshstr(pubdata) - kformat = _lookup_kformat(pub_key_type) - pubfields, pubdata = kformat.get_public(pubdata) - _check_empty(pubdata) - - if ciphername != _NONE or kdfname != _NONE: - ciphername_bytes = ciphername.tobytes() - if ciphername_bytes not in _SSH_CIPHERS: - raise UnsupportedAlgorithm( - f"Unsupported cipher: {ciphername_bytes!r}" - ) - if kdfname != _BCRYPT: - raise UnsupportedAlgorithm(f"Unsupported KDF: {kdfname!r}") - blklen = _SSH_CIPHERS[ciphername_bytes].block_len - tag_len = _SSH_CIPHERS[ciphername_bytes].tag_len - # load secret data - edata, data = _get_sshstr(data) - # see https://bugzilla.mindrot.org/show_bug.cgi?id=3553 for - # information about how OpenSSH handles AEAD tags - if _SSH_CIPHERS[ciphername_bytes].is_aead: - tag = bytes(data) - if len(tag) != tag_len: - raise ValueError("Corrupt data: invalid tag length for cipher") - else: - _check_empty(data) - _check_block_size(edata, blklen) - salt, kbuf = _get_sshstr(kdfoptions) - rounds, kbuf = _get_u32(kbuf) - _check_empty(kbuf) - ciph = _init_cipher(ciphername_bytes, password, salt.tobytes(), rounds) - dec = ciph.decryptor() - edata = memoryview(dec.update(edata)) - if _SSH_CIPHERS[ciphername_bytes].is_aead: - assert isinstance(dec, AEADDecryptionContext) - _check_empty(dec.finalize_with_tag(tag)) - else: - # _check_block_size requires data to be a full block so there - # should be no output from finalize - _check_empty(dec.finalize()) - else: - if password: - raise TypeError( - "Password was given but private key is not encrypted." - ) - # load secret data - edata, data = _get_sshstr(data) - _check_empty(data) - blklen = 8 - _check_block_size(edata, blklen) - ck1, edata = _get_u32(edata) - ck2, edata = _get_u32(edata) - if ck1 != ck2: - raise ValueError("Corrupt data: broken checksum") - - # load per-key struct - key_type, edata = _get_sshstr(edata) - if key_type != pub_key_type: - raise ValueError("Corrupt data: key type mismatch") - private_key, edata = kformat.load_private( - edata, - pubfields, - unsafe_skip_rsa_key_validation=unsafe_skip_rsa_key_validation, - ) - # We don't use the comment - _, edata = _get_sshstr(edata) - - # yes, SSH does padding check *after* all other parsing is done. - # need to follow as it writes zero-byte padding too. - if edata != _PADDING[: len(edata)]: - raise ValueError("Corrupt data: invalid padding") - - if isinstance(private_key, dsa.DSAPrivateKey): - warnings.warn( - "SSH DSA keys are deprecated and will be removed in a future " - "release.", - utils.DeprecatedIn40, - stacklevel=2, - ) - - return private_key - - -def _serialize_ssh_private_key( - private_key: SSHPrivateKeyTypes, - password: bytes, - encryption_algorithm: KeySerializationEncryption, -) -> bytes: - """Serialize private key with OpenSSH custom encoding.""" - utils._check_bytes("password", password) - if isinstance(private_key, dsa.DSAPrivateKey): - warnings.warn( - "SSH DSA key support is deprecated and will be " - "removed in a future release", - utils.DeprecatedIn40, - stacklevel=4, - ) - - key_type = _get_ssh_key_type(private_key) - kformat = _lookup_kformat(key_type) - - # setup parameters - f_kdfoptions = _FragList() - if password: - ciphername = _DEFAULT_CIPHER - blklen = _SSH_CIPHERS[ciphername].block_len - kdfname = _BCRYPT - rounds = _DEFAULT_ROUNDS - if ( - isinstance(encryption_algorithm, _KeySerializationEncryption) - and encryption_algorithm._kdf_rounds is not None - ): - rounds = encryption_algorithm._kdf_rounds - salt = os.urandom(16) - f_kdfoptions.put_sshstr(salt) - f_kdfoptions.put_u32(rounds) - ciph = _init_cipher(ciphername, password, salt, rounds) - else: - ciphername = kdfname = _NONE - blklen = 8 - ciph = None - nkeys = 1 - checkval = os.urandom(4) - comment = b"" - - # encode public and private parts together - f_public_key = _FragList() - f_public_key.put_sshstr(key_type) - kformat.encode_public(private_key.public_key(), f_public_key) - - f_secrets = _FragList([checkval, checkval]) - f_secrets.put_sshstr(key_type) - kformat.encode_private(private_key, f_secrets) - f_secrets.put_sshstr(comment) - f_secrets.put_raw(_PADDING[: blklen - (f_secrets.size() % blklen)]) - - # top-level structure - f_main = _FragList() - f_main.put_raw(_SK_MAGIC) - f_main.put_sshstr(ciphername) - f_main.put_sshstr(kdfname) - f_main.put_sshstr(f_kdfoptions) - f_main.put_u32(nkeys) - f_main.put_sshstr(f_public_key) - f_main.put_sshstr(f_secrets) - - # copy result info bytearray - slen = f_secrets.size() - mlen = f_main.size() - buf = memoryview(bytearray(mlen + blklen)) - f_main.render(buf) - ofs = mlen - slen - - # encrypt in-place - if ciph is not None: - ciph.encryptor().update_into(buf[ofs:mlen], buf[ofs:]) - - return _ssh_pem_encode(buf[:mlen]) - - -SSHPublicKeyTypes = typing.Union[ - ec.EllipticCurvePublicKey, - rsa.RSAPublicKey, - dsa.DSAPublicKey, - ed25519.Ed25519PublicKey, -] - -SSHCertPublicKeyTypes = typing.Union[ - ec.EllipticCurvePublicKey, - rsa.RSAPublicKey, - ed25519.Ed25519PublicKey, -] - - -class SSHCertificateType(enum.Enum): - USER = 1 - HOST = 2 - - -class SSHCertificate: - def __init__( - self, - _nonce: memoryview, - _public_key: SSHPublicKeyTypes, - _serial: int, - _cctype: int, - _key_id: memoryview, - _valid_principals: list[bytes], - _valid_after: int, - _valid_before: int, - _critical_options: dict[bytes, bytes], - _extensions: dict[bytes, bytes], - _sig_type: memoryview, - _sig_key: memoryview, - _inner_sig_type: memoryview, - _signature: memoryview, - _tbs_cert_body: memoryview, - _cert_key_type: bytes, - _cert_body: memoryview, - ): - self._nonce = _nonce - self._public_key = _public_key - self._serial = _serial - try: - self._type = SSHCertificateType(_cctype) - except ValueError: - raise ValueError("Invalid certificate type") - self._key_id = _key_id - self._valid_principals = _valid_principals - self._valid_after = _valid_after - self._valid_before = _valid_before - self._critical_options = _critical_options - self._extensions = _extensions - self._sig_type = _sig_type - self._sig_key = _sig_key - self._inner_sig_type = _inner_sig_type - self._signature = _signature - self._cert_key_type = _cert_key_type - self._cert_body = _cert_body - self._tbs_cert_body = _tbs_cert_body - - @property - def nonce(self) -> bytes: - return bytes(self._nonce) - - def public_key(self) -> SSHCertPublicKeyTypes: - # make mypy happy until we remove DSA support entirely and - # the underlying union won't have a disallowed type - return typing.cast(SSHCertPublicKeyTypes, self._public_key) - - @property - def serial(self) -> int: - return self._serial - - @property - def type(self) -> SSHCertificateType: - return self._type - - @property - def key_id(self) -> bytes: - return bytes(self._key_id) - - @property - def valid_principals(self) -> list[bytes]: - return self._valid_principals - - @property - def valid_before(self) -> int: - return self._valid_before - - @property - def valid_after(self) -> int: - return self._valid_after - - @property - def critical_options(self) -> dict[bytes, bytes]: - return self._critical_options - - @property - def extensions(self) -> dict[bytes, bytes]: - return self._extensions - - def signature_key(self) -> SSHCertPublicKeyTypes: - sigformat = _lookup_kformat(self._sig_type) - signature_key, sigkey_rest = sigformat.load_public(self._sig_key) - _check_empty(sigkey_rest) - return signature_key - - def public_bytes(self) -> bytes: - return ( - bytes(self._cert_key_type) - + b" " - + binascii.b2a_base64(bytes(self._cert_body), newline=False) - ) - - def verify_cert_signature(self) -> None: - signature_key = self.signature_key() - if isinstance(signature_key, ed25519.Ed25519PublicKey): - signature_key.verify( - bytes(self._signature), bytes(self._tbs_cert_body) - ) - elif isinstance(signature_key, ec.EllipticCurvePublicKey): - # The signature is encoded as a pair of big-endian integers - r, data = _get_mpint(self._signature) - s, data = _get_mpint(data) - _check_empty(data) - computed_sig = asym_utils.encode_dss_signature(r, s) - hash_alg = _get_ec_hash_alg(signature_key.curve) - signature_key.verify( - computed_sig, bytes(self._tbs_cert_body), ec.ECDSA(hash_alg) - ) - else: - assert isinstance(signature_key, rsa.RSAPublicKey) - if self._inner_sig_type == _SSH_RSA: - hash_alg = hashes.SHA1() - elif self._inner_sig_type == _SSH_RSA_SHA256: - hash_alg = hashes.SHA256() - else: - assert self._inner_sig_type == _SSH_RSA_SHA512 - hash_alg = hashes.SHA512() - signature_key.verify( - bytes(self._signature), - bytes(self._tbs_cert_body), - padding.PKCS1v15(), - hash_alg, - ) - - -def _get_ec_hash_alg(curve: ec.EllipticCurve) -> hashes.HashAlgorithm: - if isinstance(curve, ec.SECP256R1): - return hashes.SHA256() - elif isinstance(curve, ec.SECP384R1): - return hashes.SHA384() - else: - assert isinstance(curve, ec.SECP521R1) - return hashes.SHA512() - - -def _load_ssh_public_identity( - data: utils.Buffer, - _legacy_dsa_allowed=False, -) -> SSHCertificate | SSHPublicKeyTypes: - utils._check_byteslike("data", data) - - m = _SSH_PUBKEY_RC.match(data) - if not m: - raise ValueError("Invalid line format") - key_type = orig_key_type = m.group(1) - key_body = m.group(2) - with_cert = False - if key_type.endswith(_CERT_SUFFIX): - with_cert = True - key_type = key_type[: -len(_CERT_SUFFIX)] - if key_type == _SSH_DSA and not _legacy_dsa_allowed: - raise UnsupportedAlgorithm( - "DSA keys aren't supported in SSH certificates" - ) - kformat = _lookup_kformat(key_type) - - try: - rest = memoryview(binascii.a2b_base64(key_body)) - except (TypeError, binascii.Error): - raise ValueError("Invalid format") - - if with_cert: - cert_body = rest - inner_key_type, rest = _get_sshstr(rest) - if inner_key_type != orig_key_type: - raise ValueError("Invalid key format") - if with_cert: - nonce, rest = _get_sshstr(rest) - public_key, rest = kformat.load_public(rest) - if with_cert: - serial, rest = _get_u64(rest) - cctype, rest = _get_u32(rest) - key_id, rest = _get_sshstr(rest) - principals, rest = _get_sshstr(rest) - valid_principals = [] - while principals: - principal, principals = _get_sshstr(principals) - valid_principals.append(bytes(principal)) - valid_after, rest = _get_u64(rest) - valid_before, rest = _get_u64(rest) - crit_options, rest = _get_sshstr(rest) - critical_options = _parse_exts_opts(crit_options) - exts, rest = _get_sshstr(rest) - extensions = _parse_exts_opts(exts) - # Get the reserved field, which is unused. - _, rest = _get_sshstr(rest) - sig_key_raw, rest = _get_sshstr(rest) - sig_type, sig_key = _get_sshstr(sig_key_raw) - if sig_type == _SSH_DSA and not _legacy_dsa_allowed: - raise UnsupportedAlgorithm( - "DSA signatures aren't supported in SSH certificates" - ) - # Get the entire cert body and subtract the signature - tbs_cert_body = cert_body[: -len(rest)] - signature_raw, rest = _get_sshstr(rest) - _check_empty(rest) - inner_sig_type, sig_rest = _get_sshstr(signature_raw) - # RSA certs can have multiple algorithm types - if ( - sig_type == _SSH_RSA - and inner_sig_type - not in [_SSH_RSA_SHA256, _SSH_RSA_SHA512, _SSH_RSA] - ) or (sig_type != _SSH_RSA and inner_sig_type != sig_type): - raise ValueError("Signature key type does not match") - signature, sig_rest = _get_sshstr(sig_rest) - _check_empty(sig_rest) - return SSHCertificate( - nonce, - public_key, - serial, - cctype, - key_id, - valid_principals, - valid_after, - valid_before, - critical_options, - extensions, - sig_type, - sig_key, - inner_sig_type, - signature, - tbs_cert_body, - orig_key_type, - cert_body, - ) - else: - _check_empty(rest) - return public_key - - -def load_ssh_public_identity( - data: utils.Buffer, -) -> SSHCertificate | SSHPublicKeyTypes: - return _load_ssh_public_identity(data) - - -def _parse_exts_opts(exts_opts: memoryview) -> dict[bytes, bytes]: - result: dict[bytes, bytes] = {} - last_name = None - while exts_opts: - name, exts_opts = _get_sshstr(exts_opts) - bname: bytes = bytes(name) - if bname in result: - raise ValueError("Duplicate name") - if last_name is not None and bname < last_name: - raise ValueError("Fields not lexically sorted") - value, exts_opts = _get_sshstr(exts_opts) - if len(value) > 0: - value, extra = _get_sshstr(value) - if len(extra) > 0: - raise ValueError("Unexpected extra data after value") - result[bname] = bytes(value) - last_name = bname - return result - - -def ssh_key_fingerprint( - key: SSHPublicKeyTypes, - hash_algorithm: hashes.MD5 | hashes.SHA256, -) -> bytes: - if not isinstance(hash_algorithm, (hashes.MD5, hashes.SHA256)): - raise TypeError("hash_algorithm must be either MD5 or SHA256") - - key_type = _get_ssh_key_type(key) - kformat = _lookup_kformat(key_type) - - f_pub = _FragList() - f_pub.put_sshstr(key_type) - kformat.encode_public(key, f_pub) - - ssh_binary_data = f_pub.tobytes() - - # Hash the binary data - hash_obj = hashes.Hash(hash_algorithm) - hash_obj.update(ssh_binary_data) - return hash_obj.finalize() - - -def load_ssh_public_key( - data: utils.Buffer, backend: typing.Any = None -) -> SSHPublicKeyTypes: - cert_or_key = _load_ssh_public_identity(data, _legacy_dsa_allowed=True) - public_key: SSHPublicKeyTypes - if isinstance(cert_or_key, SSHCertificate): - public_key = cert_or_key.public_key() - else: - public_key = cert_or_key - - if isinstance(public_key, dsa.DSAPublicKey): - warnings.warn( - "SSH DSA keys are deprecated and will be removed in a future " - "release.", - utils.DeprecatedIn40, - stacklevel=2, - ) - return public_key - - -def serialize_ssh_public_key(public_key: SSHPublicKeyTypes) -> bytes: - """One-line public key format for OpenSSH""" - if isinstance(public_key, dsa.DSAPublicKey): - warnings.warn( - "SSH DSA key support is deprecated and will be " - "removed in a future release", - utils.DeprecatedIn40, - stacklevel=4, - ) - key_type = _get_ssh_key_type(public_key) - kformat = _lookup_kformat(key_type) - - f_pub = _FragList() - f_pub.put_sshstr(key_type) - kformat.encode_public(public_key, f_pub) - - pub = binascii.b2a_base64(f_pub.tobytes()).strip() - return b"".join([key_type, b" ", pub]) - - -SSHCertPrivateKeyTypes = typing.Union[ - ec.EllipticCurvePrivateKey, - rsa.RSAPrivateKey, - ed25519.Ed25519PrivateKey, -] - - -# This is an undocumented limit enforced in the openssh codebase for sshd and -# ssh-keygen, but it is undefined in the ssh certificates spec. -_SSHKEY_CERT_MAX_PRINCIPALS = 256 - - -class SSHCertificateBuilder: - def __init__( - self, - _public_key: SSHCertPublicKeyTypes | None = None, - _serial: int | None = None, - _type: SSHCertificateType | None = None, - _key_id: bytes | None = None, - _valid_principals: list[bytes] = [], - _valid_for_all_principals: bool = False, - _valid_before: int | None = None, - _valid_after: int | None = None, - _critical_options: list[tuple[bytes, bytes]] = [], - _extensions: list[tuple[bytes, bytes]] = [], - ): - self._public_key = _public_key - self._serial = _serial - self._type = _type - self._key_id = _key_id - self._valid_principals = _valid_principals - self._valid_for_all_principals = _valid_for_all_principals - self._valid_before = _valid_before - self._valid_after = _valid_after - self._critical_options = _critical_options - self._extensions = _extensions - - def public_key( - self, public_key: SSHCertPublicKeyTypes - ) -> SSHCertificateBuilder: - if not isinstance( - public_key, - ( - ec.EllipticCurvePublicKey, - rsa.RSAPublicKey, - ed25519.Ed25519PublicKey, - ), - ): - raise TypeError("Unsupported key type") - if self._public_key is not None: - raise ValueError("public_key already set") - - return SSHCertificateBuilder( - _public_key=public_key, - _serial=self._serial, - _type=self._type, - _key_id=self._key_id, - _valid_principals=self._valid_principals, - _valid_for_all_principals=self._valid_for_all_principals, - _valid_before=self._valid_before, - _valid_after=self._valid_after, - _critical_options=self._critical_options, - _extensions=self._extensions, - ) - - def serial(self, serial: int) -> SSHCertificateBuilder: - if not isinstance(serial, int): - raise TypeError("serial must be an integer") - if not 0 <= serial < 2**64: - raise ValueError("serial must be between 0 and 2**64") - if self._serial is not None: - raise ValueError("serial already set") - - return SSHCertificateBuilder( - _public_key=self._public_key, - _serial=serial, - _type=self._type, - _key_id=self._key_id, - _valid_principals=self._valid_principals, - _valid_for_all_principals=self._valid_for_all_principals, - _valid_before=self._valid_before, - _valid_after=self._valid_after, - _critical_options=self._critical_options, - _extensions=self._extensions, - ) - - def type(self, type: SSHCertificateType) -> SSHCertificateBuilder: - if not isinstance(type, SSHCertificateType): - raise TypeError("type must be an SSHCertificateType") - if self._type is not None: - raise ValueError("type already set") - - return SSHCertificateBuilder( - _public_key=self._public_key, - _serial=self._serial, - _type=type, - _key_id=self._key_id, - _valid_principals=self._valid_principals, - _valid_for_all_principals=self._valid_for_all_principals, - _valid_before=self._valid_before, - _valid_after=self._valid_after, - _critical_options=self._critical_options, - _extensions=self._extensions, - ) - - def key_id(self, key_id: bytes) -> SSHCertificateBuilder: - if not isinstance(key_id, bytes): - raise TypeError("key_id must be bytes") - if self._key_id is not None: - raise ValueError("key_id already set") - - return SSHCertificateBuilder( - _public_key=self._public_key, - _serial=self._serial, - _type=self._type, - _key_id=key_id, - _valid_principals=self._valid_principals, - _valid_for_all_principals=self._valid_for_all_principals, - _valid_before=self._valid_before, - _valid_after=self._valid_after, - _critical_options=self._critical_options, - _extensions=self._extensions, - ) - - def valid_principals( - self, valid_principals: list[bytes] - ) -> SSHCertificateBuilder: - if self._valid_for_all_principals: - raise ValueError( - "Principals can't be set because the cert is valid " - "for all principals" - ) - if ( - not all(isinstance(x, bytes) for x in valid_principals) - or not valid_principals - ): - raise TypeError( - "principals must be a list of bytes and can't be empty" - ) - if self._valid_principals: - raise ValueError("valid_principals already set") - - if len(valid_principals) > _SSHKEY_CERT_MAX_PRINCIPALS: - raise ValueError( - "Reached or exceeded the maximum number of valid_principals" - ) - - return SSHCertificateBuilder( - _public_key=self._public_key, - _serial=self._serial, - _type=self._type, - _key_id=self._key_id, - _valid_principals=valid_principals, - _valid_for_all_principals=self._valid_for_all_principals, - _valid_before=self._valid_before, - _valid_after=self._valid_after, - _critical_options=self._critical_options, - _extensions=self._extensions, - ) - - def valid_for_all_principals(self): - if self._valid_principals: - raise ValueError( - "valid_principals already set, can't set " - "valid_for_all_principals" - ) - if self._valid_for_all_principals: - raise ValueError("valid_for_all_principals already set") - - return SSHCertificateBuilder( - _public_key=self._public_key, - _serial=self._serial, - _type=self._type, - _key_id=self._key_id, - _valid_principals=self._valid_principals, - _valid_for_all_principals=True, - _valid_before=self._valid_before, - _valid_after=self._valid_after, - _critical_options=self._critical_options, - _extensions=self._extensions, - ) - - def valid_before(self, valid_before: int | float) -> SSHCertificateBuilder: - if not isinstance(valid_before, (int, float)): - raise TypeError("valid_before must be an int or float") - valid_before = int(valid_before) - if valid_before < 0 or valid_before >= 2**64: - raise ValueError("valid_before must [0, 2**64)") - if self._valid_before is not None: - raise ValueError("valid_before already set") - - return SSHCertificateBuilder( - _public_key=self._public_key, - _serial=self._serial, - _type=self._type, - _key_id=self._key_id, - _valid_principals=self._valid_principals, - _valid_for_all_principals=self._valid_for_all_principals, - _valid_before=valid_before, - _valid_after=self._valid_after, - _critical_options=self._critical_options, - _extensions=self._extensions, - ) - - def valid_after(self, valid_after: int | float) -> SSHCertificateBuilder: - if not isinstance(valid_after, (int, float)): - raise TypeError("valid_after must be an int or float") - valid_after = int(valid_after) - if valid_after < 0 or valid_after >= 2**64: - raise ValueError("valid_after must [0, 2**64)") - if self._valid_after is not None: - raise ValueError("valid_after already set") - - return SSHCertificateBuilder( - _public_key=self._public_key, - _serial=self._serial, - _type=self._type, - _key_id=self._key_id, - _valid_principals=self._valid_principals, - _valid_for_all_principals=self._valid_for_all_principals, - _valid_before=self._valid_before, - _valid_after=valid_after, - _critical_options=self._critical_options, - _extensions=self._extensions, - ) - - def add_critical_option( - self, name: bytes, value: bytes - ) -> SSHCertificateBuilder: - if not isinstance(name, bytes) or not isinstance(value, bytes): - raise TypeError("name and value must be bytes") - # This is O(n**2) - if name in [name for name, _ in self._critical_options]: - raise ValueError("Duplicate critical option name") - - return SSHCertificateBuilder( - _public_key=self._public_key, - _serial=self._serial, - _type=self._type, - _key_id=self._key_id, - _valid_principals=self._valid_principals, - _valid_for_all_principals=self._valid_for_all_principals, - _valid_before=self._valid_before, - _valid_after=self._valid_after, - _critical_options=[*self._critical_options, (name, value)], - _extensions=self._extensions, - ) - - def add_extension( - self, name: bytes, value: bytes - ) -> SSHCertificateBuilder: - if not isinstance(name, bytes) or not isinstance(value, bytes): - raise TypeError("name and value must be bytes") - # This is O(n**2) - if name in [name for name, _ in self._extensions]: - raise ValueError("Duplicate extension name") - - return SSHCertificateBuilder( - _public_key=self._public_key, - _serial=self._serial, - _type=self._type, - _key_id=self._key_id, - _valid_principals=self._valid_principals, - _valid_for_all_principals=self._valid_for_all_principals, - _valid_before=self._valid_before, - _valid_after=self._valid_after, - _critical_options=self._critical_options, - _extensions=[*self._extensions, (name, value)], - ) - - def sign(self, private_key: SSHCertPrivateKeyTypes) -> SSHCertificate: - if not isinstance( - private_key, - ( - ec.EllipticCurvePrivateKey, - rsa.RSAPrivateKey, - ed25519.Ed25519PrivateKey, - ), - ): - raise TypeError("Unsupported private key type") - - if self._public_key is None: - raise ValueError("public_key must be set") - - # Not required - serial = 0 if self._serial is None else self._serial - - if self._type is None: - raise ValueError("type must be set") - - # Not required - key_id = b"" if self._key_id is None else self._key_id - - # A zero length list is valid, but means the certificate - # is valid for any principal of the specified type. We require - # the user to explicitly set valid_for_all_principals to get - # that behavior. - if not self._valid_principals and not self._valid_for_all_principals: - raise ValueError( - "valid_principals must be set if valid_for_all_principals " - "is False" - ) - - if self._valid_before is None: - raise ValueError("valid_before must be set") - - if self._valid_after is None: - raise ValueError("valid_after must be set") - - if self._valid_after > self._valid_before: - raise ValueError("valid_after must be earlier than valid_before") - - # lexically sort our byte strings - self._critical_options.sort(key=lambda x: x[0]) - self._extensions.sort(key=lambda x: x[0]) - - key_type = _get_ssh_key_type(self._public_key) - cert_prefix = key_type + _CERT_SUFFIX - - # Marshal the bytes to be signed - nonce = os.urandom(32) - kformat = _lookup_kformat(key_type) - f = _FragList() - f.put_sshstr(cert_prefix) - f.put_sshstr(nonce) - kformat.encode_public(self._public_key, f) - f.put_u64(serial) - f.put_u32(self._type.value) - f.put_sshstr(key_id) - fprincipals = _FragList() - for p in self._valid_principals: - fprincipals.put_sshstr(p) - f.put_sshstr(fprincipals.tobytes()) - f.put_u64(self._valid_after) - f.put_u64(self._valid_before) - fcrit = _FragList() - for name, value in self._critical_options: - fcrit.put_sshstr(name) - if len(value) > 0: - foptval = _FragList() - foptval.put_sshstr(value) - fcrit.put_sshstr(foptval.tobytes()) - else: - fcrit.put_sshstr(value) - f.put_sshstr(fcrit.tobytes()) - fext = _FragList() - for name, value in self._extensions: - fext.put_sshstr(name) - if len(value) > 0: - fextval = _FragList() - fextval.put_sshstr(value) - fext.put_sshstr(fextval.tobytes()) - else: - fext.put_sshstr(value) - f.put_sshstr(fext.tobytes()) - f.put_sshstr(b"") # RESERVED FIELD - # encode CA public key - ca_type = _get_ssh_key_type(private_key) - caformat = _lookup_kformat(ca_type) - caf = _FragList() - caf.put_sshstr(ca_type) - caformat.encode_public(private_key.public_key(), caf) - f.put_sshstr(caf.tobytes()) - # Sigs according to the rules defined for the CA's public key - # (RFC4253 section 6.6 for ssh-rsa, RFC5656 for ECDSA, - # and RFC8032 for Ed25519). - if isinstance(private_key, ed25519.Ed25519PrivateKey): - signature = private_key.sign(f.tobytes()) - fsig = _FragList() - fsig.put_sshstr(ca_type) - fsig.put_sshstr(signature) - f.put_sshstr(fsig.tobytes()) - elif isinstance(private_key, ec.EllipticCurvePrivateKey): - hash_alg = _get_ec_hash_alg(private_key.curve) - signature = private_key.sign(f.tobytes(), ec.ECDSA(hash_alg)) - r, s = asym_utils.decode_dss_signature(signature) - fsig = _FragList() - fsig.put_sshstr(ca_type) - fsigblob = _FragList() - fsigblob.put_mpint(r) - fsigblob.put_mpint(s) - fsig.put_sshstr(fsigblob.tobytes()) - f.put_sshstr(fsig.tobytes()) - - else: - assert isinstance(private_key, rsa.RSAPrivateKey) - # Just like Golang, we're going to use SHA512 for RSA - # https://cs.opensource.google/go/x/crypto/+/refs/tags/ - # v0.4.0:ssh/certs.go;l=445 - # RFC 8332 defines SHA256 and 512 as options - fsig = _FragList() - fsig.put_sshstr(_SSH_RSA_SHA512) - signature = private_key.sign( - f.tobytes(), padding.PKCS1v15(), hashes.SHA512() - ) - fsig.put_sshstr(signature) - f.put_sshstr(fsig.tobytes()) - - cert_data = binascii.b2a_base64(f.tobytes()).strip() - # load_ssh_public_identity returns a union, but this is - # guaranteed to be an SSHCertificate, so we cast to make - # mypy happy. - return typing.cast( - SSHCertificate, - load_ssh_public_identity(b"".join([cert_prefix, b" ", cert_data])), - ) diff --git a/venv/lib/python3.9/site-packages/cryptography/hazmat/primitives/twofactor/__init__.py b/venv/lib/python3.9/site-packages/cryptography/hazmat/primitives/twofactor/__init__.py deleted file mode 100644 index c1af423..0000000 --- a/venv/lib/python3.9/site-packages/cryptography/hazmat/primitives/twofactor/__init__.py +++ /dev/null @@ -1,9 +0,0 @@ -# This file is dual licensed under the terms of the Apache License, Version -# 2.0, and the BSD License. See the LICENSE file in the root of this repository -# for complete details. - -from __future__ import annotations - - -class InvalidToken(Exception): - pass diff --git a/venv/lib/python3.9/site-packages/cryptography/hazmat/primitives/twofactor/hotp.py b/venv/lib/python3.9/site-packages/cryptography/hazmat/primitives/twofactor/hotp.py deleted file mode 100644 index 21fb000..0000000 --- a/venv/lib/python3.9/site-packages/cryptography/hazmat/primitives/twofactor/hotp.py +++ /dev/null @@ -1,101 +0,0 @@ -# This file is dual licensed under the terms of the Apache License, Version -# 2.0, and the BSD License. See the LICENSE file in the root of this repository -# for complete details. - -from __future__ import annotations - -import base64 -import typing -from urllib.parse import quote, urlencode - -from cryptography.hazmat.primitives import constant_time, hmac -from cryptography.hazmat.primitives.hashes import SHA1, SHA256, SHA512 -from cryptography.hazmat.primitives.twofactor import InvalidToken -from cryptography.utils import Buffer - -HOTPHashTypes = typing.Union[SHA1, SHA256, SHA512] - - -def _generate_uri( - hotp: HOTP, - type_name: str, - account_name: str, - issuer: str | None, - extra_parameters: list[tuple[str, int]], -) -> str: - parameters = [ - ("digits", hotp._length), - ("secret", base64.b32encode(hotp._key)), - ("algorithm", hotp._algorithm.name.upper()), - ] - - if issuer is not None: - parameters.append(("issuer", issuer)) - - parameters.extend(extra_parameters) - - label = ( - f"{quote(issuer)}:{quote(account_name)}" - if issuer - else quote(account_name) - ) - return f"otpauth://{type_name}/{label}?{urlencode(parameters)}" - - -class HOTP: - def __init__( - self, - key: Buffer, - length: int, - algorithm: HOTPHashTypes, - backend: typing.Any = None, - enforce_key_length: bool = True, - ) -> None: - if len(key) < 16 and enforce_key_length is True: - raise ValueError("Key length has to be at least 128 bits.") - - if not isinstance(length, int): - raise TypeError("Length parameter must be an integer type.") - - if length < 6 or length > 8: - raise ValueError("Length of HOTP has to be between 6 and 8.") - - if not isinstance(algorithm, (SHA1, SHA256, SHA512)): - raise TypeError("Algorithm must be SHA1, SHA256 or SHA512.") - - self._key = key - self._length = length - self._algorithm = algorithm - - def generate(self, counter: int) -> bytes: - if not isinstance(counter, int): - raise TypeError("Counter parameter must be an integer type.") - - truncated_value = self._dynamic_truncate(counter) - hotp = truncated_value % (10**self._length) - return "{0:0{1}}".format(hotp, self._length).encode() - - def verify(self, hotp: bytes, counter: int) -> None: - if not constant_time.bytes_eq(self.generate(counter), hotp): - raise InvalidToken("Supplied HOTP value does not match.") - - def _dynamic_truncate(self, counter: int) -> int: - ctx = hmac.HMAC(self._key, self._algorithm) - - try: - ctx.update(counter.to_bytes(length=8, byteorder="big")) - except OverflowError: - raise ValueError(f"Counter must be between 0 and {2**64 - 1}.") - - hmac_value = ctx.finalize() - - offset = hmac_value[len(hmac_value) - 1] & 0b1111 - p = hmac_value[offset : offset + 4] - return int.from_bytes(p, byteorder="big") & 0x7FFFFFFF - - def get_provisioning_uri( - self, account_name: str, counter: int, issuer: str | None - ) -> str: - return _generate_uri( - self, "hotp", account_name, issuer, [("counter", int(counter))] - ) diff --git a/venv/lib/python3.9/site-packages/cryptography/hazmat/primitives/twofactor/totp.py b/venv/lib/python3.9/site-packages/cryptography/hazmat/primitives/twofactor/totp.py deleted file mode 100644 index 10c725c..0000000 --- a/venv/lib/python3.9/site-packages/cryptography/hazmat/primitives/twofactor/totp.py +++ /dev/null @@ -1,56 +0,0 @@ -# This file is dual licensed under the terms of the Apache License, Version -# 2.0, and the BSD License. See the LICENSE file in the root of this repository -# for complete details. - -from __future__ import annotations - -import typing - -from cryptography.hazmat.primitives import constant_time -from cryptography.hazmat.primitives.twofactor import InvalidToken -from cryptography.hazmat.primitives.twofactor.hotp import ( - HOTP, - HOTPHashTypes, - _generate_uri, -) -from cryptography.utils import Buffer - - -class TOTP: - def __init__( - self, - key: Buffer, - length: int, - algorithm: HOTPHashTypes, - time_step: int, - backend: typing.Any = None, - enforce_key_length: bool = True, - ): - self._time_step = time_step - self._hotp = HOTP( - key, length, algorithm, enforce_key_length=enforce_key_length - ) - - def generate(self, time: int | float) -> bytes: - if not isinstance(time, (int, float)): - raise TypeError( - "Time parameter must be an integer type or float type." - ) - - counter = int(time / self._time_step) - return self._hotp.generate(counter) - - def verify(self, totp: bytes, time: int) -> None: - if not constant_time.bytes_eq(self.generate(time), totp): - raise InvalidToken("Supplied TOTP value does not match.") - - def get_provisioning_uri( - self, account_name: str, issuer: str | None - ) -> str: - return _generate_uri( - self._hotp, - "totp", - account_name, - issuer, - [("period", int(self._time_step))], - ) diff --git a/venv/lib/python3.9/site-packages/cryptography/py.typed b/venv/lib/python3.9/site-packages/cryptography/py.typed deleted file mode 100644 index e69de29..0000000 diff --git a/venv/lib/python3.9/site-packages/cryptography/utils.py b/venv/lib/python3.9/site-packages/cryptography/utils.py deleted file mode 100644 index b3868a0..0000000 --- a/venv/lib/python3.9/site-packages/cryptography/utils.py +++ /dev/null @@ -1,138 +0,0 @@ -# This file is dual licensed under the terms of the Apache License, Version -# 2.0, and the BSD License. See the LICENSE file in the root of this repository -# for complete details. - -from __future__ import annotations - -import enum -import sys -import types -import typing -import warnings -from collections.abc import Callable, Sequence - - -# We use a UserWarning subclass, instead of DeprecationWarning, because CPython -# decided deprecation warnings should be invisible by default. -class CryptographyDeprecationWarning(UserWarning): - pass - - -# Several APIs were deprecated with no specific end-of-life date because of the -# ubiquity of their use. They should not be removed until we agree on when that -# cycle ends. -DeprecatedIn36 = CryptographyDeprecationWarning -DeprecatedIn40 = CryptographyDeprecationWarning -DeprecatedIn41 = CryptographyDeprecationWarning -DeprecatedIn42 = CryptographyDeprecationWarning -DeprecatedIn43 = CryptographyDeprecationWarning -DeprecatedIn47 = CryptographyDeprecationWarning - - -# If you're wondering why we don't use `Buffer`, it's because `Buffer` would -# be more accurately named: Bufferable. It means something which has an -# `__buffer__`. Which means you can't actually treat the result as a buffer -# (and do things like take a `len()`). -if sys.version_info >= (3, 9): - Buffer = typing.Union[bytes, bytearray, memoryview] -else: - Buffer = typing.ByteString - - -def _check_bytes(name: str, value: bytes) -> None: - if not isinstance(value, bytes): - raise TypeError(f"{name} must be bytes") - - -def _check_byteslike(name: str, value: Buffer) -> None: - try: - memoryview(value) - except TypeError: - raise TypeError(f"{name} must be bytes-like") - - -def int_to_bytes(integer: int, length: int | None = None) -> bytes: - if length == 0: - raise ValueError("length argument can't be 0") - return integer.to_bytes( - length or (integer.bit_length() + 7) // 8 or 1, "big" - ) - - -class InterfaceNotImplemented(Exception): - pass - - -class _DeprecatedValue: - def __init__(self, value: object, message: str, warning_class): - self.value = value - self.message = message - self.warning_class = warning_class - - -class _ModuleWithDeprecations(types.ModuleType): - def __init__(self, module: types.ModuleType): - super().__init__(module.__name__) - self.__dict__["_module"] = module - - def __getattr__(self, name: str) -> typing.Any: - obj = getattr(self._module, name) - if isinstance(obj, _DeprecatedValue): - warnings.warn(obj.message, obj.warning_class, stacklevel=2) - obj = obj.value - return obj - - def __setattr__(self, attr: str, value: object) -> None: - setattr(self._module, attr, value) - - def __delattr__(self, attr: str) -> None: - obj = getattr(self._module, attr) - if isinstance(obj, _DeprecatedValue): - warnings.warn(obj.message, obj.warning_class, stacklevel=2) - - delattr(self._module, attr) - - def __dir__(self) -> Sequence[str]: - return ["_module", *dir(self._module)] - - -def deprecated( - value: object, - module_name: str, - message: str, - warning_class: type[Warning], - name: str | None = None, -) -> _DeprecatedValue: - module = sys.modules[module_name] - if not isinstance(module, _ModuleWithDeprecations): - sys.modules[module_name] = module = _ModuleWithDeprecations(module) - dv = _DeprecatedValue(value, message, warning_class) - # Maintain backwards compatibility with `name is None` for pyOpenSSL. - if name is not None: - setattr(module, name, dv) - return dv - - -def cached_property(func: Callable) -> property: - cached_name = f"_cached_{func}" - sentinel = object() - - def inner(instance: object): - cache = getattr(instance, cached_name, sentinel) - if cache is not sentinel: - return cache - result = func(instance) - setattr(instance, cached_name, result) - return result - - return property(inner) - - -# Python 3.10 changed representation of enums. We use well-defined object -# representation and string representation from Python 3.9. -class Enum(enum.Enum): - def __repr__(self) -> str: - return f"<{self.__class__.__name__}.{self._name_}: {self._value_!r}>" - - def __str__(self) -> str: - return f"{self.__class__.__name__}.{self._name_}" diff --git a/venv/lib/python3.9/site-packages/cryptography/x509/__init__.py b/venv/lib/python3.9/site-packages/cryptography/x509/__init__.py deleted file mode 100644 index cb34833..0000000 --- a/venv/lib/python3.9/site-packages/cryptography/x509/__init__.py +++ /dev/null @@ -1,271 +0,0 @@ -# This file is dual licensed under the terms of the Apache License, Version -# 2.0, and the BSD License. See the LICENSE file in the root of this repository -# for complete details. - -from __future__ import annotations - -from cryptography.x509 import certificate_transparency, oid, verification -from cryptography.x509.base import ( - Attribute, - AttributeNotFound, - Attributes, - Certificate, - CertificateBuilder, - CertificateRevocationList, - CertificateRevocationListBuilder, - CertificateSigningRequest, - CertificateSigningRequestBuilder, - InvalidVersion, - RevokedCertificate, - RevokedCertificateBuilder, - Version, - load_der_x509_certificate, - load_der_x509_crl, - load_der_x509_csr, - load_pem_x509_certificate, - load_pem_x509_certificates, - load_pem_x509_crl, - load_pem_x509_csr, - random_serial_number, -) -from cryptography.x509.extensions import ( - AccessDescription, - Admission, - Admissions, - AuthorityInformationAccess, - AuthorityKeyIdentifier, - BasicConstraints, - CertificateIssuer, - CertificatePolicies, - CRLDistributionPoints, - CRLNumber, - CRLReason, - DeltaCRLIndicator, - DistributionPoint, - DuplicateExtension, - ExtendedKeyUsage, - Extension, - ExtensionNotFound, - Extensions, - ExtensionType, - FreshestCRL, - GeneralNames, - InhibitAnyPolicy, - InvalidityDate, - IssuerAlternativeName, - IssuingDistributionPoint, - KeyUsage, - MSCertificateTemplate, - NameConstraints, - NamingAuthority, - NoticeReference, - OCSPAcceptableResponses, - OCSPNoCheck, - OCSPNonce, - PolicyConstraints, - PolicyInformation, - PrecertificateSignedCertificateTimestamps, - PrecertPoison, - PrivateKeyUsagePeriod, - ProfessionInfo, - ReasonFlags, - SignedCertificateTimestamps, - SubjectAlternativeName, - SubjectInformationAccess, - SubjectKeyIdentifier, - TLSFeature, - TLSFeatureType, - UnrecognizedExtension, - UserNotice, -) -from cryptography.x509.general_name import ( - DirectoryName, - DNSName, - GeneralName, - IPAddress, - OtherName, - RegisteredID, - RFC822Name, - UniformResourceIdentifier, - UnsupportedGeneralNameType, -) -from cryptography.x509.name import ( - Name, - NameAttribute, - RelativeDistinguishedName, -) -from cryptography.x509.oid import ( - AuthorityInformationAccessOID, - CertificatePoliciesOID, - CRLEntryExtensionOID, - ExtendedKeyUsageOID, - ExtensionOID, - NameOID, - ObjectIdentifier, - PublicKeyAlgorithmOID, - SignatureAlgorithmOID, -) - -OID_AUTHORITY_INFORMATION_ACCESS = ExtensionOID.AUTHORITY_INFORMATION_ACCESS -OID_AUTHORITY_KEY_IDENTIFIER = ExtensionOID.AUTHORITY_KEY_IDENTIFIER -OID_BASIC_CONSTRAINTS = ExtensionOID.BASIC_CONSTRAINTS -OID_CERTIFICATE_POLICIES = ExtensionOID.CERTIFICATE_POLICIES -OID_CRL_DISTRIBUTION_POINTS = ExtensionOID.CRL_DISTRIBUTION_POINTS -OID_EXTENDED_KEY_USAGE = ExtensionOID.EXTENDED_KEY_USAGE -OID_FRESHEST_CRL = ExtensionOID.FRESHEST_CRL -OID_INHIBIT_ANY_POLICY = ExtensionOID.INHIBIT_ANY_POLICY -OID_ISSUER_ALTERNATIVE_NAME = ExtensionOID.ISSUER_ALTERNATIVE_NAME -OID_KEY_USAGE = ExtensionOID.KEY_USAGE -OID_PRIVATE_KEY_USAGE_PERIOD = ExtensionOID.PRIVATE_KEY_USAGE_PERIOD -OID_NAME_CONSTRAINTS = ExtensionOID.NAME_CONSTRAINTS -OID_OCSP_NO_CHECK = ExtensionOID.OCSP_NO_CHECK -OID_POLICY_CONSTRAINTS = ExtensionOID.POLICY_CONSTRAINTS -OID_POLICY_MAPPINGS = ExtensionOID.POLICY_MAPPINGS -OID_SUBJECT_ALTERNATIVE_NAME = ExtensionOID.SUBJECT_ALTERNATIVE_NAME -OID_SUBJECT_DIRECTORY_ATTRIBUTES = ExtensionOID.SUBJECT_DIRECTORY_ATTRIBUTES -OID_SUBJECT_INFORMATION_ACCESS = ExtensionOID.SUBJECT_INFORMATION_ACCESS -OID_SUBJECT_KEY_IDENTIFIER = ExtensionOID.SUBJECT_KEY_IDENTIFIER - -OID_DSA_WITH_SHA1 = SignatureAlgorithmOID.DSA_WITH_SHA1 -OID_DSA_WITH_SHA224 = SignatureAlgorithmOID.DSA_WITH_SHA224 -OID_DSA_WITH_SHA256 = SignatureAlgorithmOID.DSA_WITH_SHA256 -OID_ECDSA_WITH_SHA1 = SignatureAlgorithmOID.ECDSA_WITH_SHA1 -OID_ECDSA_WITH_SHA224 = SignatureAlgorithmOID.ECDSA_WITH_SHA224 -OID_ECDSA_WITH_SHA256 = SignatureAlgorithmOID.ECDSA_WITH_SHA256 -OID_ECDSA_WITH_SHA384 = SignatureAlgorithmOID.ECDSA_WITH_SHA384 -OID_ECDSA_WITH_SHA512 = SignatureAlgorithmOID.ECDSA_WITH_SHA512 -OID_RSA_WITH_MD5 = SignatureAlgorithmOID.RSA_WITH_MD5 -OID_RSA_WITH_SHA1 = SignatureAlgorithmOID.RSA_WITH_SHA1 -OID_RSA_WITH_SHA224 = SignatureAlgorithmOID.RSA_WITH_SHA224 -OID_RSA_WITH_SHA256 = SignatureAlgorithmOID.RSA_WITH_SHA256 -OID_RSA_WITH_SHA384 = SignatureAlgorithmOID.RSA_WITH_SHA384 -OID_RSA_WITH_SHA512 = SignatureAlgorithmOID.RSA_WITH_SHA512 -OID_RSASSA_PSS = SignatureAlgorithmOID.RSASSA_PSS - -OID_COMMON_NAME = NameOID.COMMON_NAME -OID_COUNTRY_NAME = NameOID.COUNTRY_NAME -OID_DOMAIN_COMPONENT = NameOID.DOMAIN_COMPONENT -OID_DN_QUALIFIER = NameOID.DN_QUALIFIER -OID_EMAIL_ADDRESS = NameOID.EMAIL_ADDRESS -OID_GENERATION_QUALIFIER = NameOID.GENERATION_QUALIFIER -OID_GIVEN_NAME = NameOID.GIVEN_NAME -OID_LOCALITY_NAME = NameOID.LOCALITY_NAME -OID_ORGANIZATIONAL_UNIT_NAME = NameOID.ORGANIZATIONAL_UNIT_NAME -OID_ORGANIZATION_NAME = NameOID.ORGANIZATION_NAME -OID_PSEUDONYM = NameOID.PSEUDONYM -OID_SERIAL_NUMBER = NameOID.SERIAL_NUMBER -OID_STATE_OR_PROVINCE_NAME = NameOID.STATE_OR_PROVINCE_NAME -OID_SURNAME = NameOID.SURNAME -OID_TITLE = NameOID.TITLE - -OID_CLIENT_AUTH = ExtendedKeyUsageOID.CLIENT_AUTH -OID_CODE_SIGNING = ExtendedKeyUsageOID.CODE_SIGNING -OID_EMAIL_PROTECTION = ExtendedKeyUsageOID.EMAIL_PROTECTION -OID_OCSP_SIGNING = ExtendedKeyUsageOID.OCSP_SIGNING -OID_SERVER_AUTH = ExtendedKeyUsageOID.SERVER_AUTH -OID_TIME_STAMPING = ExtendedKeyUsageOID.TIME_STAMPING - -OID_ANY_POLICY = CertificatePoliciesOID.ANY_POLICY -OID_CPS_QUALIFIER = CertificatePoliciesOID.CPS_QUALIFIER -OID_CPS_USER_NOTICE = CertificatePoliciesOID.CPS_USER_NOTICE - -OID_CERTIFICATE_ISSUER = CRLEntryExtensionOID.CERTIFICATE_ISSUER -OID_CRL_REASON = CRLEntryExtensionOID.CRL_REASON -OID_INVALIDITY_DATE = CRLEntryExtensionOID.INVALIDITY_DATE - -OID_CA_ISSUERS = AuthorityInformationAccessOID.CA_ISSUERS -OID_OCSP = AuthorityInformationAccessOID.OCSP - -__all__ = [ - "OID_CA_ISSUERS", - "OID_OCSP", - "AccessDescription", - "Admission", - "Admissions", - "Attribute", - "AttributeNotFound", - "Attributes", - "AuthorityInformationAccess", - "AuthorityKeyIdentifier", - "BasicConstraints", - "CRLDistributionPoints", - "CRLNumber", - "CRLReason", - "Certificate", - "CertificateBuilder", - "CertificateIssuer", - "CertificatePolicies", - "CertificateRevocationList", - "CertificateRevocationListBuilder", - "CertificateSigningRequest", - "CertificateSigningRequestBuilder", - "DNSName", - "DeltaCRLIndicator", - "DirectoryName", - "DistributionPoint", - "DuplicateExtension", - "ExtendedKeyUsage", - "Extension", - "ExtensionNotFound", - "ExtensionType", - "Extensions", - "FreshestCRL", - "GeneralName", - "GeneralNames", - "IPAddress", - "InhibitAnyPolicy", - "InvalidVersion", - "InvalidityDate", - "IssuerAlternativeName", - "IssuingDistributionPoint", - "KeyUsage", - "MSCertificateTemplate", - "Name", - "NameAttribute", - "NameConstraints", - "NameOID", - "NamingAuthority", - "NoticeReference", - "OCSPAcceptableResponses", - "OCSPNoCheck", - "OCSPNonce", - "ObjectIdentifier", - "OtherName", - "PolicyConstraints", - "PolicyInformation", - "PrecertPoison", - "PrecertificateSignedCertificateTimestamps", - "PrivateKeyUsagePeriod", - "ProfessionInfo", - "PublicKeyAlgorithmOID", - "RFC822Name", - "ReasonFlags", - "RegisteredID", - "RelativeDistinguishedName", - "RevokedCertificate", - "RevokedCertificateBuilder", - "SignatureAlgorithmOID", - "SignedCertificateTimestamps", - "SubjectAlternativeName", - "SubjectInformationAccess", - "SubjectKeyIdentifier", - "TLSFeature", - "TLSFeatureType", - "UniformResourceIdentifier", - "UnrecognizedExtension", - "UnsupportedGeneralNameType", - "UserNotice", - "Version", - "certificate_transparency", - "load_der_x509_certificate", - "load_der_x509_crl", - "load_der_x509_csr", - "load_pem_x509_certificate", - "load_pem_x509_certificates", - "load_pem_x509_crl", - "load_pem_x509_csr", - "oid", - "random_serial_number", - "verification", - "verification", -] diff --git a/venv/lib/python3.9/site-packages/cryptography/x509/base.py b/venv/lib/python3.9/site-packages/cryptography/x509/base.py deleted file mode 100644 index a11b8fe..0000000 --- a/venv/lib/python3.9/site-packages/cryptography/x509/base.py +++ /dev/null @@ -1,773 +0,0 @@ -# This file is dual licensed under the terms of the Apache License, Version -# 2.0, and the BSD License. See the LICENSE file in the root of this repository -# for complete details. - -from __future__ import annotations - -import datetime -import os -import typing -from collections.abc import Iterable - -from cryptography import utils -from cryptography.hazmat.bindings._rust import x509 as rust_x509 -from cryptography.hazmat.primitives import hashes -from cryptography.hazmat.primitives.asymmetric import ( - dsa, - ec, - ed448, - ed25519, - padding, - rsa, - x448, - x25519, -) -from cryptography.hazmat.primitives.asymmetric.types import ( - CertificateIssuerPrivateKeyTypes, - CertificatePublicKeyTypes, -) -from cryptography.x509.extensions import ( - Extension, - ExtensionType, - _make_sequence_methods, -) -from cryptography.x509.name import Name, _ASN1Type -from cryptography.x509.oid import ObjectIdentifier - -_EARLIEST_UTC_TIME = datetime.datetime(1950, 1, 1) - -# This must be kept in sync with sign.rs's list of allowable types in -# identify_hash_type -_AllowedHashTypes = typing.Union[ - hashes.SHA224, - hashes.SHA256, - hashes.SHA384, - hashes.SHA512, - hashes.SHA3_224, - hashes.SHA3_256, - hashes.SHA3_384, - hashes.SHA3_512, -] - - -class AttributeNotFound(Exception): - def __init__(self, msg: str, oid: ObjectIdentifier) -> None: - super().__init__(msg) - self.oid = oid - - -def _reject_duplicate_extension( - extension: Extension[ExtensionType], - extensions: list[Extension[ExtensionType]], -) -> None: - # This is quadratic in the number of extensions - for e in extensions: - if e.oid == extension.oid: - raise ValueError("This extension has already been set.") - - -def _reject_duplicate_attribute( - oid: ObjectIdentifier, - attributes: list[tuple[ObjectIdentifier, bytes, int | None]], -) -> None: - # This is quadratic in the number of attributes - for attr_oid, _, _ in attributes: - if attr_oid == oid: - raise ValueError("This attribute has already been set.") - - -def _convert_to_naive_utc_time(time: datetime.datetime) -> datetime.datetime: - """Normalizes a datetime to a naive datetime in UTC. - - time -- datetime to normalize. Assumed to be in UTC if not timezone - aware. - """ - if time.tzinfo is not None: - offset = time.utcoffset() - offset = offset if offset else datetime.timedelta() - return time.replace(tzinfo=None) - offset - else: - return time - - -class Attribute: - def __init__( - self, - oid: ObjectIdentifier, - value: bytes, - _type: int = _ASN1Type.UTF8String.value, - ) -> None: - self._oid = oid - self._value = value - self._type = _type - - @property - def oid(self) -> ObjectIdentifier: - return self._oid - - @property - def value(self) -> bytes: - return self._value - - def __repr__(self) -> str: - return f"" - - def __eq__(self, other: object) -> bool: - if not isinstance(other, Attribute): - return NotImplemented - - return ( - self.oid == other.oid - and self.value == other.value - and self._type == other._type - ) - - def __hash__(self) -> int: - return hash((self.oid, self.value, self._type)) - - -class Attributes: - def __init__( - self, - attributes: Iterable[Attribute], - ) -> None: - self._attributes = list(attributes) - - __len__, __iter__, __getitem__ = _make_sequence_methods("_attributes") - - def __repr__(self) -> str: - return f"" - - def get_attribute_for_oid(self, oid: ObjectIdentifier) -> Attribute: - for attr in self: - if attr.oid == oid: - return attr - - raise AttributeNotFound(f"No {oid} attribute was found", oid) - - -class Version(utils.Enum): - v1 = 0 - v3 = 2 - - -class InvalidVersion(Exception): - def __init__(self, msg: str, parsed_version: int) -> None: - super().__init__(msg) - self.parsed_version = parsed_version - - -Certificate = rust_x509.Certificate -RevokedCertificate = rust_x509.RevokedCertificate - - -CertificateRevocationList = rust_x509.CertificateRevocationList -CertificateSigningRequest = rust_x509.CertificateSigningRequest - - -load_pem_x509_certificate = rust_x509.load_pem_x509_certificate -load_der_x509_certificate = rust_x509.load_der_x509_certificate - -load_pem_x509_certificates = rust_x509.load_pem_x509_certificates - -load_pem_x509_csr = rust_x509.load_pem_x509_csr -load_der_x509_csr = rust_x509.load_der_x509_csr - -load_pem_x509_crl = rust_x509.load_pem_x509_crl -load_der_x509_crl = rust_x509.load_der_x509_crl - - -class CertificateSigningRequestBuilder: - def __init__( - self, - subject_name: Name | None = None, - extensions: list[Extension[ExtensionType]] = [], - attributes: list[tuple[ObjectIdentifier, bytes, int | None]] = [], - ): - """ - Creates an empty X.509 certificate request (v1). - """ - self._subject_name = subject_name - self._extensions = extensions - self._attributes = attributes - - def subject_name(self, name: Name) -> CertificateSigningRequestBuilder: - """ - Sets the certificate requestor's distinguished name. - """ - if not isinstance(name, Name): - raise TypeError("Expecting x509.Name object.") - if self._subject_name is not None: - raise ValueError("The subject name may only be set once.") - return CertificateSigningRequestBuilder( - name, self._extensions, self._attributes - ) - - def add_extension( - self, extval: ExtensionType, critical: bool - ) -> CertificateSigningRequestBuilder: - """ - Adds an X.509 extension to the certificate request. - """ - if not isinstance(extval, ExtensionType): - raise TypeError("extension must be an ExtensionType") - - extension = Extension(extval.oid, critical, extval) - _reject_duplicate_extension(extension, self._extensions) - - return CertificateSigningRequestBuilder( - self._subject_name, - [*self._extensions, extension], - self._attributes, - ) - - def add_attribute( - self, - oid: ObjectIdentifier, - value: bytes, - *, - _tag: _ASN1Type | None = None, - ) -> CertificateSigningRequestBuilder: - """ - Adds an X.509 attribute with an OID and associated value. - """ - if not isinstance(oid, ObjectIdentifier): - raise TypeError("oid must be an ObjectIdentifier") - - if not isinstance(value, bytes): - raise TypeError("value must be bytes") - - if _tag is not None and not isinstance(_tag, _ASN1Type): - raise TypeError("tag must be _ASN1Type") - - _reject_duplicate_attribute(oid, self._attributes) - - if _tag is not None: - tag = _tag.value - else: - tag = None - - return CertificateSigningRequestBuilder( - self._subject_name, - self._extensions, - [*self._attributes, (oid, value, tag)], - ) - - def sign( - self, - private_key: CertificateIssuerPrivateKeyTypes, - algorithm: _AllowedHashTypes | None, - backend: typing.Any = None, - *, - rsa_padding: padding.PSS | padding.PKCS1v15 | None = None, - ecdsa_deterministic: bool | None = None, - ) -> CertificateSigningRequest: - """ - Signs the request using the requestor's private key. - """ - if self._subject_name is None: - raise ValueError("A CertificateSigningRequest must have a subject") - - if rsa_padding is not None: - if not isinstance(rsa_padding, (padding.PSS, padding.PKCS1v15)): - raise TypeError("Padding must be PSS or PKCS1v15") - if not isinstance(private_key, rsa.RSAPrivateKey): - raise TypeError("Padding is only supported for RSA keys") - - if ecdsa_deterministic is not None: - if not isinstance(private_key, ec.EllipticCurvePrivateKey): - raise TypeError( - "Deterministic ECDSA is only supported for EC keys" - ) - - return rust_x509.create_x509_csr( - self, - private_key, - algorithm, - rsa_padding, - ecdsa_deterministic, - ) - - -class CertificateBuilder: - _extensions: list[Extension[ExtensionType]] - - def __init__( - self, - issuer_name: Name | None = None, - subject_name: Name | None = None, - public_key: CertificatePublicKeyTypes | None = None, - serial_number: int | None = None, - not_valid_before: datetime.datetime | None = None, - not_valid_after: datetime.datetime | None = None, - extensions: list[Extension[ExtensionType]] = [], - ) -> None: - self._version = Version.v3 - self._issuer_name = issuer_name - self._subject_name = subject_name - self._public_key = public_key - self._serial_number = serial_number - self._not_valid_before = not_valid_before - self._not_valid_after = not_valid_after - self._extensions = extensions - - def issuer_name(self, name: Name) -> CertificateBuilder: - """ - Sets the CA's distinguished name. - """ - if not isinstance(name, Name): - raise TypeError("Expecting x509.Name object.") - if self._issuer_name is not None: - raise ValueError("The issuer name may only be set once.") - return CertificateBuilder( - name, - self._subject_name, - self._public_key, - self._serial_number, - self._not_valid_before, - self._not_valid_after, - self._extensions, - ) - - def subject_name(self, name: Name) -> CertificateBuilder: - """ - Sets the requestor's distinguished name. - """ - if not isinstance(name, Name): - raise TypeError("Expecting x509.Name object.") - if self._subject_name is not None: - raise ValueError("The subject name may only be set once.") - return CertificateBuilder( - self._issuer_name, - name, - self._public_key, - self._serial_number, - self._not_valid_before, - self._not_valid_after, - self._extensions, - ) - - def public_key( - self, - key: CertificatePublicKeyTypes, - ) -> CertificateBuilder: - """ - Sets the requestor's public key (as found in the signing request). - """ - if not isinstance( - key, - ( - dsa.DSAPublicKey, - rsa.RSAPublicKey, - ec.EllipticCurvePublicKey, - ed25519.Ed25519PublicKey, - ed448.Ed448PublicKey, - x25519.X25519PublicKey, - x448.X448PublicKey, - ), - ): - raise TypeError( - "Expecting one of DSAPublicKey, RSAPublicKey," - " EllipticCurvePublicKey, Ed25519PublicKey," - " Ed448PublicKey, X25519PublicKey, or " - "X448PublicKey." - ) - if self._public_key is not None: - raise ValueError("The public key may only be set once.") - return CertificateBuilder( - self._issuer_name, - self._subject_name, - key, - self._serial_number, - self._not_valid_before, - self._not_valid_after, - self._extensions, - ) - - def serial_number(self, number: int) -> CertificateBuilder: - """ - Sets the certificate serial number. - """ - if not isinstance(number, int): - raise TypeError("Serial number must be of integral type.") - if self._serial_number is not None: - raise ValueError("The serial number may only be set once.") - if number <= 0: - raise ValueError("The serial number should be positive.") - - # ASN.1 integers are always signed, so most significant bit must be - # zero. - if number.bit_length() >= 160: # As defined in RFC 5280 - raise ValueError( - "The serial number should not be more than 159 bits." - ) - return CertificateBuilder( - self._issuer_name, - self._subject_name, - self._public_key, - number, - self._not_valid_before, - self._not_valid_after, - self._extensions, - ) - - def not_valid_before(self, time: datetime.datetime) -> CertificateBuilder: - """ - Sets the certificate activation time. - """ - if not isinstance(time, datetime.datetime): - raise TypeError("Expecting datetime object.") - if self._not_valid_before is not None: - raise ValueError("The not valid before may only be set once.") - time = _convert_to_naive_utc_time(time) - if time < _EARLIEST_UTC_TIME: - raise ValueError( - "The not valid before date must be on or after" - " 1950 January 1)." - ) - if self._not_valid_after is not None and time > self._not_valid_after: - raise ValueError( - "The not valid before date must be before the not valid after " - "date." - ) - return CertificateBuilder( - self._issuer_name, - self._subject_name, - self._public_key, - self._serial_number, - time, - self._not_valid_after, - self._extensions, - ) - - def not_valid_after(self, time: datetime.datetime) -> CertificateBuilder: - """ - Sets the certificate expiration time. - """ - if not isinstance(time, datetime.datetime): - raise TypeError("Expecting datetime object.") - if self._not_valid_after is not None: - raise ValueError("The not valid after may only be set once.") - time = _convert_to_naive_utc_time(time) - if time < _EARLIEST_UTC_TIME: - raise ValueError( - "The not valid after date must be on or after 1950 January 1." - ) - if ( - self._not_valid_before is not None - and time < self._not_valid_before - ): - raise ValueError( - "The not valid after date must be after the not valid before " - "date." - ) - return CertificateBuilder( - self._issuer_name, - self._subject_name, - self._public_key, - self._serial_number, - self._not_valid_before, - time, - self._extensions, - ) - - def add_extension( - self, extval: ExtensionType, critical: bool - ) -> CertificateBuilder: - """ - Adds an X.509 extension to the certificate. - """ - if not isinstance(extval, ExtensionType): - raise TypeError("extension must be an ExtensionType") - - extension = Extension(extval.oid, critical, extval) - _reject_duplicate_extension(extension, self._extensions) - - return CertificateBuilder( - self._issuer_name, - self._subject_name, - self._public_key, - self._serial_number, - self._not_valid_before, - self._not_valid_after, - [*self._extensions, extension], - ) - - def sign( - self, - private_key: CertificateIssuerPrivateKeyTypes, - algorithm: _AllowedHashTypes | None, - backend: typing.Any = None, - *, - rsa_padding: padding.PSS | padding.PKCS1v15 | None = None, - ecdsa_deterministic: bool | None = None, - ) -> Certificate: - """ - Signs the certificate using the CA's private key. - """ - if self._subject_name is None: - raise ValueError("A certificate must have a subject name") - - if self._issuer_name is None: - raise ValueError("A certificate must have an issuer name") - - if self._serial_number is None: - raise ValueError("A certificate must have a serial number") - - if self._not_valid_before is None: - raise ValueError("A certificate must have a not valid before time") - - if self._not_valid_after is None: - raise ValueError("A certificate must have a not valid after time") - - if self._public_key is None: - raise ValueError("A certificate must have a public key") - - if rsa_padding is not None: - if not isinstance(rsa_padding, (padding.PSS, padding.PKCS1v15)): - raise TypeError("Padding must be PSS or PKCS1v15") - if not isinstance(private_key, rsa.RSAPrivateKey): - raise TypeError("Padding is only supported for RSA keys") - - if ecdsa_deterministic is not None: - if not isinstance(private_key, ec.EllipticCurvePrivateKey): - raise TypeError( - "Deterministic ECDSA is only supported for EC keys" - ) - - return rust_x509.create_x509_certificate( - self, - private_key, - algorithm, - rsa_padding, - ecdsa_deterministic, - ) - - -class CertificateRevocationListBuilder: - _extensions: list[Extension[ExtensionType]] - _revoked_certificates: list[RevokedCertificate] - - def __init__( - self, - issuer_name: Name | None = None, - last_update: datetime.datetime | None = None, - next_update: datetime.datetime | None = None, - extensions: list[Extension[ExtensionType]] = [], - revoked_certificates: list[RevokedCertificate] = [], - ): - self._issuer_name = issuer_name - self._last_update = last_update - self._next_update = next_update - self._extensions = extensions - self._revoked_certificates = revoked_certificates - - def issuer_name( - self, issuer_name: Name - ) -> CertificateRevocationListBuilder: - if not isinstance(issuer_name, Name): - raise TypeError("Expecting x509.Name object.") - if self._issuer_name is not None: - raise ValueError("The issuer name may only be set once.") - return CertificateRevocationListBuilder( - issuer_name, - self._last_update, - self._next_update, - self._extensions, - self._revoked_certificates, - ) - - def last_update( - self, last_update: datetime.datetime - ) -> CertificateRevocationListBuilder: - if not isinstance(last_update, datetime.datetime): - raise TypeError("Expecting datetime object.") - if self._last_update is not None: - raise ValueError("Last update may only be set once.") - last_update = _convert_to_naive_utc_time(last_update) - if last_update < _EARLIEST_UTC_TIME: - raise ValueError( - "The last update date must be on or after 1950 January 1." - ) - if self._next_update is not None and last_update > self._next_update: - raise ValueError( - "The last update date must be before the next update date." - ) - return CertificateRevocationListBuilder( - self._issuer_name, - last_update, - self._next_update, - self._extensions, - self._revoked_certificates, - ) - - def next_update( - self, next_update: datetime.datetime - ) -> CertificateRevocationListBuilder: - if not isinstance(next_update, datetime.datetime): - raise TypeError("Expecting datetime object.") - if self._next_update is not None: - raise ValueError("Last update may only be set once.") - next_update = _convert_to_naive_utc_time(next_update) - if next_update < _EARLIEST_UTC_TIME: - raise ValueError( - "The last update date must be on or after 1950 January 1." - ) - if self._last_update is not None and next_update < self._last_update: - raise ValueError( - "The next update date must be after the last update date." - ) - return CertificateRevocationListBuilder( - self._issuer_name, - self._last_update, - next_update, - self._extensions, - self._revoked_certificates, - ) - - def add_extension( - self, extval: ExtensionType, critical: bool - ) -> CertificateRevocationListBuilder: - """ - Adds an X.509 extension to the certificate revocation list. - """ - if not isinstance(extval, ExtensionType): - raise TypeError("extension must be an ExtensionType") - - extension = Extension(extval.oid, critical, extval) - _reject_duplicate_extension(extension, self._extensions) - return CertificateRevocationListBuilder( - self._issuer_name, - self._last_update, - self._next_update, - [*self._extensions, extension], - self._revoked_certificates, - ) - - def add_revoked_certificate( - self, revoked_certificate: RevokedCertificate - ) -> CertificateRevocationListBuilder: - """ - Adds a revoked certificate to the CRL. - """ - if not isinstance(revoked_certificate, RevokedCertificate): - raise TypeError("Must be an instance of RevokedCertificate") - - return CertificateRevocationListBuilder( - self._issuer_name, - self._last_update, - self._next_update, - self._extensions, - [*self._revoked_certificates, revoked_certificate], - ) - - def sign( - self, - private_key: CertificateIssuerPrivateKeyTypes, - algorithm: _AllowedHashTypes | None, - backend: typing.Any = None, - *, - rsa_padding: padding.PSS | padding.PKCS1v15 | None = None, - ecdsa_deterministic: bool | None = None, - ) -> CertificateRevocationList: - if self._issuer_name is None: - raise ValueError("A CRL must have an issuer name") - - if self._last_update is None: - raise ValueError("A CRL must have a last update time") - - if self._next_update is None: - raise ValueError("A CRL must have a next update time") - - if rsa_padding is not None: - if not isinstance(rsa_padding, (padding.PSS, padding.PKCS1v15)): - raise TypeError("Padding must be PSS or PKCS1v15") - if not isinstance(private_key, rsa.RSAPrivateKey): - raise TypeError("Padding is only supported for RSA keys") - - if ecdsa_deterministic is not None: - if not isinstance(private_key, ec.EllipticCurvePrivateKey): - raise TypeError( - "Deterministic ECDSA is only supported for EC keys" - ) - - return rust_x509.create_x509_crl( - self, - private_key, - algorithm, - rsa_padding, - ecdsa_deterministic, - ) - - -class RevokedCertificateBuilder: - def __init__( - self, - serial_number: int | None = None, - revocation_date: datetime.datetime | None = None, - extensions: list[Extension[ExtensionType]] = [], - ): - self._serial_number = serial_number - self._revocation_date = revocation_date - self._extensions = extensions - - def serial_number(self, number: int) -> RevokedCertificateBuilder: - if not isinstance(number, int): - raise TypeError("Serial number must be of integral type.") - if self._serial_number is not None: - raise ValueError("The serial number may only be set once.") - if number <= 0: - raise ValueError("The serial number should be positive") - - # ASN.1 integers are always signed, so most significant bit must be - # zero. - if number.bit_length() >= 160: # As defined in RFC 5280 - raise ValueError( - "The serial number should not be more than 159 bits." - ) - return RevokedCertificateBuilder( - number, self._revocation_date, self._extensions - ) - - def revocation_date( - self, time: datetime.datetime - ) -> RevokedCertificateBuilder: - if not isinstance(time, datetime.datetime): - raise TypeError("Expecting datetime object.") - if self._revocation_date is not None: - raise ValueError("The revocation date may only be set once.") - time = _convert_to_naive_utc_time(time) - if time < _EARLIEST_UTC_TIME: - raise ValueError( - "The revocation date must be on or after 1950 January 1." - ) - return RevokedCertificateBuilder( - self._serial_number, time, self._extensions - ) - - def add_extension( - self, extval: ExtensionType, critical: bool - ) -> RevokedCertificateBuilder: - if not isinstance(extval, ExtensionType): - raise TypeError("extension must be an ExtensionType") - - extension = Extension(extval.oid, critical, extval) - _reject_duplicate_extension(extension, self._extensions) - return RevokedCertificateBuilder( - self._serial_number, - self._revocation_date, - [*self._extensions, extension], - ) - - def build(self, backend: typing.Any = None) -> RevokedCertificate: - if self._serial_number is None: - raise ValueError("A revoked certificate must have a serial number") - if self._revocation_date is None: - raise ValueError( - "A revoked certificate must have a revocation date" - ) - return rust_x509.create_revoked_certificate(self) - - -def random_serial_number() -> int: - return int.from_bytes(os.urandom(20), "big") >> 1 diff --git a/venv/lib/python3.9/site-packages/cryptography/x509/certificate_transparency.py b/venv/lib/python3.9/site-packages/cryptography/x509/certificate_transparency.py deleted file mode 100644 index fb66cc6..0000000 --- a/venv/lib/python3.9/site-packages/cryptography/x509/certificate_transparency.py +++ /dev/null @@ -1,35 +0,0 @@ -# This file is dual licensed under the terms of the Apache License, Version -# 2.0, and the BSD License. See the LICENSE file in the root of this repository -# for complete details. - -from __future__ import annotations - -from cryptography import utils -from cryptography.hazmat.bindings._rust import x509 as rust_x509 - - -class LogEntryType(utils.Enum): - X509_CERTIFICATE = 0 - PRE_CERTIFICATE = 1 - - -class Version(utils.Enum): - v1 = 0 - - -class SignatureAlgorithm(utils.Enum): - """ - Signature algorithms that are valid for SCTs. - - These are exactly the same as SignatureAlgorithm in RFC 5246 (TLS 1.2). - - See: - """ - - ANONYMOUS = 0 - RSA = 1 - DSA = 2 - ECDSA = 3 - - -SignedCertificateTimestamp = rust_x509.Sct diff --git a/venv/lib/python3.9/site-packages/cryptography/x509/extensions.py b/venv/lib/python3.9/site-packages/cryptography/x509/extensions.py deleted file mode 100644 index 7b78e9e..0000000 --- a/venv/lib/python3.9/site-packages/cryptography/x509/extensions.py +++ /dev/null @@ -1,2533 +0,0 @@ -# This file is dual licensed under the terms of the Apache License, Version -# 2.0, and the BSD License. See the LICENSE file in the root of this repository -# for complete details. - -from __future__ import annotations - -import abc -import datetime -import hashlib -import ipaddress -import typing -from collections.abc import Iterable, Iterator - -from cryptography import utils -from cryptography.hazmat.bindings._rust import asn1 -from cryptography.hazmat.bindings._rust import x509 as rust_x509 -from cryptography.hazmat.primitives import constant_time, serialization -from cryptography.hazmat.primitives.asymmetric.ec import EllipticCurvePublicKey -from cryptography.hazmat.primitives.asymmetric.rsa import RSAPublicKey -from cryptography.hazmat.primitives.asymmetric.types import ( - CertificateIssuerPublicKeyTypes, - CertificatePublicKeyTypes, -) -from cryptography.x509.certificate_transparency import ( - SignedCertificateTimestamp, -) -from cryptography.x509.general_name import ( - DirectoryName, - DNSName, - GeneralName, - IPAddress, - OtherName, - RegisteredID, - RFC822Name, - UniformResourceIdentifier, - _IPAddressTypes, -) -from cryptography.x509.name import Name, RelativeDistinguishedName -from cryptography.x509.oid import ( - CRLEntryExtensionOID, - ExtensionOID, - ObjectIdentifier, - OCSPExtensionOID, -) - -ExtensionTypeVar = typing.TypeVar( - "ExtensionTypeVar", bound="ExtensionType", covariant=True -) - - -def _key_identifier_from_public_key( - public_key: CertificatePublicKeyTypes, -) -> bytes: - if isinstance(public_key, RSAPublicKey): - data = public_key.public_bytes( - serialization.Encoding.DER, - serialization.PublicFormat.PKCS1, - ) - elif isinstance(public_key, EllipticCurvePublicKey): - data = public_key.public_bytes( - serialization.Encoding.X962, - serialization.PublicFormat.UncompressedPoint, - ) - else: - # This is a very slow way to do this. - serialized = public_key.public_bytes( - serialization.Encoding.DER, - serialization.PublicFormat.SubjectPublicKeyInfo, - ) - data = asn1.parse_spki_for_data(serialized) - - return hashlib.sha1(data).digest() - - -def _make_sequence_methods(field_name: str): - def len_method(self) -> int: - return len(getattr(self, field_name)) - - def iter_method(self): - return iter(getattr(self, field_name)) - - def getitem_method(self, idx): - return getattr(self, field_name)[idx] - - return len_method, iter_method, getitem_method - - -class DuplicateExtension(Exception): - def __init__(self, msg: str, oid: ObjectIdentifier) -> None: - super().__init__(msg) - self.oid = oid - - -class ExtensionNotFound(Exception): - def __init__(self, msg: str, oid: ObjectIdentifier) -> None: - super().__init__(msg) - self.oid = oid - - -class ExtensionType(metaclass=abc.ABCMeta): - oid: typing.ClassVar[ObjectIdentifier] - - def public_bytes(self) -> bytes: - """ - Serializes the extension type to DER. - """ - raise NotImplementedError( - f"public_bytes is not implemented for extension type {self!r}" - ) - - -class Extensions: - def __init__(self, extensions: Iterable[Extension[ExtensionType]]) -> None: - self._extensions = list(extensions) - - def get_extension_for_oid( - self, oid: ObjectIdentifier - ) -> Extension[ExtensionType]: - for ext in self: - if ext.oid == oid: - return ext - - raise ExtensionNotFound(f"No {oid} extension was found", oid) - - def get_extension_for_class( - self, extclass: type[ExtensionTypeVar] - ) -> Extension[ExtensionTypeVar]: - if extclass is UnrecognizedExtension: - raise TypeError( - "UnrecognizedExtension can't be used with " - "get_extension_for_class because more than one instance of the" - " class may be present." - ) - - for ext in self: - if isinstance(ext.value, extclass): - return ext - - raise ExtensionNotFound( - f"No {extclass} extension was found", extclass.oid - ) - - __len__, __iter__, __getitem__ = _make_sequence_methods("_extensions") - - def __repr__(self) -> str: - return f"" - - -class CRLNumber(ExtensionType): - oid = ExtensionOID.CRL_NUMBER - - def __init__(self, crl_number: int) -> None: - if not isinstance(crl_number, int): - raise TypeError("crl_number must be an integer") - - self._crl_number = crl_number - - def __eq__(self, other: object) -> bool: - if not isinstance(other, CRLNumber): - return NotImplemented - - return self.crl_number == other.crl_number - - def __hash__(self) -> int: - return hash(self.crl_number) - - def __repr__(self) -> str: - return f"" - - @property - def crl_number(self) -> int: - return self._crl_number - - def public_bytes(self) -> bytes: - return rust_x509.encode_extension_value(self) - - -class AuthorityKeyIdentifier(ExtensionType): - oid = ExtensionOID.AUTHORITY_KEY_IDENTIFIER - - def __init__( - self, - key_identifier: bytes | None, - authority_cert_issuer: Iterable[GeneralName] | None, - authority_cert_serial_number: int | None, - ) -> None: - if (authority_cert_issuer is None) != ( - authority_cert_serial_number is None - ): - raise ValueError( - "authority_cert_issuer and authority_cert_serial_number " - "must both be present or both None" - ) - - if authority_cert_issuer is not None: - authority_cert_issuer = list(authority_cert_issuer) - if not all( - isinstance(x, GeneralName) for x in authority_cert_issuer - ): - raise TypeError( - "authority_cert_issuer must be a list of GeneralName " - "objects" - ) - - if authority_cert_serial_number is not None and not isinstance( - authority_cert_serial_number, int - ): - raise TypeError("authority_cert_serial_number must be an integer") - - self._key_identifier = key_identifier - self._authority_cert_issuer = authority_cert_issuer - self._authority_cert_serial_number = authority_cert_serial_number - - # This takes a subset of CertificatePublicKeyTypes because an issuer - # cannot have an X25519/X448 key. This introduces some unfortunate - # asymmetry that requires typing users to explicitly - # narrow their type, but we should make this accurate and not just - # convenient. - @classmethod - def from_issuer_public_key( - cls, public_key: CertificateIssuerPublicKeyTypes - ) -> AuthorityKeyIdentifier: - digest = _key_identifier_from_public_key(public_key) - return cls( - key_identifier=digest, - authority_cert_issuer=None, - authority_cert_serial_number=None, - ) - - @classmethod - def from_issuer_subject_key_identifier( - cls, ski: SubjectKeyIdentifier - ) -> AuthorityKeyIdentifier: - return cls( - key_identifier=ski.digest, - authority_cert_issuer=None, - authority_cert_serial_number=None, - ) - - def __repr__(self) -> str: - return ( - f"" - ) - - def __eq__(self, other: object) -> bool: - if not isinstance(other, AuthorityKeyIdentifier): - return NotImplemented - - return ( - self.key_identifier == other.key_identifier - and self.authority_cert_issuer == other.authority_cert_issuer - and self.authority_cert_serial_number - == other.authority_cert_serial_number - ) - - def __hash__(self) -> int: - if self.authority_cert_issuer is None: - aci = None - else: - aci = tuple(self.authority_cert_issuer) - return hash( - (self.key_identifier, aci, self.authority_cert_serial_number) - ) - - @property - def key_identifier(self) -> bytes | None: - return self._key_identifier - - @property - def authority_cert_issuer( - self, - ) -> list[GeneralName] | None: - return self._authority_cert_issuer - - @property - def authority_cert_serial_number(self) -> int | None: - return self._authority_cert_serial_number - - def public_bytes(self) -> bytes: - return rust_x509.encode_extension_value(self) - - -class SubjectKeyIdentifier(ExtensionType): - oid = ExtensionOID.SUBJECT_KEY_IDENTIFIER - - def __init__(self, digest: bytes) -> None: - self._digest = digest - - @classmethod - def from_public_key( - cls, public_key: CertificatePublicKeyTypes - ) -> SubjectKeyIdentifier: - return cls(_key_identifier_from_public_key(public_key)) - - @property - def digest(self) -> bytes: - return self._digest - - @property - def key_identifier(self) -> bytes: - return self._digest - - def __repr__(self) -> str: - return f"" - - def __eq__(self, other: object) -> bool: - if not isinstance(other, SubjectKeyIdentifier): - return NotImplemented - - return constant_time.bytes_eq(self.digest, other.digest) - - def __hash__(self) -> int: - return hash(self.digest) - - def public_bytes(self) -> bytes: - return rust_x509.encode_extension_value(self) - - -class AuthorityInformationAccess(ExtensionType): - oid = ExtensionOID.AUTHORITY_INFORMATION_ACCESS - - def __init__(self, descriptions: Iterable[AccessDescription]) -> None: - descriptions = list(descriptions) - if not all(isinstance(x, AccessDescription) for x in descriptions): - raise TypeError( - "Every item in the descriptions list must be an " - "AccessDescription" - ) - - self._descriptions = descriptions - - __len__, __iter__, __getitem__ = _make_sequence_methods("_descriptions") - - def __repr__(self) -> str: - return f"" - - def __eq__(self, other: object) -> bool: - if not isinstance(other, AuthorityInformationAccess): - return NotImplemented - - return self._descriptions == other._descriptions - - def __hash__(self) -> int: - return hash(tuple(self._descriptions)) - - def public_bytes(self) -> bytes: - return rust_x509.encode_extension_value(self) - - -class SubjectInformationAccess(ExtensionType): - oid = ExtensionOID.SUBJECT_INFORMATION_ACCESS - - def __init__(self, descriptions: Iterable[AccessDescription]) -> None: - descriptions = list(descriptions) - if not all(isinstance(x, AccessDescription) for x in descriptions): - raise TypeError( - "Every item in the descriptions list must be an " - "AccessDescription" - ) - - self._descriptions = descriptions - - __len__, __iter__, __getitem__ = _make_sequence_methods("_descriptions") - - def __repr__(self) -> str: - return f"" - - def __eq__(self, other: object) -> bool: - if not isinstance(other, SubjectInformationAccess): - return NotImplemented - - return self._descriptions == other._descriptions - - def __hash__(self) -> int: - return hash(tuple(self._descriptions)) - - def public_bytes(self) -> bytes: - return rust_x509.encode_extension_value(self) - - -class AccessDescription: - def __init__( - self, access_method: ObjectIdentifier, access_location: GeneralName - ) -> None: - if not isinstance(access_method, ObjectIdentifier): - raise TypeError("access_method must be an ObjectIdentifier") - - if not isinstance(access_location, GeneralName): - raise TypeError("access_location must be a GeneralName") - - self._access_method = access_method - self._access_location = access_location - - def __repr__(self) -> str: - return ( - f"" - ) - - def __eq__(self, other: object) -> bool: - if not isinstance(other, AccessDescription): - return NotImplemented - - return ( - self.access_method == other.access_method - and self.access_location == other.access_location - ) - - def __hash__(self) -> int: - return hash((self.access_method, self.access_location)) - - @property - def access_method(self) -> ObjectIdentifier: - return self._access_method - - @property - def access_location(self) -> GeneralName: - return self._access_location - - -class BasicConstraints(ExtensionType): - oid = ExtensionOID.BASIC_CONSTRAINTS - - def __init__(self, ca: bool, path_length: int | None) -> None: - if not isinstance(ca, bool): - raise TypeError("ca must be a boolean value") - - if path_length is not None and not ca: - raise ValueError("path_length must be None when ca is False") - - if path_length is not None and ( - not isinstance(path_length, int) or path_length < 0 - ): - raise TypeError( - "path_length must be a non-negative integer or None" - ) - - self._ca = ca - self._path_length = path_length - - @property - def ca(self) -> bool: - return self._ca - - @property - def path_length(self) -> int | None: - return self._path_length - - def __repr__(self) -> str: - return ( - f"" - ) - - def __eq__(self, other: object) -> bool: - if not isinstance(other, BasicConstraints): - return NotImplemented - - return self.ca == other.ca and self.path_length == other.path_length - - def __hash__(self) -> int: - return hash((self.ca, self.path_length)) - - def public_bytes(self) -> bytes: - return rust_x509.encode_extension_value(self) - - -class DeltaCRLIndicator(ExtensionType): - oid = ExtensionOID.DELTA_CRL_INDICATOR - - def __init__(self, crl_number: int) -> None: - if not isinstance(crl_number, int): - raise TypeError("crl_number must be an integer") - - self._crl_number = crl_number - - @property - def crl_number(self) -> int: - return self._crl_number - - def __eq__(self, other: object) -> bool: - if not isinstance(other, DeltaCRLIndicator): - return NotImplemented - - return self.crl_number == other.crl_number - - def __hash__(self) -> int: - return hash(self.crl_number) - - def __repr__(self) -> str: - return f"" - - def public_bytes(self) -> bytes: - return rust_x509.encode_extension_value(self) - - -class CRLDistributionPoints(ExtensionType): - oid = ExtensionOID.CRL_DISTRIBUTION_POINTS - - def __init__( - self, distribution_points: Iterable[DistributionPoint] - ) -> None: - distribution_points = list(distribution_points) - if not all( - isinstance(x, DistributionPoint) for x in distribution_points - ): - raise TypeError( - "distribution_points must be a list of DistributionPoint " - "objects" - ) - - self._distribution_points = distribution_points - - __len__, __iter__, __getitem__ = _make_sequence_methods( - "_distribution_points" - ) - - def __repr__(self) -> str: - return f"" - - def __eq__(self, other: object) -> bool: - if not isinstance(other, CRLDistributionPoints): - return NotImplemented - - return self._distribution_points == other._distribution_points - - def __hash__(self) -> int: - return hash(tuple(self._distribution_points)) - - def public_bytes(self) -> bytes: - return rust_x509.encode_extension_value(self) - - -class FreshestCRL(ExtensionType): - oid = ExtensionOID.FRESHEST_CRL - - def __init__( - self, distribution_points: Iterable[DistributionPoint] - ) -> None: - distribution_points = list(distribution_points) - if not all( - isinstance(x, DistributionPoint) for x in distribution_points - ): - raise TypeError( - "distribution_points must be a list of DistributionPoint " - "objects" - ) - - self._distribution_points = distribution_points - - __len__, __iter__, __getitem__ = _make_sequence_methods( - "_distribution_points" - ) - - def __repr__(self) -> str: - return f"" - - def __eq__(self, other: object) -> bool: - if not isinstance(other, FreshestCRL): - return NotImplemented - - return self._distribution_points == other._distribution_points - - def __hash__(self) -> int: - return hash(tuple(self._distribution_points)) - - def public_bytes(self) -> bytes: - return rust_x509.encode_extension_value(self) - - -class DistributionPoint: - def __init__( - self, - full_name: Iterable[GeneralName] | None, - relative_name: RelativeDistinguishedName | None, - reasons: frozenset[ReasonFlags] | None, - crl_issuer: Iterable[GeneralName] | None, - ) -> None: - if full_name and relative_name: - raise ValueError( - "You cannot provide both full_name and relative_name, at " - "least one must be None." - ) - if not full_name and not relative_name and not crl_issuer: - raise ValueError( - "Either full_name, relative_name or crl_issuer must be " - "provided." - ) - - if full_name is not None: - full_name = list(full_name) - if not all(isinstance(x, GeneralName) for x in full_name): - raise TypeError( - "full_name must be a list of GeneralName objects" - ) - - if relative_name: - if not isinstance(relative_name, RelativeDistinguishedName): - raise TypeError( - "relative_name must be a RelativeDistinguishedName" - ) - - if crl_issuer is not None: - crl_issuer = list(crl_issuer) - if not all(isinstance(x, GeneralName) for x in crl_issuer): - raise TypeError( - "crl_issuer must be None or a list of general names" - ) - - if reasons and ( - not isinstance(reasons, frozenset) - or not all(isinstance(x, ReasonFlags) for x in reasons) - ): - raise TypeError("reasons must be None or frozenset of ReasonFlags") - - if reasons and ( - ReasonFlags.unspecified in reasons - or ReasonFlags.remove_from_crl in reasons - ): - raise ValueError( - "unspecified and remove_from_crl are not valid reasons in a " - "DistributionPoint" - ) - - self._full_name = full_name - self._relative_name = relative_name - self._reasons = reasons - self._crl_issuer = crl_issuer - - def __repr__(self) -> str: - return ( - "".format(self) - ) - - def __eq__(self, other: object) -> bool: - if not isinstance(other, DistributionPoint): - return NotImplemented - - return ( - self.full_name == other.full_name - and self.relative_name == other.relative_name - and self.reasons == other.reasons - and self.crl_issuer == other.crl_issuer - ) - - def __hash__(self) -> int: - if self.full_name is not None: - fn: tuple[GeneralName, ...] | None = tuple(self.full_name) - else: - fn = None - - if self.crl_issuer is not None: - crl_issuer: tuple[GeneralName, ...] | None = tuple(self.crl_issuer) - else: - crl_issuer = None - - return hash((fn, self.relative_name, self.reasons, crl_issuer)) - - @property - def full_name(self) -> list[GeneralName] | None: - return self._full_name - - @property - def relative_name(self) -> RelativeDistinguishedName | None: - return self._relative_name - - @property - def reasons(self) -> frozenset[ReasonFlags] | None: - return self._reasons - - @property - def crl_issuer(self) -> list[GeneralName] | None: - return self._crl_issuer - - -class ReasonFlags(utils.Enum): - unspecified = "unspecified" - key_compromise = "keyCompromise" - ca_compromise = "cACompromise" - affiliation_changed = "affiliationChanged" - superseded = "superseded" - cessation_of_operation = "cessationOfOperation" - certificate_hold = "certificateHold" - privilege_withdrawn = "privilegeWithdrawn" - aa_compromise = "aACompromise" - remove_from_crl = "removeFromCRL" - - -# These are distribution point bit string mappings. Not to be confused with -# CRLReason reason flags bit string mappings. -# ReasonFlags ::= BIT STRING { -# unused (0), -# keyCompromise (1), -# cACompromise (2), -# affiliationChanged (3), -# superseded (4), -# cessationOfOperation (5), -# certificateHold (6), -# privilegeWithdrawn (7), -# aACompromise (8) } -_REASON_BIT_MAPPING = { - 1: ReasonFlags.key_compromise, - 2: ReasonFlags.ca_compromise, - 3: ReasonFlags.affiliation_changed, - 4: ReasonFlags.superseded, - 5: ReasonFlags.cessation_of_operation, - 6: ReasonFlags.certificate_hold, - 7: ReasonFlags.privilege_withdrawn, - 8: ReasonFlags.aa_compromise, -} - -_CRLREASONFLAGS = { - ReasonFlags.key_compromise: 1, - ReasonFlags.ca_compromise: 2, - ReasonFlags.affiliation_changed: 3, - ReasonFlags.superseded: 4, - ReasonFlags.cessation_of_operation: 5, - ReasonFlags.certificate_hold: 6, - ReasonFlags.privilege_withdrawn: 7, - ReasonFlags.aa_compromise: 8, -} - -# CRLReason ::= ENUMERATED { -# unspecified (0), -# keyCompromise (1), -# cACompromise (2), -# affiliationChanged (3), -# superseded (4), -# cessationOfOperation (5), -# certificateHold (6), -# -- value 7 is not used -# removeFromCRL (8), -# privilegeWithdrawn (9), -# aACompromise (10) } -_CRL_ENTRY_REASON_ENUM_TO_CODE = { - ReasonFlags.unspecified: 0, - ReasonFlags.key_compromise: 1, - ReasonFlags.ca_compromise: 2, - ReasonFlags.affiliation_changed: 3, - ReasonFlags.superseded: 4, - ReasonFlags.cessation_of_operation: 5, - ReasonFlags.certificate_hold: 6, - ReasonFlags.remove_from_crl: 8, - ReasonFlags.privilege_withdrawn: 9, - ReasonFlags.aa_compromise: 10, -} - - -class PolicyConstraints(ExtensionType): - oid = ExtensionOID.POLICY_CONSTRAINTS - - def __init__( - self, - require_explicit_policy: int | None, - inhibit_policy_mapping: int | None, - ) -> None: - if require_explicit_policy is not None and not isinstance( - require_explicit_policy, int - ): - raise TypeError( - "require_explicit_policy must be a non-negative integer or " - "None" - ) - - if inhibit_policy_mapping is not None and not isinstance( - inhibit_policy_mapping, int - ): - raise TypeError( - "inhibit_policy_mapping must be a non-negative integer or None" - ) - - if inhibit_policy_mapping is None and require_explicit_policy is None: - raise ValueError( - "At least one of require_explicit_policy and " - "inhibit_policy_mapping must not be None" - ) - - self._require_explicit_policy = require_explicit_policy - self._inhibit_policy_mapping = inhibit_policy_mapping - - def __repr__(self) -> str: - return ( - "".format(self) - ) - - def __eq__(self, other: object) -> bool: - if not isinstance(other, PolicyConstraints): - return NotImplemented - - return ( - self.require_explicit_policy == other.require_explicit_policy - and self.inhibit_policy_mapping == other.inhibit_policy_mapping - ) - - def __hash__(self) -> int: - return hash( - (self.require_explicit_policy, self.inhibit_policy_mapping) - ) - - @property - def require_explicit_policy(self) -> int | None: - return self._require_explicit_policy - - @property - def inhibit_policy_mapping(self) -> int | None: - return self._inhibit_policy_mapping - - def public_bytes(self) -> bytes: - return rust_x509.encode_extension_value(self) - - -class CertificatePolicies(ExtensionType): - oid = ExtensionOID.CERTIFICATE_POLICIES - - def __init__(self, policies: Iterable[PolicyInformation]) -> None: - policies = list(policies) - if not all(isinstance(x, PolicyInformation) for x in policies): - raise TypeError( - "Every item in the policies list must be a PolicyInformation" - ) - - self._policies = policies - - __len__, __iter__, __getitem__ = _make_sequence_methods("_policies") - - def __repr__(self) -> str: - return f"" - - def __eq__(self, other: object) -> bool: - if not isinstance(other, CertificatePolicies): - return NotImplemented - - return self._policies == other._policies - - def __hash__(self) -> int: - return hash(tuple(self._policies)) - - def public_bytes(self) -> bytes: - return rust_x509.encode_extension_value(self) - - -class PolicyInformation: - def __init__( - self, - policy_identifier: ObjectIdentifier, - policy_qualifiers: Iterable[str | UserNotice] | None, - ) -> None: - if not isinstance(policy_identifier, ObjectIdentifier): - raise TypeError("policy_identifier must be an ObjectIdentifier") - - self._policy_identifier = policy_identifier - - if policy_qualifiers is not None: - policy_qualifiers = list(policy_qualifiers) - if not all( - isinstance(x, (str, UserNotice)) for x in policy_qualifiers - ): - raise TypeError( - "policy_qualifiers must be a list of strings and/or " - "UserNotice objects or None" - ) - - self._policy_qualifiers = policy_qualifiers - - def __repr__(self) -> str: - return ( - f"" - ) - - def __eq__(self, other: object) -> bool: - if not isinstance(other, PolicyInformation): - return NotImplemented - - return ( - self.policy_identifier == other.policy_identifier - and self.policy_qualifiers == other.policy_qualifiers - ) - - def __hash__(self) -> int: - if self.policy_qualifiers is not None: - pq = tuple(self.policy_qualifiers) - else: - pq = None - - return hash((self.policy_identifier, pq)) - - @property - def policy_identifier(self) -> ObjectIdentifier: - return self._policy_identifier - - @property - def policy_qualifiers( - self, - ) -> list[str | UserNotice] | None: - return self._policy_qualifiers - - -class UserNotice: - def __init__( - self, - notice_reference: NoticeReference | None, - explicit_text: str | None, - ) -> None: - if notice_reference and not isinstance( - notice_reference, NoticeReference - ): - raise TypeError( - "notice_reference must be None or a NoticeReference" - ) - - self._notice_reference = notice_reference - self._explicit_text = explicit_text - - def __repr__(self) -> str: - return ( - f"" - ) - - def __eq__(self, other: object) -> bool: - if not isinstance(other, UserNotice): - return NotImplemented - - return ( - self.notice_reference == other.notice_reference - and self.explicit_text == other.explicit_text - ) - - def __hash__(self) -> int: - return hash((self.notice_reference, self.explicit_text)) - - @property - def notice_reference(self) -> NoticeReference | None: - return self._notice_reference - - @property - def explicit_text(self) -> str | None: - return self._explicit_text - - -class NoticeReference: - def __init__( - self, - organization: str | None, - notice_numbers: Iterable[int], - ) -> None: - self._organization = organization - notice_numbers = list(notice_numbers) - if not all(isinstance(x, int) for x in notice_numbers): - raise TypeError("notice_numbers must be a list of integers") - - self._notice_numbers = notice_numbers - - def __repr__(self) -> str: - return ( - f"" - ) - - def __eq__(self, other: object) -> bool: - if not isinstance(other, NoticeReference): - return NotImplemented - - return ( - self.organization == other.organization - and self.notice_numbers == other.notice_numbers - ) - - def __hash__(self) -> int: - return hash((self.organization, tuple(self.notice_numbers))) - - @property - def organization(self) -> str | None: - return self._organization - - @property - def notice_numbers(self) -> list[int]: - return self._notice_numbers - - -class ExtendedKeyUsage(ExtensionType): - oid = ExtensionOID.EXTENDED_KEY_USAGE - - def __init__(self, usages: Iterable[ObjectIdentifier]) -> None: - usages = list(usages) - if not all(isinstance(x, ObjectIdentifier) for x in usages): - raise TypeError( - "Every item in the usages list must be an ObjectIdentifier" - ) - - self._usages = usages - - __len__, __iter__, __getitem__ = _make_sequence_methods("_usages") - - def __repr__(self) -> str: - return f"" - - def __eq__(self, other: object) -> bool: - if not isinstance(other, ExtendedKeyUsage): - return NotImplemented - - return self._usages == other._usages - - def __hash__(self) -> int: - return hash(tuple(self._usages)) - - def public_bytes(self) -> bytes: - return rust_x509.encode_extension_value(self) - - -class OCSPNoCheck(ExtensionType): - oid = ExtensionOID.OCSP_NO_CHECK - - def __eq__(self, other: object) -> bool: - if not isinstance(other, OCSPNoCheck): - return NotImplemented - - return True - - def __hash__(self) -> int: - return hash(OCSPNoCheck) - - def __repr__(self) -> str: - return "" - - def public_bytes(self) -> bytes: - return rust_x509.encode_extension_value(self) - - -class PrecertPoison(ExtensionType): - oid = ExtensionOID.PRECERT_POISON - - def __eq__(self, other: object) -> bool: - if not isinstance(other, PrecertPoison): - return NotImplemented - - return True - - def __hash__(self) -> int: - return hash(PrecertPoison) - - def __repr__(self) -> str: - return "" - - def public_bytes(self) -> bytes: - return rust_x509.encode_extension_value(self) - - -class TLSFeature(ExtensionType): - oid = ExtensionOID.TLS_FEATURE - - def __init__(self, features: Iterable[TLSFeatureType]) -> None: - features = list(features) - if ( - not all(isinstance(x, TLSFeatureType) for x in features) - or len(features) == 0 - ): - raise TypeError( - "features must be a list of elements from the TLSFeatureType " - "enum" - ) - - self._features = features - - __len__, __iter__, __getitem__ = _make_sequence_methods("_features") - - def __repr__(self) -> str: - return f"" - - def __eq__(self, other: object) -> bool: - if not isinstance(other, TLSFeature): - return NotImplemented - - return self._features == other._features - - def __hash__(self) -> int: - return hash(tuple(self._features)) - - def public_bytes(self) -> bytes: - return rust_x509.encode_extension_value(self) - - -class TLSFeatureType(utils.Enum): - # status_request is defined in RFC 6066 and is used for what is commonly - # called OCSP Must-Staple when present in the TLS Feature extension in an - # X.509 certificate. - status_request = 5 - # status_request_v2 is defined in RFC 6961 and allows multiple OCSP - # responses to be provided. It is not currently in use by clients or - # servers. - status_request_v2 = 17 - - -_TLS_FEATURE_TYPE_TO_ENUM = {x.value: x for x in TLSFeatureType} - - -class InhibitAnyPolicy(ExtensionType): - oid = ExtensionOID.INHIBIT_ANY_POLICY - - def __init__(self, skip_certs: int) -> None: - if not isinstance(skip_certs, int): - raise TypeError("skip_certs must be an integer") - - if skip_certs < 0: - raise ValueError("skip_certs must be a non-negative integer") - - self._skip_certs = skip_certs - - def __repr__(self) -> str: - return f"" - - def __eq__(self, other: object) -> bool: - if not isinstance(other, InhibitAnyPolicy): - return NotImplemented - - return self.skip_certs == other.skip_certs - - def __hash__(self) -> int: - return hash(self.skip_certs) - - @property - def skip_certs(self) -> int: - return self._skip_certs - - def public_bytes(self) -> bytes: - return rust_x509.encode_extension_value(self) - - -class KeyUsage(ExtensionType): - oid = ExtensionOID.KEY_USAGE - - def __init__( - self, - digital_signature: bool, - content_commitment: bool, - key_encipherment: bool, - data_encipherment: bool, - key_agreement: bool, - key_cert_sign: bool, - crl_sign: bool, - encipher_only: bool, - decipher_only: bool, - ) -> None: - if not key_agreement and (encipher_only or decipher_only): - raise ValueError( - "encipher_only and decipher_only can only be true when " - "key_agreement is true" - ) - - self._digital_signature = digital_signature - self._content_commitment = content_commitment - self._key_encipherment = key_encipherment - self._data_encipherment = data_encipherment - self._key_agreement = key_agreement - self._key_cert_sign = key_cert_sign - self._crl_sign = crl_sign - self._encipher_only = encipher_only - self._decipher_only = decipher_only - - @property - def digital_signature(self) -> bool: - return self._digital_signature - - @property - def content_commitment(self) -> bool: - return self._content_commitment - - @property - def key_encipherment(self) -> bool: - return self._key_encipherment - - @property - def data_encipherment(self) -> bool: - return self._data_encipherment - - @property - def key_agreement(self) -> bool: - return self._key_agreement - - @property - def key_cert_sign(self) -> bool: - return self._key_cert_sign - - @property - def crl_sign(self) -> bool: - return self._crl_sign - - @property - def encipher_only(self) -> bool: - if not self.key_agreement: - raise ValueError( - "encipher_only is undefined unless key_agreement is true" - ) - else: - return self._encipher_only - - @property - def decipher_only(self) -> bool: - if not self.key_agreement: - raise ValueError( - "decipher_only is undefined unless key_agreement is true" - ) - else: - return self._decipher_only - - def __repr__(self) -> str: - try: - encipher_only = self.encipher_only - decipher_only = self.decipher_only - except ValueError: - # Users found None confusing because even though encipher/decipher - # have no meaning unless key_agreement is true, to construct an - # instance of the class you still need to pass False. - encipher_only = False - decipher_only = False - - return ( - f"" - ) - - def __eq__(self, other: object) -> bool: - if not isinstance(other, KeyUsage): - return NotImplemented - - return ( - self.digital_signature == other.digital_signature - and self.content_commitment == other.content_commitment - and self.key_encipherment == other.key_encipherment - and self.data_encipherment == other.data_encipherment - and self.key_agreement == other.key_agreement - and self.key_cert_sign == other.key_cert_sign - and self.crl_sign == other.crl_sign - and self._encipher_only == other._encipher_only - and self._decipher_only == other._decipher_only - ) - - def __hash__(self) -> int: - return hash( - ( - self.digital_signature, - self.content_commitment, - self.key_encipherment, - self.data_encipherment, - self.key_agreement, - self.key_cert_sign, - self.crl_sign, - self._encipher_only, - self._decipher_only, - ) - ) - - def public_bytes(self) -> bytes: - return rust_x509.encode_extension_value(self) - - -class PrivateKeyUsagePeriod(ExtensionType): - oid = ExtensionOID.PRIVATE_KEY_USAGE_PERIOD - - def __init__( - self, - not_before: datetime.datetime | None, - not_after: datetime.datetime | None, - ) -> None: - if ( - not isinstance(not_before, datetime.datetime) - and not_before is not None - ): - raise TypeError("not_before must be a datetime.datetime or None") - - if ( - not isinstance(not_after, datetime.datetime) - and not_after is not None - ): - raise TypeError("not_after must be a datetime.datetime or None") - - if not_before is None and not_after is None: - raise ValueError( - "At least one of not_before and not_after must not be None" - ) - - if ( - not_before is not None - and not_after is not None - and not_before > not_after - ): - raise ValueError("not_before must be before not_after") - - self._not_before = not_before - self._not_after = not_after - - @property - def not_before(self) -> datetime.datetime | None: - return self._not_before - - @property - def not_after(self) -> datetime.datetime | None: - return self._not_after - - def __repr__(self) -> str: - return ( - f"" - ) - - def __eq__(self, other: object) -> bool: - if not isinstance(other, PrivateKeyUsagePeriod): - return NotImplemented - - return ( - self.not_before == other.not_before - and self.not_after == other.not_after - ) - - def __hash__(self) -> int: - return hash((self.not_before, self.not_after)) - - def public_bytes(self) -> bytes: - return rust_x509.encode_extension_value(self) - - -class NameConstraints(ExtensionType): - oid = ExtensionOID.NAME_CONSTRAINTS - - def __init__( - self, - permitted_subtrees: Iterable[GeneralName] | None, - excluded_subtrees: Iterable[GeneralName] | None, - ) -> None: - if permitted_subtrees is not None: - permitted_subtrees = list(permitted_subtrees) - if not permitted_subtrees: - raise ValueError( - "permitted_subtrees must be a non-empty list or None" - ) - if not all(isinstance(x, GeneralName) for x in permitted_subtrees): - raise TypeError( - "permitted_subtrees must be a list of GeneralName objects " - "or None" - ) - - self._validate_tree(permitted_subtrees) - - if excluded_subtrees is not None: - excluded_subtrees = list(excluded_subtrees) - if not excluded_subtrees: - raise ValueError( - "excluded_subtrees must be a non-empty list or None" - ) - if not all(isinstance(x, GeneralName) for x in excluded_subtrees): - raise TypeError( - "excluded_subtrees must be a list of GeneralName objects " - "or None" - ) - - self._validate_tree(excluded_subtrees) - - if permitted_subtrees is None and excluded_subtrees is None: - raise ValueError( - "At least one of permitted_subtrees and excluded_subtrees " - "must not be None" - ) - - self._permitted_subtrees = permitted_subtrees - self._excluded_subtrees = excluded_subtrees - - def __eq__(self, other: object) -> bool: - if not isinstance(other, NameConstraints): - return NotImplemented - - return ( - self.excluded_subtrees == other.excluded_subtrees - and self.permitted_subtrees == other.permitted_subtrees - ) - - def _validate_tree(self, tree: Iterable[GeneralName]) -> None: - self._validate_ip_name(tree) - self._validate_dns_name(tree) - - def _validate_ip_name(self, tree: Iterable[GeneralName]) -> None: - if any( - isinstance(name, IPAddress) - and not isinstance( - name.value, (ipaddress.IPv4Network, ipaddress.IPv6Network) - ) - for name in tree - ): - raise TypeError( - "IPAddress name constraints must be an IPv4Network or" - " IPv6Network object" - ) - - def _validate_dns_name(self, tree: Iterable[GeneralName]) -> None: - if any( - isinstance(name, DNSName) and "*" in name.value for name in tree - ): - raise ValueError( - "DNSName name constraints must not contain the '*' wildcard" - " character" - ) - - def __repr__(self) -> str: - return ( - f"" - ) - - def __hash__(self) -> int: - if self.permitted_subtrees is not None: - ps: tuple[GeneralName, ...] | None = tuple(self.permitted_subtrees) - else: - ps = None - - if self.excluded_subtrees is not None: - es: tuple[GeneralName, ...] | None = tuple(self.excluded_subtrees) - else: - es = None - - return hash((ps, es)) - - @property - def permitted_subtrees( - self, - ) -> list[GeneralName] | None: - return self._permitted_subtrees - - @property - def excluded_subtrees( - self, - ) -> list[GeneralName] | None: - return self._excluded_subtrees - - def public_bytes(self) -> bytes: - return rust_x509.encode_extension_value(self) - - -class Extension(typing.Generic[ExtensionTypeVar]): - def __init__( - self, oid: ObjectIdentifier, critical: bool, value: ExtensionTypeVar - ) -> None: - if not isinstance(oid, ObjectIdentifier): - raise TypeError( - "oid argument must be an ObjectIdentifier instance." - ) - - if not isinstance(critical, bool): - raise TypeError("critical must be a boolean value") - - self._oid = oid - self._critical = critical - self._value = value - - @property - def oid(self) -> ObjectIdentifier: - return self._oid - - @property - def critical(self) -> bool: - return self._critical - - @property - def value(self) -> ExtensionTypeVar: - return self._value - - def __repr__(self) -> str: - return ( - f"" - ) - - def __eq__(self, other: object) -> bool: - if not isinstance(other, Extension): - return NotImplemented - - return ( - self.oid == other.oid - and self.critical == other.critical - and self.value == other.value - ) - - def __hash__(self) -> int: - return hash((self.oid, self.critical, self.value)) - - -class GeneralNames: - def __init__(self, general_names: Iterable[GeneralName]) -> None: - general_names = list(general_names) - if not all(isinstance(x, GeneralName) for x in general_names): - raise TypeError( - "Every item in the general_names list must be an " - "object conforming to the GeneralName interface" - ) - - self._general_names = general_names - - __len__, __iter__, __getitem__ = _make_sequence_methods("_general_names") - - @typing.overload - def get_values_for_type( - self, - type: type[DNSName] - | type[UniformResourceIdentifier] - | type[RFC822Name], - ) -> list[str]: ... - - @typing.overload - def get_values_for_type( - self, - type: type[DirectoryName], - ) -> list[Name]: ... - - @typing.overload - def get_values_for_type( - self, - type: type[RegisteredID], - ) -> list[ObjectIdentifier]: ... - - @typing.overload - def get_values_for_type( - self, type: type[IPAddress] - ) -> list[_IPAddressTypes]: ... - - @typing.overload - def get_values_for_type( - self, type: type[OtherName] - ) -> list[OtherName]: ... - - def get_values_for_type( - self, - type: type[DNSName] - | type[DirectoryName] - | type[IPAddress] - | type[OtherName] - | type[RFC822Name] - | type[RegisteredID] - | type[UniformResourceIdentifier], - ) -> ( - list[_IPAddressTypes] - | list[str] - | list[OtherName] - | list[Name] - | list[ObjectIdentifier] - ): - # Return the value of each GeneralName, except for OtherName instances - # which we return directly because it has two important properties not - # just one value. - objs = (i for i in self if isinstance(i, type)) - if type != OtherName: - return [i.value for i in objs] # type: ignore[return-value,unused-ignore] - return list(objs) # type: ignore[return-value,unused-ignore] - - def __repr__(self) -> str: - return f"" - - def __eq__(self, other: object) -> bool: - if not isinstance(other, GeneralNames): - return NotImplemented - - return self._general_names == other._general_names - - def __hash__(self) -> int: - return hash(tuple(self._general_names)) - - -class SubjectAlternativeName(ExtensionType): - oid = ExtensionOID.SUBJECT_ALTERNATIVE_NAME - - def __init__(self, general_names: Iterable[GeneralName]) -> None: - self._general_names = GeneralNames(general_names) - - __len__, __iter__, __getitem__ = _make_sequence_methods("_general_names") - - @typing.overload - def get_values_for_type( - self, - type: type[DNSName] - | type[UniformResourceIdentifier] - | type[RFC822Name], - ) -> list[str]: ... - - @typing.overload - def get_values_for_type( - self, - type: type[DirectoryName], - ) -> list[Name]: ... - - @typing.overload - def get_values_for_type( - self, - type: type[RegisteredID], - ) -> list[ObjectIdentifier]: ... - - @typing.overload - def get_values_for_type( - self, type: type[IPAddress] - ) -> list[_IPAddressTypes]: ... - - @typing.overload - def get_values_for_type( - self, type: type[OtherName] - ) -> list[OtherName]: ... - - def get_values_for_type( - self, - type: type[DNSName] - | type[DirectoryName] - | type[IPAddress] - | type[OtherName] - | type[RFC822Name] - | type[RegisteredID] - | type[UniformResourceIdentifier], - ) -> ( - list[_IPAddressTypes] - | list[str] - | list[OtherName] - | list[Name] - | list[ObjectIdentifier] - ): - return self._general_names.get_values_for_type(type) - - def __repr__(self) -> str: - return f"" - - def __eq__(self, other: object) -> bool: - if not isinstance(other, SubjectAlternativeName): - return NotImplemented - - return self._general_names == other._general_names - - def __hash__(self) -> int: - return hash(self._general_names) - - def public_bytes(self) -> bytes: - return rust_x509.encode_extension_value(self) - - -class IssuerAlternativeName(ExtensionType): - oid = ExtensionOID.ISSUER_ALTERNATIVE_NAME - - def __init__(self, general_names: Iterable[GeneralName]) -> None: - self._general_names = GeneralNames(general_names) - - __len__, __iter__, __getitem__ = _make_sequence_methods("_general_names") - - @typing.overload - def get_values_for_type( - self, - type: type[DNSName] - | type[UniformResourceIdentifier] - | type[RFC822Name], - ) -> list[str]: ... - - @typing.overload - def get_values_for_type( - self, - type: type[DirectoryName], - ) -> list[Name]: ... - - @typing.overload - def get_values_for_type( - self, - type: type[RegisteredID], - ) -> list[ObjectIdentifier]: ... - - @typing.overload - def get_values_for_type( - self, type: type[IPAddress] - ) -> list[_IPAddressTypes]: ... - - @typing.overload - def get_values_for_type( - self, type: type[OtherName] - ) -> list[OtherName]: ... - - def get_values_for_type( - self, - type: type[DNSName] - | type[DirectoryName] - | type[IPAddress] - | type[OtherName] - | type[RFC822Name] - | type[RegisteredID] - | type[UniformResourceIdentifier], - ) -> ( - list[_IPAddressTypes] - | list[str] - | list[OtherName] - | list[Name] - | list[ObjectIdentifier] - ): - return self._general_names.get_values_for_type(type) - - def __repr__(self) -> str: - return f"" - - def __eq__(self, other: object) -> bool: - if not isinstance(other, IssuerAlternativeName): - return NotImplemented - - return self._general_names == other._general_names - - def __hash__(self) -> int: - return hash(self._general_names) - - def public_bytes(self) -> bytes: - return rust_x509.encode_extension_value(self) - - -class CertificateIssuer(ExtensionType): - oid = CRLEntryExtensionOID.CERTIFICATE_ISSUER - - def __init__(self, general_names: Iterable[GeneralName]) -> None: - self._general_names = GeneralNames(general_names) - - __len__, __iter__, __getitem__ = _make_sequence_methods("_general_names") - - @typing.overload - def get_values_for_type( - self, - type: type[DNSName] - | type[UniformResourceIdentifier] - | type[RFC822Name], - ) -> list[str]: ... - - @typing.overload - def get_values_for_type( - self, - type: type[DirectoryName], - ) -> list[Name]: ... - - @typing.overload - def get_values_for_type( - self, - type: type[RegisteredID], - ) -> list[ObjectIdentifier]: ... - - @typing.overload - def get_values_for_type( - self, type: type[IPAddress] - ) -> list[_IPAddressTypes]: ... - - @typing.overload - def get_values_for_type( - self, type: type[OtherName] - ) -> list[OtherName]: ... - - def get_values_for_type( - self, - type: type[DNSName] - | type[DirectoryName] - | type[IPAddress] - | type[OtherName] - | type[RFC822Name] - | type[RegisteredID] - | type[UniformResourceIdentifier], - ) -> ( - list[_IPAddressTypes] - | list[str] - | list[OtherName] - | list[Name] - | list[ObjectIdentifier] - ): - return self._general_names.get_values_for_type(type) - - def __repr__(self) -> str: - return f"" - - def __eq__(self, other: object) -> bool: - if not isinstance(other, CertificateIssuer): - return NotImplemented - - return self._general_names == other._general_names - - def __hash__(self) -> int: - return hash(self._general_names) - - def public_bytes(self) -> bytes: - return rust_x509.encode_extension_value(self) - - -class CRLReason(ExtensionType): - oid = CRLEntryExtensionOID.CRL_REASON - - def __init__(self, reason: ReasonFlags) -> None: - if not isinstance(reason, ReasonFlags): - raise TypeError("reason must be an element from ReasonFlags") - - self._reason = reason - - def __repr__(self) -> str: - return f"" - - def __eq__(self, other: object) -> bool: - if not isinstance(other, CRLReason): - return NotImplemented - - return self.reason == other.reason - - def __hash__(self) -> int: - return hash(self.reason) - - @property - def reason(self) -> ReasonFlags: - return self._reason - - def public_bytes(self) -> bytes: - return rust_x509.encode_extension_value(self) - - -class InvalidityDate(ExtensionType): - oid = CRLEntryExtensionOID.INVALIDITY_DATE - - def __init__(self, invalidity_date: datetime.datetime) -> None: - if not isinstance(invalidity_date, datetime.datetime): - raise TypeError("invalidity_date must be a datetime.datetime") - - self._invalidity_date = invalidity_date - - def __repr__(self) -> str: - return f"" - - def __eq__(self, other: object) -> bool: - if not isinstance(other, InvalidityDate): - return NotImplemented - - return self.invalidity_date == other.invalidity_date - - def __hash__(self) -> int: - return hash(self.invalidity_date) - - @property - def invalidity_date(self) -> datetime.datetime: - return self._invalidity_date - - @property - def invalidity_date_utc(self) -> datetime.datetime: - if self._invalidity_date.tzinfo is None: - return self._invalidity_date.replace(tzinfo=datetime.timezone.utc) - else: - return self._invalidity_date.astimezone(tz=datetime.timezone.utc) - - def public_bytes(self) -> bytes: - return rust_x509.encode_extension_value(self) - - -class PrecertificateSignedCertificateTimestamps(ExtensionType): - oid = ExtensionOID.PRECERT_SIGNED_CERTIFICATE_TIMESTAMPS - - def __init__( - self, - signed_certificate_timestamps: Iterable[SignedCertificateTimestamp], - ) -> None: - signed_certificate_timestamps = list(signed_certificate_timestamps) - if not all( - isinstance(sct, SignedCertificateTimestamp) - for sct in signed_certificate_timestamps - ): - raise TypeError( - "Every item in the signed_certificate_timestamps list must be " - "a SignedCertificateTimestamp" - ) - self._signed_certificate_timestamps = signed_certificate_timestamps - - __len__, __iter__, __getitem__ = _make_sequence_methods( - "_signed_certificate_timestamps" - ) - - def __repr__(self) -> str: - return f"" - - def __hash__(self) -> int: - return hash(tuple(self._signed_certificate_timestamps)) - - def __eq__(self, other: object) -> bool: - if not isinstance(other, PrecertificateSignedCertificateTimestamps): - return NotImplemented - - return ( - self._signed_certificate_timestamps - == other._signed_certificate_timestamps - ) - - def public_bytes(self) -> bytes: - return rust_x509.encode_extension_value(self) - - -class SignedCertificateTimestamps(ExtensionType): - oid = ExtensionOID.SIGNED_CERTIFICATE_TIMESTAMPS - - def __init__( - self, - signed_certificate_timestamps: Iterable[SignedCertificateTimestamp], - ) -> None: - signed_certificate_timestamps = list(signed_certificate_timestamps) - if not all( - isinstance(sct, SignedCertificateTimestamp) - for sct in signed_certificate_timestamps - ): - raise TypeError( - "Every item in the signed_certificate_timestamps list must be " - "a SignedCertificateTimestamp" - ) - self._signed_certificate_timestamps = signed_certificate_timestamps - - __len__, __iter__, __getitem__ = _make_sequence_methods( - "_signed_certificate_timestamps" - ) - - def __repr__(self) -> str: - return f"" - - def __hash__(self) -> int: - return hash(tuple(self._signed_certificate_timestamps)) - - def __eq__(self, other: object) -> bool: - if not isinstance(other, SignedCertificateTimestamps): - return NotImplemented - - return ( - self._signed_certificate_timestamps - == other._signed_certificate_timestamps - ) - - def public_bytes(self) -> bytes: - return rust_x509.encode_extension_value(self) - - -class OCSPNonce(ExtensionType): - oid = OCSPExtensionOID.NONCE - - def __init__(self, nonce: bytes) -> None: - if not isinstance(nonce, bytes): - raise TypeError("nonce must be bytes") - - self._nonce = nonce - - def __eq__(self, other: object) -> bool: - if not isinstance(other, OCSPNonce): - return NotImplemented - - return self.nonce == other.nonce - - def __hash__(self) -> int: - return hash(self.nonce) - - def __repr__(self) -> str: - return f"" - - @property - def nonce(self) -> bytes: - return self._nonce - - def public_bytes(self) -> bytes: - return rust_x509.encode_extension_value(self) - - -class OCSPAcceptableResponses(ExtensionType): - oid = OCSPExtensionOID.ACCEPTABLE_RESPONSES - - def __init__(self, responses: Iterable[ObjectIdentifier]) -> None: - responses = list(responses) - if any(not isinstance(r, ObjectIdentifier) for r in responses): - raise TypeError("All responses must be ObjectIdentifiers") - - self._responses = responses - - def __eq__(self, other: object) -> bool: - if not isinstance(other, OCSPAcceptableResponses): - return NotImplemented - - return self._responses == other._responses - - def __hash__(self) -> int: - return hash(tuple(self._responses)) - - def __repr__(self) -> str: - return f"" - - def __iter__(self) -> Iterator[ObjectIdentifier]: - return iter(self._responses) - - def public_bytes(self) -> bytes: - return rust_x509.encode_extension_value(self) - - -class IssuingDistributionPoint(ExtensionType): - oid = ExtensionOID.ISSUING_DISTRIBUTION_POINT - - def __init__( - self, - full_name: Iterable[GeneralName] | None, - relative_name: RelativeDistinguishedName | None, - only_contains_user_certs: bool, - only_contains_ca_certs: bool, - only_some_reasons: frozenset[ReasonFlags] | None, - indirect_crl: bool, - only_contains_attribute_certs: bool, - ) -> None: - if full_name is not None: - full_name = list(full_name) - - if only_some_reasons and ( - not isinstance(only_some_reasons, frozenset) - or not all(isinstance(x, ReasonFlags) for x in only_some_reasons) - ): - raise TypeError( - "only_some_reasons must be None or frozenset of ReasonFlags" - ) - - if only_some_reasons and ( - ReasonFlags.unspecified in only_some_reasons - or ReasonFlags.remove_from_crl in only_some_reasons - ): - raise ValueError( - "unspecified and remove_from_crl are not valid reasons in an " - "IssuingDistributionPoint" - ) - - if not ( - isinstance(only_contains_user_certs, bool) - and isinstance(only_contains_ca_certs, bool) - and isinstance(indirect_crl, bool) - and isinstance(only_contains_attribute_certs, bool) - ): - raise TypeError( - "only_contains_user_certs, only_contains_ca_certs, " - "indirect_crl and only_contains_attribute_certs " - "must all be boolean." - ) - - # Per RFC5280 Section 5.2.5, the Issuing Distribution Point extension - # in a CRL can have only one of onlyContainsUserCerts, - # onlyContainsCACerts, onlyContainsAttributeCerts set to TRUE. - crl_constraints = [ - only_contains_user_certs, - only_contains_ca_certs, - only_contains_attribute_certs, - ] - - if len([x for x in crl_constraints if x]) > 1: - raise ValueError( - "Only one of the following can be set to True: " - "only_contains_user_certs, only_contains_ca_certs, " - "only_contains_attribute_certs" - ) - - if not any( - [ - only_contains_user_certs, - only_contains_ca_certs, - indirect_crl, - only_contains_attribute_certs, - full_name, - relative_name, - only_some_reasons, - ] - ): - raise ValueError( - "Cannot create empty extension: " - "if only_contains_user_certs, only_contains_ca_certs, " - "indirect_crl, and only_contains_attribute_certs are all False" - ", then either full_name, relative_name, or only_some_reasons " - "must have a value." - ) - - self._only_contains_user_certs = only_contains_user_certs - self._only_contains_ca_certs = only_contains_ca_certs - self._indirect_crl = indirect_crl - self._only_contains_attribute_certs = only_contains_attribute_certs - self._only_some_reasons = only_some_reasons - self._full_name = full_name - self._relative_name = relative_name - - def __repr__(self) -> str: - return ( - f"" - ) - - def __eq__(self, other: object) -> bool: - if not isinstance(other, IssuingDistributionPoint): - return NotImplemented - - return ( - self.full_name == other.full_name - and self.relative_name == other.relative_name - and self.only_contains_user_certs == other.only_contains_user_certs - and self.only_contains_ca_certs == other.only_contains_ca_certs - and self.only_some_reasons == other.only_some_reasons - and self.indirect_crl == other.indirect_crl - and self.only_contains_attribute_certs - == other.only_contains_attribute_certs - ) - - def __hash__(self) -> int: - if self.full_name is not None: - full_name: tuple[GeneralName, ...] | None = tuple(self.full_name) - else: - full_name = None - - return hash( - ( - full_name, - self.relative_name, - self.only_contains_user_certs, - self.only_contains_ca_certs, - self.only_some_reasons, - self.indirect_crl, - self.only_contains_attribute_certs, - ) - ) - - @property - def full_name(self) -> list[GeneralName] | None: - return self._full_name - - @property - def relative_name(self) -> RelativeDistinguishedName | None: - return self._relative_name - - @property - def only_contains_user_certs(self) -> bool: - return self._only_contains_user_certs - - @property - def only_contains_ca_certs(self) -> bool: - return self._only_contains_ca_certs - - @property - def only_some_reasons( - self, - ) -> frozenset[ReasonFlags] | None: - return self._only_some_reasons - - @property - def indirect_crl(self) -> bool: - return self._indirect_crl - - @property - def only_contains_attribute_certs(self) -> bool: - return self._only_contains_attribute_certs - - def public_bytes(self) -> bytes: - return rust_x509.encode_extension_value(self) - - -class MSCertificateTemplate(ExtensionType): - oid = ExtensionOID.MS_CERTIFICATE_TEMPLATE - - def __init__( - self, - template_id: ObjectIdentifier, - major_version: int | None, - minor_version: int | None, - ) -> None: - if not isinstance(template_id, ObjectIdentifier): - raise TypeError("oid must be an ObjectIdentifier") - self._template_id = template_id - if ( - major_version is not None and not isinstance(major_version, int) - ) or ( - minor_version is not None and not isinstance(minor_version, int) - ): - raise TypeError( - "major_version and minor_version must be integers or None" - ) - self._major_version = major_version - self._minor_version = minor_version - - @property - def template_id(self) -> ObjectIdentifier: - return self._template_id - - @property - def major_version(self) -> int | None: - return self._major_version - - @property - def minor_version(self) -> int | None: - return self._minor_version - - def __repr__(self) -> str: - return ( - f"" - ) - - def __eq__(self, other: object) -> bool: - if not isinstance(other, MSCertificateTemplate): - return NotImplemented - - return ( - self.template_id == other.template_id - and self.major_version == other.major_version - and self.minor_version == other.minor_version - ) - - def __hash__(self) -> int: - return hash((self.template_id, self.major_version, self.minor_version)) - - def public_bytes(self) -> bytes: - return rust_x509.encode_extension_value(self) - - -class NamingAuthority: - def __init__( - self, - id: ObjectIdentifier | None, - url: str | None, - text: str | None, - ) -> None: - if id is not None and not isinstance(id, ObjectIdentifier): - raise TypeError("id must be an ObjectIdentifier") - - if url is not None and not isinstance(url, str): - raise TypeError("url must be a str") - - if text is not None and not isinstance(text, str): - raise TypeError("text must be a str") - - self._id = id - self._url = url - self._text = text - - @property - def id(self) -> ObjectIdentifier | None: - return self._id - - @property - def url(self) -> str | None: - return self._url - - @property - def text(self) -> str | None: - return self._text - - def __repr__(self) -> str: - return ( - f"" - ) - - def __eq__(self, other: object) -> bool: - if not isinstance(other, NamingAuthority): - return NotImplemented - - return ( - self.id == other.id - and self.url == other.url - and self.text == other.text - ) - - def __hash__(self) -> int: - return hash( - ( - self.id, - self.url, - self.text, - ) - ) - - -class ProfessionInfo: - def __init__( - self, - naming_authority: NamingAuthority | None, - profession_items: Iterable[str], - profession_oids: Iterable[ObjectIdentifier] | None, - registration_number: str | None, - add_profession_info: bytes | None, - ) -> None: - if naming_authority is not None and not isinstance( - naming_authority, NamingAuthority - ): - raise TypeError("naming_authority must be a NamingAuthority") - - profession_items = list(profession_items) - if not all(isinstance(item, str) for item in profession_items): - raise TypeError( - "Every item in the profession_items list must be a str" - ) - - if profession_oids is not None: - profession_oids = list(profession_oids) - if not all( - isinstance(oid, ObjectIdentifier) for oid in profession_oids - ): - raise TypeError( - "Every item in the profession_oids list must be an " - "ObjectIdentifier" - ) - - if registration_number is not None and not isinstance( - registration_number, str - ): - raise TypeError("registration_number must be a str") - - if add_profession_info is not None and not isinstance( - add_profession_info, bytes - ): - raise TypeError("add_profession_info must be bytes") - - self._naming_authority = naming_authority - self._profession_items = profession_items - self._profession_oids = profession_oids - self._registration_number = registration_number - self._add_profession_info = add_profession_info - - @property - def naming_authority(self) -> NamingAuthority | None: - return self._naming_authority - - @property - def profession_items(self) -> list[str]: - return self._profession_items - - @property - def profession_oids(self) -> list[ObjectIdentifier] | None: - return self._profession_oids - - @property - def registration_number(self) -> str | None: - return self._registration_number - - @property - def add_profession_info(self) -> bytes | None: - return self._add_profession_info - - def __repr__(self) -> str: - return ( - f"" - ) - - def __eq__(self, other: object) -> bool: - if not isinstance(other, ProfessionInfo): - return NotImplemented - - return ( - self.naming_authority == other.naming_authority - and self.profession_items == other.profession_items - and self.profession_oids == other.profession_oids - and self.registration_number == other.registration_number - and self.add_profession_info == other.add_profession_info - ) - - def __hash__(self) -> int: - if self.profession_oids is not None: - profession_oids = tuple(self.profession_oids) - else: - profession_oids = None - return hash( - ( - self.naming_authority, - tuple(self.profession_items), - profession_oids, - self.registration_number, - self.add_profession_info, - ) - ) - - -class Admission: - def __init__( - self, - admission_authority: GeneralName | None, - naming_authority: NamingAuthority | None, - profession_infos: Iterable[ProfessionInfo], - ) -> None: - if admission_authority is not None and not isinstance( - admission_authority, GeneralName - ): - raise TypeError("admission_authority must be a GeneralName") - - if naming_authority is not None and not isinstance( - naming_authority, NamingAuthority - ): - raise TypeError("naming_authority must be a NamingAuthority") - - profession_infos = list(profession_infos) - if not all( - isinstance(info, ProfessionInfo) for info in profession_infos - ): - raise TypeError( - "Every item in the profession_infos list must be a " - "ProfessionInfo" - ) - - self._admission_authority = admission_authority - self._naming_authority = naming_authority - self._profession_infos = profession_infos - - @property - def admission_authority(self) -> GeneralName | None: - return self._admission_authority - - @property - def naming_authority(self) -> NamingAuthority | None: - return self._naming_authority - - @property - def profession_infos(self) -> list[ProfessionInfo]: - return self._profession_infos - - def __repr__(self) -> str: - return ( - f"" - ) - - def __eq__(self, other: object) -> bool: - if not isinstance(other, Admission): - return NotImplemented - - return ( - self.admission_authority == other.admission_authority - and self.naming_authority == other.naming_authority - and self.profession_infos == other.profession_infos - ) - - def __hash__(self) -> int: - return hash( - ( - self.admission_authority, - self.naming_authority, - tuple(self.profession_infos), - ) - ) - - -class Admissions(ExtensionType): - oid = ExtensionOID.ADMISSIONS - - def __init__( - self, - authority: GeneralName | None, - admissions: Iterable[Admission], - ) -> None: - if authority is not None and not isinstance(authority, GeneralName): - raise TypeError("authority must be a GeneralName") - - admissions = list(admissions) - if not all( - isinstance(admission, Admission) for admission in admissions - ): - raise TypeError( - "Every item in the contents_of_admissions list must be an " - "Admission" - ) - - self._authority = authority - self._admissions = admissions - - __len__, __iter__, __getitem__ = _make_sequence_methods("_admissions") - - @property - def authority(self) -> GeneralName | None: - return self._authority - - def __repr__(self) -> str: - return ( - f"" - ) - - def __eq__(self, other: object) -> bool: - if not isinstance(other, Admissions): - return NotImplemented - - return ( - self.authority == other.authority - and self._admissions == other._admissions - ) - - def __hash__(self) -> int: - return hash((self.authority, tuple(self._admissions))) - - def public_bytes(self) -> bytes: - return rust_x509.encode_extension_value(self) - - -class UnrecognizedExtension(ExtensionType): - def __init__(self, oid: ObjectIdentifier, value: bytes) -> None: - if not isinstance(oid, ObjectIdentifier): - raise TypeError("oid must be an ObjectIdentifier") - self._oid = oid - self._value = value - - @property - def oid(self) -> ObjectIdentifier: # type: ignore[override] - return self._oid - - @property - def value(self) -> bytes: - return self._value - - def __repr__(self) -> str: - return f"" - - def __eq__(self, other: object) -> bool: - if not isinstance(other, UnrecognizedExtension): - return NotImplemented - - return self.oid == other.oid and self.value == other.value - - def __hash__(self) -> int: - return hash((self.oid, self.value)) - - def public_bytes(self) -> bytes: - return self.value diff --git a/venv/lib/python3.9/site-packages/cryptography/x509/general_name.py b/venv/lib/python3.9/site-packages/cryptography/x509/general_name.py deleted file mode 100644 index 672f287..0000000 --- a/venv/lib/python3.9/site-packages/cryptography/x509/general_name.py +++ /dev/null @@ -1,281 +0,0 @@ -# This file is dual licensed under the terms of the Apache License, Version -# 2.0, and the BSD License. See the LICENSE file in the root of this repository -# for complete details. - -from __future__ import annotations - -import abc -import ipaddress -import typing -from email.utils import parseaddr - -from cryptography.x509.name import Name -from cryptography.x509.oid import ObjectIdentifier - -_IPAddressTypes = typing.Union[ - ipaddress.IPv4Address, - ipaddress.IPv6Address, - ipaddress.IPv4Network, - ipaddress.IPv6Network, -] - - -class UnsupportedGeneralNameType(Exception): - pass - - -class GeneralName(metaclass=abc.ABCMeta): - @property - @abc.abstractmethod - def value(self) -> typing.Any: - """ - Return the value of the object - """ - - -class RFC822Name(GeneralName): - def __init__(self, value: str) -> None: - if isinstance(value, str): - try: - value.encode("ascii") - except UnicodeEncodeError: - raise ValueError( - "RFC822Name values should be passed as an A-label string. " - "This means unicode characters should be encoded via " - "a library like idna." - ) - else: - raise TypeError("value must be string") - - name, address = parseaddr(value) - if name or not address: - # parseaddr has found a name (e.g. Name ) or the entire - # value is an empty string. - raise ValueError("Invalid rfc822name value") - - self._value = value - - @property - def value(self) -> str: - return self._value - - @classmethod - def _init_without_validation(cls, value: str) -> RFC822Name: - instance = cls.__new__(cls) - instance._value = value - return instance - - def __repr__(self) -> str: - return f"" - - def __eq__(self, other: object) -> bool: - if not isinstance(other, RFC822Name): - return NotImplemented - - return self.value == other.value - - def __hash__(self) -> int: - return hash(self.value) - - -class DNSName(GeneralName): - def __init__(self, value: str) -> None: - if isinstance(value, str): - try: - value.encode("ascii") - except UnicodeEncodeError: - raise ValueError( - "DNSName values should be passed as an A-label string. " - "This means unicode characters should be encoded via " - "a library like idna." - ) - else: - raise TypeError("value must be string") - - self._value = value - - @property - def value(self) -> str: - return self._value - - @classmethod - def _init_without_validation(cls, value: str) -> DNSName: - instance = cls.__new__(cls) - instance._value = value - return instance - - def __repr__(self) -> str: - return f"" - - def __eq__(self, other: object) -> bool: - if not isinstance(other, DNSName): - return NotImplemented - - return self.value == other.value - - def __hash__(self) -> int: - return hash(self.value) - - -class UniformResourceIdentifier(GeneralName): - def __init__(self, value: str) -> None: - if isinstance(value, str): - try: - value.encode("ascii") - except UnicodeEncodeError: - raise ValueError( - "URI values should be passed as an A-label string. " - "This means unicode characters should be encoded via " - "a library like idna." - ) - else: - raise TypeError("value must be string") - - self._value = value - - @property - def value(self) -> str: - return self._value - - @classmethod - def _init_without_validation(cls, value: str) -> UniformResourceIdentifier: - instance = cls.__new__(cls) - instance._value = value - return instance - - def __repr__(self) -> str: - return f"" - - def __eq__(self, other: object) -> bool: - if not isinstance(other, UniformResourceIdentifier): - return NotImplemented - - return self.value == other.value - - def __hash__(self) -> int: - return hash(self.value) - - -class DirectoryName(GeneralName): - def __init__(self, value: Name) -> None: - if not isinstance(value, Name): - raise TypeError("value must be a Name") - - self._value = value - - @property - def value(self) -> Name: - return self._value - - def __repr__(self) -> str: - return f"" - - def __eq__(self, other: object) -> bool: - if not isinstance(other, DirectoryName): - return NotImplemented - - return self.value == other.value - - def __hash__(self) -> int: - return hash(self.value) - - -class RegisteredID(GeneralName): - def __init__(self, value: ObjectIdentifier) -> None: - if not isinstance(value, ObjectIdentifier): - raise TypeError("value must be an ObjectIdentifier") - - self._value = value - - @property - def value(self) -> ObjectIdentifier: - return self._value - - def __repr__(self) -> str: - return f"" - - def __eq__(self, other: object) -> bool: - if not isinstance(other, RegisteredID): - return NotImplemented - - return self.value == other.value - - def __hash__(self) -> int: - return hash(self.value) - - -class IPAddress(GeneralName): - def __init__(self, value: _IPAddressTypes) -> None: - if not isinstance( - value, - ( - ipaddress.IPv4Address, - ipaddress.IPv6Address, - ipaddress.IPv4Network, - ipaddress.IPv6Network, - ), - ): - raise TypeError( - "value must be an instance of ipaddress.IPv4Address, " - "ipaddress.IPv6Address, ipaddress.IPv4Network, or " - "ipaddress.IPv6Network" - ) - - self._value = value - - @property - def value(self) -> _IPAddressTypes: - return self._value - - def _packed(self) -> bytes: - if isinstance( - self.value, (ipaddress.IPv4Address, ipaddress.IPv6Address) - ): - return self.value.packed - else: - return ( - self.value.network_address.packed + self.value.netmask.packed - ) - - def __repr__(self) -> str: - return f"" - - def __eq__(self, other: object) -> bool: - if not isinstance(other, IPAddress): - return NotImplemented - - return self.value == other.value - - def __hash__(self) -> int: - return hash(self.value) - - -class OtherName(GeneralName): - def __init__(self, type_id: ObjectIdentifier, value: bytes) -> None: - if not isinstance(type_id, ObjectIdentifier): - raise TypeError("type_id must be an ObjectIdentifier") - if not isinstance(value, bytes): - raise TypeError("value must be a binary string") - - self._type_id = type_id - self._value = value - - @property - def type_id(self) -> ObjectIdentifier: - return self._type_id - - @property - def value(self) -> bytes: - return self._value - - def __repr__(self) -> str: - return f"" - - def __eq__(self, other: object) -> bool: - if not isinstance(other, OtherName): - return NotImplemented - - return self.type_id == other.type_id and self.value == other.value - - def __hash__(self) -> int: - return hash((self.type_id, self.value)) diff --git a/venv/lib/python3.9/site-packages/cryptography/x509/name.py b/venv/lib/python3.9/site-packages/cryptography/x509/name.py deleted file mode 100644 index 907f96a..0000000 --- a/venv/lib/python3.9/site-packages/cryptography/x509/name.py +++ /dev/null @@ -1,482 +0,0 @@ -# This file is dual licensed under the terms of the Apache License, Version -# 2.0, and the BSD License. See the LICENSE file in the root of this repository -# for complete details. - -from __future__ import annotations - -import binascii -import re -import sys -import typing -import warnings -from collections.abc import Iterable, Iterator - -from cryptography import utils -from cryptography.hazmat.bindings._rust import x509 as rust_x509 -from cryptography.x509.oid import NameOID, ObjectIdentifier - - -class _ASN1Type(utils.Enum): - BitString = 3 - OctetString = 4 - UTF8String = 12 - NumericString = 18 - PrintableString = 19 - T61String = 20 - IA5String = 22 - UTCTime = 23 - GeneralizedTime = 24 - VisibleString = 26 - UniversalString = 28 - BMPString = 30 - - -_ASN1_TYPE_TO_ENUM = {i.value: i for i in _ASN1Type} -_NAMEOID_DEFAULT_TYPE: dict[ObjectIdentifier, _ASN1Type] = { - NameOID.COUNTRY_NAME: _ASN1Type.PrintableString, - NameOID.JURISDICTION_COUNTRY_NAME: _ASN1Type.PrintableString, - NameOID.SERIAL_NUMBER: _ASN1Type.PrintableString, - NameOID.DN_QUALIFIER: _ASN1Type.PrintableString, - NameOID.EMAIL_ADDRESS: _ASN1Type.IA5String, - NameOID.DOMAIN_COMPONENT: _ASN1Type.IA5String, -} - -# Type alias -_OidNameMap = typing.Mapping[ObjectIdentifier, str] -_NameOidMap = typing.Mapping[str, ObjectIdentifier] - -#: Short attribute names from RFC 4514: -#: https://tools.ietf.org/html/rfc4514#page-7 -_NAMEOID_TO_NAME: _OidNameMap = { - NameOID.COMMON_NAME: "CN", - NameOID.LOCALITY_NAME: "L", - NameOID.STATE_OR_PROVINCE_NAME: "ST", - NameOID.ORGANIZATION_NAME: "O", - NameOID.ORGANIZATIONAL_UNIT_NAME: "OU", - NameOID.COUNTRY_NAME: "C", - NameOID.STREET_ADDRESS: "STREET", - NameOID.DOMAIN_COMPONENT: "DC", - NameOID.USER_ID: "UID", -} -_NAME_TO_NAMEOID = {v: k for k, v in _NAMEOID_TO_NAME.items()} - -_NAMEOID_LENGTH_LIMIT = { - NameOID.COUNTRY_NAME: (2, 2), - NameOID.JURISDICTION_COUNTRY_NAME: (2, 2), - NameOID.COMMON_NAME: (1, 64), -} - - -def _escape_dn_value(val: str | bytes) -> str: - """Escape special characters in RFC4514 Distinguished Name value.""" - - if not val: - return "" - - # RFC 4514 Section 2.4 defines the value as being the # (U+0023) character - # followed by the hexadecimal encoding of the octets. - if isinstance(val, bytes): - return "#" + binascii.hexlify(val).decode("utf8") - - # See https://tools.ietf.org/html/rfc4514#section-2.4 - val = val.replace("\\", "\\\\") - val = val.replace('"', '\\"') - val = val.replace("+", "\\+") - val = val.replace(",", "\\,") - val = val.replace(";", "\\;") - val = val.replace("<", "\\<") - val = val.replace(">", "\\>") - val = val.replace("\0", "\\00") - - if val[0] == "#" or (val[0] == " " and len(val) > 1): - val = "\\" + val - if val[-1] == " ": - val = val[:-1] + "\\ " - - return val - - -def _unescape_dn_value(val: str) -> str: - if not val: - return "" - - # See https://tools.ietf.org/html/rfc4514#section-3 - - # special = escaped / SPACE / SHARP / EQUALS - # escaped = DQUOTE / PLUS / COMMA / SEMI / LANGLE / RANGLE - def sub(m): - val = m.group(0) - # Special character escape - if len(val) == 2: - return val[1:] - - # Unicode string of hex - return binascii.unhexlify(val.replace("\\", "")).decode() - - return _RFC4514NameParser._PAIR_MULTI_RE.sub(sub, val) - - -NameAttributeValueType = typing.TypeVar( - "NameAttributeValueType", - typing.Union[str, bytes], - str, - bytes, - covariant=True, -) - - -class NameAttribute(typing.Generic[NameAttributeValueType]): - def __init__( - self, - oid: ObjectIdentifier, - value: NameAttributeValueType, - _type: _ASN1Type | None = None, - *, - _validate: bool = True, - ) -> None: - if not isinstance(oid, ObjectIdentifier): - raise TypeError( - "oid argument must be an ObjectIdentifier instance." - ) - if _type == _ASN1Type.BitString: - if oid != NameOID.X500_UNIQUE_IDENTIFIER: - raise TypeError( - "oid must be X500_UNIQUE_IDENTIFIER for BitString type." - ) - if not isinstance(value, bytes): - raise TypeError("value must be bytes for BitString") - elif not isinstance(value, str): - raise TypeError("value argument must be a str") - - length_limits = _NAMEOID_LENGTH_LIMIT.get(oid) - if length_limits is not None: - min_length, max_length = length_limits - assert isinstance(value, str) - c_len = len(value.encode("utf8")) - if c_len < min_length or c_len > max_length: - msg = ( - f"Attribute's length must be >= {min_length} and " - f"<= {max_length}, but it was {c_len}" - ) - if _validate is True: - raise ValueError(msg) - else: - warnings.warn(msg, stacklevel=2) - - # The appropriate ASN1 string type varies by OID and is defined across - # multiple RFCs including 2459, 3280, and 5280. In general UTF8String - # is preferred (2459), but 3280 and 5280 specify several OIDs with - # alternate types. This means when we see the sentinel value we need - # to look up whether the OID has a non-UTF8 type. If it does, set it - # to that. Otherwise, UTF8! - if _type is None: - _type = _NAMEOID_DEFAULT_TYPE.get(oid, _ASN1Type.UTF8String) - - if not isinstance(_type, _ASN1Type): - raise TypeError("_type must be from the _ASN1Type enum") - - self._oid = oid - self._value: NameAttributeValueType = value - self._type: _ASN1Type = _type - - @property - def oid(self) -> ObjectIdentifier: - return self._oid - - @property - def value(self) -> NameAttributeValueType: - return self._value - - @property - def rfc4514_attribute_name(self) -> str: - """ - The short attribute name (for example "CN") if available, - otherwise the OID dotted string. - """ - return _NAMEOID_TO_NAME.get(self.oid, self.oid.dotted_string) - - def rfc4514_string( - self, attr_name_overrides: _OidNameMap | None = None - ) -> str: - """ - Format as RFC4514 Distinguished Name string. - - Use short attribute name if available, otherwise fall back to OID - dotted string. - """ - attr_name = ( - attr_name_overrides.get(self.oid) if attr_name_overrides else None - ) - if attr_name is None: - attr_name = self.rfc4514_attribute_name - - return f"{attr_name}={_escape_dn_value(self.value)}" - - def __eq__(self, other: object) -> bool: - if not isinstance(other, NameAttribute): - return NotImplemented - - return self.oid == other.oid and self.value == other.value - - def __hash__(self) -> int: - return hash((self.oid, self.value)) - - def __repr__(self) -> str: - return f"" - - -class RelativeDistinguishedName: - def __init__(self, attributes: Iterable[NameAttribute[str | bytes]]): - attributes = list(attributes) - if not attributes: - raise ValueError("a relative distinguished name cannot be empty") - if not all(isinstance(x, NameAttribute) for x in attributes): - raise TypeError("attributes must be an iterable of NameAttribute") - - # Keep list and frozenset to preserve attribute order where it matters - self._attributes = attributes - self._attribute_set = frozenset(attributes) - - if len(self._attribute_set) != len(attributes): - raise ValueError("duplicate attributes are not allowed") - - def get_attributes_for_oid( - self, - oid: ObjectIdentifier, - ) -> list[NameAttribute[str | bytes]]: - return [i for i in self if i.oid == oid] - - def rfc4514_string( - self, attr_name_overrides: _OidNameMap | None = None - ) -> str: - """ - Format as RFC4514 Distinguished Name string. - - Within each RDN, attributes are joined by '+', although that is rarely - used in certificates. - """ - return "+".join( - attr.rfc4514_string(attr_name_overrides) - for attr in self._attributes - ) - - def __eq__(self, other: object) -> bool: - if not isinstance(other, RelativeDistinguishedName): - return NotImplemented - - return self._attribute_set == other._attribute_set - - def __hash__(self) -> int: - return hash(self._attribute_set) - - def __iter__(self) -> Iterator[NameAttribute[str | bytes]]: - return iter(self._attributes) - - def __len__(self) -> int: - return len(self._attributes) - - def __repr__(self) -> str: - return f"" - - -class Name: - @typing.overload - def __init__( - self, attributes: Iterable[NameAttribute[str | bytes]] - ) -> None: ... - - @typing.overload - def __init__( - self, attributes: Iterable[RelativeDistinguishedName] - ) -> None: ... - - def __init__( - self, - attributes: Iterable[ - NameAttribute[str | bytes] | RelativeDistinguishedName - ], - ) -> None: - attributes = list(attributes) - if all(isinstance(x, NameAttribute) for x in attributes): - self._attributes = [ - RelativeDistinguishedName([typing.cast(NameAttribute, x)]) - for x in attributes - ] - elif all(isinstance(x, RelativeDistinguishedName) for x in attributes): - self._attributes = typing.cast( - typing.List[RelativeDistinguishedName], attributes - ) - else: - raise TypeError( - "attributes must be a list of NameAttribute" - " or a list RelativeDistinguishedName" - ) - - @classmethod - def from_rfc4514_string( - cls, - data: str, - attr_name_overrides: _NameOidMap | None = None, - ) -> Name: - return _RFC4514NameParser(data, attr_name_overrides or {}).parse() - - def rfc4514_string( - self, attr_name_overrides: _OidNameMap | None = None - ) -> str: - """ - Format as RFC4514 Distinguished Name string. - For example 'CN=foobar.com,O=Foo Corp,C=US' - - An X.509 name is a two-level structure: a list of sets of attributes. - Each list element is separated by ',' and within each list element, set - elements are separated by '+'. The latter is almost never used in - real world certificates. According to RFC4514 section 2.1 the - RDNSequence must be reversed when converting to string representation. - """ - return ",".join( - attr.rfc4514_string(attr_name_overrides) - for attr in reversed(self._attributes) - ) - - def get_attributes_for_oid( - self, - oid: ObjectIdentifier, - ) -> list[NameAttribute[str | bytes]]: - return [i for i in self if i.oid == oid] - - @property - def rdns(self) -> list[RelativeDistinguishedName]: - return self._attributes - - def public_bytes(self, backend: typing.Any = None) -> bytes: - return rust_x509.encode_name_bytes(self) - - def __eq__(self, other: object) -> bool: - if not isinstance(other, Name): - return NotImplemented - - return self._attributes == other._attributes - - def __hash__(self) -> int: - # TODO: this is relatively expensive, if this looks like a bottleneck - # for you, consider optimizing! - return hash(tuple(self._attributes)) - - def __iter__(self) -> Iterator[NameAttribute[str | bytes]]: - for rdn in self._attributes: - yield from rdn - - def __len__(self) -> int: - return sum(len(rdn) for rdn in self._attributes) - - def __repr__(self) -> str: - return f"" - - -class _RFC4514NameParser: - _OID_RE = re.compile(r"(0|([1-9]\d*))(\.(0|([1-9]\d*)))+") - _DESCR_RE = re.compile(r"[a-zA-Z][a-zA-Z\d-]*") - - _ESCAPE_SPECIAL = r"[\\ #=\"\+,;<>]" - _ESCAPE_HEX = r"[\da-zA-Z]{2}" - _PAIR = rf"\\({_ESCAPE_SPECIAL}|{_ESCAPE_HEX})" - _PAIR_MULTI_RE = re.compile(rf"(\\{_ESCAPE_SPECIAL})|((\\{_ESCAPE_HEX})+)") - _LUTF1 = r"[\x01-\x1f\x21\x24-\x2A\x2D-\x3A\x3D\x3F-\x5B\x5D-\x7F]" - _SUTF1 = r"[\x01-\x21\x23-\x2A\x2D-\x3A\x3D\x3F-\x5B\x5D-\x7F]" - _TUTF1 = r"[\x01-\x1F\x21\x23-\x2A\x2D-\x3A\x3D\x3F-\x5B\x5D-\x7F]" - _UTFMB = rf"[\x80-{chr(sys.maxunicode)}]" - _LEADCHAR = rf"{_LUTF1}|{_UTFMB}" - _STRINGCHAR = rf"{_SUTF1}|{_UTFMB}" - _TRAILCHAR = rf"{_TUTF1}|{_UTFMB}" - _STRING_RE = re.compile( - rf""" - ( - ({_LEADCHAR}|{_PAIR}) - ( - ({_STRINGCHAR}|{_PAIR})* - ({_TRAILCHAR}|{_PAIR}) - )? - )? - """, - re.VERBOSE, - ) - _HEXSTRING_RE = re.compile(r"#([\da-zA-Z]{2})+") - - def __init__(self, data: str, attr_name_overrides: _NameOidMap) -> None: - self._data = data - self._idx = 0 - - self._attr_name_overrides = attr_name_overrides - - def _has_data(self) -> bool: - return self._idx < len(self._data) - - def _peek(self) -> str | None: - if self._has_data(): - return self._data[self._idx] - return None - - def _read_char(self, ch: str) -> None: - if self._peek() != ch: - raise ValueError - self._idx += 1 - - def _read_re(self, pat) -> str: - match = pat.match(self._data, pos=self._idx) - if match is None: - raise ValueError - val = match.group() - self._idx += len(val) - return val - - def parse(self) -> Name: - """ - Parses the `data` string and converts it to a Name. - - According to RFC4514 section 2.1 the RDNSequence must be - reversed when converting to string representation. So, when - we parse it, we need to reverse again to get the RDNs on the - correct order. - """ - - if not self._has_data(): - return Name([]) - - rdns = [self._parse_rdn()] - - while self._has_data(): - self._read_char(",") - rdns.append(self._parse_rdn()) - - return Name(reversed(rdns)) - - def _parse_rdn(self) -> RelativeDistinguishedName: - nas = [self._parse_na()] - while self._peek() == "+": - self._read_char("+") - nas.append(self._parse_na()) - - return RelativeDistinguishedName(nas) - - def _parse_na(self) -> NameAttribute[str]: - try: - oid_value = self._read_re(self._OID_RE) - except ValueError: - name = self._read_re(self._DESCR_RE) - oid = self._attr_name_overrides.get( - name, _NAME_TO_NAMEOID.get(name) - ) - if oid is None: - raise ValueError - else: - oid = ObjectIdentifier(oid_value) - - self._read_char("=") - if self._peek() == "#": - value = self._read_re(self._HEXSTRING_RE) - value = binascii.unhexlify(value[1:]).decode() - else: - raw_value = self._read_re(self._STRING_RE) - value = _unescape_dn_value(raw_value) - - return NameAttribute(oid, value) diff --git a/venv/lib/python3.9/site-packages/cryptography/x509/ocsp.py b/venv/lib/python3.9/site-packages/cryptography/x509/ocsp.py deleted file mode 100644 index f61ed80..0000000 --- a/venv/lib/python3.9/site-packages/cryptography/x509/ocsp.py +++ /dev/null @@ -1,379 +0,0 @@ -# This file is dual licensed under the terms of the Apache License, Version -# 2.0, and the BSD License. See the LICENSE file in the root of this repository -# for complete details. - -from __future__ import annotations - -import datetime -from collections.abc import Iterable - -from cryptography import utils, x509 -from cryptography.hazmat.bindings._rust import ocsp -from cryptography.hazmat.primitives import hashes -from cryptography.hazmat.primitives.asymmetric.types import ( - CertificateIssuerPrivateKeyTypes, -) -from cryptography.x509.base import _reject_duplicate_extension - - -class OCSPResponderEncoding(utils.Enum): - HASH = "By Hash" - NAME = "By Name" - - -class OCSPResponseStatus(utils.Enum): - SUCCESSFUL = 0 - MALFORMED_REQUEST = 1 - INTERNAL_ERROR = 2 - TRY_LATER = 3 - SIG_REQUIRED = 5 - UNAUTHORIZED = 6 - - -_ALLOWED_HASHES = ( - hashes.SHA1, - hashes.SHA224, - hashes.SHA256, - hashes.SHA384, - hashes.SHA512, -) - - -def _verify_algorithm(algorithm: hashes.HashAlgorithm) -> None: - if not isinstance(algorithm, _ALLOWED_HASHES): - raise ValueError( - "Algorithm must be SHA1, SHA224, SHA256, SHA384, or SHA512" - ) - - -class OCSPCertStatus(utils.Enum): - GOOD = 0 - REVOKED = 1 - UNKNOWN = 2 - - -class _SingleResponse: - def __init__( - self, - resp: tuple[x509.Certificate, x509.Certificate] | None, - resp_hash: tuple[bytes, bytes, int] | None, - algorithm: hashes.HashAlgorithm, - cert_status: OCSPCertStatus, - this_update: datetime.datetime, - next_update: datetime.datetime | None, - revocation_time: datetime.datetime | None, - revocation_reason: x509.ReasonFlags | None, - ): - _verify_algorithm(algorithm) - if not isinstance(this_update, datetime.datetime): - raise TypeError("this_update must be a datetime object") - if next_update is not None and not isinstance( - next_update, datetime.datetime - ): - raise TypeError("next_update must be a datetime object or None") - - self._resp = resp - self._resp_hash = resp_hash - self._algorithm = algorithm - self._this_update = this_update - self._next_update = next_update - - if not isinstance(cert_status, OCSPCertStatus): - raise TypeError( - "cert_status must be an item from the OCSPCertStatus enum" - ) - if cert_status is not OCSPCertStatus.REVOKED: - if revocation_time is not None: - raise ValueError( - "revocation_time can only be provided if the certificate " - "is revoked" - ) - if revocation_reason is not None: - raise ValueError( - "revocation_reason can only be provided if the certificate" - " is revoked" - ) - else: - if not isinstance(revocation_time, datetime.datetime): - raise TypeError("revocation_time must be a datetime object") - - if revocation_reason is not None and not isinstance( - revocation_reason, x509.ReasonFlags - ): - raise TypeError( - "revocation_reason must be an item from the ReasonFlags " - "enum or None" - ) - - self._cert_status = cert_status - self._revocation_time = revocation_time - self._revocation_reason = revocation_reason - - -OCSPRequest = ocsp.OCSPRequest -OCSPResponse = ocsp.OCSPResponse -OCSPSingleResponse = ocsp.OCSPSingleResponse - - -class OCSPRequestBuilder: - def __init__( - self, - request: tuple[ - x509.Certificate, x509.Certificate, hashes.HashAlgorithm - ] - | None = None, - request_hash: tuple[bytes, bytes, int, hashes.HashAlgorithm] - | None = None, - extensions: list[x509.Extension[x509.ExtensionType]] = [], - ) -> None: - self._request = request - self._request_hash = request_hash - self._extensions = extensions - - def add_certificate( - self, - cert: x509.Certificate, - issuer: x509.Certificate, - algorithm: hashes.HashAlgorithm, - ) -> OCSPRequestBuilder: - if self._request is not None or self._request_hash is not None: - raise ValueError("Only one certificate can be added to a request") - - _verify_algorithm(algorithm) - if not isinstance(cert, x509.Certificate) or not isinstance( - issuer, x509.Certificate - ): - raise TypeError("cert and issuer must be a Certificate") - - return OCSPRequestBuilder( - (cert, issuer, algorithm), self._request_hash, self._extensions - ) - - def add_certificate_by_hash( - self, - issuer_name_hash: bytes, - issuer_key_hash: bytes, - serial_number: int, - algorithm: hashes.HashAlgorithm, - ) -> OCSPRequestBuilder: - if self._request is not None or self._request_hash is not None: - raise ValueError("Only one certificate can be added to a request") - - if not isinstance(serial_number, int): - raise TypeError("serial_number must be an integer") - - _verify_algorithm(algorithm) - utils._check_bytes("issuer_name_hash", issuer_name_hash) - utils._check_bytes("issuer_key_hash", issuer_key_hash) - if algorithm.digest_size != len( - issuer_name_hash - ) or algorithm.digest_size != len(issuer_key_hash): - raise ValueError( - "issuer_name_hash and issuer_key_hash must be the same length " - "as the digest size of the algorithm" - ) - - return OCSPRequestBuilder( - self._request, - (issuer_name_hash, issuer_key_hash, serial_number, algorithm), - self._extensions, - ) - - def add_extension( - self, extval: x509.ExtensionType, critical: bool - ) -> OCSPRequestBuilder: - if not isinstance(extval, x509.ExtensionType): - raise TypeError("extension must be an ExtensionType") - - extension = x509.Extension(extval.oid, critical, extval) - _reject_duplicate_extension(extension, self._extensions) - - return OCSPRequestBuilder( - self._request, self._request_hash, [*self._extensions, extension] - ) - - def build(self) -> OCSPRequest: - if self._request is None and self._request_hash is None: - raise ValueError("You must add a certificate before building") - - return ocsp.create_ocsp_request(self) - - -class OCSPResponseBuilder: - def __init__( - self, - response: _SingleResponse | None = None, - responder_id: tuple[x509.Certificate, OCSPResponderEncoding] - | None = None, - certs: list[x509.Certificate] | None = None, - extensions: list[x509.Extension[x509.ExtensionType]] = [], - ): - self._response = response - self._responder_id = responder_id - self._certs = certs - self._extensions = extensions - - def add_response( - self, - cert: x509.Certificate, - issuer: x509.Certificate, - algorithm: hashes.HashAlgorithm, - cert_status: OCSPCertStatus, - this_update: datetime.datetime, - next_update: datetime.datetime | None, - revocation_time: datetime.datetime | None, - revocation_reason: x509.ReasonFlags | None, - ) -> OCSPResponseBuilder: - if self._response is not None: - raise ValueError("Only one response per OCSPResponse.") - - if not isinstance(cert, x509.Certificate) or not isinstance( - issuer, x509.Certificate - ): - raise TypeError("cert and issuer must be a Certificate") - - singleresp = _SingleResponse( - (cert, issuer), - None, - algorithm, - cert_status, - this_update, - next_update, - revocation_time, - revocation_reason, - ) - return OCSPResponseBuilder( - singleresp, - self._responder_id, - self._certs, - self._extensions, - ) - - def add_response_by_hash( - self, - issuer_name_hash: bytes, - issuer_key_hash: bytes, - serial_number: int, - algorithm: hashes.HashAlgorithm, - cert_status: OCSPCertStatus, - this_update: datetime.datetime, - next_update: datetime.datetime | None, - revocation_time: datetime.datetime | None, - revocation_reason: x509.ReasonFlags | None, - ) -> OCSPResponseBuilder: - if self._response is not None: - raise ValueError("Only one response per OCSPResponse.") - - if not isinstance(serial_number, int): - raise TypeError("serial_number must be an integer") - - utils._check_bytes("issuer_name_hash", issuer_name_hash) - utils._check_bytes("issuer_key_hash", issuer_key_hash) - _verify_algorithm(algorithm) - if algorithm.digest_size != len( - issuer_name_hash - ) or algorithm.digest_size != len(issuer_key_hash): - raise ValueError( - "issuer_name_hash and issuer_key_hash must be the same length " - "as the digest size of the algorithm" - ) - - singleresp = _SingleResponse( - None, - (issuer_name_hash, issuer_key_hash, serial_number), - algorithm, - cert_status, - this_update, - next_update, - revocation_time, - revocation_reason, - ) - return OCSPResponseBuilder( - singleresp, - self._responder_id, - self._certs, - self._extensions, - ) - - def responder_id( - self, encoding: OCSPResponderEncoding, responder_cert: x509.Certificate - ) -> OCSPResponseBuilder: - if self._responder_id is not None: - raise ValueError("responder_id can only be set once") - if not isinstance(responder_cert, x509.Certificate): - raise TypeError("responder_cert must be a Certificate") - if not isinstance(encoding, OCSPResponderEncoding): - raise TypeError( - "encoding must be an element from OCSPResponderEncoding" - ) - - return OCSPResponseBuilder( - self._response, - (responder_cert, encoding), - self._certs, - self._extensions, - ) - - def certificates( - self, certs: Iterable[x509.Certificate] - ) -> OCSPResponseBuilder: - if self._certs is not None: - raise ValueError("certificates may only be set once") - certs = list(certs) - if len(certs) == 0: - raise ValueError("certs must not be an empty list") - if not all(isinstance(x, x509.Certificate) for x in certs): - raise TypeError("certs must be a list of Certificates") - return OCSPResponseBuilder( - self._response, - self._responder_id, - certs, - self._extensions, - ) - - def add_extension( - self, extval: x509.ExtensionType, critical: bool - ) -> OCSPResponseBuilder: - if not isinstance(extval, x509.ExtensionType): - raise TypeError("extension must be an ExtensionType") - - extension = x509.Extension(extval.oid, critical, extval) - _reject_duplicate_extension(extension, self._extensions) - - return OCSPResponseBuilder( - self._response, - self._responder_id, - self._certs, - [*self._extensions, extension], - ) - - def sign( - self, - private_key: CertificateIssuerPrivateKeyTypes, - algorithm: hashes.HashAlgorithm | None, - ) -> OCSPResponse: - if self._response is None: - raise ValueError("You must add a response before signing") - if self._responder_id is None: - raise ValueError("You must add a responder_id before signing") - - return ocsp.create_ocsp_response( - OCSPResponseStatus.SUCCESSFUL, self, private_key, algorithm - ) - - @classmethod - def build_unsuccessful( - cls, response_status: OCSPResponseStatus - ) -> OCSPResponse: - if not isinstance(response_status, OCSPResponseStatus): - raise TypeError( - "response_status must be an item from OCSPResponseStatus" - ) - if response_status is OCSPResponseStatus.SUCCESSFUL: - raise ValueError("response_status cannot be SUCCESSFUL") - - return ocsp.create_ocsp_response(response_status, None, None, None) - - -load_der_ocsp_request = ocsp.load_der_ocsp_request -load_der_ocsp_response = ocsp.load_der_ocsp_response diff --git a/venv/lib/python3.9/site-packages/cryptography/x509/oid.py b/venv/lib/python3.9/site-packages/cryptography/x509/oid.py deleted file mode 100644 index 520fc7a..0000000 --- a/venv/lib/python3.9/site-packages/cryptography/x509/oid.py +++ /dev/null @@ -1,37 +0,0 @@ -# This file is dual licensed under the terms of the Apache License, Version -# 2.0, and the BSD License. See the LICENSE file in the root of this repository -# for complete details. - -from __future__ import annotations - -from cryptography.hazmat._oid import ( - AttributeOID, - AuthorityInformationAccessOID, - CertificatePoliciesOID, - CRLEntryExtensionOID, - ExtendedKeyUsageOID, - ExtensionOID, - NameOID, - ObjectIdentifier, - OCSPExtensionOID, - OtherNameFormOID, - PublicKeyAlgorithmOID, - SignatureAlgorithmOID, - SubjectInformationAccessOID, -) - -__all__ = [ - "AttributeOID", - "AuthorityInformationAccessOID", - "CRLEntryExtensionOID", - "CertificatePoliciesOID", - "ExtendedKeyUsageOID", - "ExtensionOID", - "NameOID", - "OCSPExtensionOID", - "ObjectIdentifier", - "OtherNameFormOID", - "PublicKeyAlgorithmOID", - "SignatureAlgorithmOID", - "SubjectInformationAccessOID", -] diff --git a/venv/lib/python3.9/site-packages/cryptography/x509/verification.py b/venv/lib/python3.9/site-packages/cryptography/x509/verification.py deleted file mode 100644 index 2db4324..0000000 --- a/venv/lib/python3.9/site-packages/cryptography/x509/verification.py +++ /dev/null @@ -1,34 +0,0 @@ -# This file is dual licensed under the terms of the Apache License, Version -# 2.0, and the BSD License. See the LICENSE file in the root of this repository -# for complete details. - -from __future__ import annotations - -import typing - -from cryptography.hazmat.bindings._rust import x509 as rust_x509 -from cryptography.x509.general_name import DNSName, IPAddress - -__all__ = [ - "ClientVerifier", - "Criticality", - "ExtensionPolicy", - "Policy", - "PolicyBuilder", - "ServerVerifier", - "Store", - "Subject", - "VerificationError", - "VerifiedClient", -] - -Store = rust_x509.Store -Subject = typing.Union[DNSName, IPAddress] -VerifiedClient = rust_x509.VerifiedClient -ClientVerifier = rust_x509.ClientVerifier -ServerVerifier = rust_x509.ServerVerifier -PolicyBuilder = rust_x509.PolicyBuilder -Policy = rust_x509.Policy -ExtensionPolicy = rust_x509.ExtensionPolicy -Criticality = rust_x509.Criticality -VerificationError = rust_x509.VerificationError diff --git a/venv/lib/python3.9/site-packages/distutils-precedence.pth b/venv/lib/python3.9/site-packages/distutils-precedence.pth deleted file mode 100644 index 7f009fe..0000000 --- a/venv/lib/python3.9/site-packages/distutils-precedence.pth +++ /dev/null @@ -1 +0,0 @@ -import os; var = 'SETUPTOOLS_USE_DISTUTILS'; enabled = os.environ.get(var, 'local') == 'local'; enabled and __import__('_distutils_hack').add_shim(); diff --git a/venv/lib/python3.9/site-packages/engineio/__init__.py b/venv/lib/python3.9/site-packages/engineio/__init__.py deleted file mode 100644 index 4919efd..0000000 --- a/venv/lib/python3.9/site-packages/engineio/__init__.py +++ /dev/null @@ -1,13 +0,0 @@ -from .client import Client -from .middleware import WSGIApp, Middleware -from .server import Server -from .async_server import AsyncServer -from .async_client import AsyncClient -from .async_drivers.asgi import ASGIApp -try: - from .async_drivers.tornado import get_tornado_handler -except ImportError: # pragma: no cover - get_tornado_handler = None - -__all__ = ['Server', 'WSGIApp', 'Middleware', 'Client', - 'AsyncServer', 'ASGIApp', 'get_tornado_handler', 'AsyncClient'] diff --git a/venv/lib/python3.9/site-packages/engineio/async_client.py b/venv/lib/python3.9/site-packages/engineio/async_client.py deleted file mode 100644 index 238ba52..0000000 --- a/venv/lib/python3.9/site-packages/engineio/async_client.py +++ /dev/null @@ -1,692 +0,0 @@ -import asyncio -from http.cookies import SimpleCookie -import inspect -import signal -import ssl -import threading - -try: - import aiohttp -except ImportError: # pragma: no cover - aiohttp = None - -from . import base_client -from . import exceptions -from . import packet -from . import payload - -async_signal_handler_set = False - -# this set is used to keep references to background tasks to prevent them from -# being garbage collected mid-execution. Solution taken from -# https://docs.python.org/3/library/asyncio-task.html#asyncio.create_task -task_reference_holder = set() - - -def async_signal_handler(): - """SIGINT handler. - - Disconnect all active async clients. - """ - async def _handler(): # pragma: no cover - for c in base_client.connected_clients[:]: - if c.is_asyncio_based(): - await c.disconnect() - - # cancel all running tasks - tasks = [task for task in asyncio.all_tasks() if task is not - asyncio.current_task()] - for task in tasks: - task.cancel() - await asyncio.gather(*tasks, return_exceptions=True) - asyncio.get_running_loop().stop() - - asyncio.ensure_future(_handler()) - - -class AsyncClient(base_client.BaseClient): - """An Engine.IO client for asyncio. - - This class implements a fully compliant Engine.IO web client with support - for websocket and long-polling transports, compatible with the asyncio - framework on Python 3.5 or newer. - - :param logger: To enable logging set to ``True`` or pass a logger object to - use. To disable logging set to ``False``. The default is - ``False``. Note that fatal errors are logged even when - ``logger`` is ``False``. - :param json: An alternative JSON module to use for encoding and decoding - packets. Custom json modules must have ``dumps`` and ``loads`` - functions that are compatible with the standard library - versions. This is a process-wide setting, all instantiated - servers and clients must use the same JSON module. - :param request_timeout: A timeout in seconds for requests. The default is - 5 seconds. - :param http_session: an initialized ``aiohttp.ClientSession`` object to be - used when sending requests to the server. Use it if - you need to add special client options such as proxy - servers, SSL certificates, custom CA bundle, etc. - :param ssl_verify: ``True`` to verify SSL certificates, or ``False`` to - skip SSL certificate verification, allowing - connections to servers with self signed certificates. - The default is ``True``. - :param handle_sigint: Set to ``True`` to automatically handle disconnection - when the process is interrupted, or to ``False`` to - leave interrupt handling to the calling application. - Interrupt handling can only be enabled when the - client instance is created in the main thread. - :param websocket_extra_options: Dictionary containing additional keyword - arguments passed to - ``aiohttp.ws_connect()``. - :param timestamp_requests: If ``True`` a timestamp is added to the query - string of Socket.IO requests as a cache-busting - measure. Set to ``False`` to disable. - """ - def is_asyncio_based(self): - return True - - async def connect(self, url, headers=None, transports=None, - engineio_path='engine.io'): - """Connect to an Engine.IO server. - - :param url: The URL of the Engine.IO server. It can include custom - query string parameters if required by the server. - :param headers: A dictionary with custom headers to send with the - connection request. - :param transports: The list of allowed transports. Valid transports - are ``'polling'`` and ``'websocket'``. If not - given, the polling transport is connected first, - then an upgrade to websocket is attempted. - :param engineio_path: The endpoint where the Engine.IO server is - installed. The default value is appropriate for - most cases. - - Note: this method is a coroutine. - - Example usage:: - - eio = engineio.Client() - await eio.connect('http://localhost:5000') - """ - global async_signal_handler_set - if self.handle_sigint and not async_signal_handler_set and \ - threading.current_thread() == threading.main_thread(): - try: - asyncio.get_running_loop().add_signal_handler( - signal.SIGINT, async_signal_handler) - except NotImplementedError: # pragma: no cover - self.logger.warning('Signal handler is unsupported') - async_signal_handler_set = True - - if self.state != 'disconnected': - raise ValueError('Client is not in a disconnected state') - valid_transports = ['polling', 'websocket'] - if transports is not None: - if isinstance(transports, str): - transports = [transports] - transports = [transport for transport in transports - if transport in valid_transports] - if not transports: - raise ValueError('No valid transports provided') - self.transports = transports or valid_transports - return await getattr(self, '_connect_' + self.transports[0])( - url, headers or {}, engineio_path) - - async def wait(self): - """Wait until the connection with the server ends. - - Client applications can use this function to block the main thread - during the life of the connection. - - Note: this method is a coroutine. - """ - if self.read_loop_task: - await self.read_loop_task - - async def send(self, data): - """Send a message to the server. - - :param data: The data to send to the server. Data can be of type - ``str``, ``bytes``, ``list`` or ``dict``. If a ``list`` - or ``dict``, the data will be serialized as JSON. - - Note: this method is a coroutine. - """ - await self._send_packet(packet.Packet(packet.MESSAGE, data=data)) - - async def disconnect(self, abort=False, reason=None): - """Disconnect from the server. - - :param abort: If set to ``True``, do not wait for background tasks - associated with the connection to end. - - Note: this method is a coroutine. - """ - if self.state == 'connected': - await self._send_packet(packet.Packet(packet.CLOSE)) - await self.queue.put(None) - self.state = 'disconnecting' - await self._trigger_event('disconnect', - reason or self.reason.CLIENT_DISCONNECT, - run_async=False) - if self.current_transport == 'websocket': - await self.ws.close() - if not abort: - await self.read_loop_task - self.state = 'disconnected' - try: - base_client.connected_clients.remove(self) - except ValueError: # pragma: no cover - pass - await self._reset() - - def start_background_task(self, target, *args, **kwargs): - """Start a background task. - - This is a utility function that applications can use to start a - background task. - - :param target: the target function to execute. - :param args: arguments to pass to the function. - :param kwargs: keyword arguments to pass to the function. - - The return value is a ``asyncio.Task`` object. - """ - return asyncio.ensure_future(target(*args, **kwargs)) - - async def sleep(self, seconds=0): - """Sleep for the requested amount of time. - - Note: this method is a coroutine. - """ - return await asyncio.sleep(seconds) - - def create_queue(self, *args, **kwargs): - """Create a queue object.""" - return asyncio.Queue(*args, **kwargs) - - def get_queue_empty_exception(self): - """Return the queue empty exception raised by queues created by the - ``create_queue()`` method. - """ - return asyncio.QueueEmpty - - def create_event(self): - """Create an event object.""" - return asyncio.Event() - - async def _reset(self): - super()._reset() - while True: # pragma: no cover - try: - self.queue.get_nowait() - self.queue.task_done() - except self.queue_empty: - break - if not self.external_http: # pragma: no cover - if self.http and not self.http.closed: - await self.http.close() - - def __del__(self): # pragma: no cover - # try to close the aiohttp session if it is still open - if self.http and not self.http.closed: - try: - loop = asyncio.get_event_loop() - if loop.is_running(): - loop.ensure_future(self.http.close()) - else: - loop.run_until_complete(self.http.close()) - except: - pass - - async def _connect_polling(self, url, headers, engineio_path): - """Establish a long-polling connection to the Engine.IO server.""" - if aiohttp is None: # pragma: no cover - self.logger.error('aiohttp not installed -- cannot make HTTP ' - 'requests!') - return - self.base_url = self._get_engineio_url(url, engineio_path, 'polling') - self.logger.info('Attempting polling connection to ' + self.base_url) - r = await self._send_request( - 'GET', self.base_url + self._get_url_timestamp(), headers=headers, - timeout=self.request_timeout) - if r is None or isinstance(r, str): - await self._reset() - raise exceptions.ConnectionError( - r or 'Connection refused by the server') - if r.status < 200 or r.status >= 300: - await self._reset() - try: - arg = await r.json() - except aiohttp.ClientError: - arg = None - raise exceptions.ConnectionError( - 'Unexpected status code {} in server response'.format( - r.status), arg) - try: - p = payload.Payload(encoded_payload=(await r.read()).decode( - 'utf-8')) - except ValueError: - raise exceptions.ConnectionError( - 'Unexpected response from server') from None - open_packet = p.packets[0] - if open_packet.packet_type != packet.OPEN: - raise exceptions.ConnectionError( - 'OPEN packet not returned by server') - self.logger.info( - 'Polling connection accepted with ' + str(open_packet.data)) - self.sid = open_packet.data['sid'] - self.upgrades = open_packet.data['upgrades'] - self.ping_interval = int(open_packet.data['pingInterval']) / 1000.0 - self.ping_timeout = int(open_packet.data['pingTimeout']) / 1000.0 - self.current_transport = 'polling' - self.base_url += '&sid=' + self.sid - - self.state = 'connected' - base_client.connected_clients.append(self) - await self._trigger_event('connect', run_async=False) - - for pkt in p.packets[1:]: - await self._receive_packet(pkt) - - if 'websocket' in self.upgrades and 'websocket' in self.transports: - # attempt to upgrade to websocket - if await self._connect_websocket(url, headers, engineio_path): - # upgrade to websocket succeeded, we're done here - return - - self.write_loop_task = self.start_background_task(self._write_loop) - self.read_loop_task = self.start_background_task( - self._read_loop_polling) - - async def _connect_websocket(self, url, headers, engineio_path): - """Establish or upgrade to a WebSocket connection with the server.""" - if aiohttp is None: # pragma: no cover - self.logger.error('aiohttp package not installed') - return False - websocket_url = self._get_engineio_url(url, engineio_path, - 'websocket') - if self.sid: - self.logger.info( - 'Attempting WebSocket upgrade to ' + websocket_url) - upgrade = True - websocket_url += '&sid=' + self.sid - else: - upgrade = False - self.base_url = websocket_url - self.logger.info( - 'Attempting WebSocket connection to ' + websocket_url) - - if self.http is None or self.http.closed: # pragma: no cover - self.http = aiohttp.ClientSession() - - # extract any new cookies passed in a header so that they can also be - # sent the the WebSocket route - for header, value in headers.items(): - if header.lower() == 'cookie': - ck = SimpleCookie(headers[header]) - self.http.cookie_jar.update_cookies( - {k: m.value for k, m in ck.items()}) - del headers[header] - break - - extra_options = { - 'timeout': aiohttp.ClientWSTimeout(ws_close=self.request_timeout)} - if not self.ssl_verify: - ssl_context = ssl.create_default_context() - ssl_context.check_hostname = False - ssl_context.verify_mode = ssl.CERT_NONE - extra_options['ssl'] = ssl_context - - # combine internally generated options with the ones supplied by the - # caller. The caller's options take precedence. - headers.update(self.websocket_extra_options.pop('headers', {})) - extra_options['headers'] = headers - extra_options.update(self.websocket_extra_options) - - try: - ws = await self.http.ws_connect( - websocket_url + self._get_url_timestamp(), **extra_options) - except (aiohttp.client_exceptions.WSServerHandshakeError, - aiohttp.client_exceptions.ServerConnectionError, - aiohttp.client_exceptions.ClientConnectionError): - if upgrade: - self.logger.warning( - 'WebSocket upgrade failed: connection error') - return False - else: - raise exceptions.ConnectionError('Connection error') - if upgrade: - p = packet.Packet(packet.PING, data='probe').encode() - try: - await ws.send_str(p) - except Exception as e: # pragma: no cover - self.logger.warning( - 'WebSocket upgrade failed: unexpected send exception: %s', - str(e)) - return False - try: - p = (await ws.receive()).data - except Exception as e: # pragma: no cover - self.logger.warning( - 'WebSocket upgrade failed: unexpected recv exception: %s', - str(e)) - return False - pkt = packet.Packet(encoded_packet=p) - if pkt.packet_type != packet.PONG or pkt.data != 'probe': - self.logger.warning( - 'WebSocket upgrade failed: no PONG packet') - return False - p = packet.Packet(packet.UPGRADE).encode() - try: - await ws.send_str(p) - except Exception as e: # pragma: no cover - self.logger.warning( - 'WebSocket upgrade failed: unexpected send exception: %s', - str(e)) - return False - self.current_transport = 'websocket' - self.logger.info('WebSocket upgrade was successful') - else: - try: - p = (await ws.receive()).data - except Exception as e: # pragma: no cover - raise exceptions.ConnectionError( - 'Unexpected recv exception: ' + str(e)) - open_packet = packet.Packet(encoded_packet=p) - if open_packet.packet_type != packet.OPEN: - raise exceptions.ConnectionError('no OPEN packet') - self.logger.info( - 'WebSocket connection accepted with ' + str(open_packet.data)) - self.sid = open_packet.data['sid'] - self.upgrades = open_packet.data['upgrades'] - self.ping_interval = int(open_packet.data['pingInterval']) / 1000.0 - self.ping_timeout = int(open_packet.data['pingTimeout']) / 1000.0 - self.current_transport = 'websocket' - - self.state = 'connected' - base_client.connected_clients.append(self) - await self._trigger_event('connect', run_async=False) - - self.ws = ws - self.write_loop_task = self.start_background_task(self._write_loop) - self.read_loop_task = self.start_background_task( - self._read_loop_websocket) - return True - - async def _receive_packet(self, pkt): - """Handle incoming packets from the server.""" - packet_name = packet.packet_names[pkt.packet_type] \ - if pkt.packet_type < len(packet.packet_names) else 'UNKNOWN' - self.logger.info( - 'Received packet %s data %s', packet_name, - pkt.data if not isinstance(pkt.data, bytes) else '') - if pkt.packet_type == packet.MESSAGE: - await self._trigger_event('message', pkt.data, run_async=True) - elif pkt.packet_type == packet.PING: - await self._send_packet(packet.Packet(packet.PONG, pkt.data)) - elif pkt.packet_type == packet.CLOSE: - await self.disconnect(abort=True, - reason=self.reason.SERVER_DISCONNECT) - elif pkt.packet_type == packet.NOOP: - pass - else: - self.logger.error('Received unexpected packet of type %s', - pkt.packet_type) - - async def _send_packet(self, pkt): - """Queue a packet to be sent to the server.""" - if self.state != 'connected': - return - await self.queue.put(pkt) - self.logger.info( - 'Sending packet %s data %s', - packet.packet_names[pkt.packet_type], - pkt.data if not isinstance(pkt.data, bytes) else '') - - async def _send_request( - self, method, url, headers=None, body=None, - timeout=None): # pragma: no cover - if self.http is None or self.http.closed: - self.http = aiohttp.ClientSession() - http_method = getattr(self.http, method.lower()) - - try: - if not self.ssl_verify: - return await http_method( - url, headers=headers, data=body, - timeout=aiohttp.ClientTimeout(total=timeout), ssl=False) - else: - return await http_method( - url, headers=headers, data=body, - timeout=aiohttp.ClientTimeout(total=timeout)) - - except (aiohttp.ClientError, asyncio.TimeoutError) as exc: - self.logger.info('HTTP %s request to %s failed with error %s.', - method, url, exc) - return str(exc) - - async def _trigger_event(self, event, *args, **kwargs): - """Invoke an event handler.""" - run_async = kwargs.pop('run_async', False) - ret = None - if event in self.handlers: - if inspect.iscoroutinefunction(self.handlers[event]) is True: - if run_async: - task = self.start_background_task(self.handlers[event], - *args) - task_reference_holder.add(task) - task.add_done_callback(task_reference_holder.discard) - return task - else: - try: - try: - ret = await self.handlers[event](*args) - except TypeError: - if event == 'disconnect' and \ - len(args) == 1: # pragma: no branch - # legacy disconnect events do not have a reason - # argument - return await self.handlers[event]() - else: # pragma: no cover - raise - except asyncio.CancelledError: # pragma: no cover - pass - except: - self.logger.exception(event + ' async handler error') - if event == 'connect': - # if connect handler raised error we reject the - # connection - return False - else: - if run_async: - async def async_handler(): - return self.handlers[event](*args) - - task = self.start_background_task(async_handler) - task_reference_holder.add(task) - task.add_done_callback(task_reference_holder.discard) - return task - else: - try: - try: - ret = self.handlers[event](*args) - except TypeError: - if event == 'disconnect' and \ - len(args) == 1: # pragma: no branch - # legacy disconnect events do not have a reason - # argument - ret = self.handlers[event]() - else: # pragma: no cover - raise - except: - self.logger.exception(event + ' handler error') - if event == 'connect': - # if connect handler raised error we reject the - # connection - return False - return ret - - async def _read_loop_polling(self): - """Read packets by polling the Engine.IO server.""" - while self.state == 'connected' and self.write_loop_task: - self.logger.info( - 'Sending polling GET request to ' + self.base_url) - r = await self._send_request( - 'GET', self.base_url + self._get_url_timestamp(), - timeout=max(self.ping_interval, self.ping_timeout) + 5) - if r is None or isinstance(r, str): - self.logger.warning( - r or 'Connection refused by the server, aborting') - await self.queue.put(None) - break - if r.status < 200 or r.status >= 300: - self.logger.warning('Unexpected status code %s in server ' - 'response, aborting', r.status) - await self.queue.put(None) - break - try: - p = payload.Payload(encoded_payload=(await r.read()).decode( - 'utf-8')) - except ValueError: - self.logger.warning( - 'Unexpected packet from server, aborting') - await self.queue.put(None) - break - for pkt in p.packets: - await self._receive_packet(pkt) - - if self.write_loop_task: # pragma: no branch - self.logger.info('Waiting for write loop task to end') - await self.write_loop_task - if self.state == 'connected': - await self._trigger_event( - 'disconnect', self.reason.TRANSPORT_ERROR, run_async=False) - try: - base_client.connected_clients.remove(self) - except ValueError: # pragma: no cover - pass - await self._reset() - self.logger.info('Exiting read loop task') - - async def _read_loop_websocket(self): - """Read packets from the Engine.IO WebSocket connection.""" - while self.state == 'connected': - p = None - try: - p = await asyncio.wait_for( - self.ws.receive(), - timeout=self.ping_interval + self.ping_timeout) - if not isinstance(p.data, (str, bytes)): # pragma: no cover - self.logger.warning( - 'Server sent %s packet data %s, aborting', - 'close' if p.type in [aiohttp.WSMsgType.CLOSE, - aiohttp.WSMsgType.CLOSING] - else str(p.type), str(p.data)) - await self.queue.put(None) - break # the connection is broken - p = p.data - except asyncio.TimeoutError: - self.logger.warning( - 'Server has stopped communicating, aborting') - await self.queue.put(None) - break - except aiohttp.client_exceptions.ServerDisconnectedError: - self.logger.info( - 'Read loop: WebSocket connection was closed, aborting') - await self.queue.put(None) - break - except Exception as e: - self.logger.info( - 'Unexpected error receiving packet: "%s", aborting', - str(e)) - await self.queue.put(None) - break - try: - pkt = packet.Packet(encoded_packet=p) - except Exception as e: # pragma: no cover - self.logger.info( - 'Unexpected error decoding packet: "%s", aborting', str(e)) - await self.queue.put(None) - break - await self._receive_packet(pkt) - - if self.write_loop_task: # pragma: no branch - self.logger.info('Waiting for write loop task to end') - await self.write_loop_task - if self.state == 'connected': - await self._trigger_event( - 'disconnect', self.reason.TRANSPORT_ERROR, run_async=False) - try: - base_client.connected_clients.remove(self) - except ValueError: # pragma: no cover - pass - await self._reset() - self.logger.info('Exiting read loop task') - - async def _write_loop(self): - """This background task sends packages to the server as they are - pushed to the send queue. - """ - while self.state == 'connected': - # to simplify the timeout handling, use the maximum of the - # ping interval and ping timeout as timeout, with an extra 5 - # seconds grace period - timeout = max(self.ping_interval, self.ping_timeout) + 5 - packets = None - try: - packets = [await asyncio.wait_for(self.queue.get(), timeout)] - except (self.queue_empty, asyncio.TimeoutError): - self.logger.error('packet queue is empty, aborting') - break - except asyncio.CancelledError: # pragma: no cover - break - if packets == [None]: - self.queue.task_done() - packets = [] - else: - while True: - try: - packets.append(self.queue.get_nowait()) - except self.queue_empty: - break - if packets[-1] is None: - packets = packets[:-1] - self.queue.task_done() - break - if not packets: - # empty packet list returned -> connection closed - break - if self.current_transport == 'polling': - p = payload.Payload(packets=packets) - r = await self._send_request( - 'POST', self.base_url, body=p.encode(), - headers={'Content-Type': 'text/plain'}, - timeout=self.request_timeout) - for pkt in packets: - self.queue.task_done() - if r is None or isinstance(r, str): - self.logger.warning( - r or 'Connection refused by the server, aborting') - break - if r.status < 200 or r.status >= 300: - self.logger.warning('Unexpected status code %s in server ' - 'response, aborting', r.status) - self.write_loop_task = None - break - else: - # websocket - try: - for pkt in packets: - if pkt.binary: - await self.ws.send_bytes(pkt.encode()) - else: - await self.ws.send_str(pkt.encode()) - self.queue.task_done() - except (aiohttp.client_exceptions.ServerDisconnectedError, - BrokenPipeError, OSError): - self.logger.info( - 'Write loop: WebSocket connection was closed, ' - 'aborting') - break - self.logger.info('Exiting write loop task') diff --git a/venv/lib/python3.9/site-packages/engineio/async_drivers/__init__.py b/venv/lib/python3.9/site-packages/engineio/async_drivers/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/venv/lib/python3.9/site-packages/engineio/async_drivers/_websocket_wsgi.py b/venv/lib/python3.9/site-packages/engineio/async_drivers/_websocket_wsgi.py deleted file mode 100644 index aca30dc..0000000 --- a/venv/lib/python3.9/site-packages/engineio/async_drivers/_websocket_wsgi.py +++ /dev/null @@ -1,34 +0,0 @@ -import simple_websocket - - -class SimpleWebSocketWSGI: # pragma: no cover - """ - This wrapper class provides a threading WebSocket interface that is - compatible with eventlet's implementation. - """ - def __init__(self, handler, server, **kwargs): - self.app = handler - self.server_args = kwargs - - def __call__(self, environ, start_response): - self.ws = simple_websocket.Server(environ, **self.server_args) - ret = self.app(self) - if self.ws.mode == 'gunicorn': - raise StopIteration() - return ret - - def close(self): - if self.ws.connected: - self.ws.close() - - def send(self, message): - try: - return self.ws.send(message) - except simple_websocket.ConnectionClosed: - raise OSError() - - def wait(self): - try: - return self.ws.receive() - except simple_websocket.ConnectionClosed: - return None diff --git a/venv/lib/python3.9/site-packages/engineio/async_drivers/aiohttp.py b/venv/lib/python3.9/site-packages/engineio/async_drivers/aiohttp.py deleted file mode 100644 index 41131d8..0000000 --- a/venv/lib/python3.9/site-packages/engineio/async_drivers/aiohttp.py +++ /dev/null @@ -1,120 +0,0 @@ -import inspect -import sys - -from aiohttp.web import Response, WebSocketResponse - - -def create_route(app, engineio_server, engineio_endpoint): - """This function sets up the engine.io endpoint as a route for the - application. - - Note that both GET and POST requests must be hooked up on the engine.io - endpoint. - """ - app.router.add_get(engineio_endpoint, engineio_server.handle_request) - app.router.add_post(engineio_endpoint, engineio_server.handle_request) - app.router.add_route('OPTIONS', engineio_endpoint, - engineio_server.handle_request) - - -def translate_request(request): - """This function takes the arguments passed to the request handler and - uses them to generate a WSGI compatible environ dictionary. - """ - environ = { - 'wsgi.input': request.content, - 'wsgi.errors': sys.stderr, - 'wsgi.version': (1, 0), - 'wsgi.async': True, - 'wsgi.multithread': False, - 'wsgi.multiprocess': False, - 'wsgi.run_once': False, - 'SERVER_SOFTWARE': 'aiohttp', - 'REQUEST_METHOD': request.method, - 'QUERY_STRING': request.query_string or '', - 'RAW_URI': request.path_qs, - 'SERVER_PROTOCOL': f'HTTP/{request.version[0]}.{request.version[1]}', - 'REMOTE_ADDR': '127.0.0.1', - 'REMOTE_PORT': '0', - 'SERVER_NAME': 'aiohttp', - 'SERVER_PORT': '0', - 'aiohttp.request': request - } - - for hdr_name, hdr_value in request.headers.items(): - hdr_name = hdr_name.upper() - if hdr_name == 'CONTENT-TYPE': - environ['CONTENT_TYPE'] = hdr_value - continue - elif hdr_name == 'CONTENT-LENGTH': - environ['CONTENT_LENGTH'] = hdr_value - continue - - key = 'HTTP_%s' % hdr_name.replace('-', '_') - if key in environ: - hdr_value = f'{environ[key]},{hdr_value}' - - environ[key] = hdr_value - - environ['wsgi.url_scheme'] = environ.get('HTTP_X_FORWARDED_PROTO', 'http') - - environ['PATH_INFO'] = request.path - environ['SCRIPT_NAME'] = '' - - return environ - - -def make_response(status, headers, payload, environ): - """This function generates an appropriate response object for this async - mode. - """ - return Response(body=payload, status=int(status.split()[0]), - headers=headers) - - -class WebSocket: # pragma: no cover - """ - This wrapper class provides a aiohttp WebSocket interface that is - somewhat compatible with eventlet's implementation. - """ - def __init__(self, handler, server): - self.handler = handler - self._sock = None - - async def __call__(self, environ): - request = environ['aiohttp.request'] - self._sock = WebSocketResponse(max_msg_size=0) - await self._sock.prepare(request) - - self.environ = environ - await self.handler(self) - return self._sock - - async def close(self): - await self._sock.close() - - async def send(self, message): - if isinstance(message, bytes): - f = self._sock.send_bytes - else: - f = self._sock.send_str - if inspect.iscoroutinefunction(f): - await f(message) - else: - f(message) - - async def wait(self): - msg = await self._sock.receive() - if not isinstance(msg.data, bytes) and \ - not isinstance(msg.data, str): - raise OSError() - return msg.data - - -_async = { - 'asyncio': True, - 'create_route': create_route, - 'translate_request': translate_request, - 'make_response': make_response, - 'websocket': WebSocket, -} diff --git a/venv/lib/python3.9/site-packages/engineio/async_drivers/asgi.py b/venv/lib/python3.9/site-packages/engineio/async_drivers/asgi.py deleted file mode 100644 index c3581c6..0000000 --- a/venv/lib/python3.9/site-packages/engineio/async_drivers/asgi.py +++ /dev/null @@ -1,296 +0,0 @@ -import inspect -import os -import sys - -from engineio.static_files import get_static_file - - -class ASGIApp: - """ASGI application middleware for Engine.IO. - - This middleware dispatches traffic to an Engine.IO application. It can - also serve a list of static files to the client, or forward unrelated - HTTP traffic to another ASGI application. - - :param engineio_server: The Engine.IO server. Must be an instance of the - ``engineio.AsyncServer`` class. - :param static_files: A dictionary with static file mapping rules. See the - documentation for details on this argument. - :param other_asgi_app: A separate ASGI app that receives all other traffic. - :param engineio_path: The endpoint where the Engine.IO application should - be installed. The default value is appropriate for - most cases. With a value of ``None``, all incoming - traffic is directed to the Engine.IO server, with the - assumption that routing, if necessary, is handled by - a different layer. When this option is set to - ``None``, ``static_files`` and ``other_asgi_app`` are - ignored. - :param on_startup: function to be called on application startup; can be - coroutine - :param on_shutdown: function to be called on application shutdown; can be - coroutine - - Example usage:: - - import engineio - import uvicorn - - eio = engineio.AsyncServer() - app = engineio.ASGIApp(eio, static_files={ - '/': {'content_type': 'text/html', 'filename': 'index.html'}, - '/index.html': {'content_type': 'text/html', - 'filename': 'index.html'}, - }) - uvicorn.run(app, '127.0.0.1', 5000) - """ - def __init__(self, engineio_server, other_asgi_app=None, - static_files=None, engineio_path='engine.io', - on_startup=None, on_shutdown=None): - self.engineio_server = engineio_server - self.other_asgi_app = other_asgi_app - self.engineio_path = engineio_path - if self.engineio_path is not None: - if not self.engineio_path.startswith('/'): - self.engineio_path = '/' + self.engineio_path - if not self.engineio_path.endswith('/'): - self.engineio_path += '/' - self.static_files = static_files or {} - self.on_startup = on_startup - self.on_shutdown = on_shutdown - - async def __call__(self, scope, receive, send): - if scope['type'] == 'lifespan': - await self.lifespan(scope, receive, send) - elif scope['type'] in ['http', 'websocket'] and ( - self.engineio_path is None - or self._ensure_trailing_slash(scope['path']).startswith( - self.engineio_path)): - await self.engineio_server.handle_request(scope, receive, send) - else: - static_file = get_static_file(scope['path'], self.static_files) \ - if scope['type'] == 'http' and self.static_files else None - if static_file and os.path.exists(static_file['filename']): - await self.serve_static_file(static_file, receive, send) - elif self.other_asgi_app is not None: - await self.other_asgi_app(scope, receive, send) - else: - await self.not_found(receive, send) - - async def serve_static_file(self, static_file, receive, - send): # pragma: no cover - event = await receive() - if event['type'] == 'http.request': - with open(static_file['filename'], 'rb') as f: - payload = f.read() - await send({'type': 'http.response.start', - 'status': 200, - 'headers': [(b'Content-Type', static_file[ - 'content_type'].encode('utf-8'))]}) - await send({'type': 'http.response.body', - 'body': payload}) - - async def lifespan(self, scope, receive, send): - if self.other_asgi_app is not None and self.on_startup is None and \ - self.on_shutdown is None: - # let the other ASGI app handle lifespan events - await self.other_asgi_app(scope, receive, send) - return - - while True: - event = await receive() - if event['type'] == 'lifespan.startup': - if self.on_startup: - try: - await self.on_startup() \ - if inspect.iscoroutinefunction(self.on_startup) \ - else self.on_startup() - except: - await send({'type': 'lifespan.startup.failed'}) - return - await send({'type': 'lifespan.startup.complete'}) - elif event['type'] == 'lifespan.shutdown': - if self.on_shutdown: - try: - await self.on_shutdown() \ - if inspect.iscoroutinefunction(self.on_shutdown) \ - else self.on_shutdown() - except: - await send({'type': 'lifespan.shutdown.failed'}) - return - await send({'type': 'lifespan.shutdown.complete'}) - return - - async def not_found(self, receive, send): - """Return a 404 Not Found error to the client.""" - await send({'type': 'http.response.start', - 'status': 404, - 'headers': [(b'Content-Type', b'text/plain')]}) - await send({'type': 'http.response.body', - 'body': b'Not Found'}) - - def _ensure_trailing_slash(self, path): - if not path.endswith('/'): - path += '/' - return path - - -async def translate_request(scope, receive, send): - class AwaitablePayload: # pragma: no cover - def __init__(self, payload): - self.payload = payload or b'' - - async def read(self, length=None): - if length is None: - r = self.payload - self.payload = b'' - else: - r = self.payload[:length] - self.payload = self.payload[length:] - return r - - event = await receive() - payload = b'' - if event['type'] == 'http.request': - payload += event.get('body') or b'' - while event.get('more_body'): - event = await receive() - if event['type'] == 'http.request': - payload += event.get('body') or b'' - elif event['type'] == 'websocket.connect': - pass - else: - return {} - - raw_uri = scope['path'] - query_string = '' - if 'query_string' in scope and scope['query_string']: - try: - query_string = scope['query_string'].decode('utf-8') - except UnicodeDecodeError: - pass - else: - raw_uri += '?' + query_string - environ = { - 'wsgi.input': AwaitablePayload(payload), - 'wsgi.errors': sys.stderr, - 'wsgi.version': (1, 0), - 'wsgi.async': True, - 'wsgi.multithread': False, - 'wsgi.multiprocess': False, - 'wsgi.run_once': False, - 'SERVER_SOFTWARE': 'asgi', - 'REQUEST_METHOD': scope.get('method', 'GET'), - 'PATH_INFO': scope['path'], - 'QUERY_STRING': query_string, - 'RAW_URI': raw_uri, - 'SCRIPT_NAME': '', - 'SERVER_PROTOCOL': 'HTTP/1.1', - 'REMOTE_ADDR': '127.0.0.1', - 'REMOTE_PORT': '0', - 'SERVER_NAME': 'asgi', - 'SERVER_PORT': '0', - 'asgi.receive': receive, - 'asgi.send': send, - 'asgi.scope': scope, - } - - for hdr_name, hdr_value in scope['headers']: - try: - hdr_name = hdr_name.upper().decode('utf-8') - hdr_value = hdr_value.decode('utf-8') - except UnicodeDecodeError: - # skip header if it cannot be decoded - continue - if hdr_name == 'CONTENT-TYPE': - environ['CONTENT_TYPE'] = hdr_value - continue - elif hdr_name == 'CONTENT-LENGTH': - environ['CONTENT_LENGTH'] = hdr_value - continue - - key = 'HTTP_%s' % hdr_name.replace('-', '_') - if key in environ: - hdr_value = f'{environ[key]},{hdr_value}' - - environ[key] = hdr_value - - environ['wsgi.url_scheme'] = environ.get('HTTP_X_FORWARDED_PROTO', 'http') - return environ - - -async def make_response(status, headers, payload, environ): - headers = [(h[0].encode('utf-8'), h[1].encode('utf-8')) for h in headers] - if environ['asgi.scope']['type'] == 'websocket': - if status.startswith('200 '): - await environ['asgi.send']({'type': 'websocket.accept', - 'headers': headers}) - else: - if payload: - reason = payload.decode('utf-8') \ - if isinstance(payload, bytes) else str(payload) - await environ['asgi.send']({'type': 'websocket.close', - 'reason': reason}) - else: - await environ['asgi.send']({'type': 'websocket.close'}) - return - - await environ['asgi.send']({'type': 'http.response.start', - 'status': int(status.split(' ')[0]), - 'headers': headers}) - await environ['asgi.send']({'type': 'http.response.body', - 'body': payload}) - - -class WebSocket: # pragma: no cover - """ - This wrapper class provides an asgi WebSocket interface that is - somewhat compatible with eventlet's implementation. - """ - def __init__(self, handler, server): - self.handler = handler - self.asgi_receive = None - self.asgi_send = None - - async def __call__(self, environ): - self.asgi_receive = environ['asgi.receive'] - self.asgi_send = environ['asgi.send'] - await self.asgi_send({'type': 'websocket.accept'}) - await self.handler(self) - return '' # send nothing as response - - async def close(self): - try: - await self.asgi_send({'type': 'websocket.close'}) - except Exception: - # if the socket is already close we don't care - pass - - async def send(self, message): - msg_bytes = None - msg_text = None - if isinstance(message, bytes): - msg_bytes = message - else: - msg_text = message - await self.asgi_send({'type': 'websocket.send', - 'bytes': msg_bytes, - 'text': msg_text}) - - async def wait(self): - event = await self.asgi_receive() - if event['type'] != 'websocket.receive': - raise OSError() - if event.get('bytes', None) is not None: - return event['bytes'] - elif event.get('text', None) is not None: - return event['text'] - else: # pragma: no cover - raise OSError() - - -_async = { - 'asyncio': True, - 'translate_request': translate_request, - 'make_response': make_response, - 'websocket': WebSocket, -} diff --git a/venv/lib/python3.9/site-packages/engineio/async_drivers/eventlet.py b/venv/lib/python3.9/site-packages/engineio/async_drivers/eventlet.py deleted file mode 100644 index 6361c4d..0000000 --- a/venv/lib/python3.9/site-packages/engineio/async_drivers/eventlet.py +++ /dev/null @@ -1,52 +0,0 @@ -from eventlet.green.threading import Event -from eventlet import queue, sleep, spawn -from eventlet.websocket import WebSocketWSGI as _WebSocketWSGI - - -class EventletThread: # pragma: no cover - """Thread class that uses eventlet green threads. - - Eventlet's own Thread class has a strange bug that causes _DummyThread - objects to be created and leaked, since they are never garbage collected. - """ - def __init__(self, target, args=None, kwargs=None): - self.target = target - self.args = args or () - self.kwargs = kwargs or {} - self.g = None - - def start(self): - self.g = spawn(self.target, *self.args, **self.kwargs) - - def join(self): - if self.g: - return self.g.wait() - - -class WebSocketWSGI(_WebSocketWSGI): # pragma: no cover - def __init__(self, handler, server): - try: - super().__init__( - handler, max_frame_length=int(server.max_http_buffer_size)) - except TypeError: # pragma: no cover - # older versions of eventlet do not support a max frame size - super().__init__(handler) - self._sock = None - - def __call__(self, environ, start_response): - if 'eventlet.input' not in environ: - raise RuntimeError('You need to use the eventlet server. ' - 'See the Deployment section of the ' - 'documentation for more information.') - self._sock = environ['eventlet.input'].get_socket() - return super().__call__(environ, start_response) - - -_async = { - 'thread': EventletThread, - 'queue': queue.Queue, - 'queue_empty': queue.Empty, - 'event': Event, - 'websocket': WebSocketWSGI, - 'sleep': sleep, -} diff --git a/venv/lib/python3.9/site-packages/engineio/async_drivers/gevent.py b/venv/lib/python3.9/site-packages/engineio/async_drivers/gevent.py deleted file mode 100644 index db284a5..0000000 --- a/venv/lib/python3.9/site-packages/engineio/async_drivers/gevent.py +++ /dev/null @@ -1,83 +0,0 @@ -import gevent -from gevent import queue -from gevent.event import Event -try: - # use gevent-websocket if installed - import geventwebsocket # noqa - SimpleWebSocketWSGI = None -except ImportError: # pragma: no cover - # fallback to simple_websocket when gevent-websocket is not installed - from engineio.async_drivers._websocket_wsgi import SimpleWebSocketWSGI - - -class Thread(gevent.Greenlet): # pragma: no cover - """ - This wrapper class provides gevent Greenlet interface that is compatible - with the standard library's Thread class. - """ - def __init__(self, target, args=[], kwargs={}): - super().__init__(target, *args, **kwargs) - - def _run(self): - return self.run() - - -if SimpleWebSocketWSGI is not None: - class WebSocketWSGI(SimpleWebSocketWSGI): # pragma: no cover - """ - This wrapper class provides a gevent WebSocket interface that is - compatible with eventlet's implementation, using the simple-websocket - package. - """ - def __init__(self, handler, server): - # to avoid the requirement that the standard library is - # monkey-patched, here we pass the gevent versions of the - # concurrency and networking classes required by simple-websocket - import gevent.event - import gevent.selectors - super().__init__(handler, server, - thread_class=Thread, - event_class=gevent.event.Event, - selector_class=gevent.selectors.DefaultSelector) -else: - class WebSocketWSGI: # pragma: no cover - """ - This wrapper class provides a gevent WebSocket interface that is - compatible with eventlet's implementation, using the gevent-websocket - package. - """ - def __init__(self, handler, server): - self.app = handler - - def __call__(self, environ, start_response): - if 'wsgi.websocket' not in environ: - raise RuntimeError('The gevent-websocket server is not ' - 'configured appropriately. ' - 'See the Deployment section of the ' - 'documentation for more information.') - self._sock = environ['wsgi.websocket'] - self.environ = environ - self.version = self._sock.version - self.path = self._sock.path - self.origin = self._sock.origin - self.protocol = self._sock.protocol - return self.app(self) - - def close(self): - return self._sock.close() - - def send(self, message): - return self._sock.send(message) - - def wait(self): - return self._sock.receive() - - -_async = { - 'thread': Thread, - 'queue': queue.JoinableQueue, - 'queue_empty': queue.Empty, - 'event': Event, - 'websocket': WebSocketWSGI, - 'sleep': gevent.sleep, -} diff --git a/venv/lib/python3.9/site-packages/engineio/async_drivers/gevent_uwsgi.py b/venv/lib/python3.9/site-packages/engineio/async_drivers/gevent_uwsgi.py deleted file mode 100644 index b5ccefc..0000000 --- a/venv/lib/python3.9/site-packages/engineio/async_drivers/gevent_uwsgi.py +++ /dev/null @@ -1,168 +0,0 @@ -import gevent -from gevent import queue -from gevent.event import Event -from gevent import selectors -import uwsgi -_websocket_available = hasattr(uwsgi, 'websocket_handshake') - - -class Thread(gevent.Greenlet): # pragma: no cover - """ - This wrapper class provides gevent Greenlet interface that is compatible - with the standard library's Thread class. - """ - def __init__(self, target, args=[], kwargs={}): - super().__init__(target, *args, **kwargs) - - def _run(self): - return self.run() - - -class uWSGIWebSocket: # pragma: no cover - """ - This wrapper class provides a uWSGI WebSocket interface that is - compatible with eventlet's implementation. - """ - def __init__(self, handler, server): - self.app = handler - self._sock = None - self.received_messages = [] - - def __call__(self, environ, start_response): - self._sock = uwsgi.connection_fd() - self.environ = environ - - uwsgi.websocket_handshake() - - self._req_ctx = None - if hasattr(uwsgi, 'request_context'): - # uWSGI >= 2.1.x with support for api access across-greenlets - self._req_ctx = uwsgi.request_context() - else: - # use event and queue for sending messages - self._event = Event() - self._send_queue = queue.Queue() - - # spawn a select greenlet - def select_greenlet_runner(fd, event): - """Sets event when data becomes available to read on fd.""" - sel = selectors.DefaultSelector() - sel.register(fd, selectors.EVENT_READ) - try: - while True: - sel.select() - event.set() - except gevent.GreenletExit: - sel.unregister(fd) - self._select_greenlet = gevent.spawn( - select_greenlet_runner, - self._sock, - self._event) - - self.app(self) - uwsgi.disconnect() - return '' # send nothing as response - - def close(self): - """Disconnects uWSGI from the client.""" - if self._req_ctx is None: - # better kill it here in case wait() is not called again - self._select_greenlet.kill() - self._event.set() - - def _send(self, msg): - """Transmits message either in binary or UTF-8 text mode, - depending on its type.""" - if isinstance(msg, bytes): - method = uwsgi.websocket_send_binary - else: - method = uwsgi.websocket_send - if self._req_ctx is not None: - method(msg, request_context=self._req_ctx) - else: - method(msg) - - def _decode_received(self, msg): - """Returns either bytes or str, depending on message type.""" - if not isinstance(msg, bytes): - # already decoded - do nothing - return msg - # only decode from utf-8 if message is not binary data - type = ord(msg[0:1]) - if type >= 48: # no binary - return msg.decode('utf-8') - # binary message, don't try to decode - return msg - - def send(self, msg): - """Queues a message for sending. Real transmission is done in - wait method. - Sends directly if uWSGI version is new enough.""" - if self._req_ctx is not None: - self._send(msg) - else: - self._send_queue.put(msg) - self._event.set() - - def wait(self): - """Waits and returns received messages. - If running in compatibility mode for older uWSGI versions, - it also sends messages that have been queued by send(). - A return value of None means that connection was closed. - This must be called repeatedly. For uWSGI < 2.1.x it must - be called from the main greenlet.""" - while True: - if self._req_ctx is not None: - try: - msg = uwsgi.websocket_recv(request_context=self._req_ctx) - except OSError: # connection closed - self.close() - return None - return self._decode_received(msg) - else: - if self.received_messages: - return self.received_messages.pop(0) - - # we wake up at least every 3 seconds to let uWSGI - # do its ping/ponging - event_set = self._event.wait(timeout=3) - if event_set: - self._event.clear() - # maybe there is something to send - msgs = [] - while True: - try: - msgs.append(self._send_queue.get(block=False)) - except gevent.queue.Empty: - break - for msg in msgs: - try: - self._send(msg) - except OSError: - self.close() - return None - # maybe there is something to receive, if not, at least - # ensure uWSGI does its ping/ponging - while True: - try: - msg = uwsgi.websocket_recv_nb() - except OSError: # connection closed - self.close() - return None - if msg: # message available - self.received_messages.append( - self._decode_received(msg)) - else: - break - if self.received_messages: - return self.received_messages.pop(0) - - -_async = { - 'thread': Thread, - 'queue': queue.JoinableQueue, - 'queue_empty': queue.Empty, - 'event': Event, - 'websocket': uWSGIWebSocket if _websocket_available else None, - 'sleep': gevent.sleep, -} diff --git a/venv/lib/python3.9/site-packages/engineio/async_drivers/sanic.py b/venv/lib/python3.9/site-packages/engineio/async_drivers/sanic.py deleted file mode 100644 index 4d6a5b8..0000000 --- a/venv/lib/python3.9/site-packages/engineio/async_drivers/sanic.py +++ /dev/null @@ -1,148 +0,0 @@ -import sys -from urllib.parse import urlsplit - -try: # pragma: no cover - from sanic.response import HTTPResponse - try: - from sanic.server.protocols.websocket_protocol import WebSocketProtocol - except ImportError: - from sanic.websocket import WebSocketProtocol -except ImportError: - HTTPResponse = None - WebSocketProtocol = None - - -def create_route(app, engineio_server, engineio_endpoint): # pragma: no cover - """This function sets up the engine.io endpoint as a route for the - application. - - Note that both GET and POST requests must be hooked up on the engine.io - endpoint. - """ - app.add_route(engineio_server.handle_request, engineio_endpoint, - methods=['GET', 'POST', 'OPTIONS']) - try: - app.enable_websocket() - except AttributeError: - # ignore, this version does not support websocket - pass - - -def translate_request(request): # pragma: no cover - """This function takes the arguments passed to the request handler and - uses them to generate a WSGI compatible environ dictionary. - """ - class AwaitablePayload: - def __init__(self, payload): - self.payload = payload or b'' - - async def read(self, length=None): - if length is None: - r = self.payload - self.payload = b'' - else: - r = self.payload[:length] - self.payload = self.payload[length:] - return r - - uri_parts = urlsplit(request.url) - environ = { - 'wsgi.input': AwaitablePayload(request.body), - 'wsgi.errors': sys.stderr, - 'wsgi.version': (1, 0), - 'wsgi.async': True, - 'wsgi.multithread': False, - 'wsgi.multiprocess': False, - 'wsgi.run_once': False, - 'SERVER_SOFTWARE': 'sanic', - 'REQUEST_METHOD': request.method, - 'QUERY_STRING': uri_parts.query or '', - 'RAW_URI': request.url, - 'SERVER_PROTOCOL': 'HTTP/' + request.version, - 'REMOTE_ADDR': '127.0.0.1', - 'REMOTE_PORT': '0', - 'SERVER_NAME': 'sanic', - 'SERVER_PORT': '0', - 'sanic.request': request - } - - for hdr_name, hdr_value in request.headers.items(): - hdr_name = hdr_name.upper() - if hdr_name == 'CONTENT-TYPE': - environ['CONTENT_TYPE'] = hdr_value - continue - elif hdr_name == 'CONTENT-LENGTH': - environ['CONTENT_LENGTH'] = hdr_value - continue - - key = 'HTTP_%s' % hdr_name.replace('-', '_') - if key in environ: - hdr_value = f'{environ[key]},{hdr_value}' - - environ[key] = hdr_value - - environ['wsgi.url_scheme'] = environ.get('HTTP_X_FORWARDED_PROTO', 'http') - - path_info = uri_parts.path - - environ['PATH_INFO'] = path_info - environ['SCRIPT_NAME'] = '' - - return environ - - -def make_response(status, headers, payload, environ): # pragma: no cover - """This function generates an appropriate response object for this async - mode. - """ - headers_dict = {} - content_type = None - for h in headers: - if h[0].lower() == 'content-type': - content_type = h[1] - else: - headers_dict[h[0]] = h[1] - return HTTPResponse(body=payload, content_type=content_type, - status=int(status.split()[0]), headers=headers_dict) - - -class WebSocket: # pragma: no cover - """ - This wrapper class provides a sanic WebSocket interface that is - somewhat compatible with eventlet's implementation. - """ - def __init__(self, handler, server): - self.handler = handler - self.server = server - self._sock = None - - async def __call__(self, environ): - request = environ['sanic.request'] - protocol = request.transport.get_protocol() - self._sock = await protocol.websocket_handshake(request) - - self.environ = environ - await self.handler(self) - return self.server._ok() - - async def close(self): - await self._sock.close() - - async def send(self, message): - await self._sock.send(message) - - async def wait(self): - data = await self._sock.recv() - if not isinstance(data, bytes) and \ - not isinstance(data, str): - raise OSError() - return data - - -_async = { - 'asyncio': True, - 'create_route': create_route, - 'translate_request': translate_request, - 'make_response': make_response, - 'websocket': WebSocket if WebSocketProtocol else None, -} diff --git a/venv/lib/python3.9/site-packages/engineio/async_drivers/threading.py b/venv/lib/python3.9/site-packages/engineio/async_drivers/threading.py deleted file mode 100644 index 1615579..0000000 --- a/venv/lib/python3.9/site-packages/engineio/async_drivers/threading.py +++ /dev/null @@ -1,19 +0,0 @@ -import queue -import threading -import time -from engineio.async_drivers._websocket_wsgi import SimpleWebSocketWSGI - - -class DaemonThread(threading.Thread): # pragma: no cover - def __init__(self, *args, **kwargs): - super().__init__(*args, **kwargs, daemon=True) - - -_async = { - 'thread': DaemonThread, - 'queue': queue.Queue, - 'queue_empty': queue.Empty, - 'event': threading.Event, - 'websocket': SimpleWebSocketWSGI, - 'sleep': time.sleep, -} diff --git a/venv/lib/python3.9/site-packages/engineio/async_drivers/tornado.py b/venv/lib/python3.9/site-packages/engineio/async_drivers/tornado.py deleted file mode 100644 index 01e7d71..0000000 --- a/venv/lib/python3.9/site-packages/engineio/async_drivers/tornado.py +++ /dev/null @@ -1,183 +0,0 @@ -import asyncio -import inspect -import sys -from urllib.parse import urlsplit -from .. import exceptions - -import tornado.web -import tornado.websocket - - -def get_tornado_handler(engineio_server): - class Handler(tornado.websocket.WebSocketHandler): # pragma: no cover - def __init__(self, *args, **kwargs): - super().__init__(*args, **kwargs) - if isinstance(engineio_server.cors_allowed_origins, str): - if engineio_server.cors_allowed_origins == '*': - self.allowed_origins = None - else: - self.allowed_origins = [ - engineio_server.cors_allowed_origins] - else: - self.allowed_origins = engineio_server.cors_allowed_origins - self.receive_queue = asyncio.Queue() - - async def get(self, *args, **kwargs): - if self.request.headers.get('Upgrade', '').lower() == 'websocket': - ret = super().get(*args, **kwargs) - if inspect.iscoroutine(ret): - await ret - else: - await engineio_server.handle_request(self) - - async def open(self, *args, **kwargs): - # this is the handler for the websocket request - asyncio.ensure_future(engineio_server.handle_request(self)) - - async def post(self, *args, **kwargs): - await engineio_server.handle_request(self) - - async def options(self, *args, **kwargs): - await engineio_server.handle_request(self) - - async def on_message(self, message): - await self.receive_queue.put(message) - - async def get_next_message(self): - return await self.receive_queue.get() - - def on_close(self): - self.receive_queue.put_nowait(None) - - def check_origin(self, origin): - if self.allowed_origins is None or origin in self.allowed_origins: - return True - return super().check_origin(origin) - - def get_compression_options(self): - # enable compression - return {} - - return Handler - - -def translate_request(handler): - """This function takes the arguments passed to the request handler and - uses them to generate a WSGI compatible environ dictionary. - """ - class AwaitablePayload: - def __init__(self, payload): - self.payload = payload or b'' - - async def read(self, length=None): - if length is None: - r = self.payload - self.payload = b'' - else: - r = self.payload[:length] - self.payload = self.payload[length:] - return r - - payload = handler.request.body - - uri_parts = urlsplit(handler.request.path) - full_uri = handler.request.path - if handler.request.query: # pragma: no cover - full_uri += '?' + handler.request.query - environ = { - 'wsgi.input': AwaitablePayload(payload), - 'wsgi.errors': sys.stderr, - 'wsgi.version': (1, 0), - 'wsgi.async': True, - 'wsgi.multithread': False, - 'wsgi.multiprocess': False, - 'wsgi.run_once': False, - 'SERVER_SOFTWARE': 'aiohttp', - 'REQUEST_METHOD': handler.request.method, - 'QUERY_STRING': handler.request.query or '', - 'RAW_URI': full_uri, - 'SERVER_PROTOCOL': 'HTTP/%s' % handler.request.version, - 'REMOTE_ADDR': '127.0.0.1', - 'REMOTE_PORT': '0', - 'SERVER_NAME': 'aiohttp', - 'SERVER_PORT': '0', - 'tornado.handler': handler - } - - for hdr_name, hdr_value in handler.request.headers.items(): - hdr_name = hdr_name.upper() - if hdr_name == 'CONTENT-TYPE': - environ['CONTENT_TYPE'] = hdr_value - continue - elif hdr_name == 'CONTENT-LENGTH': - environ['CONTENT_LENGTH'] = hdr_value - continue - - key = 'HTTP_%s' % hdr_name.replace('-', '_') - environ[key] = hdr_value - - environ['wsgi.url_scheme'] = environ.get('HTTP_X_FORWARDED_PROTO', 'http') - - path_info = uri_parts.path - - environ['PATH_INFO'] = path_info - environ['SCRIPT_NAME'] = '' - - return environ - - -def make_response(status, headers, payload, environ): - """This function generates an appropriate response object for this async - mode. - """ - tornado_handler = environ['tornado.handler'] - try: - tornado_handler.set_status(int(status.split()[0])) - except RuntimeError: # pragma: no cover - # for websocket connections Tornado does not accept a response, since - # it already emitted the 101 status code - return - for header, value in headers: - tornado_handler.set_header(header, value) - tornado_handler.write(payload) - tornado_handler.finish() - - -class WebSocket: # pragma: no cover - """ - This wrapper class provides a tornado WebSocket interface that is - somewhat compatible with eventlet's implementation. - """ - def __init__(self, handler, server): - self.handler = handler - self.tornado_handler = None - - async def __call__(self, environ): - self.tornado_handler = environ['tornado.handler'] - self.environ = environ - await self.handler(self) - - async def close(self): - self.tornado_handler.close() - - async def send(self, message): - try: - self.tornado_handler.write_message( - message, binary=isinstance(message, bytes)) - except tornado.websocket.WebSocketClosedError: - raise exceptions.EngineIOError() - - async def wait(self): - msg = await self.tornado_handler.get_next_message() - if not isinstance(msg, bytes) and \ - not isinstance(msg, str): - raise OSError() - return msg - - -_async = { - 'asyncio': True, - 'translate_request': translate_request, - 'make_response': make_response, - 'websocket': WebSocket, -} diff --git a/venv/lib/python3.9/site-packages/engineio/async_server.py b/venv/lib/python3.9/site-packages/engineio/async_server.py deleted file mode 100644 index e0e252e..0000000 --- a/venv/lib/python3.9/site-packages/engineio/async_server.py +++ /dev/null @@ -1,613 +0,0 @@ -import asyncio -import inspect -import urllib - -from . import base_server -from . import exceptions -from . import packet -from . import async_socket - -# this set is used to keep references to background tasks to prevent them from -# being garbage collected mid-execution. Solution taken from -# https://docs.python.org/3/library/asyncio-task.html#asyncio.create_task -task_reference_holder = set() - - -class AsyncServer(base_server.BaseServer): - """An Engine.IO server for asyncio. - - This class implements a fully compliant Engine.IO web server with support - for websocket and long-polling transports, compatible with the asyncio - framework on Python 3.5 or newer. - - :param async_mode: The asynchronous model to use. See the Deployment - section in the documentation for a description of the - available options. Valid async modes are "aiohttp", - "sanic", "tornado" and "asgi". If this argument is not - given, "aiohttp" is tried first, followed by "sanic", - "tornado", and finally "asgi". The first async mode that - has all its dependencies installed is the one that is - chosen. - :param ping_interval: The interval in seconds at which the server pings - the client. The default is 25 seconds. For advanced - control, a two element tuple can be given, where - the first number is the ping interval and the second - is a grace period added by the server. - :param ping_timeout: The time in seconds that the client waits for the - server to respond before disconnecting. The default - is 20 seconds. - :param max_http_buffer_size: The maximum size that is accepted for incoming - messages. The default is 1,000,000 bytes. In - spite of its name, the value set in this - argument is enforced for HTTP long-polling and - WebSocket connections. - :param allow_upgrades: Whether to allow transport upgrades or not. - :param http_compression: Whether to compress packages when using the - polling transport. - :param compression_threshold: Only compress messages when their byte size - is greater than this value. - :param cookie: If set to a string, it is the name of the HTTP cookie the - server sends back tot he client containing the client - session id. If set to a dictionary, the ``'name'`` key - contains the cookie name and other keys define cookie - attributes, where the value of each attribute can be a - string, a callable with no arguments, or a boolean. If set - to ``None`` (the default), a cookie is not sent to the - client. - :param cors_allowed_origins: Origin or list of origins that are allowed to - connect to this server. Only the same origin - is allowed by default. Set this argument to - ``'*'`` or ``['*']`` to allow all origins, or - to ``[]`` to disable CORS handling. - :param cors_credentials: Whether credentials (cookies, authentication) are - allowed in requests to this server. - :param logger: To enable logging set to ``True`` or pass a logger object to - use. To disable logging set to ``False``. Note that fatal - errors are logged even when ``logger`` is ``False``. - :param json: An alternative JSON module to use for encoding and decoding - packets. Custom JSON modules must have ``dumps`` and ``loads`` - functions that are compatible with the standard library - versions. This is a process-wide setting, all instantiated - servers and clients must use the same JSON module. - :param async_handlers: If set to ``True``, run message event handlers in - non-blocking threads. To run handlers synchronously, - set to ``False``. The default is ``True``. - :param monitor_clients: If set to ``True``, a background task will ensure - inactive clients are closed. Set to ``False`` to - disable the monitoring task (not recommended). The - default is ``True``. - :param transports: The list of allowed transports. Valid transports - are ``'polling'`` and ``'websocket'``. Defaults to - ``['polling', 'websocket']``. - :param kwargs: Reserved for future extensions, any additional parameters - given as keyword arguments will be silently ignored. - """ - def is_asyncio_based(self): - return True - - def async_modes(self): - return ['aiohttp', 'sanic', 'tornado', 'asgi'] - - def attach(self, app, engineio_path='engine.io'): - """Attach the Engine.IO server to an application.""" - engineio_path = engineio_path.strip('/') - self._async['create_route'](app, self, f'/{engineio_path}/') - - async def send(self, sid, data): - """Send a message to a client. - - :param sid: The session id of the recipient client. - :param data: The data to send to the client. Data can be of type - ``str``, ``bytes``, ``list`` or ``dict``. If a ``list`` - or ``dict``, the data will be serialized as JSON. - - Note: this method is a coroutine. - """ - await self.send_packet(sid, packet.Packet(packet.MESSAGE, data=data)) - - async def send_packet(self, sid, pkt): - """Send a raw packet to a client. - - :param sid: The session id of the recipient client. - :param pkt: The packet to send to the client. - - Note: this method is a coroutine. - """ - try: - socket = self._get_socket(sid) - except KeyError: - # the socket is not available - self.logger.warning('Cannot send to sid %s', sid) - return - await socket.send(pkt) - - async def get_session(self, sid): - """Return the user session for a client. - - :param sid: The session id of the client. - - The return value is a dictionary. Modifications made to this - dictionary are not guaranteed to be preserved. If you want to modify - the user session, use the ``session`` context manager instead. - """ - socket = self._get_socket(sid) - return socket.session - - async def save_session(self, sid, session): - """Store the user session for a client. - - :param sid: The session id of the client. - :param session: The session dictionary. - """ - socket = self._get_socket(sid) - socket.session = session - - def session(self, sid): - """Return the user session for a client with context manager syntax. - - :param sid: The session id of the client. - - This is a context manager that returns the user session dictionary for - the client. Any changes that are made to this dictionary inside the - context manager block are saved back to the session. Example usage:: - - @eio.on('connect') - def on_connect(sid, environ): - username = authenticate_user(environ) - if not username: - return False - with eio.session(sid) as session: - session['username'] = username - - @eio.on('message') - def on_message(sid, msg): - async with eio.session(sid) as session: - print('received message from ', session['username']) - """ - class _session_context_manager: - def __init__(self, server, sid): - self.server = server - self.sid = sid - self.session = None - - async def __aenter__(self): - self.session = await self.server.get_session(sid) - return self.session - - async def __aexit__(self, *args): - await self.server.save_session(sid, self.session) - - return _session_context_manager(self, sid) - - async def disconnect(self, sid=None): - """Disconnect a client. - - :param sid: The session id of the client to close. If this parameter - is not given, then all clients are closed. - - Note: this method is a coroutine. - """ - if sid is not None: - try: - socket = self._get_socket(sid) - except KeyError: # pragma: no cover - # the socket was already closed or gone - pass - else: - await socket.close(reason=self.reason.SERVER_DISCONNECT) - if sid in self.sockets: # pragma: no cover - del self.sockets[sid] - else: - await asyncio.wait([ - asyncio.create_task(client.close( - reason=self.reason.SERVER_DISCONNECT)) - for client in self.sockets.values() - ]) - self.sockets = {} - - async def handle_request(self, *args, **kwargs): - """Handle an HTTP request from the client. - - This is the entry point of the Engine.IO application. This function - returns the HTTP response to deliver to the client. - - Note: this method is a coroutine. - """ - translate_request = self._async['translate_request'] - if inspect.iscoroutinefunction(translate_request): - environ = await translate_request(*args, **kwargs) - else: - environ = translate_request(*args, **kwargs) - - if self.cors_allowed_origins != []: - # Validate the origin header if present - # This is important for WebSocket more than for HTTP, since - # browsers only apply CORS controls to HTTP. - origin = environ.get('HTTP_ORIGIN') - if origin: - allowed_origins = self._cors_allowed_origins(environ) - if allowed_origins is not None and origin not in \ - allowed_origins: - self._log_error_once( - origin + ' is not an accepted origin.', 'bad-origin') - return await self._make_response( - self._bad_request( - origin + ' is not an accepted origin.'), - environ) - - method = environ['REQUEST_METHOD'] - query = urllib.parse.parse_qs(environ.get('QUERY_STRING', '')) - - sid = query['sid'][0] if 'sid' in query else None - jsonp = False - jsonp_index = None - - # make sure the client uses an allowed transport - transport = query.get('transport', ['polling'])[0] - if transport not in self.transports: - self._log_error_once('Invalid transport', 'bad-transport') - return await self._make_response( - self._bad_request('Invalid transport'), environ) - - # make sure the client speaks a compatible Engine.IO version - sid = query['sid'][0] if 'sid' in query else None - if sid is None and query.get('EIO') != ['4']: - self._log_error_once( - 'The client is using an unsupported version of the Socket.IO ' - 'or Engine.IO protocols', 'bad-version' - ) - return await self._make_response(self._bad_request( - 'The client is using an unsupported version of the Socket.IO ' - 'or Engine.IO protocols' - ), environ) - - if 'j' in query: - jsonp = True - try: - jsonp_index = int(query['j'][0]) - except (ValueError, KeyError, IndexError): - # Invalid JSONP index number - pass - - if jsonp and jsonp_index is None: - self._log_error_once('Invalid JSONP index number', - 'bad-jsonp-index') - r = self._bad_request('Invalid JSONP index number') - elif method == 'GET': - upgrade_header = environ.get('HTTP_UPGRADE').lower() \ - if 'HTTP_UPGRADE' in environ else None - if sid is None: - # transport must be one of 'polling' or 'websocket'. - # if 'websocket', the HTTP_UPGRADE header must match. - if transport == 'polling' \ - or transport == upgrade_header == 'websocket': - r = await self._handle_connect(environ, transport, - jsonp_index) - else: - self._log_error_once('Invalid websocket upgrade', - 'bad-upgrade') - r = self._bad_request('Invalid websocket upgrade') - else: - if sid not in self.sockets: - self._log_error_once(f'Invalid session {sid}', 'bad-sid') - r = self._bad_request(f'Invalid session {sid}') - else: - try: - socket = self._get_socket(sid) - except KeyError as e: # pragma: no cover - self._log_error_once(f'{e} {sid}', 'bad-sid') - r = self._bad_request(f'{e} {sid}') - else: - if self.transport(sid) != transport and \ - transport != upgrade_header: - self._log_error_once( - f'Invalid transport for session {sid}', - 'bad-transport') - r = self._bad_request('Invalid transport') - else: - try: - packets = await socket.handle_get_request( - environ) - if isinstance(packets, list): - r = self._ok(packets, - jsonp_index=jsonp_index) - else: - r = packets - except exceptions.EngineIOError: - if sid in self.sockets: # pragma: no cover - await self.disconnect(sid) - r = self._bad_request() - if sid in self.sockets and \ - self.sockets[sid].closed: - del self.sockets[sid] - elif method == 'POST': - if sid is None or sid not in self.sockets: - self._log_error_once(f'Invalid session {sid}', 'bad-sid') - r = self._bad_request(f'Invalid session {sid}') - else: - socket = self._get_socket(sid) - try: - await socket.handle_post_request(environ) - r = self._ok(jsonp_index=jsonp_index) - except exceptions.EngineIOError: - if sid in self.sockets: # pragma: no cover - await self.disconnect(sid) - r = self._bad_request() - except: # pragma: no cover - # for any other unexpected errors, we log the error - # and keep going - self.logger.exception('post request handler error') - r = self._ok(jsonp_index=jsonp_index) - elif method == 'OPTIONS': - r = self._ok() - else: - self.logger.warning('Method %s not supported', method) - r = self._method_not_found() - if not isinstance(r, dict): - return r - if self.http_compression and \ - len(r['response']) >= self.compression_threshold: - encodings = [e.split(';')[0].strip() for e in - environ.get('HTTP_ACCEPT_ENCODING', '').split(',')] - for encoding in encodings: - if encoding in self.compression_methods: - r['response'] = \ - getattr(self, '_' + encoding)(r['response']) - r['headers'] += [('Content-Encoding', encoding)] - break - return await self._make_response(r, environ) - - async def shutdown(self): - """Stop Socket.IO background tasks. - - This method stops background activity initiated by the Socket.IO - server. It must be called before shutting down the web server. - """ - self.logger.info('Socket.IO is shutting down') - if self.service_task_event: # pragma: no cover - self.service_task_event.set() - await self.service_task_handle - self.service_task_handle = None - - def start_background_task(self, target, *args, **kwargs): - """Start a background task using the appropriate async model. - - This is a utility function that applications can use to start a - background task using the method that is compatible with the - selected async mode. - - :param target: the target function to execute. - :param args: arguments to pass to the function. - :param kwargs: keyword arguments to pass to the function. - - The return value is a ``asyncio.Task`` object. - """ - return asyncio.ensure_future(target(*args, **kwargs)) - - async def sleep(self, seconds=0): - """Sleep for the requested amount of time using the appropriate async - model. - - This is a utility function that applications can use to put a task to - sleep without having to worry about using the correct call for the - selected async mode. - - Note: this method is a coroutine. - """ - return await asyncio.sleep(seconds) - - def create_queue(self, *args, **kwargs): - """Create a queue object using the appropriate async model. - - This is a utility function that applications can use to create a queue - without having to worry about using the correct call for the selected - async mode. For asyncio based async modes, this returns an instance of - ``asyncio.Queue``. - """ - return asyncio.Queue(*args, **kwargs) - - def get_queue_empty_exception(self): - """Return the queue empty exception for the appropriate async model. - - This is a utility function that applications can use to work with a - queue without having to worry about using the correct call for the - selected async mode. For asyncio based async modes, this returns an - instance of ``asyncio.QueueEmpty``. - """ - return asyncio.QueueEmpty - - def create_event(self, *args, **kwargs): - """Create an event object using the appropriate async model. - - This is a utility function that applications can use to create an - event without having to worry about using the correct call for the - selected async mode. For asyncio based async modes, this returns - an instance of ``asyncio.Event``. - """ - return asyncio.Event(*args, **kwargs) - - async def _make_response(self, response_dict, environ): - cors_headers = self._cors_headers(environ) - make_response = self._async['make_response'] - if inspect.iscoroutinefunction(make_response): - response = await make_response( - response_dict['status'], - response_dict['headers'] + cors_headers, - response_dict['response'], environ) - else: - response = make_response( - response_dict['status'], - response_dict['headers'] + cors_headers, - response_dict['response'], environ) - return response - - async def _handle_connect(self, environ, transport, jsonp_index=None): - """Handle a client connection request.""" - if self.start_service_task: - # start the service task to monitor connected clients - self.start_service_task = False - self.service_task_handle = self.start_background_task( - self._service_task) - - sid = self.generate_id() - s = async_socket.AsyncSocket(self, sid) - self.sockets[sid] = s - - pkt = packet.Packet(packet.OPEN, { - 'sid': sid, - 'upgrades': self._upgrades(sid, transport), - 'pingTimeout': int(self.ping_timeout * 1000), - 'pingInterval': int( - self.ping_interval + self.ping_interval_grace_period) * 1000, - 'maxPayload': self.max_http_buffer_size, - }) - await s.send(pkt) - s.schedule_ping() - - ret = await self._trigger_event('connect', sid, environ, - run_async=False) - if ret is not None and ret is not True: - del self.sockets[sid] - self.logger.warning('Application rejected connection') - return self._unauthorized(ret or None) - - if transport == 'websocket': - ret = await s.handle_get_request(environ) - if s.closed and sid in self.sockets: - # websocket connection ended, so we are done - del self.sockets[sid] - return ret - else: - s.connected = True - headers = None - if self.cookie: - if isinstance(self.cookie, dict): - headers = [( - 'Set-Cookie', - self._generate_sid_cookie(sid, self.cookie) - )] - else: - headers = [( - 'Set-Cookie', - self._generate_sid_cookie(sid, { - 'name': self.cookie, 'path': '/', 'SameSite': 'Lax' - }) - )] - try: - return self._ok(await s.poll(), headers=headers, - jsonp_index=jsonp_index) - except exceptions.QueueEmpty: - return self._bad_request() - - async def _trigger_event(self, event, *args, **kwargs): - """Invoke an event handler.""" - run_async = kwargs.pop('run_async', False) - ret = None - if event in self.handlers: - if inspect.iscoroutinefunction(self.handlers[event]): - async def run_async_handler(): - try: - try: - return await self.handlers[event](*args) - except TypeError: - if event == 'disconnect' and \ - len(args) == 2: # pragma: no branch - # legacy disconnect events do not have a reason - # argument - return await self.handlers[event](args[0]) - else: # pragma: no cover - raise - except asyncio.CancelledError: # pragma: no cover - pass - except: - self.logger.exception(event + ' async handler error') - if event == 'connect': - # if connect handler raised error we reject the - # connection - return False - - if run_async: - ret = self.start_background_task(run_async_handler) - task_reference_holder.add(ret) - ret.add_done_callback(task_reference_holder.discard) - else: - ret = await run_async_handler() - else: - async def run_sync_handler(): - try: - try: - return self.handlers[event](*args) - except TypeError: - if event == 'disconnect' and \ - len(args) == 2: # pragma: no branch - # legacy disconnect events do not have a reason - # argument - return self.handlers[event](args[0]) - else: # pragma: no cover - raise - except: - self.logger.exception(event + ' handler error') - if event == 'connect': - # if connect handler raised error we reject the - # connection - return False - - if run_async: - ret = self.start_background_task(run_sync_handler) - task_reference_holder.add(ret) - ret.add_done_callback(task_reference_holder.discard) - else: - ret = await run_sync_handler() - return ret - - async def _service_task(self): # pragma: no cover - """Monitor connected clients and clean up those that time out.""" - loop = asyncio.get_running_loop() - self.service_task_event = self.create_event() - while not self.service_task_event.is_set(): - if len(self.sockets) == 0: - # nothing to do - try: - await asyncio.wait_for(self.service_task_event.wait(), - timeout=self.ping_timeout) - break - except asyncio.TimeoutError: - continue - - # go through the entire client list in a ping interval cycle - sleep_interval = self.ping_timeout / len(self.sockets) - - try: - # iterate over the current clients - for s in self.sockets.copy().values(): - if s.closed: - try: - del self.sockets[s.sid] - except KeyError: - # the socket could have also been removed by - # the _get_socket() method from another thread - pass - elif not s.closing: - await s.check_ping_timeout() - try: - await asyncio.wait_for(self.service_task_event.wait(), - timeout=sleep_interval) - raise KeyboardInterrupt() - except asyncio.TimeoutError: - continue - except ( - SystemExit, - KeyboardInterrupt, - asyncio.CancelledError, - GeneratorExit, - ): - self.logger.info('service task canceled') - break - except: - if loop.is_closed(): - self.logger.info('event loop is closed, exiting service ' - 'task') - break - - # an unexpected exception has occurred, log it and continue - self.logger.exception('service task exception') diff --git a/venv/lib/python3.9/site-packages/engineio/async_socket.py b/venv/lib/python3.9/site-packages/engineio/async_socket.py deleted file mode 100644 index cfdbe1a..0000000 --- a/venv/lib/python3.9/site-packages/engineio/async_socket.py +++ /dev/null @@ -1,261 +0,0 @@ -import asyncio -import sys -import time - -from . import base_socket -from . import exceptions -from . import packet -from . import payload - - -class AsyncSocket(base_socket.BaseSocket): - async def poll(self): - """Wait for packets to send to the client.""" - try: - packets = [await asyncio.wait_for( - self.queue.get(), - self.server.ping_interval + self.server.ping_timeout)] - self.queue.task_done() - except (asyncio.TimeoutError, asyncio.CancelledError): - raise exceptions.QueueEmpty() - if packets == [None]: - return [] - while True: - try: - pkt = self.queue.get_nowait() - self.queue.task_done() - if pkt is None: - self.queue.put_nowait(None) - break - packets.append(pkt) - except asyncio.QueueEmpty: - break - return packets - - async def receive(self, pkt): - """Receive packet from the client.""" - self.server.logger.info('%s: Received packet %s data %s', - self.sid, packet.packet_names[pkt.packet_type], - pkt.data if not isinstance(pkt.data, bytes) - else '') - if pkt.packet_type == packet.PONG: - self.schedule_ping() - elif pkt.packet_type == packet.MESSAGE: - await self.server._trigger_event( - 'message', self.sid, pkt.data, - run_async=self.server.async_handlers) - elif pkt.packet_type == packet.UPGRADE: - await self.send(packet.Packet(packet.NOOP)) - elif pkt.packet_type == packet.CLOSE: - await self.close(wait=False, abort=True, - reason=self.server.reason.CLIENT_DISCONNECT) - else: - raise exceptions.UnknownPacketError() - - async def check_ping_timeout(self): - """Make sure the client is still sending pings.""" - if self.closed: - raise exceptions.SocketIsClosedError() - if self.last_ping and \ - time.time() - self.last_ping > self.server.ping_timeout: - self.server.logger.info('%s: Client is gone, closing socket', - self.sid) - # Passing abort=False here will cause close() to write a - # CLOSE packet. This has the effect of updating half-open sockets - # to their correct state of disconnected - await self.close(wait=False, abort=False, - reason=self.server.reason.PING_TIMEOUT) - return False - return True - - async def send(self, pkt): - """Send a packet to the client.""" - if not await self.check_ping_timeout(): - return - else: - await self.queue.put(pkt) - self.server.logger.info('%s: Sending packet %s data %s', - self.sid, packet.packet_names[pkt.packet_type], - pkt.data if not isinstance(pkt.data, bytes) - else '') - - async def handle_get_request(self, environ): - """Handle a long-polling GET request from the client.""" - connections = [ - s.strip() - for s in environ.get('HTTP_CONNECTION', '').lower().split(',')] - transport = environ.get('HTTP_UPGRADE', '').lower() - if 'upgrade' in connections and transport in self.upgrade_protocols: - self.server.logger.info('%s: Received request to upgrade to %s', - self.sid, transport) - return await getattr(self, '_upgrade_' + transport)(environ) - if self.upgrading or self.upgraded: - # we are upgrading to WebSocket, do not return any more packets - # through the polling endpoint - return [packet.Packet(packet.NOOP)] - try: - packets = await self.poll() - except exceptions.QueueEmpty: - exc = sys.exc_info() - await self.close(wait=False, - reason=self.server.reason.TRANSPORT_ERROR) - raise exc[1].with_traceback(exc[2]) - return packets - - async def handle_post_request(self, environ): - """Handle a long-polling POST request from the client.""" - length = int(environ.get('CONTENT_LENGTH', '0')) - if length > self.server.max_http_buffer_size: - raise exceptions.ContentTooLongError() - else: - body = (await environ['wsgi.input'].read(length)).decode('utf-8') - p = payload.Payload(encoded_payload=body) - for pkt in p.packets: - await self.receive(pkt) - - async def close(self, wait=True, abort=False, reason=None): - """Close the socket connection.""" - if not self.closed and not self.closing: - self.closing = True - await self.server._trigger_event( - 'disconnect', self.sid, - reason or self.server.reason.SERVER_DISCONNECT, - run_async=False) - if not abort: - await self.send(packet.Packet(packet.CLOSE)) - self.closed = True - if wait: - await self.queue.join() - - def schedule_ping(self): - self.server.start_background_task(self._send_ping) - - async def _send_ping(self): - self.last_ping = None - await asyncio.sleep(self.server.ping_interval) - if not self.closing and not self.closed: - self.last_ping = time.time() - await self.send(packet.Packet(packet.PING)) - - async def _upgrade_websocket(self, environ): - """Upgrade the connection from polling to websocket.""" - if self.upgraded: - raise OSError('Socket has been upgraded already') - if self.server._async['websocket'] is None: - # the selected async mode does not support websocket - return self.server._bad_request() - ws = self.server._async['websocket']( - self._websocket_handler, self.server) - return await ws(environ) - - async def _websocket_handler(self, ws): - """Engine.IO handler for websocket transport.""" - async def websocket_wait(): - data = await ws.wait() - if data and len(data) > self.server.max_http_buffer_size: - raise ValueError('packet is too large') - return data - - if self.connected: - # the socket was already connected, so this is an upgrade - self.upgrading = True # hold packet sends during the upgrade - - try: - pkt = await websocket_wait() - except OSError: # pragma: no cover - return - decoded_pkt = packet.Packet(encoded_packet=pkt) - if decoded_pkt.packet_type != packet.PING or \ - decoded_pkt.data != 'probe': - self.server.logger.info( - '%s: Failed websocket upgrade, no PING packet', self.sid) - self.upgrading = False - return - await ws.send(packet.Packet(packet.PONG, data='probe').encode()) - await self.queue.put(packet.Packet(packet.NOOP)) # end poll - - try: - pkt = await websocket_wait() - except OSError: # pragma: no cover - self.upgrading = False - return - decoded_pkt = packet.Packet(encoded_packet=pkt) - if decoded_pkt.packet_type != packet.UPGRADE: - self.upgraded = False - self.server.logger.info( - ('%s: Failed websocket upgrade, expected UPGRADE packet, ' - 'received %s instead.'), - self.sid, pkt) - self.upgrading = False - return - self.upgraded = True - self.upgrading = False - else: - self.connected = True - self.upgraded = True - - # start separate writer thread - async def writer(): - while True: - packets = None - try: - packets = await self.poll() - except exceptions.QueueEmpty: - break - if not packets: - # empty packet list returned -> connection closed - break - try: - for pkt in packets: - await ws.send(pkt.encode()) - except: - break - await ws.close() - - writer_task = asyncio.ensure_future(writer()) - - self.server.logger.info( - '%s: Upgrade to websocket successful', self.sid) - - while True: - p = None - wait_task = asyncio.ensure_future(websocket_wait()) - try: - p = await asyncio.wait_for( - wait_task, - self.server.ping_interval + self.server.ping_timeout) - except asyncio.CancelledError: # pragma: no cover - # there is a bug (https://bugs.python.org/issue30508) in - # asyncio that causes a "Task exception never retrieved" error - # to appear when wait_task raises an exception before it gets - # cancelled. Calling wait_task.exception() prevents the error - # from being issued in Python 3.6, but causes other errors in - # other versions, so we run it with all errors suppressed and - # hope for the best. - try: - wait_task.exception() - except: - pass - break - except: - break - if p is None: - # connection closed by client - break - pkt = packet.Packet(encoded_packet=p) - try: - await self.receive(pkt) - except exceptions.UnknownPacketError: # pragma: no cover - pass - except exceptions.SocketIsClosedError: # pragma: no cover - self.server.logger.info('Receive error -- socket is closed') - break - except: # pragma: no cover - # if we get an unexpected exception we log the error and exit - # the connection properly - self.server.logger.exception('Unknown receive error') - - await self.queue.put(None) # unlock the writer task so it can exit - await asyncio.wait_for(writer_task, timeout=None) - await self.close(wait=False, abort=True, - reason=self.server.reason.TRANSPORT_CLOSE) diff --git a/venv/lib/python3.9/site-packages/engineio/base_client.py b/venv/lib/python3.9/site-packages/engineio/base_client.py deleted file mode 100644 index 01a42c5..0000000 --- a/venv/lib/python3.9/site-packages/engineio/base_client.py +++ /dev/null @@ -1,169 +0,0 @@ -import logging -import signal -import threading -import time -import urllib -from . import packet - -default_logger = logging.getLogger('engineio.client') -connected_clients = [] - - -def signal_handler(sig, frame): - """SIGINT handler. - - Disconnect all active clients and then invoke the original signal handler. - """ - for client in connected_clients[:]: - if not client.is_asyncio_based(): - client.disconnect() - if callable(original_signal_handler): - return original_signal_handler(sig, frame) - else: # pragma: no cover - # Handle case where no original SIGINT handler was present. - return signal.default_int_handler(sig, frame) - - -original_signal_handler = None - - -class BaseClient: - event_names = ['connect', 'disconnect', 'message'] - - class reason: - """Disconnection reasons.""" - #: Client-initiated disconnection. - CLIENT_DISCONNECT = 'client disconnect' - #: Server-initiated disconnection. - SERVER_DISCONNECT = 'server disconnect' - #: Transport error. - TRANSPORT_ERROR = 'transport error' - - def __init__(self, logger=False, json=None, request_timeout=5, - http_session=None, ssl_verify=True, handle_sigint=True, - websocket_extra_options=None, timestamp_requests=True): - global original_signal_handler - if handle_sigint and original_signal_handler is None and \ - threading.current_thread() == threading.main_thread(): - original_signal_handler = signal.signal(signal.SIGINT, - signal_handler) - self.handlers = {} - self.base_url = None - self.transports = None - self.current_transport = None - self.sid = None - self.upgrades = None - self.ping_interval = None - self.ping_timeout = None - self.http = http_session - self.external_http = http_session is not None - self.handle_sigint = handle_sigint - self.ws = None - self.read_loop_task = None - self.write_loop_task = None - self.queue = self.create_queue() - self.queue_empty = self.get_queue_empty_exception() - self.state = 'disconnected' - self.ssl_verify = ssl_verify - self.websocket_extra_options = websocket_extra_options or {} - self.timestamp_requests = timestamp_requests - - if json is not None: - packet.Packet.json = json - if not isinstance(logger, bool): - self.logger = logger - else: - self.logger = default_logger - if self.logger.level == logging.NOTSET: - if logger: - self.logger.setLevel(logging.INFO) - else: - self.logger.setLevel(logging.ERROR) - self.logger.addHandler(logging.StreamHandler()) - - self.request_timeout = request_timeout - - def is_asyncio_based(self): - return False - - def on(self, event, handler=None): - """Register an event handler. - - :param event: The event name. Can be ``'connect'``, ``'message'`` or - ``'disconnect'``. - :param handler: The function that should be invoked to handle the - event. When this parameter is not given, the method - acts as a decorator for the handler function. - - Example usage:: - - # as a decorator: - @eio.on('connect') - def connect_handler(): - print('Connection request') - - # as a method: - def message_handler(msg): - print('Received message: ', msg) - eio.send('response') - eio.on('message', message_handler) - """ - if event not in self.event_names: - raise ValueError('Invalid event') - - def set_handler(handler): - self.handlers[event] = handler - return handler - - if handler is None: - return set_handler - set_handler(handler) - - def transport(self): - """Return the name of the transport currently in use. - - The possible values returned by this function are ``'polling'`` and - ``'websocket'``. - """ - return self.current_transport - - def _reset(self): - self.state = 'disconnected' - self.sid = None - - def _get_engineio_url(self, url, engineio_path, transport): - """Generate the Engine.IO connection URL.""" - engineio_path = engineio_path.strip('/') - parsed_url = urllib.parse.urlparse(url) - - if transport == 'polling': - scheme = 'http' - elif transport == 'websocket': - scheme = 'ws' - else: # pragma: no cover - raise ValueError('invalid transport') - if parsed_url.scheme in ['https', 'wss']: - scheme += 's' - - return ('{scheme}://{netloc}/{path}/?{query}' - '{sep}transport={transport}&EIO=4').format( - scheme=scheme, netloc=parsed_url.netloc, - path=engineio_path, query=parsed_url.query, - sep='&' if parsed_url.query else '', - transport=transport) - - def _get_url_timestamp(self): - """Generate the Engine.IO query string timestamp.""" - if not self.timestamp_requests: - return '' - return '&t=' + str(time.time()) - - def create_queue(self, *args, **kwargs): # pragma: no cover - """Create a queue object.""" - raise NotImplementedError('must be implemented in a subclass') - - def get_queue_empty_exception(self): # pragma: no cover - """Return the queue empty exception raised by queues created by the - ``create_queue()`` method. - """ - raise NotImplementedError('must be implemented in a subclass') diff --git a/venv/lib/python3.9/site-packages/engineio/base_server.py b/venv/lib/python3.9/site-packages/engineio/base_server.py deleted file mode 100644 index 7d717fb..0000000 --- a/venv/lib/python3.9/site-packages/engineio/base_server.py +++ /dev/null @@ -1,358 +0,0 @@ -import base64 -import gzip -import importlib -import io -import logging -import secrets -import zlib - -from . import packet -from . import payload - -default_logger = logging.getLogger('engineio.server') - - -class BaseServer: - compression_methods = ['gzip', 'deflate'] - event_names = ['connect', 'disconnect', 'message'] - valid_transports = ['polling', 'websocket'] - _default_monitor_clients = True - sequence_number = 0 - - class reason: - """Disconnection reasons.""" - #: Server-initiated disconnection. - SERVER_DISCONNECT = 'server disconnect' - #: Client-initiated disconnection. - CLIENT_DISCONNECT = 'client disconnect' - #: Ping timeout. - PING_TIMEOUT = 'ping timeout' - #: Transport close. - TRANSPORT_CLOSE = 'transport close' - #: Transport error. - TRANSPORT_ERROR = 'transport error' - - def __init__(self, async_mode=None, ping_interval=25, ping_timeout=20, - max_http_buffer_size=1000000, allow_upgrades=True, - http_compression=True, compression_threshold=1024, - cookie=None, cors_allowed_origins=None, - cors_credentials=True, logger=False, json=None, - async_handlers=True, monitor_clients=None, transports=None, - **kwargs): - self.ping_timeout = ping_timeout - if isinstance(ping_interval, tuple): - self.ping_interval = ping_interval[0] - self.ping_interval_grace_period = ping_interval[1] - else: - self.ping_interval = ping_interval - self.ping_interval_grace_period = 0 - self.max_http_buffer_size = max_http_buffer_size - self.allow_upgrades = allow_upgrades - self.http_compression = http_compression - self.compression_threshold = compression_threshold - self.cookie = cookie - self.cors_allowed_origins = cors_allowed_origins - self.cors_credentials = cors_credentials - self.async_handlers = async_handlers - self.sockets = {} - self.handlers = {} - self.log_message_keys = set() - self.start_service_task = monitor_clients \ - if monitor_clients is not None else self._default_monitor_clients - self.service_task_handle = None - self.service_task_event = None - if json is not None: - packet.Packet.json = json - if not isinstance(logger, bool): - self.logger = logger - else: - self.logger = default_logger - if self.logger.level == logging.NOTSET: - if logger: - self.logger.setLevel(logging.INFO) - else: - self.logger.setLevel(logging.ERROR) - self.logger.addHandler(logging.StreamHandler()) - modes = self.async_modes() - if async_mode is not None: - modes = [async_mode] if async_mode in modes else [] - self._async = None - self.async_mode = None - for mode in modes: - try: - self._async = importlib.import_module( - 'engineio.async_drivers.' + mode)._async - asyncio_based = self._async['asyncio'] \ - if 'asyncio' in self._async else False - if asyncio_based != self.is_asyncio_based(): - continue # pragma: no cover - self.async_mode = mode - break - except ImportError: - pass - if self.async_mode is None: - raise ValueError('Invalid async_mode specified') - if self.is_asyncio_based() and \ - ('asyncio' not in self._async or not - self._async['asyncio']): # pragma: no cover - raise ValueError('The selected async_mode is not asyncio ' - 'compatible') - if not self.is_asyncio_based() and 'asyncio' in self._async and \ - self._async['asyncio']: # pragma: no cover - raise ValueError('The selected async_mode requires asyncio and ' - 'must use the AsyncServer class') - if transports is not None: - if isinstance(transports, str): - transports = [transports] - transports = [transport for transport in transports - if transport in self.valid_transports] - if not transports: - raise ValueError('No valid transports provided') - self.transports = transports or self.valid_transports - self.logger.info('Server initialized for %s.', self.async_mode) - - def is_asyncio_based(self): - return False - - def async_modes(self): - return ['eventlet', 'gevent_uwsgi', 'gevent', 'threading'] - - def on(self, event, handler=None): - """Register an event handler. - - :param event: The event name. Can be ``'connect'``, ``'message'`` or - ``'disconnect'``. - :param handler: The function that should be invoked to handle the - event. When this parameter is not given, the method - acts as a decorator for the handler function. - - Example usage:: - - # as a decorator: - @eio.on('connect') - def connect_handler(sid, environ): - print('Connection request') - if environ['REMOTE_ADDR'] in blacklisted: - return False # reject - - # as a method: - def message_handler(sid, msg): - print('Received message: ', msg) - eio.send(sid, 'response') - eio.on('message', message_handler) - - The handler function receives the ``sid`` (session ID) for the - client as first argument. The ``'connect'`` event handler receives the - WSGI environment as a second argument, and can return ``False`` to - reject the connection. The ``'message'`` handler receives the message - payload as a second argument. The ``'disconnect'`` handler does not - take a second argument. - """ - if event not in self.event_names: - raise ValueError('Invalid event') - - def set_handler(handler): - self.handlers[event] = handler - return handler - - if handler is None: - return set_handler - set_handler(handler) - - def transport(self, sid): - """Return the name of the transport used by the client. - - The two possible values returned by this function are ``'polling'`` - and ``'websocket'``. - - :param sid: The session of the client. - """ - return 'websocket' if self._get_socket(sid).upgraded else 'polling' - - def create_queue(self, *args, **kwargs): - """Create a queue object using the appropriate async model. - - This is a utility function that applications can use to create a queue - without having to worry about using the correct call for the selected - async mode. - """ - return self._async['queue'](*args, **kwargs) - - def get_queue_empty_exception(self): - """Return the queue empty exception for the appropriate async model. - - This is a utility function that applications can use to work with a - queue without having to worry about using the correct call for the - selected async mode. - """ - return self._async['queue_empty'] - - def create_event(self, *args, **kwargs): - """Create an event object using the appropriate async model. - - This is a utility function that applications can use to create an - event without having to worry about using the correct call for the - selected async mode. - """ - return self._async['event'](*args, **kwargs) - - def generate_id(self): - """Generate a unique session id.""" - id = base64.b64encode( - secrets.token_bytes(12) + self.sequence_number.to_bytes(3, 'big')) - self.sequence_number = (self.sequence_number + 1) & 0xffffff - return id.decode('utf-8').replace('/', '_').replace('+', '-') - - def _generate_sid_cookie(self, sid, attributes): - """Generate the sid cookie.""" - cookie = attributes.get('name', 'io') + '=' + sid - for attribute, value in attributes.items(): - if attribute == 'name': - continue - if callable(value): - value = value() - if value is True: - cookie += '; ' + attribute - else: - cookie += '; ' + attribute + '=' + value - return cookie - - def _upgrades(self, sid, transport): - """Return the list of possible upgrades for a client connection.""" - if not self.allow_upgrades or self._get_socket(sid).upgraded or \ - transport == 'websocket': - return [] - if self._async['websocket'] is None: # pragma: no cover - self._log_error_once( - 'The WebSocket transport is not available, you must install a ' - 'WebSocket server that is compatible with your async mode to ' - 'enable it. See the documentation for details.', - 'no-websocket') - return [] - return ['websocket'] - - def _get_socket(self, sid): - """Return the socket object for a given session.""" - try: - s = self.sockets[sid] - except KeyError: - raise KeyError('Session not found') - if s.closed: - del self.sockets[sid] - raise KeyError('Session is disconnected') - return s - - def _ok(self, packets=None, headers=None, jsonp_index=None): - """Generate a successful HTTP response.""" - if packets is not None: - if headers is None: - headers = [] - headers += [('Content-Type', 'text/plain; charset=UTF-8')] - return {'status': '200 OK', - 'headers': headers, - 'response': payload.Payload(packets=packets).encode( - jsonp_index=jsonp_index).encode('utf-8')} - else: - return {'status': '200 OK', - 'headers': [('Content-Type', 'text/plain')], - 'response': b'OK'} - - def _bad_request(self, message=None): - """Generate a bad request HTTP error response.""" - if message is None: - message = 'Bad Request' - message = packet.Packet.json.dumps(message) - return {'status': '400 BAD REQUEST', - 'headers': [('Content-Type', 'text/plain')], - 'response': message.encode('utf-8')} - - def _method_not_found(self): - """Generate a method not found HTTP error response.""" - return {'status': '405 METHOD NOT FOUND', - 'headers': [('Content-Type', 'text/plain')], - 'response': b'Method Not Found'} - - def _unauthorized(self, message=None): - """Generate a unauthorized HTTP error response.""" - if message is None: - message = 'Unauthorized' - message = packet.Packet.json.dumps(message) - return {'status': '401 UNAUTHORIZED', - 'headers': [('Content-Type', 'application/json')], - 'response': message.encode('utf-8')} - - def _cors_allowed_origins(self, environ): - if self.cors_allowed_origins is None: - allowed_origins = [] - if 'wsgi.url_scheme' in environ and 'HTTP_HOST' in environ: - allowed_origins.append('{scheme}://{host}'.format( - scheme=environ['wsgi.url_scheme'], - host=environ['HTTP_HOST'])) - if 'HTTP_X_FORWARDED_PROTO' in environ or \ - 'HTTP_X_FORWARDED_HOST' in environ: - scheme = environ.get( - 'HTTP_X_FORWARDED_PROTO', - environ['wsgi.url_scheme']).split(',')[0].strip() - allowed_origins.append('{scheme}://{host}'.format( - scheme=scheme, host=environ.get( - 'HTTP_X_FORWARDED_HOST', - environ['HTTP_HOST']).split( - ',')[0].strip())) - elif self.cors_allowed_origins == '*': - allowed_origins = None - elif isinstance(self.cors_allowed_origins, str): - allowed_origins = [self.cors_allowed_origins] - elif callable(self.cors_allowed_origins): - origin = environ.get('HTTP_ORIGIN') - try: - is_allowed = self.cors_allowed_origins(origin, environ) - except TypeError: - is_allowed = self.cors_allowed_origins(origin) - allowed_origins = [origin] if is_allowed else [] - else: - if '*' in self.cors_allowed_origins: - allowed_origins = None - else: - allowed_origins = self.cors_allowed_origins - return allowed_origins - - def _cors_headers(self, environ): - """Return the cross-origin-resource-sharing headers.""" - if self.cors_allowed_origins == []: - # special case, CORS handling is completely disabled - return [] - headers = [] - allowed_origins = self._cors_allowed_origins(environ) - if 'HTTP_ORIGIN' in environ and \ - (allowed_origins is None or environ['HTTP_ORIGIN'] in - allowed_origins): - headers = [('Access-Control-Allow-Origin', environ['HTTP_ORIGIN'])] - if environ['REQUEST_METHOD'] == 'OPTIONS': - headers += [('Access-Control-Allow-Methods', 'OPTIONS, GET, POST')] - if 'HTTP_ACCESS_CONTROL_REQUEST_HEADERS' in environ: - headers += [('Access-Control-Allow-Headers', - environ['HTTP_ACCESS_CONTROL_REQUEST_HEADERS'])] - if self.cors_credentials: - headers += [('Access-Control-Allow-Credentials', 'true')] - return headers - - def _gzip(self, response): - """Apply gzip compression to a response.""" - bytesio = io.BytesIO() - with gzip.GzipFile(fileobj=bytesio, mode='w') as gz: - gz.write(response) - return bytesio.getvalue() - - def _deflate(self, response): - """Apply deflate compression to a response.""" - return zlib.compress(response) - - def _log_error_once(self, message, message_key): - """Log message with logging.ERROR level the first time, then log - with given level.""" - if message_key not in self.log_message_keys: - self.logger.error(message + ' (further occurrences of this error ' - 'will be logged with level INFO)') - self.log_message_keys.add(message_key) - else: - self.logger.info(message) diff --git a/venv/lib/python3.9/site-packages/engineio/base_socket.py b/venv/lib/python3.9/site-packages/engineio/base_socket.py deleted file mode 100644 index 6b5d7dc..0000000 --- a/venv/lib/python3.9/site-packages/engineio/base_socket.py +++ /dev/null @@ -1,14 +0,0 @@ -class BaseSocket: - upgrade_protocols = ['websocket'] - - def __init__(self, server, sid): - self.server = server - self.sid = sid - self.queue = self.server.create_queue() - self.last_ping = None - self.connected = False - self.upgrading = False - self.upgraded = False - self.closing = False - self.closed = False - self.session = {} diff --git a/venv/lib/python3.9/site-packages/engineio/client.py b/venv/lib/python3.9/site-packages/engineio/client.py deleted file mode 100644 index e8865df..0000000 --- a/venv/lib/python3.9/site-packages/engineio/client.py +++ /dev/null @@ -1,636 +0,0 @@ -from base64 import b64encode -from http.cookies import SimpleCookie -import logging -import queue -import ssl -import threading -import time -import urllib -from engineio.json import JSONDecodeError - -try: - import requests -except ImportError: # pragma: no cover - requests = None -try: - import websocket -except ImportError: # pragma: no cover - websocket = None -from . import base_client -from . import exceptions -from . import packet -from . import payload - -default_logger = logging.getLogger('engineio.client') - - -class Client(base_client.BaseClient): - """An Engine.IO client. - - This class implements a fully compliant Engine.IO web client with support - for websocket and long-polling transports. - - :param logger: To enable logging set to ``True`` or pass a logger object to - use. To disable logging set to ``False``. The default is - ``False``. Note that fatal errors are logged even when - ``logger`` is ``False``. - :param json: An alternative JSON module to use for encoding and decoding - packets. Custom json modules must have ``dumps`` and ``loads`` - functions that are compatible with the standard library - versions. This is a process-wide setting, all instantiated - servers and clients must use the same JSON module. - :param request_timeout: A timeout in seconds for requests. The default is - 5 seconds. - :param http_session: an initialized ``requests.Session`` object to be used - when sending requests to the server. Use it if you - need to add special client options such as proxy - servers, SSL certificates, custom CA bundle, etc. - :param ssl_verify: ``True`` to verify SSL certificates, or ``False`` to - skip SSL certificate verification, allowing - connections to servers with self signed certificates. - The default is ``True``. - :param handle_sigint: Set to ``True`` to automatically handle disconnection - when the process is interrupted, or to ``False`` to - leave interrupt handling to the calling application. - Interrupt handling can only be enabled when the - client instance is created in the main thread. - :param websocket_extra_options: Dictionary containing additional keyword - arguments passed to - ``websocket.create_connection()``. - :param timestamp_requests: If ``True`` a timestamp is added to the query - string of Socket.IO requests as a cache-busting - measure. Set to ``False`` to disable. - """ - def connect(self, url, headers=None, transports=None, - engineio_path='engine.io'): - """Connect to an Engine.IO server. - - :param url: The URL of the Engine.IO server. It can include custom - query string parameters if required by the server. - :param headers: A dictionary with custom headers to send with the - connection request. - :param transports: The list of allowed transports. Valid transports - are ``'polling'`` and ``'websocket'``. If not - given, the polling transport is connected first, - then an upgrade to websocket is attempted. - :param engineio_path: The endpoint where the Engine.IO server is - installed. The default value is appropriate for - most cases. - - Example usage:: - - eio = engineio.Client() - eio.connect('http://localhost:5000') - """ - if self.state != 'disconnected': - raise ValueError('Client is not in a disconnected state') - valid_transports = ['polling', 'websocket'] - if transports is not None: - if isinstance(transports, str): - transports = [transports] - transports = [transport for transport in transports - if transport in valid_transports] - if not transports: - raise ValueError('No valid transports provided') - self.transports = transports or valid_transports - return getattr(self, '_connect_' + self.transports[0])( - url, headers or {}, engineio_path) - - def wait(self): - """Wait until the connection with the server ends. - - Client applications can use this function to block the main thread - during the life of the connection. - """ - if self.read_loop_task: - self.read_loop_task.join() - - def send(self, data): - """Send a message to the server. - - :param data: The data to send to the server. Data can be of type - ``str``, ``bytes``, ``list`` or ``dict``. If a ``list`` - or ``dict``, the data will be serialized as JSON. - """ - self._send_packet(packet.Packet(packet.MESSAGE, data=data)) - - def disconnect(self, abort=False, reason=None): - """Disconnect from the server. - - :param abort: If set to ``True``, do not wait for background tasks - associated with the connection to end. - """ - if self.state == 'connected': - self._send_packet(packet.Packet(packet.CLOSE)) - self.queue.put(None) - self.state = 'disconnecting' - self._trigger_event('disconnect', - reason or self.reason.CLIENT_DISCONNECT, - run_async=False) - if self.current_transport == 'websocket': - self.ws.close() - if not abort: - self.read_loop_task.join() - self.state = 'disconnected' - try: - base_client.connected_clients.remove(self) - except ValueError: # pragma: no cover - pass - self._reset() - - def start_background_task(self, target, *args, **kwargs): - """Start a background task. - - This is a utility function that applications can use to start a - background task. - - :param target: the target function to execute. - :param args: arguments to pass to the function. - :param kwargs: keyword arguments to pass to the function. - - This function returns an object that represents the background task, - on which the ``join()`` method can be invoked to wait for the task to - complete. - """ - th = threading.Thread(target=target, args=args, kwargs=kwargs, - daemon=True) - th.start() - return th - - def sleep(self, seconds=0): - """Sleep for the requested amount of time.""" - return time.sleep(seconds) - - def create_queue(self, *args, **kwargs): - """Create a queue object.""" - return queue.Queue(*args, **kwargs) - - def get_queue_empty_exception(self): - """Return the queue empty exception raised by queues created by the - ``create_queue()`` method. - """ - return queue.Empty - - def create_event(self, *args, **kwargs): - """Create an event object.""" - return threading.Event(*args, **kwargs) - - def _reset(self): - super()._reset() - while True: # pragma: no cover - try: - self.queue.get_nowait() - self.queue.task_done() - except self.queue_empty: - break - - def _connect_polling(self, url, headers, engineio_path): - """Establish a long-polling connection to the Engine.IO server.""" - if requests is None: # pragma: no cover - # not installed - self.logger.error('requests package is not installed -- cannot ' - 'send HTTP requests!') - return - self.base_url = self._get_engineio_url(url, engineio_path, 'polling') - self.logger.info('Attempting polling connection to ' + self.base_url) - r = self._send_request( - 'GET', self.base_url + self._get_url_timestamp(), headers=headers, - timeout=self.request_timeout) - if r is None or isinstance(r, str): - self._reset() - raise exceptions.ConnectionError( - r or 'Connection refused by the server') - if r.status_code < 200 or r.status_code >= 300: - self._reset() - try: - arg = r.json() - except JSONDecodeError: - arg = None - raise exceptions.ConnectionError( - 'Unexpected status code {} in server response'.format( - r.status_code), arg) - try: - p = payload.Payload(encoded_payload=r.content.decode('utf-8')) - except ValueError: - raise exceptions.ConnectionError( - 'Unexpected response from server') from None - open_packet = p.packets[0] - if open_packet.packet_type != packet.OPEN: - raise exceptions.ConnectionError( - 'OPEN packet not returned by server') - self.logger.info( - 'Polling connection accepted with ' + str(open_packet.data)) - self.sid = open_packet.data['sid'] - self.upgrades = open_packet.data['upgrades'] - self.ping_interval = int(open_packet.data['pingInterval']) / 1000.0 - self.ping_timeout = int(open_packet.data['pingTimeout']) / 1000.0 - self.current_transport = 'polling' - self.base_url += '&sid=' + self.sid - - self.state = 'connected' - base_client.connected_clients.append(self) - self._trigger_event('connect', run_async=False) - - for pkt in p.packets[1:]: - self._receive_packet(pkt) - - if 'websocket' in self.upgrades and 'websocket' in self.transports: - # attempt to upgrade to websocket - if self._connect_websocket(url, headers, engineio_path): - # upgrade to websocket succeeded, we're done here - return - - # start background tasks associated with this client - self.write_loop_task = self.start_background_task(self._write_loop) - self.read_loop_task = self.start_background_task( - self._read_loop_polling) - - def _connect_websocket(self, url, headers, engineio_path): - """Establish or upgrade to a WebSocket connection with the server.""" - if websocket is None: # pragma: no cover - # not installed - self.logger.error('websocket-client package not installed, only ' - 'polling transport is available') - return False - websocket_url = self._get_engineio_url(url, engineio_path, 'websocket') - if self.sid: - self.logger.info( - 'Attempting WebSocket upgrade to ' + websocket_url) - upgrade = True - websocket_url += '&sid=' + self.sid - else: - upgrade = False - self.base_url = websocket_url - self.logger.info( - 'Attempting WebSocket connection to ' + websocket_url) - - # get cookies and other settings from the long-polling connection - # so that they are preserved when connecting to the WebSocket route - cookies = None - extra_options = {} - if self.http: - # cookies - ck = SimpleCookie() - for cookie in self.http.cookies: - ck[cookie.name] = cookie.value - cookies = ck.output(header='', sep=';').strip() - for header, value in headers.items(): - if header.lower() == 'cookie': - if cookies: - cookies += '; ' - cookies += value - del headers[header] - break - - # auth - if 'Authorization' not in headers and self.http.auth is not None: - if not isinstance(self.http.auth, tuple): # pragma: no cover - raise ValueError('Only basic authentication is supported') - basic_auth = '{}:{}'.format( - self.http.auth[0], self.http.auth[1]).encode('utf-8') - basic_auth = b64encode(basic_auth).decode('utf-8') - headers['Authorization'] = 'Basic ' + basic_auth - - # cert - # this can be given as ('certfile', 'keyfile') or just 'certfile' - if isinstance(self.http.cert, tuple): - extra_options['sslopt'] = { - 'certfile': self.http.cert[0], - 'keyfile': self.http.cert[1]} - elif self.http.cert: - extra_options['sslopt'] = {'certfile': self.http.cert} - - # proxies - if self.http.proxies: - proxy_url = None - if websocket_url.startswith('ws://'): - proxy_url = self.http.proxies.get( - 'ws', self.http.proxies.get('http')) - else: # wss:// - proxy_url = self.http.proxies.get( - 'wss', self.http.proxies.get('https')) - if proxy_url: - parsed_url = urllib.parse.urlparse( - proxy_url if '://' in proxy_url - else 'scheme://' + proxy_url) - extra_options['http_proxy_host'] = parsed_url.hostname - extra_options['http_proxy_port'] = parsed_url.port - extra_options['http_proxy_auth'] = ( - (parsed_url.username, parsed_url.password) - if parsed_url.username or parsed_url.password - else None) - - # verify - if isinstance(self.http.verify, str): - if 'sslopt' in extra_options: - extra_options['sslopt']['ca_certs'] = self.http.verify - else: - extra_options['sslopt'] = {'ca_certs': self.http.verify} - elif not self.http.verify: - self.ssl_verify = False - - if not self.ssl_verify: - if 'sslopt' in extra_options: - extra_options['sslopt'].update({"cert_reqs": ssl.CERT_NONE}) - else: - extra_options['sslopt'] = {"cert_reqs": ssl.CERT_NONE} - - # combine internally generated options with the ones supplied by the - # caller. The caller's options take precedence. - headers.update(self.websocket_extra_options.pop('header', {})) - extra_options['header'] = headers - extra_options['cookie'] = cookies - extra_options['enable_multithread'] = True - extra_options['timeout'] = self.request_timeout - extra_options.update(self.websocket_extra_options) - try: - ws = websocket.create_connection( - websocket_url + self._get_url_timestamp(), **extra_options) - except (ConnectionError, OSError, websocket.WebSocketException): - if upgrade: - self.logger.warning( - 'WebSocket upgrade failed: connection error') - return False - else: - raise exceptions.ConnectionError('Connection error') - if upgrade: - p = packet.Packet(packet.PING, data='probe').encode() - try: - ws.send(p) - except Exception as e: # pragma: no cover - self.logger.warning( - 'WebSocket upgrade failed: unexpected send exception: %s', - str(e)) - return False - try: - p = ws.recv() - except Exception as e: # pragma: no cover - self.logger.warning( - 'WebSocket upgrade failed: unexpected recv exception: %s', - str(e)) - return False - pkt = packet.Packet(encoded_packet=p) - if pkt.packet_type != packet.PONG or pkt.data != 'probe': - self.logger.warning( - 'WebSocket upgrade failed: no PONG packet') - return False - p = packet.Packet(packet.UPGRADE).encode() - try: - ws.send(p) - except Exception as e: # pragma: no cover - self.logger.warning( - 'WebSocket upgrade failed: unexpected send exception: %s', - str(e)) - return False - self.current_transport = 'websocket' - self.logger.info('WebSocket upgrade was successful') - else: - try: - p = ws.recv() - except Exception as e: # pragma: no cover - raise exceptions.ConnectionError( - 'Unexpected recv exception: ' + str(e)) - open_packet = packet.Packet(encoded_packet=p) - if open_packet.packet_type != packet.OPEN: - raise exceptions.ConnectionError('no OPEN packet') - self.logger.info( - 'WebSocket connection accepted with ' + str(open_packet.data)) - self.sid = open_packet.data['sid'] - self.upgrades = open_packet.data['upgrades'] - self.ping_interval = int(open_packet.data['pingInterval']) / 1000.0 - self.ping_timeout = int(open_packet.data['pingTimeout']) / 1000.0 - self.current_transport = 'websocket' - - self.state = 'connected' - base_client.connected_clients.append(self) - self._trigger_event('connect', run_async=False) - self.ws = ws - self.ws.settimeout(self.ping_interval + self.ping_timeout) - - # start background tasks associated with this client - self.write_loop_task = self.start_background_task(self._write_loop) - self.read_loop_task = self.start_background_task( - self._read_loop_websocket) - return True - - def _receive_packet(self, pkt): - """Handle incoming packets from the server.""" - packet_name = packet.packet_names[pkt.packet_type] \ - if pkt.packet_type < len(packet.packet_names) else 'UNKNOWN' - self.logger.info( - 'Received packet %s data %s', packet_name, - pkt.data if not isinstance(pkt.data, bytes) else '') - if pkt.packet_type == packet.MESSAGE: - self._trigger_event('message', pkt.data, run_async=True) - elif pkt.packet_type == packet.PING: - self._send_packet(packet.Packet(packet.PONG, pkt.data)) - elif pkt.packet_type == packet.CLOSE: - self.disconnect(abort=True, reason=self.reason.SERVER_DISCONNECT) - elif pkt.packet_type == packet.NOOP: - pass - else: - self.logger.error('Received unexpected packet of type %s', - pkt.packet_type) - - def _send_packet(self, pkt): - """Queue a packet to be sent to the server.""" - if self.state != 'connected': - return - self.queue.put(pkt) - self.logger.info( - 'Sending packet %s data %s', - packet.packet_names[pkt.packet_type], - pkt.data if not isinstance(pkt.data, bytes) else '') - - def _send_request( - self, method, url, headers=None, body=None, - timeout=None): # pragma: no cover - if self.http is None: - self.http = requests.Session() - if not self.ssl_verify: - self.http.verify = False - try: - return self.http.request(method, url, headers=headers, data=body, - timeout=timeout) - except requests.exceptions.RequestException as exc: - self.logger.info('HTTP %s request to %s failed with error %s.', - method, url, exc) - return str(exc) - - def _trigger_event(self, event, *args, **kwargs): - """Invoke an event handler.""" - run_async = kwargs.pop('run_async', False) - if event in self.handlers: - if run_async: - return self.start_background_task(self.handlers[event], *args) - else: - try: - try: - return self.handlers[event](*args) - except TypeError: - if event == 'disconnect' and \ - len(args) == 1: # pragma: no branch - # legacy disconnect events do not have a reason - # argument - return self.handlers[event]() - else: # pragma: no cover - raise - except: - self.logger.exception(event + ' handler error') - - def _read_loop_polling(self): - """Read packets by polling the Engine.IO server.""" - while self.state == 'connected' and self.write_loop_task: - self.logger.info( - 'Sending polling GET request to ' + self.base_url) - r = self._send_request( - 'GET', self.base_url + self._get_url_timestamp(), - timeout=max(self.ping_interval, self.ping_timeout) + 5) - if r is None or isinstance(r, str): - self.logger.warning( - r or 'Connection refused by the server, aborting') - self.queue.put(None) - break - if r.status_code < 200 or r.status_code >= 300: - self.logger.warning('Unexpected status code %s in server ' - 'response, aborting', r.status_code) - self.queue.put(None) - break - try: - p = payload.Payload(encoded_payload=r.content.decode('utf-8')) - except ValueError: - self.logger.warning( - 'Unexpected packet from server, aborting') - self.queue.put(None) - break - for pkt in p.packets: - self._receive_packet(pkt) - - if self.write_loop_task: # pragma: no branch - self.logger.info('Waiting for write loop task to end') - self.write_loop_task.join() - if self.state == 'connected': - self._trigger_event('disconnect', self.reason.TRANSPORT_ERROR, - run_async=False) - try: - base_client.connected_clients.remove(self) - except ValueError: # pragma: no cover - pass - self._reset() - self.logger.info('Exiting read loop task') - - def _read_loop_websocket(self): - """Read packets from the Engine.IO WebSocket connection.""" - while self.state == 'connected': - p = None - try: - p = self.ws.recv() - if len(p) == 0 and not self.ws.connected: # pragma: no cover - # websocket client can return an empty string after close - raise websocket.WebSocketConnectionClosedException() - except websocket.WebSocketTimeoutException: - self.logger.warning( - 'Server has stopped communicating, aborting') - self.queue.put(None) - break - except websocket.WebSocketConnectionClosedException: - self.logger.warning( - 'WebSocket connection was closed, aborting') - self.queue.put(None) - break - except Exception as e: # pragma: no cover - if type(e) is OSError and e.errno == 9: - self.logger.info( - 'WebSocket connection is closing, aborting') - else: - self.logger.info( - 'Unexpected error receiving packet: "%s", aborting', - str(e)) - self.queue.put(None) - break - try: - pkt = packet.Packet(encoded_packet=p) - except Exception as e: # pragma: no cover - self.logger.info( - 'Unexpected error decoding packet: "%s", aborting', str(e)) - self.queue.put(None) - break - self._receive_packet(pkt) - - if self.write_loop_task: # pragma: no branch - self.logger.info('Waiting for write loop task to end') - self.write_loop_task.join() - if self.state == 'connected': - self._trigger_event('disconnect', self.reason.TRANSPORT_ERROR, - run_async=False) - try: - base_client.connected_clients.remove(self) - except ValueError: # pragma: no cover - pass - self._reset() - self.logger.info('Exiting read loop task') - - def _write_loop(self): - """This background task sends packages to the server as they are - pushed to the send queue. - """ - while self.state == 'connected': - # to simplify the timeout handling, use the maximum of the - # ping interval and ping timeout as timeout, with an extra 5 - # seconds grace period - timeout = max(self.ping_interval, self.ping_timeout) + 5 - packets = None - try: - packets = [self.queue.get(timeout=timeout)] - except self.queue_empty: - self.logger.error('packet queue is empty, aborting') - break - if packets == [None]: - self.queue.task_done() - packets = [] - else: - while True: - try: - packets.append(self.queue.get(block=False)) - except self.queue_empty: - break - if packets[-1] is None: - packets = packets[:-1] - self.queue.task_done() - break - if not packets: - # empty packet list returned -> connection closed - break - if self.current_transport == 'polling': - p = payload.Payload(packets=packets) - r = self._send_request( - 'POST', self.base_url, body=p.encode(), - headers={'Content-Type': 'text/plain'}, - timeout=self.request_timeout) - for pkt in packets: - self.queue.task_done() - if r is None or isinstance(r, str): - self.logger.warning( - r or 'Connection refused by the server, aborting') - break - if r.status_code < 200 or r.status_code >= 300: - self.logger.warning('Unexpected status code %s in server ' - 'response, aborting', r.status_code) - self.write_loop_task = None - break - else: - # websocket - try: - for pkt in packets: - encoded_packet = pkt.encode() - if pkt.binary: - self.ws.send_binary(encoded_packet) - else: - self.ws.send(encoded_packet) - self.queue.task_done() - except (websocket.WebSocketConnectionClosedException, - BrokenPipeError, OSError): - self.logger.warning( - 'WebSocket connection was closed, aborting') - break - self.logger.info('Exiting write loop task') diff --git a/venv/lib/python3.9/site-packages/engineio/exceptions.py b/venv/lib/python3.9/site-packages/engineio/exceptions.py deleted file mode 100644 index fb0b3e0..0000000 --- a/venv/lib/python3.9/site-packages/engineio/exceptions.py +++ /dev/null @@ -1,22 +0,0 @@ -class EngineIOError(Exception): - pass - - -class ContentTooLongError(EngineIOError): - pass - - -class UnknownPacketError(EngineIOError): - pass - - -class QueueEmpty(EngineIOError): - pass - - -class SocketIsClosedError(EngineIOError): - pass - - -class ConnectionError(EngineIOError): - pass diff --git a/venv/lib/python3.9/site-packages/engineio/json.py b/venv/lib/python3.9/site-packages/engineio/json.py deleted file mode 100644 index b612556..0000000 --- a/venv/lib/python3.9/site-packages/engineio/json.py +++ /dev/null @@ -1,16 +0,0 @@ -"""JSON-compatible module with sane defaults.""" - -from json import * # noqa: F401, F403 -from json import loads as original_loads - - -def _safe_int(s): - if len(s) > 100: - raise ValueError('Integer is too large') - return int(s) - - -def loads(*args, **kwargs): - if 'parse_int' not in kwargs: # pragma: no cover - kwargs['parse_int'] = _safe_int - return original_loads(*args, **kwargs) diff --git a/venv/lib/python3.9/site-packages/engineio/middleware.py b/venv/lib/python3.9/site-packages/engineio/middleware.py deleted file mode 100644 index 0e34fb0..0000000 --- a/venv/lib/python3.9/site-packages/engineio/middleware.py +++ /dev/null @@ -1,86 +0,0 @@ -import os -from engineio.static_files import get_static_file - - -class WSGIApp: - """WSGI application middleware for Engine.IO. - - This middleware dispatches traffic to an Engine.IO application. It can - also serve a list of static files to the client, or forward unrelated - HTTP traffic to another WSGI application. - - :param engineio_app: The Engine.IO server. Must be an instance of the - ``engineio.Server`` class. - :param wsgi_app: The WSGI app that receives all other traffic. - :param static_files: A dictionary with static file mapping rules. See the - documentation for details on this argument. - :param engineio_path: The endpoint where the Engine.IO application should - be installed. The default value is appropriate for - most cases. - - Example usage:: - - import engineio - import eventlet - - eio = engineio.Server() - app = engineio.WSGIApp(eio, static_files={ - '/': {'content_type': 'text/html', 'filename': 'index.html'}, - '/index.html': {'content_type': 'text/html', - 'filename': 'index.html'}, - }) - eventlet.wsgi.server(eventlet.listen(('', 8000)), app) - """ - def __init__(self, engineio_app, wsgi_app=None, static_files=None, - engineio_path='engine.io'): - self.engineio_app = engineio_app - self.wsgi_app = wsgi_app - self.engineio_path = engineio_path - if not self.engineio_path.startswith('/'): - self.engineio_path = '/' + self.engineio_path - if not self.engineio_path.endswith('/'): - self.engineio_path += '/' - self.static_files = static_files or {} - - def __call__(self, environ, start_response): - if 'gunicorn.socket' in environ: - # gunicorn saves the socket under environ['gunicorn.socket'], while - # eventlet saves it under environ['eventlet.input']. Eventlet also - # stores the socket inside a wrapper class, while gunicon writes it - # directly into the environment. To give eventlet's WebSocket - # module access to this socket when running under gunicorn, here we - # copy the socket to the eventlet format. - class Input: - def __init__(self, socket): - self.socket = socket - - def get_socket(self): - return self.socket - - environ['eventlet.input'] = Input(environ['gunicorn.socket']) - path = environ['PATH_INFO'] - if path is not None and path.startswith(self.engineio_path): - return self.engineio_app.handle_request(environ, start_response) - else: - static_file = get_static_file(path, self.static_files) \ - if self.static_files else None - if static_file and os.path.exists(static_file['filename']): - start_response( - '200 OK', - [('Content-Type', static_file['content_type'])]) - with open(static_file['filename'], 'rb') as f: - return [f.read()] - elif self.wsgi_app is not None: - return self.wsgi_app(environ, start_response) - return self.not_found(start_response) - - def not_found(self, start_response): - start_response("404 Not Found", [('Content-Type', 'text/plain')]) - return [b'Not Found'] - - -class Middleware(WSGIApp): - """This class has been renamed to ``WSGIApp`` and is now deprecated.""" - def __init__(self, engineio_app, wsgi_app=None, - engineio_path='engine.io'): - super().__init__(engineio_app, wsgi_app, engineio_path=engineio_path) diff --git a/venv/lib/python3.9/site-packages/engineio/packet.py b/venv/lib/python3.9/site-packages/engineio/packet.py deleted file mode 100644 index 40bb6df..0000000 --- a/venv/lib/python3.9/site-packages/engineio/packet.py +++ /dev/null @@ -1,82 +0,0 @@ -import base64 -from engineio import json as _json - -(OPEN, CLOSE, PING, PONG, MESSAGE, UPGRADE, NOOP) = (0, 1, 2, 3, 4, 5, 6) -packet_names = ['OPEN', 'CLOSE', 'PING', 'PONG', 'MESSAGE', 'UPGRADE', 'NOOP'] - -binary_types = (bytes, bytearray) - - -class Packet: - """Engine.IO packet.""" - - json = _json - - def __init__(self, packet_type=NOOP, data=None, encoded_packet=None): - self.packet_type = packet_type - self.data = data - self.encode_cache = None - if isinstance(data, str): - self.binary = False - elif isinstance(data, binary_types): - self.binary = True - else: - self.binary = False - if self.binary and self.packet_type != MESSAGE: - raise ValueError('Binary packets can only be of type MESSAGE') - if encoded_packet is not None: - self.decode(encoded_packet) - - def encode(self, b64=False): - """Encode the packet for transmission. - - Note: as a performance optimization, subsequent calls to this method - will return a cached encoded packet, even if the data has changed. - """ - if self.encode_cache: - return self.encode_cache - if self.binary: - if b64: - encoded_packet = 'b' + base64.b64encode(self.data).decode( - 'utf-8') - else: - encoded_packet = self.data - else: - encoded_packet = str(self.packet_type) - if isinstance(self.data, str): - encoded_packet += self.data - elif isinstance(self.data, dict) or isinstance(self.data, list): - encoded_packet += self.json.dumps(self.data, - separators=(',', ':')) - elif self.data is not None: - encoded_packet += str(self.data) - self.encode_cache = encoded_packet - return encoded_packet - - def decode(self, encoded_packet): - """Decode a transmitted package.""" - self.binary = isinstance(encoded_packet, binary_types) - if not self.binary and len(encoded_packet) == 0: - raise ValueError('Invalid empty packet received') - b64 = not self.binary and encoded_packet[0] == 'b' - if b64: - self.binary = True - self.packet_type = MESSAGE - self.data = base64.b64decode(encoded_packet[1:]) - else: - if self.binary and not isinstance(encoded_packet, bytes): - encoded_packet = bytes(encoded_packet) - if self.binary: - self.packet_type = MESSAGE - self.data = encoded_packet - else: - self.packet_type = int(encoded_packet[0]) - try: - if encoded_packet[1].isnumeric(): - # do not allow integer payloads, see - # github.com/miguelgrinberg/python-engineio/issues/75 - # for background on this decision - raise ValueError - self.data = self.json.loads(encoded_packet[1:]) - except (ValueError, IndexError): - self.data = encoded_packet[1:] diff --git a/venv/lib/python3.9/site-packages/engineio/payload.py b/venv/lib/python3.9/site-packages/engineio/payload.py deleted file mode 100644 index 775241b..0000000 --- a/venv/lib/python3.9/site-packages/engineio/payload.py +++ /dev/null @@ -1,46 +0,0 @@ -import urllib - -from . import packet - - -class Payload: - """Engine.IO payload.""" - max_decode_packets = 16 - - def __init__(self, packets=None, encoded_payload=None): - self.packets = packets or [] - if encoded_payload is not None: - self.decode(encoded_payload) - - def encode(self, jsonp_index=None): - """Encode the payload for transmission.""" - encoded_payload = '' - for pkt in self.packets: - if encoded_payload: - encoded_payload += '\x1e' - encoded_payload += pkt.encode(b64=True) - if jsonp_index is not None: - encoded_payload = '___eio[' + \ - str(jsonp_index) + \ - ']("' + \ - encoded_payload.replace('"', '\\"') + \ - '");' - return encoded_payload - - def decode(self, encoded_payload): - """Decode a transmitted payload.""" - self.packets = [] - - if len(encoded_payload) == 0: - return - - # JSONP POST payload starts with 'd=' - if encoded_payload.startswith('d='): - encoded_payload = urllib.parse.parse_qs( - encoded_payload)['d'][0] - - encoded_packets = encoded_payload.split('\x1e') - if len(encoded_packets) > self.max_decode_packets: - raise ValueError('Too many packets in payload') - self.packets = [packet.Packet(encoded_packet=encoded_packet) - for encoded_packet in encoded_packets] diff --git a/venv/lib/python3.9/site-packages/engineio/server.py b/venv/lib/python3.9/site-packages/engineio/server.py deleted file mode 100644 index 917c53f..0000000 --- a/venv/lib/python3.9/site-packages/engineio/server.py +++ /dev/null @@ -1,504 +0,0 @@ -import logging -import urllib - -from . import base_server -from . import exceptions -from . import packet -from . import socket - -default_logger = logging.getLogger('engineio.server') - - -class Server(base_server.BaseServer): - """An Engine.IO server. - - This class implements a fully compliant Engine.IO web server with support - for websocket and long-polling transports. - - :param async_mode: The asynchronous model to use. See the Deployment - section in the documentation for a description of the - available options. Valid async modes are "threading", - "eventlet", "gevent" and "gevent_uwsgi". If this - argument is not given, "eventlet" is tried first, then - "gevent_uwsgi", then "gevent", and finally "threading". - The first async mode that has all its dependencies - installed is the one that is chosen. - :param ping_interval: The interval in seconds at which the server pings - the client. The default is 25 seconds. For advanced - control, a two element tuple can be given, where - the first number is the ping interval and the second - is a grace period added by the server. - :param ping_timeout: The time in seconds that the client waits for the - server to respond before disconnecting. The default - is 20 seconds. - :param max_http_buffer_size: The maximum size that is accepted for incoming - messages. The default is 1,000,000 bytes. In - spite of its name, the value set in this - argument is enforced for HTTP long-polling and - WebSocket connections. - :param allow_upgrades: Whether to allow transport upgrades or not. The - default is ``True``. - :param http_compression: Whether to compress packages when using the - polling transport. The default is ``True``. - :param compression_threshold: Only compress messages when their byte size - is greater than this value. The default is - 1024 bytes. - :param cookie: If set to a string, it is the name of the HTTP cookie the - server sends back tot he client containing the client - session id. If set to a dictionary, the ``'name'`` key - contains the cookie name and other keys define cookie - attributes, where the value of each attribute can be a - string, a callable with no arguments, or a boolean. If set - to ``None`` (the default), a cookie is not sent to the - client. - :param cors_allowed_origins: Origin or list of origins that are allowed to - connect to this server. Only the same origin - is allowed by default. Set this argument to - ``'*'`` or ``['*']`` to allow all origins, or - to ``[]`` to disable CORS handling. - :param cors_credentials: Whether credentials (cookies, authentication) are - allowed in requests to this server. The default - is ``True``. - :param logger: To enable logging set to ``True`` or pass a logger object to - use. To disable logging set to ``False``. The default is - ``False``. Note that fatal errors are logged even when - ``logger`` is ``False``. - :param json: An alternative JSON module to use for encoding and decoding - packets. Custom JSON modules must have ``dumps`` and ``loads`` - functions that are compatible with the standard library - versions. This is a process-wide setting, all instantiated - servers and clients must use the same JSON module. - :param async_handlers: If set to ``True``, run message event handlers in - non-blocking threads. To run handlers synchronously, - set to ``False``. The default is ``True``. - :param monitor_clients: If set to ``True``, a background task will ensure - inactive clients are closed. Set to ``False`` to - disable the monitoring task (not recommended). The - default is ``True``. - :param transports: The list of allowed transports. Valid transports - are ``'polling'`` and ``'websocket'``. Defaults to - ``['polling', 'websocket']``. - :param kwargs: Reserved for future extensions, any additional parameters - given as keyword arguments will be silently ignored. - """ - def send(self, sid, data): - """Send a message to a client. - - :param sid: The session id of the recipient client. - :param data: The data to send to the client. Data can be of type - ``str``, ``bytes``, ``list`` or ``dict``. If a ``list`` - or ``dict``, the data will be serialized as JSON. - """ - self.send_packet(sid, packet.Packet(packet.MESSAGE, data=data)) - - def send_packet(self, sid, pkt): - """Send a raw packet to a client. - - :param sid: The session id of the recipient client. - :param pkt: The packet to send to the client. - """ - try: - socket = self._get_socket(sid) - except KeyError: - # the socket is not available - self.logger.warning('Cannot send to sid %s', sid) - return - socket.send(pkt) - - def get_session(self, sid): - """Return the user session for a client. - - :param sid: The session id of the client. - - The return value is a dictionary. Modifications made to this - dictionary are not guaranteed to be preserved unless - ``save_session()`` is called, or when the ``session`` context manager - is used. - """ - socket = self._get_socket(sid) - return socket.session - - def save_session(self, sid, session): - """Store the user session for a client. - - :param sid: The session id of the client. - :param session: The session dictionary. - """ - socket = self._get_socket(sid) - socket.session = session - - def session(self, sid): - """Return the user session for a client with context manager syntax. - - :param sid: The session id of the client. - - This is a context manager that returns the user session dictionary for - the client. Any changes that are made to this dictionary inside the - context manager block are saved back to the session. Example usage:: - - @eio.on('connect') - def on_connect(sid, environ): - username = authenticate_user(environ) - if not username: - return False - with eio.session(sid) as session: - session['username'] = username - - @eio.on('message') - def on_message(sid, msg): - with eio.session(sid) as session: - print('received message from ', session['username']) - """ - class _session_context_manager: - def __init__(self, server, sid): - self.server = server - self.sid = sid - self.session = None - - def __enter__(self): - self.session = self.server.get_session(sid) - return self.session - - def __exit__(self, *args): - self.server.save_session(sid, self.session) - - return _session_context_manager(self, sid) - - def disconnect(self, sid=None): - """Disconnect a client. - - :param sid: The session id of the client to close. If this parameter - is not given, then all clients are closed. - """ - if sid is not None: - try: - socket = self._get_socket(sid) - except KeyError: # pragma: no cover - # the socket was already closed or gone - pass - else: - socket.close(reason=self.reason.SERVER_DISCONNECT) - if sid in self.sockets: # pragma: no cover - del self.sockets[sid] - else: - for client in self.sockets.copy().values(): - client.close(reason=self.reason.SERVER_DISCONNECT) - self.sockets = {} - - def handle_request(self, environ, start_response): - """Handle an HTTP request from the client. - - This is the entry point of the Engine.IO application, using the same - interface as a WSGI application. For the typical usage, this function - is invoked by the :class:`Middleware` instance, but it can be invoked - directly when the middleware is not used. - - :param environ: The WSGI environment. - :param start_response: The WSGI ``start_response`` function. - - This function returns the HTTP response body to deliver to the client - as a byte sequence. - """ - if self.cors_allowed_origins != []: - # Validate the origin header if present - # This is important for WebSocket more than for HTTP, since - # browsers only apply CORS controls to HTTP. - origin = environ.get('HTTP_ORIGIN') - if origin: - allowed_origins = self._cors_allowed_origins(environ) - if allowed_origins is not None and origin not in \ - allowed_origins: - self._log_error_once( - origin + ' is not an accepted origin.', 'bad-origin') - r = self._bad_request('Not an accepted origin.') - start_response(r['status'], r['headers']) - return [r['response']] - - method = environ['REQUEST_METHOD'] - query = urllib.parse.parse_qs(environ.get('QUERY_STRING', '')) - jsonp = False - jsonp_index = None - - # make sure the client uses an allowed transport - transport = query.get('transport', ['polling'])[0] - if transport not in self.transports: - self._log_error_once('Invalid transport', 'bad-transport') - r = self._bad_request('Invalid transport') - start_response(r['status'], r['headers']) - return [r['response']] - - # make sure the client speaks a compatible Engine.IO version - sid = query['sid'][0] if 'sid' in query else None - if sid is None and query.get('EIO') != ['4']: - self._log_error_once( - 'The client is using an unsupported version of the Socket.IO ' - 'or Engine.IO protocols', 'bad-version') - r = self._bad_request( - 'The client is using an unsupported version of the Socket.IO ' - 'or Engine.IO protocols') - start_response(r['status'], r['headers']) - return [r['response']] - - if 'j' in query: - jsonp = True - try: - jsonp_index = int(query['j'][0]) - except (ValueError, KeyError, IndexError): - # Invalid JSONP index number - pass - - if jsonp and jsonp_index is None: - self._log_error_once('Invalid JSONP index number', - 'bad-jsonp-index') - r = self._bad_request('Invalid JSONP index number') - elif method == 'GET': - upgrade_header = environ.get('HTTP_UPGRADE').lower() \ - if 'HTTP_UPGRADE' in environ else None - if sid is None: - # transport must be one of 'polling' or 'websocket'. - # if 'websocket', the HTTP_UPGRADE header must match. - if transport == 'polling' \ - or transport == upgrade_header == 'websocket': - r = self._handle_connect(environ, start_response, - transport, jsonp_index) - else: - self._log_error_once('Invalid websocket upgrade', - 'bad-upgrade') - r = self._bad_request('Invalid websocket upgrade') - else: - if sid not in self.sockets: - self._log_error_once(f'Invalid session {sid}', 'bad-sid') - r = self._bad_request(f'Invalid session {sid}') - else: - try: - socket = self._get_socket(sid) - except KeyError as e: # pragma: no cover - self._log_error_once(f'{e} {sid}', 'bad-sid') - r = self._bad_request(f'{e} {sid}') - else: - if self.transport(sid) != transport and \ - transport != upgrade_header: - self._log_error_once( - f'Invalid transport for session {sid}', - 'bad-transport') - r = self._bad_request('Invalid transport') - else: - try: - packets = socket.handle_get_request( - environ, start_response) - if isinstance(packets, list): - r = self._ok(packets, - jsonp_index=jsonp_index) - else: - r = packets - except exceptions.EngineIOError: - if sid in self.sockets: # pragma: no cover - self.disconnect(sid) - r = self._bad_request() - if sid in self.sockets and \ - self.sockets[sid].closed: - del self.sockets[sid] - elif method == 'POST': - if sid is None or sid not in self.sockets: - self._log_error_once(f'Invalid session {sid}', 'bad-sid') - r = self._bad_request(f'Invalid session {sid}') - else: - socket = self._get_socket(sid) - try: - socket.handle_post_request(environ) - r = self._ok(jsonp_index=jsonp_index) - except exceptions.EngineIOError: - if sid in self.sockets: # pragma: no cover - self.disconnect(sid) - r = self._bad_request() - except: # pragma: no cover - # for any other unexpected errors, we log the error - # and keep going - self.logger.exception('post request handler error') - r = self._ok(jsonp_index=jsonp_index) - elif method == 'OPTIONS': - r = self._ok() - else: - self.logger.warning('Method %s not supported', method) - r = self._method_not_found() - - if not isinstance(r, dict): - return r - if self.http_compression and \ - len(r['response']) >= self.compression_threshold: - encodings = [e.split(';')[0].strip() for e in - environ.get('HTTP_ACCEPT_ENCODING', '').split(',')] - for encoding in encodings: - if encoding in self.compression_methods: - r['response'] = \ - getattr(self, '_' + encoding)(r['response']) - r['headers'] += [('Content-Encoding', encoding)] - break - cors_headers = self._cors_headers(environ) - start_response(r['status'], r['headers'] + cors_headers) - return [r['response']] - - def shutdown(self): - """Stop Socket.IO background tasks. - - This method stops background activity initiated by the Socket.IO - server. It must be called before shutting down the web server. - """ - self.logger.info('Socket.IO is shutting down') - if self.service_task_event: # pragma: no cover - self.service_task_event.set() - self.service_task_handle.join() - self.service_task_handle = None - - def start_background_task(self, target, *args, **kwargs): - """Start a background task using the appropriate async model. - - This is a utility function that applications can use to start a - background task using the method that is compatible with the - selected async mode. - - :param target: the target function to execute. - :param args: arguments to pass to the function. - :param kwargs: keyword arguments to pass to the function. - - This function returns an object that represents the background task, - on which the ``join()`` methond can be invoked to wait for the task to - complete. - """ - th = self._async['thread'](target=target, args=args, kwargs=kwargs) - th.start() - return th # pragma: no cover - - def sleep(self, seconds=0): - """Sleep for the requested amount of time using the appropriate async - model. - - This is a utility function that applications can use to put a task to - sleep without having to worry about using the correct call for the - selected async mode. - """ - return self._async['sleep'](seconds) - - def _handle_connect(self, environ, start_response, transport, - jsonp_index=None): - """Handle a client connection request.""" - if self.start_service_task: - # start the service task to monitor connected clients - self.start_service_task = False - self.service_task_handle = self.start_background_task( - self._service_task) - - sid = self.generate_id() - s = socket.Socket(self, sid) - self.sockets[sid] = s - - pkt = packet.Packet(packet.OPEN, { - 'sid': sid, - 'upgrades': self._upgrades(sid, transport), - 'pingTimeout': int(self.ping_timeout * 1000), - 'pingInterval': int( - self.ping_interval + self.ping_interval_grace_period) * 1000, - 'maxPayload': self.max_http_buffer_size, - }) - s.send(pkt) - s.schedule_ping() - - # NOTE: some sections below are marked as "no cover" to workaround - # what seems to be a bug in the coverage package. All the lines below - # are covered by tests, but some are not reported as such for some - # reason - ret = self._trigger_event('connect', sid, environ, run_async=False) - if ret is not None and ret is not True: # pragma: no cover - del self.sockets[sid] - self.logger.warning('Application rejected connection') - return self._unauthorized(ret or None) - - if transport == 'websocket': # pragma: no cover - ret = s.handle_get_request(environ, start_response) - if s.closed and sid in self.sockets: - # websocket connection ended, so we are done - del self.sockets[sid] - return ret - else: # pragma: no cover - s.connected = True - headers = None - if self.cookie: - if isinstance(self.cookie, dict): - headers = [( - 'Set-Cookie', - self._generate_sid_cookie(sid, self.cookie) - )] - else: - headers = [( - 'Set-Cookie', - self._generate_sid_cookie(sid, { - 'name': self.cookie, 'path': '/', 'SameSite': 'Lax' - }) - )] - try: - return self._ok(s.poll(), headers=headers, - jsonp_index=jsonp_index) - except exceptions.QueueEmpty: - return self._bad_request() - - def _trigger_event(self, event, *args, **kwargs): - """Invoke an event handler.""" - run_async = kwargs.pop('run_async', False) - if event in self.handlers: - def run_handler(): - try: - try: - return self.handlers[event](*args) - except TypeError: - if event == 'disconnect' and \ - len(args) == 2: # pragma: no branch - # legacy disconnect events do not have a reason - # argument - return self.handlers[event](args[0]) - else: # pragma: no cover - raise - except: - self.logger.exception(event + ' handler error') - if event == 'connect': - # if connect handler raised error we reject the - # connection - return False - - if run_async: - return self.start_background_task(run_handler) - else: - return run_handler() - - def _service_task(self): # pragma: no cover - """Monitor connected clients and clean up those that time out.""" - self.service_task_event = self.create_event() - while not self.service_task_event.is_set(): - if len(self.sockets) == 0: - # nothing to do - if self.service_task_event.wait(timeout=self.ping_timeout): - break - continue - - # go through the entire client list in a ping interval cycle - sleep_interval = float(self.ping_timeout) / len(self.sockets) - - try: - # iterate over the current clients - for s in self.sockets.copy().values(): - if s.closed: - try: - del self.sockets[s.sid] - except KeyError: - # the socket could have also been removed by - # the _get_socket() method from another thread - pass - elif not s.closing: - s.check_ping_timeout() - if self.service_task_event.wait(timeout=sleep_interval): - raise KeyboardInterrupt() - except (SystemExit, KeyboardInterrupt): - self.logger.info('service task canceled') - break - except: - # an unexpected exception has occurred, log it and continue - self.logger.exception('service task exception') diff --git a/venv/lib/python3.9/site-packages/engineio/socket.py b/venv/lib/python3.9/site-packages/engineio/socket.py deleted file mode 100644 index 26bb94b..0000000 --- a/venv/lib/python3.9/site-packages/engineio/socket.py +++ /dev/null @@ -1,256 +0,0 @@ -import sys -import time - -from . import base_socket -from . import exceptions -from . import packet -from . import payload - - -class Socket(base_socket.BaseSocket): - """An Engine.IO socket.""" - def poll(self): - """Wait for packets to send to the client.""" - queue_empty = self.server.get_queue_empty_exception() - try: - packets = [self.queue.get( - timeout=self.server.ping_interval + self.server.ping_timeout)] - self.queue.task_done() - except queue_empty: - raise exceptions.QueueEmpty() - if packets == [None]: - return [] - while True: - try: - pkt = self.queue.get(block=False) - self.queue.task_done() - if pkt is None: - self.queue.put(None) - break - packets.append(pkt) - except queue_empty: - break - return packets - - def receive(self, pkt): - """Receive packet from the client.""" - packet_name = packet.packet_names[pkt.packet_type] \ - if pkt.packet_type < len(packet.packet_names) else 'UNKNOWN' - self.server.logger.info('%s: Received packet %s data %s', - self.sid, packet_name, - pkt.data if not isinstance(pkt.data, bytes) - else '') - if pkt.packet_type == packet.PONG: - self.schedule_ping() - elif pkt.packet_type == packet.MESSAGE: - self.server._trigger_event('message', self.sid, pkt.data, - run_async=self.server.async_handlers) - elif pkt.packet_type == packet.UPGRADE: - self.send(packet.Packet(packet.NOOP)) - elif pkt.packet_type == packet.CLOSE: - self.close(wait=False, abort=True, - reason=self.server.reason.CLIENT_DISCONNECT) - else: - raise exceptions.UnknownPacketError() - - def check_ping_timeout(self): - """Make sure the client is still responding to pings.""" - if self.closed: - raise exceptions.SocketIsClosedError() - if self.last_ping and \ - time.time() - self.last_ping > self.server.ping_timeout: - self.server.logger.info('%s: Client is gone, closing socket', - self.sid) - # Passing abort=False here will cause close() to write a - # CLOSE packet. This has the effect of updating half-open sockets - # to their correct state of disconnected - self.close(wait=False, abort=False, - reason=self.server.reason.PING_TIMEOUT) - return False - return True - - def send(self, pkt): - """Send a packet to the client.""" - if not self.check_ping_timeout(): - return - else: - self.queue.put(pkt) - self.server.logger.info('%s: Sending packet %s data %s', - self.sid, packet.packet_names[pkt.packet_type], - pkt.data if not isinstance(pkt.data, bytes) - else '') - - def handle_get_request(self, environ, start_response): - """Handle a long-polling GET request from the client.""" - connections = [ - s.strip() - for s in environ.get('HTTP_CONNECTION', '').lower().split(',')] - transport = environ.get('HTTP_UPGRADE', '').lower() - if 'upgrade' in connections and transport in self.upgrade_protocols: - self.server.logger.info('%s: Received request to upgrade to %s', - self.sid, transport) - return getattr(self, '_upgrade_' + transport)(environ, - start_response) - if self.upgrading or self.upgraded: - # we are upgrading to WebSocket, do not return any more packets - # through the polling endpoint - return [packet.Packet(packet.NOOP)] - try: - packets = self.poll() - except exceptions.QueueEmpty: - exc = sys.exc_info() - self.close(wait=False, reason=self.server.reason.TRANSPORT_ERROR) - raise exc[1].with_traceback(exc[2]) - return packets - - def handle_post_request(self, environ): - """Handle a long-polling POST request from the client.""" - length = int(environ.get('CONTENT_LENGTH', '0')) - if length > self.server.max_http_buffer_size: - raise exceptions.ContentTooLongError() - else: - body = environ['wsgi.input'].read(length).decode('utf-8') - p = payload.Payload(encoded_payload=body) - for pkt in p.packets: - self.receive(pkt) - - def close(self, wait=True, abort=False, reason=None): - """Close the socket connection.""" - if not self.closed and not self.closing: - self.closing = True - self.server._trigger_event( - 'disconnect', self.sid, - reason or self.server.reason.SERVER_DISCONNECT, - run_async=False) - if not abort: - self.send(packet.Packet(packet.CLOSE)) - self.closed = True - self.queue.put(None) - if wait: - self.queue.join() - - def schedule_ping(self): - self.server.start_background_task(self._send_ping) - - def _send_ping(self): - self.last_ping = None - self.server.sleep(self.server.ping_interval) - if not self.closing and not self.closed: - self.last_ping = time.time() - self.send(packet.Packet(packet.PING)) - - def _upgrade_websocket(self, environ, start_response): - """Upgrade the connection from polling to websocket.""" - if self.upgraded: - raise OSError('Socket has been upgraded already') - if self.server._async['websocket'] is None: - # the selected async mode does not support websocket - return self.server._bad_request() - ws = self.server._async['websocket']( - self._websocket_handler, self.server) - return ws(environ, start_response) - - def _websocket_handler(self, ws): - """Engine.IO handler for websocket transport.""" - def websocket_wait(): - data = ws.wait() - if data and len(data) > self.server.max_http_buffer_size: - raise ValueError('packet is too large') - return data - - # try to set a socket timeout matching the configured ping interval - # and timeout - for attr in ['_sock', 'socket']: # pragma: no cover - if hasattr(ws, attr) and hasattr(getattr(ws, attr), 'settimeout'): - getattr(ws, attr).settimeout( - self.server.ping_interval + self.server.ping_timeout) - - if self.connected: - # the socket was already connected, so this is an upgrade - self.upgrading = True # hold packet sends during the upgrade - - pkt = websocket_wait() - decoded_pkt = packet.Packet(encoded_packet=pkt) - if decoded_pkt.packet_type != packet.PING or \ - decoded_pkt.data != 'probe': - self.server.logger.info( - '%s: Failed websocket upgrade, no PING packet', self.sid) - self.upgrading = False - return [] - ws.send(packet.Packet(packet.PONG, data='probe').encode()) - self.queue.put(packet.Packet(packet.NOOP)) # end poll - - pkt = websocket_wait() - decoded_pkt = packet.Packet(encoded_packet=pkt) - if decoded_pkt.packet_type != packet.UPGRADE: - self.upgraded = False - self.server.logger.info( - ('%s: Failed websocket upgrade, expected UPGRADE packet, ' - 'received %s instead.'), - self.sid, pkt) - self.upgrading = False - return [] - self.upgraded = True - self.upgrading = False - else: - self.connected = True - self.upgraded = True - - # start separate writer thread - def writer(): - while True: - packets = None - try: - packets = self.poll() - except exceptions.QueueEmpty: - break - if not packets: - # empty packet list returned -> connection closed - break - try: - for pkt in packets: - ws.send(pkt.encode()) - except: - break - ws.close() - - writer_task = self.server.start_background_task(writer) - - self.server.logger.info( - '%s: Upgrade to websocket successful', self.sid) - - while True: - p = None - try: - p = websocket_wait() - except Exception as e: - # if the socket is already closed, we can assume this is a - # downstream error of that - if not self.closed: # pragma: no cover - self.server.logger.info( - '%s: Unexpected error "%s", closing connection', - self.sid, str(e)) - break - if p is None: - # connection closed by client - break - pkt = packet.Packet(encoded_packet=p) - try: - self.receive(pkt) - except exceptions.UnknownPacketError: # pragma: no cover - pass - except exceptions.SocketIsClosedError: # pragma: no cover - self.server.logger.info('Receive error -- socket is closed') - break - except: # pragma: no cover - # if we get an unexpected exception we log the error and exit - # the connection properly - self.server.logger.exception('Unknown receive error') - break - - self.queue.put(None) # unlock the writer task so that it can exit - writer_task.join() - self.close(wait=False, abort=True, - reason=self.server.reason.TRANSPORT_CLOSE) - - return [] diff --git a/venv/lib/python3.9/site-packages/engineio/static_files.py b/venv/lib/python3.9/site-packages/engineio/static_files.py deleted file mode 100644 index 77c8915..0000000 --- a/venv/lib/python3.9/site-packages/engineio/static_files.py +++ /dev/null @@ -1,60 +0,0 @@ -content_types = { - 'css': 'text/css', - 'gif': 'image/gif', - 'html': 'text/html', - 'jpg': 'image/jpeg', - 'js': 'application/javascript', - 'json': 'application/json', - 'png': 'image/png', - 'txt': 'text/plain', -} - - -def get_static_file(path, static_files): - """Return the local filename and content type for the requested static - file URL. - - :param path: the path portion of the requested URL. - :param static_files: a static file configuration dictionary. - - This function returns a dictionary with two keys, "filename" and - "content_type". If the requested URL does not match any static file, the - return value is None. - """ - extra_path = '' - if path in static_files: - f = static_files[path] - else: - f = None - while path != '': - path, last = path.rsplit('/', 1) - extra_path = '/' + last + extra_path - if path in static_files: - f = static_files[path] - break - elif path + '/' in static_files: - f = static_files[path + '/'] - break - if f: - if isinstance(f, str): - f = {'filename': f} - else: - f = f.copy() # in case it is mutated below - if f['filename'].endswith('/') and extra_path.startswith('/'): - extra_path = extra_path[1:] - f['filename'] += extra_path - if f['filename'].endswith('/'): - if '' in static_files: - if isinstance(static_files[''], str): - f['filename'] += static_files[''] - else: - f['filename'] += static_files['']['filename'] - if 'content_type' in static_files['']: - f['content_type'] = static_files['']['content_type'] - else: - f['filename'] += 'index.html' - if 'content_type' not in f: - ext = f['filename'].rsplit('.')[-1] - f['content_type'] = content_types.get( - ext, 'application/octet-stream') - return f diff --git a/venv/lib/python3.9/site-packages/flask-3.1.3.dist-info/INSTALLER b/venv/lib/python3.9/site-packages/flask-3.1.3.dist-info/INSTALLER deleted file mode 100644 index a1b589e..0000000 --- a/venv/lib/python3.9/site-packages/flask-3.1.3.dist-info/INSTALLER +++ /dev/null @@ -1 +0,0 @@ -pip diff --git a/venv/lib/python3.9/site-packages/flask-3.1.3.dist-info/METADATA b/venv/lib/python3.9/site-packages/flask-3.1.3.dist-info/METADATA deleted file mode 100644 index 9d8623c..0000000 --- a/venv/lib/python3.9/site-packages/flask-3.1.3.dist-info/METADATA +++ /dev/null @@ -1,91 +0,0 @@ -Metadata-Version: 2.4 -Name: Flask -Version: 3.1.3 -Summary: A simple framework for building complex web applications. -Maintainer-email: Pallets -Requires-Python: >=3.9 -Description-Content-Type: text/markdown -License-Expression: BSD-3-Clause -Classifier: Development Status :: 5 - Production/Stable -Classifier: Environment :: Web Environment -Classifier: Framework :: Flask -Classifier: Intended Audience :: Developers -Classifier: Operating System :: OS Independent -Classifier: Programming Language :: Python -Classifier: Topic :: Internet :: WWW/HTTP :: Dynamic Content -Classifier: Topic :: Internet :: WWW/HTTP :: WSGI -Classifier: Topic :: Internet :: WWW/HTTP :: WSGI :: Application -Classifier: Topic :: Software Development :: Libraries :: Application Frameworks -Classifier: Typing :: Typed -License-File: LICENSE.txt -Requires-Dist: blinker>=1.9.0 -Requires-Dist: click>=8.1.3 -Requires-Dist: importlib-metadata>=3.6.0; python_version < '3.10' -Requires-Dist: itsdangerous>=2.2.0 -Requires-Dist: jinja2>=3.1.2 -Requires-Dist: markupsafe>=2.1.1 -Requires-Dist: werkzeug>=3.1.0 -Requires-Dist: asgiref>=3.2 ; extra == "async" -Requires-Dist: python-dotenv ; extra == "dotenv" -Project-URL: Changes, https://flask.palletsprojects.com/page/changes/ -Project-URL: Chat, https://discord.gg/pallets -Project-URL: Documentation, https://flask.palletsprojects.com/ -Project-URL: Donate, https://palletsprojects.com/donate -Project-URL: Source, https://github.com/pallets/flask/ -Provides-Extra: async -Provides-Extra: dotenv - -
    - -# Flask - -Flask is a lightweight [WSGI] web application framework. It is designed -to make getting started quick and easy, with the ability to scale up to -complex applications. It began as a simple wrapper around [Werkzeug] -and [Jinja], and has become one of the most popular Python web -application frameworks. - -Flask offers suggestions, but doesn't enforce any dependencies or -project layout. It is up to the developer to choose the tools and -libraries they want to use. There are many extensions provided by the -community that make adding new functionality easy. - -[WSGI]: https://wsgi.readthedocs.io/ -[Werkzeug]: https://werkzeug.palletsprojects.com/ -[Jinja]: https://jinja.palletsprojects.com/ - -## A Simple Example - -```python -# save this as app.py -from flask import Flask - -app = Flask(__name__) - -@app.route("/") -def hello(): - return "Hello, World!" -``` - -``` -$ flask run - * Running on http://127.0.0.1:5000/ (Press CTRL+C to quit) -``` - -## Donate - -The Pallets organization develops and supports Flask and the libraries -it uses. In order to grow the community of contributors and users, and -allow the maintainers to devote more time to the projects, [please -donate today]. - -[please donate today]: https://palletsprojects.com/donate - -## Contributing - -See our [detailed contributing documentation][contrib] for many ways to -contribute, including reporting issues, requesting features, asking or answering -questions, and making PRs. - -[contrib]: https://palletsprojects.com/contributing/ - diff --git a/venv/lib/python3.9/site-packages/flask-3.1.3.dist-info/RECORD b/venv/lib/python3.9/site-packages/flask-3.1.3.dist-info/RECORD deleted file mode 100644 index 87b6cba..0000000 --- a/venv/lib/python3.9/site-packages/flask-3.1.3.dist-info/RECORD +++ /dev/null @@ -1,58 +0,0 @@ -../../../bin/flask,sha256=P08Ez2FkehsldCPBvfWzIWbK7QzGpy60eyWsLKAacP0,182 -flask-3.1.3.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 -flask-3.1.3.dist-info/METADATA,sha256=qmdg7W9UVwRHTXBzPkpjp_FIHjdpc-3IlqE9AqciTHw,3167 -flask-3.1.3.dist-info/RECORD,, -flask-3.1.3.dist-info/REQUESTED,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 -flask-3.1.3.dist-info/WHEEL,sha256=G2gURzTEtmeR8nrdXUJfNiB3VYVxigPQ-bEQujpNiNs,82 -flask-3.1.3.dist-info/entry_points.txt,sha256=bBP7hTOS5fz9zLtC7sPofBZAlMkEvBxu7KqS6l5lvc4,40 -flask-3.1.3.dist-info/licenses/LICENSE.txt,sha256=SJqOEQhQntmKN7uYPhHg9-HTHwvY-Zp5yESOf_N9B-o,1475 -flask/__init__.py,sha256=mHvJN9Swtl1RDtjCqCIYyIniK_SZ_l_hqUynOzgpJ9o,2701 -flask/__main__.py,sha256=bYt9eEaoRQWdejEHFD8REx9jxVEdZptECFsV7F49Ink,30 -flask/__pycache__/__init__.cpython-39.pyc,, -flask/__pycache__/__main__.cpython-39.pyc,, -flask/__pycache__/app.cpython-39.pyc,, -flask/__pycache__/blueprints.cpython-39.pyc,, -flask/__pycache__/cli.cpython-39.pyc,, -flask/__pycache__/config.cpython-39.pyc,, -flask/__pycache__/ctx.cpython-39.pyc,, -flask/__pycache__/debughelpers.cpython-39.pyc,, -flask/__pycache__/globals.cpython-39.pyc,, -flask/__pycache__/helpers.cpython-39.pyc,, -flask/__pycache__/logging.cpython-39.pyc,, -flask/__pycache__/sessions.cpython-39.pyc,, -flask/__pycache__/signals.cpython-39.pyc,, -flask/__pycache__/templating.cpython-39.pyc,, -flask/__pycache__/testing.cpython-39.pyc,, -flask/__pycache__/typing.cpython-39.pyc,, -flask/__pycache__/views.cpython-39.pyc,, -flask/__pycache__/wrappers.cpython-39.pyc,, -flask/app.py,sha256=k7tW8LHRSldUi6zKsFKK7Axa_WL4zu1e2wPNthIsu7o,61719 -flask/blueprints.py,sha256=p5QE2lY18GItbdr_RKRpZ8Do17g0PvQGIgZkSUDhX2k,4541 -flask/cli.py,sha256=Pfh72-BxlvoH0QHCDOc1HvXG7Kq5Xetf3zzNz2kNSHk,37184 -flask/config.py,sha256=PiqF0DPam6HW0FH4CH1hpXTBe30NSzjPEOwrz1b6kt0,13219 -flask/ctx.py,sha256=oMe0TRsScW0qdaIqavVsk8P9qiEvAY5VHn1FAgkX8nk,15521 -flask/debughelpers.py,sha256=PGIDhStW_efRjpaa3zHIpo-htStJOR41Ip3OJWPYBwo,6080 -flask/globals.py,sha256=XdQZmStBmPIs8t93tjx6pO7Bm3gobAaONWkFcUHaGas,1713 -flask/helpers.py,sha256=rJZge7_J288J1UQv5-kNf4oEaw332PP8NTW0QRIBbXE,23517 -flask/json/__init__.py,sha256=hLNR898paqoefdeAhraa5wyJy-bmRB2k2dV4EgVy2Z8,5602 -flask/json/__pycache__/__init__.cpython-39.pyc,, -flask/json/__pycache__/provider.cpython-39.pyc,, -flask/json/__pycache__/tag.cpython-39.pyc,, -flask/json/provider.py,sha256=5imEzY5HjV2HoUVrQbJLqXCzMNpZXfD0Y1XqdLV2XBA,7672 -flask/json/tag.py,sha256=DhaNwuIOhdt2R74oOC9Y4Z8ZprxFYiRb5dUP5byyINw,9281 -flask/logging.py,sha256=8sM3WMTubi1cBb2c_lPkWpN0J8dMAqrgKRYLLi1dCVI,2377 -flask/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 -flask/sansio/README.md,sha256=-0X1tECnilmz1cogx-YhNw5d7guK7GKrq_DEV2OzlU0,228 -flask/sansio/__pycache__/app.cpython-39.pyc,, -flask/sansio/__pycache__/blueprints.cpython-39.pyc,, -flask/sansio/__pycache__/scaffold.cpython-39.pyc,, -flask/sansio/app.py,sha256=whGURQDkN0jmhS4CHO7DQ96GGlZS0kETkKkAkoRjl4U,38106 -flask/sansio/blueprints.py,sha256=Tqe-7EkZ-tbWchm8iDoCfD848f0_3nLv6NNjeIPvHwM,24637 -flask/sansio/scaffold.py,sha256=wSASXYdFRWJmqcL0Xq-T7N-PDVUSiFGvjO9kPZg58bk,30371 -flask/sessions.py,sha256=eywRqmytTmYnX_EC78-YBGJoTc5XD_lRphQG5LbN1d0,14969 -flask/signals.py,sha256=V7lMUww7CqgJ2ThUBn1PiatZtQanOyt7OZpu2GZI-34,750 -flask/templating.py,sha256=vbIkwYAxsSEfDxQID1gKRvBQQcGWEuWYCnH0XK3EqOI,7678 -flask/testing.py,sha256=zzC7XxhBWOP9H697IV_4SG7Lg3Lzb5PWiyEP93_KQXE,10117 -flask/typing.py,sha256=L-L5t2jKgS0aOmVhioQ_ylqcgiVFnA6yxO-RLNhq-GU,3293 -flask/views.py,sha256=xzJx6oJqGElThtEghZN7ZQGMw5TDFyuRxUkecwRuAoA,6962 -flask/wrappers.py,sha256=jUkv4mVek2Iq4hwxd4RvqrIMb69Bv0PElDgWLmd5ORo,9406 diff --git a/venv/lib/python3.9/site-packages/flask-3.1.3.dist-info/REQUESTED b/venv/lib/python3.9/site-packages/flask-3.1.3.dist-info/REQUESTED deleted file mode 100644 index e69de29..0000000 diff --git a/venv/lib/python3.9/site-packages/flask-3.1.3.dist-info/WHEEL b/venv/lib/python3.9/site-packages/flask-3.1.3.dist-info/WHEEL deleted file mode 100644 index d8b9936..0000000 --- a/venv/lib/python3.9/site-packages/flask-3.1.3.dist-info/WHEEL +++ /dev/null @@ -1,4 +0,0 @@ -Wheel-Version: 1.0 -Generator: flit 3.12.0 -Root-Is-Purelib: true -Tag: py3-none-any diff --git a/venv/lib/python3.9/site-packages/flask-3.1.3.dist-info/entry_points.txt b/venv/lib/python3.9/site-packages/flask-3.1.3.dist-info/entry_points.txt deleted file mode 100644 index eec6733..0000000 --- a/venv/lib/python3.9/site-packages/flask-3.1.3.dist-info/entry_points.txt +++ /dev/null @@ -1,3 +0,0 @@ -[console_scripts] -flask=flask.cli:main - diff --git a/venv/lib/python3.9/site-packages/flask-3.1.3.dist-info/licenses/LICENSE.txt b/venv/lib/python3.9/site-packages/flask-3.1.3.dist-info/licenses/LICENSE.txt deleted file mode 100644 index 9d227a0..0000000 --- a/venv/lib/python3.9/site-packages/flask-3.1.3.dist-info/licenses/LICENSE.txt +++ /dev/null @@ -1,28 +0,0 @@ -Copyright 2010 Pallets - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - -1. Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - -2. Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - -3. Neither the name of the copyright holder nor the names of its - contributors may be used to endorse or promote products derived from - this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A -PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED -TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR -PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF -LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING -NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/venv/lib/python3.9/site-packages/flask/__init__.py b/venv/lib/python3.9/site-packages/flask/__init__.py deleted file mode 100644 index 1fdc50c..0000000 --- a/venv/lib/python3.9/site-packages/flask/__init__.py +++ /dev/null @@ -1,61 +0,0 @@ -from __future__ import annotations - -import typing as t - -from . import json as json -from .app import Flask as Flask -from .blueprints import Blueprint as Blueprint -from .config import Config as Config -from .ctx import after_this_request as after_this_request -from .ctx import copy_current_request_context as copy_current_request_context -from .ctx import has_app_context as has_app_context -from .ctx import has_request_context as has_request_context -from .globals import current_app as current_app -from .globals import g as g -from .globals import request as request -from .globals import session as session -from .helpers import abort as abort -from .helpers import flash as flash -from .helpers import get_flashed_messages as get_flashed_messages -from .helpers import get_template_attribute as get_template_attribute -from .helpers import make_response as make_response -from .helpers import redirect as redirect -from .helpers import send_file as send_file -from .helpers import send_from_directory as send_from_directory -from .helpers import stream_with_context as stream_with_context -from .helpers import url_for as url_for -from .json import jsonify as jsonify -from .signals import appcontext_popped as appcontext_popped -from .signals import appcontext_pushed as appcontext_pushed -from .signals import appcontext_tearing_down as appcontext_tearing_down -from .signals import before_render_template as before_render_template -from .signals import got_request_exception as got_request_exception -from .signals import message_flashed as message_flashed -from .signals import request_finished as request_finished -from .signals import request_started as request_started -from .signals import request_tearing_down as request_tearing_down -from .signals import template_rendered as template_rendered -from .templating import render_template as render_template -from .templating import render_template_string as render_template_string -from .templating import stream_template as stream_template -from .templating import stream_template_string as stream_template_string -from .wrappers import Request as Request -from .wrappers import Response as Response - -if not t.TYPE_CHECKING: - - def __getattr__(name: str) -> t.Any: - if name == "__version__": - import importlib.metadata - import warnings - - warnings.warn( - "The '__version__' attribute is deprecated and will be removed in" - " Flask 3.2. Use feature detection or" - " 'importlib.metadata.version(\"flask\")' instead.", - DeprecationWarning, - stacklevel=2, - ) - return importlib.metadata.version("flask") - - raise AttributeError(name) diff --git a/venv/lib/python3.9/site-packages/flask/__main__.py b/venv/lib/python3.9/site-packages/flask/__main__.py deleted file mode 100644 index 4e28416..0000000 --- a/venv/lib/python3.9/site-packages/flask/__main__.py +++ /dev/null @@ -1,3 +0,0 @@ -from .cli import main - -main() diff --git a/venv/lib/python3.9/site-packages/flask/app.py b/venv/lib/python3.9/site-packages/flask/app.py deleted file mode 100644 index cc326db..0000000 --- a/venv/lib/python3.9/site-packages/flask/app.py +++ /dev/null @@ -1,1536 +0,0 @@ -from __future__ import annotations - -import collections.abc as cabc -import os -import sys -import typing as t -import weakref -from datetime import timedelta -from inspect import iscoroutinefunction -from itertools import chain -from types import TracebackType -from urllib.parse import quote as _url_quote - -import click -from werkzeug.datastructures import Headers -from werkzeug.datastructures import ImmutableDict -from werkzeug.exceptions import BadRequestKeyError -from werkzeug.exceptions import HTTPException -from werkzeug.exceptions import InternalServerError -from werkzeug.routing import BuildError -from werkzeug.routing import MapAdapter -from werkzeug.routing import RequestRedirect -from werkzeug.routing import RoutingException -from werkzeug.routing import Rule -from werkzeug.serving import is_running_from_reloader -from werkzeug.wrappers import Response as BaseResponse -from werkzeug.wsgi import get_host - -from . import cli -from . import typing as ft -from .ctx import AppContext -from .ctx import RequestContext -from .globals import _cv_app -from .globals import _cv_request -from .globals import current_app -from .globals import g -from .globals import request -from .globals import request_ctx -from .globals import session -from .helpers import get_debug_flag -from .helpers import get_flashed_messages -from .helpers import get_load_dotenv -from .helpers import send_from_directory -from .sansio.app import App -from .sansio.scaffold import _sentinel -from .sessions import SecureCookieSessionInterface -from .sessions import SessionInterface -from .signals import appcontext_tearing_down -from .signals import got_request_exception -from .signals import request_finished -from .signals import request_started -from .signals import request_tearing_down -from .templating import Environment -from .wrappers import Request -from .wrappers import Response - -if t.TYPE_CHECKING: # pragma: no cover - from _typeshed.wsgi import StartResponse - from _typeshed.wsgi import WSGIEnvironment - - from .testing import FlaskClient - from .testing import FlaskCliRunner - from .typing import HeadersValue - -T_shell_context_processor = t.TypeVar( - "T_shell_context_processor", bound=ft.ShellContextProcessorCallable -) -T_teardown = t.TypeVar("T_teardown", bound=ft.TeardownCallable) -T_template_filter = t.TypeVar("T_template_filter", bound=ft.TemplateFilterCallable) -T_template_global = t.TypeVar("T_template_global", bound=ft.TemplateGlobalCallable) -T_template_test = t.TypeVar("T_template_test", bound=ft.TemplateTestCallable) - - -def _make_timedelta(value: timedelta | int | None) -> timedelta | None: - if value is None or isinstance(value, timedelta): - return value - - return timedelta(seconds=value) - - -class Flask(App): - """The flask object implements a WSGI application and acts as the central - object. It is passed the name of the module or package of the - application. Once it is created it will act as a central registry for - the view functions, the URL rules, template configuration and much more. - - The name of the package is used to resolve resources from inside the - package or the folder the module is contained in depending on if the - package parameter resolves to an actual python package (a folder with - an :file:`__init__.py` file inside) or a standard module (just a ``.py`` file). - - For more information about resource loading, see :func:`open_resource`. - - Usually you create a :class:`Flask` instance in your main module or - in the :file:`__init__.py` file of your package like this:: - - from flask import Flask - app = Flask(__name__) - - .. admonition:: About the First Parameter - - The idea of the first parameter is to give Flask an idea of what - belongs to your application. This name is used to find resources - on the filesystem, can be used by extensions to improve debugging - information and a lot more. - - So it's important what you provide there. If you are using a single - module, `__name__` is always the correct value. If you however are - using a package, it's usually recommended to hardcode the name of - your package there. - - For example if your application is defined in :file:`yourapplication/app.py` - you should create it with one of the two versions below:: - - app = Flask('yourapplication') - app = Flask(__name__.split('.')[0]) - - Why is that? The application will work even with `__name__`, thanks - to how resources are looked up. However it will make debugging more - painful. Certain extensions can make assumptions based on the - import name of your application. For example the Flask-SQLAlchemy - extension will look for the code in your application that triggered - an SQL query in debug mode. If the import name is not properly set - up, that debugging information is lost. (For example it would only - pick up SQL queries in `yourapplication.app` and not - `yourapplication.views.frontend`) - - .. versionadded:: 0.7 - The `static_url_path`, `static_folder`, and `template_folder` - parameters were added. - - .. versionadded:: 0.8 - The `instance_path` and `instance_relative_config` parameters were - added. - - .. versionadded:: 0.11 - The `root_path` parameter was added. - - .. versionadded:: 1.0 - The ``host_matching`` and ``static_host`` parameters were added. - - .. versionadded:: 1.0 - The ``subdomain_matching`` parameter was added. Subdomain - matching needs to be enabled manually now. Setting - :data:`SERVER_NAME` does not implicitly enable it. - - :param import_name: the name of the application package - :param static_url_path: can be used to specify a different path for the - static files on the web. Defaults to the name - of the `static_folder` folder. - :param static_folder: The folder with static files that is served at - ``static_url_path``. Relative to the application ``root_path`` - or an absolute path. Defaults to ``'static'``. - :param static_host: the host to use when adding the static route. - Defaults to None. Required when using ``host_matching=True`` - with a ``static_folder`` configured. - :param host_matching: set ``url_map.host_matching`` attribute. - Defaults to False. - :param subdomain_matching: consider the subdomain relative to - :data:`SERVER_NAME` when matching routes. Defaults to False. - :param template_folder: the folder that contains the templates that should - be used by the application. Defaults to - ``'templates'`` folder in the root path of the - application. - :param instance_path: An alternative instance path for the application. - By default the folder ``'instance'`` next to the - package or module is assumed to be the instance - path. - :param instance_relative_config: if set to ``True`` relative filenames - for loading the config are assumed to - be relative to the instance path instead - of the application root. - :param root_path: The path to the root of the application files. - This should only be set manually when it can't be detected - automatically, such as for namespace packages. - """ - - default_config = ImmutableDict( - { - "DEBUG": None, - "TESTING": False, - "PROPAGATE_EXCEPTIONS": None, - "SECRET_KEY": None, - "SECRET_KEY_FALLBACKS": None, - "PERMANENT_SESSION_LIFETIME": timedelta(days=31), - "USE_X_SENDFILE": False, - "TRUSTED_HOSTS": None, - "SERVER_NAME": None, - "APPLICATION_ROOT": "/", - "SESSION_COOKIE_NAME": "session", - "SESSION_COOKIE_DOMAIN": None, - "SESSION_COOKIE_PATH": None, - "SESSION_COOKIE_HTTPONLY": True, - "SESSION_COOKIE_SECURE": False, - "SESSION_COOKIE_PARTITIONED": False, - "SESSION_COOKIE_SAMESITE": None, - "SESSION_REFRESH_EACH_REQUEST": True, - "MAX_CONTENT_LENGTH": None, - "MAX_FORM_MEMORY_SIZE": 500_000, - "MAX_FORM_PARTS": 1_000, - "SEND_FILE_MAX_AGE_DEFAULT": None, - "TRAP_BAD_REQUEST_ERRORS": None, - "TRAP_HTTP_EXCEPTIONS": False, - "EXPLAIN_TEMPLATE_LOADING": False, - "PREFERRED_URL_SCHEME": "http", - "TEMPLATES_AUTO_RELOAD": None, - "MAX_COOKIE_SIZE": 4093, - "PROVIDE_AUTOMATIC_OPTIONS": True, - } - ) - - #: The class that is used for request objects. See :class:`~flask.Request` - #: for more information. - request_class: type[Request] = Request - - #: The class that is used for response objects. See - #: :class:`~flask.Response` for more information. - response_class: type[Response] = Response - - #: the session interface to use. By default an instance of - #: :class:`~flask.sessions.SecureCookieSessionInterface` is used here. - #: - #: .. versionadded:: 0.8 - session_interface: SessionInterface = SecureCookieSessionInterface() - - def __init__( - self, - import_name: str, - static_url_path: str | None = None, - static_folder: str | os.PathLike[str] | None = "static", - static_host: str | None = None, - host_matching: bool = False, - subdomain_matching: bool = False, - template_folder: str | os.PathLike[str] | None = "templates", - instance_path: str | None = None, - instance_relative_config: bool = False, - root_path: str | None = None, - ): - super().__init__( - import_name=import_name, - static_url_path=static_url_path, - static_folder=static_folder, - static_host=static_host, - host_matching=host_matching, - subdomain_matching=subdomain_matching, - template_folder=template_folder, - instance_path=instance_path, - instance_relative_config=instance_relative_config, - root_path=root_path, - ) - - #: The Click command group for registering CLI commands for this - #: object. The commands are available from the ``flask`` command - #: once the application has been discovered and blueprints have - #: been registered. - self.cli = cli.AppGroup() - - # Set the name of the Click group in case someone wants to add - # the app's commands to another CLI tool. - self.cli.name = self.name - - # Add a static route using the provided static_url_path, static_host, - # and static_folder if there is a configured static_folder. - # Note we do this without checking if static_folder exists. - # For one, it might be created while the server is running (e.g. during - # development). Also, Google App Engine stores static files somewhere - if self.has_static_folder: - assert bool(static_host) == host_matching, ( - "Invalid static_host/host_matching combination" - ) - # Use a weakref to avoid creating a reference cycle between the app - # and the view function (see #3761). - self_ref = weakref.ref(self) - self.add_url_rule( - f"{self.static_url_path}/", - endpoint="static", - host=static_host, - view_func=lambda **kw: self_ref().send_static_file(**kw), # type: ignore - ) - - def get_send_file_max_age(self, filename: str | None) -> int | None: - """Used by :func:`send_file` to determine the ``max_age`` cache - value for a given file path if it wasn't passed. - - By default, this returns :data:`SEND_FILE_MAX_AGE_DEFAULT` from - the configuration of :data:`~flask.current_app`. This defaults - to ``None``, which tells the browser to use conditional requests - instead of a timed cache, which is usually preferable. - - Note this is a duplicate of the same method in the Flask - class. - - .. versionchanged:: 2.0 - The default configuration is ``None`` instead of 12 hours. - - .. versionadded:: 0.9 - """ - value = current_app.config["SEND_FILE_MAX_AGE_DEFAULT"] - - if value is None: - return None - - if isinstance(value, timedelta): - return int(value.total_seconds()) - - return value # type: ignore[no-any-return] - - def send_static_file(self, filename: str) -> Response: - """The view function used to serve files from - :attr:`static_folder`. A route is automatically registered for - this view at :attr:`static_url_path` if :attr:`static_folder` is - set. - - Note this is a duplicate of the same method in the Flask - class. - - .. versionadded:: 0.5 - - """ - if not self.has_static_folder: - raise RuntimeError("'static_folder' must be set to serve static_files.") - - # send_file only knows to call get_send_file_max_age on the app, - # call it here so it works for blueprints too. - max_age = self.get_send_file_max_age(filename) - return send_from_directory( - t.cast(str, self.static_folder), filename, max_age=max_age - ) - - def open_resource( - self, resource: str, mode: str = "rb", encoding: str | None = None - ) -> t.IO[t.AnyStr]: - """Open a resource file relative to :attr:`root_path` for reading. - - For example, if the file ``schema.sql`` is next to the file - ``app.py`` where the ``Flask`` app is defined, it can be opened - with: - - .. code-block:: python - - with app.open_resource("schema.sql") as f: - conn.executescript(f.read()) - - :param resource: Path to the resource relative to :attr:`root_path`. - :param mode: Open the file in this mode. Only reading is supported, - valid values are ``"r"`` (or ``"rt"``) and ``"rb"``. - :param encoding: Open the file with this encoding when opening in text - mode. This is ignored when opening in binary mode. - - .. versionchanged:: 3.1 - Added the ``encoding`` parameter. - """ - if mode not in {"r", "rt", "rb"}: - raise ValueError("Resources can only be opened for reading.") - - path = os.path.join(self.root_path, resource) - - if mode == "rb": - return open(path, mode) # pyright: ignore - - return open(path, mode, encoding=encoding) - - def open_instance_resource( - self, resource: str, mode: str = "rb", encoding: str | None = "utf-8" - ) -> t.IO[t.AnyStr]: - """Open a resource file relative to the application's instance folder - :attr:`instance_path`. Unlike :meth:`open_resource`, files in the - instance folder can be opened for writing. - - :param resource: Path to the resource relative to :attr:`instance_path`. - :param mode: Open the file in this mode. - :param encoding: Open the file with this encoding when opening in text - mode. This is ignored when opening in binary mode. - - .. versionchanged:: 3.1 - Added the ``encoding`` parameter. - """ - path = os.path.join(self.instance_path, resource) - - if "b" in mode: - return open(path, mode) - - return open(path, mode, encoding=encoding) - - def create_jinja_environment(self) -> Environment: - """Create the Jinja environment based on :attr:`jinja_options` - and the various Jinja-related methods of the app. Changing - :attr:`jinja_options` after this will have no effect. Also adds - Flask-related globals and filters to the environment. - - .. versionchanged:: 0.11 - ``Environment.auto_reload`` set in accordance with - ``TEMPLATES_AUTO_RELOAD`` configuration option. - - .. versionadded:: 0.5 - """ - options = dict(self.jinja_options) - - if "autoescape" not in options: - options["autoescape"] = self.select_jinja_autoescape - - if "auto_reload" not in options: - auto_reload = self.config["TEMPLATES_AUTO_RELOAD"] - - if auto_reload is None: - auto_reload = self.debug - - options["auto_reload"] = auto_reload - - rv = self.jinja_environment(self, **options) - rv.globals.update( - url_for=self.url_for, - get_flashed_messages=get_flashed_messages, - config=self.config, - # request, session and g are normally added with the - # context processor for efficiency reasons but for imported - # templates we also want the proxies in there. - request=request, - session=session, - g=g, - ) - rv.policies["json.dumps_function"] = self.json.dumps - return rv - - def create_url_adapter(self, request: Request | None) -> MapAdapter | None: - """Creates a URL adapter for the given request. The URL adapter - is created at a point where the request context is not yet set - up so the request is passed explicitly. - - .. versionchanged:: 3.1 - If :data:`SERVER_NAME` is set, it does not restrict requests to - only that domain, for both ``subdomain_matching`` and - ``host_matching``. - - .. versionchanged:: 1.0 - :data:`SERVER_NAME` no longer implicitly enables subdomain - matching. Use :attr:`subdomain_matching` instead. - - .. versionchanged:: 0.9 - This can be called outside a request when the URL adapter is created - for an application context. - - .. versionadded:: 0.6 - """ - if request is not None: - if (trusted_hosts := self.config["TRUSTED_HOSTS"]) is not None: - request.trusted_hosts = trusted_hosts - - # Check trusted_hosts here until bind_to_environ does. - request.host = get_host(request.environ, request.trusted_hosts) # pyright: ignore - subdomain = None - server_name = self.config["SERVER_NAME"] - - if self.url_map.host_matching: - # Don't pass SERVER_NAME, otherwise it's used and the actual - # host is ignored, which breaks host matching. - server_name = None - elif not self.subdomain_matching: - # Werkzeug doesn't implement subdomain matching yet. Until then, - # disable it by forcing the current subdomain to the default, or - # the empty string. - subdomain = self.url_map.default_subdomain or "" - - return self.url_map.bind_to_environ( - request.environ, server_name=server_name, subdomain=subdomain - ) - - # Need at least SERVER_NAME to match/build outside a request. - if self.config["SERVER_NAME"] is not None: - return self.url_map.bind( - self.config["SERVER_NAME"], - script_name=self.config["APPLICATION_ROOT"], - url_scheme=self.config["PREFERRED_URL_SCHEME"], - ) - - return None - - def raise_routing_exception(self, request: Request) -> t.NoReturn: - """Intercept routing exceptions and possibly do something else. - - In debug mode, intercept a routing redirect and replace it with - an error if the body will be discarded. - - With modern Werkzeug this shouldn't occur, since it now uses a - 308 status which tells the browser to resend the method and - body. - - .. versionchanged:: 2.1 - Don't intercept 307 and 308 redirects. - - :meta private: - :internal: - """ - if ( - not self.debug - or not isinstance(request.routing_exception, RequestRedirect) - or request.routing_exception.code in {307, 308} - or request.method in {"GET", "HEAD", "OPTIONS"} - ): - raise request.routing_exception # type: ignore[misc] - - from .debughelpers import FormDataRoutingRedirect - - raise FormDataRoutingRedirect(request) - - def update_template_context(self, context: dict[str, t.Any]) -> None: - """Update the template context with some commonly used variables. - This injects request, session, config and g into the template - context as well as everything template context processors want - to inject. Note that the as of Flask 0.6, the original values - in the context will not be overridden if a context processor - decides to return a value with the same key. - - :param context: the context as a dictionary that is updated in place - to add extra variables. - """ - names: t.Iterable[str | None] = (None,) - - # A template may be rendered outside a request context. - if request: - names = chain(names, reversed(request.blueprints)) - - # The values passed to render_template take precedence. Keep a - # copy to re-apply after all context functions. - orig_ctx = context.copy() - - for name in names: - if name in self.template_context_processors: - for func in self.template_context_processors[name]: - context.update(self.ensure_sync(func)()) - - context.update(orig_ctx) - - def make_shell_context(self) -> dict[str, t.Any]: - """Returns the shell context for an interactive shell for this - application. This runs all the registered shell context - processors. - - .. versionadded:: 0.11 - """ - rv = {"app": self, "g": g} - for processor in self.shell_context_processors: - rv.update(processor()) - return rv - - def run( - self, - host: str | None = None, - port: int | None = None, - debug: bool | None = None, - load_dotenv: bool = True, - **options: t.Any, - ) -> None: - """Runs the application on a local development server. - - Do not use ``run()`` in a production setting. It is not intended to - meet security and performance requirements for a production server. - Instead, see :doc:`/deploying/index` for WSGI server recommendations. - - If the :attr:`debug` flag is set the server will automatically reload - for code changes and show a debugger in case an exception happened. - - If you want to run the application in debug mode, but disable the - code execution on the interactive debugger, you can pass - ``use_evalex=False`` as parameter. This will keep the debugger's - traceback screen active, but disable code execution. - - It is not recommended to use this function for development with - automatic reloading as this is badly supported. Instead you should - be using the :command:`flask` command line script's ``run`` support. - - .. admonition:: Keep in Mind - - Flask will suppress any server error with a generic error page - unless it is in debug mode. As such to enable just the - interactive debugger without the code reloading, you have to - invoke :meth:`run` with ``debug=True`` and ``use_reloader=False``. - Setting ``use_debugger`` to ``True`` without being in debug mode - won't catch any exceptions because there won't be any to - catch. - - :param host: the hostname to listen on. Set this to ``'0.0.0.0'`` to - have the server available externally as well. Defaults to - ``'127.0.0.1'`` or the host in the ``SERVER_NAME`` config variable - if present. - :param port: the port of the webserver. Defaults to ``5000`` or the - port defined in the ``SERVER_NAME`` config variable if present. - :param debug: if given, enable or disable debug mode. See - :attr:`debug`. - :param load_dotenv: Load the nearest :file:`.env` and :file:`.flaskenv` - files to set environment variables. Will also change the working - directory to the directory containing the first file found. - :param options: the options to be forwarded to the underlying Werkzeug - server. See :func:`werkzeug.serving.run_simple` for more - information. - - .. versionchanged:: 1.0 - If installed, python-dotenv will be used to load environment - variables from :file:`.env` and :file:`.flaskenv` files. - - The :envvar:`FLASK_DEBUG` environment variable will override :attr:`debug`. - - Threaded mode is enabled by default. - - .. versionchanged:: 0.10 - The default port is now picked from the ``SERVER_NAME`` - variable. - """ - # Ignore this call so that it doesn't start another server if - # the 'flask run' command is used. - if os.environ.get("FLASK_RUN_FROM_CLI") == "true": - if not is_running_from_reloader(): - click.secho( - " * Ignoring a call to 'app.run()' that would block" - " the current 'flask' CLI command.\n" - " Only call 'app.run()' in an 'if __name__ ==" - ' "__main__"\' guard.', - fg="red", - ) - - return - - if get_load_dotenv(load_dotenv): - cli.load_dotenv() - - # if set, env var overrides existing value - if "FLASK_DEBUG" in os.environ: - self.debug = get_debug_flag() - - # debug passed to method overrides all other sources - if debug is not None: - self.debug = bool(debug) - - server_name = self.config.get("SERVER_NAME") - sn_host = sn_port = None - - if server_name: - sn_host, _, sn_port = server_name.partition(":") - - if not host: - if sn_host: - host = sn_host - else: - host = "127.0.0.1" - - if port or port == 0: - port = int(port) - elif sn_port: - port = int(sn_port) - else: - port = 5000 - - options.setdefault("use_reloader", self.debug) - options.setdefault("use_debugger", self.debug) - options.setdefault("threaded", True) - - cli.show_server_banner(self.debug, self.name) - - from werkzeug.serving import run_simple - - try: - run_simple(t.cast(str, host), port, self, **options) - finally: - # reset the first request information if the development server - # reset normally. This makes it possible to restart the server - # without reloader and that stuff from an interactive shell. - self._got_first_request = False - - def test_client(self, use_cookies: bool = True, **kwargs: t.Any) -> FlaskClient: - """Creates a test client for this application. For information - about unit testing head over to :doc:`/testing`. - - Note that if you are testing for assertions or exceptions in your - application code, you must set ``app.testing = True`` in order for the - exceptions to propagate to the test client. Otherwise, the exception - will be handled by the application (not visible to the test client) and - the only indication of an AssertionError or other exception will be a - 500 status code response to the test client. See the :attr:`testing` - attribute. For example:: - - app.testing = True - client = app.test_client() - - The test client can be used in a ``with`` block to defer the closing down - of the context until the end of the ``with`` block. This is useful if - you want to access the context locals for testing:: - - with app.test_client() as c: - rv = c.get('/?vodka=42') - assert request.args['vodka'] == '42' - - Additionally, you may pass optional keyword arguments that will then - be passed to the application's :attr:`test_client_class` constructor. - For example:: - - from flask.testing import FlaskClient - - class CustomClient(FlaskClient): - def __init__(self, *args, **kwargs): - self._authentication = kwargs.pop("authentication") - super(CustomClient,self).__init__( *args, **kwargs) - - app.test_client_class = CustomClient - client = app.test_client(authentication='Basic ....') - - See :class:`~flask.testing.FlaskClient` for more information. - - .. versionchanged:: 0.4 - added support for ``with`` block usage for the client. - - .. versionadded:: 0.7 - The `use_cookies` parameter was added as well as the ability - to override the client to be used by setting the - :attr:`test_client_class` attribute. - - .. versionchanged:: 0.11 - Added `**kwargs` to support passing additional keyword arguments to - the constructor of :attr:`test_client_class`. - """ - cls = self.test_client_class - if cls is None: - from .testing import FlaskClient as cls - return cls( # type: ignore - self, self.response_class, use_cookies=use_cookies, **kwargs - ) - - def test_cli_runner(self, **kwargs: t.Any) -> FlaskCliRunner: - """Create a CLI runner for testing CLI commands. - See :ref:`testing-cli`. - - Returns an instance of :attr:`test_cli_runner_class`, by default - :class:`~flask.testing.FlaskCliRunner`. The Flask app object is - passed as the first argument. - - .. versionadded:: 1.0 - """ - cls = self.test_cli_runner_class - - if cls is None: - from .testing import FlaskCliRunner as cls - - return cls(self, **kwargs) # type: ignore - - def handle_http_exception( - self, e: HTTPException - ) -> HTTPException | ft.ResponseReturnValue: - """Handles an HTTP exception. By default this will invoke the - registered error handlers and fall back to returning the - exception as response. - - .. versionchanged:: 1.0.3 - ``RoutingException``, used internally for actions such as - slash redirects during routing, is not passed to error - handlers. - - .. versionchanged:: 1.0 - Exceptions are looked up by code *and* by MRO, so - ``HTTPException`` subclasses can be handled with a catch-all - handler for the base ``HTTPException``. - - .. versionadded:: 0.3 - """ - # Proxy exceptions don't have error codes. We want to always return - # those unchanged as errors - if e.code is None: - return e - - # RoutingExceptions are used internally to trigger routing - # actions, such as slash redirects raising RequestRedirect. They - # are not raised or handled in user code. - if isinstance(e, RoutingException): - return e - - handler = self._find_error_handler(e, request.blueprints) - if handler is None: - return e - return self.ensure_sync(handler)(e) # type: ignore[no-any-return] - - def handle_user_exception( - self, e: Exception - ) -> HTTPException | ft.ResponseReturnValue: - """This method is called whenever an exception occurs that - should be handled. A special case is :class:`~werkzeug - .exceptions.HTTPException` which is forwarded to the - :meth:`handle_http_exception` method. This function will either - return a response value or reraise the exception with the same - traceback. - - .. versionchanged:: 1.0 - Key errors raised from request data like ``form`` show the - bad key in debug mode rather than a generic bad request - message. - - .. versionadded:: 0.7 - """ - if isinstance(e, BadRequestKeyError) and ( - self.debug or self.config["TRAP_BAD_REQUEST_ERRORS"] - ): - e.show_exception = True - - if isinstance(e, HTTPException) and not self.trap_http_exception(e): - return self.handle_http_exception(e) - - handler = self._find_error_handler(e, request.blueprints) - - if handler is None: - raise - - return self.ensure_sync(handler)(e) # type: ignore[no-any-return] - - def handle_exception(self, e: Exception) -> Response: - """Handle an exception that did not have an error handler - associated with it, or that was raised from an error handler. - This always causes a 500 ``InternalServerError``. - - Always sends the :data:`got_request_exception` signal. - - If :data:`PROPAGATE_EXCEPTIONS` is ``True``, such as in debug - mode, the error will be re-raised so that the debugger can - display it. Otherwise, the original exception is logged, and - an :exc:`~werkzeug.exceptions.InternalServerError` is returned. - - If an error handler is registered for ``InternalServerError`` or - ``500``, it will be used. For consistency, the handler will - always receive the ``InternalServerError``. The original - unhandled exception is available as ``e.original_exception``. - - .. versionchanged:: 1.1.0 - Always passes the ``InternalServerError`` instance to the - handler, setting ``original_exception`` to the unhandled - error. - - .. versionchanged:: 1.1.0 - ``after_request`` functions and other finalization is done - even for the default 500 response when there is no handler. - - .. versionadded:: 0.3 - """ - exc_info = sys.exc_info() - got_request_exception.send(self, _async_wrapper=self.ensure_sync, exception=e) - propagate = self.config["PROPAGATE_EXCEPTIONS"] - - if propagate is None: - propagate = self.testing or self.debug - - if propagate: - # Re-raise if called with an active exception, otherwise - # raise the passed in exception. - if exc_info[1] is e: - raise - - raise e - - self.log_exception(exc_info) - server_error: InternalServerError | ft.ResponseReturnValue - server_error = InternalServerError(original_exception=e) - handler = self._find_error_handler(server_error, request.blueprints) - - if handler is not None: - server_error = self.ensure_sync(handler)(server_error) - - return self.finalize_request(server_error, from_error_handler=True) - - def log_exception( - self, - exc_info: (tuple[type, BaseException, TracebackType] | tuple[None, None, None]), - ) -> None: - """Logs an exception. This is called by :meth:`handle_exception` - if debugging is disabled and right before the handler is called. - The default implementation logs the exception as error on the - :attr:`logger`. - - .. versionadded:: 0.8 - """ - self.logger.error( - f"Exception on {request.path} [{request.method}]", exc_info=exc_info - ) - - def dispatch_request(self) -> ft.ResponseReturnValue: - """Does the request dispatching. Matches the URL and returns the - return value of the view or error handler. This does not have to - be a response object. In order to convert the return value to a - proper response object, call :func:`make_response`. - - .. versionchanged:: 0.7 - This no longer does the exception handling, this code was - moved to the new :meth:`full_dispatch_request`. - """ - req = request_ctx.request - if req.routing_exception is not None: - self.raise_routing_exception(req) - rule: Rule = req.url_rule # type: ignore[assignment] - # if we provide automatic options for this URL and the - # request came with the OPTIONS method, reply automatically - if ( - getattr(rule, "provide_automatic_options", False) - and req.method == "OPTIONS" - ): - return self.make_default_options_response() - # otherwise dispatch to the handler for that endpoint - view_args: dict[str, t.Any] = req.view_args # type: ignore[assignment] - return self.ensure_sync(self.view_functions[rule.endpoint])(**view_args) # type: ignore[no-any-return] - - def full_dispatch_request(self) -> Response: - """Dispatches the request and on top of that performs request - pre and postprocessing as well as HTTP exception catching and - error handling. - - .. versionadded:: 0.7 - """ - self._got_first_request = True - - try: - request_started.send(self, _async_wrapper=self.ensure_sync) - rv = self.preprocess_request() - if rv is None: - rv = self.dispatch_request() - except Exception as e: - rv = self.handle_user_exception(e) - return self.finalize_request(rv) - - def finalize_request( - self, - rv: ft.ResponseReturnValue | HTTPException, - from_error_handler: bool = False, - ) -> Response: - """Given the return value from a view function this finalizes - the request by converting it into a response and invoking the - postprocessing functions. This is invoked for both normal - request dispatching as well as error handlers. - - Because this means that it might be called as a result of a - failure a special safe mode is available which can be enabled - with the `from_error_handler` flag. If enabled, failures in - response processing will be logged and otherwise ignored. - - :internal: - """ - response = self.make_response(rv) - try: - response = self.process_response(response) - request_finished.send( - self, _async_wrapper=self.ensure_sync, response=response - ) - except Exception: - if not from_error_handler: - raise - self.logger.exception( - "Request finalizing failed with an error while handling an error" - ) - return response - - def make_default_options_response(self) -> Response: - """This method is called to create the default ``OPTIONS`` response. - This can be changed through subclassing to change the default - behavior of ``OPTIONS`` responses. - - .. versionadded:: 0.7 - """ - adapter = request_ctx.url_adapter - methods = adapter.allowed_methods() # type: ignore[union-attr] - rv = self.response_class() - rv.allow.update(methods) - return rv - - def ensure_sync(self, func: t.Callable[..., t.Any]) -> t.Callable[..., t.Any]: - """Ensure that the function is synchronous for WSGI workers. - Plain ``def`` functions are returned as-is. ``async def`` - functions are wrapped to run and wait for the response. - - Override this method to change how the app runs async views. - - .. versionadded:: 2.0 - """ - if iscoroutinefunction(func): - return self.async_to_sync(func) - - return func - - def async_to_sync( - self, func: t.Callable[..., t.Coroutine[t.Any, t.Any, t.Any]] - ) -> t.Callable[..., t.Any]: - """Return a sync function that will run the coroutine function. - - .. code-block:: python - - result = app.async_to_sync(func)(*args, **kwargs) - - Override this method to change how the app converts async code - to be synchronously callable. - - .. versionadded:: 2.0 - """ - try: - from asgiref.sync import async_to_sync as asgiref_async_to_sync - except ImportError: - raise RuntimeError( - "Install Flask with the 'async' extra in order to use async views." - ) from None - - return asgiref_async_to_sync(func) - - def url_for( - self, - /, - endpoint: str, - *, - _anchor: str | None = None, - _method: str | None = None, - _scheme: str | None = None, - _external: bool | None = None, - **values: t.Any, - ) -> str: - """Generate a URL to the given endpoint with the given values. - - This is called by :func:`flask.url_for`, and can be called - directly as well. - - An *endpoint* is the name of a URL rule, usually added with - :meth:`@app.route() `, and usually the same name as the - view function. A route defined in a :class:`~flask.Blueprint` - will prepend the blueprint's name separated by a ``.`` to the - endpoint. - - In some cases, such as email messages, you want URLs to include - the scheme and domain, like ``https://example.com/hello``. When - not in an active request, URLs will be external by default, but - this requires setting :data:`SERVER_NAME` so Flask knows what - domain to use. :data:`APPLICATION_ROOT` and - :data:`PREFERRED_URL_SCHEME` should also be configured as - needed. This config is only used when not in an active request. - - Functions can be decorated with :meth:`url_defaults` to modify - keyword arguments before the URL is built. - - If building fails for some reason, such as an unknown endpoint - or incorrect values, the app's :meth:`handle_url_build_error` - method is called. If that returns a string, that is returned, - otherwise a :exc:`~werkzeug.routing.BuildError` is raised. - - :param endpoint: The endpoint name associated with the URL to - generate. If this starts with a ``.``, the current blueprint - name (if any) will be used. - :param _anchor: If given, append this as ``#anchor`` to the URL. - :param _method: If given, generate the URL associated with this - method for the endpoint. - :param _scheme: If given, the URL will have this scheme if it - is external. - :param _external: If given, prefer the URL to be internal - (False) or require it to be external (True). External URLs - include the scheme and domain. When not in an active - request, URLs are external by default. - :param values: Values to use for the variable parts of the URL - rule. Unknown keys are appended as query string arguments, - like ``?a=b&c=d``. - - .. versionadded:: 2.2 - Moved from ``flask.url_for``, which calls this method. - """ - req_ctx = _cv_request.get(None) - - if req_ctx is not None: - url_adapter = req_ctx.url_adapter - blueprint_name = req_ctx.request.blueprint - - # If the endpoint starts with "." and the request matches a - # blueprint, the endpoint is relative to the blueprint. - if endpoint[:1] == ".": - if blueprint_name is not None: - endpoint = f"{blueprint_name}{endpoint}" - else: - endpoint = endpoint[1:] - - # When in a request, generate a URL without scheme and - # domain by default, unless a scheme is given. - if _external is None: - _external = _scheme is not None - else: - app_ctx = _cv_app.get(None) - - # If called by helpers.url_for, an app context is active, - # use its url_adapter. Otherwise, app.url_for was called - # directly, build an adapter. - if app_ctx is not None: - url_adapter = app_ctx.url_adapter - else: - url_adapter = self.create_url_adapter(None) - - if url_adapter is None: - raise RuntimeError( - "Unable to build URLs outside an active request" - " without 'SERVER_NAME' configured. Also configure" - " 'APPLICATION_ROOT' and 'PREFERRED_URL_SCHEME' as" - " needed." - ) - - # When outside a request, generate a URL with scheme and - # domain by default. - if _external is None: - _external = True - - # It is an error to set _scheme when _external=False, in order - # to avoid accidental insecure URLs. - if _scheme is not None and not _external: - raise ValueError("When specifying '_scheme', '_external' must be True.") - - self.inject_url_defaults(endpoint, values) - - try: - rv = url_adapter.build( # type: ignore[union-attr] - endpoint, - values, - method=_method, - url_scheme=_scheme, - force_external=_external, - ) - except BuildError as error: - values.update( - _anchor=_anchor, _method=_method, _scheme=_scheme, _external=_external - ) - return self.handle_url_build_error(error, endpoint, values) - - if _anchor is not None: - _anchor = _url_quote(_anchor, safe="%!#$&'()*+,/:;=?@") - rv = f"{rv}#{_anchor}" - - return rv - - def make_response(self, rv: ft.ResponseReturnValue) -> Response: - """Convert the return value from a view function to an instance of - :attr:`response_class`. - - :param rv: the return value from the view function. The view function - must return a response. Returning ``None``, or the view ending - without returning, is not allowed. The following types are allowed - for ``view_rv``: - - ``str`` - A response object is created with the string encoded to UTF-8 - as the body. - - ``bytes`` - A response object is created with the bytes as the body. - - ``dict`` - A dictionary that will be jsonify'd before being returned. - - ``list`` - A list that will be jsonify'd before being returned. - - ``generator`` or ``iterator`` - A generator that returns ``str`` or ``bytes`` to be - streamed as the response. - - ``tuple`` - Either ``(body, status, headers)``, ``(body, status)``, or - ``(body, headers)``, where ``body`` is any of the other types - allowed here, ``status`` is a string or an integer, and - ``headers`` is a dictionary or a list of ``(key, value)`` - tuples. If ``body`` is a :attr:`response_class` instance, - ``status`` overwrites the exiting value and ``headers`` are - extended. - - :attr:`response_class` - The object is returned unchanged. - - other :class:`~werkzeug.wrappers.Response` class - The object is coerced to :attr:`response_class`. - - :func:`callable` - The function is called as a WSGI application. The result is - used to create a response object. - - .. versionchanged:: 2.2 - A generator will be converted to a streaming response. - A list will be converted to a JSON response. - - .. versionchanged:: 1.1 - A dict will be converted to a JSON response. - - .. versionchanged:: 0.9 - Previously a tuple was interpreted as the arguments for the - response object. - """ - - status: int | None = None - headers: HeadersValue | None = None - - # unpack tuple returns - if isinstance(rv, tuple): - len_rv = len(rv) - - # a 3-tuple is unpacked directly - if len_rv == 3: - rv, status, headers = rv # type: ignore[misc] - # decide if a 2-tuple has status or headers - elif len_rv == 2: - if isinstance(rv[1], (Headers, dict, tuple, list)): - rv, headers = rv # pyright: ignore - else: - rv, status = rv # type: ignore[assignment,misc] - # other sized tuples are not allowed - else: - raise TypeError( - "The view function did not return a valid response tuple." - " The tuple must have the form (body, status, headers)," - " (body, status), or (body, headers)." - ) - - # the body must not be None - if rv is None: - raise TypeError( - f"The view function for {request.endpoint!r} did not" - " return a valid response. The function either returned" - " None or ended without a return statement." - ) - - # make sure the body is an instance of the response class - if not isinstance(rv, self.response_class): - if isinstance(rv, (str, bytes, bytearray)) or isinstance(rv, cabc.Iterator): - # let the response class set the status and headers instead of - # waiting to do it manually, so that the class can handle any - # special logic - rv = self.response_class( - rv, # pyright: ignore - status=status, - headers=headers, # type: ignore[arg-type] - ) - status = headers = None - elif isinstance(rv, (dict, list)): - rv = self.json.response(rv) - elif isinstance(rv, BaseResponse) or callable(rv): - # evaluate a WSGI callable, or coerce a different response - # class to the correct type - try: - rv = self.response_class.force_type( - rv, # type: ignore[arg-type] - request.environ, - ) - except TypeError as e: - raise TypeError( - f"{e}\nThe view function did not return a valid" - " response. The return type must be a string," - " dict, list, tuple with headers or status," - " Response instance, or WSGI callable, but it" - f" was a {type(rv).__name__}." - ).with_traceback(sys.exc_info()[2]) from None - else: - raise TypeError( - "The view function did not return a valid" - " response. The return type must be a string," - " dict, list, tuple with headers or status," - " Response instance, or WSGI callable, but it was a" - f" {type(rv).__name__}." - ) - - rv = t.cast(Response, rv) - # prefer the status if it was provided - if status is not None: - if isinstance(status, (str, bytes, bytearray)): - rv.status = status - else: - rv.status_code = status - - # extend existing headers with provided headers - if headers: - rv.headers.update(headers) - - return rv - - def preprocess_request(self) -> ft.ResponseReturnValue | None: - """Called before the request is dispatched. Calls - :attr:`url_value_preprocessors` registered with the app and the - current blueprint (if any). Then calls :attr:`before_request_funcs` - registered with the app and the blueprint. - - If any :meth:`before_request` handler returns a non-None value, the - value is handled as if it was the return value from the view, and - further request handling is stopped. - """ - names = (None, *reversed(request.blueprints)) - - for name in names: - if name in self.url_value_preprocessors: - for url_func in self.url_value_preprocessors[name]: - url_func(request.endpoint, request.view_args) - - for name in names: - if name in self.before_request_funcs: - for before_func in self.before_request_funcs[name]: - rv = self.ensure_sync(before_func)() - - if rv is not None: - return rv # type: ignore[no-any-return] - - return None - - def process_response(self, response: Response) -> Response: - """Can be overridden in order to modify the response object - before it's sent to the WSGI server. By default this will - call all the :meth:`after_request` decorated functions. - - .. versionchanged:: 0.5 - As of Flask 0.5 the functions registered for after request - execution are called in reverse order of registration. - - :param response: a :attr:`response_class` object. - :return: a new response object or the same, has to be an - instance of :attr:`response_class`. - """ - ctx = request_ctx._get_current_object() # type: ignore[attr-defined] - - for func in ctx._after_request_functions: - response = self.ensure_sync(func)(response) - - for name in chain(request.blueprints, (None,)): - if name in self.after_request_funcs: - for func in reversed(self.after_request_funcs[name]): - response = self.ensure_sync(func)(response) - - if not self.session_interface.is_null_session(ctx._session): - self.session_interface.save_session(self, ctx._session, response) - - return response - - def do_teardown_request( - self, - exc: BaseException | None = _sentinel, # type: ignore[assignment] - ) -> None: - """Called after the request is dispatched and the response is - returned, right before the request context is popped. - - This calls all functions decorated with - :meth:`teardown_request`, and :meth:`Blueprint.teardown_request` - if a blueprint handled the request. Finally, the - :data:`request_tearing_down` signal is sent. - - This is called by - :meth:`RequestContext.pop() `, - which may be delayed during testing to maintain access to - resources. - - :param exc: An unhandled exception raised while dispatching the - request. Detected from the current exception information if - not passed. Passed to each teardown function. - - .. versionchanged:: 0.9 - Added the ``exc`` argument. - """ - if exc is _sentinel: - exc = sys.exc_info()[1] - - for name in chain(request.blueprints, (None,)): - if name in self.teardown_request_funcs: - for func in reversed(self.teardown_request_funcs[name]): - self.ensure_sync(func)(exc) - - request_tearing_down.send(self, _async_wrapper=self.ensure_sync, exc=exc) - - def do_teardown_appcontext( - self, - exc: BaseException | None = _sentinel, # type: ignore[assignment] - ) -> None: - """Called right before the application context is popped. - - When handling a request, the application context is popped - after the request context. See :meth:`do_teardown_request`. - - This calls all functions decorated with - :meth:`teardown_appcontext`. Then the - :data:`appcontext_tearing_down` signal is sent. - - This is called by - :meth:`AppContext.pop() `. - - .. versionadded:: 0.9 - """ - if exc is _sentinel: - exc = sys.exc_info()[1] - - for func in reversed(self.teardown_appcontext_funcs): - self.ensure_sync(func)(exc) - - appcontext_tearing_down.send(self, _async_wrapper=self.ensure_sync, exc=exc) - - def app_context(self) -> AppContext: - """Create an :class:`~flask.ctx.AppContext`. Use as a ``with`` - block to push the context, which will make :data:`current_app` - point at this application. - - An application context is automatically pushed by - :meth:`RequestContext.push() ` - when handling a request, and when running a CLI command. Use - this to manually create a context outside of these situations. - - :: - - with app.app_context(): - init_db() - - See :doc:`/appcontext`. - - .. versionadded:: 0.9 - """ - return AppContext(self) - - def request_context(self, environ: WSGIEnvironment) -> RequestContext: - """Create a :class:`~flask.ctx.RequestContext` representing a - WSGI environment. Use a ``with`` block to push the context, - which will make :data:`request` point at this request. - - See :doc:`/reqcontext`. - - Typically you should not call this from your own code. A request - context is automatically pushed by the :meth:`wsgi_app` when - handling a request. Use :meth:`test_request_context` to create - an environment and context instead of this method. - - :param environ: a WSGI environment - """ - return RequestContext(self, environ) - - def test_request_context(self, *args: t.Any, **kwargs: t.Any) -> RequestContext: - """Create a :class:`~flask.ctx.RequestContext` for a WSGI - environment created from the given values. This is mostly useful - during testing, where you may want to run a function that uses - request data without dispatching a full request. - - See :doc:`/reqcontext`. - - Use a ``with`` block to push the context, which will make - :data:`request` point at the request for the created - environment. :: - - with app.test_request_context(...): - generate_report() - - When using the shell, it may be easier to push and pop the - context manually to avoid indentation. :: - - ctx = app.test_request_context(...) - ctx.push() - ... - ctx.pop() - - Takes the same arguments as Werkzeug's - :class:`~werkzeug.test.EnvironBuilder`, with some defaults from - the application. See the linked Werkzeug docs for most of the - available arguments. Flask-specific behavior is listed here. - - :param path: URL path being requested. - :param base_url: Base URL where the app is being served, which - ``path`` is relative to. If not given, built from - :data:`PREFERRED_URL_SCHEME`, ``subdomain``, - :data:`SERVER_NAME`, and :data:`APPLICATION_ROOT`. - :param subdomain: Subdomain name to append to - :data:`SERVER_NAME`. - :param url_scheme: Scheme to use instead of - :data:`PREFERRED_URL_SCHEME`. - :param data: The request body, either as a string or a dict of - form keys and values. - :param json: If given, this is serialized as JSON and passed as - ``data``. Also defaults ``content_type`` to - ``application/json``. - :param args: other positional arguments passed to - :class:`~werkzeug.test.EnvironBuilder`. - :param kwargs: other keyword arguments passed to - :class:`~werkzeug.test.EnvironBuilder`. - """ - from .testing import EnvironBuilder - - builder = EnvironBuilder(self, *args, **kwargs) - - try: - return self.request_context(builder.get_environ()) - finally: - builder.close() - - def wsgi_app( - self, environ: WSGIEnvironment, start_response: StartResponse - ) -> cabc.Iterable[bytes]: - """The actual WSGI application. This is not implemented in - :meth:`__call__` so that middlewares can be applied without - losing a reference to the app object. Instead of doing this:: - - app = MyMiddleware(app) - - It's a better idea to do this instead:: - - app.wsgi_app = MyMiddleware(app.wsgi_app) - - Then you still have the original application object around and - can continue to call methods on it. - - .. versionchanged:: 0.7 - Teardown events for the request and app contexts are called - even if an unhandled error occurs. Other events may not be - called depending on when an error occurs during dispatch. - See :ref:`callbacks-and-errors`. - - :param environ: A WSGI environment. - :param start_response: A callable accepting a status code, - a list of headers, and an optional exception context to - start the response. - """ - ctx = self.request_context(environ) - error: BaseException | None = None - try: - try: - ctx.push() - response = self.full_dispatch_request() - except Exception as e: - error = e - response = self.handle_exception(e) - except: - error = sys.exc_info()[1] - raise - return response(environ, start_response) - finally: - if "werkzeug.debug.preserve_context" in environ: - environ["werkzeug.debug.preserve_context"](_cv_app.get()) - environ["werkzeug.debug.preserve_context"](_cv_request.get()) - - if error is not None and self.should_ignore_error(error): - error = None - - ctx.pop(error) - - def __call__( - self, environ: WSGIEnvironment, start_response: StartResponse - ) -> cabc.Iterable[bytes]: - """The WSGI server calls the Flask application object as the - WSGI application. This calls :meth:`wsgi_app`, which can be - wrapped to apply middleware. - """ - return self.wsgi_app(environ, start_response) diff --git a/venv/lib/python3.9/site-packages/flask/blueprints.py b/venv/lib/python3.9/site-packages/flask/blueprints.py deleted file mode 100644 index b6d4e43..0000000 --- a/venv/lib/python3.9/site-packages/flask/blueprints.py +++ /dev/null @@ -1,128 +0,0 @@ -from __future__ import annotations - -import os -import typing as t -from datetime import timedelta - -from .cli import AppGroup -from .globals import current_app -from .helpers import send_from_directory -from .sansio.blueprints import Blueprint as SansioBlueprint -from .sansio.blueprints import BlueprintSetupState as BlueprintSetupState # noqa -from .sansio.scaffold import _sentinel - -if t.TYPE_CHECKING: # pragma: no cover - from .wrappers import Response - - -class Blueprint(SansioBlueprint): - def __init__( - self, - name: str, - import_name: str, - static_folder: str | os.PathLike[str] | None = None, - static_url_path: str | None = None, - template_folder: str | os.PathLike[str] | None = None, - url_prefix: str | None = None, - subdomain: str | None = None, - url_defaults: dict[str, t.Any] | None = None, - root_path: str | None = None, - cli_group: str | None = _sentinel, # type: ignore - ) -> None: - super().__init__( - name, - import_name, - static_folder, - static_url_path, - template_folder, - url_prefix, - subdomain, - url_defaults, - root_path, - cli_group, - ) - - #: The Click command group for registering CLI commands for this - #: object. The commands are available from the ``flask`` command - #: once the application has been discovered and blueprints have - #: been registered. - self.cli = AppGroup() - - # Set the name of the Click group in case someone wants to add - # the app's commands to another CLI tool. - self.cli.name = self.name - - def get_send_file_max_age(self, filename: str | None) -> int | None: - """Used by :func:`send_file` to determine the ``max_age`` cache - value for a given file path if it wasn't passed. - - By default, this returns :data:`SEND_FILE_MAX_AGE_DEFAULT` from - the configuration of :data:`~flask.current_app`. This defaults - to ``None``, which tells the browser to use conditional requests - instead of a timed cache, which is usually preferable. - - Note this is a duplicate of the same method in the Flask - class. - - .. versionchanged:: 2.0 - The default configuration is ``None`` instead of 12 hours. - - .. versionadded:: 0.9 - """ - value = current_app.config["SEND_FILE_MAX_AGE_DEFAULT"] - - if value is None: - return None - - if isinstance(value, timedelta): - return int(value.total_seconds()) - - return value # type: ignore[no-any-return] - - def send_static_file(self, filename: str) -> Response: - """The view function used to serve files from - :attr:`static_folder`. A route is automatically registered for - this view at :attr:`static_url_path` if :attr:`static_folder` is - set. - - Note this is a duplicate of the same method in the Flask - class. - - .. versionadded:: 0.5 - - """ - if not self.has_static_folder: - raise RuntimeError("'static_folder' must be set to serve static_files.") - - # send_file only knows to call get_send_file_max_age on the app, - # call it here so it works for blueprints too. - max_age = self.get_send_file_max_age(filename) - return send_from_directory( - t.cast(str, self.static_folder), filename, max_age=max_age - ) - - def open_resource( - self, resource: str, mode: str = "rb", encoding: str | None = "utf-8" - ) -> t.IO[t.AnyStr]: - """Open a resource file relative to :attr:`root_path` for reading. The - blueprint-relative equivalent of the app's :meth:`~.Flask.open_resource` - method. - - :param resource: Path to the resource relative to :attr:`root_path`. - :param mode: Open the file in this mode. Only reading is supported, - valid values are ``"r"`` (or ``"rt"``) and ``"rb"``. - :param encoding: Open the file with this encoding when opening in text - mode. This is ignored when opening in binary mode. - - .. versionchanged:: 3.1 - Added the ``encoding`` parameter. - """ - if mode not in {"r", "rt", "rb"}: - raise ValueError("Resources can only be opened for reading.") - - path = os.path.join(self.root_path, resource) - - if mode == "rb": - return open(path, mode) # pyright: ignore - - return open(path, mode, encoding=encoding) diff --git a/venv/lib/python3.9/site-packages/flask/cli.py b/venv/lib/python3.9/site-packages/flask/cli.py deleted file mode 100644 index ed11f25..0000000 --- a/venv/lib/python3.9/site-packages/flask/cli.py +++ /dev/null @@ -1,1135 +0,0 @@ -from __future__ import annotations - -import ast -import collections.abc as cabc -import importlib.metadata -import inspect -import os -import platform -import re -import sys -import traceback -import typing as t -from functools import update_wrapper -from operator import itemgetter -from types import ModuleType - -import click -from click.core import ParameterSource -from werkzeug import run_simple -from werkzeug.serving import is_running_from_reloader -from werkzeug.utils import import_string - -from .globals import current_app -from .helpers import get_debug_flag -from .helpers import get_load_dotenv - -if t.TYPE_CHECKING: - import ssl - - from _typeshed.wsgi import StartResponse - from _typeshed.wsgi import WSGIApplication - from _typeshed.wsgi import WSGIEnvironment - - from .app import Flask - - -class NoAppException(click.UsageError): - """Raised if an application cannot be found or loaded.""" - - -def find_best_app(module: ModuleType) -> Flask: - """Given a module instance this tries to find the best possible - application in the module or raises an exception. - """ - from . import Flask - - # Search for the most common names first. - for attr_name in ("app", "application"): - app = getattr(module, attr_name, None) - - if isinstance(app, Flask): - return app - - # Otherwise find the only object that is a Flask instance. - matches = [v for v in module.__dict__.values() if isinstance(v, Flask)] - - if len(matches) == 1: - return matches[0] - elif len(matches) > 1: - raise NoAppException( - "Detected multiple Flask applications in module" - f" '{module.__name__}'. Use '{module.__name__}:name'" - " to specify the correct one." - ) - - # Search for app factory functions. - for attr_name in ("create_app", "make_app"): - app_factory = getattr(module, attr_name, None) - - if inspect.isfunction(app_factory): - try: - app = app_factory() - - if isinstance(app, Flask): - return app - except TypeError as e: - if not _called_with_wrong_args(app_factory): - raise - - raise NoAppException( - f"Detected factory '{attr_name}' in module '{module.__name__}'," - " but could not call it without arguments. Use" - f" '{module.__name__}:{attr_name}(args)'" - " to specify arguments." - ) from e - - raise NoAppException( - "Failed to find Flask application or factory in module" - f" '{module.__name__}'. Use '{module.__name__}:name'" - " to specify one." - ) - - -def _called_with_wrong_args(f: t.Callable[..., Flask]) -> bool: - """Check whether calling a function raised a ``TypeError`` because - the call failed or because something in the factory raised the - error. - - :param f: The function that was called. - :return: ``True`` if the call failed. - """ - tb = sys.exc_info()[2] - - try: - while tb is not None: - if tb.tb_frame.f_code is f.__code__: - # In the function, it was called successfully. - return False - - tb = tb.tb_next - - # Didn't reach the function. - return True - finally: - # Delete tb to break a circular reference. - # https://docs.python.org/2/library/sys.html#sys.exc_info - del tb - - -def find_app_by_string(module: ModuleType, app_name: str) -> Flask: - """Check if the given string is a variable name or a function. Call - a function to get the app instance, or return the variable directly. - """ - from . import Flask - - # Parse app_name as a single expression to determine if it's a valid - # attribute name or function call. - try: - expr = ast.parse(app_name.strip(), mode="eval").body - except SyntaxError: - raise NoAppException( - f"Failed to parse {app_name!r} as an attribute name or function call." - ) from None - - if isinstance(expr, ast.Name): - name = expr.id - args = [] - kwargs = {} - elif isinstance(expr, ast.Call): - # Ensure the function name is an attribute name only. - if not isinstance(expr.func, ast.Name): - raise NoAppException( - f"Function reference must be a simple name: {app_name!r}." - ) - - name = expr.func.id - - # Parse the positional and keyword arguments as literals. - try: - args = [ast.literal_eval(arg) for arg in expr.args] - kwargs = { - kw.arg: ast.literal_eval(kw.value) - for kw in expr.keywords - if kw.arg is not None - } - except ValueError: - # literal_eval gives cryptic error messages, show a generic - # message with the full expression instead. - raise NoAppException( - f"Failed to parse arguments as literal values: {app_name!r}." - ) from None - else: - raise NoAppException( - f"Failed to parse {app_name!r} as an attribute name or function call." - ) - - try: - attr = getattr(module, name) - except AttributeError as e: - raise NoAppException( - f"Failed to find attribute {name!r} in {module.__name__!r}." - ) from e - - # If the attribute is a function, call it with any args and kwargs - # to get the real application. - if inspect.isfunction(attr): - try: - app = attr(*args, **kwargs) - except TypeError as e: - if not _called_with_wrong_args(attr): - raise - - raise NoAppException( - f"The factory {app_name!r} in module" - f" {module.__name__!r} could not be called with the" - " specified arguments." - ) from e - else: - app = attr - - if isinstance(app, Flask): - return app - - raise NoAppException( - "A valid Flask application was not obtained from" - f" '{module.__name__}:{app_name}'." - ) - - -def prepare_import(path: str) -> str: - """Given a filename this will try to calculate the python path, add it - to the search path and return the actual module name that is expected. - """ - path = os.path.realpath(path) - - fname, ext = os.path.splitext(path) - if ext == ".py": - path = fname - - if os.path.basename(path) == "__init__": - path = os.path.dirname(path) - - module_name = [] - - # move up until outside package structure (no __init__.py) - while True: - path, name = os.path.split(path) - module_name.append(name) - - if not os.path.exists(os.path.join(path, "__init__.py")): - break - - if sys.path[0] != path: - sys.path.insert(0, path) - - return ".".join(module_name[::-1]) - - -@t.overload -def locate_app( - module_name: str, app_name: str | None, raise_if_not_found: t.Literal[True] = True -) -> Flask: ... - - -@t.overload -def locate_app( - module_name: str, app_name: str | None, raise_if_not_found: t.Literal[False] = ... -) -> Flask | None: ... - - -def locate_app( - module_name: str, app_name: str | None, raise_if_not_found: bool = True -) -> Flask | None: - try: - __import__(module_name) - except ImportError: - # Reraise the ImportError if it occurred within the imported module. - # Determine this by checking whether the trace has a depth > 1. - if sys.exc_info()[2].tb_next: # type: ignore[union-attr] - raise NoAppException( - f"While importing {module_name!r}, an ImportError was" - f" raised:\n\n{traceback.format_exc()}" - ) from None - elif raise_if_not_found: - raise NoAppException(f"Could not import {module_name!r}.") from None - else: - return None - - module = sys.modules[module_name] - - if app_name is None: - return find_best_app(module) - else: - return find_app_by_string(module, app_name) - - -def get_version(ctx: click.Context, param: click.Parameter, value: t.Any) -> None: - if not value or ctx.resilient_parsing: - return - - flask_version = importlib.metadata.version("flask") - werkzeug_version = importlib.metadata.version("werkzeug") - - click.echo( - f"Python {platform.python_version()}\n" - f"Flask {flask_version}\n" - f"Werkzeug {werkzeug_version}", - color=ctx.color, - ) - ctx.exit() - - -version_option = click.Option( - ["--version"], - help="Show the Flask version.", - expose_value=False, - callback=get_version, - is_flag=True, - is_eager=True, -) - - -class ScriptInfo: - """Helper object to deal with Flask applications. This is usually not - necessary to interface with as it's used internally in the dispatching - to click. In future versions of Flask this object will most likely play - a bigger role. Typically it's created automatically by the - :class:`FlaskGroup` but you can also manually create it and pass it - onwards as click object. - - .. versionchanged:: 3.1 - Added the ``load_dotenv_defaults`` parameter and attribute. - """ - - def __init__( - self, - app_import_path: str | None = None, - create_app: t.Callable[..., Flask] | None = None, - set_debug_flag: bool = True, - load_dotenv_defaults: bool = True, - ) -> None: - #: Optionally the import path for the Flask application. - self.app_import_path = app_import_path - #: Optionally a function that is passed the script info to create - #: the instance of the application. - self.create_app = create_app - #: A dictionary with arbitrary data that can be associated with - #: this script info. - self.data: dict[t.Any, t.Any] = {} - self.set_debug_flag = set_debug_flag - - self.load_dotenv_defaults = get_load_dotenv(load_dotenv_defaults) - """Whether default ``.flaskenv`` and ``.env`` files should be loaded. - - ``ScriptInfo`` doesn't load anything, this is for reference when doing - the load elsewhere during processing. - - .. versionadded:: 3.1 - """ - - self._loaded_app: Flask | None = None - - def load_app(self) -> Flask: - """Loads the Flask app (if not yet loaded) and returns it. Calling - this multiple times will just result in the already loaded app to - be returned. - """ - if self._loaded_app is not None: - return self._loaded_app - app: Flask | None = None - if self.create_app is not None: - app = self.create_app() - else: - if self.app_import_path: - path, name = ( - re.split(r":(?![\\/])", self.app_import_path, maxsplit=1) + [None] - )[:2] - import_name = prepare_import(path) - app = locate_app(import_name, name) - else: - for path in ("wsgi.py", "app.py"): - import_name = prepare_import(path) - app = locate_app(import_name, None, raise_if_not_found=False) - - if app is not None: - break - - if app is None: - raise NoAppException( - "Could not locate a Flask application. Use the" - " 'flask --app' option, 'FLASK_APP' environment" - " variable, or a 'wsgi.py' or 'app.py' file in the" - " current directory." - ) - - if self.set_debug_flag: - # Update the app's debug flag through the descriptor so that - # other values repopulate as well. - app.debug = get_debug_flag() - - self._loaded_app = app - return app - - -pass_script_info = click.make_pass_decorator(ScriptInfo, ensure=True) - -F = t.TypeVar("F", bound=t.Callable[..., t.Any]) - - -def with_appcontext(f: F) -> F: - """Wraps a callback so that it's guaranteed to be executed with the - script's application context. - - Custom commands (and their options) registered under ``app.cli`` or - ``blueprint.cli`` will always have an app context available, this - decorator is not required in that case. - - .. versionchanged:: 2.2 - The app context is active for subcommands as well as the - decorated callback. The app context is always available to - ``app.cli`` command and parameter callbacks. - """ - - @click.pass_context - def decorator(ctx: click.Context, /, *args: t.Any, **kwargs: t.Any) -> t.Any: - if not current_app: - app = ctx.ensure_object(ScriptInfo).load_app() - ctx.with_resource(app.app_context()) - - return ctx.invoke(f, *args, **kwargs) - - return update_wrapper(decorator, f) # type: ignore[return-value] - - -class AppGroup(click.Group): - """This works similar to a regular click :class:`~click.Group` but it - changes the behavior of the :meth:`command` decorator so that it - automatically wraps the functions in :func:`with_appcontext`. - - Not to be confused with :class:`FlaskGroup`. - """ - - def command( # type: ignore[override] - self, *args: t.Any, **kwargs: t.Any - ) -> t.Callable[[t.Callable[..., t.Any]], click.Command]: - """This works exactly like the method of the same name on a regular - :class:`click.Group` but it wraps callbacks in :func:`with_appcontext` - unless it's disabled by passing ``with_appcontext=False``. - """ - wrap_for_ctx = kwargs.pop("with_appcontext", True) - - def decorator(f: t.Callable[..., t.Any]) -> click.Command: - if wrap_for_ctx: - f = with_appcontext(f) - return super(AppGroup, self).command(*args, **kwargs)(f) # type: ignore[no-any-return] - - return decorator - - def group( # type: ignore[override] - self, *args: t.Any, **kwargs: t.Any - ) -> t.Callable[[t.Callable[..., t.Any]], click.Group]: - """This works exactly like the method of the same name on a regular - :class:`click.Group` but it defaults the group class to - :class:`AppGroup`. - """ - kwargs.setdefault("cls", AppGroup) - return super().group(*args, **kwargs) # type: ignore[no-any-return] - - -def _set_app(ctx: click.Context, param: click.Option, value: str | None) -> str | None: - if value is None: - return None - - info = ctx.ensure_object(ScriptInfo) - info.app_import_path = value - return value - - -# This option is eager so the app will be available if --help is given. -# --help is also eager, so --app must be before it in the param list. -# no_args_is_help bypasses eager processing, so this option must be -# processed manually in that case to ensure FLASK_APP gets picked up. -_app_option = click.Option( - ["-A", "--app"], - metavar="IMPORT", - help=( - "The Flask application or factory function to load, in the form 'module:name'." - " Module can be a dotted import or file path. Name is not required if it is" - " 'app', 'application', 'create_app', or 'make_app', and can be 'name(args)' to" - " pass arguments." - ), - is_eager=True, - expose_value=False, - callback=_set_app, -) - - -def _set_debug(ctx: click.Context, param: click.Option, value: bool) -> bool | None: - # If the flag isn't provided, it will default to False. Don't use - # that, let debug be set by env in that case. - source = ctx.get_parameter_source(param.name) # type: ignore[arg-type] - - if source is not None and source in ( - ParameterSource.DEFAULT, - ParameterSource.DEFAULT_MAP, - ): - return None - - # Set with env var instead of ScriptInfo.load so that it can be - # accessed early during a factory function. - os.environ["FLASK_DEBUG"] = "1" if value else "0" - return value - - -_debug_option = click.Option( - ["--debug/--no-debug"], - help="Set debug mode.", - expose_value=False, - callback=_set_debug, -) - - -def _env_file_callback( - ctx: click.Context, param: click.Option, value: str | None -) -> str | None: - try: - import dotenv # noqa: F401 - except ImportError: - # Only show an error if a value was passed, otherwise we still want to - # call load_dotenv and show a message without exiting. - if value is not None: - raise click.BadParameter( - "python-dotenv must be installed to load an env file.", - ctx=ctx, - param=param, - ) from None - - # Load if a value was passed, or we want to load default files, or both. - if value is not None or ctx.obj.load_dotenv_defaults: - load_dotenv(value, load_defaults=ctx.obj.load_dotenv_defaults) - - return value - - -# This option is eager so env vars are loaded as early as possible to be -# used by other options. -_env_file_option = click.Option( - ["-e", "--env-file"], - type=click.Path(exists=True, dir_okay=False), - help=( - "Load environment variables from this file, taking precedence over" - " those set by '.env' and '.flaskenv'. Variables set directly in the" - " environment take highest precedence. python-dotenv must be installed." - ), - is_eager=True, - expose_value=False, - callback=_env_file_callback, -) - - -class FlaskGroup(AppGroup): - """Special subclass of the :class:`AppGroup` group that supports - loading more commands from the configured Flask app. Normally a - developer does not have to interface with this class but there are - some very advanced use cases for which it makes sense to create an - instance of this. see :ref:`custom-scripts`. - - :param add_default_commands: if this is True then the default run and - shell commands will be added. - :param add_version_option: adds the ``--version`` option. - :param create_app: an optional callback that is passed the script info and - returns the loaded app. - :param load_dotenv: Load the nearest :file:`.env` and :file:`.flaskenv` - files to set environment variables. Will also change the working - directory to the directory containing the first file found. - :param set_debug_flag: Set the app's debug flag. - - .. versionchanged:: 3.1 - ``-e path`` takes precedence over default ``.env`` and ``.flaskenv`` files. - - .. versionchanged:: 2.2 - Added the ``-A/--app``, ``--debug/--no-debug``, ``-e/--env-file`` options. - - .. versionchanged:: 2.2 - An app context is pushed when running ``app.cli`` commands, so - ``@with_appcontext`` is no longer required for those commands. - - .. versionchanged:: 1.0 - If installed, python-dotenv will be used to load environment variables - from :file:`.env` and :file:`.flaskenv` files. - """ - - def __init__( - self, - add_default_commands: bool = True, - create_app: t.Callable[..., Flask] | None = None, - add_version_option: bool = True, - load_dotenv: bool = True, - set_debug_flag: bool = True, - **extra: t.Any, - ) -> None: - params: list[click.Parameter] = list(extra.pop("params", None) or ()) - # Processing is done with option callbacks instead of a group - # callback. This allows users to make a custom group callback - # without losing the behavior. --env-file must come first so - # that it is eagerly evaluated before --app. - params.extend((_env_file_option, _app_option, _debug_option)) - - if add_version_option: - params.append(version_option) - - if "context_settings" not in extra: - extra["context_settings"] = {} - - extra["context_settings"].setdefault("auto_envvar_prefix", "FLASK") - - super().__init__(params=params, **extra) - - self.create_app = create_app - self.load_dotenv = load_dotenv - self.set_debug_flag = set_debug_flag - - if add_default_commands: - self.add_command(run_command) - self.add_command(shell_command) - self.add_command(routes_command) - - self._loaded_plugin_commands = False - - def _load_plugin_commands(self) -> None: - if self._loaded_plugin_commands: - return - - if sys.version_info >= (3, 10): - from importlib import metadata - else: - # Use a backport on Python < 3.10. We technically have - # importlib.metadata on 3.8+, but the API changed in 3.10, - # so use the backport for consistency. - import importlib_metadata as metadata # pyright: ignore - - for ep in metadata.entry_points(group="flask.commands"): - self.add_command(ep.load(), ep.name) - - self._loaded_plugin_commands = True - - def get_command(self, ctx: click.Context, name: str) -> click.Command | None: - self._load_plugin_commands() - # Look up built-in and plugin commands, which should be - # available even if the app fails to load. - rv = super().get_command(ctx, name) - - if rv is not None: - return rv - - info = ctx.ensure_object(ScriptInfo) - - # Look up commands provided by the app, showing an error and - # continuing if the app couldn't be loaded. - try: - app = info.load_app() - except NoAppException as e: - click.secho(f"Error: {e.format_message()}\n", err=True, fg="red") - return None - - # Push an app context for the loaded app unless it is already - # active somehow. This makes the context available to parameter - # and command callbacks without needing @with_appcontext. - if not current_app or current_app._get_current_object() is not app: # type: ignore[attr-defined] - ctx.with_resource(app.app_context()) - - return app.cli.get_command(ctx, name) - - def list_commands(self, ctx: click.Context) -> list[str]: - self._load_plugin_commands() - # Start with the built-in and plugin commands. - rv = set(super().list_commands(ctx)) - info = ctx.ensure_object(ScriptInfo) - - # Add commands provided by the app, showing an error and - # continuing if the app couldn't be loaded. - try: - rv.update(info.load_app().cli.list_commands(ctx)) - except NoAppException as e: - # When an app couldn't be loaded, show the error message - # without the traceback. - click.secho(f"Error: {e.format_message()}\n", err=True, fg="red") - except Exception: - # When any other errors occurred during loading, show the - # full traceback. - click.secho(f"{traceback.format_exc()}\n", err=True, fg="red") - - return sorted(rv) - - def make_context( - self, - info_name: str | None, - args: list[str], - parent: click.Context | None = None, - **extra: t.Any, - ) -> click.Context: - # Set a flag to tell app.run to become a no-op. If app.run was - # not in a __name__ == __main__ guard, it would start the server - # when importing, blocking whatever command is being called. - os.environ["FLASK_RUN_FROM_CLI"] = "true" - - if "obj" not in extra and "obj" not in self.context_settings: - extra["obj"] = ScriptInfo( - create_app=self.create_app, - set_debug_flag=self.set_debug_flag, - load_dotenv_defaults=self.load_dotenv, - ) - - return super().make_context(info_name, args, parent=parent, **extra) - - def parse_args(self, ctx: click.Context, args: list[str]) -> list[str]: - if (not args and self.no_args_is_help) or ( - len(args) == 1 and args[0] in self.get_help_option_names(ctx) - ): - # Attempt to load --env-file and --app early in case they - # were given as env vars. Otherwise no_args_is_help will not - # see commands from app.cli. - _env_file_option.handle_parse_result(ctx, {}, []) - _app_option.handle_parse_result(ctx, {}, []) - - return super().parse_args(ctx, args) - - -def _path_is_ancestor(path: str, other: str) -> bool: - """Take ``other`` and remove the length of ``path`` from it. Then join it - to ``path``. If it is the original value, ``path`` is an ancestor of - ``other``.""" - return os.path.join(path, other[len(path) :].lstrip(os.sep)) == other - - -def load_dotenv( - path: str | os.PathLike[str] | None = None, load_defaults: bool = True -) -> bool: - """Load "dotenv" files to set environment variables. A given path takes - precedence over ``.env``, which takes precedence over ``.flaskenv``. After - loading and combining these files, values are only set if the key is not - already set in ``os.environ``. - - This is a no-op if `python-dotenv`_ is not installed. - - .. _python-dotenv: https://github.com/theskumar/python-dotenv#readme - - :param path: Load the file at this location. - :param load_defaults: Search for and load the default ``.flaskenv`` and - ``.env`` files. - :return: ``True`` if at least one env var was loaded. - - .. versionchanged:: 3.1 - Added the ``load_defaults`` parameter. A given path takes precedence - over default files. - - .. versionchanged:: 2.0 - The current directory is not changed to the location of the - loaded file. - - .. versionchanged:: 2.0 - When loading the env files, set the default encoding to UTF-8. - - .. versionchanged:: 1.1.0 - Returns ``False`` when python-dotenv is not installed, or when - the given path isn't a file. - - .. versionadded:: 1.0 - """ - try: - import dotenv - except ImportError: - if path or os.path.isfile(".env") or os.path.isfile(".flaskenv"): - click.secho( - " * Tip: There are .env files present. Install python-dotenv" - " to use them.", - fg="yellow", - err=True, - ) - - return False - - data: dict[str, str | None] = {} - - if load_defaults: - for default_name in (".flaskenv", ".env"): - if not (default_path := dotenv.find_dotenv(default_name, usecwd=True)): - continue - - data |= dotenv.dotenv_values(default_path, encoding="utf-8") - - if path is not None and os.path.isfile(path): - data |= dotenv.dotenv_values(path, encoding="utf-8") - - for key, value in data.items(): - if key in os.environ or value is None: - continue - - os.environ[key] = value - - return bool(data) # True if at least one env var was loaded. - - -def show_server_banner(debug: bool, app_import_path: str | None) -> None: - """Show extra startup messages the first time the server is run, - ignoring the reloader. - """ - if is_running_from_reloader(): - return - - if app_import_path is not None: - click.echo(f" * Serving Flask app '{app_import_path}'") - - if debug is not None: - click.echo(f" * Debug mode: {'on' if debug else 'off'}") - - -class CertParamType(click.ParamType): - """Click option type for the ``--cert`` option. Allows either an - existing file, the string ``'adhoc'``, or an import for a - :class:`~ssl.SSLContext` object. - """ - - name = "path" - - def __init__(self) -> None: - self.path_type = click.Path(exists=True, dir_okay=False, resolve_path=True) - - def convert( - self, value: t.Any, param: click.Parameter | None, ctx: click.Context | None - ) -> t.Any: - try: - import ssl - except ImportError: - raise click.BadParameter( - 'Using "--cert" requires Python to be compiled with SSL support.', - ctx, - param, - ) from None - - try: - return self.path_type(value, param, ctx) - except click.BadParameter: - value = click.STRING(value, param, ctx).lower() - - if value == "adhoc": - try: - import cryptography # noqa: F401 - except ImportError: - raise click.BadParameter( - "Using ad-hoc certificates requires the cryptography library.", - ctx, - param, - ) from None - - return value - - obj = import_string(value, silent=True) - - if isinstance(obj, ssl.SSLContext): - return obj - - raise - - -def _validate_key(ctx: click.Context, param: click.Parameter, value: t.Any) -> t.Any: - """The ``--key`` option must be specified when ``--cert`` is a file. - Modifies the ``cert`` param to be a ``(cert, key)`` pair if needed. - """ - cert = ctx.params.get("cert") - is_adhoc = cert == "adhoc" - - try: - import ssl - except ImportError: - is_context = False - else: - is_context = isinstance(cert, ssl.SSLContext) - - if value is not None: - if is_adhoc: - raise click.BadParameter( - 'When "--cert" is "adhoc", "--key" is not used.', ctx, param - ) - - if is_context: - raise click.BadParameter( - 'When "--cert" is an SSLContext object, "--key" is not used.', - ctx, - param, - ) - - if not cert: - raise click.BadParameter('"--cert" must also be specified.', ctx, param) - - ctx.params["cert"] = cert, value - - else: - if cert and not (is_adhoc or is_context): - raise click.BadParameter('Required when using "--cert".', ctx, param) - - return value - - -class SeparatedPathType(click.Path): - """Click option type that accepts a list of values separated by the - OS's path separator (``:``, ``;`` on Windows). Each value is - validated as a :class:`click.Path` type. - """ - - def convert( - self, value: t.Any, param: click.Parameter | None, ctx: click.Context | None - ) -> t.Any: - items = self.split_envvar_value(value) - # can't call no-arg super() inside list comprehension until Python 3.12 - super_convert = super().convert - return [super_convert(item, param, ctx) for item in items] - - -@click.command("run", short_help="Run a development server.") -@click.option("--host", "-h", default="127.0.0.1", help="The interface to bind to.") -@click.option("--port", "-p", default=5000, help="The port to bind to.") -@click.option( - "--cert", - type=CertParamType(), - help="Specify a certificate file to use HTTPS.", - is_eager=True, -) -@click.option( - "--key", - type=click.Path(exists=True, dir_okay=False, resolve_path=True), - callback=_validate_key, - expose_value=False, - help="The key file to use when specifying a certificate.", -) -@click.option( - "--reload/--no-reload", - default=None, - help="Enable or disable the reloader. By default the reloader " - "is active if debug is enabled.", -) -@click.option( - "--debugger/--no-debugger", - default=None, - help="Enable or disable the debugger. By default the debugger " - "is active if debug is enabled.", -) -@click.option( - "--with-threads/--without-threads", - default=True, - help="Enable or disable multithreading.", -) -@click.option( - "--extra-files", - default=None, - type=SeparatedPathType(), - help=( - "Extra files that trigger a reload on change. Multiple paths" - f" are separated by {os.path.pathsep!r}." - ), -) -@click.option( - "--exclude-patterns", - default=None, - type=SeparatedPathType(), - help=( - "Files matching these fnmatch patterns will not trigger a reload" - " on change. Multiple patterns are separated by" - f" {os.path.pathsep!r}." - ), -) -@pass_script_info -def run_command( - info: ScriptInfo, - host: str, - port: int, - reload: bool, - debugger: bool, - with_threads: bool, - cert: ssl.SSLContext | tuple[str, str | None] | t.Literal["adhoc"] | None, - extra_files: list[str] | None, - exclude_patterns: list[str] | None, -) -> None: - """Run a local development server. - - This server is for development purposes only. It does not provide - the stability, security, or performance of production WSGI servers. - - The reloader and debugger are enabled by default with the '--debug' - option. - """ - try: - app: WSGIApplication = info.load_app() # pyright: ignore - except Exception as e: - if is_running_from_reloader(): - # When reloading, print out the error immediately, but raise - # it later so the debugger or server can handle it. - traceback.print_exc() - err = e - - def app( - environ: WSGIEnvironment, start_response: StartResponse - ) -> cabc.Iterable[bytes]: - raise err from None - - else: - # When not reloading, raise the error immediately so the - # command fails. - raise e from None - - debug = get_debug_flag() - - if reload is None: - reload = debug - - if debugger is None: - debugger = debug - - show_server_banner(debug, info.app_import_path) - - run_simple( - host, - port, - app, - use_reloader=reload, - use_debugger=debugger, - threaded=with_threads, - ssl_context=cert, - extra_files=extra_files, - exclude_patterns=exclude_patterns, - ) - - -run_command.params.insert(0, _debug_option) - - -@click.command("shell", short_help="Run a shell in the app context.") -@with_appcontext -def shell_command() -> None: - """Run an interactive Python shell in the context of a given - Flask application. The application will populate the default - namespace of this shell according to its configuration. - - This is useful for executing small snippets of management code - without having to manually configure the application. - """ - import code - - banner = ( - f"Python {sys.version} on {sys.platform}\n" - f"App: {current_app.import_name}\n" - f"Instance: {current_app.instance_path}" - ) - ctx: dict[str, t.Any] = {} - - # Support the regular Python interpreter startup script if someone - # is using it. - startup = os.environ.get("PYTHONSTARTUP") - if startup and os.path.isfile(startup): - with open(startup) as f: - eval(compile(f.read(), startup, "exec"), ctx) - - ctx.update(current_app.make_shell_context()) - - # Site, customize, or startup script can set a hook to call when - # entering interactive mode. The default one sets up readline with - # tab and history completion. - interactive_hook = getattr(sys, "__interactivehook__", None) - - if interactive_hook is not None: - try: - import readline - from rlcompleter import Completer - except ImportError: - pass - else: - # rlcompleter uses __main__.__dict__ by default, which is - # flask.__main__. Use the shell context instead. - readline.set_completer(Completer(ctx).complete) - - interactive_hook() - - code.interact(banner=banner, local=ctx) - - -@click.command("routes", short_help="Show the routes for the app.") -@click.option( - "--sort", - "-s", - type=click.Choice(("endpoint", "methods", "domain", "rule", "match")), - default="endpoint", - help=( - "Method to sort routes by. 'match' is the order that Flask will match routes" - " when dispatching a request." - ), -) -@click.option("--all-methods", is_flag=True, help="Show HEAD and OPTIONS methods.") -@with_appcontext -def routes_command(sort: str, all_methods: bool) -> None: - """Show all registered routes with endpoints and methods.""" - rules = list(current_app.url_map.iter_rules()) - - if not rules: - click.echo("No routes were registered.") - return - - ignored_methods = set() if all_methods else {"HEAD", "OPTIONS"} - host_matching = current_app.url_map.host_matching - has_domain = any(rule.host if host_matching else rule.subdomain for rule in rules) - rows = [] - - for rule in rules: - row = [ - rule.endpoint, - ", ".join(sorted((rule.methods or set()) - ignored_methods)), - ] - - if has_domain: - row.append((rule.host if host_matching else rule.subdomain) or "") - - row.append(rule.rule) - rows.append(row) - - headers = ["Endpoint", "Methods"] - sorts = ["endpoint", "methods"] - - if has_domain: - headers.append("Host" if host_matching else "Subdomain") - sorts.append("domain") - - headers.append("Rule") - sorts.append("rule") - - try: - rows.sort(key=itemgetter(sorts.index(sort))) - except ValueError: - pass - - rows.insert(0, headers) - widths = [max(len(row[i]) for row in rows) for i in range(len(headers))] - rows.insert(1, ["-" * w for w in widths]) - template = " ".join(f"{{{i}:<{w}}}" for i, w in enumerate(widths)) - - for row in rows: - click.echo(template.format(*row)) - - -cli = FlaskGroup( - name="flask", - help="""\ -A general utility script for Flask applications. - -An application to load must be given with the '--app' option, -'FLASK_APP' environment variable, or with a 'wsgi.py' or 'app.py' file -in the current directory. -""", -) - - -def main() -> None: - cli.main() - - -if __name__ == "__main__": - main() diff --git a/venv/lib/python3.9/site-packages/flask/config.py b/venv/lib/python3.9/site-packages/flask/config.py deleted file mode 100644 index 34ef1a5..0000000 --- a/venv/lib/python3.9/site-packages/flask/config.py +++ /dev/null @@ -1,367 +0,0 @@ -from __future__ import annotations - -import errno -import json -import os -import types -import typing as t - -from werkzeug.utils import import_string - -if t.TYPE_CHECKING: - import typing_extensions as te - - from .sansio.app import App - - -T = t.TypeVar("T") - - -class ConfigAttribute(t.Generic[T]): - """Makes an attribute forward to the config""" - - def __init__( - self, name: str, get_converter: t.Callable[[t.Any], T] | None = None - ) -> None: - self.__name__ = name - self.get_converter = get_converter - - @t.overload - def __get__(self, obj: None, owner: None) -> te.Self: ... - - @t.overload - def __get__(self, obj: App, owner: type[App]) -> T: ... - - def __get__(self, obj: App | None, owner: type[App] | None = None) -> T | te.Self: - if obj is None: - return self - - rv = obj.config[self.__name__] - - if self.get_converter is not None: - rv = self.get_converter(rv) - - return rv # type: ignore[no-any-return] - - def __set__(self, obj: App, value: t.Any) -> None: - obj.config[self.__name__] = value - - -class Config(dict): # type: ignore[type-arg] - """Works exactly like a dict but provides ways to fill it from files - or special dictionaries. There are two common patterns to populate the - config. - - Either you can fill the config from a config file:: - - app.config.from_pyfile('yourconfig.cfg') - - Or alternatively you can define the configuration options in the - module that calls :meth:`from_object` or provide an import path to - a module that should be loaded. It is also possible to tell it to - use the same module and with that provide the configuration values - just before the call:: - - DEBUG = True - SECRET_KEY = 'development key' - app.config.from_object(__name__) - - In both cases (loading from any Python file or loading from modules), - only uppercase keys are added to the config. This makes it possible to use - lowercase values in the config file for temporary values that are not added - to the config or to define the config keys in the same file that implements - the application. - - Probably the most interesting way to load configurations is from an - environment variable pointing to a file:: - - app.config.from_envvar('YOURAPPLICATION_SETTINGS') - - In this case before launching the application you have to set this - environment variable to the file you want to use. On Linux and OS X - use the export statement:: - - export YOURAPPLICATION_SETTINGS='/path/to/config/file' - - On windows use `set` instead. - - :param root_path: path to which files are read relative from. When the - config object is created by the application, this is - the application's :attr:`~flask.Flask.root_path`. - :param defaults: an optional dictionary of default values - """ - - def __init__( - self, - root_path: str | os.PathLike[str], - defaults: dict[str, t.Any] | None = None, - ) -> None: - super().__init__(defaults or {}) - self.root_path = root_path - - def from_envvar(self, variable_name: str, silent: bool = False) -> bool: - """Loads a configuration from an environment variable pointing to - a configuration file. This is basically just a shortcut with nicer - error messages for this line of code:: - - app.config.from_pyfile(os.environ['YOURAPPLICATION_SETTINGS']) - - :param variable_name: name of the environment variable - :param silent: set to ``True`` if you want silent failure for missing - files. - :return: ``True`` if the file was loaded successfully. - """ - rv = os.environ.get(variable_name) - if not rv: - if silent: - return False - raise RuntimeError( - f"The environment variable {variable_name!r} is not set" - " and as such configuration could not be loaded. Set" - " this variable and make it point to a configuration" - " file" - ) - return self.from_pyfile(rv, silent=silent) - - def from_prefixed_env( - self, prefix: str = "FLASK", *, loads: t.Callable[[str], t.Any] = json.loads - ) -> bool: - """Load any environment variables that start with ``FLASK_``, - dropping the prefix from the env key for the config key. Values - are passed through a loading function to attempt to convert them - to more specific types than strings. - - Keys are loaded in :func:`sorted` order. - - The default loading function attempts to parse values as any - valid JSON type, including dicts and lists. - - Specific items in nested dicts can be set by separating the - keys with double underscores (``__``). If an intermediate key - doesn't exist, it will be initialized to an empty dict. - - :param prefix: Load env vars that start with this prefix, - separated with an underscore (``_``). - :param loads: Pass each string value to this function and use - the returned value as the config value. If any error is - raised it is ignored and the value remains a string. The - default is :func:`json.loads`. - - .. versionadded:: 2.1 - """ - prefix = f"{prefix}_" - - for key in sorted(os.environ): - if not key.startswith(prefix): - continue - - value = os.environ[key] - key = key.removeprefix(prefix) - - try: - value = loads(value) - except Exception: - # Keep the value as a string if loading failed. - pass - - if "__" not in key: - # A non-nested key, set directly. - self[key] = value - continue - - # Traverse nested dictionaries with keys separated by "__". - current = self - *parts, tail = key.split("__") - - for part in parts: - # If an intermediate dict does not exist, create it. - if part not in current: - current[part] = {} - - current = current[part] - - current[tail] = value - - return True - - def from_pyfile( - self, filename: str | os.PathLike[str], silent: bool = False - ) -> bool: - """Updates the values in the config from a Python file. This function - behaves as if the file was imported as module with the - :meth:`from_object` function. - - :param filename: the filename of the config. This can either be an - absolute filename or a filename relative to the - root path. - :param silent: set to ``True`` if you want silent failure for missing - files. - :return: ``True`` if the file was loaded successfully. - - .. versionadded:: 0.7 - `silent` parameter. - """ - filename = os.path.join(self.root_path, filename) - d = types.ModuleType("config") - d.__file__ = filename - try: - with open(filename, mode="rb") as config_file: - exec(compile(config_file.read(), filename, "exec"), d.__dict__) - except OSError as e: - if silent and e.errno in (errno.ENOENT, errno.EISDIR, errno.ENOTDIR): - return False - e.strerror = f"Unable to load configuration file ({e.strerror})" - raise - self.from_object(d) - return True - - def from_object(self, obj: object | str) -> None: - """Updates the values from the given object. An object can be of one - of the following two types: - - - a string: in this case the object with that name will be imported - - an actual object reference: that object is used directly - - Objects are usually either modules or classes. :meth:`from_object` - loads only the uppercase attributes of the module/class. A ``dict`` - object will not work with :meth:`from_object` because the keys of a - ``dict`` are not attributes of the ``dict`` class. - - Example of module-based configuration:: - - app.config.from_object('yourapplication.default_config') - from yourapplication import default_config - app.config.from_object(default_config) - - Nothing is done to the object before loading. If the object is a - class and has ``@property`` attributes, it needs to be - instantiated before being passed to this method. - - You should not use this function to load the actual configuration but - rather configuration defaults. The actual config should be loaded - with :meth:`from_pyfile` and ideally from a location not within the - package because the package might be installed system wide. - - See :ref:`config-dev-prod` for an example of class-based configuration - using :meth:`from_object`. - - :param obj: an import name or object - """ - if isinstance(obj, str): - obj = import_string(obj) - for key in dir(obj): - if key.isupper(): - self[key] = getattr(obj, key) - - def from_file( - self, - filename: str | os.PathLike[str], - load: t.Callable[[t.IO[t.Any]], t.Mapping[str, t.Any]], - silent: bool = False, - text: bool = True, - ) -> bool: - """Update the values in the config from a file that is loaded - using the ``load`` parameter. The loaded data is passed to the - :meth:`from_mapping` method. - - .. code-block:: python - - import json - app.config.from_file("config.json", load=json.load) - - import tomllib - app.config.from_file("config.toml", load=tomllib.load, text=False) - - :param filename: The path to the data file. This can be an - absolute path or relative to the config root path. - :param load: A callable that takes a file handle and returns a - mapping of loaded data from the file. - :type load: ``Callable[[Reader], Mapping]`` where ``Reader`` - implements a ``read`` method. - :param silent: Ignore the file if it doesn't exist. - :param text: Open the file in text or binary mode. - :return: ``True`` if the file was loaded successfully. - - .. versionchanged:: 2.3 - The ``text`` parameter was added. - - .. versionadded:: 2.0 - """ - filename = os.path.join(self.root_path, filename) - - try: - with open(filename, "r" if text else "rb") as f: - obj = load(f) - except OSError as e: - if silent and e.errno in (errno.ENOENT, errno.EISDIR): - return False - - e.strerror = f"Unable to load configuration file ({e.strerror})" - raise - - return self.from_mapping(obj) - - def from_mapping( - self, mapping: t.Mapping[str, t.Any] | None = None, **kwargs: t.Any - ) -> bool: - """Updates the config like :meth:`update` ignoring items with - non-upper keys. - - :return: Always returns ``True``. - - .. versionadded:: 0.11 - """ - mappings: dict[str, t.Any] = {} - if mapping is not None: - mappings.update(mapping) - mappings.update(kwargs) - for key, value in mappings.items(): - if key.isupper(): - self[key] = value - return True - - def get_namespace( - self, namespace: str, lowercase: bool = True, trim_namespace: bool = True - ) -> dict[str, t.Any]: - """Returns a dictionary containing a subset of configuration options - that match the specified namespace/prefix. Example usage:: - - app.config['IMAGE_STORE_TYPE'] = 'fs' - app.config['IMAGE_STORE_PATH'] = '/var/app/images' - app.config['IMAGE_STORE_BASE_URL'] = 'http://img.website.com' - image_store_config = app.config.get_namespace('IMAGE_STORE_') - - The resulting dictionary `image_store_config` would look like:: - - { - 'type': 'fs', - 'path': '/var/app/images', - 'base_url': 'http://img.website.com' - } - - This is often useful when configuration options map directly to - keyword arguments in functions or class constructors. - - :param namespace: a configuration namespace - :param lowercase: a flag indicating if the keys of the resulting - dictionary should be lowercase - :param trim_namespace: a flag indicating if the keys of the resulting - dictionary should not include the namespace - - .. versionadded:: 0.11 - """ - rv = {} - for k, v in self.items(): - if not k.startswith(namespace): - continue - if trim_namespace: - key = k[len(namespace) :] - else: - key = k - if lowercase: - key = key.lower() - rv[key] = v - return rv - - def __repr__(self) -> str: - return f"<{type(self).__name__} {dict.__repr__(self)}>" diff --git a/venv/lib/python3.9/site-packages/flask/ctx.py b/venv/lib/python3.9/site-packages/flask/ctx.py deleted file mode 100644 index 5f7b1f1..0000000 --- a/venv/lib/python3.9/site-packages/flask/ctx.py +++ /dev/null @@ -1,459 +0,0 @@ -from __future__ import annotations - -import contextvars -import sys -import typing as t -from functools import update_wrapper -from types import TracebackType - -from werkzeug.exceptions import HTTPException - -from . import typing as ft -from .globals import _cv_app -from .globals import _cv_request -from .signals import appcontext_popped -from .signals import appcontext_pushed - -if t.TYPE_CHECKING: # pragma: no cover - from _typeshed.wsgi import WSGIEnvironment - - from .app import Flask - from .sessions import SessionMixin - from .wrappers import Request - - -# a singleton sentinel value for parameter defaults -_sentinel = object() - - -class _AppCtxGlobals: - """A plain object. Used as a namespace for storing data during an - application context. - - Creating an app context automatically creates this object, which is - made available as the :data:`g` proxy. - - .. describe:: 'key' in g - - Check whether an attribute is present. - - .. versionadded:: 0.10 - - .. describe:: iter(g) - - Return an iterator over the attribute names. - - .. versionadded:: 0.10 - """ - - # Define attr methods to let mypy know this is a namespace object - # that has arbitrary attributes. - - def __getattr__(self, name: str) -> t.Any: - try: - return self.__dict__[name] - except KeyError: - raise AttributeError(name) from None - - def __setattr__(self, name: str, value: t.Any) -> None: - self.__dict__[name] = value - - def __delattr__(self, name: str) -> None: - try: - del self.__dict__[name] - except KeyError: - raise AttributeError(name) from None - - def get(self, name: str, default: t.Any | None = None) -> t.Any: - """Get an attribute by name, or a default value. Like - :meth:`dict.get`. - - :param name: Name of attribute to get. - :param default: Value to return if the attribute is not present. - - .. versionadded:: 0.10 - """ - return self.__dict__.get(name, default) - - def pop(self, name: str, default: t.Any = _sentinel) -> t.Any: - """Get and remove an attribute by name. Like :meth:`dict.pop`. - - :param name: Name of attribute to pop. - :param default: Value to return if the attribute is not present, - instead of raising a ``KeyError``. - - .. versionadded:: 0.11 - """ - if default is _sentinel: - return self.__dict__.pop(name) - else: - return self.__dict__.pop(name, default) - - def setdefault(self, name: str, default: t.Any = None) -> t.Any: - """Get the value of an attribute if it is present, otherwise - set and return a default value. Like :meth:`dict.setdefault`. - - :param name: Name of attribute to get. - :param default: Value to set and return if the attribute is not - present. - - .. versionadded:: 0.11 - """ - return self.__dict__.setdefault(name, default) - - def __contains__(self, item: str) -> bool: - return item in self.__dict__ - - def __iter__(self) -> t.Iterator[str]: - return iter(self.__dict__) - - def __repr__(self) -> str: - ctx = _cv_app.get(None) - if ctx is not None: - return f"" - return object.__repr__(self) - - -def after_this_request( - f: ft.AfterRequestCallable[t.Any], -) -> ft.AfterRequestCallable[t.Any]: - """Executes a function after this request. This is useful to modify - response objects. The function is passed the response object and has - to return the same or a new one. - - Example:: - - @app.route('/') - def index(): - @after_this_request - def add_header(response): - response.headers['X-Foo'] = 'Parachute' - return response - return 'Hello World!' - - This is more useful if a function other than the view function wants to - modify a response. For instance think of a decorator that wants to add - some headers without converting the return value into a response object. - - .. versionadded:: 0.9 - """ - ctx = _cv_request.get(None) - - if ctx is None: - raise RuntimeError( - "'after_this_request' can only be used when a request" - " context is active, such as in a view function." - ) - - ctx._after_request_functions.append(f) - return f - - -F = t.TypeVar("F", bound=t.Callable[..., t.Any]) - - -def copy_current_request_context(f: F) -> F: - """A helper function that decorates a function to retain the current - request context. This is useful when working with greenlets. The moment - the function is decorated a copy of the request context is created and - then pushed when the function is called. The current session is also - included in the copied request context. - - Example:: - - import gevent - from flask import copy_current_request_context - - @app.route('/') - def index(): - @copy_current_request_context - def do_some_work(): - # do some work here, it can access flask.request or - # flask.session like you would otherwise in the view function. - ... - gevent.spawn(do_some_work) - return 'Regular response' - - .. versionadded:: 0.10 - """ - ctx = _cv_request.get(None) - - if ctx is None: - raise RuntimeError( - "'copy_current_request_context' can only be used when a" - " request context is active, such as in a view function." - ) - - ctx = ctx.copy() - - def wrapper(*args: t.Any, **kwargs: t.Any) -> t.Any: - with ctx: - return ctx.app.ensure_sync(f)(*args, **kwargs) - - return update_wrapper(wrapper, f) # type: ignore[return-value] - - -def has_request_context() -> bool: - """If you have code that wants to test if a request context is there or - not this function can be used. For instance, you may want to take advantage - of request information if the request object is available, but fail - silently if it is unavailable. - - :: - - class User(db.Model): - - def __init__(self, username, remote_addr=None): - self.username = username - if remote_addr is None and has_request_context(): - remote_addr = request.remote_addr - self.remote_addr = remote_addr - - Alternatively you can also just test any of the context bound objects - (such as :class:`request` or :class:`g`) for truthness:: - - class User(db.Model): - - def __init__(self, username, remote_addr=None): - self.username = username - if remote_addr is None and request: - remote_addr = request.remote_addr - self.remote_addr = remote_addr - - .. versionadded:: 0.7 - """ - return _cv_request.get(None) is not None - - -def has_app_context() -> bool: - """Works like :func:`has_request_context` but for the application - context. You can also just do a boolean check on the - :data:`current_app` object instead. - - .. versionadded:: 0.9 - """ - return _cv_app.get(None) is not None - - -class AppContext: - """The app context contains application-specific information. An app - context is created and pushed at the beginning of each request if - one is not already active. An app context is also pushed when - running CLI commands. - """ - - def __init__(self, app: Flask) -> None: - self.app = app - self.url_adapter = app.create_url_adapter(None) - self.g: _AppCtxGlobals = app.app_ctx_globals_class() - self._cv_tokens: list[contextvars.Token[AppContext]] = [] - - def push(self) -> None: - """Binds the app context to the current context.""" - self._cv_tokens.append(_cv_app.set(self)) - appcontext_pushed.send(self.app, _async_wrapper=self.app.ensure_sync) - - def pop(self, exc: BaseException | None = _sentinel) -> None: # type: ignore - """Pops the app context.""" - try: - if len(self._cv_tokens) == 1: - if exc is _sentinel: - exc = sys.exc_info()[1] - self.app.do_teardown_appcontext(exc) - finally: - ctx = _cv_app.get() - _cv_app.reset(self._cv_tokens.pop()) - - if ctx is not self: - raise AssertionError( - f"Popped wrong app context. ({ctx!r} instead of {self!r})" - ) - - appcontext_popped.send(self.app, _async_wrapper=self.app.ensure_sync) - - def __enter__(self) -> AppContext: - self.push() - return self - - def __exit__( - self, - exc_type: type | None, - exc_value: BaseException | None, - tb: TracebackType | None, - ) -> None: - self.pop(exc_value) - - -class RequestContext: - """The request context contains per-request information. The Flask - app creates and pushes it at the beginning of the request, then pops - it at the end of the request. It will create the URL adapter and - request object for the WSGI environment provided. - - Do not attempt to use this class directly, instead use - :meth:`~flask.Flask.test_request_context` and - :meth:`~flask.Flask.request_context` to create this object. - - When the request context is popped, it will evaluate all the - functions registered on the application for teardown execution - (:meth:`~flask.Flask.teardown_request`). - - The request context is automatically popped at the end of the - request. When using the interactive debugger, the context will be - restored so ``request`` is still accessible. Similarly, the test - client can preserve the context after the request ends. However, - teardown functions may already have closed some resources such as - database connections. - """ - - def __init__( - self, - app: Flask, - environ: WSGIEnvironment, - request: Request | None = None, - session: SessionMixin | None = None, - ) -> None: - self.app = app - if request is None: - request = app.request_class(environ) - request.json_module = app.json - self.request: Request = request - self.url_adapter = None - try: - self.url_adapter = app.create_url_adapter(self.request) - except HTTPException as e: - self.request.routing_exception = e - self.flashes: list[tuple[str, str]] | None = None - self._session: SessionMixin | None = session - # Functions that should be executed after the request on the response - # object. These will be called before the regular "after_request" - # functions. - self._after_request_functions: list[ft.AfterRequestCallable[t.Any]] = [] - - self._cv_tokens: list[ - tuple[contextvars.Token[RequestContext], AppContext | None] - ] = [] - - def copy(self) -> RequestContext: - """Creates a copy of this request context with the same request object. - This can be used to move a request context to a different greenlet. - Because the actual request object is the same this cannot be used to - move a request context to a different thread unless access to the - request object is locked. - - .. versionadded:: 0.10 - - .. versionchanged:: 1.1 - The current session object is used instead of reloading the original - data. This prevents `flask.session` pointing to an out-of-date object. - """ - return self.__class__( - self.app, - environ=self.request.environ, - request=self.request, - session=self._session, - ) - - def match_request(self) -> None: - """Can be overridden by a subclass to hook into the matching - of the request. - """ - try: - result = self.url_adapter.match(return_rule=True) # type: ignore - self.request.url_rule, self.request.view_args = result # type: ignore - except HTTPException as e: - self.request.routing_exception = e - - @property - def session(self) -> SessionMixin: - """The session data associated with this request. Not available until - this context has been pushed. Accessing this property, also accessed by - the :data:`~flask.session` proxy, sets :attr:`.SessionMixin.accessed`. - """ - assert self._session is not None, "The session has not yet been opened." - self._session.accessed = True - return self._session - - def push(self) -> None: - # Before we push the request context we have to ensure that there - # is an application context. - app_ctx = _cv_app.get(None) - - if app_ctx is None or app_ctx.app is not self.app: - app_ctx = self.app.app_context() - app_ctx.push() - else: - app_ctx = None - - self._cv_tokens.append((_cv_request.set(self), app_ctx)) - - # Open the session at the moment that the request context is available. - # This allows a custom open_session method to use the request context. - # Only open a new session if this is the first time the request was - # pushed, otherwise stream_with_context loses the session. - if self._session is None: - session_interface = self.app.session_interface - self._session = session_interface.open_session(self.app, self.request) - - if self._session is None: - self._session = session_interface.make_null_session(self.app) - - # Match the request URL after loading the session, so that the - # session is available in custom URL converters. - if self.url_adapter is not None: - self.match_request() - - def pop(self, exc: BaseException | None = _sentinel) -> None: # type: ignore - """Pops the request context and unbinds it by doing that. This will - also trigger the execution of functions registered by the - :meth:`~flask.Flask.teardown_request` decorator. - - .. versionchanged:: 0.9 - Added the `exc` argument. - """ - clear_request = len(self._cv_tokens) == 1 - - try: - if clear_request: - if exc is _sentinel: - exc = sys.exc_info()[1] - self.app.do_teardown_request(exc) - - request_close = getattr(self.request, "close", None) - if request_close is not None: - request_close() - finally: - ctx = _cv_request.get() - token, app_ctx = self._cv_tokens.pop() - _cv_request.reset(token) - - # get rid of circular dependencies at the end of the request - # so that we don't require the GC to be active. - if clear_request: - ctx.request.environ["werkzeug.request"] = None - - if app_ctx is not None: - app_ctx.pop(exc) - - if ctx is not self: - raise AssertionError( - f"Popped wrong request context. ({ctx!r} instead of {self!r})" - ) - - def __enter__(self) -> RequestContext: - self.push() - return self - - def __exit__( - self, - exc_type: type | None, - exc_value: BaseException | None, - tb: TracebackType | None, - ) -> None: - self.pop(exc_value) - - def __repr__(self) -> str: - return ( - f"<{type(self).__name__} {self.request.url!r}" - f" [{self.request.method}] of {self.app.name}>" - ) diff --git a/venv/lib/python3.9/site-packages/flask/debughelpers.py b/venv/lib/python3.9/site-packages/flask/debughelpers.py deleted file mode 100644 index 2c8c4c4..0000000 --- a/venv/lib/python3.9/site-packages/flask/debughelpers.py +++ /dev/null @@ -1,178 +0,0 @@ -from __future__ import annotations - -import typing as t - -from jinja2.loaders import BaseLoader -from werkzeug.routing import RequestRedirect - -from .blueprints import Blueprint -from .globals import request_ctx -from .sansio.app import App - -if t.TYPE_CHECKING: - from .sansio.scaffold import Scaffold - from .wrappers import Request - - -class UnexpectedUnicodeError(AssertionError, UnicodeError): - """Raised in places where we want some better error reporting for - unexpected unicode or binary data. - """ - - -class DebugFilesKeyError(KeyError, AssertionError): - """Raised from request.files during debugging. The idea is that it can - provide a better error message than just a generic KeyError/BadRequest. - """ - - def __init__(self, request: Request, key: str) -> None: - form_matches = request.form.getlist(key) - buf = [ - f"You tried to access the file {key!r} in the request.files" - " dictionary but it does not exist. The mimetype for the" - f" request is {request.mimetype!r} instead of" - " 'multipart/form-data' which means that no file contents" - " were transmitted. To fix this error you should provide" - ' enctype="multipart/form-data" in your form.' - ] - if form_matches: - names = ", ".join(repr(x) for x in form_matches) - buf.append( - "\n\nThe browser instead transmitted some file names. " - f"This was submitted: {names}" - ) - self.msg = "".join(buf) - - def __str__(self) -> str: - return self.msg - - -class FormDataRoutingRedirect(AssertionError): - """This exception is raised in debug mode if a routing redirect - would cause the browser to drop the method or body. This happens - when method is not GET, HEAD or OPTIONS and the status code is not - 307 or 308. - """ - - def __init__(self, request: Request) -> None: - exc = request.routing_exception - assert isinstance(exc, RequestRedirect) - buf = [ - f"A request was sent to '{request.url}', but routing issued" - f" a redirect to the canonical URL '{exc.new_url}'." - ] - - if f"{request.base_url}/" == exc.new_url.partition("?")[0]: - buf.append( - " The URL was defined with a trailing slash. Flask" - " will redirect to the URL with a trailing slash if it" - " was accessed without one." - ) - - buf.append( - " Send requests to the canonical URL, or use 307 or 308 for" - " routing redirects. Otherwise, browsers will drop form" - " data.\n\n" - "This exception is only raised in debug mode." - ) - super().__init__("".join(buf)) - - -def attach_enctype_error_multidict(request: Request) -> None: - """Patch ``request.files.__getitem__`` to raise a descriptive error - about ``enctype=multipart/form-data``. - - :param request: The request to patch. - :meta private: - """ - oldcls = request.files.__class__ - - class newcls(oldcls): # type: ignore[valid-type, misc] - def __getitem__(self, key: str) -> t.Any: - try: - return super().__getitem__(key) - except KeyError as e: - if key not in request.form: - raise - - raise DebugFilesKeyError(request, key).with_traceback( - e.__traceback__ - ) from None - - newcls.__name__ = oldcls.__name__ - newcls.__module__ = oldcls.__module__ - request.files.__class__ = newcls - - -def _dump_loader_info(loader: BaseLoader) -> t.Iterator[str]: - yield f"class: {type(loader).__module__}.{type(loader).__name__}" - for key, value in sorted(loader.__dict__.items()): - if key.startswith("_"): - continue - if isinstance(value, (tuple, list)): - if not all(isinstance(x, str) for x in value): - continue - yield f"{key}:" - for item in value: - yield f" - {item}" - continue - elif not isinstance(value, (str, int, float, bool)): - continue - yield f"{key}: {value!r}" - - -def explain_template_loading_attempts( - app: App, - template: str, - attempts: list[ - tuple[ - BaseLoader, - Scaffold, - tuple[str, str | None, t.Callable[[], bool] | None] | None, - ] - ], -) -> None: - """This should help developers understand what failed""" - info = [f"Locating template {template!r}:"] - total_found = 0 - blueprint = None - if request_ctx and request_ctx.request.blueprint is not None: - blueprint = request_ctx.request.blueprint - - for idx, (loader, srcobj, triple) in enumerate(attempts): - if isinstance(srcobj, App): - src_info = f"application {srcobj.import_name!r}" - elif isinstance(srcobj, Blueprint): - src_info = f"blueprint {srcobj.name!r} ({srcobj.import_name})" - else: - src_info = repr(srcobj) - - info.append(f"{idx + 1:5}: trying loader of {src_info}") - - for line in _dump_loader_info(loader): - info.append(f" {line}") - - if triple is None: - detail = "no match" - else: - detail = f"found ({triple[1] or ''!r})" - total_found += 1 - info.append(f" -> {detail}") - - seems_fishy = False - if total_found == 0: - info.append("Error: the template could not be found.") - seems_fishy = True - elif total_found > 1: - info.append("Warning: multiple loaders returned a match for the template.") - seems_fishy = True - - if blueprint is not None and seems_fishy: - info.append( - " The template was looked up from an endpoint that belongs" - f" to the blueprint {blueprint!r}." - ) - info.append(" Maybe you did not place a template in the right folder?") - info.append(" See https://flask.palletsprojects.com/blueprints/#templates") - - app.logger.info("\n".join(info)) diff --git a/venv/lib/python3.9/site-packages/flask/globals.py b/venv/lib/python3.9/site-packages/flask/globals.py deleted file mode 100644 index e2c410c..0000000 --- a/venv/lib/python3.9/site-packages/flask/globals.py +++ /dev/null @@ -1,51 +0,0 @@ -from __future__ import annotations - -import typing as t -from contextvars import ContextVar - -from werkzeug.local import LocalProxy - -if t.TYPE_CHECKING: # pragma: no cover - from .app import Flask - from .ctx import _AppCtxGlobals - from .ctx import AppContext - from .ctx import RequestContext - from .sessions import SessionMixin - from .wrappers import Request - - -_no_app_msg = """\ -Working outside of application context. - -This typically means that you attempted to use functionality that needed -the current application. To solve this, set up an application context -with app.app_context(). See the documentation for more information.\ -""" -_cv_app: ContextVar[AppContext] = ContextVar("flask.app_ctx") -app_ctx: AppContext = LocalProxy( # type: ignore[assignment] - _cv_app, unbound_message=_no_app_msg -) -current_app: Flask = LocalProxy( # type: ignore[assignment] - _cv_app, "app", unbound_message=_no_app_msg -) -g: _AppCtxGlobals = LocalProxy( # type: ignore[assignment] - _cv_app, "g", unbound_message=_no_app_msg -) - -_no_req_msg = """\ -Working outside of request context. - -This typically means that you attempted to use functionality that needed -an active HTTP request. Consult the documentation on testing for -information about how to avoid this problem.\ -""" -_cv_request: ContextVar[RequestContext] = ContextVar("flask.request_ctx") -request_ctx: RequestContext = LocalProxy( # type: ignore[assignment] - _cv_request, unbound_message=_no_req_msg -) -request: Request = LocalProxy( # type: ignore[assignment] - _cv_request, "request", unbound_message=_no_req_msg -) -session: SessionMixin = LocalProxy( # type: ignore[assignment] - _cv_request, "session", unbound_message=_no_req_msg -) diff --git a/venv/lib/python3.9/site-packages/flask/helpers.py b/venv/lib/python3.9/site-packages/flask/helpers.py deleted file mode 100644 index 5d412c9..0000000 --- a/venv/lib/python3.9/site-packages/flask/helpers.py +++ /dev/null @@ -1,641 +0,0 @@ -from __future__ import annotations - -import importlib.util -import os -import sys -import typing as t -from datetime import datetime -from functools import cache -from functools import update_wrapper - -import werkzeug.utils -from werkzeug.exceptions import abort as _wz_abort -from werkzeug.utils import redirect as _wz_redirect -from werkzeug.wrappers import Response as BaseResponse - -from .globals import _cv_app -from .globals import _cv_request -from .globals import current_app -from .globals import request -from .globals import request_ctx -from .globals import session -from .signals import message_flashed - -if t.TYPE_CHECKING: # pragma: no cover - from .wrappers import Response - - -def get_debug_flag() -> bool: - """Get whether debug mode should be enabled for the app, indicated by the - :envvar:`FLASK_DEBUG` environment variable. The default is ``False``. - """ - val = os.environ.get("FLASK_DEBUG") - return bool(val and val.lower() not in {"0", "false", "no"}) - - -def get_load_dotenv(default: bool = True) -> bool: - """Get whether the user has disabled loading default dotenv files by - setting :envvar:`FLASK_SKIP_DOTENV`. The default is ``True``, load - the files. - - :param default: What to return if the env var isn't set. - """ - val = os.environ.get("FLASK_SKIP_DOTENV") - - if not val: - return default - - return val.lower() in ("0", "false", "no") - - -@t.overload -def stream_with_context( - generator_or_function: t.Iterator[t.AnyStr], -) -> t.Iterator[t.AnyStr]: ... - - -@t.overload -def stream_with_context( - generator_or_function: t.Callable[..., t.Iterator[t.AnyStr]], -) -> t.Callable[[t.Iterator[t.AnyStr]], t.Iterator[t.AnyStr]]: ... - - -def stream_with_context( - generator_or_function: t.Iterator[t.AnyStr] | t.Callable[..., t.Iterator[t.AnyStr]], -) -> t.Iterator[t.AnyStr] | t.Callable[[t.Iterator[t.AnyStr]], t.Iterator[t.AnyStr]]: - """Wrap a response generator function so that it runs inside the current - request context. This keeps :data:`request`, :data:`session`, and :data:`g` - available, even though at the point the generator runs the request context - will typically have ended. - - Use it as a decorator on a generator function: - - .. code-block:: python - - from flask import stream_with_context, request, Response - - @app.get("/stream") - def streamed_response(): - @stream_with_context - def generate(): - yield "Hello " - yield request.args["name"] - yield "!" - - return Response(generate()) - - Or use it as a wrapper around a created generator: - - .. code-block:: python - - from flask import stream_with_context, request, Response - - @app.get("/stream") - def streamed_response(): - def generate(): - yield "Hello " - yield request.args["name"] - yield "!" - - return Response(stream_with_context(generate())) - - .. versionadded:: 0.9 - """ - try: - gen = iter(generator_or_function) # type: ignore[arg-type] - except TypeError: - - def decorator(*args: t.Any, **kwargs: t.Any) -> t.Any: - gen = generator_or_function(*args, **kwargs) # type: ignore[operator] - return stream_with_context(gen) - - return update_wrapper(decorator, generator_or_function) # type: ignore[arg-type] - - def generator() -> t.Iterator[t.AnyStr]: - if (req_ctx := _cv_request.get(None)) is None: - raise RuntimeError( - "'stream_with_context' can only be used when a request" - " context is active, such as in a view function." - ) - - app_ctx = _cv_app.get() - # Setup code below will run the generator to this point, so that the - # current contexts are recorded. The contexts must be pushed after, - # otherwise their ContextVar will record the wrong event loop during - # async view functions. - yield None # type: ignore[misc] - - # Push the app context first, so that the request context does not - # automatically create and push a different app context. - with app_ctx, req_ctx: - try: - yield from gen - finally: - # Clean up in case the user wrapped a WSGI iterator. - if hasattr(gen, "close"): - gen.close() - - # Execute the generator to the sentinel value. This ensures the context is - # preserved in the generator's state. Further iteration will push the - # context and yield from the original iterator. - wrapped_g = generator() - next(wrapped_g) - return wrapped_g - - -def make_response(*args: t.Any) -> Response: - """Sometimes it is necessary to set additional headers in a view. Because - views do not have to return response objects but can return a value that - is converted into a response object by Flask itself, it becomes tricky to - add headers to it. This function can be called instead of using a return - and you will get a response object which you can use to attach headers. - - If view looked like this and you want to add a new header:: - - def index(): - return render_template('index.html', foo=42) - - You can now do something like this:: - - def index(): - response = make_response(render_template('index.html', foo=42)) - response.headers['X-Parachutes'] = 'parachutes are cool' - return response - - This function accepts the very same arguments you can return from a - view function. This for example creates a response with a 404 error - code:: - - response = make_response(render_template('not_found.html'), 404) - - The other use case of this function is to force the return value of a - view function into a response which is helpful with view - decorators:: - - response = make_response(view_function()) - response.headers['X-Parachutes'] = 'parachutes are cool' - - Internally this function does the following things: - - - if no arguments are passed, it creates a new response argument - - if one argument is passed, :meth:`flask.Flask.make_response` - is invoked with it. - - if more than one argument is passed, the arguments are passed - to the :meth:`flask.Flask.make_response` function as tuple. - - .. versionadded:: 0.6 - """ - if not args: - return current_app.response_class() - if len(args) == 1: - args = args[0] - return current_app.make_response(args) - - -def url_for( - endpoint: str, - *, - _anchor: str | None = None, - _method: str | None = None, - _scheme: str | None = None, - _external: bool | None = None, - **values: t.Any, -) -> str: - """Generate a URL to the given endpoint with the given values. - - This requires an active request or application context, and calls - :meth:`current_app.url_for() `. See that method - for full documentation. - - :param endpoint: The endpoint name associated with the URL to - generate. If this starts with a ``.``, the current blueprint - name (if any) will be used. - :param _anchor: If given, append this as ``#anchor`` to the URL. - :param _method: If given, generate the URL associated with this - method for the endpoint. - :param _scheme: If given, the URL will have this scheme if it is - external. - :param _external: If given, prefer the URL to be internal (False) or - require it to be external (True). External URLs include the - scheme and domain. When not in an active request, URLs are - external by default. - :param values: Values to use for the variable parts of the URL rule. - Unknown keys are appended as query string arguments, like - ``?a=b&c=d``. - - .. versionchanged:: 2.2 - Calls ``current_app.url_for``, allowing an app to override the - behavior. - - .. versionchanged:: 0.10 - The ``_scheme`` parameter was added. - - .. versionchanged:: 0.9 - The ``_anchor`` and ``_method`` parameters were added. - - .. versionchanged:: 0.9 - Calls ``app.handle_url_build_error`` on build errors. - """ - return current_app.url_for( - endpoint, - _anchor=_anchor, - _method=_method, - _scheme=_scheme, - _external=_external, - **values, - ) - - -def redirect( - location: str, code: int = 302, Response: type[BaseResponse] | None = None -) -> BaseResponse: - """Create a redirect response object. - - If :data:`~flask.current_app` is available, it will use its - :meth:`~flask.Flask.redirect` method, otherwise it will use - :func:`werkzeug.utils.redirect`. - - :param location: The URL to redirect to. - :param code: The status code for the redirect. - :param Response: The response class to use. Not used when - ``current_app`` is active, which uses ``app.response_class``. - - .. versionadded:: 2.2 - Calls ``current_app.redirect`` if available instead of always - using Werkzeug's default ``redirect``. - """ - if current_app: - return current_app.redirect(location, code=code) - - return _wz_redirect(location, code=code, Response=Response) - - -def abort(code: int | BaseResponse, *args: t.Any, **kwargs: t.Any) -> t.NoReturn: - """Raise an :exc:`~werkzeug.exceptions.HTTPException` for the given - status code. - - If :data:`~flask.current_app` is available, it will call its - :attr:`~flask.Flask.aborter` object, otherwise it will use - :func:`werkzeug.exceptions.abort`. - - :param code: The status code for the exception, which must be - registered in ``app.aborter``. - :param args: Passed to the exception. - :param kwargs: Passed to the exception. - - .. versionadded:: 2.2 - Calls ``current_app.aborter`` if available instead of always - using Werkzeug's default ``abort``. - """ - if current_app: - current_app.aborter(code, *args, **kwargs) - - _wz_abort(code, *args, **kwargs) - - -def get_template_attribute(template_name: str, attribute: str) -> t.Any: - """Loads a macro (or variable) a template exports. This can be used to - invoke a macro from within Python code. If you for example have a - template named :file:`_cider.html` with the following contents: - - .. sourcecode:: html+jinja - - {% macro hello(name) %}Hello {{ name }}!{% endmacro %} - - You can access this from Python code like this:: - - hello = get_template_attribute('_cider.html', 'hello') - return hello('World') - - .. versionadded:: 0.2 - - :param template_name: the name of the template - :param attribute: the name of the variable of macro to access - """ - return getattr(current_app.jinja_env.get_template(template_name).module, attribute) - - -def flash(message: str, category: str = "message") -> None: - """Flashes a message to the next request. In order to remove the - flashed message from the session and to display it to the user, - the template has to call :func:`get_flashed_messages`. - - .. versionchanged:: 0.3 - `category` parameter added. - - :param message: the message to be flashed. - :param category: the category for the message. The following values - are recommended: ``'message'`` for any kind of message, - ``'error'`` for errors, ``'info'`` for information - messages and ``'warning'`` for warnings. However any - kind of string can be used as category. - """ - # Original implementation: - # - # session.setdefault('_flashes', []).append((category, message)) - # - # This assumed that changes made to mutable structures in the session are - # always in sync with the session object, which is not true for session - # implementations that use external storage for keeping their keys/values. - flashes = session.get("_flashes", []) - flashes.append((category, message)) - session["_flashes"] = flashes - app = current_app._get_current_object() # type: ignore - message_flashed.send( - app, - _async_wrapper=app.ensure_sync, - message=message, - category=category, - ) - - -def get_flashed_messages( - with_categories: bool = False, category_filter: t.Iterable[str] = () -) -> list[str] | list[tuple[str, str]]: - """Pulls all flashed messages from the session and returns them. - Further calls in the same request to the function will return - the same messages. By default just the messages are returned, - but when `with_categories` is set to ``True``, the return value will - be a list of tuples in the form ``(category, message)`` instead. - - Filter the flashed messages to one or more categories by providing those - categories in `category_filter`. This allows rendering categories in - separate html blocks. The `with_categories` and `category_filter` - arguments are distinct: - - * `with_categories` controls whether categories are returned with message - text (``True`` gives a tuple, where ``False`` gives just the message text). - * `category_filter` filters the messages down to only those matching the - provided categories. - - See :doc:`/patterns/flashing` for examples. - - .. versionchanged:: 0.3 - `with_categories` parameter added. - - .. versionchanged:: 0.9 - `category_filter` parameter added. - - :param with_categories: set to ``True`` to also receive categories. - :param category_filter: filter of categories to limit return values. Only - categories in the list will be returned. - """ - flashes = request_ctx.flashes - if flashes is None: - flashes = session.pop("_flashes") if "_flashes" in session else [] - request_ctx.flashes = flashes - if category_filter: - flashes = list(filter(lambda f: f[0] in category_filter, flashes)) - if not with_categories: - return [x[1] for x in flashes] - return flashes - - -def _prepare_send_file_kwargs(**kwargs: t.Any) -> dict[str, t.Any]: - if kwargs.get("max_age") is None: - kwargs["max_age"] = current_app.get_send_file_max_age - - kwargs.update( - environ=request.environ, - use_x_sendfile=current_app.config["USE_X_SENDFILE"], - response_class=current_app.response_class, - _root_path=current_app.root_path, - ) - return kwargs - - -def send_file( - path_or_file: os.PathLike[t.AnyStr] | str | t.IO[bytes], - mimetype: str | None = None, - as_attachment: bool = False, - download_name: str | None = None, - conditional: bool = True, - etag: bool | str = True, - last_modified: datetime | int | float | None = None, - max_age: None | (int | t.Callable[[str | None], int | None]) = None, -) -> Response: - """Send the contents of a file to the client. - - The first argument can be a file path or a file-like object. Paths - are preferred in most cases because Werkzeug can manage the file and - get extra information from the path. Passing a file-like object - requires that the file is opened in binary mode, and is mostly - useful when building a file in memory with :class:`io.BytesIO`. - - Never pass file paths provided by a user. The path is assumed to be - trusted, so a user could craft a path to access a file you didn't - intend. Use :func:`send_from_directory` to safely serve - user-requested paths from within a directory. - - If the WSGI server sets a ``file_wrapper`` in ``environ``, it is - used, otherwise Werkzeug's built-in wrapper is used. Alternatively, - if the HTTP server supports ``X-Sendfile``, configuring Flask with - ``USE_X_SENDFILE = True`` will tell the server to send the given - path, which is much more efficient than reading it in Python. - - :param path_or_file: The path to the file to send, relative to the - current working directory if a relative path is given. - Alternatively, a file-like object opened in binary mode. Make - sure the file pointer is seeked to the start of the data. - :param mimetype: The MIME type to send for the file. If not - provided, it will try to detect it from the file name. - :param as_attachment: Indicate to a browser that it should offer to - save the file instead of displaying it. - :param download_name: The default name browsers will use when saving - the file. Defaults to the passed file name. - :param conditional: Enable conditional and range responses based on - request headers. Requires passing a file path and ``environ``. - :param etag: Calculate an ETag for the file, which requires passing - a file path. Can also be a string to use instead. - :param last_modified: The last modified time to send for the file, - in seconds. If not provided, it will try to detect it from the - file path. - :param max_age: How long the client should cache the file, in - seconds. If set, ``Cache-Control`` will be ``public``, otherwise - it will be ``no-cache`` to prefer conditional caching. - - .. versionchanged:: 2.0 - ``download_name`` replaces the ``attachment_filename`` - parameter. If ``as_attachment=False``, it is passed with - ``Content-Disposition: inline`` instead. - - .. versionchanged:: 2.0 - ``max_age`` replaces the ``cache_timeout`` parameter. - ``conditional`` is enabled and ``max_age`` is not set by - default. - - .. versionchanged:: 2.0 - ``etag`` replaces the ``add_etags`` parameter. It can be a - string to use instead of generating one. - - .. versionchanged:: 2.0 - Passing a file-like object that inherits from - :class:`~io.TextIOBase` will raise a :exc:`ValueError` rather - than sending an empty file. - - .. versionadded:: 2.0 - Moved the implementation to Werkzeug. This is now a wrapper to - pass some Flask-specific arguments. - - .. versionchanged:: 1.1 - ``filename`` may be a :class:`~os.PathLike` object. - - .. versionchanged:: 1.1 - Passing a :class:`~io.BytesIO` object supports range requests. - - .. versionchanged:: 1.0.3 - Filenames are encoded with ASCII instead of Latin-1 for broader - compatibility with WSGI servers. - - .. versionchanged:: 1.0 - UTF-8 filenames as specified in :rfc:`2231` are supported. - - .. versionchanged:: 0.12 - The filename is no longer automatically inferred from file - objects. If you want to use automatic MIME and etag support, - pass a filename via ``filename_or_fp`` or - ``attachment_filename``. - - .. versionchanged:: 0.12 - ``attachment_filename`` is preferred over ``filename`` for MIME - detection. - - .. versionchanged:: 0.9 - ``cache_timeout`` defaults to - :meth:`Flask.get_send_file_max_age`. - - .. versionchanged:: 0.7 - MIME guessing and etag support for file-like objects was - removed because it was unreliable. Pass a filename if you are - able to, otherwise attach an etag yourself. - - .. versionchanged:: 0.5 - The ``add_etags``, ``cache_timeout`` and ``conditional`` - parameters were added. The default behavior is to add etags. - - .. versionadded:: 0.2 - """ - return werkzeug.utils.send_file( # type: ignore[return-value] - **_prepare_send_file_kwargs( - path_or_file=path_or_file, - environ=request.environ, - mimetype=mimetype, - as_attachment=as_attachment, - download_name=download_name, - conditional=conditional, - etag=etag, - last_modified=last_modified, - max_age=max_age, - ) - ) - - -def send_from_directory( - directory: os.PathLike[str] | str, - path: os.PathLike[str] | str, - **kwargs: t.Any, -) -> Response: - """Send a file from within a directory using :func:`send_file`. - - .. code-block:: python - - @app.route("/uploads/") - def download_file(name): - return send_from_directory( - app.config['UPLOAD_FOLDER'], name, as_attachment=True - ) - - This is a secure way to serve files from a folder, such as static - files or uploads. Uses :func:`~werkzeug.security.safe_join` to - ensure the path coming from the client is not maliciously crafted to - point outside the specified directory. - - If the final path does not point to an existing regular file, - raises a 404 :exc:`~werkzeug.exceptions.NotFound` error. - - :param directory: The directory that ``path`` must be located under, - relative to the current application's root path. This *must not* - be a value provided by the client, otherwise it becomes insecure. - :param path: The path to the file to send, relative to - ``directory``. - :param kwargs: Arguments to pass to :func:`send_file`. - - .. versionchanged:: 2.0 - ``path`` replaces the ``filename`` parameter. - - .. versionadded:: 2.0 - Moved the implementation to Werkzeug. This is now a wrapper to - pass some Flask-specific arguments. - - .. versionadded:: 0.5 - """ - return werkzeug.utils.send_from_directory( # type: ignore[return-value] - directory, path, **_prepare_send_file_kwargs(**kwargs) - ) - - -def get_root_path(import_name: str) -> str: - """Find the root path of a package, or the path that contains a - module. If it cannot be found, returns the current working - directory. - - Not to be confused with the value returned by :func:`find_package`. - - :meta private: - """ - # Module already imported and has a file attribute. Use that first. - mod = sys.modules.get(import_name) - - if mod is not None and hasattr(mod, "__file__") and mod.__file__ is not None: - return os.path.dirname(os.path.abspath(mod.__file__)) - - # Next attempt: check the loader. - try: - spec = importlib.util.find_spec(import_name) - - if spec is None: - raise ValueError - except (ImportError, ValueError): - loader = None - else: - loader = spec.loader - - # Loader does not exist or we're referring to an unloaded main - # module or a main module without path (interactive sessions), go - # with the current working directory. - if loader is None: - return os.getcwd() - - if hasattr(loader, "get_filename"): - filepath = loader.get_filename(import_name) # pyright: ignore - else: - # Fall back to imports. - __import__(import_name) - mod = sys.modules[import_name] - filepath = getattr(mod, "__file__", None) - - # If we don't have a file path it might be because it is a - # namespace package. In this case pick the root path from the - # first module that is contained in the package. - if filepath is None: - raise RuntimeError( - "No root path can be found for the provided module" - f" {import_name!r}. This can happen because the module" - " came from an import hook that does not provide file" - " name information or because it's a namespace package." - " In this case the root path needs to be explicitly" - " provided." - ) - - # filepath is import_name.py for a module, or __init__.py for a package. - return os.path.dirname(os.path.abspath(filepath)) # type: ignore[no-any-return] - - -@cache -def _split_blueprint_path(name: str) -> list[str]: - out: list[str] = [name] - - if "." in name: - out.extend(_split_blueprint_path(name.rpartition(".")[0])) - - return out diff --git a/venv/lib/python3.9/site-packages/flask/json/__init__.py b/venv/lib/python3.9/site-packages/flask/json/__init__.py deleted file mode 100644 index c0941d0..0000000 --- a/venv/lib/python3.9/site-packages/flask/json/__init__.py +++ /dev/null @@ -1,170 +0,0 @@ -from __future__ import annotations - -import json as _json -import typing as t - -from ..globals import current_app -from .provider import _default - -if t.TYPE_CHECKING: # pragma: no cover - from ..wrappers import Response - - -def dumps(obj: t.Any, **kwargs: t.Any) -> str: - """Serialize data as JSON. - - If :data:`~flask.current_app` is available, it will use its - :meth:`app.json.dumps() ` - method, otherwise it will use :func:`json.dumps`. - - :param obj: The data to serialize. - :param kwargs: Arguments passed to the ``dumps`` implementation. - - .. versionchanged:: 2.3 - The ``app`` parameter was removed. - - .. versionchanged:: 2.2 - Calls ``current_app.json.dumps``, allowing an app to override - the behavior. - - .. versionchanged:: 2.0.2 - :class:`decimal.Decimal` is supported by converting to a string. - - .. versionchanged:: 2.0 - ``encoding`` will be removed in Flask 2.1. - - .. versionchanged:: 1.0.3 - ``app`` can be passed directly, rather than requiring an app - context for configuration. - """ - if current_app: - return current_app.json.dumps(obj, **kwargs) - - kwargs.setdefault("default", _default) - return _json.dumps(obj, **kwargs) - - -def dump(obj: t.Any, fp: t.IO[str], **kwargs: t.Any) -> None: - """Serialize data as JSON and write to a file. - - If :data:`~flask.current_app` is available, it will use its - :meth:`app.json.dump() ` - method, otherwise it will use :func:`json.dump`. - - :param obj: The data to serialize. - :param fp: A file opened for writing text. Should use the UTF-8 - encoding to be valid JSON. - :param kwargs: Arguments passed to the ``dump`` implementation. - - .. versionchanged:: 2.3 - The ``app`` parameter was removed. - - .. versionchanged:: 2.2 - Calls ``current_app.json.dump``, allowing an app to override - the behavior. - - .. versionchanged:: 2.0 - Writing to a binary file, and the ``encoding`` argument, will be - removed in Flask 2.1. - """ - if current_app: - current_app.json.dump(obj, fp, **kwargs) - else: - kwargs.setdefault("default", _default) - _json.dump(obj, fp, **kwargs) - - -def loads(s: str | bytes, **kwargs: t.Any) -> t.Any: - """Deserialize data as JSON. - - If :data:`~flask.current_app` is available, it will use its - :meth:`app.json.loads() ` - method, otherwise it will use :func:`json.loads`. - - :param s: Text or UTF-8 bytes. - :param kwargs: Arguments passed to the ``loads`` implementation. - - .. versionchanged:: 2.3 - The ``app`` parameter was removed. - - .. versionchanged:: 2.2 - Calls ``current_app.json.loads``, allowing an app to override - the behavior. - - .. versionchanged:: 2.0 - ``encoding`` will be removed in Flask 2.1. The data must be a - string or UTF-8 bytes. - - .. versionchanged:: 1.0.3 - ``app`` can be passed directly, rather than requiring an app - context for configuration. - """ - if current_app: - return current_app.json.loads(s, **kwargs) - - return _json.loads(s, **kwargs) - - -def load(fp: t.IO[t.AnyStr], **kwargs: t.Any) -> t.Any: - """Deserialize data as JSON read from a file. - - If :data:`~flask.current_app` is available, it will use its - :meth:`app.json.load() ` - method, otherwise it will use :func:`json.load`. - - :param fp: A file opened for reading text or UTF-8 bytes. - :param kwargs: Arguments passed to the ``load`` implementation. - - .. versionchanged:: 2.3 - The ``app`` parameter was removed. - - .. versionchanged:: 2.2 - Calls ``current_app.json.load``, allowing an app to override - the behavior. - - .. versionchanged:: 2.2 - The ``app`` parameter will be removed in Flask 2.3. - - .. versionchanged:: 2.0 - ``encoding`` will be removed in Flask 2.1. The file must be text - mode, or binary mode with UTF-8 bytes. - """ - if current_app: - return current_app.json.load(fp, **kwargs) - - return _json.load(fp, **kwargs) - - -def jsonify(*args: t.Any, **kwargs: t.Any) -> Response: - """Serialize the given arguments as JSON, and return a - :class:`~flask.Response` object with the ``application/json`` - mimetype. A dict or list returned from a view will be converted to a - JSON response automatically without needing to call this. - - This requires an active request or application context, and calls - :meth:`app.json.response() `. - - In debug mode, the output is formatted with indentation to make it - easier to read. This may also be controlled by the provider. - - Either positional or keyword arguments can be given, not both. - If no arguments are given, ``None`` is serialized. - - :param args: A single value to serialize, or multiple values to - treat as a list to serialize. - :param kwargs: Treat as a dict to serialize. - - .. versionchanged:: 2.2 - Calls ``current_app.json.response``, allowing an app to override - the behavior. - - .. versionchanged:: 2.0.2 - :class:`decimal.Decimal` is supported by converting to a string. - - .. versionchanged:: 0.11 - Added support for serializing top-level arrays. This was a - security risk in ancient browsers. See :ref:`security-json`. - - .. versionadded:: 0.2 - """ - return current_app.json.response(*args, **kwargs) # type: ignore[return-value] diff --git a/venv/lib/python3.9/site-packages/flask/json/provider.py b/venv/lib/python3.9/site-packages/flask/json/provider.py deleted file mode 100644 index ea7e475..0000000 --- a/venv/lib/python3.9/site-packages/flask/json/provider.py +++ /dev/null @@ -1,215 +0,0 @@ -from __future__ import annotations - -import dataclasses -import decimal -import json -import typing as t -import uuid -import weakref -from datetime import date - -from werkzeug.http import http_date - -if t.TYPE_CHECKING: # pragma: no cover - from werkzeug.sansio.response import Response - - from ..sansio.app import App - - -class JSONProvider: - """A standard set of JSON operations for an application. Subclasses - of this can be used to customize JSON behavior or use different - JSON libraries. - - To implement a provider for a specific library, subclass this base - class and implement at least :meth:`dumps` and :meth:`loads`. All - other methods have default implementations. - - To use a different provider, either subclass ``Flask`` and set - :attr:`~flask.Flask.json_provider_class` to a provider class, or set - :attr:`app.json ` to an instance of the class. - - :param app: An application instance. This will be stored as a - :class:`weakref.proxy` on the :attr:`_app` attribute. - - .. versionadded:: 2.2 - """ - - def __init__(self, app: App) -> None: - self._app: App = weakref.proxy(app) - - def dumps(self, obj: t.Any, **kwargs: t.Any) -> str: - """Serialize data as JSON. - - :param obj: The data to serialize. - :param kwargs: May be passed to the underlying JSON library. - """ - raise NotImplementedError - - def dump(self, obj: t.Any, fp: t.IO[str], **kwargs: t.Any) -> None: - """Serialize data as JSON and write to a file. - - :param obj: The data to serialize. - :param fp: A file opened for writing text. Should use the UTF-8 - encoding to be valid JSON. - :param kwargs: May be passed to the underlying JSON library. - """ - fp.write(self.dumps(obj, **kwargs)) - - def loads(self, s: str | bytes, **kwargs: t.Any) -> t.Any: - """Deserialize data as JSON. - - :param s: Text or UTF-8 bytes. - :param kwargs: May be passed to the underlying JSON library. - """ - raise NotImplementedError - - def load(self, fp: t.IO[t.AnyStr], **kwargs: t.Any) -> t.Any: - """Deserialize data as JSON read from a file. - - :param fp: A file opened for reading text or UTF-8 bytes. - :param kwargs: May be passed to the underlying JSON library. - """ - return self.loads(fp.read(), **kwargs) - - def _prepare_response_obj( - self, args: tuple[t.Any, ...], kwargs: dict[str, t.Any] - ) -> t.Any: - if args and kwargs: - raise TypeError("app.json.response() takes either args or kwargs, not both") - - if not args and not kwargs: - return None - - if len(args) == 1: - return args[0] - - return args or kwargs - - def response(self, *args: t.Any, **kwargs: t.Any) -> Response: - """Serialize the given arguments as JSON, and return a - :class:`~flask.Response` object with the ``application/json`` - mimetype. - - The :func:`~flask.json.jsonify` function calls this method for - the current application. - - Either positional or keyword arguments can be given, not both. - If no arguments are given, ``None`` is serialized. - - :param args: A single value to serialize, or multiple values to - treat as a list to serialize. - :param kwargs: Treat as a dict to serialize. - """ - obj = self._prepare_response_obj(args, kwargs) - return self._app.response_class(self.dumps(obj), mimetype="application/json") - - -def _default(o: t.Any) -> t.Any: - if isinstance(o, date): - return http_date(o) - - if isinstance(o, (decimal.Decimal, uuid.UUID)): - return str(o) - - if dataclasses and dataclasses.is_dataclass(o): - return dataclasses.asdict(o) # type: ignore[arg-type] - - if hasattr(o, "__html__"): - return str(o.__html__()) - - raise TypeError(f"Object of type {type(o).__name__} is not JSON serializable") - - -class DefaultJSONProvider(JSONProvider): - """Provide JSON operations using Python's built-in :mod:`json` - library. Serializes the following additional data types: - - - :class:`datetime.datetime` and :class:`datetime.date` are - serialized to :rfc:`822` strings. This is the same as the HTTP - date format. - - :class:`uuid.UUID` is serialized to a string. - - :class:`dataclasses.dataclass` is passed to - :func:`dataclasses.asdict`. - - :class:`~markupsafe.Markup` (or any object with a ``__html__`` - method) will call the ``__html__`` method to get a string. - """ - - default: t.Callable[[t.Any], t.Any] = staticmethod(_default) # type: ignore[assignment] - """Apply this function to any object that :meth:`json.dumps` does - not know how to serialize. It should return a valid JSON type or - raise a ``TypeError``. - """ - - ensure_ascii = True - """Replace non-ASCII characters with escape sequences. This may be - more compatible with some clients, but can be disabled for better - performance and size. - """ - - sort_keys = True - """Sort the keys in any serialized dicts. This may be useful for - some caching situations, but can be disabled for better performance. - When enabled, keys must all be strings, they are not converted - before sorting. - """ - - compact: bool | None = None - """If ``True``, or ``None`` out of debug mode, the :meth:`response` - output will not add indentation, newlines, or spaces. If ``False``, - or ``None`` in debug mode, it will use a non-compact representation. - """ - - mimetype = "application/json" - """The mimetype set in :meth:`response`.""" - - def dumps(self, obj: t.Any, **kwargs: t.Any) -> str: - """Serialize data as JSON to a string. - - Keyword arguments are passed to :func:`json.dumps`. Sets some - parameter defaults from the :attr:`default`, - :attr:`ensure_ascii`, and :attr:`sort_keys` attributes. - - :param obj: The data to serialize. - :param kwargs: Passed to :func:`json.dumps`. - """ - kwargs.setdefault("default", self.default) - kwargs.setdefault("ensure_ascii", self.ensure_ascii) - kwargs.setdefault("sort_keys", self.sort_keys) - return json.dumps(obj, **kwargs) - - def loads(self, s: str | bytes, **kwargs: t.Any) -> t.Any: - """Deserialize data as JSON from a string or bytes. - - :param s: Text or UTF-8 bytes. - :param kwargs: Passed to :func:`json.loads`. - """ - return json.loads(s, **kwargs) - - def response(self, *args: t.Any, **kwargs: t.Any) -> Response: - """Serialize the given arguments as JSON, and return a - :class:`~flask.Response` object with it. The response mimetype - will be "application/json" and can be changed with - :attr:`mimetype`. - - If :attr:`compact` is ``False`` or debug mode is enabled, the - output will be formatted to be easier to read. - - Either positional or keyword arguments can be given, not both. - If no arguments are given, ``None`` is serialized. - - :param args: A single value to serialize, or multiple values to - treat as a list to serialize. - :param kwargs: Treat as a dict to serialize. - """ - obj = self._prepare_response_obj(args, kwargs) - dump_args: dict[str, t.Any] = {} - - if (self.compact is None and self._app.debug) or self.compact is False: - dump_args.setdefault("indent", 2) - else: - dump_args.setdefault("separators", (",", ":")) - - return self._app.response_class( - f"{self.dumps(obj, **dump_args)}\n", mimetype=self.mimetype - ) diff --git a/venv/lib/python3.9/site-packages/flask/json/tag.py b/venv/lib/python3.9/site-packages/flask/json/tag.py deleted file mode 100644 index 8dc3629..0000000 --- a/venv/lib/python3.9/site-packages/flask/json/tag.py +++ /dev/null @@ -1,327 +0,0 @@ -""" -Tagged JSON -~~~~~~~~~~~ - -A compact representation for lossless serialization of non-standard JSON -types. :class:`~flask.sessions.SecureCookieSessionInterface` uses this -to serialize the session data, but it may be useful in other places. It -can be extended to support other types. - -.. autoclass:: TaggedJSONSerializer - :members: - -.. autoclass:: JSONTag - :members: - -Let's see an example that adds support for -:class:`~collections.OrderedDict`. Dicts don't have an order in JSON, so -to handle this we will dump the items as a list of ``[key, value]`` -pairs. Subclass :class:`JSONTag` and give it the new key ``' od'`` to -identify the type. The session serializer processes dicts first, so -insert the new tag at the front of the order since ``OrderedDict`` must -be processed before ``dict``. - -.. code-block:: python - - from flask.json.tag import JSONTag - - class TagOrderedDict(JSONTag): - __slots__ = ('serializer',) - key = ' od' - - def check(self, value): - return isinstance(value, OrderedDict) - - def to_json(self, value): - return [[k, self.serializer.tag(v)] for k, v in iteritems(value)] - - def to_python(self, value): - return OrderedDict(value) - - app.session_interface.serializer.register(TagOrderedDict, index=0) -""" - -from __future__ import annotations - -import typing as t -from base64 import b64decode -from base64 import b64encode -from datetime import datetime -from uuid import UUID - -from markupsafe import Markup -from werkzeug.http import http_date -from werkzeug.http import parse_date - -from ..json import dumps -from ..json import loads - - -class JSONTag: - """Base class for defining type tags for :class:`TaggedJSONSerializer`.""" - - __slots__ = ("serializer",) - - #: The tag to mark the serialized object with. If empty, this tag is - #: only used as an intermediate step during tagging. - key: str = "" - - def __init__(self, serializer: TaggedJSONSerializer) -> None: - """Create a tagger for the given serializer.""" - self.serializer = serializer - - def check(self, value: t.Any) -> bool: - """Check if the given value should be tagged by this tag.""" - raise NotImplementedError - - def to_json(self, value: t.Any) -> t.Any: - """Convert the Python object to an object that is a valid JSON type. - The tag will be added later.""" - raise NotImplementedError - - def to_python(self, value: t.Any) -> t.Any: - """Convert the JSON representation back to the correct type. The tag - will already be removed.""" - raise NotImplementedError - - def tag(self, value: t.Any) -> dict[str, t.Any]: - """Convert the value to a valid JSON type and add the tag structure - around it.""" - return {self.key: self.to_json(value)} - - -class TagDict(JSONTag): - """Tag for 1-item dicts whose only key matches a registered tag. - - Internally, the dict key is suffixed with `__`, and the suffix is removed - when deserializing. - """ - - __slots__ = () - key = " di" - - def check(self, value: t.Any) -> bool: - return ( - isinstance(value, dict) - and len(value) == 1 - and next(iter(value)) in self.serializer.tags - ) - - def to_json(self, value: t.Any) -> t.Any: - key = next(iter(value)) - return {f"{key}__": self.serializer.tag(value[key])} - - def to_python(self, value: t.Any) -> t.Any: - key = next(iter(value)) - return {key[:-2]: value[key]} - - -class PassDict(JSONTag): - __slots__ = () - - def check(self, value: t.Any) -> bool: - return isinstance(value, dict) - - def to_json(self, value: t.Any) -> t.Any: - # JSON objects may only have string keys, so don't bother tagging the - # key here. - return {k: self.serializer.tag(v) for k, v in value.items()} - - tag = to_json - - -class TagTuple(JSONTag): - __slots__ = () - key = " t" - - def check(self, value: t.Any) -> bool: - return isinstance(value, tuple) - - def to_json(self, value: t.Any) -> t.Any: - return [self.serializer.tag(item) for item in value] - - def to_python(self, value: t.Any) -> t.Any: - return tuple(value) - - -class PassList(JSONTag): - __slots__ = () - - def check(self, value: t.Any) -> bool: - return isinstance(value, list) - - def to_json(self, value: t.Any) -> t.Any: - return [self.serializer.tag(item) for item in value] - - tag = to_json - - -class TagBytes(JSONTag): - __slots__ = () - key = " b" - - def check(self, value: t.Any) -> bool: - return isinstance(value, bytes) - - def to_json(self, value: t.Any) -> t.Any: - return b64encode(value).decode("ascii") - - def to_python(self, value: t.Any) -> t.Any: - return b64decode(value) - - -class TagMarkup(JSONTag): - """Serialize anything matching the :class:`~markupsafe.Markup` API by - having a ``__html__`` method to the result of that method. Always - deserializes to an instance of :class:`~markupsafe.Markup`.""" - - __slots__ = () - key = " m" - - def check(self, value: t.Any) -> bool: - return callable(getattr(value, "__html__", None)) - - def to_json(self, value: t.Any) -> t.Any: - return str(value.__html__()) - - def to_python(self, value: t.Any) -> t.Any: - return Markup(value) - - -class TagUUID(JSONTag): - __slots__ = () - key = " u" - - def check(self, value: t.Any) -> bool: - return isinstance(value, UUID) - - def to_json(self, value: t.Any) -> t.Any: - return value.hex - - def to_python(self, value: t.Any) -> t.Any: - return UUID(value) - - -class TagDateTime(JSONTag): - __slots__ = () - key = " d" - - def check(self, value: t.Any) -> bool: - return isinstance(value, datetime) - - def to_json(self, value: t.Any) -> t.Any: - return http_date(value) - - def to_python(self, value: t.Any) -> t.Any: - return parse_date(value) - - -class TaggedJSONSerializer: - """Serializer that uses a tag system to compactly represent objects that - are not JSON types. Passed as the intermediate serializer to - :class:`itsdangerous.Serializer`. - - The following extra types are supported: - - * :class:`dict` - * :class:`tuple` - * :class:`bytes` - * :class:`~markupsafe.Markup` - * :class:`~uuid.UUID` - * :class:`~datetime.datetime` - """ - - __slots__ = ("tags", "order") - - #: Tag classes to bind when creating the serializer. Other tags can be - #: added later using :meth:`~register`. - default_tags = [ - TagDict, - PassDict, - TagTuple, - PassList, - TagBytes, - TagMarkup, - TagUUID, - TagDateTime, - ] - - def __init__(self) -> None: - self.tags: dict[str, JSONTag] = {} - self.order: list[JSONTag] = [] - - for cls in self.default_tags: - self.register(cls) - - def register( - self, - tag_class: type[JSONTag], - force: bool = False, - index: int | None = None, - ) -> None: - """Register a new tag with this serializer. - - :param tag_class: tag class to register. Will be instantiated with this - serializer instance. - :param force: overwrite an existing tag. If false (default), a - :exc:`KeyError` is raised. - :param index: index to insert the new tag in the tag order. Useful when - the new tag is a special case of an existing tag. If ``None`` - (default), the tag is appended to the end of the order. - - :raise KeyError: if the tag key is already registered and ``force`` is - not true. - """ - tag = tag_class(self) - key = tag.key - - if key: - if not force and key in self.tags: - raise KeyError(f"Tag '{key}' is already registered.") - - self.tags[key] = tag - - if index is None: - self.order.append(tag) - else: - self.order.insert(index, tag) - - def tag(self, value: t.Any) -> t.Any: - """Convert a value to a tagged representation if necessary.""" - for tag in self.order: - if tag.check(value): - return tag.tag(value) - - return value - - def untag(self, value: dict[str, t.Any]) -> t.Any: - """Convert a tagged representation back to the original type.""" - if len(value) != 1: - return value - - key = next(iter(value)) - - if key not in self.tags: - return value - - return self.tags[key].to_python(value[key]) - - def _untag_scan(self, value: t.Any) -> t.Any: - if isinstance(value, dict): - # untag each item recursively - value = {k: self._untag_scan(v) for k, v in value.items()} - # untag the dict itself - value = self.untag(value) - elif isinstance(value, list): - # untag each item recursively - value = [self._untag_scan(item) for item in value] - - return value - - def dumps(self, value: t.Any) -> str: - """Tag the value and dump it to a compact JSON string.""" - return dumps(self.tag(value), separators=(",", ":")) - - def loads(self, value: str) -> t.Any: - """Load data from a JSON string and deserialized any tagged objects.""" - return self._untag_scan(loads(value)) diff --git a/venv/lib/python3.9/site-packages/flask/logging.py b/venv/lib/python3.9/site-packages/flask/logging.py deleted file mode 100644 index 0cb8f43..0000000 --- a/venv/lib/python3.9/site-packages/flask/logging.py +++ /dev/null @@ -1,79 +0,0 @@ -from __future__ import annotations - -import logging -import sys -import typing as t - -from werkzeug.local import LocalProxy - -from .globals import request - -if t.TYPE_CHECKING: # pragma: no cover - from .sansio.app import App - - -@LocalProxy -def wsgi_errors_stream() -> t.TextIO: - """Find the most appropriate error stream for the application. If a request - is active, log to ``wsgi.errors``, otherwise use ``sys.stderr``. - - If you configure your own :class:`logging.StreamHandler`, you may want to - use this for the stream. If you are using file or dict configuration and - can't import this directly, you can refer to it as - ``ext://flask.logging.wsgi_errors_stream``. - """ - if request: - return request.environ["wsgi.errors"] # type: ignore[no-any-return] - - return sys.stderr - - -def has_level_handler(logger: logging.Logger) -> bool: - """Check if there is a handler in the logging chain that will handle the - given logger's :meth:`effective level <~logging.Logger.getEffectiveLevel>`. - """ - level = logger.getEffectiveLevel() - current = logger - - while current: - if any(handler.level <= level for handler in current.handlers): - return True - - if not current.propagate: - break - - current = current.parent # type: ignore - - return False - - -#: Log messages to :func:`~flask.logging.wsgi_errors_stream` with the format -#: ``[%(asctime)s] %(levelname)s in %(module)s: %(message)s``. -default_handler = logging.StreamHandler(wsgi_errors_stream) # type: ignore -default_handler.setFormatter( - logging.Formatter("[%(asctime)s] %(levelname)s in %(module)s: %(message)s") -) - - -def create_logger(app: App) -> logging.Logger: - """Get the Flask app's logger and configure it if needed. - - The logger name will be the same as - :attr:`app.import_name `. - - When :attr:`~flask.Flask.debug` is enabled, set the logger level to - :data:`logging.DEBUG` if it is not set. - - If there is no handler for the logger's effective level, add a - :class:`~logging.StreamHandler` for - :func:`~flask.logging.wsgi_errors_stream` with a basic format. - """ - logger = logging.getLogger(app.name) - - if app.debug and not logger.level: - logger.setLevel(logging.DEBUG) - - if not has_level_handler(logger): - logger.addHandler(default_handler) - - return logger diff --git a/venv/lib/python3.9/site-packages/flask/py.typed b/venv/lib/python3.9/site-packages/flask/py.typed deleted file mode 100644 index e69de29..0000000 diff --git a/venv/lib/python3.9/site-packages/flask/sansio/README.md b/venv/lib/python3.9/site-packages/flask/sansio/README.md deleted file mode 100644 index 623ac19..0000000 --- a/venv/lib/python3.9/site-packages/flask/sansio/README.md +++ /dev/null @@ -1,6 +0,0 @@ -# Sansio - -This folder contains code that can be used by alternative Flask -implementations, for example Quart. The code therefore cannot do any -IO, nor be part of a likely IO path. Finally this code cannot use the -Flask globals. diff --git a/venv/lib/python3.9/site-packages/flask/sansio/app.py b/venv/lib/python3.9/site-packages/flask/sansio/app.py deleted file mode 100644 index 58cb873..0000000 --- a/venv/lib/python3.9/site-packages/flask/sansio/app.py +++ /dev/null @@ -1,964 +0,0 @@ -from __future__ import annotations - -import logging -import os -import sys -import typing as t -from datetime import timedelta -from itertools import chain - -from werkzeug.exceptions import Aborter -from werkzeug.exceptions import BadRequest -from werkzeug.exceptions import BadRequestKeyError -from werkzeug.routing import BuildError -from werkzeug.routing import Map -from werkzeug.routing import Rule -from werkzeug.sansio.response import Response -from werkzeug.utils import cached_property -from werkzeug.utils import redirect as _wz_redirect - -from .. import typing as ft -from ..config import Config -from ..config import ConfigAttribute -from ..ctx import _AppCtxGlobals -from ..helpers import _split_blueprint_path -from ..helpers import get_debug_flag -from ..json.provider import DefaultJSONProvider -from ..json.provider import JSONProvider -from ..logging import create_logger -from ..templating import DispatchingJinjaLoader -from ..templating import Environment -from .scaffold import _endpoint_from_view_func -from .scaffold import find_package -from .scaffold import Scaffold -from .scaffold import setupmethod - -if t.TYPE_CHECKING: # pragma: no cover - from werkzeug.wrappers import Response as BaseResponse - - from ..testing import FlaskClient - from ..testing import FlaskCliRunner - from .blueprints import Blueprint - -T_shell_context_processor = t.TypeVar( - "T_shell_context_processor", bound=ft.ShellContextProcessorCallable -) -T_teardown = t.TypeVar("T_teardown", bound=ft.TeardownCallable) -T_template_filter = t.TypeVar("T_template_filter", bound=ft.TemplateFilterCallable) -T_template_global = t.TypeVar("T_template_global", bound=ft.TemplateGlobalCallable) -T_template_test = t.TypeVar("T_template_test", bound=ft.TemplateTestCallable) - - -def _make_timedelta(value: timedelta | int | None) -> timedelta | None: - if value is None or isinstance(value, timedelta): - return value - - return timedelta(seconds=value) - - -class App(Scaffold): - """The flask object implements a WSGI application and acts as the central - object. It is passed the name of the module or package of the - application. Once it is created it will act as a central registry for - the view functions, the URL rules, template configuration and much more. - - The name of the package is used to resolve resources from inside the - package or the folder the module is contained in depending on if the - package parameter resolves to an actual python package (a folder with - an :file:`__init__.py` file inside) or a standard module (just a ``.py`` file). - - For more information about resource loading, see :func:`open_resource`. - - Usually you create a :class:`Flask` instance in your main module or - in the :file:`__init__.py` file of your package like this:: - - from flask import Flask - app = Flask(__name__) - - .. admonition:: About the First Parameter - - The idea of the first parameter is to give Flask an idea of what - belongs to your application. This name is used to find resources - on the filesystem, can be used by extensions to improve debugging - information and a lot more. - - So it's important what you provide there. If you are using a single - module, `__name__` is always the correct value. If you however are - using a package, it's usually recommended to hardcode the name of - your package there. - - For example if your application is defined in :file:`yourapplication/app.py` - you should create it with one of the two versions below:: - - app = Flask('yourapplication') - app = Flask(__name__.split('.')[0]) - - Why is that? The application will work even with `__name__`, thanks - to how resources are looked up. However it will make debugging more - painful. Certain extensions can make assumptions based on the - import name of your application. For example the Flask-SQLAlchemy - extension will look for the code in your application that triggered - an SQL query in debug mode. If the import name is not properly set - up, that debugging information is lost. (For example it would only - pick up SQL queries in `yourapplication.app` and not - `yourapplication.views.frontend`) - - .. versionadded:: 0.7 - The `static_url_path`, `static_folder`, and `template_folder` - parameters were added. - - .. versionadded:: 0.8 - The `instance_path` and `instance_relative_config` parameters were - added. - - .. versionadded:: 0.11 - The `root_path` parameter was added. - - .. versionadded:: 1.0 - The ``host_matching`` and ``static_host`` parameters were added. - - .. versionadded:: 1.0 - The ``subdomain_matching`` parameter was added. Subdomain - matching needs to be enabled manually now. Setting - :data:`SERVER_NAME` does not implicitly enable it. - - :param import_name: the name of the application package - :param static_url_path: can be used to specify a different path for the - static files on the web. Defaults to the name - of the `static_folder` folder. - :param static_folder: The folder with static files that is served at - ``static_url_path``. Relative to the application ``root_path`` - or an absolute path. Defaults to ``'static'``. - :param static_host: the host to use when adding the static route. - Defaults to None. Required when using ``host_matching=True`` - with a ``static_folder`` configured. - :param host_matching: set ``url_map.host_matching`` attribute. - Defaults to False. - :param subdomain_matching: consider the subdomain relative to - :data:`SERVER_NAME` when matching routes. Defaults to False. - :param template_folder: the folder that contains the templates that should - be used by the application. Defaults to - ``'templates'`` folder in the root path of the - application. - :param instance_path: An alternative instance path for the application. - By default the folder ``'instance'`` next to the - package or module is assumed to be the instance - path. - :param instance_relative_config: if set to ``True`` relative filenames - for loading the config are assumed to - be relative to the instance path instead - of the application root. - :param root_path: The path to the root of the application files. - This should only be set manually when it can't be detected - automatically, such as for namespace packages. - """ - - #: The class of the object assigned to :attr:`aborter`, created by - #: :meth:`create_aborter`. That object is called by - #: :func:`flask.abort` to raise HTTP errors, and can be - #: called directly as well. - #: - #: Defaults to :class:`werkzeug.exceptions.Aborter`. - #: - #: .. versionadded:: 2.2 - aborter_class = Aborter - - #: The class that is used for the Jinja environment. - #: - #: .. versionadded:: 0.11 - jinja_environment = Environment - - #: The class that is used for the :data:`~flask.g` instance. - #: - #: Example use cases for a custom class: - #: - #: 1. Store arbitrary attributes on flask.g. - #: 2. Add a property for lazy per-request database connectors. - #: 3. Return None instead of AttributeError on unexpected attributes. - #: 4. Raise exception if an unexpected attr is set, a "controlled" flask.g. - #: - #: In Flask 0.9 this property was called `request_globals_class` but it - #: was changed in 0.10 to :attr:`app_ctx_globals_class` because the - #: flask.g object is now application context scoped. - #: - #: .. versionadded:: 0.10 - app_ctx_globals_class = _AppCtxGlobals - - #: The class that is used for the ``config`` attribute of this app. - #: Defaults to :class:`~flask.Config`. - #: - #: Example use cases for a custom class: - #: - #: 1. Default values for certain config options. - #: 2. Access to config values through attributes in addition to keys. - #: - #: .. versionadded:: 0.11 - config_class = Config - - #: The testing flag. Set this to ``True`` to enable the test mode of - #: Flask extensions (and in the future probably also Flask itself). - #: For example this might activate test helpers that have an - #: additional runtime cost which should not be enabled by default. - #: - #: If this is enabled and PROPAGATE_EXCEPTIONS is not changed from the - #: default it's implicitly enabled. - #: - #: This attribute can also be configured from the config with the - #: ``TESTING`` configuration key. Defaults to ``False``. - testing = ConfigAttribute[bool]("TESTING") - - #: If a secret key is set, cryptographic components can use this to - #: sign cookies and other things. Set this to a complex random value - #: when you want to use the secure cookie for instance. - #: - #: This attribute can also be configured from the config with the - #: :data:`SECRET_KEY` configuration key. Defaults to ``None``. - secret_key = ConfigAttribute[t.Union[str, bytes, None]]("SECRET_KEY") - - #: A :class:`~datetime.timedelta` which is used to set the expiration - #: date of a permanent session. The default is 31 days which makes a - #: permanent session survive for roughly one month. - #: - #: This attribute can also be configured from the config with the - #: ``PERMANENT_SESSION_LIFETIME`` configuration key. Defaults to - #: ``timedelta(days=31)`` - permanent_session_lifetime = ConfigAttribute[timedelta]( - "PERMANENT_SESSION_LIFETIME", - get_converter=_make_timedelta, # type: ignore[arg-type] - ) - - json_provider_class: type[JSONProvider] = DefaultJSONProvider - """A subclass of :class:`~flask.json.provider.JSONProvider`. An - instance is created and assigned to :attr:`app.json` when creating - the app. - - The default, :class:`~flask.json.provider.DefaultJSONProvider`, uses - Python's built-in :mod:`json` library. A different provider can use - a different JSON library. - - .. versionadded:: 2.2 - """ - - #: Options that are passed to the Jinja environment in - #: :meth:`create_jinja_environment`. Changing these options after - #: the environment is created (accessing :attr:`jinja_env`) will - #: have no effect. - #: - #: .. versionchanged:: 1.1.0 - #: This is a ``dict`` instead of an ``ImmutableDict`` to allow - #: easier configuration. - #: - jinja_options: dict[str, t.Any] = {} - - #: The rule object to use for URL rules created. This is used by - #: :meth:`add_url_rule`. Defaults to :class:`werkzeug.routing.Rule`. - #: - #: .. versionadded:: 0.7 - url_rule_class = Rule - - #: The map object to use for storing the URL rules and routing - #: configuration parameters. Defaults to :class:`werkzeug.routing.Map`. - #: - #: .. versionadded:: 1.1.0 - url_map_class = Map - - #: The :meth:`test_client` method creates an instance of this test - #: client class. Defaults to :class:`~flask.testing.FlaskClient`. - #: - #: .. versionadded:: 0.7 - test_client_class: type[FlaskClient] | None = None - - #: The :class:`~click.testing.CliRunner` subclass, by default - #: :class:`~flask.testing.FlaskCliRunner` that is used by - #: :meth:`test_cli_runner`. Its ``__init__`` method should take a - #: Flask app object as the first argument. - #: - #: .. versionadded:: 1.0 - test_cli_runner_class: type[FlaskCliRunner] | None = None - - default_config: dict[str, t.Any] - response_class: type[Response] - - def __init__( - self, - import_name: str, - static_url_path: str | None = None, - static_folder: str | os.PathLike[str] | None = "static", - static_host: str | None = None, - host_matching: bool = False, - subdomain_matching: bool = False, - template_folder: str | os.PathLike[str] | None = "templates", - instance_path: str | None = None, - instance_relative_config: bool = False, - root_path: str | None = None, - ) -> None: - super().__init__( - import_name=import_name, - static_folder=static_folder, - static_url_path=static_url_path, - template_folder=template_folder, - root_path=root_path, - ) - - if instance_path is None: - instance_path = self.auto_find_instance_path() - elif not os.path.isabs(instance_path): - raise ValueError( - "If an instance path is provided it must be absolute." - " A relative path was given instead." - ) - - #: Holds the path to the instance folder. - #: - #: .. versionadded:: 0.8 - self.instance_path = instance_path - - #: The configuration dictionary as :class:`Config`. This behaves - #: exactly like a regular dictionary but supports additional methods - #: to load a config from files. - self.config = self.make_config(instance_relative_config) - - #: An instance of :attr:`aborter_class` created by - #: :meth:`make_aborter`. This is called by :func:`flask.abort` - #: to raise HTTP errors, and can be called directly as well. - #: - #: .. versionadded:: 2.2 - #: Moved from ``flask.abort``, which calls this object. - self.aborter = self.make_aborter() - - self.json: JSONProvider = self.json_provider_class(self) - """Provides access to JSON methods. Functions in ``flask.json`` - will call methods on this provider when the application context - is active. Used for handling JSON requests and responses. - - An instance of :attr:`json_provider_class`. Can be customized by - changing that attribute on a subclass, or by assigning to this - attribute afterwards. - - The default, :class:`~flask.json.provider.DefaultJSONProvider`, - uses Python's built-in :mod:`json` library. A different provider - can use a different JSON library. - - .. versionadded:: 2.2 - """ - - #: A list of functions that are called by - #: :meth:`handle_url_build_error` when :meth:`.url_for` raises a - #: :exc:`~werkzeug.routing.BuildError`. Each function is called - #: with ``error``, ``endpoint`` and ``values``. If a function - #: returns ``None`` or raises a ``BuildError``, it is skipped. - #: Otherwise, its return value is returned by ``url_for``. - #: - #: .. versionadded:: 0.9 - self.url_build_error_handlers: list[ - t.Callable[[Exception, str, dict[str, t.Any]], str] - ] = [] - - #: A list of functions that are called when the application context - #: is destroyed. Since the application context is also torn down - #: if the request ends this is the place to store code that disconnects - #: from databases. - #: - #: .. versionadded:: 0.9 - self.teardown_appcontext_funcs: list[ft.TeardownCallable] = [] - - #: A list of shell context processor functions that should be run - #: when a shell context is created. - #: - #: .. versionadded:: 0.11 - self.shell_context_processors: list[ft.ShellContextProcessorCallable] = [] - - #: Maps registered blueprint names to blueprint objects. The - #: dict retains the order the blueprints were registered in. - #: Blueprints can be registered multiple times, this dict does - #: not track how often they were attached. - #: - #: .. versionadded:: 0.7 - self.blueprints: dict[str, Blueprint] = {} - - #: a place where extensions can store application specific state. For - #: example this is where an extension could store database engines and - #: similar things. - #: - #: The key must match the name of the extension module. For example in - #: case of a "Flask-Foo" extension in `flask_foo`, the key would be - #: ``'foo'``. - #: - #: .. versionadded:: 0.7 - self.extensions: dict[str, t.Any] = {} - - #: The :class:`~werkzeug.routing.Map` for this instance. You can use - #: this to change the routing converters after the class was created - #: but before any routes are connected. Example:: - #: - #: from werkzeug.routing import BaseConverter - #: - #: class ListConverter(BaseConverter): - #: def to_python(self, value): - #: return value.split(',') - #: def to_url(self, values): - #: return ','.join(super(ListConverter, self).to_url(value) - #: for value in values) - #: - #: app = Flask(__name__) - #: app.url_map.converters['list'] = ListConverter - self.url_map = self.url_map_class(host_matching=host_matching) - - self.subdomain_matching = subdomain_matching - - # tracks internally if the application already handled at least one - # request. - self._got_first_request = False - - def _check_setup_finished(self, f_name: str) -> None: - if self._got_first_request: - raise AssertionError( - f"The setup method '{f_name}' can no longer be called" - " on the application. It has already handled its first" - " request, any changes will not be applied" - " consistently.\n" - "Make sure all imports, decorators, functions, etc." - " needed to set up the application are done before" - " running it." - ) - - @cached_property - def name(self) -> str: - """The name of the application. This is usually the import name - with the difference that it's guessed from the run file if the - import name is main. This name is used as a display name when - Flask needs the name of the application. It can be set and overridden - to change the value. - - .. versionadded:: 0.8 - """ - if self.import_name == "__main__": - fn: str | None = getattr(sys.modules["__main__"], "__file__", None) - if fn is None: - return "__main__" - return os.path.splitext(os.path.basename(fn))[0] - return self.import_name - - @cached_property - def logger(self) -> logging.Logger: - """A standard Python :class:`~logging.Logger` for the app, with - the same name as :attr:`name`. - - In debug mode, the logger's :attr:`~logging.Logger.level` will - be set to :data:`~logging.DEBUG`. - - If there are no handlers configured, a default handler will be - added. See :doc:`/logging` for more information. - - .. versionchanged:: 1.1.0 - The logger takes the same name as :attr:`name` rather than - hard-coding ``"flask.app"``. - - .. versionchanged:: 1.0.0 - Behavior was simplified. The logger is always named - ``"flask.app"``. The level is only set during configuration, - it doesn't check ``app.debug`` each time. Only one format is - used, not different ones depending on ``app.debug``. No - handlers are removed, and a handler is only added if no - handlers are already configured. - - .. versionadded:: 0.3 - """ - return create_logger(self) - - @cached_property - def jinja_env(self) -> Environment: - """The Jinja environment used to load templates. - - The environment is created the first time this property is - accessed. Changing :attr:`jinja_options` after that will have no - effect. - """ - return self.create_jinja_environment() - - def create_jinja_environment(self) -> Environment: - raise NotImplementedError() - - def make_config(self, instance_relative: bool = False) -> Config: - """Used to create the config attribute by the Flask constructor. - The `instance_relative` parameter is passed in from the constructor - of Flask (there named `instance_relative_config`) and indicates if - the config should be relative to the instance path or the root path - of the application. - - .. versionadded:: 0.8 - """ - root_path = self.root_path - if instance_relative: - root_path = self.instance_path - defaults = dict(self.default_config) - defaults["DEBUG"] = get_debug_flag() - return self.config_class(root_path, defaults) - - def make_aborter(self) -> Aborter: - """Create the object to assign to :attr:`aborter`. That object - is called by :func:`flask.abort` to raise HTTP errors, and can - be called directly as well. - - By default, this creates an instance of :attr:`aborter_class`, - which defaults to :class:`werkzeug.exceptions.Aborter`. - - .. versionadded:: 2.2 - """ - return self.aborter_class() - - def auto_find_instance_path(self) -> str: - """Tries to locate the instance path if it was not provided to the - constructor of the application class. It will basically calculate - the path to a folder named ``instance`` next to your main file or - the package. - - .. versionadded:: 0.8 - """ - prefix, package_path = find_package(self.import_name) - if prefix is None: - return os.path.join(package_path, "instance") - return os.path.join(prefix, "var", f"{self.name}-instance") - - def create_global_jinja_loader(self) -> DispatchingJinjaLoader: - """Creates the loader for the Jinja environment. Can be used to - override just the loader and keeping the rest unchanged. It's - discouraged to override this function. Instead one should override - the :meth:`jinja_loader` function instead. - - The global loader dispatches between the loaders of the application - and the individual blueprints. - - .. versionadded:: 0.7 - """ - return DispatchingJinjaLoader(self) - - def select_jinja_autoescape(self, filename: str | None) -> bool: - """Returns ``True`` if autoescaping should be active for the given - template name. If no template name is given, returns `True`. - - .. versionchanged:: 2.2 - Autoescaping is now enabled by default for ``.svg`` files. - - .. versionadded:: 0.5 - """ - if filename is None: - return True - return filename.endswith((".html", ".htm", ".xml", ".xhtml", ".svg")) - - @property - def debug(self) -> bool: - """Whether debug mode is enabled. When using ``flask run`` to start the - development server, an interactive debugger will be shown for unhandled - exceptions, and the server will be reloaded when code changes. This maps to the - :data:`DEBUG` config key. It may not behave as expected if set late. - - **Do not enable debug mode when deploying in production.** - - Default: ``False`` - """ - return self.config["DEBUG"] # type: ignore[no-any-return] - - @debug.setter - def debug(self, value: bool) -> None: - self.config["DEBUG"] = value - - if self.config["TEMPLATES_AUTO_RELOAD"] is None: - self.jinja_env.auto_reload = value - - @setupmethod - def register_blueprint(self, blueprint: Blueprint, **options: t.Any) -> None: - """Register a :class:`~flask.Blueprint` on the application. Keyword - arguments passed to this method will override the defaults set on the - blueprint. - - Calls the blueprint's :meth:`~flask.Blueprint.register` method after - recording the blueprint in the application's :attr:`blueprints`. - - :param blueprint: The blueprint to register. - :param url_prefix: Blueprint routes will be prefixed with this. - :param subdomain: Blueprint routes will match on this subdomain. - :param url_defaults: Blueprint routes will use these default values for - view arguments. - :param options: Additional keyword arguments are passed to - :class:`~flask.blueprints.BlueprintSetupState`. They can be - accessed in :meth:`~flask.Blueprint.record` callbacks. - - .. versionchanged:: 2.0.1 - The ``name`` option can be used to change the (pre-dotted) - name the blueprint is registered with. This allows the same - blueprint to be registered multiple times with unique names - for ``url_for``. - - .. versionadded:: 0.7 - """ - blueprint.register(self, options) - - def iter_blueprints(self) -> t.ValuesView[Blueprint]: - """Iterates over all blueprints by the order they were registered. - - .. versionadded:: 0.11 - """ - return self.blueprints.values() - - @setupmethod - def add_url_rule( - self, - rule: str, - endpoint: str | None = None, - view_func: ft.RouteCallable | None = None, - provide_automatic_options: bool | None = None, - **options: t.Any, - ) -> None: - if endpoint is None: - endpoint = _endpoint_from_view_func(view_func) # type: ignore - options["endpoint"] = endpoint - methods = options.pop("methods", None) - - # if the methods are not given and the view_func object knows its - # methods we can use that instead. If neither exists, we go with - # a tuple of only ``GET`` as default. - if methods is None: - methods = getattr(view_func, "methods", None) or ("GET",) - if isinstance(methods, str): - raise TypeError( - "Allowed methods must be a list of strings, for" - ' example: @app.route(..., methods=["POST"])' - ) - methods = {item.upper() for item in methods} - - # Methods that should always be added - required_methods: set[str] = set(getattr(view_func, "required_methods", ())) - - # starting with Flask 0.8 the view_func object can disable and - # force-enable the automatic options handling. - if provide_automatic_options is None: - provide_automatic_options = getattr( - view_func, "provide_automatic_options", None - ) - - if provide_automatic_options is None: - if "OPTIONS" not in methods and self.config["PROVIDE_AUTOMATIC_OPTIONS"]: - provide_automatic_options = True - required_methods.add("OPTIONS") - else: - provide_automatic_options = False - - # Add the required methods now. - methods |= required_methods - - rule_obj = self.url_rule_class(rule, methods=methods, **options) - rule_obj.provide_automatic_options = provide_automatic_options # type: ignore[attr-defined] - - self.url_map.add(rule_obj) - if view_func is not None: - old_func = self.view_functions.get(endpoint) - if old_func is not None and old_func != view_func: - raise AssertionError( - "View function mapping is overwriting an existing" - f" endpoint function: {endpoint}" - ) - self.view_functions[endpoint] = view_func - - @setupmethod - def template_filter( - self, name: str | None = None - ) -> t.Callable[[T_template_filter], T_template_filter]: - """A decorator that is used to register custom template filter. - You can specify a name for the filter, otherwise the function - name will be used. Example:: - - @app.template_filter() - def reverse(s): - return s[::-1] - - :param name: the optional name of the filter, otherwise the - function name will be used. - """ - - def decorator(f: T_template_filter) -> T_template_filter: - self.add_template_filter(f, name=name) - return f - - return decorator - - @setupmethod - def add_template_filter( - self, f: ft.TemplateFilterCallable, name: str | None = None - ) -> None: - """Register a custom template filter. Works exactly like the - :meth:`template_filter` decorator. - - :param name: the optional name of the filter, otherwise the - function name will be used. - """ - self.jinja_env.filters[name or f.__name__] = f - - @setupmethod - def template_test( - self, name: str | None = None - ) -> t.Callable[[T_template_test], T_template_test]: - """A decorator that is used to register custom template test. - You can specify a name for the test, otherwise the function - name will be used. Example:: - - @app.template_test() - def is_prime(n): - if n == 2: - return True - for i in range(2, int(math.ceil(math.sqrt(n))) + 1): - if n % i == 0: - return False - return True - - .. versionadded:: 0.10 - - :param name: the optional name of the test, otherwise the - function name will be used. - """ - - def decorator(f: T_template_test) -> T_template_test: - self.add_template_test(f, name=name) - return f - - return decorator - - @setupmethod - def add_template_test( - self, f: ft.TemplateTestCallable, name: str | None = None - ) -> None: - """Register a custom template test. Works exactly like the - :meth:`template_test` decorator. - - .. versionadded:: 0.10 - - :param name: the optional name of the test, otherwise the - function name will be used. - """ - self.jinja_env.tests[name or f.__name__] = f - - @setupmethod - def template_global( - self, name: str | None = None - ) -> t.Callable[[T_template_global], T_template_global]: - """A decorator that is used to register a custom template global function. - You can specify a name for the global function, otherwise the function - name will be used. Example:: - - @app.template_global() - def double(n): - return 2 * n - - .. versionadded:: 0.10 - - :param name: the optional name of the global function, otherwise the - function name will be used. - """ - - def decorator(f: T_template_global) -> T_template_global: - self.add_template_global(f, name=name) - return f - - return decorator - - @setupmethod - def add_template_global( - self, f: ft.TemplateGlobalCallable, name: str | None = None - ) -> None: - """Register a custom template global function. Works exactly like the - :meth:`template_global` decorator. - - .. versionadded:: 0.10 - - :param name: the optional name of the global function, otherwise the - function name will be used. - """ - self.jinja_env.globals[name or f.__name__] = f - - @setupmethod - def teardown_appcontext(self, f: T_teardown) -> T_teardown: - """Registers a function to be called when the application - context is popped. The application context is typically popped - after the request context for each request, at the end of CLI - commands, or after a manually pushed context ends. - - .. code-block:: python - - with app.app_context(): - ... - - When the ``with`` block exits (or ``ctx.pop()`` is called), the - teardown functions are called just before the app context is - made inactive. Since a request context typically also manages an - application context it would also be called when you pop a - request context. - - When a teardown function was called because of an unhandled - exception it will be passed an error object. If an - :meth:`errorhandler` is registered, it will handle the exception - and the teardown will not receive it. - - Teardown functions must avoid raising exceptions. If they - execute code that might fail they must surround that code with a - ``try``/``except`` block and log any errors. - - The return values of teardown functions are ignored. - - .. versionadded:: 0.9 - """ - self.teardown_appcontext_funcs.append(f) - return f - - @setupmethod - def shell_context_processor( - self, f: T_shell_context_processor - ) -> T_shell_context_processor: - """Registers a shell context processor function. - - .. versionadded:: 0.11 - """ - self.shell_context_processors.append(f) - return f - - def _find_error_handler( - self, e: Exception, blueprints: list[str] - ) -> ft.ErrorHandlerCallable | None: - """Return a registered error handler for an exception in this order: - blueprint handler for a specific code, app handler for a specific code, - blueprint handler for an exception class, app handler for an exception - class, or ``None`` if a suitable handler is not found. - """ - exc_class, code = self._get_exc_class_and_code(type(e)) - names = (*blueprints, None) - - for c in (code, None) if code is not None else (None,): - for name in names: - handler_map = self.error_handler_spec[name][c] - - if not handler_map: - continue - - for cls in exc_class.__mro__: - handler = handler_map.get(cls) - - if handler is not None: - return handler - return None - - def trap_http_exception(self, e: Exception) -> bool: - """Checks if an HTTP exception should be trapped or not. By default - this will return ``False`` for all exceptions except for a bad request - key error if ``TRAP_BAD_REQUEST_ERRORS`` is set to ``True``. It - also returns ``True`` if ``TRAP_HTTP_EXCEPTIONS`` is set to ``True``. - - This is called for all HTTP exceptions raised by a view function. - If it returns ``True`` for any exception the error handler for this - exception is not called and it shows up as regular exception in the - traceback. This is helpful for debugging implicitly raised HTTP - exceptions. - - .. versionchanged:: 1.0 - Bad request errors are not trapped by default in debug mode. - - .. versionadded:: 0.8 - """ - if self.config["TRAP_HTTP_EXCEPTIONS"]: - return True - - trap_bad_request = self.config["TRAP_BAD_REQUEST_ERRORS"] - - # if unset, trap key errors in debug mode - if ( - trap_bad_request is None - and self.debug - and isinstance(e, BadRequestKeyError) - ): - return True - - if trap_bad_request: - return isinstance(e, BadRequest) - - return False - - def should_ignore_error(self, error: BaseException | None) -> bool: - """This is called to figure out if an error should be ignored - or not as far as the teardown system is concerned. If this - function returns ``True`` then the teardown handlers will not be - passed the error. - - .. versionadded:: 0.10 - """ - return False - - def redirect(self, location: str, code: int = 302) -> BaseResponse: - """Create a redirect response object. - - This is called by :func:`flask.redirect`, and can be called - directly as well. - - :param location: The URL to redirect to. - :param code: The status code for the redirect. - - .. versionadded:: 2.2 - Moved from ``flask.redirect``, which calls this method. - """ - return _wz_redirect( - location, - code=code, - Response=self.response_class, # type: ignore[arg-type] - ) - - def inject_url_defaults(self, endpoint: str, values: dict[str, t.Any]) -> None: - """Injects the URL defaults for the given endpoint directly into - the values dictionary passed. This is used internally and - automatically called on URL building. - - .. versionadded:: 0.7 - """ - names: t.Iterable[str | None] = (None,) - - # url_for may be called outside a request context, parse the - # passed endpoint instead of using request.blueprints. - if "." in endpoint: - names = chain( - names, reversed(_split_blueprint_path(endpoint.rpartition(".")[0])) - ) - - for name in names: - if name in self.url_default_functions: - for func in self.url_default_functions[name]: - func(endpoint, values) - - def handle_url_build_error( - self, error: BuildError, endpoint: str, values: dict[str, t.Any] - ) -> str: - """Called by :meth:`.url_for` if a - :exc:`~werkzeug.routing.BuildError` was raised. If this returns - a value, it will be returned by ``url_for``, otherwise the error - will be re-raised. - - Each function in :attr:`url_build_error_handlers` is called with - ``error``, ``endpoint`` and ``values``. If a function returns - ``None`` or raises a ``BuildError``, it is skipped. Otherwise, - its return value is returned by ``url_for``. - - :param error: The active ``BuildError`` being handled. - :param endpoint: The endpoint being built. - :param values: The keyword arguments passed to ``url_for``. - """ - for handler in self.url_build_error_handlers: - try: - rv = handler(error, endpoint, values) - except BuildError as e: - # make error available outside except block - error = e - else: - if rv is not None: - return rv - - # Re-raise if called with an active exception, otherwise raise - # the passed in exception. - if error is sys.exc_info()[1]: - raise - - raise error diff --git a/venv/lib/python3.9/site-packages/flask/sansio/blueprints.py b/venv/lib/python3.9/site-packages/flask/sansio/blueprints.py deleted file mode 100644 index 4f912cc..0000000 --- a/venv/lib/python3.9/site-packages/flask/sansio/blueprints.py +++ /dev/null @@ -1,632 +0,0 @@ -from __future__ import annotations - -import os -import typing as t -from collections import defaultdict -from functools import update_wrapper - -from .. import typing as ft -from .scaffold import _endpoint_from_view_func -from .scaffold import _sentinel -from .scaffold import Scaffold -from .scaffold import setupmethod - -if t.TYPE_CHECKING: # pragma: no cover - from .app import App - -DeferredSetupFunction = t.Callable[["BlueprintSetupState"], None] -T_after_request = t.TypeVar("T_after_request", bound=ft.AfterRequestCallable[t.Any]) -T_before_request = t.TypeVar("T_before_request", bound=ft.BeforeRequestCallable) -T_error_handler = t.TypeVar("T_error_handler", bound=ft.ErrorHandlerCallable) -T_teardown = t.TypeVar("T_teardown", bound=ft.TeardownCallable) -T_template_context_processor = t.TypeVar( - "T_template_context_processor", bound=ft.TemplateContextProcessorCallable -) -T_template_filter = t.TypeVar("T_template_filter", bound=ft.TemplateFilterCallable) -T_template_global = t.TypeVar("T_template_global", bound=ft.TemplateGlobalCallable) -T_template_test = t.TypeVar("T_template_test", bound=ft.TemplateTestCallable) -T_url_defaults = t.TypeVar("T_url_defaults", bound=ft.URLDefaultCallable) -T_url_value_preprocessor = t.TypeVar( - "T_url_value_preprocessor", bound=ft.URLValuePreprocessorCallable -) - - -class BlueprintSetupState: - """Temporary holder object for registering a blueprint with the - application. An instance of this class is created by the - :meth:`~flask.Blueprint.make_setup_state` method and later passed - to all register callback functions. - """ - - def __init__( - self, - blueprint: Blueprint, - app: App, - options: t.Any, - first_registration: bool, - ) -> None: - #: a reference to the current application - self.app = app - - #: a reference to the blueprint that created this setup state. - self.blueprint = blueprint - - #: a dictionary with all options that were passed to the - #: :meth:`~flask.Flask.register_blueprint` method. - self.options = options - - #: as blueprints can be registered multiple times with the - #: application and not everything wants to be registered - #: multiple times on it, this attribute can be used to figure - #: out if the blueprint was registered in the past already. - self.first_registration = first_registration - - subdomain = self.options.get("subdomain") - if subdomain is None: - subdomain = self.blueprint.subdomain - - #: The subdomain that the blueprint should be active for, ``None`` - #: otherwise. - self.subdomain = subdomain - - url_prefix = self.options.get("url_prefix") - if url_prefix is None: - url_prefix = self.blueprint.url_prefix - #: The prefix that should be used for all URLs defined on the - #: blueprint. - self.url_prefix = url_prefix - - self.name = self.options.get("name", blueprint.name) - self.name_prefix = self.options.get("name_prefix", "") - - #: A dictionary with URL defaults that is added to each and every - #: URL that was defined with the blueprint. - self.url_defaults = dict(self.blueprint.url_values_defaults) - self.url_defaults.update(self.options.get("url_defaults", ())) - - def add_url_rule( - self, - rule: str, - endpoint: str | None = None, - view_func: ft.RouteCallable | None = None, - **options: t.Any, - ) -> None: - """A helper method to register a rule (and optionally a view function) - to the application. The endpoint is automatically prefixed with the - blueprint's name. - """ - if self.url_prefix is not None: - if rule: - rule = "/".join((self.url_prefix.rstrip("/"), rule.lstrip("/"))) - else: - rule = self.url_prefix - options.setdefault("subdomain", self.subdomain) - if endpoint is None: - endpoint = _endpoint_from_view_func(view_func) # type: ignore - defaults = self.url_defaults - if "defaults" in options: - defaults = dict(defaults, **options.pop("defaults")) - - self.app.add_url_rule( - rule, - f"{self.name_prefix}.{self.name}.{endpoint}".lstrip("."), - view_func, - defaults=defaults, - **options, - ) - - -class Blueprint(Scaffold): - """Represents a blueprint, a collection of routes and other - app-related functions that can be registered on a real application - later. - - A blueprint is an object that allows defining application functions - without requiring an application object ahead of time. It uses the - same decorators as :class:`~flask.Flask`, but defers the need for an - application by recording them for later registration. - - Decorating a function with a blueprint creates a deferred function - that is called with :class:`~flask.blueprints.BlueprintSetupState` - when the blueprint is registered on an application. - - See :doc:`/blueprints` for more information. - - :param name: The name of the blueprint. Will be prepended to each - endpoint name. - :param import_name: The name of the blueprint package, usually - ``__name__``. This helps locate the ``root_path`` for the - blueprint. - :param static_folder: A folder with static files that should be - served by the blueprint's static route. The path is relative to - the blueprint's root path. Blueprint static files are disabled - by default. - :param static_url_path: The url to serve static files from. - Defaults to ``static_folder``. If the blueprint does not have - a ``url_prefix``, the app's static route will take precedence, - and the blueprint's static files won't be accessible. - :param template_folder: A folder with templates that should be added - to the app's template search path. The path is relative to the - blueprint's root path. Blueprint templates are disabled by - default. Blueprint templates have a lower precedence than those - in the app's templates folder. - :param url_prefix: A path to prepend to all of the blueprint's URLs, - to make them distinct from the rest of the app's routes. - :param subdomain: A subdomain that blueprint routes will match on by - default. - :param url_defaults: A dict of default values that blueprint routes - will receive by default. - :param root_path: By default, the blueprint will automatically set - this based on ``import_name``. In certain situations this - automatic detection can fail, so the path can be specified - manually instead. - - .. versionchanged:: 1.1.0 - Blueprints have a ``cli`` group to register nested CLI commands. - The ``cli_group`` parameter controls the name of the group under - the ``flask`` command. - - .. versionadded:: 0.7 - """ - - _got_registered_once = False - - def __init__( - self, - name: str, - import_name: str, - static_folder: str | os.PathLike[str] | None = None, - static_url_path: str | None = None, - template_folder: str | os.PathLike[str] | None = None, - url_prefix: str | None = None, - subdomain: str | None = None, - url_defaults: dict[str, t.Any] | None = None, - root_path: str | None = None, - cli_group: str | None = _sentinel, # type: ignore[assignment] - ): - super().__init__( - import_name=import_name, - static_folder=static_folder, - static_url_path=static_url_path, - template_folder=template_folder, - root_path=root_path, - ) - - if not name: - raise ValueError("'name' may not be empty.") - - if "." in name: - raise ValueError("'name' may not contain a dot '.' character.") - - self.name = name - self.url_prefix = url_prefix - self.subdomain = subdomain - self.deferred_functions: list[DeferredSetupFunction] = [] - - if url_defaults is None: - url_defaults = {} - - self.url_values_defaults = url_defaults - self.cli_group = cli_group - self._blueprints: list[tuple[Blueprint, dict[str, t.Any]]] = [] - - def _check_setup_finished(self, f_name: str) -> None: - if self._got_registered_once: - raise AssertionError( - f"The setup method '{f_name}' can no longer be called on the blueprint" - f" '{self.name}'. It has already been registered at least once, any" - " changes will not be applied consistently.\n" - "Make sure all imports, decorators, functions, etc. needed to set up" - " the blueprint are done before registering it." - ) - - @setupmethod - def record(self, func: DeferredSetupFunction) -> None: - """Registers a function that is called when the blueprint is - registered on the application. This function is called with the - state as argument as returned by the :meth:`make_setup_state` - method. - """ - self.deferred_functions.append(func) - - @setupmethod - def record_once(self, func: DeferredSetupFunction) -> None: - """Works like :meth:`record` but wraps the function in another - function that will ensure the function is only called once. If the - blueprint is registered a second time on the application, the - function passed is not called. - """ - - def wrapper(state: BlueprintSetupState) -> None: - if state.first_registration: - func(state) - - self.record(update_wrapper(wrapper, func)) - - def make_setup_state( - self, app: App, options: dict[str, t.Any], first_registration: bool = False - ) -> BlueprintSetupState: - """Creates an instance of :meth:`~flask.blueprints.BlueprintSetupState` - object that is later passed to the register callback functions. - Subclasses can override this to return a subclass of the setup state. - """ - return BlueprintSetupState(self, app, options, first_registration) - - @setupmethod - def register_blueprint(self, blueprint: Blueprint, **options: t.Any) -> None: - """Register a :class:`~flask.Blueprint` on this blueprint. Keyword - arguments passed to this method will override the defaults set - on the blueprint. - - .. versionchanged:: 2.0.1 - The ``name`` option can be used to change the (pre-dotted) - name the blueprint is registered with. This allows the same - blueprint to be registered multiple times with unique names - for ``url_for``. - - .. versionadded:: 2.0 - """ - if blueprint is self: - raise ValueError("Cannot register a blueprint on itself") - self._blueprints.append((blueprint, options)) - - def register(self, app: App, options: dict[str, t.Any]) -> None: - """Called by :meth:`Flask.register_blueprint` to register all - views and callbacks registered on the blueprint with the - application. Creates a :class:`.BlueprintSetupState` and calls - each :meth:`record` callback with it. - - :param app: The application this blueprint is being registered - with. - :param options: Keyword arguments forwarded from - :meth:`~Flask.register_blueprint`. - - .. versionchanged:: 2.3 - Nested blueprints now correctly apply subdomains. - - .. versionchanged:: 2.1 - Registering the same blueprint with the same name multiple - times is an error. - - .. versionchanged:: 2.0.1 - Nested blueprints are registered with their dotted name. - This allows different blueprints with the same name to be - nested at different locations. - - .. versionchanged:: 2.0.1 - The ``name`` option can be used to change the (pre-dotted) - name the blueprint is registered with. This allows the same - blueprint to be registered multiple times with unique names - for ``url_for``. - """ - name_prefix = options.get("name_prefix", "") - self_name = options.get("name", self.name) - name = f"{name_prefix}.{self_name}".lstrip(".") - - if name in app.blueprints: - bp_desc = "this" if app.blueprints[name] is self else "a different" - existing_at = f" '{name}'" if self_name != name else "" - - raise ValueError( - f"The name '{self_name}' is already registered for" - f" {bp_desc} blueprint{existing_at}. Use 'name=' to" - f" provide a unique name." - ) - - first_bp_registration = not any(bp is self for bp in app.blueprints.values()) - first_name_registration = name not in app.blueprints - - app.blueprints[name] = self - self._got_registered_once = True - state = self.make_setup_state(app, options, first_bp_registration) - - if self.has_static_folder: - state.add_url_rule( - f"{self.static_url_path}/", - view_func=self.send_static_file, # type: ignore[attr-defined] - endpoint="static", - ) - - # Merge blueprint data into parent. - if first_bp_registration or first_name_registration: - self._merge_blueprint_funcs(app, name) - - for deferred in self.deferred_functions: - deferred(state) - - cli_resolved_group = options.get("cli_group", self.cli_group) - - if self.cli.commands: - if cli_resolved_group is None: - app.cli.commands.update(self.cli.commands) - elif cli_resolved_group is _sentinel: - self.cli.name = name - app.cli.add_command(self.cli) - else: - self.cli.name = cli_resolved_group - app.cli.add_command(self.cli) - - for blueprint, bp_options in self._blueprints: - bp_options = bp_options.copy() - bp_url_prefix = bp_options.get("url_prefix") - bp_subdomain = bp_options.get("subdomain") - - if bp_subdomain is None: - bp_subdomain = blueprint.subdomain - - if state.subdomain is not None and bp_subdomain is not None: - bp_options["subdomain"] = bp_subdomain + "." + state.subdomain - elif bp_subdomain is not None: - bp_options["subdomain"] = bp_subdomain - elif state.subdomain is not None: - bp_options["subdomain"] = state.subdomain - - if bp_url_prefix is None: - bp_url_prefix = blueprint.url_prefix - - if state.url_prefix is not None and bp_url_prefix is not None: - bp_options["url_prefix"] = ( - state.url_prefix.rstrip("/") + "/" + bp_url_prefix.lstrip("/") - ) - elif bp_url_prefix is not None: - bp_options["url_prefix"] = bp_url_prefix - elif state.url_prefix is not None: - bp_options["url_prefix"] = state.url_prefix - - bp_options["name_prefix"] = name - blueprint.register(app, bp_options) - - def _merge_blueprint_funcs(self, app: App, name: str) -> None: - def extend( - bp_dict: dict[ft.AppOrBlueprintKey, list[t.Any]], - parent_dict: dict[ft.AppOrBlueprintKey, list[t.Any]], - ) -> None: - for key, values in bp_dict.items(): - key = name if key is None else f"{name}.{key}" - parent_dict[key].extend(values) - - for key, value in self.error_handler_spec.items(): - key = name if key is None else f"{name}.{key}" - value = defaultdict( - dict, - { - code: {exc_class: func for exc_class, func in code_values.items()} - for code, code_values in value.items() - }, - ) - app.error_handler_spec[key] = value - - for endpoint, func in self.view_functions.items(): - app.view_functions[endpoint] = func - - extend(self.before_request_funcs, app.before_request_funcs) - extend(self.after_request_funcs, app.after_request_funcs) - extend( - self.teardown_request_funcs, - app.teardown_request_funcs, - ) - extend(self.url_default_functions, app.url_default_functions) - extend(self.url_value_preprocessors, app.url_value_preprocessors) - extend(self.template_context_processors, app.template_context_processors) - - @setupmethod - def add_url_rule( - self, - rule: str, - endpoint: str | None = None, - view_func: ft.RouteCallable | None = None, - provide_automatic_options: bool | None = None, - **options: t.Any, - ) -> None: - """Register a URL rule with the blueprint. See :meth:`.Flask.add_url_rule` for - full documentation. - - The URL rule is prefixed with the blueprint's URL prefix. The endpoint name, - used with :func:`url_for`, is prefixed with the blueprint's name. - """ - if endpoint and "." in endpoint: - raise ValueError("'endpoint' may not contain a dot '.' character.") - - if view_func and hasattr(view_func, "__name__") and "." in view_func.__name__: - raise ValueError("'view_func' name may not contain a dot '.' character.") - - self.record( - lambda s: s.add_url_rule( - rule, - endpoint, - view_func, - provide_automatic_options=provide_automatic_options, - **options, - ) - ) - - @setupmethod - def app_template_filter( - self, name: str | None = None - ) -> t.Callable[[T_template_filter], T_template_filter]: - """Register a template filter, available in any template rendered by the - application. Equivalent to :meth:`.Flask.template_filter`. - - :param name: the optional name of the filter, otherwise the - function name will be used. - """ - - def decorator(f: T_template_filter) -> T_template_filter: - self.add_app_template_filter(f, name=name) - return f - - return decorator - - @setupmethod - def add_app_template_filter( - self, f: ft.TemplateFilterCallable, name: str | None = None - ) -> None: - """Register a template filter, available in any template rendered by the - application. Works like the :meth:`app_template_filter` decorator. Equivalent to - :meth:`.Flask.add_template_filter`. - - :param name: the optional name of the filter, otherwise the - function name will be used. - """ - - def register_template(state: BlueprintSetupState) -> None: - state.app.jinja_env.filters[name or f.__name__] = f - - self.record_once(register_template) - - @setupmethod - def app_template_test( - self, name: str | None = None - ) -> t.Callable[[T_template_test], T_template_test]: - """Register a template test, available in any template rendered by the - application. Equivalent to :meth:`.Flask.template_test`. - - .. versionadded:: 0.10 - - :param name: the optional name of the test, otherwise the - function name will be used. - """ - - def decorator(f: T_template_test) -> T_template_test: - self.add_app_template_test(f, name=name) - return f - - return decorator - - @setupmethod - def add_app_template_test( - self, f: ft.TemplateTestCallable, name: str | None = None - ) -> None: - """Register a template test, available in any template rendered by the - application. Works like the :meth:`app_template_test` decorator. Equivalent to - :meth:`.Flask.add_template_test`. - - .. versionadded:: 0.10 - - :param name: the optional name of the test, otherwise the - function name will be used. - """ - - def register_template(state: BlueprintSetupState) -> None: - state.app.jinja_env.tests[name or f.__name__] = f - - self.record_once(register_template) - - @setupmethod - def app_template_global( - self, name: str | None = None - ) -> t.Callable[[T_template_global], T_template_global]: - """Register a template global, available in any template rendered by the - application. Equivalent to :meth:`.Flask.template_global`. - - .. versionadded:: 0.10 - - :param name: the optional name of the global, otherwise the - function name will be used. - """ - - def decorator(f: T_template_global) -> T_template_global: - self.add_app_template_global(f, name=name) - return f - - return decorator - - @setupmethod - def add_app_template_global( - self, f: ft.TemplateGlobalCallable, name: str | None = None - ) -> None: - """Register a template global, available in any template rendered by the - application. Works like the :meth:`app_template_global` decorator. Equivalent to - :meth:`.Flask.add_template_global`. - - .. versionadded:: 0.10 - - :param name: the optional name of the global, otherwise the - function name will be used. - """ - - def register_template(state: BlueprintSetupState) -> None: - state.app.jinja_env.globals[name or f.__name__] = f - - self.record_once(register_template) - - @setupmethod - def before_app_request(self, f: T_before_request) -> T_before_request: - """Like :meth:`before_request`, but before every request, not only those handled - by the blueprint. Equivalent to :meth:`.Flask.before_request`. - """ - self.record_once( - lambda s: s.app.before_request_funcs.setdefault(None, []).append(f) - ) - return f - - @setupmethod - def after_app_request(self, f: T_after_request) -> T_after_request: - """Like :meth:`after_request`, but after every request, not only those handled - by the blueprint. Equivalent to :meth:`.Flask.after_request`. - """ - self.record_once( - lambda s: s.app.after_request_funcs.setdefault(None, []).append(f) - ) - return f - - @setupmethod - def teardown_app_request(self, f: T_teardown) -> T_teardown: - """Like :meth:`teardown_request`, but after every request, not only those - handled by the blueprint. Equivalent to :meth:`.Flask.teardown_request`. - """ - self.record_once( - lambda s: s.app.teardown_request_funcs.setdefault(None, []).append(f) - ) - return f - - @setupmethod - def app_context_processor( - self, f: T_template_context_processor - ) -> T_template_context_processor: - """Like :meth:`context_processor`, but for templates rendered by every view, not - only by the blueprint. Equivalent to :meth:`.Flask.context_processor`. - """ - self.record_once( - lambda s: s.app.template_context_processors.setdefault(None, []).append(f) - ) - return f - - @setupmethod - def app_errorhandler( - self, code: type[Exception] | int - ) -> t.Callable[[T_error_handler], T_error_handler]: - """Like :meth:`errorhandler`, but for every request, not only those handled by - the blueprint. Equivalent to :meth:`.Flask.errorhandler`. - """ - - def decorator(f: T_error_handler) -> T_error_handler: - def from_blueprint(state: BlueprintSetupState) -> None: - state.app.errorhandler(code)(f) - - self.record_once(from_blueprint) - return f - - return decorator - - @setupmethod - def app_url_value_preprocessor( - self, f: T_url_value_preprocessor - ) -> T_url_value_preprocessor: - """Like :meth:`url_value_preprocessor`, but for every request, not only those - handled by the blueprint. Equivalent to :meth:`.Flask.url_value_preprocessor`. - """ - self.record_once( - lambda s: s.app.url_value_preprocessors.setdefault(None, []).append(f) - ) - return f - - @setupmethod - def app_url_defaults(self, f: T_url_defaults) -> T_url_defaults: - """Like :meth:`url_defaults`, but for every request, not only those handled by - the blueprint. Equivalent to :meth:`.Flask.url_defaults`. - """ - self.record_once( - lambda s: s.app.url_default_functions.setdefault(None, []).append(f) - ) - return f diff --git a/venv/lib/python3.9/site-packages/flask/sansio/scaffold.py b/venv/lib/python3.9/site-packages/flask/sansio/scaffold.py deleted file mode 100644 index 0e96f15..0000000 --- a/venv/lib/python3.9/site-packages/flask/sansio/scaffold.py +++ /dev/null @@ -1,792 +0,0 @@ -from __future__ import annotations - -import importlib.util -import os -import pathlib -import sys -import typing as t -from collections import defaultdict -from functools import update_wrapper - -from jinja2 import BaseLoader -from jinja2 import FileSystemLoader -from werkzeug.exceptions import default_exceptions -from werkzeug.exceptions import HTTPException -from werkzeug.utils import cached_property - -from .. import typing as ft -from ..helpers import get_root_path -from ..templating import _default_template_ctx_processor - -if t.TYPE_CHECKING: # pragma: no cover - from click import Group - -# a singleton sentinel value for parameter defaults -_sentinel = object() - -F = t.TypeVar("F", bound=t.Callable[..., t.Any]) -T_after_request = t.TypeVar("T_after_request", bound=ft.AfterRequestCallable[t.Any]) -T_before_request = t.TypeVar("T_before_request", bound=ft.BeforeRequestCallable) -T_error_handler = t.TypeVar("T_error_handler", bound=ft.ErrorHandlerCallable) -T_teardown = t.TypeVar("T_teardown", bound=ft.TeardownCallable) -T_template_context_processor = t.TypeVar( - "T_template_context_processor", bound=ft.TemplateContextProcessorCallable -) -T_url_defaults = t.TypeVar("T_url_defaults", bound=ft.URLDefaultCallable) -T_url_value_preprocessor = t.TypeVar( - "T_url_value_preprocessor", bound=ft.URLValuePreprocessorCallable -) -T_route = t.TypeVar("T_route", bound=ft.RouteCallable) - - -def setupmethod(f: F) -> F: - f_name = f.__name__ - - def wrapper_func(self: Scaffold, *args: t.Any, **kwargs: t.Any) -> t.Any: - self._check_setup_finished(f_name) - return f(self, *args, **kwargs) - - return t.cast(F, update_wrapper(wrapper_func, f)) - - -class Scaffold: - """Common behavior shared between :class:`~flask.Flask` and - :class:`~flask.blueprints.Blueprint`. - - :param import_name: The import name of the module where this object - is defined. Usually :attr:`__name__` should be used. - :param static_folder: Path to a folder of static files to serve. - If this is set, a static route will be added. - :param static_url_path: URL prefix for the static route. - :param template_folder: Path to a folder containing template files. - for rendering. If this is set, a Jinja loader will be added. - :param root_path: The path that static, template, and resource files - are relative to. Typically not set, it is discovered based on - the ``import_name``. - - .. versionadded:: 2.0 - """ - - cli: Group - name: str - _static_folder: str | None = None - _static_url_path: str | None = None - - def __init__( - self, - import_name: str, - static_folder: str | os.PathLike[str] | None = None, - static_url_path: str | None = None, - template_folder: str | os.PathLike[str] | None = None, - root_path: str | None = None, - ): - #: The name of the package or module that this object belongs - #: to. Do not change this once it is set by the constructor. - self.import_name = import_name - - self.static_folder = static_folder - self.static_url_path = static_url_path - - #: The path to the templates folder, relative to - #: :attr:`root_path`, to add to the template loader. ``None`` if - #: templates should not be added. - self.template_folder = template_folder - - if root_path is None: - root_path = get_root_path(self.import_name) - - #: Absolute path to the package on the filesystem. Used to look - #: up resources contained in the package. - self.root_path = root_path - - #: A dictionary mapping endpoint names to view functions. - #: - #: To register a view function, use the :meth:`route` decorator. - #: - #: This data structure is internal. It should not be modified - #: directly and its format may change at any time. - self.view_functions: dict[str, ft.RouteCallable] = {} - - #: A data structure of registered error handlers, in the format - #: ``{scope: {code: {class: handler}}}``. The ``scope`` key is - #: the name of a blueprint the handlers are active for, or - #: ``None`` for all requests. The ``code`` key is the HTTP - #: status code for ``HTTPException``, or ``None`` for - #: other exceptions. The innermost dictionary maps exception - #: classes to handler functions. - #: - #: To register an error handler, use the :meth:`errorhandler` - #: decorator. - #: - #: This data structure is internal. It should not be modified - #: directly and its format may change at any time. - self.error_handler_spec: dict[ - ft.AppOrBlueprintKey, - dict[int | None, dict[type[Exception], ft.ErrorHandlerCallable]], - ] = defaultdict(lambda: defaultdict(dict)) - - #: A data structure of functions to call at the beginning of - #: each request, in the format ``{scope: [functions]}``. The - #: ``scope`` key is the name of a blueprint the functions are - #: active for, or ``None`` for all requests. - #: - #: To register a function, use the :meth:`before_request` - #: decorator. - #: - #: This data structure is internal. It should not be modified - #: directly and its format may change at any time. - self.before_request_funcs: dict[ - ft.AppOrBlueprintKey, list[ft.BeforeRequestCallable] - ] = defaultdict(list) - - #: A data structure of functions to call at the end of each - #: request, in the format ``{scope: [functions]}``. The - #: ``scope`` key is the name of a blueprint the functions are - #: active for, or ``None`` for all requests. - #: - #: To register a function, use the :meth:`after_request` - #: decorator. - #: - #: This data structure is internal. It should not be modified - #: directly and its format may change at any time. - self.after_request_funcs: dict[ - ft.AppOrBlueprintKey, list[ft.AfterRequestCallable[t.Any]] - ] = defaultdict(list) - - #: A data structure of functions to call at the end of each - #: request even if an exception is raised, in the format - #: ``{scope: [functions]}``. The ``scope`` key is the name of a - #: blueprint the functions are active for, or ``None`` for all - #: requests. - #: - #: To register a function, use the :meth:`teardown_request` - #: decorator. - #: - #: This data structure is internal. It should not be modified - #: directly and its format may change at any time. - self.teardown_request_funcs: dict[ - ft.AppOrBlueprintKey, list[ft.TeardownCallable] - ] = defaultdict(list) - - #: A data structure of functions to call to pass extra context - #: values when rendering templates, in the format - #: ``{scope: [functions]}``. The ``scope`` key is the name of a - #: blueprint the functions are active for, or ``None`` for all - #: requests. - #: - #: To register a function, use the :meth:`context_processor` - #: decorator. - #: - #: This data structure is internal. It should not be modified - #: directly and its format may change at any time. - self.template_context_processors: dict[ - ft.AppOrBlueprintKey, list[ft.TemplateContextProcessorCallable] - ] = defaultdict(list, {None: [_default_template_ctx_processor]}) - - #: A data structure of functions to call to modify the keyword - #: arguments passed to the view function, in the format - #: ``{scope: [functions]}``. The ``scope`` key is the name of a - #: blueprint the functions are active for, or ``None`` for all - #: requests. - #: - #: To register a function, use the - #: :meth:`url_value_preprocessor` decorator. - #: - #: This data structure is internal. It should not be modified - #: directly and its format may change at any time. - self.url_value_preprocessors: dict[ - ft.AppOrBlueprintKey, - list[ft.URLValuePreprocessorCallable], - ] = defaultdict(list) - - #: A data structure of functions to call to modify the keyword - #: arguments when generating URLs, in the format - #: ``{scope: [functions]}``. The ``scope`` key is the name of a - #: blueprint the functions are active for, or ``None`` for all - #: requests. - #: - #: To register a function, use the :meth:`url_defaults` - #: decorator. - #: - #: This data structure is internal. It should not be modified - #: directly and its format may change at any time. - self.url_default_functions: dict[ - ft.AppOrBlueprintKey, list[ft.URLDefaultCallable] - ] = defaultdict(list) - - def __repr__(self) -> str: - return f"<{type(self).__name__} {self.name!r}>" - - def _check_setup_finished(self, f_name: str) -> None: - raise NotImplementedError - - @property - def static_folder(self) -> str | None: - """The absolute path to the configured static folder. ``None`` - if no static folder is set. - """ - if self._static_folder is not None: - return os.path.join(self.root_path, self._static_folder) - else: - return None - - @static_folder.setter - def static_folder(self, value: str | os.PathLike[str] | None) -> None: - if value is not None: - value = os.fspath(value).rstrip(r"\/") - - self._static_folder = value - - @property - def has_static_folder(self) -> bool: - """``True`` if :attr:`static_folder` is set. - - .. versionadded:: 0.5 - """ - return self.static_folder is not None - - @property - def static_url_path(self) -> str | None: - """The URL prefix that the static route will be accessible from. - - If it was not configured during init, it is derived from - :attr:`static_folder`. - """ - if self._static_url_path is not None: - return self._static_url_path - - if self.static_folder is not None: - basename = os.path.basename(self.static_folder) - return f"/{basename}".rstrip("/") - - return None - - @static_url_path.setter - def static_url_path(self, value: str | None) -> None: - if value is not None: - value = value.rstrip("/") - - self._static_url_path = value - - @cached_property - def jinja_loader(self) -> BaseLoader | None: - """The Jinja loader for this object's templates. By default this - is a class :class:`jinja2.loaders.FileSystemLoader` to - :attr:`template_folder` if it is set. - - .. versionadded:: 0.5 - """ - if self.template_folder is not None: - return FileSystemLoader(os.path.join(self.root_path, self.template_folder)) - else: - return None - - def _method_route( - self, - method: str, - rule: str, - options: dict[str, t.Any], - ) -> t.Callable[[T_route], T_route]: - if "methods" in options: - raise TypeError("Use the 'route' decorator to use the 'methods' argument.") - - return self.route(rule, methods=[method], **options) - - @setupmethod - def get(self, rule: str, **options: t.Any) -> t.Callable[[T_route], T_route]: - """Shortcut for :meth:`route` with ``methods=["GET"]``. - - .. versionadded:: 2.0 - """ - return self._method_route("GET", rule, options) - - @setupmethod - def post(self, rule: str, **options: t.Any) -> t.Callable[[T_route], T_route]: - """Shortcut for :meth:`route` with ``methods=["POST"]``. - - .. versionadded:: 2.0 - """ - return self._method_route("POST", rule, options) - - @setupmethod - def put(self, rule: str, **options: t.Any) -> t.Callable[[T_route], T_route]: - """Shortcut for :meth:`route` with ``methods=["PUT"]``. - - .. versionadded:: 2.0 - """ - return self._method_route("PUT", rule, options) - - @setupmethod - def delete(self, rule: str, **options: t.Any) -> t.Callable[[T_route], T_route]: - """Shortcut for :meth:`route` with ``methods=["DELETE"]``. - - .. versionadded:: 2.0 - """ - return self._method_route("DELETE", rule, options) - - @setupmethod - def patch(self, rule: str, **options: t.Any) -> t.Callable[[T_route], T_route]: - """Shortcut for :meth:`route` with ``methods=["PATCH"]``. - - .. versionadded:: 2.0 - """ - return self._method_route("PATCH", rule, options) - - @setupmethod - def route(self, rule: str, **options: t.Any) -> t.Callable[[T_route], T_route]: - """Decorate a view function to register it with the given URL - rule and options. Calls :meth:`add_url_rule`, which has more - details about the implementation. - - .. code-block:: python - - @app.route("/") - def index(): - return "Hello, World!" - - See :ref:`url-route-registrations`. - - The endpoint name for the route defaults to the name of the view - function if the ``endpoint`` parameter isn't passed. - - The ``methods`` parameter defaults to ``["GET"]``. ``HEAD`` and - ``OPTIONS`` are added automatically. - - :param rule: The URL rule string. - :param options: Extra options passed to the - :class:`~werkzeug.routing.Rule` object. - """ - - def decorator(f: T_route) -> T_route: - endpoint = options.pop("endpoint", None) - self.add_url_rule(rule, endpoint, f, **options) - return f - - return decorator - - @setupmethod - def add_url_rule( - self, - rule: str, - endpoint: str | None = None, - view_func: ft.RouteCallable | None = None, - provide_automatic_options: bool | None = None, - **options: t.Any, - ) -> None: - """Register a rule for routing incoming requests and building - URLs. The :meth:`route` decorator is a shortcut to call this - with the ``view_func`` argument. These are equivalent: - - .. code-block:: python - - @app.route("/") - def index(): - ... - - .. code-block:: python - - def index(): - ... - - app.add_url_rule("/", view_func=index) - - See :ref:`url-route-registrations`. - - The endpoint name for the route defaults to the name of the view - function if the ``endpoint`` parameter isn't passed. An error - will be raised if a function has already been registered for the - endpoint. - - The ``methods`` parameter defaults to ``["GET"]``. ``HEAD`` is - always added automatically, and ``OPTIONS`` is added - automatically by default. - - ``view_func`` does not necessarily need to be passed, but if the - rule should participate in routing an endpoint name must be - associated with a view function at some point with the - :meth:`endpoint` decorator. - - .. code-block:: python - - app.add_url_rule("/", endpoint="index") - - @app.endpoint("index") - def index(): - ... - - If ``view_func`` has a ``required_methods`` attribute, those - methods are added to the passed and automatic methods. If it - has a ``provide_automatic_methods`` attribute, it is used as the - default if the parameter is not passed. - - :param rule: The URL rule string. - :param endpoint: The endpoint name to associate with the rule - and view function. Used when routing and building URLs. - Defaults to ``view_func.__name__``. - :param view_func: The view function to associate with the - endpoint name. - :param provide_automatic_options: Add the ``OPTIONS`` method and - respond to ``OPTIONS`` requests automatically. - :param options: Extra options passed to the - :class:`~werkzeug.routing.Rule` object. - """ - raise NotImplementedError - - @setupmethod - def endpoint(self, endpoint: str) -> t.Callable[[F], F]: - """Decorate a view function to register it for the given - endpoint. Used if a rule is added without a ``view_func`` with - :meth:`add_url_rule`. - - .. code-block:: python - - app.add_url_rule("/ex", endpoint="example") - - @app.endpoint("example") - def example(): - ... - - :param endpoint: The endpoint name to associate with the view - function. - """ - - def decorator(f: F) -> F: - self.view_functions[endpoint] = f - return f - - return decorator - - @setupmethod - def before_request(self, f: T_before_request) -> T_before_request: - """Register a function to run before each request. - - For example, this can be used to open a database connection, or - to load the logged in user from the session. - - .. code-block:: python - - @app.before_request - def load_user(): - if "user_id" in session: - g.user = db.session.get(session["user_id"]) - - The function will be called without any arguments. If it returns - a non-``None`` value, the value is handled as if it was the - return value from the view, and further request handling is - stopped. - - This is available on both app and blueprint objects. When used on an app, this - executes before every request. When used on a blueprint, this executes before - every request that the blueprint handles. To register with a blueprint and - execute before every request, use :meth:`.Blueprint.before_app_request`. - """ - self.before_request_funcs.setdefault(None, []).append(f) - return f - - @setupmethod - def after_request(self, f: T_after_request) -> T_after_request: - """Register a function to run after each request to this object. - - The function is called with the response object, and must return - a response object. This allows the functions to modify or - replace the response before it is sent. - - If a function raises an exception, any remaining - ``after_request`` functions will not be called. Therefore, this - should not be used for actions that must execute, such as to - close resources. Use :meth:`teardown_request` for that. - - This is available on both app and blueprint objects. When used on an app, this - executes after every request. When used on a blueprint, this executes after - every request that the blueprint handles. To register with a blueprint and - execute after every request, use :meth:`.Blueprint.after_app_request`. - """ - self.after_request_funcs.setdefault(None, []).append(f) - return f - - @setupmethod - def teardown_request(self, f: T_teardown) -> T_teardown: - """Register a function to be called when the request context is - popped. Typically this happens at the end of each request, but - contexts may be pushed manually as well during testing. - - .. code-block:: python - - with app.test_request_context(): - ... - - When the ``with`` block exits (or ``ctx.pop()`` is called), the - teardown functions are called just before the request context is - made inactive. - - When a teardown function was called because of an unhandled - exception it will be passed an error object. If an - :meth:`errorhandler` is registered, it will handle the exception - and the teardown will not receive it. - - Teardown functions must avoid raising exceptions. If they - execute code that might fail they must surround that code with a - ``try``/``except`` block and log any errors. - - The return values of teardown functions are ignored. - - This is available on both app and blueprint objects. When used on an app, this - executes after every request. When used on a blueprint, this executes after - every request that the blueprint handles. To register with a blueprint and - execute after every request, use :meth:`.Blueprint.teardown_app_request`. - """ - self.teardown_request_funcs.setdefault(None, []).append(f) - return f - - @setupmethod - def context_processor( - self, - f: T_template_context_processor, - ) -> T_template_context_processor: - """Registers a template context processor function. These functions run before - rendering a template. The keys of the returned dict are added as variables - available in the template. - - This is available on both app and blueprint objects. When used on an app, this - is called for every rendered template. When used on a blueprint, this is called - for templates rendered from the blueprint's views. To register with a blueprint - and affect every template, use :meth:`.Blueprint.app_context_processor`. - """ - self.template_context_processors[None].append(f) - return f - - @setupmethod - def url_value_preprocessor( - self, - f: T_url_value_preprocessor, - ) -> T_url_value_preprocessor: - """Register a URL value preprocessor function for all view - functions in the application. These functions will be called before the - :meth:`before_request` functions. - - The function can modify the values captured from the matched url before - they are passed to the view. For example, this can be used to pop a - common language code value and place it in ``g`` rather than pass it to - every view. - - The function is passed the endpoint name and values dict. The return - value is ignored. - - This is available on both app and blueprint objects. When used on an app, this - is called for every request. When used on a blueprint, this is called for - requests that the blueprint handles. To register with a blueprint and affect - every request, use :meth:`.Blueprint.app_url_value_preprocessor`. - """ - self.url_value_preprocessors[None].append(f) - return f - - @setupmethod - def url_defaults(self, f: T_url_defaults) -> T_url_defaults: - """Callback function for URL defaults for all view functions of the - application. It's called with the endpoint and values and should - update the values passed in place. - - This is available on both app and blueprint objects. When used on an app, this - is called for every request. When used on a blueprint, this is called for - requests that the blueprint handles. To register with a blueprint and affect - every request, use :meth:`.Blueprint.app_url_defaults`. - """ - self.url_default_functions[None].append(f) - return f - - @setupmethod - def errorhandler( - self, code_or_exception: type[Exception] | int - ) -> t.Callable[[T_error_handler], T_error_handler]: - """Register a function to handle errors by code or exception class. - - A decorator that is used to register a function given an - error code. Example:: - - @app.errorhandler(404) - def page_not_found(error): - return 'This page does not exist', 404 - - You can also register handlers for arbitrary exceptions:: - - @app.errorhandler(DatabaseError) - def special_exception_handler(error): - return 'Database connection failed', 500 - - This is available on both app and blueprint objects. When used on an app, this - can handle errors from every request. When used on a blueprint, this can handle - errors from requests that the blueprint handles. To register with a blueprint - and affect every request, use :meth:`.Blueprint.app_errorhandler`. - - .. versionadded:: 0.7 - Use :meth:`register_error_handler` instead of modifying - :attr:`error_handler_spec` directly, for application wide error - handlers. - - .. versionadded:: 0.7 - One can now additionally also register custom exception types - that do not necessarily have to be a subclass of the - :class:`~werkzeug.exceptions.HTTPException` class. - - :param code_or_exception: the code as integer for the handler, or - an arbitrary exception - """ - - def decorator(f: T_error_handler) -> T_error_handler: - self.register_error_handler(code_or_exception, f) - return f - - return decorator - - @setupmethod - def register_error_handler( - self, - code_or_exception: type[Exception] | int, - f: ft.ErrorHandlerCallable, - ) -> None: - """Alternative error attach function to the :meth:`errorhandler` - decorator that is more straightforward to use for non decorator - usage. - - .. versionadded:: 0.7 - """ - exc_class, code = self._get_exc_class_and_code(code_or_exception) - self.error_handler_spec[None][code][exc_class] = f - - @staticmethod - def _get_exc_class_and_code( - exc_class_or_code: type[Exception] | int, - ) -> tuple[type[Exception], int | None]: - """Get the exception class being handled. For HTTP status codes - or ``HTTPException`` subclasses, return both the exception and - status code. - - :param exc_class_or_code: Any exception class, or an HTTP status - code as an integer. - """ - exc_class: type[Exception] - - if isinstance(exc_class_or_code, int): - try: - exc_class = default_exceptions[exc_class_or_code] - except KeyError: - raise ValueError( - f"'{exc_class_or_code}' is not a recognized HTTP" - " error code. Use a subclass of HTTPException with" - " that code instead." - ) from None - else: - exc_class = exc_class_or_code - - if isinstance(exc_class, Exception): - raise TypeError( - f"{exc_class!r} is an instance, not a class. Handlers" - " can only be registered for Exception classes or HTTP" - " error codes." - ) - - if not issubclass(exc_class, Exception): - raise ValueError( - f"'{exc_class.__name__}' is not a subclass of Exception." - " Handlers can only be registered for Exception classes" - " or HTTP error codes." - ) - - if issubclass(exc_class, HTTPException): - return exc_class, exc_class.code - else: - return exc_class, None - - -def _endpoint_from_view_func(view_func: ft.RouteCallable) -> str: - """Internal helper that returns the default endpoint for a given - function. This always is the function name. - """ - assert view_func is not None, "expected view func if endpoint is not provided." - return view_func.__name__ - - -def _find_package_path(import_name: str) -> str: - """Find the path that contains the package or module.""" - root_mod_name, _, _ = import_name.partition(".") - - try: - root_spec = importlib.util.find_spec(root_mod_name) - - if root_spec is None: - raise ValueError("not found") - except (ImportError, ValueError): - # ImportError: the machinery told us it does not exist - # ValueError: - # - the module name was invalid - # - the module name is __main__ - # - we raised `ValueError` due to `root_spec` being `None` - return os.getcwd() - - if root_spec.submodule_search_locations: - if root_spec.origin is None or root_spec.origin == "namespace": - # namespace package - package_spec = importlib.util.find_spec(import_name) - - if package_spec is not None and package_spec.submodule_search_locations: - # Pick the path in the namespace that contains the submodule. - package_path = pathlib.Path( - os.path.commonpath(package_spec.submodule_search_locations) - ) - search_location = next( - location - for location in root_spec.submodule_search_locations - if package_path.is_relative_to(location) - ) - else: - # Pick the first path. - search_location = root_spec.submodule_search_locations[0] - - return os.path.dirname(search_location) - else: - # package with __init__.py - return os.path.dirname(os.path.dirname(root_spec.origin)) - else: - # module - return os.path.dirname(root_spec.origin) # type: ignore[type-var, return-value] - - -def find_package(import_name: str) -> tuple[str | None, str]: - """Find the prefix that a package is installed under, and the path - that it would be imported from. - - The prefix is the directory containing the standard directory - hierarchy (lib, bin, etc.). If the package is not installed to the - system (:attr:`sys.prefix`) or a virtualenv (``site-packages``), - ``None`` is returned. - - The path is the entry in :attr:`sys.path` that contains the package - for import. If the package is not installed, it's assumed that the - package was imported from the current working directory. - """ - package_path = _find_package_path(import_name) - py_prefix = os.path.abspath(sys.prefix) - - # installed to the system - if pathlib.PurePath(package_path).is_relative_to(py_prefix): - return py_prefix, package_path - - site_parent, site_folder = os.path.split(package_path) - - # installed to a virtualenv - if site_folder.lower() == "site-packages": - parent, folder = os.path.split(site_parent) - - # Windows (prefix/lib/site-packages) - if folder.lower() == "lib": - return parent, package_path - - # Unix (prefix/lib/pythonX.Y/site-packages) - if os.path.basename(parent).lower() == "lib": - return os.path.dirname(parent), package_path - - # something else (prefix/site-packages) - return site_parent, package_path - - # not installed - return None, package_path diff --git a/venv/lib/python3.9/site-packages/flask/sessions.py b/venv/lib/python3.9/site-packages/flask/sessions.py deleted file mode 100644 index ad35770..0000000 --- a/venv/lib/python3.9/site-packages/flask/sessions.py +++ /dev/null @@ -1,385 +0,0 @@ -from __future__ import annotations - -import collections.abc as c -import hashlib -import typing as t -from collections.abc import MutableMapping -from datetime import datetime -from datetime import timezone - -from itsdangerous import BadSignature -from itsdangerous import URLSafeTimedSerializer -from werkzeug.datastructures import CallbackDict - -from .json.tag import TaggedJSONSerializer - -if t.TYPE_CHECKING: # pragma: no cover - import typing_extensions as te - - from .app import Flask - from .wrappers import Request - from .wrappers import Response - - -class SessionMixin(MutableMapping[str, t.Any]): - """Expands a basic dictionary with session attributes.""" - - @property - def permanent(self) -> bool: - """This reflects the ``'_permanent'`` key in the dict.""" - return self.get("_permanent", False) # type: ignore[no-any-return] - - @permanent.setter - def permanent(self, value: bool) -> None: - self["_permanent"] = bool(value) - - #: Some implementations can detect whether a session is newly - #: created, but that is not guaranteed. Use with caution. The mixin - # default is hard-coded ``False``. - new = False - - #: Some implementations can detect changes to the session and set - #: this when that happens. The mixin default is hard coded to - #: ``True``. - modified = True - - accessed = False - """Indicates if the session was accessed, even if it was not modified. This - is set when the session object is accessed through the request context, - including the global :data:`.session` proxy. A ``Vary: cookie`` header will - be added if this is ``True``. - - .. versionchanged:: 3.1.3 - This is tracked by the request context. - """ - - -class SecureCookieSession(CallbackDict[str, t.Any], SessionMixin): - """Base class for sessions based on signed cookies. - - This session backend will set the :attr:`modified` and - :attr:`accessed` attributes. It cannot reliably track whether a - session is new (vs. empty), so :attr:`new` remains hard coded to - ``False``. - """ - - #: When data is changed, this is set to ``True``. Only the session - #: dictionary itself is tracked; if the session contains mutable - #: data (for example a nested dict) then this must be set to - #: ``True`` manually when modifying that data. The session cookie - #: will only be written to the response if this is ``True``. - modified = False - - def __init__( - self, - initial: c.Mapping[str, t.Any] | None = None, - ) -> None: - def on_update(self: te.Self) -> None: - self.modified = True - - super().__init__(initial, on_update) - - -class NullSession(SecureCookieSession): - """Class used to generate nicer error messages if sessions are not - available. Will still allow read-only access to the empty session - but fail on setting. - """ - - def _fail(self, *args: t.Any, **kwargs: t.Any) -> t.NoReturn: - raise RuntimeError( - "The session is unavailable because no secret " - "key was set. Set the secret_key on the " - "application to something unique and secret." - ) - - __setitem__ = __delitem__ = clear = pop = popitem = update = setdefault = _fail - del _fail - - -class SessionInterface: - """The basic interface you have to implement in order to replace the - default session interface which uses werkzeug's securecookie - implementation. The only methods you have to implement are - :meth:`open_session` and :meth:`save_session`, the others have - useful defaults which you don't need to change. - - The session object returned by the :meth:`open_session` method has to - provide a dictionary like interface plus the properties and methods - from the :class:`SessionMixin`. We recommend just subclassing a dict - and adding that mixin:: - - class Session(dict, SessionMixin): - pass - - If :meth:`open_session` returns ``None`` Flask will call into - :meth:`make_null_session` to create a session that acts as replacement - if the session support cannot work because some requirement is not - fulfilled. The default :class:`NullSession` class that is created - will complain that the secret key was not set. - - To replace the session interface on an application all you have to do - is to assign :attr:`flask.Flask.session_interface`:: - - app = Flask(__name__) - app.session_interface = MySessionInterface() - - Multiple requests with the same session may be sent and handled - concurrently. When implementing a new session interface, consider - whether reads or writes to the backing store must be synchronized. - There is no guarantee on the order in which the session for each - request is opened or saved, it will occur in the order that requests - begin and end processing. - - .. versionadded:: 0.8 - """ - - #: :meth:`make_null_session` will look here for the class that should - #: be created when a null session is requested. Likewise the - #: :meth:`is_null_session` method will perform a typecheck against - #: this type. - null_session_class = NullSession - - #: A flag that indicates if the session interface is pickle based. - #: This can be used by Flask extensions to make a decision in regards - #: to how to deal with the session object. - #: - #: .. versionadded:: 0.10 - pickle_based = False - - def make_null_session(self, app: Flask) -> NullSession: - """Creates a null session which acts as a replacement object if the - real session support could not be loaded due to a configuration - error. This mainly aids the user experience because the job of the - null session is to still support lookup without complaining but - modifications are answered with a helpful error message of what - failed. - - This creates an instance of :attr:`null_session_class` by default. - """ - return self.null_session_class() - - def is_null_session(self, obj: object) -> bool: - """Checks if a given object is a null session. Null sessions are - not asked to be saved. - - This checks if the object is an instance of :attr:`null_session_class` - by default. - """ - return isinstance(obj, self.null_session_class) - - def get_cookie_name(self, app: Flask) -> str: - """The name of the session cookie. Uses``app.config["SESSION_COOKIE_NAME"]``.""" - return app.config["SESSION_COOKIE_NAME"] # type: ignore[no-any-return] - - def get_cookie_domain(self, app: Flask) -> str | None: - """The value of the ``Domain`` parameter on the session cookie. If not set, - browsers will only send the cookie to the exact domain it was set from. - Otherwise, they will send it to any subdomain of the given value as well. - - Uses the :data:`SESSION_COOKIE_DOMAIN` config. - - .. versionchanged:: 2.3 - Not set by default, does not fall back to ``SERVER_NAME``. - """ - return app.config["SESSION_COOKIE_DOMAIN"] # type: ignore[no-any-return] - - def get_cookie_path(self, app: Flask) -> str: - """Returns the path for which the cookie should be valid. The - default implementation uses the value from the ``SESSION_COOKIE_PATH`` - config var if it's set, and falls back to ``APPLICATION_ROOT`` or - uses ``/`` if it's ``None``. - """ - return app.config["SESSION_COOKIE_PATH"] or app.config["APPLICATION_ROOT"] # type: ignore[no-any-return] - - def get_cookie_httponly(self, app: Flask) -> bool: - """Returns True if the session cookie should be httponly. This - currently just returns the value of the ``SESSION_COOKIE_HTTPONLY`` - config var. - """ - return app.config["SESSION_COOKIE_HTTPONLY"] # type: ignore[no-any-return] - - def get_cookie_secure(self, app: Flask) -> bool: - """Returns True if the cookie should be secure. This currently - just returns the value of the ``SESSION_COOKIE_SECURE`` setting. - """ - return app.config["SESSION_COOKIE_SECURE"] # type: ignore[no-any-return] - - def get_cookie_samesite(self, app: Flask) -> str | None: - """Return ``'Strict'`` or ``'Lax'`` if the cookie should use the - ``SameSite`` attribute. This currently just returns the value of - the :data:`SESSION_COOKIE_SAMESITE` setting. - """ - return app.config["SESSION_COOKIE_SAMESITE"] # type: ignore[no-any-return] - - def get_cookie_partitioned(self, app: Flask) -> bool: - """Returns True if the cookie should be partitioned. By default, uses - the value of :data:`SESSION_COOKIE_PARTITIONED`. - - .. versionadded:: 3.1 - """ - return app.config["SESSION_COOKIE_PARTITIONED"] # type: ignore[no-any-return] - - def get_expiration_time(self, app: Flask, session: SessionMixin) -> datetime | None: - """A helper method that returns an expiration date for the session - or ``None`` if the session is linked to the browser session. The - default implementation returns now + the permanent session - lifetime configured on the application. - """ - if session.permanent: - return datetime.now(timezone.utc) + app.permanent_session_lifetime - return None - - def should_set_cookie(self, app: Flask, session: SessionMixin) -> bool: - """Used by session backends to determine if a ``Set-Cookie`` header - should be set for this session cookie for this response. If the session - has been modified, the cookie is set. If the session is permanent and - the ``SESSION_REFRESH_EACH_REQUEST`` config is true, the cookie is - always set. - - This check is usually skipped if the session was deleted. - - .. versionadded:: 0.11 - """ - - return session.modified or ( - session.permanent and app.config["SESSION_REFRESH_EACH_REQUEST"] - ) - - def open_session(self, app: Flask, request: Request) -> SessionMixin | None: - """This is called at the beginning of each request, after - pushing the request context, before matching the URL. - - This must return an object which implements a dictionary-like - interface as well as the :class:`SessionMixin` interface. - - This will return ``None`` to indicate that loading failed in - some way that is not immediately an error. The request - context will fall back to using :meth:`make_null_session` - in this case. - """ - raise NotImplementedError() - - def save_session( - self, app: Flask, session: SessionMixin, response: Response - ) -> None: - """This is called at the end of each request, after generating - a response, before removing the request context. It is skipped - if :meth:`is_null_session` returns ``True``. - """ - raise NotImplementedError() - - -session_json_serializer = TaggedJSONSerializer() - - -def _lazy_sha1(string: bytes = b"") -> t.Any: - """Don't access ``hashlib.sha1`` until runtime. FIPS builds may not include - SHA-1, in which case the import and use as a default would fail before the - developer can configure something else. - """ - return hashlib.sha1(string) - - -class SecureCookieSessionInterface(SessionInterface): - """The default session interface that stores sessions in signed cookies - through the :mod:`itsdangerous` module. - """ - - #: the salt that should be applied on top of the secret key for the - #: signing of cookie based sessions. - salt = "cookie-session" - #: the hash function to use for the signature. The default is sha1 - digest_method = staticmethod(_lazy_sha1) - #: the name of the itsdangerous supported key derivation. The default - #: is hmac. - key_derivation = "hmac" - #: A python serializer for the payload. The default is a compact - #: JSON derived serializer with support for some extra Python types - #: such as datetime objects or tuples. - serializer = session_json_serializer - session_class = SecureCookieSession - - def get_signing_serializer(self, app: Flask) -> URLSafeTimedSerializer | None: - if not app.secret_key: - return None - - keys: list[str | bytes] = [] - - if fallbacks := app.config["SECRET_KEY_FALLBACKS"]: - keys.extend(fallbacks) - - keys.append(app.secret_key) # itsdangerous expects current key at top - return URLSafeTimedSerializer( - keys, # type: ignore[arg-type] - salt=self.salt, - serializer=self.serializer, - signer_kwargs={ - "key_derivation": self.key_derivation, - "digest_method": self.digest_method, - }, - ) - - def open_session(self, app: Flask, request: Request) -> SecureCookieSession | None: - s = self.get_signing_serializer(app) - if s is None: - return None - val = request.cookies.get(self.get_cookie_name(app)) - if not val: - return self.session_class() - max_age = int(app.permanent_session_lifetime.total_seconds()) - try: - data = s.loads(val, max_age=max_age) - return self.session_class(data) - except BadSignature: - return self.session_class() - - def save_session( - self, app: Flask, session: SessionMixin, response: Response - ) -> None: - name = self.get_cookie_name(app) - domain = self.get_cookie_domain(app) - path = self.get_cookie_path(app) - secure = self.get_cookie_secure(app) - partitioned = self.get_cookie_partitioned(app) - samesite = self.get_cookie_samesite(app) - httponly = self.get_cookie_httponly(app) - - # Add a "Vary: Cookie" header if the session was accessed at all. - if session.accessed: - response.vary.add("Cookie") - - # If the session is modified to be empty, remove the cookie. - # If the session is empty, return without setting the cookie. - if not session: - if session.modified: - response.delete_cookie( - name, - domain=domain, - path=path, - secure=secure, - partitioned=partitioned, - samesite=samesite, - httponly=httponly, - ) - response.vary.add("Cookie") - - return - - if not self.should_set_cookie(app, session): - return - - expires = self.get_expiration_time(app, session) - val = self.get_signing_serializer(app).dumps(dict(session)) # type: ignore[union-attr] - response.set_cookie( - name, - val, - expires=expires, - httponly=httponly, - domain=domain, - path=path, - secure=secure, - partitioned=partitioned, - samesite=samesite, - ) - response.vary.add("Cookie") diff --git a/venv/lib/python3.9/site-packages/flask/signals.py b/venv/lib/python3.9/site-packages/flask/signals.py deleted file mode 100644 index 444fda9..0000000 --- a/venv/lib/python3.9/site-packages/flask/signals.py +++ /dev/null @@ -1,17 +0,0 @@ -from __future__ import annotations - -from blinker import Namespace - -# This namespace is only for signals provided by Flask itself. -_signals = Namespace() - -template_rendered = _signals.signal("template-rendered") -before_render_template = _signals.signal("before-render-template") -request_started = _signals.signal("request-started") -request_finished = _signals.signal("request-finished") -request_tearing_down = _signals.signal("request-tearing-down") -got_request_exception = _signals.signal("got-request-exception") -appcontext_tearing_down = _signals.signal("appcontext-tearing-down") -appcontext_pushed = _signals.signal("appcontext-pushed") -appcontext_popped = _signals.signal("appcontext-popped") -message_flashed = _signals.signal("message-flashed") diff --git a/venv/lib/python3.9/site-packages/flask/templating.py b/venv/lib/python3.9/site-packages/flask/templating.py deleted file mode 100644 index c5fb5b9..0000000 --- a/venv/lib/python3.9/site-packages/flask/templating.py +++ /dev/null @@ -1,220 +0,0 @@ -from __future__ import annotations - -import typing as t - -from jinja2 import BaseLoader -from jinja2 import Environment as BaseEnvironment -from jinja2 import Template -from jinja2 import TemplateNotFound - -from .globals import _cv_app -from .globals import _cv_request -from .globals import current_app -from .globals import request -from .helpers import stream_with_context -from .signals import before_render_template -from .signals import template_rendered - -if t.TYPE_CHECKING: # pragma: no cover - from .app import Flask - from .sansio.app import App - from .sansio.scaffold import Scaffold - - -def _default_template_ctx_processor() -> dict[str, t.Any]: - """Default template context processor. Replaces the ``request`` and ``g`` - proxies with their concrete objects for faster access. - """ - appctx = _cv_app.get(None) - reqctx = _cv_request.get(None) - rv: dict[str, t.Any] = {} - if appctx is not None: - rv["g"] = appctx.g - if reqctx is not None: - rv["request"] = reqctx.request - # The session proxy cannot be replaced, accessing it gets - # RequestContext.session, which sets session.accessed. - return rv - - -class Environment(BaseEnvironment): - """Works like a regular Jinja environment but has some additional - knowledge of how Flask's blueprint works so that it can prepend the - name of the blueprint to referenced templates if necessary. - """ - - def __init__(self, app: App, **options: t.Any) -> None: - if "loader" not in options: - options["loader"] = app.create_global_jinja_loader() - BaseEnvironment.__init__(self, **options) - self.app = app - - -class DispatchingJinjaLoader(BaseLoader): - """A loader that looks for templates in the application and all - the blueprint folders. - """ - - def __init__(self, app: App) -> None: - self.app = app - - def get_source( - self, environment: BaseEnvironment, template: str - ) -> tuple[str, str | None, t.Callable[[], bool] | None]: - if self.app.config["EXPLAIN_TEMPLATE_LOADING"]: - return self._get_source_explained(environment, template) - return self._get_source_fast(environment, template) - - def _get_source_explained( - self, environment: BaseEnvironment, template: str - ) -> tuple[str, str | None, t.Callable[[], bool] | None]: - attempts = [] - rv: tuple[str, str | None, t.Callable[[], bool] | None] | None - trv: None | (tuple[str, str | None, t.Callable[[], bool] | None]) = None - - for srcobj, loader in self._iter_loaders(template): - try: - rv = loader.get_source(environment, template) - if trv is None: - trv = rv - except TemplateNotFound: - rv = None - attempts.append((loader, srcobj, rv)) - - from .debughelpers import explain_template_loading_attempts - - explain_template_loading_attempts(self.app, template, attempts) - - if trv is not None: - return trv - raise TemplateNotFound(template) - - def _get_source_fast( - self, environment: BaseEnvironment, template: str - ) -> tuple[str, str | None, t.Callable[[], bool] | None]: - for _srcobj, loader in self._iter_loaders(template): - try: - return loader.get_source(environment, template) - except TemplateNotFound: - continue - raise TemplateNotFound(template) - - def _iter_loaders(self, template: str) -> t.Iterator[tuple[Scaffold, BaseLoader]]: - loader = self.app.jinja_loader - if loader is not None: - yield self.app, loader - - for blueprint in self.app.iter_blueprints(): - loader = blueprint.jinja_loader - if loader is not None: - yield blueprint, loader - - def list_templates(self) -> list[str]: - result = set() - loader = self.app.jinja_loader - if loader is not None: - result.update(loader.list_templates()) - - for blueprint in self.app.iter_blueprints(): - loader = blueprint.jinja_loader - if loader is not None: - for template in loader.list_templates(): - result.add(template) - - return list(result) - - -def _render(app: Flask, template: Template, context: dict[str, t.Any]) -> str: - app.update_template_context(context) - before_render_template.send( - app, _async_wrapper=app.ensure_sync, template=template, context=context - ) - rv = template.render(context) - template_rendered.send( - app, _async_wrapper=app.ensure_sync, template=template, context=context - ) - return rv - - -def render_template( - template_name_or_list: str | Template | list[str | Template], - **context: t.Any, -) -> str: - """Render a template by name with the given context. - - :param template_name_or_list: The name of the template to render. If - a list is given, the first name to exist will be rendered. - :param context: The variables to make available in the template. - """ - app = current_app._get_current_object() # type: ignore[attr-defined] - template = app.jinja_env.get_or_select_template(template_name_or_list) - return _render(app, template, context) - - -def render_template_string(source: str, **context: t.Any) -> str: - """Render a template from the given source string with the given - context. - - :param source: The source code of the template to render. - :param context: The variables to make available in the template. - """ - app = current_app._get_current_object() # type: ignore[attr-defined] - template = app.jinja_env.from_string(source) - return _render(app, template, context) - - -def _stream( - app: Flask, template: Template, context: dict[str, t.Any] -) -> t.Iterator[str]: - app.update_template_context(context) - before_render_template.send( - app, _async_wrapper=app.ensure_sync, template=template, context=context - ) - - def generate() -> t.Iterator[str]: - yield from template.generate(context) - template_rendered.send( - app, _async_wrapper=app.ensure_sync, template=template, context=context - ) - - rv = generate() - - # If a request context is active, keep it while generating. - if request: - rv = stream_with_context(rv) - - return rv - - -def stream_template( - template_name_or_list: str | Template | list[str | Template], - **context: t.Any, -) -> t.Iterator[str]: - """Render a template by name with the given context as a stream. - This returns an iterator of strings, which can be used as a - streaming response from a view. - - :param template_name_or_list: The name of the template to render. If - a list is given, the first name to exist will be rendered. - :param context: The variables to make available in the template. - - .. versionadded:: 2.2 - """ - app = current_app._get_current_object() # type: ignore[attr-defined] - template = app.jinja_env.get_or_select_template(template_name_or_list) - return _stream(app, template, context) - - -def stream_template_string(source: str, **context: t.Any) -> t.Iterator[str]: - """Render a template from the given source string with the given - context as a stream. This returns an iterator of strings, which can - be used as a streaming response from a view. - - :param source: The source code of the template to render. - :param context: The variables to make available in the template. - - .. versionadded:: 2.2 - """ - app = current_app._get_current_object() # type: ignore[attr-defined] - template = app.jinja_env.from_string(source) - return _stream(app, template, context) diff --git a/venv/lib/python3.9/site-packages/flask/testing.py b/venv/lib/python3.9/site-packages/flask/testing.py deleted file mode 100644 index 55eb12f..0000000 --- a/venv/lib/python3.9/site-packages/flask/testing.py +++ /dev/null @@ -1,298 +0,0 @@ -from __future__ import annotations - -import importlib.metadata -import typing as t -from contextlib import contextmanager -from contextlib import ExitStack -from copy import copy -from types import TracebackType -from urllib.parse import urlsplit - -import werkzeug.test -from click.testing import CliRunner -from click.testing import Result -from werkzeug.test import Client -from werkzeug.wrappers import Request as BaseRequest - -from .cli import ScriptInfo -from .sessions import SessionMixin - -if t.TYPE_CHECKING: # pragma: no cover - from _typeshed.wsgi import WSGIEnvironment - from werkzeug.test import TestResponse - - from .app import Flask - - -class EnvironBuilder(werkzeug.test.EnvironBuilder): - """An :class:`~werkzeug.test.EnvironBuilder`, that takes defaults from the - application. - - :param app: The Flask application to configure the environment from. - :param path: URL path being requested. - :param base_url: Base URL where the app is being served, which - ``path`` is relative to. If not given, built from - :data:`PREFERRED_URL_SCHEME`, ``subdomain``, - :data:`SERVER_NAME`, and :data:`APPLICATION_ROOT`. - :param subdomain: Subdomain name to append to :data:`SERVER_NAME`. - :param url_scheme: Scheme to use instead of - :data:`PREFERRED_URL_SCHEME`. - :param json: If given, this is serialized as JSON and passed as - ``data``. Also defaults ``content_type`` to - ``application/json``. - :param args: other positional arguments passed to - :class:`~werkzeug.test.EnvironBuilder`. - :param kwargs: other keyword arguments passed to - :class:`~werkzeug.test.EnvironBuilder`. - """ - - def __init__( - self, - app: Flask, - path: str = "/", - base_url: str | None = None, - subdomain: str | None = None, - url_scheme: str | None = None, - *args: t.Any, - **kwargs: t.Any, - ) -> None: - assert not (base_url or subdomain or url_scheme) or ( - base_url is not None - ) != bool(subdomain or url_scheme), ( - 'Cannot pass "subdomain" or "url_scheme" with "base_url".' - ) - - if base_url is None: - http_host = app.config.get("SERVER_NAME") or "localhost" - app_root = app.config["APPLICATION_ROOT"] - - if subdomain: - http_host = f"{subdomain}.{http_host}" - - if url_scheme is None: - url_scheme = app.config["PREFERRED_URL_SCHEME"] - - url = urlsplit(path) - base_url = ( - f"{url.scheme or url_scheme}://{url.netloc or http_host}" - f"/{app_root.lstrip('/')}" - ) - path = url.path - - if url.query: - path = f"{path}?{url.query}" - - self.app = app - super().__init__(path, base_url, *args, **kwargs) - - def json_dumps(self, obj: t.Any, **kwargs: t.Any) -> str: - """Serialize ``obj`` to a JSON-formatted string. - - The serialization will be configured according to the config associated - with this EnvironBuilder's ``app``. - """ - return self.app.json.dumps(obj, **kwargs) - - -_werkzeug_version = "" - - -def _get_werkzeug_version() -> str: - global _werkzeug_version - - if not _werkzeug_version: - _werkzeug_version = importlib.metadata.version("werkzeug") - - return _werkzeug_version - - -class FlaskClient(Client): - """Works like a regular Werkzeug test client but has knowledge about - Flask's contexts to defer the cleanup of the request context until - the end of a ``with`` block. For general information about how to - use this class refer to :class:`werkzeug.test.Client`. - - .. versionchanged:: 0.12 - `app.test_client()` includes preset default environment, which can be - set after instantiation of the `app.test_client()` object in - `client.environ_base`. - - Basic usage is outlined in the :doc:`/testing` chapter. - """ - - application: Flask - - def __init__(self, *args: t.Any, **kwargs: t.Any) -> None: - super().__init__(*args, **kwargs) - self.preserve_context = False - self._new_contexts: list[t.ContextManager[t.Any]] = [] - self._context_stack = ExitStack() - self.environ_base = { - "REMOTE_ADDR": "127.0.0.1", - "HTTP_USER_AGENT": f"Werkzeug/{_get_werkzeug_version()}", - } - - @contextmanager - def session_transaction( - self, *args: t.Any, **kwargs: t.Any - ) -> t.Iterator[SessionMixin]: - """When used in combination with a ``with`` statement this opens a - session transaction. This can be used to modify the session that - the test client uses. Once the ``with`` block is left the session is - stored back. - - :: - - with client.session_transaction() as session: - session['value'] = 42 - - Internally this is implemented by going through a temporary test - request context and since session handling could depend on - request variables this function accepts the same arguments as - :meth:`~flask.Flask.test_request_context` which are directly - passed through. - """ - if self._cookies is None: - raise TypeError( - "Cookies are disabled. Create a client with 'use_cookies=True'." - ) - - app = self.application - ctx = app.test_request_context(*args, **kwargs) - self._add_cookies_to_wsgi(ctx.request.environ) - - with ctx: - sess = app.session_interface.open_session(app, ctx.request) - - if sess is None: - raise RuntimeError("Session backend did not open a session.") - - yield sess - resp = app.response_class() - - if app.session_interface.is_null_session(sess): - return - - with ctx: - app.session_interface.save_session(app, sess, resp) - - self._update_cookies_from_response( - ctx.request.host.partition(":")[0], - ctx.request.path, - resp.headers.getlist("Set-Cookie"), - ) - - def _copy_environ(self, other: WSGIEnvironment) -> WSGIEnvironment: - out = {**self.environ_base, **other} - - if self.preserve_context: - out["werkzeug.debug.preserve_context"] = self._new_contexts.append - - return out - - def _request_from_builder_args( - self, args: tuple[t.Any, ...], kwargs: dict[str, t.Any] - ) -> BaseRequest: - kwargs["environ_base"] = self._copy_environ(kwargs.get("environ_base", {})) - builder = EnvironBuilder(self.application, *args, **kwargs) - - try: - return builder.get_request() - finally: - builder.close() - - def open( - self, - *args: t.Any, - buffered: bool = False, - follow_redirects: bool = False, - **kwargs: t.Any, - ) -> TestResponse: - if args and isinstance( - args[0], (werkzeug.test.EnvironBuilder, dict, BaseRequest) - ): - if isinstance(args[0], werkzeug.test.EnvironBuilder): - builder = copy(args[0]) - builder.environ_base = self._copy_environ(builder.environ_base or {}) # type: ignore[arg-type] - request = builder.get_request() - elif isinstance(args[0], dict): - request = EnvironBuilder.from_environ( - args[0], app=self.application, environ_base=self._copy_environ({}) - ).get_request() - else: - # isinstance(args[0], BaseRequest) - request = copy(args[0]) - request.environ = self._copy_environ(request.environ) - else: - # request is None - request = self._request_from_builder_args(args, kwargs) - - # Pop any previously preserved contexts. This prevents contexts - # from being preserved across redirects or multiple requests - # within a single block. - self._context_stack.close() - - response = super().open( - request, - buffered=buffered, - follow_redirects=follow_redirects, - ) - response.json_module = self.application.json # type: ignore[assignment] - - # Re-push contexts that were preserved during the request. - for cm in self._new_contexts: - self._context_stack.enter_context(cm) - - self._new_contexts.clear() - return response - - def __enter__(self) -> FlaskClient: - if self.preserve_context: - raise RuntimeError("Cannot nest client invocations") - self.preserve_context = True - return self - - def __exit__( - self, - exc_type: type | None, - exc_value: BaseException | None, - tb: TracebackType | None, - ) -> None: - self.preserve_context = False - self._context_stack.close() - - -class FlaskCliRunner(CliRunner): - """A :class:`~click.testing.CliRunner` for testing a Flask app's - CLI commands. Typically created using - :meth:`~flask.Flask.test_cli_runner`. See :ref:`testing-cli`. - """ - - def __init__(self, app: Flask, **kwargs: t.Any) -> None: - self.app = app - super().__init__(**kwargs) - - def invoke( # type: ignore - self, cli: t.Any = None, args: t.Any = None, **kwargs: t.Any - ) -> Result: - """Invokes a CLI command in an isolated environment. See - :meth:`CliRunner.invoke ` for - full method documentation. See :ref:`testing-cli` for examples. - - If the ``obj`` argument is not given, passes an instance of - :class:`~flask.cli.ScriptInfo` that knows how to load the Flask - app being tested. - - :param cli: Command object to invoke. Default is the app's - :attr:`~flask.app.Flask.cli` group. - :param args: List of strings to invoke the command with. - - :return: a :class:`~click.testing.Result` object. - """ - if cli is None: - cli = self.app.cli - - if "obj" not in kwargs: - kwargs["obj"] = ScriptInfo(create_app=lambda: self.app) - - return super().invoke(cli, args, **kwargs) diff --git a/venv/lib/python3.9/site-packages/flask/typing.py b/venv/lib/python3.9/site-packages/flask/typing.py deleted file mode 100644 index 6b70c40..0000000 --- a/venv/lib/python3.9/site-packages/flask/typing.py +++ /dev/null @@ -1,93 +0,0 @@ -from __future__ import annotations - -import collections.abc as cabc -import typing as t - -if t.TYPE_CHECKING: # pragma: no cover - from _typeshed.wsgi import WSGIApplication # noqa: F401 - from werkzeug.datastructures import Headers # noqa: F401 - from werkzeug.sansio.response import Response # noqa: F401 - -# The possible types that are directly convertible or are a Response object. -ResponseValue = t.Union[ - "Response", - str, - bytes, - list[t.Any], - # Only dict is actually accepted, but Mapping allows for TypedDict. - t.Mapping[str, t.Any], - t.Iterator[str], - t.Iterator[bytes], - cabc.AsyncIterable[str], # for Quart, until App is generic. - cabc.AsyncIterable[bytes], -] - -# the possible types for an individual HTTP header -# This should be a Union, but mypy doesn't pass unless it's a TypeVar. -HeaderValue = t.Union[str, list[str], tuple[str, ...]] - -# the possible types for HTTP headers -HeadersValue = t.Union[ - "Headers", - t.Mapping[str, HeaderValue], - t.Sequence[tuple[str, HeaderValue]], -] - -# The possible types returned by a route function. -ResponseReturnValue = t.Union[ - ResponseValue, - tuple[ResponseValue, HeadersValue], - tuple[ResponseValue, int], - tuple[ResponseValue, int, HeadersValue], - "WSGIApplication", -] - -# Allow any subclass of werkzeug.Response, such as the one from Flask, -# as a callback argument. Using werkzeug.Response directly makes a -# callback annotated with flask.Response fail type checking. -ResponseClass = t.TypeVar("ResponseClass", bound="Response") - -AppOrBlueprintKey = t.Optional[str] # The App key is None, whereas blueprints are named -AfterRequestCallable = t.Union[ - t.Callable[[ResponseClass], ResponseClass], - t.Callable[[ResponseClass], t.Awaitable[ResponseClass]], -] -BeforeFirstRequestCallable = t.Union[ - t.Callable[[], None], t.Callable[[], t.Awaitable[None]] -] -BeforeRequestCallable = t.Union[ - t.Callable[[], t.Optional[ResponseReturnValue]], - t.Callable[[], t.Awaitable[t.Optional[ResponseReturnValue]]], -] -ShellContextProcessorCallable = t.Callable[[], dict[str, t.Any]] -TeardownCallable = t.Union[ - t.Callable[[t.Optional[BaseException]], None], - t.Callable[[t.Optional[BaseException]], t.Awaitable[None]], -] -TemplateContextProcessorCallable = t.Union[ - t.Callable[[], dict[str, t.Any]], - t.Callable[[], t.Awaitable[dict[str, t.Any]]], -] -TemplateFilterCallable = t.Callable[..., t.Any] -TemplateGlobalCallable = t.Callable[..., t.Any] -TemplateTestCallable = t.Callable[..., bool] -URLDefaultCallable = t.Callable[[str, dict[str, t.Any]], None] -URLValuePreprocessorCallable = t.Callable[ - [t.Optional[str], t.Optional[dict[str, t.Any]]], None -] - -# This should take Exception, but that either breaks typing the argument -# with a specific exception, or decorating multiple times with different -# exceptions (and using a union type on the argument). -# https://github.com/pallets/flask/issues/4095 -# https://github.com/pallets/flask/issues/4295 -# https://github.com/pallets/flask/issues/4297 -ErrorHandlerCallable = t.Union[ - t.Callable[[t.Any], ResponseReturnValue], - t.Callable[[t.Any], t.Awaitable[ResponseReturnValue]], -] - -RouteCallable = t.Union[ - t.Callable[..., ResponseReturnValue], - t.Callable[..., t.Awaitable[ResponseReturnValue]], -] diff --git a/venv/lib/python3.9/site-packages/flask/views.py b/venv/lib/python3.9/site-packages/flask/views.py deleted file mode 100644 index 53fe976..0000000 --- a/venv/lib/python3.9/site-packages/flask/views.py +++ /dev/null @@ -1,191 +0,0 @@ -from __future__ import annotations - -import typing as t - -from . import typing as ft -from .globals import current_app -from .globals import request - -F = t.TypeVar("F", bound=t.Callable[..., t.Any]) - -http_method_funcs = frozenset( - ["get", "post", "head", "options", "delete", "put", "trace", "patch"] -) - - -class View: - """Subclass this class and override :meth:`dispatch_request` to - create a generic class-based view. Call :meth:`as_view` to create a - view function that creates an instance of the class with the given - arguments and calls its ``dispatch_request`` method with any URL - variables. - - See :doc:`views` for a detailed guide. - - .. code-block:: python - - class Hello(View): - init_every_request = False - - def dispatch_request(self, name): - return f"Hello, {name}!" - - app.add_url_rule( - "/hello/", view_func=Hello.as_view("hello") - ) - - Set :attr:`methods` on the class to change what methods the view - accepts. - - Set :attr:`decorators` on the class to apply a list of decorators to - the generated view function. Decorators applied to the class itself - will not be applied to the generated view function! - - Set :attr:`init_every_request` to ``False`` for efficiency, unless - you need to store request-global data on ``self``. - """ - - #: The methods this view is registered for. Uses the same default - #: (``["GET", "HEAD", "OPTIONS"]``) as ``route`` and - #: ``add_url_rule`` by default. - methods: t.ClassVar[t.Collection[str] | None] = None - - #: Control whether the ``OPTIONS`` method is handled automatically. - #: Uses the same default (``True``) as ``route`` and - #: ``add_url_rule`` by default. - provide_automatic_options: t.ClassVar[bool | None] = None - - #: A list of decorators to apply, in order, to the generated view - #: function. Remember that ``@decorator`` syntax is applied bottom - #: to top, so the first decorator in the list would be the bottom - #: decorator. - #: - #: .. versionadded:: 0.8 - decorators: t.ClassVar[list[t.Callable[..., t.Any]]] = [] - - #: Create a new instance of this view class for every request by - #: default. If a view subclass sets this to ``False``, the same - #: instance is used for every request. - #: - #: A single instance is more efficient, especially if complex setup - #: is done during init. However, storing data on ``self`` is no - #: longer safe across requests, and :data:`~flask.g` should be used - #: instead. - #: - #: .. versionadded:: 2.2 - init_every_request: t.ClassVar[bool] = True - - def dispatch_request(self) -> ft.ResponseReturnValue: - """The actual view function behavior. Subclasses must override - this and return a valid response. Any variables from the URL - rule are passed as keyword arguments. - """ - raise NotImplementedError() - - @classmethod - def as_view( - cls, name: str, *class_args: t.Any, **class_kwargs: t.Any - ) -> ft.RouteCallable: - """Convert the class into a view function that can be registered - for a route. - - By default, the generated view will create a new instance of the - view class for every request and call its - :meth:`dispatch_request` method. If the view class sets - :attr:`init_every_request` to ``False``, the same instance will - be used for every request. - - Except for ``name``, all other arguments passed to this method - are forwarded to the view class ``__init__`` method. - - .. versionchanged:: 2.2 - Added the ``init_every_request`` class attribute. - """ - if cls.init_every_request: - - def view(**kwargs: t.Any) -> ft.ResponseReturnValue: - self = view.view_class( # type: ignore[attr-defined] - *class_args, **class_kwargs - ) - return current_app.ensure_sync(self.dispatch_request)(**kwargs) # type: ignore[no-any-return] - - else: - self = cls(*class_args, **class_kwargs) # pyright: ignore - - def view(**kwargs: t.Any) -> ft.ResponseReturnValue: - return current_app.ensure_sync(self.dispatch_request)(**kwargs) # type: ignore[no-any-return] - - if cls.decorators: - view.__name__ = name - view.__module__ = cls.__module__ - for decorator in cls.decorators: - view = decorator(view) - - # We attach the view class to the view function for two reasons: - # first of all it allows us to easily figure out what class-based - # view this thing came from, secondly it's also used for instantiating - # the view class so you can actually replace it with something else - # for testing purposes and debugging. - view.view_class = cls # type: ignore - view.__name__ = name - view.__doc__ = cls.__doc__ - view.__module__ = cls.__module__ - view.methods = cls.methods # type: ignore - view.provide_automatic_options = cls.provide_automatic_options # type: ignore - return view - - -class MethodView(View): - """Dispatches request methods to the corresponding instance methods. - For example, if you implement a ``get`` method, it will be used to - handle ``GET`` requests. - - This can be useful for defining a REST API. - - :attr:`methods` is automatically set based on the methods defined on - the class. - - See :doc:`views` for a detailed guide. - - .. code-block:: python - - class CounterAPI(MethodView): - def get(self): - return str(session.get("counter", 0)) - - def post(self): - session["counter"] = session.get("counter", 0) + 1 - return redirect(url_for("counter")) - - app.add_url_rule( - "/counter", view_func=CounterAPI.as_view("counter") - ) - """ - - def __init_subclass__(cls, **kwargs: t.Any) -> None: - super().__init_subclass__(**kwargs) - - if "methods" not in cls.__dict__: - methods = set() - - for base in cls.__bases__: - if getattr(base, "methods", None): - methods.update(base.methods) # type: ignore[attr-defined] - - for key in http_method_funcs: - if hasattr(cls, key): - methods.add(key.upper()) - - if methods: - cls.methods = methods - - def dispatch_request(self, **kwargs: t.Any) -> ft.ResponseReturnValue: - meth = getattr(self, request.method.lower(), None) - - # If the request method is HEAD and we don't have a handler for it - # retry with GET. - if meth is None and request.method == "HEAD": - meth = getattr(self, "get", None) - - assert meth is not None, f"Unimplemented method {request.method!r}" - return current_app.ensure_sync(meth)(**kwargs) # type: ignore[no-any-return] diff --git a/venv/lib/python3.9/site-packages/flask/wrappers.py b/venv/lib/python3.9/site-packages/flask/wrappers.py deleted file mode 100644 index bab6102..0000000 --- a/venv/lib/python3.9/site-packages/flask/wrappers.py +++ /dev/null @@ -1,257 +0,0 @@ -from __future__ import annotations - -import typing as t - -from werkzeug.exceptions import BadRequest -from werkzeug.exceptions import HTTPException -from werkzeug.wrappers import Request as RequestBase -from werkzeug.wrappers import Response as ResponseBase - -from . import json -from .globals import current_app -from .helpers import _split_blueprint_path - -if t.TYPE_CHECKING: # pragma: no cover - from werkzeug.routing import Rule - - -class Request(RequestBase): - """The request object used by default in Flask. Remembers the - matched endpoint and view arguments. - - It is what ends up as :class:`~flask.request`. If you want to replace - the request object used you can subclass this and set - :attr:`~flask.Flask.request_class` to your subclass. - - The request object is a :class:`~werkzeug.wrappers.Request` subclass and - provides all of the attributes Werkzeug defines plus a few Flask - specific ones. - """ - - json_module: t.Any = json - - #: The internal URL rule that matched the request. This can be - #: useful to inspect which methods are allowed for the URL from - #: a before/after handler (``request.url_rule.methods``) etc. - #: Though if the request's method was invalid for the URL rule, - #: the valid list is available in ``routing_exception.valid_methods`` - #: instead (an attribute of the Werkzeug exception - #: :exc:`~werkzeug.exceptions.MethodNotAllowed`) - #: because the request was never internally bound. - #: - #: .. versionadded:: 0.6 - url_rule: Rule | None = None - - #: A dict of view arguments that matched the request. If an exception - #: happened when matching, this will be ``None``. - view_args: dict[str, t.Any] | None = None - - #: If matching the URL failed, this is the exception that will be - #: raised / was raised as part of the request handling. This is - #: usually a :exc:`~werkzeug.exceptions.NotFound` exception or - #: something similar. - routing_exception: HTTPException | None = None - - _max_content_length: int | None = None - _max_form_memory_size: int | None = None - _max_form_parts: int | None = None - - @property - def max_content_length(self) -> int | None: - """The maximum number of bytes that will be read during this request. If - this limit is exceeded, a 413 :exc:`~werkzeug.exceptions.RequestEntityTooLarge` - error is raised. If it is set to ``None``, no limit is enforced at the - Flask application level. However, if it is ``None`` and the request has - no ``Content-Length`` header and the WSGI server does not indicate that - it terminates the stream, then no data is read to avoid an infinite - stream. - - Each request defaults to the :data:`MAX_CONTENT_LENGTH` config, which - defaults to ``None``. It can be set on a specific ``request`` to apply - the limit to that specific view. This should be set appropriately based - on an application's or view's specific needs. - - .. versionchanged:: 3.1 - This can be set per-request. - - .. versionchanged:: 0.6 - This is configurable through Flask config. - """ - if self._max_content_length is not None: - return self._max_content_length - - if not current_app: - return super().max_content_length - - return current_app.config["MAX_CONTENT_LENGTH"] # type: ignore[no-any-return] - - @max_content_length.setter - def max_content_length(self, value: int | None) -> None: - self._max_content_length = value - - @property - def max_form_memory_size(self) -> int | None: - """The maximum size in bytes any non-file form field may be in a - ``multipart/form-data`` body. If this limit is exceeded, a 413 - :exc:`~werkzeug.exceptions.RequestEntityTooLarge` error is raised. If it - is set to ``None``, no limit is enforced at the Flask application level. - - Each request defaults to the :data:`MAX_FORM_MEMORY_SIZE` config, which - defaults to ``500_000``. It can be set on a specific ``request`` to - apply the limit to that specific view. This should be set appropriately - based on an application's or view's specific needs. - - .. versionchanged:: 3.1 - This is configurable through Flask config. - """ - if self._max_form_memory_size is not None: - return self._max_form_memory_size - - if not current_app: - return super().max_form_memory_size - - return current_app.config["MAX_FORM_MEMORY_SIZE"] # type: ignore[no-any-return] - - @max_form_memory_size.setter - def max_form_memory_size(self, value: int | None) -> None: - self._max_form_memory_size = value - - @property # type: ignore[override] - def max_form_parts(self) -> int | None: - """The maximum number of fields that may be present in a - ``multipart/form-data`` body. If this limit is exceeded, a 413 - :exc:`~werkzeug.exceptions.RequestEntityTooLarge` error is raised. If it - is set to ``None``, no limit is enforced at the Flask application level. - - Each request defaults to the :data:`MAX_FORM_PARTS` config, which - defaults to ``1_000``. It can be set on a specific ``request`` to apply - the limit to that specific view. This should be set appropriately based - on an application's or view's specific needs. - - .. versionchanged:: 3.1 - This is configurable through Flask config. - """ - if self._max_form_parts is not None: - return self._max_form_parts - - if not current_app: - return super().max_form_parts - - return current_app.config["MAX_FORM_PARTS"] # type: ignore[no-any-return] - - @max_form_parts.setter - def max_form_parts(self, value: int | None) -> None: - self._max_form_parts = value - - @property - def endpoint(self) -> str | None: - """The endpoint that matched the request URL. - - This will be ``None`` if matching failed or has not been - performed yet. - - This in combination with :attr:`view_args` can be used to - reconstruct the same URL or a modified URL. - """ - if self.url_rule is not None: - return self.url_rule.endpoint # type: ignore[no-any-return] - - return None - - @property - def blueprint(self) -> str | None: - """The registered name of the current blueprint. - - This will be ``None`` if the endpoint is not part of a - blueprint, or if URL matching failed or has not been performed - yet. - - This does not necessarily match the name the blueprint was - created with. It may have been nested, or registered with a - different name. - """ - endpoint = self.endpoint - - if endpoint is not None and "." in endpoint: - return endpoint.rpartition(".")[0] - - return None - - @property - def blueprints(self) -> list[str]: - """The registered names of the current blueprint upwards through - parent blueprints. - - This will be an empty list if there is no current blueprint, or - if URL matching failed. - - .. versionadded:: 2.0.1 - """ - name = self.blueprint - - if name is None: - return [] - - return _split_blueprint_path(name) - - def _load_form_data(self) -> None: - super()._load_form_data() - - # In debug mode we're replacing the files multidict with an ad-hoc - # subclass that raises a different error for key errors. - if ( - current_app - and current_app.debug - and self.mimetype != "multipart/form-data" - and not self.files - ): - from .debughelpers import attach_enctype_error_multidict - - attach_enctype_error_multidict(self) - - def on_json_loading_failed(self, e: ValueError | None) -> t.Any: - try: - return super().on_json_loading_failed(e) - except BadRequest as ebr: - if current_app and current_app.debug: - raise - - raise BadRequest() from ebr - - -class Response(ResponseBase): - """The response object that is used by default in Flask. Works like the - response object from Werkzeug but is set to have an HTML mimetype by - default. Quite often you don't have to create this object yourself because - :meth:`~flask.Flask.make_response` will take care of that for you. - - If you want to replace the response object used you can subclass this and - set :attr:`~flask.Flask.response_class` to your subclass. - - .. versionchanged:: 1.0 - JSON support is added to the response, like the request. This is useful - when testing to get the test client response data as JSON. - - .. versionchanged:: 1.0 - - Added :attr:`max_cookie_size`. - """ - - default_mimetype: str | None = "text/html" - - json_module = json - - autocorrect_location_header = False - - @property - def max_cookie_size(self) -> int: # type: ignore - """Read-only view of the :data:`MAX_COOKIE_SIZE` config key. - - See :attr:`~werkzeug.wrappers.Response.max_cookie_size` in - Werkzeug's docs. - """ - if current_app: - return current_app.config["MAX_COOKIE_SIZE"] # type: ignore[no-any-return] - - # return Werkzeug's default when not in an app context - return super().max_cookie_size diff --git a/venv/lib/python3.9/site-packages/flask_socketio-5.6.1.dist-info/INSTALLER b/venv/lib/python3.9/site-packages/flask_socketio-5.6.1.dist-info/INSTALLER deleted file mode 100644 index a1b589e..0000000 --- a/venv/lib/python3.9/site-packages/flask_socketio-5.6.1.dist-info/INSTALLER +++ /dev/null @@ -1 +0,0 @@ -pip diff --git a/venv/lib/python3.9/site-packages/flask_socketio-5.6.1.dist-info/METADATA b/venv/lib/python3.9/site-packages/flask_socketio-5.6.1.dist-info/METADATA deleted file mode 100644 index e34ddf3..0000000 --- a/venv/lib/python3.9/site-packages/flask_socketio-5.6.1.dist-info/METADATA +++ /dev/null @@ -1,80 +0,0 @@ -Metadata-Version: 2.4 -Name: Flask-SocketIO -Version: 5.6.1 -Summary: Socket.IO integration for Flask applications -Author-email: Miguel Grinberg -Project-URL: Homepage, https://github.com/miguelgrinberg/flask-socketio -Project-URL: Bug Tracker, https://github.com/miguelgrinberg/flask-socketio/issues -Classifier: Environment :: Web Environment -Classifier: Intended Audience :: Developers -Classifier: Programming Language :: Python :: 3 -Classifier: License :: OSI Approved :: MIT License -Classifier: Operating System :: OS Independent -Requires-Python: >=3.8 -Description-Content-Type: text/markdown -License-File: LICENSE -Requires-Dist: blinker -Requires-Dist: click -Requires-Dist: flask -Requires-Dist: Flask>=2.1.0 -Requires-Dist: jinja2 -Requires-Dist: python-socketio>=5.12.0 -Requires-Dist: werkzeug -Provides-Extra: docs -Requires-Dist: sphinx; extra == "docs" -Requires-Dist: furo; extra == "docs" -Provides-Extra: dev -Requires-Dist: flask-login; extra == "dev" -Requires-Dist: flask-session; extra == "dev" -Requires-Dist: pytest; extra == "dev" -Requires-Dist: pytest-cov; extra == "dev" -Requires-Dist: redis; extra == "dev" -Requires-Dist: tox; extra == "dev" -Dynamic: license-file - -Flask-SocketIO -============== - -[![Build status](https://github.com/miguelgrinberg/flask-socketio/workflows/build/badge.svg)](https://github.com/miguelgrinberg/Flask-SocketIO/actions) [![codecov](https://codecov.io/gh/miguelgrinberg/flask-socketio/branch/main/graph/badge.svg)](https://codecov.io/gh/miguelgrinberg/flask-socketio) - -Socket.IO integration for Flask applications. - -Installation ------------- - -You can install this package as usual with pip: - - pip install flask-socketio - -Example -------- - -```py -from flask import Flask, render_template -from flask_socketio import SocketIO, emit - -app = Flask(__name__) -app.config['SECRET_KEY'] = 'secret!' -socketio = SocketIO(app) - -@app.route('/') -def index(): - return render_template('index.html') - -@socketio.event -def my_event(message): - emit('my response', {'data': 'got it!'}) - -if __name__ == '__main__': - socketio.run(app) -``` - -Resources ---------- - -- [Tutorial](http://blog.miguelgrinberg.com/post/easy-websockets-with-flask-and-gevent) -- [Documentation](http://flask-socketio.readthedocs.io/en/latest/) -- [PyPI](https://pypi.python.org/pypi/Flask-SocketIO) -- [Change Log](https://github.com/miguelgrinberg/Flask-SocketIO/blob/main/CHANGES.md) -- Questions? See the [questions](https://stackoverflow.com/questions/tagged/flask-socketio) others have asked on Stack Overflow, or [ask](https://stackoverflow.com/questions/ask?tags=python+flask-socketio+python-socketio) your own question. - diff --git a/venv/lib/python3.9/site-packages/flask_socketio-5.6.1.dist-info/RECORD b/venv/lib/python3.9/site-packages/flask_socketio-5.6.1.dist-info/RECORD deleted file mode 100644 index 18cd573..0000000 --- a/venv/lib/python3.9/site-packages/flask_socketio-5.6.1.dist-info/RECORD +++ /dev/null @@ -1,13 +0,0 @@ -flask_socketio-5.6.1.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 -flask_socketio-5.6.1.dist-info/METADATA,sha256=UxUoj5w97Okq7Da_t5eNKjqKPePH8742sKIKz7sApz4,2650 -flask_socketio-5.6.1.dist-info/RECORD,, -flask_socketio-5.6.1.dist-info/REQUESTED,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 -flask_socketio-5.6.1.dist-info/WHEEL,sha256=YCfwYGOYMi5Jhw2fU4yNgwErybb2IX5PEwBKV4ZbdBo,91 -flask_socketio-5.6.1.dist-info/licenses/LICENSE,sha256=aNCWbkgKjS_T1cJtACyZbvCM36KxWnfQ0LWTuavuYKQ,1082 -flask_socketio-5.6.1.dist-info/top_level.txt,sha256=C1ugzQBJ3HHUJsWGzyt70XRVOX-y4CUAR8MWKjwJOQ8,15 -flask_socketio/__init__.py,sha256=jM_b0DUuMVqujMJDqknjaUgAOagdgGlbNILdAX4rKuw,56423 -flask_socketio/__pycache__/__init__.cpython-39.pyc,, -flask_socketio/__pycache__/namespace.cpython-39.pyc,, -flask_socketio/__pycache__/test_client.cpython-39.pyc,, -flask_socketio/namespace.py,sha256=UkVryJvFYgnCMKWSF35GVfGdyh2cXRDyRbfmEPPchVA,2329 -flask_socketio/test_client.py,sha256=pyvjNemWok8WuvEMDu8KYxc0U5Hdyvek4_vbxKsLCdU,11348 diff --git a/venv/lib/python3.9/site-packages/flask_socketio-5.6.1.dist-info/REQUESTED b/venv/lib/python3.9/site-packages/flask_socketio-5.6.1.dist-info/REQUESTED deleted file mode 100644 index e69de29..0000000 diff --git a/venv/lib/python3.9/site-packages/flask_socketio-5.6.1.dist-info/WHEEL b/venv/lib/python3.9/site-packages/flask_socketio-5.6.1.dist-info/WHEEL deleted file mode 100644 index 1ef5583..0000000 --- a/venv/lib/python3.9/site-packages/flask_socketio-5.6.1.dist-info/WHEEL +++ /dev/null @@ -1,5 +0,0 @@ -Wheel-Version: 1.0 -Generator: setuptools (82.0.0) -Root-Is-Purelib: true -Tag: py3-none-any - diff --git a/venv/lib/python3.9/site-packages/flask_socketio-5.6.1.dist-info/licenses/LICENSE b/venv/lib/python3.9/site-packages/flask_socketio-5.6.1.dist-info/licenses/LICENSE deleted file mode 100644 index f5c10ab..0000000 --- a/venv/lib/python3.9/site-packages/flask_socketio-5.6.1.dist-info/licenses/LICENSE +++ /dev/null @@ -1,20 +0,0 @@ -The MIT License (MIT) - -Copyright (c) 2014 Miguel Grinberg - -Permission is hereby granted, free of charge, to any person obtaining a copy of -this software and associated documentation files (the "Software"), to deal in -the Software without restriction, including without limitation the rights to -use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of -the Software, and to permit persons to whom the Software is furnished to do so, -subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS -FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR -COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER -IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/venv/lib/python3.9/site-packages/flask_socketio-5.6.1.dist-info/top_level.txt b/venv/lib/python3.9/site-packages/flask_socketio-5.6.1.dist-info/top_level.txt deleted file mode 100755 index ba82ec3..0000000 --- a/venv/lib/python3.9/site-packages/flask_socketio-5.6.1.dist-info/top_level.txt +++ /dev/null @@ -1 +0,0 @@ -flask_socketio diff --git a/venv/lib/python3.9/site-packages/flask_socketio/__init__.py b/venv/lib/python3.9/site-packages/flask_socketio/__init__.py deleted file mode 100644 index eeee6e2..0000000 --- a/venv/lib/python3.9/site-packages/flask_socketio/__init__.py +++ /dev/null @@ -1,1148 +0,0 @@ -from functools import wraps -import os -import sys - -# make sure gevent-socketio is not installed, as it conflicts with -# python-socketio -gevent_socketio_found = True -try: - from socketio import socketio_manage # noqa: F401 -except ImportError: - gevent_socketio_found = False -if gevent_socketio_found: - print('The gevent-socketio package is incompatible with this version of ' - 'the Flask-SocketIO extension. Please uninstall it, and then ' - 'install the latest version of python-socketio in its place.') - sys.exit(1) - -import flask -from flask import has_request_context, json as flask_json -from flask.sessions import SessionMixin -import socketio -from socketio.exceptions import ConnectionRefusedError # noqa: F401 -from werkzeug.debug import DebuggedApplication -from werkzeug._reloader import run_with_reloader - -from .namespace import Namespace -from .test_client import SocketIOTestClient - - -class _SocketIOMiddleware(socketio.WSGIApp): - """This WSGI middleware simply exposes the Flask application in the WSGI - environment before executing the request. - """ - def __init__(self, socketio_app, flask_app, socketio_path='socket.io'): - self.flask_app = flask_app - super().__init__(socketio_app, flask_app.wsgi_app, - socketio_path=socketio_path) - - def __call__(self, environ, start_response): - environ = environ.copy() - environ['flask.app'] = self.flask_app - return super().__call__(environ, start_response) - - -class _ManagedSession(dict, SessionMixin): - """This class is used for user sessions that are managed by - Flask-SocketIO. It is simple dict, expanded with the Flask session - attributes.""" - pass - - -class SocketIO: - """Create a Flask-SocketIO server. - - :param app: The flask application instance. If the application instance - isn't known at the time this class is instantiated, then call - ``socketio.init_app(app)`` once the application instance is - available. - :param manage_session: If set to ``True``, this extension manages the user - session for Socket.IO events. If set to ``False``, - Flask's own session management is used. When using - Flask's cookie based sessions it is recommended that - you leave this set to the default of ``True``. When - using server-side sessions, a ``False`` setting - enables sharing the user session between HTTP routes - and Socket.IO events. - :param message_queue: A connection URL for a message queue service the - server can use for multi-process communication. A - message queue is not required when using a single - server process. - :param channel: The channel name, when using a message queue. If a channel - isn't specified, a default channel will be used. If - multiple clusters of SocketIO processes need to use the - same message queue without interfering with each other, - then each cluster should use a different channel. - :param path: The path where the Socket.IO server is exposed. Defaults to - ``'socket.io'``. Leave this as is unless you know what you are - doing. - :param resource: Alias to ``path``. - :param kwargs: Socket.IO and Engine.IO server options. - - The Socket.IO server options are detailed below: - - :param client_manager: The client manager instance that will manage the - client list. When this is omitted, the client list - is stored in an in-memory structure, so the use of - multiple connected servers is not possible. - :param logger: To enable logging set to ``True`` or pass a logger object to - use. To disable logging set to ``False``. The default is - ``False``. Note that fatal errors are logged even when - ``logger`` is ``False``. - :param serializer: The serialization method to use when transmitting - packets. Valid values are ``'default'``, ``'pickle'``, - ``'msgpack'`` and ``'cbor'``. Alternatively, a subclass - of the :class:`Packet` class with custom implementations - of the ``encode()`` and ``decode()`` methods can be - provided. Client and server must use compatible - serializers. - :param json: An alternative JSON module to use for encoding and decoding - packets. Custom json modules must have ``dumps`` and ``loads`` - functions that are compatible with the standard library - versions. This is a process-wide setting, all instantiated - servers and clients must use the same JSON module. - :param async_handlers: If set to ``True``, event handlers for a client are - executed in separate threads. To run handlers for a - client synchronously, set to ``False``. The default - is ``True``. - :param always_connect: When set to ``False``, new connections are - provisory until the connect handler returns - something other than ``False``, at which point they - are accepted. When set to ``True``, connections are - immediately accepted, and then if the connect - handler returns ``False`` a disconnect is issued. - Set to ``True`` if you need to emit events from the - connect handler and your client is confused when it - receives events before the connection acceptance. - In any other case use the default of ``False``. - :param namespaces: a list of namespaces that are accepted, in addition to - any namespaces for which handlers have been defined. The - default is `['/']`, which always accepts connections to - the default namespace. Set to `'*'` to accept all - namespaces. - - The Engine.IO server configuration supports the following settings: - - :param async_mode: The asynchronous model to use. See the Deployment - section in the documentation for a description of the - available options. Valid async modes are "threading", - "eventlet", "gevent" and "gevent_uwsgi". If this - argument is not given, "eventlet" is tried first, then - "gevent_uwsgi", then "gevent", and finally "threading". - The first async mode that has all its dependencies - installed is the one that is chosen. - :param ping_interval: The interval in seconds at which the server pings - the client. The default is 25 seconds. For advanced - control, a two element tuple can be given, where - the first number is the ping interval and the second - is a grace period added by the server. - :param ping_timeout: The time in seconds that the client waits for the - server to respond before disconnecting. The default - is 20 seconds. - :param max_http_buffer_size: The maximum size that is accepted for incoming - messages. The default is 1,000,000 bytes. In - spite of its name, the value set in this - argument is enforced for HTTP long-polling and - WebSocket connections. - :param allow_upgrades: Whether to allow transport upgrades or not. The - default is ``True``. - :param http_compression: Whether to compress packages when using the - polling transport. The default is ``True``. - :param compression_threshold: Only compress messages when their byte size - is greater than this value. The default is - 1024 bytes. - :param cookie: If set to a string, it is the name of the HTTP cookie the - server sends back tot he client containing the client - session id. If set to a dictionary, the ``'name'`` key - contains the cookie name and other keys define cookie - attributes, where the value of each attribute can be a - string, a callable with no arguments, or a boolean. If set - to ``None`` (the default), a cookie is not sent to the - client. - :param cors_allowed_origins: Origin or list of origins that are allowed to - connect to this server. Only the same origin - is allowed by default. Set this argument to - ``'*'`` or ``['*']`` to allow all origins, or - to ``[]`` to disable CORS handling. - :param cors_credentials: Whether credentials (cookies, authentication) are - allowed in requests to this server. The default - is ``True``. - :param monitor_clients: If set to ``True``, a background task will ensure - inactive clients are closed. Set to ``False`` to - disable the monitoring task (not recommended). The - default is ``True``. - :param transports: The list of allowed transports. Valid transports - are ``'polling'`` and ``'websocket'``. Defaults to - ``['polling', 'websocket']``. - :param engineio_logger: To enable Engine.IO logging set to ``True`` or pass - a logger object to use. To disable logging set to - ``False``. The default is ``False``. Note that - fatal errors are logged even when - ``engineio_logger`` is ``False``. - """ - reason = socketio.Server.reason - - def __init__(self, app=None, **kwargs): - self.server = None - self.server_options = {} - self.wsgi_server = None - self.handlers = [] - self.namespace_handlers = [] - self.exception_handlers = {} - self.default_exception_handler = None - self.manage_session = True - # We can call init_app when: - # - we were given the Flask app instance (standard initialization) - # - we were not given the app, but we were given a message_queue - # (standard initialization for auxiliary process) - # In all other cases we collect the arguments and assume the client - # will call init_app from an app factory function. - if app is not None or 'message_queue' in kwargs: - self.init_app(app, **kwargs) - else: - self.server_options.update(kwargs) - - def init_app(self, app, **kwargs): - if app is not None: - if not hasattr(app, 'extensions'): - app.extensions = {} # pragma: no cover - app.extensions['socketio'] = self - self.server_options.update(kwargs) - self.manage_session = self.server_options.pop('manage_session', - self.manage_session) - - if 'client_manager' not in kwargs: - url = self.server_options.get('message_queue', None) - channel = self.server_options.pop('channel', 'flask-socketio') - write_only = app is None - if url: - if url.startswith(('redis://', "rediss://")): - queue_class = socketio.RedisManager - elif url.startswith('kafka://'): - queue_class = socketio.KafkaManager - elif url.startswith('zmq'): - queue_class = socketio.ZmqManager - else: - queue_class = socketio.KombuManager - queue = queue_class(url, channel=channel, - write_only=write_only) - self.server_options['client_manager'] = queue - - if 'json' in self.server_options and \ - self.server_options['json'] == flask_json: - # flask's json module is tricky to use because its output - # changes when it is invoked inside or outside the app context - # so here to prevent any ambiguities we replace it with wrappers - # that ensure that the app context is always present - class FlaskSafeJSON: - @staticmethod - def dumps(*args, **kwargs): - with app.app_context(): - return flask_json.dumps(*args, **kwargs) - - @staticmethod - def loads(*args, **kwargs): - with app.app_context(): - return flask_json.loads(*args, **kwargs) - - self.server_options['json'] = FlaskSafeJSON - - resource = self.server_options.pop('path', None) or \ - self.server_options.pop('resource', None) or 'socket.io' - if resource.startswith('/'): - resource = resource[1:] - if os.environ.get('FLASK_RUN_FROM_CLI'): - if self.server_options.get('async_mode') is None: - self.server_options['async_mode'] = 'threading' - self.server = socketio.Server(**self.server_options) - self.async_mode = self.server.async_mode - for handler in self.handlers: - self.server.on(handler[0], handler[1], namespace=handler[2]) - for namespace_handler in self.namespace_handlers: - self.server.register_namespace(namespace_handler) - - if app is not None: - # here we attach the SocketIO middleware to the SocketIO object so - # it can be referenced later if debug middleware needs to be - # inserted - self.sockio_mw = _SocketIOMiddleware(self.server, app, - socketio_path=resource) - app.wsgi_app = self.sockio_mw - - def on(self, message, namespace=None): - """Decorator to register a SocketIO event handler. - - This decorator must be applied to SocketIO event handlers. Example:: - - @socketio.on('my event', namespace='/chat') - def handle_my_custom_event(json): - print('received json: ' + str(json)) - - :param message: The name of the event. This is normally a user defined - string, but a few event names are already defined. Use - ``'message'`` to define a handler that takes a string - payload, ``'json'`` to define a handler that takes a - JSON blob payload, ``'connect'`` or ``'disconnect'`` - to create handlers for connection and disconnection - events. - :param namespace: The namespace on which the handler is to be - registered. Defaults to the global namespace. - """ - namespace = namespace or '/' - - def decorator(handler): - @wraps(handler) - def _handler(sid, *args): - real_ns = namespace - if namespace == '*': - real_ns = sid - sid = args[0] - args = args[1:] - real_msg = message - if message == '*': - real_msg = sid - sid = args[0] - args = [real_msg] + list(args[1:]) - return self._handle_event(handler, message, real_ns, sid, - *args) - - if self.server: - self.server.on(message, _handler, namespace=namespace) - else: - self.handlers.append((message, _handler, namespace)) - return handler - return decorator - - def on_error(self, namespace=None): - """Decorator to define a custom error handler for SocketIO events. - - This decorator can be applied to a function that acts as an error - handler for a namespace. This handler will be invoked when a SocketIO - event handler raises an exception. The handler function must accept one - argument, which is the exception raised. Example:: - - @socketio.on_error(namespace='/chat') - def chat_error_handler(e): - print('An error has occurred: ' + str(e)) - - :param namespace: The namespace for which to register the error - handler. Defaults to the global namespace. - """ - namespace = namespace or '/' - - def decorator(exception_handler): - if not callable(exception_handler): - raise ValueError('exception_handler must be callable') - self.exception_handlers[namespace] = exception_handler - return exception_handler - return decorator - - def on_error_default(self, exception_handler): - """Decorator to define a default error handler for SocketIO events. - - This decorator can be applied to a function that acts as a default - error handler for any namespaces that do not have a specific handler. - Example:: - - @socketio.on_error_default - def error_handler(e): - print('An error has occurred: ' + str(e)) - """ - if not callable(exception_handler): - raise ValueError('exception_handler must be callable') - self.default_exception_handler = exception_handler - return exception_handler - - def on_event(self, message, handler, namespace=None): - """Register a SocketIO event handler. - - ``on_event`` is the non-decorator version of ``'on'``. - - Example:: - - def on_foo_event(json): - print('received json: ' + str(json)) - - socketio.on_event('my event', on_foo_event, namespace='/chat') - - :param message: The name of the event. This is normally a user defined - string, but a few event names are already defined. Use - ``'message'`` to define a handler that takes a string - payload, ``'json'`` to define a handler that takes a - JSON blob payload, ``'connect'`` or ``'disconnect'`` - to create handlers for connection and disconnection - events. - :param handler: The function that handles the event. - :param namespace: The namespace on which the handler is to be - registered. Defaults to the global namespace. - """ - self.on(message, namespace=namespace)(handler) - - def event(self, *args, **kwargs): - """Decorator to register an event handler. - - This is a simplified version of the ``on()`` method that takes the - event name from the decorated function. - - Example usage:: - - @socketio.event - def my_event(data): - print('Received data: ', data) - - The above example is equivalent to:: - - @socketio.on('my_event') - def my_event(data): - print('Received data: ', data) - - A custom namespace can be given as an argument to the decorator:: - - @socketio.event(namespace='/test') - def my_event(data): - print('Received data: ', data) - """ - if len(args) == 1 and len(kwargs) == 0 and callable(args[0]): - # the decorator was invoked without arguments - # args[0] is the decorated function - return self.on(args[0].__name__)(args[0]) - else: - # the decorator was invoked with arguments - def set_handler(handler): - return self.on(handler.__name__, *args, **kwargs)(handler) - - return set_handler - - def on_namespace(self, namespace_handler): - if not isinstance(namespace_handler, Namespace): - raise ValueError('Not a namespace instance.') - namespace_handler._set_socketio(self) - if self.server: - self.server.register_namespace(namespace_handler) - else: - self.namespace_handlers.append(namespace_handler) - - def emit(self, event, *args, **kwargs): - """Emit a server generated SocketIO event. - - This function emits a SocketIO event to one or more connected clients. - A JSON blob can be attached to the event as payload. This function can - be used outside of a SocketIO event context, so it is appropriate to - use when the server is the originator of an event, outside of any - client context, such as in a regular HTTP request handler or a - background task. Example:: - - @app.route('/ping') - def ping(): - socketio.emit('ping event', {'data': 42}, namespace='/chat') - - :param event: The name of the user event to emit. - :param args: A dictionary with the JSON data to send as payload. - :param namespace: The namespace under which the message is to be sent. - Defaults to the global namespace. - :param to: Send the message to all the users in the given room, or to - the user with the given session ID. If this parameter is not - included, the event is sent to all connected users. - :param include_self: ``True`` to include the sender when broadcasting - or addressing a room, or ``False`` to send to - everyone but the sender. - :param skip_sid: The session id of a client to ignore when broadcasting - or addressing a room. This is typically set to the - originator of the message, so that everyone except - that client receive the message. To skip multiple sids - pass a list. - :param callback: If given, this function will be called to acknowledge - that the client has received the message. The - arguments that will be passed to the function are - those provided by the client. Callback functions can - only be used when addressing an individual client. - """ - namespace = kwargs.pop('namespace', '/') - to = kwargs.pop('to', None) or kwargs.pop('room', None) - include_self = kwargs.pop('include_self', True) - skip_sid = kwargs.pop('skip_sid', None) - if not include_self and not skip_sid: - skip_sid = flask.request.sid - callback = kwargs.pop('callback', None) - if callback: - # wrap the callback so that it sets app app and request contexts - sid = None - original_callback = callback - original_namespace = namespace - if has_request_context(): - sid = getattr(flask.request, 'sid', None) - original_namespace = getattr(flask.request, 'namespace', None) - - def _callback_wrapper(*args): - return self._handle_event(original_callback, None, - original_namespace, sid, *args) - - if sid: - # the callback wrapper above will install a request context - # before invoking the original callback - # we only use it if the emit was issued from a Socket.IO - # populated request context (i.e. request.sid is defined) - callback = _callback_wrapper - self.server.emit(event, *args, namespace=namespace, to=to, - skip_sid=skip_sid, callback=callback, **kwargs) - - def call(self, event, *args, **kwargs): # pragma: no cover - """Emit a SocketIO event and wait for the response. - - This method issues an emit with a callback and waits for the callback - to be invoked by the client before returning. If the callback isn’t - invoked before the timeout, then a TimeoutError exception is raised. If - the Socket.IO connection drops during the wait, this method still waits - until the specified timeout. Example:: - - def get_status(client, data): - status = call('status', {'data': data}, to=client) - - :param event: The name of the user event to emit. - :param args: A dictionary with the JSON data to send as payload. - :param namespace: The namespace under which the message is to be sent. - Defaults to the global namespace. - :param to: The session ID of the recipient client. - :param timeout: The waiting timeout. If the timeout is reached before - the client acknowledges the event, then a - ``TimeoutError`` exception is raised. The default is 60 - seconds. - :param ignore_queue: Only used when a message queue is configured. If - set to ``True``, the event is emitted to the - client directly, without going through the queue. - This is more efficient, but only works when a - single server process is used, or when there is a - single addressee. It is recommended to always - leave this parameter with its default value of - ``False``. - """ - namespace = kwargs.pop('namespace', '/') - to = kwargs.pop('to', None) or kwargs.pop('room', None) - return self.server.call(event, *args, namespace=namespace, to=to, - **kwargs) - - def send(self, data, json=False, namespace=None, to=None, - callback=None, include_self=True, skip_sid=None, **kwargs): - """Send a server-generated SocketIO message. - - This function sends a simple SocketIO message to one or more connected - clients. The message can be a string or a JSON blob. This is a simpler - version of ``emit()``, which should be preferred. This function can be - used outside of a SocketIO event context, so it is appropriate to use - when the server is the originator of an event. - - :param data: The message to send, either a string or a JSON blob. - :param json: ``True`` if ``message`` is a JSON blob, ``False`` - otherwise. - :param namespace: The namespace under which the message is to be sent. - Defaults to the global namespace. - :param to: Send the message to all the users in the given room, or to - the user with the given session ID. If this parameter is not - included, the event is sent to all connected users. - :param include_self: ``True`` to include the sender when broadcasting - or addressing a room, or ``False`` to send to - everyone but the sender. - :param skip_sid: The session id of a client to ignore when broadcasting - or addressing a room. This is typically set to the - originator of the message, so that everyone except - that client receive the message. To skip multiple sids - pass a list. - :param callback: If given, this function will be called to acknowledge - that the client has received the message. The - arguments that will be passed to the function are - those provided by the client. Callback functions can - only be used when addressing an individual client. - """ - skip_sid = flask.request.sid if not include_self else skip_sid - if json: - self.emit('json', data, namespace=namespace, to=to, - skip_sid=skip_sid, callback=callback, **kwargs) - else: - self.emit('message', data, namespace=namespace, to=to, - skip_sid=skip_sid, callback=callback, **kwargs) - - def close_room(self, room, namespace=None): - """Close a room. - - This function removes any users that are in the given room and then - deletes the room from the server. This function can be used outside - of a SocketIO event context. - - :param room: The name of the room to close. - :param namespace: The namespace under which the room exists. Defaults - to the global namespace. - """ - self.server.close_room(room, namespace) - - def run(self, app, host=None, port=None, **kwargs): # pragma: no cover - """Run the SocketIO web server. - - :param app: The Flask application instance. - :param host: The hostname or IP address for the server to listen on. - Defaults to 127.0.0.1. - :param port: The port number for the server to listen on. Defaults to - 5000. - :param debug: ``True`` to start the server in debug mode, ``False`` to - start in normal mode. - :param use_reloader: ``True`` to enable the Flask reloader, ``False`` - to disable it. - :param reloader_options: A dictionary with options that are passed to - the Flask reloader, such as ``extra_files``, - ``reloader_type``, etc. - :param extra_files: A list of additional files that the Flask - reloader should watch. Defaults to ``None``. - Deprecated, use ``reloader_options`` instead. - :param log_output: If ``True``, the server logs all incoming - connections. If ``False`` logging is disabled. - Defaults to ``True`` in debug mode, ``False`` - in normal mode. Unused when the threading async - mode is used. - :param allow_unsafe_werkzeug: Set to ``True`` to allow the use of the - Werkzeug web server in a production - setting. Default is ``False``. Set to - ``True`` at your own risk. - :param kwargs: Additional web server options. The web server options - are specific to the server used in each of the supported - async modes. Note that options provided here will - not be seen when using an external web server such - as gunicorn, since this method is not called in that - case. - """ - if host is None: - host = '127.0.0.1' - if port is None: - server_name = app.config['SERVER_NAME'] - if server_name and ':' in server_name: - port = int(server_name.rsplit(':', 1)[1]) - else: - port = 5000 - - debug = kwargs.pop('debug', app.debug) - log_output = kwargs.pop('log_output', debug) - use_reloader = kwargs.pop('use_reloader', debug) - extra_files = kwargs.pop('extra_files', None) - reloader_options = kwargs.pop('reloader_options', {}) - if extra_files: - reloader_options['extra_files'] = extra_files - - app.debug = debug - if app.debug and self.server.eio.async_mode != 'threading': - # put the debug middleware between the SocketIO middleware - # and the Flask application instance - # - # mw1 mw2 mw3 Flask app - # o ---- o ---- o ---- o - # / - # o Flask-SocketIO - # \ middleware - # o - # Flask-SocketIO WebSocket handler - # - # BECOMES - # - # dbg-mw mw1 mw2 mw3 Flask app - # o ---- o ---- o ---- o ---- o - # / - # o Flask-SocketIO - # \ middleware - # o - # Flask-SocketIO WebSocket handler - # - self.sockio_mw.wsgi_app = DebuggedApplication( - self.sockio_mw.wsgi_app, evalex=True) - - allow_unsafe_werkzeug = kwargs.pop('allow_unsafe_werkzeug', False) - if self.server.eio.async_mode == 'threading': - try: - import simple_websocket # noqa: F401 - except ImportError: - from werkzeug._internal import _log - _log('warning', 'WebSocket transport not available. Install ' - 'simple-websocket for improved performance.') - if not sys.stdin or not sys.stdin.isatty(): # pragma: no cover - if not allow_unsafe_werkzeug: - raise RuntimeError('The Werkzeug web server is not ' - 'designed to run in production. Pass ' - 'allow_unsafe_werkzeug=True to the ' - 'run() method to disable this error.') - else: - from werkzeug._internal import _log - _log('warning', ('Werkzeug appears to be used in a ' - 'production deployment. Consider ' - 'switching to a production web server ' - 'instead.')) - app.run(host=host, port=port, threaded=True, - use_reloader=use_reloader, **reloader_options, **kwargs) - elif self.server.eio.async_mode == 'eventlet': - def run_server(): - import eventlet - import eventlet.wsgi - import eventlet.green - addresses = eventlet.green.socket.getaddrinfo(host, port) - if not addresses: - raise RuntimeError( - 'Could not resolve host to a valid address') - eventlet_socket = eventlet.listen(addresses[0][4], - addresses[0][0]) - - # If provided an SSL argument, use an SSL socket - ssl_args = ['keyfile', 'certfile', 'server_side', 'cert_reqs', - 'ssl_version', 'ca_certs', - 'do_handshake_on_connect', 'suppress_ragged_eofs', - 'ciphers'] - ssl_params = {k: kwargs[k] for k in kwargs - if k in ssl_args and kwargs[k] is not None} - for k in ssl_args: - kwargs.pop(k, None) - if len(ssl_params) > 0: - ssl_params['server_side'] = True # Listening requires true - eventlet_socket = eventlet.wrap_ssl(eventlet_socket, - **ssl_params) - - eventlet.wsgi.server(eventlet_socket, app, - log_output=log_output, **kwargs) - - if use_reloader: - run_with_reloader(run_server, **reloader_options) - else: - run_server() - elif self.server.eio.async_mode == 'gevent': - from gevent import pywsgi - try: - from geventwebsocket.handler import WebSocketHandler - gevent_websocket = True - except ImportError: - # WebSocket support will come from the simple-websocket package - gevent_websocket = False - - log = 'default' - if not log_output: - log = None - if gevent_websocket: - self.wsgi_server = pywsgi.WSGIServer( - (host, port), app, handler_class=WebSocketHandler, - log=log, **kwargs) - else: - self.wsgi_server = pywsgi.WSGIServer((host, port), app, - log=log, **kwargs) - - if use_reloader: - # monkey patching is required by the reloader - from gevent import monkey - monkey.patch_thread() - monkey.patch_time() - - def run_server(): - self.wsgi_server.serve_forever() - - run_with_reloader(run_server, **reloader_options) - else: - self.wsgi_server.serve_forever() - - def stop(self): - """Stop a running SocketIO web server. - - This method must be called from a HTTP or SocketIO handler function. - """ - if self.server.eio.async_mode == 'threading': - func = flask.request.environ.get('werkzeug.server.shutdown') - if func: - func() - else: - raise RuntimeError('Cannot stop unknown web server') - elif self.server.eio.async_mode == 'eventlet': - raise SystemExit - elif self.server.eio.async_mode == 'gevent': - self.wsgi_server.stop() - - def start_background_task(self, target, *args, **kwargs): - """Start a background task using the appropriate async model. - - This is a utility function that applications can use to start a - background task using the method that is compatible with the - selected async mode. - - :param target: the target function to execute. - :param args: arguments to pass to the function. - :param kwargs: keyword arguments to pass to the function. - - This function returns an object that represents the background task, - on which the ``join()`` method can be invoked to wait for the task to - complete. - """ - return self.server.start_background_task(target, *args, **kwargs) - - def sleep(self, seconds=0): - """Sleep for the requested amount of time using the appropriate async - model. - - This is a utility function that applications can use to put a task to - sleep without having to worry about using the correct call for the - selected async mode. - """ - return self.server.sleep(seconds) - - def test_client(self, app, namespace=None, query_string=None, - headers=None, auth=None, flask_test_client=None): - """The Socket.IO test client is useful for testing a Flask-SocketIO - server. It works in a similar way to the Flask Test Client, but - adapted to the Socket.IO server. - - :param app: The Flask application instance. - :param namespace: The namespace for the client. If not provided, the - client connects to the server on the global - namespace. - :param query_string: A string with custom query string arguments. - :param headers: A dictionary with custom HTTP headers. - :param auth: Optional authentication data, given as a dictionary. - :param flask_test_client: The instance of the Flask test client - currently in use. Passing the Flask test - client is optional, but is necessary if you - want the Flask user session and any other - cookies set in HTTP routes accessible from - Socket.IO events. - """ - return SocketIOTestClient(app, self, namespace=namespace, - query_string=query_string, headers=headers, - auth=auth, - flask_test_client=flask_test_client) - - def _handle_event(self, handler, message, namespace, sid, *args): - environ = self.server.get_environ(sid, namespace=namespace) - if not environ: - # we don't have record of this client, ignore this event - return '', 400 - app = environ['flask.app'] - with app.request_context(environ): - if self.manage_session: - # manage a separate session for this client's Socket.IO events - # created as a copy of the regular user session - if 'saved_session' not in environ: - environ['saved_session'] = _ManagedSession(flask.session) - session_obj = environ['saved_session'] - if hasattr(flask, 'globals') and \ - hasattr(flask.globals, 'app_ctx'): - if hasattr(flask.globals.app_ctx, 'session'): - # get context for flask >= 3.2 - ctx = flask.globals.app_ctx._get_current_object() - else: - # get context for Flask >= 2.2, < 3.2 - ctx = flask.globals.request_ctx._get_current_object() - else: # pragma: no cover - # get context for Flask < 2.2 - ctx = flask._request_ctx_stack.top - if hasattr(ctx, '_session'): - # update session for Flask >= 3.1.3 - ctx._session = session_obj - else: - # update session for Flask < 3.1.3 - ctx.session = session_obj - else: - # let Flask handle the user session - # for cookie based sessions, this effectively freezes the - # session to its state at connection time - # for server-side sessions, this allows HTTP and Socket.IO to - # share the session, with both having read/write access to it - session_obj = flask.session._get_current_object() - flask.request.sid = sid - flask.request.namespace = namespace - flask.request.event = {'message': message, 'args': args} - try: - if message == 'connect': - auth = args[1] if len(args) > 1 else None - try: - ret = handler(auth) - except TypeError: - ret = handler() - else: - ret = handler(*args) - except ConnectionRefusedError: - raise # let this error bubble up to python-socketio - except: - err_handler = self.exception_handlers.get( - namespace, self.default_exception_handler) - if err_handler is None: - raise - type, value, traceback = sys.exc_info() - return err_handler(value) - if not self.manage_session: - # when Flask is managing the user session, it needs to save it - if not hasattr(session_obj, 'modified') or \ - session_obj.modified: - resp = app.response_class() - app.session_interface.save_session(app, session_obj, resp) - return ret - - -def emit(event, *args, **kwargs): - """Emit a SocketIO event. - - This function emits a SocketIO event to one or more connected clients. A - JSON blob can be attached to the event as payload. This is a function that - can only be called from a SocketIO event handler, as in obtains some - information from the current client context. Example:: - - @socketio.on('my event') - def handle_my_custom_event(json): - emit('my response', {'data': 42}) - - :param event: The name of the user event to emit. - :param args: A dictionary with the JSON data to send as payload. - :param namespace: The namespace under which the message is to be sent. - Defaults to the namespace used by the originating event. - A ``'/'`` can be used to explicitly specify the global - namespace. - :param callback: Callback function to invoke with the client's - acknowledgement. - :param broadcast: ``True`` to send the message to all clients, or ``False`` - to only reply to the sender of the originating event. - :param to: Send the message to all the users in the given room, or to the - user with the given session ID. If this argument is not set and - ``broadcast`` is ``False``, then the message is sent only to the - originating user. - :param include_self: ``True`` to include the sender when broadcasting or - addressing a room, or ``False`` to send to everyone - but the sender. - :param skip_sid: The session id of a client to ignore when broadcasting - or addressing a room. This is typically set to the - originator of the message, so that everyone except - that client receive the message. To skip multiple sids - pass a list. - :param ignore_queue: Only used when a message queue is configured. If - set to ``True``, the event is emitted to the - clients directly, without going through the queue. - This is more efficient, but only works when a - single server process is used, or when there is a - single addressee. It is recommended to always leave - this parameter with its default value of ``False``. - """ - if 'namespace' in kwargs: - namespace = kwargs['namespace'] - else: - namespace = flask.request.namespace - callback = kwargs.get('callback') - broadcast = kwargs.get('broadcast') - to = kwargs.pop('to', None) or kwargs.pop('room', None) - if to is None and not broadcast: - to = flask.request.sid - include_self = kwargs.get('include_self', True) - skip_sid = kwargs.get('skip_sid') - ignore_queue = kwargs.get('ignore_queue', False) - - socketio = flask.current_app.extensions['socketio'] - return socketio.emit(event, *args, namespace=namespace, to=to, - include_self=include_self, skip_sid=skip_sid, - callback=callback, ignore_queue=ignore_queue) - - -def call(event, *args, **kwargs): # pragma: no cover - """Emit a SocketIO event and wait for the response. - - This function issues an emit with a callback and waits for the callback to - be invoked by the client before returning. If the callback isn’t invoked - before the timeout, then a TimeoutError exception is raised. If the - Socket.IO connection drops during the wait, this method still waits until - the specified timeout. Example:: - - def get_status(client, data): - status = call('status', {'data': data}, to=client) - - :param event: The name of the user event to emit. - :param args: A dictionary with the JSON data to send as payload. - :param namespace: The namespace under which the message is to be sent. - Defaults to the namespace used by the originating event. - A ``'/'`` can be used to explicitly specify the global - namespace. - :param to: The session ID of the recipient client. If this argument is not - given, the event is sent to the originating client. - :param timeout: The waiting timeout. If the timeout is reached before the - client acknowledges the event, then a ``TimeoutError`` - exception is raised. The default is 60 seconds. - :param ignore_queue: Only used when a message queue is configured. If - set to ``True``, the event is emitted to the - client directly, without going through the queue. - This is more efficient, but only works when a - single server process is used, or when there is a - single addressee. It is recommended to always leave - this parameter with its default value of ``False``. - """ - if 'namespace' in kwargs: - namespace = kwargs['namespace'] - else: - namespace = flask.request.namespace - to = kwargs.pop('to', None) or kwargs.pop('room', None) - if to is None: - to = flask.request.sid - timeout = kwargs.get('timeout', 60) - ignore_queue = kwargs.get('ignore_queue', False) - - socketio = flask.current_app.extensions['socketio'] - return socketio.call(event, *args, namespace=namespace, to=to, - ignore_queue=ignore_queue, timeout=timeout) - - -def send(message, **kwargs): - """Send a SocketIO message. - - This function sends a simple SocketIO message to one or more connected - clients. The message can be a string or a JSON blob. This is a simpler - version of ``emit()``, which should be preferred. This is a function that - can only be called from a SocketIO event handler. - - :param message: The message to send, either a string or a JSON blob. - :param json: ``True`` if ``message`` is a JSON blob, ``False`` - otherwise. - :param namespace: The namespace under which the message is to be sent. - Defaults to the namespace used by the originating event. - An empty string can be used to use the global namespace. - :param callback: Callback function to invoke with the client's - acknowledgement. - :param broadcast: ``True`` to send the message to all connected clients, or - ``False`` to only reply to the sender of the originating - event. - :param to: Send the message to all the users in the given room, or to the - user with the given session ID. If this argument is not set and - ``broadcast`` is ``False``, then the message is sent only to the - originating user. - :param include_self: ``True`` to include the sender when broadcasting or - addressing a room, or ``False`` to send to everyone - but the sender. - :param skip_sid: The session id of a client to ignore when broadcasting - or addressing a room. This is typically set to the - originator of the message, so that everyone except - that client receive the message. To skip multiple sids - pass a list. - :param ignore_queue: Only used when a message queue is configured. If - set to ``True``, the event is emitted to the - clients directly, without going through the queue. - This is more efficient, but only works when a - single server process is used, or when there is a - single addressee. It is recommended to always leave - this parameter with its default value of ``False``. - """ - json = kwargs.get('json', False) - if 'namespace' in kwargs: - namespace = kwargs['namespace'] - else: - namespace = flask.request.namespace - callback = kwargs.get('callback') - broadcast = kwargs.get('broadcast') - to = kwargs.pop('to', None) or kwargs.pop('room', None) - if to is None and not broadcast: - to = flask.request.sid - include_self = kwargs.get('include_self', True) - skip_sid = kwargs.get('skip_sid') - ignore_queue = kwargs.get('ignore_queue', False) - - socketio = flask.current_app.extensions['socketio'] - return socketio.send(message, json=json, namespace=namespace, to=to, - include_self=include_self, skip_sid=skip_sid, - callback=callback, ignore_queue=ignore_queue) - - -def join_room(room, sid=None, namespace=None): - """Join a room. - - This function puts the user in a room, under the current namespace. The - user and the namespace are obtained from the event context. This is a - function that can only be called from a SocketIO event handler. Example:: - - @socketio.on('join') - def on_join(data): - username = session['username'] - room = data['room'] - join_room(room) - send(username + ' has entered the room.', to=room) - - :param room: The name of the room to join. - :param sid: The session id of the client. If not provided, the client is - obtained from the request context. - :param namespace: The namespace for the room. If not provided, the - namespace is obtained from the request context. - """ - socketio = flask.current_app.extensions['socketio'] - sid = sid or flask.request.sid - namespace = namespace or flask.request.namespace - socketio.server.enter_room(sid, room, namespace=namespace) - - -def leave_room(room, sid=None, namespace=None): - """Leave a room. - - This function removes the user from a room, under the current namespace. - The user and the namespace are obtained from the event context. Example:: - - @socketio.on('leave') - def on_leave(data): - username = session['username'] - room = data['room'] - leave_room(room) - send(username + ' has left the room.', to=room) - - :param room: The name of the room to leave. - :param sid: The session id of the client. If not provided, the client is - obtained from the request context. - :param namespace: The namespace for the room. If not provided, the - namespace is obtained from the request context. - """ - socketio = flask.current_app.extensions['socketio'] - sid = sid or flask.request.sid - namespace = namespace or flask.request.namespace - socketio.server.leave_room(sid, room, namespace=namespace) - - -def close_room(room, namespace=None): - """Close a room. - - This function removes any users that are in the given room and then deletes - the room from the server. - - :param room: The name of the room to close. - :param namespace: The namespace for the room. If not provided, the - namespace is obtained from the request context. - """ - socketio = flask.current_app.extensions['socketio'] - namespace = namespace or flask.request.namespace - socketio.server.close_room(room, namespace=namespace) - - -def rooms(sid=None, namespace=None): - """Return a list of the rooms the client is in. - - This function returns all the rooms the client has entered, including its - own room, assigned by the Socket.IO server. - - :param sid: The session id of the client. If not provided, the client is - obtained from the request context. - :param namespace: The namespace for the room. If not provided, the - namespace is obtained from the request context. - """ - socketio = flask.current_app.extensions['socketio'] - sid = sid or flask.request.sid - namespace = namespace or flask.request.namespace - return socketio.server.rooms(sid, namespace=namespace) - - -def disconnect(sid=None, namespace=None, silent=False): - """Disconnect the client. - - This function terminates the connection with the client. As a result of - this call the client will receive a disconnect event. Example:: - - @socketio.on('message') - def receive_message(msg): - if is_banned(session['username']): - disconnect() - else: - # ... - - :param sid: The session id of the client. If not provided, the client is - obtained from the request context. - :param namespace: The namespace for the room. If not provided, the - namespace is obtained from the request context. - :param silent: this option is deprecated. - """ - socketio = flask.current_app.extensions['socketio'] - sid = sid or flask.request.sid - namespace = namespace or flask.request.namespace - return socketio.server.disconnect(sid, namespace=namespace) diff --git a/venv/lib/python3.9/site-packages/flask_socketio/namespace.py b/venv/lib/python3.9/site-packages/flask_socketio/namespace.py deleted file mode 100644 index 541fa79..0000000 --- a/venv/lib/python3.9/site-packages/flask_socketio/namespace.py +++ /dev/null @@ -1,54 +0,0 @@ -from socketio import Namespace as _Namespace - - -class Namespace(_Namespace): - def __init__(self, namespace=None): - super().__init__(namespace) - self.socketio = None - - def _set_socketio(self, socketio): - self.socketio = socketio - - def trigger_event(self, event, *args): - """Dispatch an event to the proper handler method. - - In the most common usage, this method is not overloaded by subclasses, - as it performs the routing of events to methods. However, this - method can be overridden if special dispatching rules are needed, or if - having a single method that catches all events is desired. - """ - handler_name = 'on_' + (event or '') - if not hasattr(self, handler_name): - # there is no handler for this event, so we ignore it - return - handler = getattr(self, handler_name) - try: - return self.socketio._handle_event(handler, event, self.namespace, - *args) - except TypeError: - if event == 'disconnect': - # legacy disconnect events do not have the reason argument - return self.socketio._handle_event( - handler, event, self.namespace, *args[:-1]) - else: - raise - - def emit(self, event, data=None, room=None, include_self=True, - namespace=None, callback=None): - """Emit a custom event to one or more connected clients.""" - return self.socketio.emit(event, data, room=room, - include_self=include_self, - namespace=namespace or self.namespace, - callback=callback) - - def send(self, data, room=None, include_self=True, namespace=None, - callback=None): - """Send a message to one or more connected clients.""" - return self.socketio.send(data, room=room, include_self=include_self, - namespace=namespace or self.namespace, - callback=callback) - - def close_room(self, room, namespace=None): - """Close a room.""" - return self.socketio.close_room(room=room, - namespace=namespace or self.namespace) diff --git a/venv/lib/python3.9/site-packages/flask_socketio/test_client.py b/venv/lib/python3.9/site-packages/flask_socketio/test_client.py deleted file mode 100644 index f1ac441..0000000 --- a/venv/lib/python3.9/site-packages/flask_socketio/test_client.py +++ /dev/null @@ -1,244 +0,0 @@ -import uuid - -from socketio import packet -from socketio.pubsub_manager import PubSubManager -from flask.testing import EnvironBuilder - - -class SocketIOTestClient: - """ - This class is useful for testing a Flask-SocketIO server. It works in a - similar way to the Flask Test Client, but adapted to the Socket.IO server. - - :param app: The Flask application instance. - :param socketio: The application's ``SocketIO`` instance. - :param namespace: The namespace for the client. If not provided, the client - connects to the server on the global namespace. - :param query_string: A string with custom query string arguments. - :param headers: A dictionary with custom HTTP headers. - :param auth: Optional authentication data, given as a dictionary. - :param flask_test_client: The instance of the Flask test client - currently in use. Passing the Flask test - client is optional, but is necessary if you - want the Flask user session and any other - cookies set in HTTP routes accessible from - Socket.IO events. - """ - clients = {} - - def __init__(self, app, socketio, namespace=None, query_string=None, - headers=None, auth=None, flask_test_client=None): - def _mock_send_packet(eio_sid, pkt): - # make sure the packet can be encoded and decoded - epkt = pkt.encode() - if not isinstance(epkt, list): - pkt = packet.Packet(encoded_packet=epkt) - else: - pkt = packet.Packet(encoded_packet=epkt[0]) - for att in epkt[1:]: - pkt.add_attachment(att) - client = self.clients.get(eio_sid) - if not client: - return - if pkt.packet_type == packet.EVENT or \ - pkt.packet_type == packet.BINARY_EVENT: - if pkt.data[0] == 'message' or pkt.data[0] == 'json': - client.queue.append({ - 'name': pkt.data[0], - 'args': pkt.data[1], - 'namespace': pkt.namespace or '/'}) - else: - client.queue.append({ - 'name': pkt.data[0], - 'args': pkt.data[1:], - 'namespace': pkt.namespace or '/'}) - elif pkt.packet_type == packet.ACK or \ - pkt.packet_type == packet.BINARY_ACK: - client.acks = {'args': pkt.data, - 'namespace': pkt.namespace or '/'} - elif pkt.packet_type in [packet.DISCONNECT, packet.CONNECT_ERROR]: - client.connected[pkt.namespace or '/'] = False - - _current_packet = None - - def _mock_send_eio_packet(eio_sid, eio_pkt): - nonlocal _current_packet - if _current_packet is not None: - _current_packet.add_attachment(eio_pkt.data) - if _current_packet.attachment_count == \ - len(_current_packet.attachments): - _mock_send_packet(eio_sid, _current_packet) - _current_packet = None - else: - pkt = packet.Packet(encoded_packet=eio_pkt.data) - if pkt.attachment_count == 0: - _mock_send_packet(eio_sid, pkt) - else: - _current_packet = pkt - - self.app = app - self.flask_test_client = flask_test_client - self.eio_sid = uuid.uuid4().hex - self.clients[self.eio_sid] = self - self.callback_counter = 0 - self.socketio = socketio - self.connected = {} - self.queue = [] - self.acks = None - socketio.server._send_packet = _mock_send_packet - socketio.server._send_eio_packet = _mock_send_eio_packet - socketio.server.environ[self.eio_sid] = {} - socketio.server.async_handlers = False # easier to test when - socketio.server.eio.async_handlers = False # events are sync - if isinstance(socketio.server.manager, PubSubManager): - raise RuntimeError('Test client cannot be used with a message ' - 'queue. Disable the queue on your test ' - 'configuration.') - socketio.server.manager.initialize() - self.connect(namespace=namespace, query_string=query_string, - headers=headers, auth=auth) - - def is_connected(self, namespace=None): - """Check if a namespace is connected. - - :param namespace: The namespace to check. The global namespace is - assumed if this argument is not provided. - """ - return self.connected.get(namespace or '/', False) - - def connect(self, namespace=None, query_string=None, headers=None, - auth=None): - """Connect the client. - - :param namespace: The namespace for the client. If not provided, the - client connects to the server on the global - namespace. - :param query_string: A string with custom query string arguments. - :param headers: A dictionary with custom HTTP headers. - :param auth: Optional authentication data, given as a dictionary. - - Note that it is usually not necessary to explicitly call this method, - since a connection is automatically established when an instance of - this class is created. An example where it this method would be useful - is when the application accepts multiple namespace connections. - """ - url = '/socket.io' - namespace = namespace or '/' - if query_string: - if query_string[0] != '?': - query_string = '?' + query_string - url += query_string - if self.flask_test_client: - # let Flask's test client build an environ dictionary - req = self.flask_test_client._request_from_builder_args( - args=(), kwargs={'path': url, 'headers': headers}) - environ = req.environ - else: - environ = EnvironBuilder( - self.app, path=url, headers=headers).get_environ() - environ['flask.app'] = self.app - - if self.flask_test_client: - # inject cookies from Flask - if hasattr(self.flask_test_client, '_add_cookies_to_wsgi'): - # flask >= 2.3 - self.flask_test_client._add_cookies_to_wsgi(environ) - else: # pragma: no cover - # flask < 2.3 - self.flask_test_client.cookie_jar.inject_wsgi(environ) - self.socketio.server._handle_eio_connect(self.eio_sid, environ) - pkt = packet.Packet(packet.CONNECT, auth, namespace=namespace) - self.socketio.server._handle_eio_message(self.eio_sid, pkt.encode()) - sid = self.socketio.server.manager.sid_from_eio_sid(self.eio_sid, - namespace) - if sid: - self.connected[namespace] = True - - def disconnect(self, namespace=None): - """Disconnect the client. - - :param namespace: The namespace to disconnect. The global namespace is - assumed if this argument is not provided. - """ - if not self.is_connected(namespace): - raise RuntimeError('not connected') - pkt = packet.Packet(packet.DISCONNECT, namespace=namespace) - self.socketio.server._handle_eio_message(self.eio_sid, pkt.encode()) - del self.connected[namespace or '/'] - - def emit(self, event, *args, **kwargs): - """Emit an event to the server. - - :param event: The event name. - :param *args: The event arguments. - :param callback: ``True`` if the client requests a callback, ``False`` - if not. Note that client-side callbacks are not - implemented, a callback request will just tell the - server to provide the arguments to invoke the - callback, but no callback is invoked. Instead, the - arguments that the server provided for the callback - are returned by this function. - :param namespace: The namespace of the event. The global namespace is - assumed if this argument is not provided. - """ - namespace = kwargs.pop('namespace', None) - if not self.is_connected(namespace): - raise RuntimeError('not connected') - callback = kwargs.pop('callback', False) - id = None - if callback: - self.callback_counter += 1 - id = self.callback_counter - pkt = packet.Packet(packet.EVENT, data=[event] + list(args), - namespace=namespace, id=id) - encoded_pkt = pkt.encode() - if isinstance(encoded_pkt, list): - for epkt in encoded_pkt: - self.socketio.server._handle_eio_message(self.eio_sid, epkt) - else: - self.socketio.server._handle_eio_message(self.eio_sid, encoded_pkt) - if self.acks is not None: - ack = self.acks - self.acks = None - return ack['args'][0] if len(ack['args']) == 1 \ - else ack['args'] - - def send(self, data, json=False, callback=False, namespace=None): - """Send a text or JSON message to the server. - - :param data: A string, dictionary or list to send to the server. - :param json: ``True`` to send a JSON message, ``False`` to send a text - message. - :param callback: ``True`` if the client requests a callback, ``False`` - if not. Note that client-side callbacks are not - implemented, a callback request will just tell the - server to provide the arguments to invoke the - callback, but no callback is invoked. Instead, the - arguments that the server provided for the callback - are returned by this function. - :param namespace: The namespace of the event. The global namespace is - assumed if this argument is not provided. - """ - if json: - msg = 'json' - else: - msg = 'message' - return self.emit(msg, data, callback=callback, namespace=namespace) - - def get_received(self, namespace=None): - """Return the list of messages received from the server. - - Since this is not a real client, any time the server emits an event, - the event is simply stored. The test code can invoke this method to - obtain the list of events that were received since the last call. - - :param namespace: The namespace to get events from. The global - namespace is assumed if this argument is not - provided. - """ - if not self.is_connected(namespace): - raise RuntimeError('not connected') - namespace = namespace or '/' - r = [pkt for pkt in self.queue if pkt['namespace'] == namespace] - self.queue = [pkt for pkt in self.queue if pkt not in r] - return r diff --git a/venv/lib/python3.9/site-packages/frozenlist-1.8.0.dist-info/INSTALLER b/venv/lib/python3.9/site-packages/frozenlist-1.8.0.dist-info/INSTALLER deleted file mode 100644 index a1b589e..0000000 --- a/venv/lib/python3.9/site-packages/frozenlist-1.8.0.dist-info/INSTALLER +++ /dev/null @@ -1 +0,0 @@ -pip diff --git a/venv/lib/python3.9/site-packages/frozenlist-1.8.0.dist-info/METADATA b/venv/lib/python3.9/site-packages/frozenlist-1.8.0.dist-info/METADATA deleted file mode 100644 index 30d6653..0000000 --- a/venv/lib/python3.9/site-packages/frozenlist-1.8.0.dist-info/METADATA +++ /dev/null @@ -1,672 +0,0 @@ -Metadata-Version: 2.4 -Name: frozenlist -Version: 1.8.0 -Summary: A list-like structure which implements collections.abc.MutableSequence -Home-page: https://github.com/aio-libs/frozenlist -Maintainer: aiohttp team -Maintainer-email: team@aiohttp.org -License: Apache-2.0 -Project-URL: Chat: Matrix, https://matrix.to/#/#aio-libs:matrix.org -Project-URL: Chat: Matrix Space, https://matrix.to/#/#aio-libs-space:matrix.org -Project-URL: CI: Github Actions, https://github.com/aio-libs/frozenlist/actions -Project-URL: Code of Conduct, https://github.com/aio-libs/.github/blob/master/CODE_OF_CONDUCT.md -Project-URL: Coverage: codecov, https://codecov.io/github/aio-libs/frozenlist -Project-URL: Docs: Changelog, https://github.com/aio-libs/frozenlist/blob/master/CHANGES.rst#changelog -Project-URL: Docs: RTD, https://frozenlist.aio-libs.org -Project-URL: GitHub: issues, https://github.com/aio-libs/frozenlist/issues -Project-URL: GitHub: repo, https://github.com/aio-libs/frozenlist -Classifier: Development Status :: 5 - Production/Stable -Classifier: Intended Audience :: Developers -Classifier: Operating System :: POSIX -Classifier: Operating System :: MacOS :: MacOS X -Classifier: Operating System :: Microsoft :: Windows -Classifier: Programming Language :: Cython -Classifier: Programming Language :: Python -Classifier: Programming Language :: Python :: 3 -Classifier: Programming Language :: Python :: 3.9 -Classifier: Programming Language :: Python :: 3.10 -Classifier: Programming Language :: Python :: 3.11 -Classifier: Programming Language :: Python :: 3.12 -Classifier: Programming Language :: Python :: 3.13 -Classifier: Programming Language :: Python :: 3.14 -Classifier: Programming Language :: Python :: Implementation :: CPython -Classifier: Programming Language :: Python :: Implementation :: PyPy -Requires-Python: >=3.9 -Description-Content-Type: text/x-rst -License-File: LICENSE -Dynamic: license-file - -frozenlist -========== - -.. image:: https://github.com/aio-libs/frozenlist/workflows/CI/badge.svg - :target: https://github.com/aio-libs/frozenlist/actions - :alt: GitHub status for master branch - -.. image:: https://codecov.io/gh/aio-libs/frozenlist/branch/master/graph/badge.svg?flag=pytest - :target: https://codecov.io/gh/aio-libs/frozenlist?flags[]=pytest - :alt: codecov.io status for master branch - -.. image:: https://img.shields.io/pypi/v/frozenlist.svg?logo=Python&logoColor=white - :target: https://pypi.org/project/frozenlist - :alt: frozenlist @ PyPI - -.. image:: https://readthedocs.org/projects/frozenlist/badge/?version=latest - :target: https://frozenlist.aio-libs.org - :alt: Read The Docs build status badge - -.. image:: https://img.shields.io/matrix/aio-libs:matrix.org?label=Discuss%20on%20Matrix%20at%20%23aio-libs%3Amatrix.org&logo=matrix&server_fqdn=matrix.org&style=flat - :target: https://matrix.to/#/%23aio-libs:matrix.org - :alt: Matrix Room — #aio-libs:matrix.org - -.. image:: https://img.shields.io/matrix/aio-libs-space:matrix.org?label=Discuss%20on%20Matrix%20at%20%23aio-libs-space%3Amatrix.org&logo=matrix&server_fqdn=matrix.org&style=flat - :target: https://matrix.to/#/%23aio-libs-space:matrix.org - :alt: Matrix Space — #aio-libs-space:matrix.org - -Introduction ------------- - -``frozenlist.FrozenList`` is a list-like structure which implements -``collections.abc.MutableSequence``. The list is *mutable* until ``FrozenList.freeze`` -is called, after which list modifications raise ``RuntimeError``: - - ->>> from frozenlist import FrozenList ->>> fl = FrozenList([17, 42]) ->>> fl.append('spam') ->>> fl.append('Vikings') ->>> fl - ->>> fl.freeze() ->>> fl - ->>> fl.frozen -True ->>> fl.append("Monty") -Traceback (most recent call last): - File "", line 1, in - File "frozenlist/_frozenlist.pyx", line 97, in frozenlist._frozenlist.FrozenList.append - self._check_frozen() - File "frozenlist/_frozenlist.pyx", line 19, in frozenlist._frozenlist.FrozenList._check_frozen - raise RuntimeError("Cannot modify frozen list.") -RuntimeError: Cannot modify frozen list. - - -FrozenList is also hashable, but only when frozen. Otherwise it also throws a RuntimeError: - - ->>> fl = FrozenList([17, 42, 'spam']) ->>> hash(fl) -Traceback (most recent call last): - File "", line 1, in - File "frozenlist/_frozenlist.pyx", line 111, in frozenlist._frozenlist.FrozenList.__hash__ - raise RuntimeError("Cannot hash unfrozen list.") -RuntimeError: Cannot hash unfrozen list. ->>> fl.freeze() ->>> hash(fl) -3713081631934410656 ->>> dictionary = {fl: 'Vikings'} # frozen fl can be a dict key ->>> dictionary -{: 'Vikings'} - - -Installation ------------- - -:: - - $ pip install frozenlist - - -Documentation -------------- - -https://frozenlist.aio-libs.org - -Communication channels ----------------------- - -We have a *Matrix Space* `#aio-libs-space:matrix.org -`_ which is -also accessible via Gitter. - -License -------- - -``frozenlist`` is offered under the Apache 2 license. - -Source code ------------ - -The project is hosted on GitHub_ - -Please file an issue in the `bug tracker -`_ if you have found a bug -or have some suggestions to improve the library. - -.. _GitHub: https://github.com/aio-libs/frozenlist - -========= -Changelog -========= - -.. - You should *NOT* be adding new change log entries to this file, this - file is managed by towncrier. You *may* edit previous change logs to - fix problems like typo corrections or such. - To add a new change log entry, please see - https://pip.pypa.io/en/latest/development/contributing/#news-entries - we named the news folder "changes". - - WARNING: Don't drop the next directive! - -.. towncrier release notes start - -v1.8.0 -====== - -*(2025-10-05)* - - -Contributor-facing changes --------------------------- - -- The ``reusable-cibuildwheel.yml`` workflow has been refactored to - be more generic and ``ci-cd.yml`` now holds all the configuration - toggles -- by `@webknjaz `__. - - *Related issues and pull requests on GitHub:* - `#668 `__. - -- When building wheels, the source distribution is now passed directly - to the ``cibuildwheel`` invocation -- by `@webknjaz `__. - - *Related issues and pull requests on GitHub:* - `#669 `__. - -- Builds and tests have been added to - ``ci-cd.yml`` for arm64 Windows wheels -- by `@finnagin `__. - - *Related issues and pull requests on GitHub:* - `#677 `__. - -- Started building wheels for CPython 3.14 -- by `@kumaraditya303 `__. - - *Related issues and pull requests on GitHub:* - `#681 `__, `#682 `__. - -- Removed ``--config-settings=pure-python=false`` from ``requirements/dev.txt``. - Developers on CPython still get accelerated builds by default. To explicitly build - a pure Python wheel, use ``pip install -e . --config-settings=pure-python=true`` - -- by `@bdraco `__. - - *Related issues and pull requests on GitHub:* - `#687 `__. - - ----- - - -v1.7.0 -====== - -*(2025-06-09)* - - -Features --------- - -- Added deepcopy support to FrozenList -- by `@bdraco `__. - - *Related issues and pull requests on GitHub:* - `#659 `__. - - -Packaging updates and notes for downstreams -------------------------------------------- - -- Fixed an issue where ``frozenlist`` binary wheels would be built with debugging symbols and line tracing enabled, which significantly impacted performance. Line tracing is now disabled by default and can only be enabled explicitly -- by `@bdraco `__. - - This change ensures that production builds are optimized for performance. Developers who need line tracing for debugging purposes can still enable it by: - - 1. Setting the ``FROZENLIST_CYTHON_TRACING`` environment variable - 2. Using the ``--config-setting=with-cython-tracing=true`` option with pip - - *Related issues and pull requests on GitHub:* - `#660 `__. - -- Enabled ``PIP_CONSTRAINT`` environment variable in the build configuration to ensure the pinned Cython version from ``requirements/cython.txt`` is used during wheel builds. - - *Related issues and pull requests on GitHub:* - `#661 `__. - - ----- - - -v1.6.2 -====== - -*(2025-06-03)* - - -No significant changes. - - ----- - - -v1.6.1 -====== - -*(2025-06-02)* - - -Bug fixes ---------- - -- Correctly use ``cimport`` for including ``PyBool_FromLong`` -- by `@lysnikolaou `__. - - *Related issues and pull requests on GitHub:* - `#653 `__. - - -Packaging updates and notes for downstreams -------------------------------------------- - -- Exclude ``_frozenlist.cpp`` from bdists/wheels -- by `@musicinmybrain `__. - - *Related issues and pull requests on GitHub:* - `#649 `__. - -- Updated to use Cython 3.1 universally across the build path -- by `@lysnikolaou `__. - - *Related issues and pull requests on GitHub:* - `#654 `__. - - ----- - - -v1.6.0 -====== - -*(2025-04-17)* - - -Bug fixes ---------- - -- Stopped implicitly allowing the use of Cython pre-release versions when - building the distribution package -- by `@ajsanchezsanz `__ and - `@markgreene74 `__. - - *Related commits on GitHub:* - `41591f2 `__. - - -Features --------- - -- Implemented support for the free-threaded build of CPython 3.13 -- by `@lysnikolaou `__. - - *Related issues and pull requests on GitHub:* - `#618 `__. - -- Started building armv7l wheels -- by `@bdraco `__. - - *Related issues and pull requests on GitHub:* - `#642 `__. - - -Packaging updates and notes for downstreams -------------------------------------------- - -- Stopped implicitly allowing the use of Cython pre-release versions when - building the distribution package -- by `@ajsanchezsanz `__ and - `@markgreene74 `__. - - *Related commits on GitHub:* - `41591f2 `__. - -- Started building wheels for the free-threaded build of CPython 3.13 -- by `@lysnikolaou `__. - - *Related issues and pull requests on GitHub:* - `#618 `__. - -- The packaging metadata switched to including an SPDX license identifier introduced in `PEP 639 `__ -- by `@cdce8p `__. - - *Related issues and pull requests on GitHub:* - `#639 `__. - - -Contributor-facing changes --------------------------- - -- GitHub Actions CI/CD is now configured to manage caching pip-ecosystem - dependencies using `re-actors/cache-python-deps`_ -- an action by - `@webknjaz `__ that takes into account ABI stability and the exact - version of Python runtime. - - .. _`re-actors/cache-python-deps`: - https://github.com/marketplace/actions/cache-python-deps - - *Related issues and pull requests on GitHub:* - `#633 `__. - -- Organized dependencies into test and lint dependencies so that no - unnecessary ones are installed during CI runs -- by `@lysnikolaou `__. - - *Related issues and pull requests on GitHub:* - `#636 `__. - - ----- - - -1.5.0 (2024-10-22) -================== - -Bug fixes ---------- - -- An incorrect signature of the ``__class_getitem__`` class method - has been fixed, adding a missing ``class_item`` argument under - Python 3.8 and older. - - This change also improves the code coverage of this method that - was previously missing -- by `@webknjaz `__. - - - *Related issues and pull requests on GitHub:* - `#567 `__, `#571 `__. - - -Improved documentation ----------------------- - -- Rendered issue, PR, and commit links now lead to - ``frozenlist``'s repo instead of ``yarl``'s repo. - - - *Related issues and pull requests on GitHub:* - `#573 `__. - -- On the ``Contributing docs`` page, - a link to the ``Towncrier philosophy`` has been fixed. - - - *Related issues and pull requests on GitHub:* - `#574 `__. - - -Packaging updates and notes for downstreams -------------------------------------------- - -- A name of a temporary building directory now reflects - that it's related to ``frozenlist``, not ``yarl``. - - - *Related issues and pull requests on GitHub:* - `#573 `__. - -- Declared Python 3.13 supported officially in the distribution package metadata. - - - *Related issues and pull requests on GitHub:* - `#595 `__. - - ----- - - -1.4.1 (2023-12-15) -================== - -Packaging updates and notes for downstreams -------------------------------------------- - -- Declared Python 3.12 and PyPy 3.8-3.10 supported officially - in the distribution package metadata. - - - *Related issues and pull requests on GitHub:* - `#553 `__. - -- Replaced the packaging is replaced from an old-fashioned ``setup.py`` to an - in-tree `PEP 517 `__ build backend -- by `@webknjaz `__. - - Whenever the end-users or downstream packagers need to build ``frozenlist`` - from source (a Git checkout or an sdist), they may pass a ``config_settings`` - flag ``pure-python``. If this flag is not set, a C-extension will be built - and included into the distribution. - - Here is how this can be done with ``pip``: - - .. code-block:: console - - $ python3 -m pip install . --config-settings=pure-python= - - This will also work with ``-e | --editable``. - - The same can be achieved via ``pypa/build``: - - .. code-block:: console - - $ python3 -m build --config-setting=pure-python= - - Adding ``-w | --wheel`` can force ``pypa/build`` produce a wheel from source - directly, as opposed to building an ``sdist`` and then building from it. - - - *Related issues and pull requests on GitHub:* - `#560 `__. - - -Contributor-facing changes --------------------------- - -- It is now possible to request line tracing in Cython builds using the - ``with-cython-tracing`` `PEP 517 `__ config setting - -- `@webknjaz `__. - - This can be used in CI and development environment to measure coverage - on Cython modules, but is not normally useful to the end-users or - downstream packagers. - - Here's a usage example: - - .. code-block:: console - - $ python3 -Im pip install . --config-settings=with-cython-tracing=true - - For editable installs, this setting is on by default. Otherwise, it's - off unless requested explicitly. - - The following produces C-files required for the Cython coverage - plugin to map the measurements back to the PYX-files: - - .. code-block:: console - - $ python -Im pip install -e . - - Alternatively, the ``FROZENLIST_CYTHON_TRACING=1`` environment variable - can be set to do the same as the `PEP 517 `__ config setting. - - - *Related issues and pull requests on GitHub:* - `#560 `__. - -- Coverage collection has been implemented for the Cython modules - -- by `@webknjaz `__. - - It will also be reported to Codecov from any non-release CI jobs. - - - *Related issues and pull requests on GitHub:* - `#561 `__. - -- A step-by-step ``Release Guide`` guide has - been added, describing how to release *frozenlist* -- by `@webknjaz `__. - - This is primarily targeting the maintainers. - - - *Related issues and pull requests on GitHub:* - `#563 `__. - -- Detailed ``Contributing Guidelines`` on - authoring the changelog fragments have been published in the - documentation -- by `@webknjaz `__. - - - *Related issues and pull requests on GitHub:* - `#564 `__. - - ----- - - -1.4.0 (2023-07-12) -================== - -The published source distribution package became buildable -under Python 3.12. - - ----- - - -Bugfixes --------- - -- Removed an unused ``typing.Tuple`` import - `#411 `_ - - -Deprecations and Removals -------------------------- - -- Dropped Python 3.7 support. - `#413 `_ - - -Misc ----- - -- `#410 `_, `#433 `_ - - ----- - - -1.3.3 (2022-11-08) -================== - -- Fixed CI runs when creating a new release, where new towncrier versions - fail when the current version section is already present. - - ----- - - -1.3.2 (2022-11-08) -================== - -Misc ----- - -- Updated the CI runs to better check for test results and to avoid deprecated syntax. `#327 `_ - - ----- - - -1.3.1 (2022-08-02) -================== - -The published source distribution package became buildable -under Python 3.11. - - ----- - - -1.3.0 (2022-01-18) -================== - -Bugfixes --------- - -- Do not install C sources with binary distributions. - `#250 `_ - - -Deprecations and Removals -------------------------- - -- Dropped Python 3.6 support - `#274 `_ - - ----- - - -1.2.0 (2021-10-16) -================== - -Features --------- - -- ``FrozenList`` now supports being used as a generic type as per PEP 585, e.g. ``frozen_int_list: FrozenList[int]`` (requires Python 3.9 or newer). - `#172 `_ -- Added support for Python 3.10. - `#227 `_ -- Started shipping platform-specific wheels with the ``musl`` tag targeting typical Alpine Linux runtimes. - `#227 `_ -- Started shipping platform-specific arm64 wheels for Apple Silicon. - `#227 `_ - - ----- - - -1.1.1 (2020-11-14) -================== - -Bugfixes --------- - -- Provide x86 Windows wheels. - `#169 `_ - - ----- - - -1.1.0 (2020-10-13) -================== - -Features --------- - -- Add support for hashing of a frozen list. - `#136 `_ - -- Support Python 3.8 and 3.9. - -- Provide wheels for ``aarch64``, ``i686``, ``ppc64le``, ``s390x`` architectures on - Linux as well as ``x86_64``. - - ----- - - -1.0.0 (2019-11-09) -================== - -Deprecations and Removals -------------------------- - -- Dropped support for Python 3.5; only 3.6, 3.7 and 3.8 are supported going forward. - `#24 `_ diff --git a/venv/lib/python3.9/site-packages/frozenlist-1.8.0.dist-info/RECORD b/venv/lib/python3.9/site-packages/frozenlist-1.8.0.dist-info/RECORD deleted file mode 100644 index c863789..0000000 --- a/venv/lib/python3.9/site-packages/frozenlist-1.8.0.dist-info/RECORD +++ /dev/null @@ -1,12 +0,0 @@ -frozenlist-1.8.0.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 -frozenlist-1.8.0.dist-info/METADATA,sha256=lGwi3J9-LHby1pjwCkMG2-Sagg4rPxoOIv5ShsvsNfE,20333 -frozenlist-1.8.0.dist-info/RECORD,, -frozenlist-1.8.0.dist-info/WHEEL,sha256=IArzJf9J4Hj3DKjrYC0eEkABNjBPm7UE3dK4SCixVJs,180 -frozenlist-1.8.0.dist-info/licenses/LICENSE,sha256=b9UkPpLdf5jsacesN3co50kFcJ_1J6W_mNbQJjwE9bY,11332 -frozenlist-1.8.0.dist-info/top_level.txt,sha256=jivtxsPXA3nK3WBWW2LW5Mtu_GHt8UZA13NeCs2cKuA,11 -frozenlist/__init__.py,sha256=xAIE2u9ncAbjATGIPfno_OJfe8AQ-1h7z_uc73dYsEA,2108 -frozenlist/__init__.pyi,sha256=vMEoES1xGegPtVXoCi9XydEeHsyuIq-KdeXwP5PdsaA,1470 -frozenlist/__pycache__/__init__.cpython-39.pyc,, -frozenlist/_frozenlist.cpython-39-x86_64-linux-gnu.so,sha256=TJ852d9MC5JHQytsQZbDT_pwLKr-4_wHLsBTpSdIU4A,700952 -frozenlist/_frozenlist.pyx,sha256=t-aGjuEiVt_MZPBJ0RnraavVmPBK6arz3i48ZvXuYsU,3708 -frozenlist/py.typed,sha256=sow9soTwP9T_gEAQSVh7Gb8855h04Nwmhs2We-JRgZM,7 diff --git a/venv/lib/python3.9/site-packages/frozenlist-1.8.0.dist-info/WHEEL b/venv/lib/python3.9/site-packages/frozenlist-1.8.0.dist-info/WHEEL deleted file mode 100644 index fce86d5..0000000 --- a/venv/lib/python3.9/site-packages/frozenlist-1.8.0.dist-info/WHEEL +++ /dev/null @@ -1,7 +0,0 @@ -Wheel-Version: 1.0 -Generator: setuptools (80.9.0) -Root-Is-Purelib: false -Tag: cp39-cp39-manylinux_2_5_x86_64 -Tag: cp39-cp39-manylinux1_x86_64 -Tag: cp39-cp39-manylinux_2_28_x86_64 - diff --git a/venv/lib/python3.9/site-packages/frozenlist-1.8.0.dist-info/licenses/LICENSE b/venv/lib/python3.9/site-packages/frozenlist-1.8.0.dist-info/licenses/LICENSE deleted file mode 100644 index 7082a2d..0000000 --- a/venv/lib/python3.9/site-packages/frozenlist-1.8.0.dist-info/licenses/LICENSE +++ /dev/null @@ -1,201 +0,0 @@ -Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "{}" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright 2013-2019 Nikolay Kim and Andrew Svetlov - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. diff --git a/venv/lib/python3.9/site-packages/frozenlist-1.8.0.dist-info/top_level.txt b/venv/lib/python3.9/site-packages/frozenlist-1.8.0.dist-info/top_level.txt deleted file mode 100644 index 52f13fc..0000000 --- a/venv/lib/python3.9/site-packages/frozenlist-1.8.0.dist-info/top_level.txt +++ /dev/null @@ -1 +0,0 @@ -frozenlist diff --git a/venv/lib/python3.9/site-packages/frozenlist/__init__.py b/venv/lib/python3.9/site-packages/frozenlist/__init__.py deleted file mode 100644 index 41c8595..0000000 --- a/venv/lib/python3.9/site-packages/frozenlist/__init__.py +++ /dev/null @@ -1,86 +0,0 @@ -import os -import types -from collections.abc import MutableSequence -from functools import total_ordering - -__version__ = "1.8.0" - -__all__ = ("FrozenList", "PyFrozenList") # type: Tuple[str, ...] - - -NO_EXTENSIONS = bool(os.environ.get("FROZENLIST_NO_EXTENSIONS")) # type: bool - - -@total_ordering -class FrozenList(MutableSequence): - __slots__ = ("_frozen", "_items") - __class_getitem__ = classmethod(types.GenericAlias) - - def __init__(self, items=None): - self._frozen = False - if items is not None: - items = list(items) - else: - items = [] - self._items = items - - @property - def frozen(self): - return self._frozen - - def freeze(self): - self._frozen = True - - def __getitem__(self, index): - return self._items[index] - - def __setitem__(self, index, value): - if self._frozen: - raise RuntimeError("Cannot modify frozen list.") - self._items[index] = value - - def __delitem__(self, index): - if self._frozen: - raise RuntimeError("Cannot modify frozen list.") - del self._items[index] - - def __len__(self): - return self._items.__len__() - - def __iter__(self): - return self._items.__iter__() - - def __reversed__(self): - return self._items.__reversed__() - - def __eq__(self, other): - return list(self) == other - - def __le__(self, other): - return list(self) <= other - - def insert(self, pos, item): - if self._frozen: - raise RuntimeError("Cannot modify frozen list.") - self._items.insert(pos, item) - - def __repr__(self): - return f"" - - def __hash__(self): - if self._frozen: - return hash(tuple(self)) - else: - raise RuntimeError("Cannot hash unfrozen list.") - - -PyFrozenList = FrozenList - - -if not NO_EXTENSIONS: - try: - from ._frozenlist import FrozenList as CFrozenList # type: ignore - except ImportError: # pragma: no cover - pass - else: - FrozenList = CFrozenList # type: ignore diff --git a/venv/lib/python3.9/site-packages/frozenlist/__init__.pyi b/venv/lib/python3.9/site-packages/frozenlist/__init__.pyi deleted file mode 100644 index ae803ef..0000000 --- a/venv/lib/python3.9/site-packages/frozenlist/__init__.pyi +++ /dev/null @@ -1,47 +0,0 @@ -from typing import ( - Generic, - Iterable, - Iterator, - List, - MutableSequence, - Optional, - TypeVar, - Union, - overload, -) - -_T = TypeVar("_T") -_Arg = Union[List[_T], Iterable[_T]] - -class FrozenList(MutableSequence[_T], Generic[_T]): - def __init__(self, items: Optional[_Arg[_T]] = None) -> None: ... - @property - def frozen(self) -> bool: ... - def freeze(self) -> None: ... - @overload - def __getitem__(self, i: int) -> _T: ... - @overload - def __getitem__(self, s: slice) -> FrozenList[_T]: ... - @overload - def __setitem__(self, i: int, o: _T) -> None: ... - @overload - def __setitem__(self, s: slice, o: Iterable[_T]) -> None: ... - @overload - def __delitem__(self, i: int) -> None: ... - @overload - def __delitem__(self, i: slice) -> None: ... - def __len__(self) -> int: ... - def __iter__(self) -> Iterator[_T]: ... - def __reversed__(self) -> Iterator[_T]: ... - def __eq__(self, other: object) -> bool: ... - def __le__(self, other: FrozenList[_T]) -> bool: ... - def __ne__(self, other: object) -> bool: ... - def __lt__(self, other: FrozenList[_T]) -> bool: ... - def __ge__(self, other: FrozenList[_T]) -> bool: ... - def __gt__(self, other: FrozenList[_T]) -> bool: ... - def insert(self, pos: int, item: _T) -> None: ... - def __repr__(self) -> str: ... - def __hash__(self) -> int: ... - -# types for C accelerators are the same -CFrozenList = PyFrozenList = FrozenList diff --git a/venv/lib/python3.9/site-packages/frozenlist/_frozenlist.cpython-39-x86_64-linux-gnu.so b/venv/lib/python3.9/site-packages/frozenlist/_frozenlist.cpython-39-x86_64-linux-gnu.so deleted file mode 100755 index dc8db8b..0000000 Binary files a/venv/lib/python3.9/site-packages/frozenlist/_frozenlist.cpython-39-x86_64-linux-gnu.so and /dev/null differ diff --git a/venv/lib/python3.9/site-packages/frozenlist/_frozenlist.pyx b/venv/lib/python3.9/site-packages/frozenlist/_frozenlist.pyx deleted file mode 100644 index a82d8c8..0000000 --- a/venv/lib/python3.9/site-packages/frozenlist/_frozenlist.pyx +++ /dev/null @@ -1,148 +0,0 @@ -# cython: freethreading_compatible = True -# distutils: language = c++ - -from cpython.bool cimport PyBool_FromLong -from libcpp.atomic cimport atomic - -import copy -import types -from collections.abc import MutableSequence - - -cdef class FrozenList: - __class_getitem__ = classmethod(types.GenericAlias) - - cdef atomic[bint] _frozen - cdef list _items - - def __init__(self, items=None): - self._frozen.store(False) - if items is not None: - items = list(items) - else: - items = [] - self._items = items - - @property - def frozen(self): - return PyBool_FromLong(self._frozen.load()) - - cdef object _check_frozen(self): - if self._frozen.load(): - raise RuntimeError("Cannot modify frozen list.") - - cdef inline object _fast_len(self): - return len(self._items) - - def freeze(self): - self._frozen.store(True) - - def __getitem__(self, index): - return self._items[index] - - def __setitem__(self, index, value): - self._check_frozen() - self._items[index] = value - - def __delitem__(self, index): - self._check_frozen() - del self._items[index] - - def __len__(self): - return self._fast_len() - - def __iter__(self): - return self._items.__iter__() - - def __reversed__(self): - return self._items.__reversed__() - - def __richcmp__(self, other, op): - if op == 0: # < - return list(self) < other - if op == 1: # <= - return list(self) <= other - if op == 2: # == - return list(self) == other - if op == 3: # != - return list(self) != other - if op == 4: # > - return list(self) > other - if op == 5: # => - return list(self) >= other - - def insert(self, pos, item): - self._check_frozen() - self._items.insert(pos, item) - - def __contains__(self, item): - return item in self._items - - def __iadd__(self, items): - self._check_frozen() - self._items += list(items) - return self - - def index(self, item): - return self._items.index(item) - - def remove(self, item): - self._check_frozen() - self._items.remove(item) - - def clear(self): - self._check_frozen() - self._items.clear() - - def extend(self, items): - self._check_frozen() - self._items += list(items) - - def reverse(self): - self._check_frozen() - self._items.reverse() - - def pop(self, index=-1): - self._check_frozen() - return self._items.pop(index) - - def append(self, item): - self._check_frozen() - return self._items.append(item) - - def count(self, item): - return self._items.count(item) - - def __repr__(self): - return ''.format(self._frozen.load(), - self._items) - - def __hash__(self): - if self._frozen.load(): - return hash(tuple(self._items)) - else: - raise RuntimeError("Cannot hash unfrozen list.") - - def __deepcopy__(self, memo): - cdef FrozenList new_list - obj_id = id(self) - - # Return existing copy if already processed (circular reference) - if obj_id in memo: - return memo[obj_id] - - # Create new instance and register immediately - new_list = self.__class__([]) - memo[obj_id] = new_list - - # Deep copy items - new_list._items[:] = [copy.deepcopy(item, memo) for item in self._items] - - # Preserve frozen state - if self._frozen.load(): - new_list.freeze() - - return new_list - - -MutableSequence.register(FrozenList) diff --git a/venv/lib/python3.9/site-packages/frozenlist/py.typed b/venv/lib/python3.9/site-packages/frozenlist/py.typed deleted file mode 100644 index f5642f7..0000000 --- a/venv/lib/python3.9/site-packages/frozenlist/py.typed +++ /dev/null @@ -1 +0,0 @@ -Marker diff --git a/venv/lib/python3.9/site-packages/gevent-26.4.0.dist-info/INSTALLER b/venv/lib/python3.9/site-packages/gevent-26.4.0.dist-info/INSTALLER deleted file mode 100644 index a1b589e..0000000 --- a/venv/lib/python3.9/site-packages/gevent-26.4.0.dist-info/INSTALLER +++ /dev/null @@ -1 +0,0 @@ -pip diff --git a/venv/lib/python3.9/site-packages/gevent-26.4.0.dist-info/METADATA b/venv/lib/python3.9/site-packages/gevent-26.4.0.dist-info/METADATA deleted file mode 100644 index e7ceda5..0000000 --- a/venv/lib/python3.9/site-packages/gevent-26.4.0.dist-info/METADATA +++ /dev/null @@ -1,379 +0,0 @@ -Metadata-Version: 2.4 -Name: gevent -Version: 26.4.0 -Summary: Coroutine-based network library -Home-page: http://www.gevent.org/ -Author: Denis Bilenko -Author-email: denis.bilenko@gmail.com -Maintainer: Jason Madden -Maintainer-email: jason@seecoresoftware.com -License: MIT -Project-URL: Bug Tracker, https://github.com/gevent/gevent/issues -Project-URL: Source Code, https://github.com/gevent/gevent/ -Project-URL: Documentation, http://www.gevent.org -Project-URL: Changes, https://www.gevent.org/changelog.html -Keywords: greenlet coroutine cooperative multitasking light threads monkey -Classifier: Programming Language :: Python :: 3 :: Only -Classifier: Programming Language :: Python :: 3.9 -Classifier: Programming Language :: Python :: 3.10 -Classifier: Programming Language :: Python :: 3.11 -Classifier: Programming Language :: Python :: 3.12 -Classifier: Programming Language :: Python :: 3.13 -Classifier: Programming Language :: Python :: Implementation :: CPython -Classifier: Programming Language :: Python :: Implementation :: PyPy -Classifier: Operating System :: MacOS :: MacOS X -Classifier: Operating System :: POSIX -Classifier: Operating System :: Microsoft :: Windows -Classifier: Topic :: Internet -Classifier: Topic :: Software Development :: Libraries :: Python Modules -Classifier: Intended Audience :: Developers -Classifier: Development Status :: 4 - Beta -Requires-Python: >=3.9 -Description-Content-Type: text/x-rst -License-File: LICENSE -Requires-Dist: greenlet>=3.2.2; platform_python_implementation == "CPython" -Requires-Dist: cffi>=1.17.1; platform_python_implementation == "CPython" and sys_platform == "win32" -Requires-Dist: zope.event -Requires-Dist: zope.interface -Provides-Extra: dnspython -Requires-Dist: dnspython<2.0,>=1.16.0; python_version < "3.10" and extra == "dnspython" -Requires-Dist: idna; python_version < "3.10" and extra == "dnspython" -Provides-Extra: events -Provides-Extra: monitor -Requires-Dist: psutil>=6.0.0; (sys_platform != "win32" or platform_python_implementation == "CPython") and extra == "monitor" -Provides-Extra: recommended -Requires-Dist: cffi>=1.17.1; platform_python_implementation == "CPython" and extra == "recommended" -Requires-Dist: dnspython<2.0,>=1.16.0; python_version < "3.10" and extra == "recommended" -Requires-Dist: idna; python_version < "3.10" and extra == "recommended" -Requires-Dist: psutil>=6.0.0; (sys_platform != "win32" or platform_python_implementation == "CPython") and extra == "recommended" -Provides-Extra: docs -Requires-Dist: sphinx; extra == "docs" -Requires-Dist: furo; extra == "docs" -Requires-Dist: repoze.sphinx.autointerface; extra == "docs" -Requires-Dist: sphinxcontrib-programoutput; extra == "docs" -Requires-Dist: zope.schema; extra == "docs" -Provides-Extra: test -Requires-Dist: cffi>=1.17.1; platform_python_implementation == "CPython" and extra == "test" -Requires-Dist: dnspython<2.0,>=1.16.0; python_version < "3.10" and extra == "test" -Requires-Dist: idna; python_version < "3.10" and extra == "test" -Requires-Dist: psutil>=6.0.0; (sys_platform != "win32" or platform_python_implementation == "CPython") and extra == "test" -Requires-Dist: requests; extra == "test" -Requires-Dist: coverage<7.13,>=5.0; sys_platform != "win32" and extra == "test" -Requires-Dist: objgraph; extra == "test" -Dynamic: author -Dynamic: author-email -Dynamic: classifier -Dynamic: description -Dynamic: home-page -Dynamic: keywords -Dynamic: license -Dynamic: license-file -Dynamic: maintainer -Dynamic: maintainer-email -Dynamic: project-url -Dynamic: provides-extra -Dynamic: requires-dist -Dynamic: requires-python -Dynamic: summary - -======== - gevent -======== - -.. image:: https://github.com/gevent/gevent/workflows/gevent%20testing/badge.svg - :target: https://github.com/gevent/gevent/actions - -.. image:: https://ci.appveyor.com/api/projects/status/bqxl88yhpho223jg?svg=true - :target: https://ci.appveyor.com/project/denik/gevent - -.. image:: https://coveralls.io/repos/gevent/gevent/badge.svg?branch=master&service=github - :target: https://coveralls.io/github/gevent/gevent?branch=master - -.. - This file is included in README.rst from the top-level - so it is limited to pure ReST markup, not Sphinx. - - - -gevent is a coroutine_ -based Python_ networking library that uses -`greenlet `_ to provide a high-level synchronous API on top of the `libev`_ -or `libuv`_ event loop. - -Features include: - - -* Fast event loop based on `libev`_ or `libuv`_. -* Lightweight execution units based on greenlets. -* API that re-uses concepts from the Python standard library (for - examples there are `events`_ and - `queues`_). -* `Cooperative sockets with SSL support `_ -* `Cooperative DNS queries `_ performed through a threadpool, - dnspython, or c-ares. -* `Monkey patching utility `_ to get 3rd party modules to become cooperative -* TCP/UDP/HTTP servers -* Subprocess support (through `gevent.subprocess`_) -* Thread pools - -gevent is `inspired by eventlet`_ but features a more consistent API, -simpler implementation and better performance. Read why others `use -gevent`_ and check out the list of the `open source projects based on -gevent`_. - -gevent was written by `Denis Bilenko `_. - -Since version 1.1, gevent is maintained by Jason Madden for -`NextThought `_ (through gevent 21) and -`Institutional Shareholder Services `_ -with help from the `contributors -`_ and is -licensed under the MIT license. - -See `what's new`_ in the latest major release. - -Check out the detailed changelog_ for this version. - -.. _events: http://www.gevent.org/api/gevent.event.html#gevent.event.Event -.. _queues: http://www.gevent.org/api/gevent.queue.html#gevent.queue.Queue -.. _gevent.subprocess: http://www.gevent.org/api/gevent.subprocess.html#module-gevent.subprocess - -.. _coroutine: https://en.wikipedia.org/wiki/Coroutine -.. _Python: http://python.org -.. _libev: http://software.schmorp.de/pkg/libev.html -.. _libuv: http://libuv.org -.. _inspired by eventlet: http://blog.gevent.org/2010/02/27/why-gevent/ -.. _use gevent: http://groups.google.com/group/gevent/browse_thread/thread/4de9703e5dca8271 -.. _open source projects based on gevent: https://github.com/gevent/gevent/wiki/Projects -.. _what's new: http://www.gevent.org/whatsnew_1_5.html -.. _changelog: http://www.gevent.org/changelog.html - - -Read the documentation online at http://www.gevent.org. - -Post issues on the `bug tracker`_, discuss and ask open ended -questions on the `mailing list`_, and find announcements and -information on the blog_ and `twitter (@gevent)`_. - -=============================== - Installation and Requirements -=============================== - -.. _installation: - -.. - This file is included in README.rst so it is limited to plain - ReST markup, not Sphinx. - -.. note:: - - If you are reading this document on the `Python Package Index`_ - (PyPI, https://pypi.org/), it is specific to the version of gevent that - you are viewing. If you are viewing this document on gevent.org, it - refers to the current state of gevent in source control (git - master). - -Supported Platforms -=================== - -This version of gevent runs on Python 3.9 and up (for exact details -of tested versions, see the classifiers on the PyPI page or in -``setup.py``). gevent requires the `greenlet -`_ library and will install the -`cffi`_ library by default on Windows. The cffi library will become -the default on all platforms in a future release of gevent. - -This version of gevent is also tested on PyPy 3.10 (7.3.12); it -should run on PyPy 3.9 and above. On PyPy, there are no external -dependencies. - -gevent is tested on Windows, macOS, and Linux, and should run on most -other Unix-like operating systems (e.g., FreeBSD, Solaris, etc.) - -.. note:: - - Windows is supported as a tier 2, "best effort," platform. It is - suitable for development, but not recommended for production. In - particular, PyPy3 on Windows may have issues, especially with - subprocesses. - - On Windows, using the deprecated libev backend, gevent is - limited to a maximum of 1024 open sockets due to - `limitations in libev`_. This limitation should not exist - with the default libuv backend. - - -.. admonition:: Free-Threading is not Supported - - Beginning with 3.14 (and experimental in 3.13), CPython may be - built in a free-threaded mode where the GIL is not used by default. - gevent does not support this mode (although it will build with it), - and using gevent in such an interpreter will cause the GIL to be - enabled. - - The underlying greenlet library `also has this limitation - `_. - - In addition, other limitations in greenlet mean that attempting to - use gevent in a free-threaded interpreter is not recommended at - this time. It is likely to work, but may have resource leaks. - -Older Versions of Python ------------------------- - -Users of older versions of Python 2 or Python 3 may install an older -version of gevent. Note that these versions are generally not -supported. - -+-------+-------+ -|Python |Gevent | -|Version|Version| -+=======+=======+ -|2.5 |1.0.x | -| | | -+-------+-------+ -|2.6 |1.1.x | -+-------+-------+ -|<= |1.2.x | -|2.7.8 | | -+-------+-------+ -|3.3 |1.2.x | -+-------+-------+ -|3.4.0 -| 1.3.x | -|3.4.2 | | -| | | -+-------+-------+ -|3.4.3 | 1.4.x | -| | | -| | | -+-------+-------+ -|3.5.x | 20.9.0| -| | | -| | | -+-------+-------+ -|2.7.9 -| | -|2.7.18,| 22.10 | -|3.6, | | -|3.7 | | -| | | -+-------+-------+ -|3.8 | 24.2.1| -+-------+-------+ - -Installation -============ - -.. note:: - - This section is about installing released versions of gevent as - distributed on the `Python Package Index`_. For building gevent - from source, including customizing the build and embedded - libraries, see `Installing From Source`_. - -.. _Python Package Index: http://pypi.org/project/gevent - -gevent and greenlet can both be installed with `pip`_, e.g., ``pip -install gevent``. Installation using `buildout -`_ is also supported. - -On Windows, macOS, and Linux, both gevent and greenlet are -distributed as binary `wheels`_. - -.. tip:: - - You need Pip 8.0 or later, or buildout 2.10.0, to install the binary - wheels on Windows or macOS. On Linux, you'll need `pip 19 - `_ to install the - manylinux2010 wheels. - -.. tip:: - - While the x86-64 binaries are considered production quality, they - are built with relatively low optimization levels and no hardware - specific optimizations. Serious production users are encouraged to - install from source with appropriate compiler flags. - -.. tip:: - - Beginning with gevent 20.12.0, 64-bit ARM binaries are distributed - on PyPI for aarch64 manylinux2014 compatible systems. Installing these - needs a very recent version of ``pip``. These wheels *do not* - contain the c-ares resolver, are not tested, and are built with - very low levels of optimization. Serious production users of - gevent on 64-bit ARM systems are encouraged to build their own - binary wheels. - - Beginning with gevent 22.10.0, ppc64le binaries are distributed on - PyPI. The same caveats apply as for 64-bit ARM binaries. Using them - for anything other than local development is discouraged. - - Beginning with gevent 23, muslinux aarch64 and S390X binaries - are distributed on PyPI. The same caveats apply as for 64-bit ARM - binaries. Using them for anything other than local development is - discouraged. - - -Installing From Source ----------------------- - -If you are unable to use the binary wheels (for platforms where no -pre-built wheels are available or if wheel installation is disabled), -you can build gevent from source. A normal ``pip install`` will -fall back to doing this if no binary wheel is available. See -`Installing From Source`_ for more, including common installation issues. - -Extra Dependencies -================== - -There are a number -of additional libraries that extend gevent's functionality and will be -used if they are available. All of these may be installed using -`setuptools extras -`_, -as named below, e.g., ``pip install gevent[events]``. - -events - In versions of gevent up to and including 20.5.0, this provided configurable - event support using `zope.event - `_ and was highly - recommended. - - In versions after that, this extra is empty and does nothing. It - will be removed in gevent 21.0. - -dnspython - Enables a pure-Python resolver, backed by `dnspython - `_. On Python 2, this also - includes `idna `_. They can be - installed with the ``dnspython`` extra. - - .. note:: This is not compatible with Python 3.10+ or dnspython 2. - -monitor - Enhancements to gevent's self-monitoring capabilities. This - includes the `psutil `_ library, - which is needed to monitor memory usage. (Note that this may not - build on all platforms.) - -recommended - A shortcut for installing suggested extras together. This includes - the non-test extras defined here, plus additions that improve - gevent's operation on certain platforms (for example, in the past, - it has included backports of newer APIs). - -test - Everything needed to run the complete gevent test suite. - - -.. _`pip`: https://pip.pypa.io/en/stable/installing/ -.. _`wheels`: http://pythonwheels.com -.. _`gevent 1.5`: whatsnew_1_5.html -.. _`Installing From Source`: https://www.gevent.org/development/installing_from_source.html - -.. _`cffi`: https://cffi.readthedocs.io -.. _`limitations in libev`: http://pod.tst.eu/http://cvs.schmorp.de/libev/ev.pod#WIN32_PLATFORM_LIMITATIONS_AND_WORKA - - -.. _bug tracker: https://github.com/gevent/gevent/issues -.. _mailing list: http://groups.google.com/group/gevent -.. _blog: https://dev.nextthought.com/blog/categories/gevent.html -.. _twitter (@gevent): http://twitter.com/gevent diff --git a/venv/lib/python3.9/site-packages/gevent-26.4.0.dist-info/RECORD b/venv/lib/python3.9/site-packages/gevent-26.4.0.dist-info/RECORD deleted file mode 100644 index ee4c930..0000000 --- a/venv/lib/python3.9/site-packages/gevent-26.4.0.dist-info/RECORD +++ /dev/null @@ -1,559 +0,0 @@ -gevent-26.4.0.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 -gevent-26.4.0.dist-info/METADATA,sha256=Hnd4JrwMFUuiDjdWs2zZI0qizU5cCCzJuY1xxqrgALk,14436 -gevent-26.4.0.dist-info/RECORD,, -gevent-26.4.0.dist-info/REQUESTED,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 -gevent-26.4.0.dist-info/WHEEL,sha256=qPmJyWyQZZZsTIoPVtZka1PEBRwhSMmilee5MyOokDs,102 -gevent-26.4.0.dist-info/entry_points.txt,sha256=g2MTL3KfdJVJ6CEp0d4f9x6HjLAp-MklXYlxlZQ9_u4,95 -gevent-26.4.0.dist-info/licenses/LICENSE,sha256=TUa8EdGeOFPVQyWXO44sUwkPVjinvyf6H18SMseJAfc,1235 -gevent-26.4.0.dist-info/top_level.txt,sha256=fpElGiTe2fdw27vmNxdV5MQpyndjzWZMk5TB_NMYPSI,7 -gevent/__init__.py,sha256=k443jQ4OP8p_xpvLDmPA_k2AJX8c0drC9PSUzQI3PCY,3406 -gevent/__pycache__/__init__.cpython-39.pyc,, -gevent/__pycache__/_abstract_linkable.cpython-39.pyc,, -gevent/__pycache__/_compat.cpython-39.pyc,, -gevent/__pycache__/_config.cpython-39.pyc,, -gevent/__pycache__/_fileobjectcommon.cpython-39.pyc,, -gevent/__pycache__/_fileobjectposix.cpython-39.pyc,, -gevent/__pycache__/_greenlet_primitives.cpython-39.pyc,, -gevent/__pycache__/_hub_local.cpython-39.pyc,, -gevent/__pycache__/_hub_primitives.cpython-39.pyc,, -gevent/__pycache__/_ident.cpython-39.pyc,, -gevent/__pycache__/_imap.cpython-39.pyc,, -gevent/__pycache__/_interfaces.cpython-39.pyc,, -gevent/__pycache__/_monitor.cpython-39.pyc,, -gevent/__pycache__/_patcher.cpython-39.pyc,, -gevent/__pycache__/_semaphore.cpython-39.pyc,, -gevent/__pycache__/_socket3.cpython-39.pyc,, -gevent/__pycache__/_socketcommon.cpython-39.pyc,, -gevent/__pycache__/_tblib.cpython-39.pyc,, -gevent/__pycache__/_threading.cpython-39.pyc,, -gevent/__pycache__/_tracer.cpython-39.pyc,, -gevent/__pycache__/_util.cpython-39.pyc,, -gevent/__pycache__/_waiter.cpython-39.pyc,, -gevent/__pycache__/ares.cpython-39.pyc,, -gevent/__pycache__/backdoor.cpython-39.pyc,, -gevent/__pycache__/baseserver.cpython-39.pyc,, -gevent/__pycache__/builtins.cpython-39.pyc,, -gevent/__pycache__/contextvars.cpython-39.pyc,, -gevent/__pycache__/core.cpython-39.pyc,, -gevent/__pycache__/event.cpython-39.pyc,, -gevent/__pycache__/events.cpython-39.pyc,, -gevent/__pycache__/exceptions.cpython-39.pyc,, -gevent/__pycache__/fileobject.cpython-39.pyc,, -gevent/__pycache__/greenlet.cpython-39.pyc,, -gevent/__pycache__/hub.cpython-39.pyc,, -gevent/__pycache__/local.cpython-39.pyc,, -gevent/__pycache__/lock.cpython-39.pyc,, -gevent/__pycache__/os.cpython-39.pyc,, -gevent/__pycache__/pool.cpython-39.pyc,, -gevent/__pycache__/pywsgi.cpython-39.pyc,, -gevent/__pycache__/queue.cpython-39.pyc,, -gevent/__pycache__/resolver_ares.cpython-39.pyc,, -gevent/__pycache__/resolver_thread.cpython-39.pyc,, -gevent/__pycache__/select.cpython-39.pyc,, -gevent/__pycache__/selectors.cpython-39.pyc,, -gevent/__pycache__/server.cpython-39.pyc,, -gevent/__pycache__/signal.cpython-39.pyc,, -gevent/__pycache__/socket.cpython-39.pyc,, -gevent/__pycache__/ssl.cpython-39.pyc,, -gevent/__pycache__/subprocess.cpython-39.pyc,, -gevent/__pycache__/thread.cpython-39.pyc,, -gevent/__pycache__/threading.cpython-39.pyc,, -gevent/__pycache__/threadpool.cpython-39.pyc,, -gevent/__pycache__/time.cpython-39.pyc,, -gevent/__pycache__/timeout.cpython-39.pyc,, -gevent/__pycache__/util.cpython-39.pyc,, -gevent/__pycache__/win32util.cpython-39.pyc,, -gevent/_abstract_linkable.py,sha256=oN5vmwA87__1J4uYo_Fha94tRlnOSzDIn5c22JMpgAY,23307 -gevent/_compat.py,sha256=9PIVyfCmm2qbERq4r8vorDXhDI4RqSACYg2-gT5XBsM,4147 -gevent/_config.py,sha256=iqrPFIMuU_FON_EJWW2eADkkSlcoRNq5FSCGkd2lqAY,21843 -gevent/_ffi/__init__.py,sha256=BTBgjjvO4ecQBPbReBhem-0zvy1Mq6jXf5dMrykGIhs,493 -gevent/_ffi/__pycache__/__init__.cpython-39.pyc,, -gevent/_ffi/__pycache__/callback.cpython-39.pyc,, -gevent/_ffi/__pycache__/loop.cpython-39.pyc,, -gevent/_ffi/__pycache__/watcher.cpython-39.pyc,, -gevent/_ffi/callback.py,sha256=JL2mvMVD7vVaatIdUxo9UfvUJvIwiHhZ7qLGgiBc8YA,1564 -gevent/_ffi/loop.py,sha256=bkRKg67wfjHhYM5DPBzeiMZQ5tqdM0ijC-waBGO85CY,32221 -gevent/_ffi/watcher.py,sha256=eaTCOfOPCTn2sGqf7CwbZcRNr0AzG7gfIYOasZ-5S64,20982 -gevent/_fileobjectcommon.py,sha256=S-69DeitiPnvjbGfexTuD2yzPeI0-eDv_1DBIlV0sTg,24359 -gevent/_fileobjectposix.py,sha256=_-olxI6HSHVOBMIy7cuVjzQ310D7TJDN_BcEvS_GfVg,12867 -gevent/_gevent_c_abstract_linkable.cpython-39-x86_64-linux-gnu.so,sha256=O07bl8aNrNceFmkuBS2UCL66lSeqaI7-kwGlgwe7R2k,879184 -gevent/_gevent_c_greenlet_primitives.cpython-39-x86_64-linux-gnu.so,sha256=9cpbgKub87cCu49c8QU8JJAL6TZcBAkQ-r9WC56l6Hk,467856 -gevent/_gevent_c_hub_local.cpython-39-x86_64-linux-gnu.so,sha256=1t3qaQIYxvP483N1KxfewAvUsGEIdPjJEe1EQMtZKL8,384480 -gevent/_gevent_c_hub_primitives.cpython-39-x86_64-linux-gnu.so,sha256=_ek8g-WMo6EIIGyQP7HOyX5P_v_RP0ddIyrs2RTJ96k,1004536 -gevent/_gevent_c_ident.cpython-39-x86_64-linux-gnu.so,sha256=bUG6mv5TI9v7NkMCC9o10b9MkUJQVToJtKoyoO8t1AM,319160 -gevent/_gevent_c_imap.cpython-39-x86_64-linux-gnu.so,sha256=yy6UVK62k_m0zeGhbCEkb5PVMHibFz5sxeMVUydObd0,569744 -gevent/_gevent_c_semaphore.cpython-39-x86_64-linux-gnu.so,sha256=QVBGNjkOOfHh-MuDGJgj3haVQj26D9_qRqNbh-WhVGs,919784 -gevent/_gevent_c_tracer.cpython-39-x86_64-linux-gnu.so,sha256=1B_wnnqcc-Y0CEywfZLCrXA98CGLRMFv5PNa2Brg32w,653632 -gevent/_gevent_c_waiter.cpython-39-x86_64-linux-gnu.so,sha256=l1hE4BZaskv7eUVV5-WkAfkCooMs8otDvFBYWyYrwQ4,520072 -gevent/_gevent_cevent.cpython-39-x86_64-linux-gnu.so,sha256=KZfOdE_NAHyp2z7olnnduswJFez9Mb0PFN_MWr7ud6E,726696 -gevent/_gevent_cgreenlet.cpython-39-x86_64-linux-gnu.so,sha256=U3KDIpM3TfPE46dnClSeb-AZ5w-fLdUbvxZjlFou-W8,1737160 -gevent/_gevent_clocal.cpython-39-x86_64-linux-gnu.so,sha256=SleSWJwy9N4fHnGPwAPxAYntWJ2j5yhCJF_bbyGbayk,892704 -gevent/_gevent_cqueue.cpython-39-x86_64-linux-gnu.so,sha256=oisEYUbjuiNSOr325cLEBJ47Ks1wEVIKOZUgUZDZBoA,1617424 -gevent/_greenlet_primitives.py,sha256=i2b0bj5oYr5qzhRRQPhzbCMEg9zMRAx_zhiSOCHtTeY,4647 -gevent/_hub_local.py,sha256=8GJdnF5I-0FnfHHRadOzHVbkOSQaTpZEXSrVFi3s_ME,4827 -gevent/_hub_primitives.py,sha256=aTCXhH1gJNdb1JONz7X0fBnNCu9Lv1U55sVF2dXpnUk,14026 -gevent/_ident.py,sha256=w7kjbyaNR4MVzRTjB0_3ZUZ-JYS6eukY55l-r_MdjM4,2249 -gevent/_imap.py,sha256=RtrIfyUPPMFxNX4gSVuJQLjn6oxIdI2t9ERVErIgtwg,7672 -gevent/_interfaces.py,sha256=x6C1cCk3taLGZHgZdntaZ1lm1tc8vv4bpMZuJHHKlls,9985 -gevent/_monitor.py,sha256=u4mr6Jm_rifaBz_c_ucspvK2ycTWA8u_6js03cJScls,12079 -gevent/_patcher.py,sha256=e4dfPB9MhmnipVpwwEPcChMbiC2F0Rp_MdkwZ02ZF_c,9020 -gevent/_semaphore.py,sha256=BBjdqHfz8NFVD_XbKbiGxgMUvxYfGeBXA1qh26tgqb8,20887 -gevent/_socket3.py,sha256=un-14nAyir0Qt4t4oan_r4k7B54h20KLJWUpyavm4Go,23663 -gevent/_socketcommon.py,sha256=v2d0FGS_2jlw8bHeX7HC37Xpc7TnpCqojx1sfU6PPNE,25984 -gevent/_tblib.py,sha256=KEUqdUGWtBQiqffg-iFs5DXPFhxs5B-pdfDjjDsf2Cg,12810 -gevent/_threading.py,sha256=mYFPLhSlSWXTGDixNLm0JFfnh3jH1e51fyl5iSXaczM,8342 -gevent/_tracer.py,sha256=FX1B-6s7GWWKLvcdYKRZYCbHABy9i3c5p66cy95ijKM,6455 -gevent/_util.py,sha256=piN-RGPbJ5H2-HLylfwPOfYILdKvkvFWyu4KcWLI9_U,10984 -gevent/_waiter.py,sha256=fCVW5AxbqvIYROgHbC22kljXr6wHIr54fPePtTVMoW4,7387 -gevent/ares.py,sha256=2LLRXoWkyS5YwSpJ0b7R_e3M8ikwpsA53eUWizys8eM,383 -gevent/backdoor.py,sha256=9QhAL6qPSgBgVVSXYyUXC8DbFwRIxKkQ8kzQreZq4LQ,8674 -gevent/baseserver.py,sha256=WANbcgk4Sa0Se-vnF_jM7vPpi4lU224djJ2eiH7Rgao,16716 -gevent/builtins.py,sha256=0K7haEs0DhfIEhArBaxaRRx_i3Dws2ZqFWey6HOYjHo,4108 -gevent/contextvars.py,sha256=a0f8GxwQESkQM-zUNO-gdmDcW-2-kV321auE6KbSHGw,9838 -gevent/core.py,sha256=XgaVreHocvO9JCVby3JCo8ixbllJL08V9OrA7ETDaHs,479 -gevent/event.py,sha256=A3jGW2iaUrZ5NxE2aZeZKoGOVogFwuvy_PEN7-KOLEo,15110 -gevent/events.py,sha256=olRj_SbHNW-I8Ifs6vNYWaRKV0bWtgEFnOYt6Uhihuk,17182 -gevent/exceptions.py,sha256=0YCfR0WyL1VFtQ5oqKtr8sj8ts0U8wh04UDGwH-_8cc,3823 -gevent/fileobject.py,sha256=GNeYmbGSLWq8t311pVbgYsyDpzMmtQ8m2fHI15a0EpI,3020 -gevent/greenlet.py,sha256=_mE6nBep4cyCPXHgJB7FSaZCbOskwezE3vtL_Zwqkys,46347 -gevent/hub.py,sha256=_ZodHnESbnnj2qg8p-4aGhY4HH4u-7T7wJHI00JYJAM,34590 -gevent/libev/__init__.py,sha256=I6hpYFJCnbBBDrousKzZ7Ql--mnfAFwfM2q1BuxcMfI,169 -gevent/libev/__pycache__/__init__.cpython-39.pyc,, -gevent/libev/__pycache__/_corecffi_build.cpython-39.pyc,, -gevent/libev/__pycache__/corecffi.cpython-39.pyc,, -gevent/libev/__pycache__/watcher.cpython-39.pyc,, -gevent/libev/_corecffi.abi3.so,sha256=VoHh59-nVDCO4EtpUzlJ6W0282KYlAW29ILA3A63M8w,383680 -gevent/libev/_corecffi_build.py,sha256=ARUO9jiMqdfk80aSs4_CkBIIwcpUaF9enyj-AJVXVP8,4059 -gevent/libev/corecext.cpython-39-x86_64-linux-gnu.so,sha256=ta1-gwLgDxY7GGbp04Ve1MyFEDlXllQDQBZh3nki3t8,2401256 -gevent/libev/corecffi.py,sha256=yxz0x6YzcQSFPSuba3JJpPJkkdU7KBwFPa299cGOGSw,13720 -gevent/libev/watcher.py,sha256=eaIiXusNuLSN3DtEqB3BpbgS6C91dSfYJT7pX7Kw5Ac,8196 -gevent/libuv/__init__.py,sha256=I6hpYFJCnbBBDrousKzZ7Ql--mnfAFwfM2q1BuxcMfI,169 -gevent/libuv/__pycache__/__init__.cpython-39.pyc,, -gevent/libuv/__pycache__/_corecffi_build.cpython-39.pyc,, -gevent/libuv/__pycache__/loop.cpython-39.pyc,, -gevent/libuv/__pycache__/watcher.cpython-39.pyc,, -gevent/libuv/_corecffi.abi3.so,sha256=4iFT1W6Jq2l5brV5U13hyai98j2_24CI9zHd-z-1yM0,1282272 -gevent/libuv/_corecffi_build.py,sha256=0vp4N0SsIS_ClIba_1_hdwH4A_bWiMQdTOrHT8HJbyo,11676 -gevent/libuv/loop.py,sha256=sAjyJe48RpOrldp0hxXWJ8LpukKZSnvsyZLIEA_jl6Y,30385 -gevent/libuv/watcher.py,sha256=eKYkUdYsPhWYc-eOJh1-LFqVK1FG6o3N3aoMnvg1xJ4,29069 -gevent/local.py,sha256=I12OWg8nWR5q7p3UZhJjSMfbyHuShVqYqQTkmPdF-8k,21457 -gevent/lock.py,sha256=szq7dShyvOHad-nZPXH8p-JA2WKBaeY6PXx4arFqsJM,11587 -gevent/monkey/__init__.py,sha256=3STdzP6RHGLUkRrSkTVPpHGccz3kRSeq4hUswYtdIDw,26713 -gevent/monkey/__main__.py,sha256=JPNIwI-Qb_VQERows-n4R2XzcY8rGCt5FR8kUiKD1J4,31 -gevent/monkey/__pycache__/__init__.cpython-39.pyc,, -gevent/monkey/__pycache__/__main__.cpython-39.pyc,, -gevent/monkey/__pycache__/_errors.cpython-39.pyc,, -gevent/monkey/__pycache__/_main.cpython-39.pyc,, -gevent/monkey/__pycache__/_patch_thread_common.cpython-39.pyc,, -gevent/monkey/__pycache__/_patch_thread_gte313.cpython-39.pyc,, -gevent/monkey/__pycache__/_patch_thread_lt313.cpython-39.pyc,, -gevent/monkey/__pycache__/_state.cpython-39.pyc,, -gevent/monkey/__pycache__/_util.cpython-39.pyc,, -gevent/monkey/__pycache__/api.cpython-39.pyc,, -gevent/monkey/_errors.py,sha256=cBctoXo4sAME97eaCdWGY1q1zEOtG8krDFyv-O5WOiQ,547 -gevent/monkey/_main.py,sha256=8zzhBLrRSBV0D_GbgwcY_iwsIR3ayrG9xX8TvyGAvH8,4411 -gevent/monkey/_patch_thread_common.py,sha256=tC4pYcPNGwGUEmDCeZ0Gqu2uqPTNLBVdoQY4GSh4tA0,13253 -gevent/monkey/_patch_thread_gte313.py,sha256=qJ-zRqorbNu_TheCLQbkRjpnU0qHsys5dgjEF7K4Rx0,4082 -gevent/monkey/_patch_thread_lt313.py,sha256=CTsQFPuHDrXyIphWZAYWqMwHVhYg_ucWsVR-93UFFlk,3182 -gevent/monkey/_state.py,sha256=FGJFTDXFUwio1b-IwtlOmXCysVrqheM9j9JjRxOzrqI,1897 -gevent/monkey/_util.py,sha256=U-KBkLB9v5J7RedNHOfK7qaaonaKo5Z7oQ-5gwrYnAo,3689 -gevent/monkey/api.py,sha256=ZoRUk0e-wVXE6CnTI8BULQaDAIVqyEmTCwXhVzUrh5s,6760 -gevent/os.py,sha256=Qikg66OYH_k8r-Zd9QKMIqWoDCWkZ3-SA53_IL0rfis,26187 -gevent/pool.py,sha256=JSt0I106SQr3wYjc9z919ebcX3MUyM33gaAbohSXNCo,25634 -gevent/pywsgi.py,sha256=45e-9_KKZx23OGfvwEadV2r8xLL6HZnaJZuym2qTbIQ,69235 -gevent/queue.py,sha256=X3liAQ9DM-0a7u6JBxFEQgpd_ilIy0XKB6sydV0EVw0,27832 -gevent/resolver/__init__.py,sha256=lx0L8Up3DXkp61RQxceQbmj5AVFt9WGMhHi12-iy7GI,10760 -gevent/resolver/__pycache__/__init__.cpython-39.pyc,, -gevent/resolver/__pycache__/_addresses.cpython-39.pyc,, -gevent/resolver/__pycache__/_hostsfile.cpython-39.pyc,, -gevent/resolver/__pycache__/ares.cpython-39.pyc,, -gevent/resolver/__pycache__/blocking.cpython-39.pyc,, -gevent/resolver/__pycache__/dnspython.cpython-39.pyc,, -gevent/resolver/__pycache__/thread.cpython-39.pyc,, -gevent/resolver/_addresses.py,sha256=BvLXxwN1QTQ4Pajgk5UwvHRP6J8TDQ8n-_75AfIaOVo,4795 -gevent/resolver/_hostsfile.py,sha256=KY6q-aY5F1f3MV4SZioAcstBRvxm4647-JKlCtY47E0,4629 -gevent/resolver/ares.py,sha256=6Oed67PUah45MwMQz3KFIWNAnm7XkoRJXx9vz7voJEc,12965 -gevent/resolver/blocking.py,sha256=5ubBMewB7X-JouMKIlf_s2JNw4KJ_EqmNVUg4PrrSaA,1216 -gevent/resolver/cares.cpython-39-x86_64-linux-gnu.so,sha256=9M1IetYJVo-WyBPBoIZzAPV8Gt63PQxufe4oQJBHC-E,2807072 -gevent/resolver/dnspython.py,sha256=cZ0mQyWluVz_h2YsyS_sSg0n7NEpuFPsZhp63WMyFeg,20706 -gevent/resolver/thread.py,sha256=DTSwSwBRsSJKjPjyAHS0qT07oDxmFOhR4wYLfSSaJCU,2487 -gevent/resolver_ares.py,sha256=s5Jo9Z0b-zKxSWcIvW5onaFE2OrfqLuNnTPlOoxFxEQ,486 -gevent/resolver_thread.py,sha256=jcKcEVCXwyRqcsDUZmryQ9hc-83yztgaM4kuTKHOvaw,504 -gevent/select.py,sha256=Adagyqf9HURToTcOx18_JbXET3pTf1lV3bi953877VM,13582 -gevent/selectors.py,sha256=DBW8Wv3NipQCIxqO3IiQfvM_vyjGLdJv9q9c9pCClVU,12573 -gevent/server.py,sha256=7rrN3Ieujlo0vKddDyYIqgocslsW-3VNG-faOfOk7vE,10852 -gevent/signal.py,sha256=voK9aRWTaAfbiiRhiCVpwomJe9NI_w937B2HbNAXmVw,6834 -gevent/socket.py,sha256=CUC-jiNIjbXghj_muCXyn9Ij7GUDa44kKxBb3F1-PMM,6503 -gevent/ssl.py,sha256=pF2sqESHcRdaRNMoNpUqrV7NGBUVWo10pHP11N53TKA,34832 -gevent/subprocess.py,sha256=ayCXgBB4I4ySnwSn0Flb0XnCAIMZCYbIl4YlW-WgcYI,85082 -gevent/testing/__init__.py,sha256=WRhMiGHQ0B_35EoZXOTRsguBIu694cyFQVoozWwXMAE,5532 -gevent/testing/__pycache__/__init__.cpython-39.pyc,, -gevent/testing/__pycache__/errorhandler.cpython-39.pyc,, -gevent/testing/__pycache__/exception.cpython-39.pyc,, -gevent/testing/__pycache__/flaky.cpython-39.pyc,, -gevent/testing/__pycache__/hub.cpython-39.pyc,, -gevent/testing/__pycache__/leakcheck.cpython-39.pyc,, -gevent/testing/__pycache__/modules.cpython-39.pyc,, -gevent/testing/__pycache__/monkey_test.cpython-39.pyc,, -gevent/testing/__pycache__/openfiles.cpython-39.pyc,, -gevent/testing/__pycache__/params.cpython-39.pyc,, -gevent/testing/__pycache__/patched_tests_setup.cpython-39.pyc,, -gevent/testing/__pycache__/resources.cpython-39.pyc,, -gevent/testing/__pycache__/six.cpython-39.pyc,, -gevent/testing/__pycache__/skipping.cpython-39.pyc,, -gevent/testing/__pycache__/sockets.cpython-39.pyc,, -gevent/testing/__pycache__/support.cpython-39.pyc,, -gevent/testing/__pycache__/switching.cpython-39.pyc,, -gevent/testing/__pycache__/sysinfo.cpython-39.pyc,, -gevent/testing/__pycache__/testcase.cpython-39.pyc,, -gevent/testing/__pycache__/testrunner.cpython-39.pyc,, -gevent/testing/__pycache__/timing.cpython-39.pyc,, -gevent/testing/__pycache__/travis.cpython-39.pyc,, -gevent/testing/__pycache__/util.cpython-39.pyc,, -gevent/testing/coveragesite/__pycache__/sitecustomize.cpython-39.pyc,, -gevent/testing/coveragesite/sitecustomize.py,sha256=FYxC7JifoSRVmQ4tM6gaiiyW9E9trwlMy1I8eGvHXZc,2503 -gevent/testing/errorhandler.py,sha256=NzoItIrdz8t0YOFEAa6fn9WyFnubs_egnpV8yD7AcDQ,2329 -gevent/testing/exception.py,sha256=yQHF9Ebom2JAKUq70mLsdFk9p4eorpK36O-3iH1LL1Q,1265 -gevent/testing/flaky.py,sha256=x-IujIZGK_m2FYRyi4RxKMZhLfxq25p47En4DAlYhCs,4104 -gevent/testing/hub.py,sha256=Qmo7bcZPLIEOF7mncgV3vR-KrbHLUT_pORNQejrltig,3115 -gevent/testing/leakcheck.py,sha256=GWs8MQFj3Lwh9bCHuyExeu3_RuiEdByHr3YGTP00mxA,8612 -gevent/testing/modules.py,sha256=qGfvohEps4mo6_hqcRZHlEuxBx1wDNqRY_DZmJDM61o,4987 -gevent/testing/monkey_test.py,sha256=tOkTRrC4jyAh5DLhO3tNNePLPKjPpuIWIy8KghU5EMk,6112 -gevent/testing/openfiles.py,sha256=g_CYpyt2ekNVeM5nKTUmghiY6PsNsPY2HXsHwH3qP_s,8743 -gevent/testing/params.py,sha256=B-5PoctZfrtii3rcjA68kmI0wvwg7_sHJ4pWFzRAcbw,2674 -gevent/testing/patched_tests_setup.py,sha256=lQeXiCGKQstTwMum-ndB4iEg4wdAHHz-Q55-yJQ3HHo,68305 -gevent/testing/resources.py,sha256=C3cxaDi56orLzs50vTCnGElxk-ChJBjFV3JX2f610_A,7481 -gevent/testing/six.py,sha256=Q1c2A317t3agHEH1CJBn6y13Q0jJZ2t4BCruyNfujMA,278 -gevent/testing/skipping.py,sha256=UT6GA4z9n2pJJ2WY7dmcPS-U3FdwKoDUWpTWzqRsiUY,6650 -gevent/testing/sockets.py,sha256=CvtRiCVxCXcv_Vv3OFQiEYEH-Mok32sY18JiATEbeI4,2285 -gevent/testing/support.py,sha256=hn2IghJcKYUcS7hcii9RdWBLy0gGOu2nRTlEEvaq06U,4631 -gevent/testing/switching.py,sha256=6idIaCiHKFZF8aibeHjxIdZi38cxXCKuhQRHUT1YWoo,2708 -gevent/testing/sysinfo.py,sha256=GjlaaTxfi0axRZJ4m9awfvlia5C508RsnOI60xr7ccg,7870 -gevent/testing/testcase.py,sha256=3efJN9HcU3KrznyOLaVeQ3KzxaV_2VDLwj4Tlbzuxac,18679 -gevent/testing/testrunner.py,sha256=GmJlQIgCgWk1LmNCXQxfs3-B88nQUSOtRzFFeBevIdA,36552 -gevent/testing/timing.py,sha256=Yy9dQ3KvJ9uEV6BwpgM3ZEnVYP1ic6jgVGqZF1uWLLc,4982 -gevent/testing/travis.py,sha256=yYJlIY2L4vMzSxaODPVhANFaB_svNmwhrw4CRotQXlc,877 -gevent/testing/util.py,sha256=vZrHh7xCJfFukG41yFwyLMx9LFaQrpbFJS4sVRhMsO0,19271 -gevent/tests/2_7_keycert.pem,sha256=PuSO2qCmga4an7pkSs7ep1Fo16yrQKd9i84DnrqSYcI,5081 -gevent/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 -gevent/tests/__main__.py,sha256=EMw-OppCjl-heu15mLg-cf400NS1Ikuy96OisvLoKLM,179 -gevent/tests/__pycache__/__init__.cpython-39.pyc,, -gevent/tests/__pycache__/__main__.cpython-39.pyc,, -gevent/tests/__pycache__/_blocks_at_top_level.cpython-39.pyc,, -gevent/tests/__pycache__/_import_import_patch.cpython-39.pyc,, -gevent/tests/__pycache__/_import_patch.cpython-39.pyc,, -gevent/tests/__pycache__/_import_wait.cpython-39.pyc,, -gevent/tests/__pycache__/_imports_at_top_level.cpython-39.pyc,, -gevent/tests/__pycache__/_imports_imports_at_top_level.cpython-39.pyc,, -gevent/tests/__pycache__/getaddrinfo_module.cpython-39.pyc,, -gevent/tests/__pycache__/known_failures.cpython-39.pyc,, -gevent/tests/__pycache__/lock_tests.cpython-39.pyc,, -gevent/tests/__pycache__/test__GreenletExit.cpython-39.pyc,, -gevent/tests/__pycache__/test___config.cpython-39.pyc,, -gevent/tests/__pycache__/test___ident.cpython-39.pyc,, -gevent/tests/__pycache__/test___monitor.cpython-39.pyc,, -gevent/tests/__pycache__/test___monkey_patching.cpython-39.pyc,, -gevent/tests/__pycache__/test__all__.cpython-39.pyc,, -gevent/tests/__pycache__/test__api.cpython-39.pyc,, -gevent/tests/__pycache__/test__api_timeout.cpython-39.pyc,, -gevent/tests/__pycache__/test__ares_host_result.cpython-39.pyc,, -gevent/tests/__pycache__/test__ares_timeout.cpython-39.pyc,, -gevent/tests/__pycache__/test__backdoor.cpython-39.pyc,, -gevent/tests/__pycache__/test__close_backend_fd.cpython-39.pyc,, -gevent/tests/__pycache__/test__compat.cpython-39.pyc,, -gevent/tests/__pycache__/test__contextvars.cpython-39.pyc,, -gevent/tests/__pycache__/test__core.cpython-39.pyc,, -gevent/tests/__pycache__/test__core_async.cpython-39.pyc,, -gevent/tests/__pycache__/test__core_callback.cpython-39.pyc,, -gevent/tests/__pycache__/test__core_fork.cpython-39.pyc,, -gevent/tests/__pycache__/test__core_loop_run.cpython-39.pyc,, -gevent/tests/__pycache__/test__core_stat.cpython-39.pyc,, -gevent/tests/__pycache__/test__core_timer.cpython-39.pyc,, -gevent/tests/__pycache__/test__core_watcher.cpython-39.pyc,, -gevent/tests/__pycache__/test__destroy.cpython-39.pyc,, -gevent/tests/__pycache__/test__destroy_default_loop.cpython-39.pyc,, -gevent/tests/__pycache__/test__doctests.cpython-39.pyc,, -gevent/tests/__pycache__/test__environ.cpython-39.pyc,, -gevent/tests/__pycache__/test__event.cpython-39.pyc,, -gevent/tests/__pycache__/test__events.cpython-39.pyc,, -gevent/tests/__pycache__/test__example_echoserver.cpython-39.pyc,, -gevent/tests/__pycache__/test__example_portforwarder.cpython-39.pyc,, -gevent/tests/__pycache__/test__example_udp_client.cpython-39.pyc,, -gevent/tests/__pycache__/test__example_udp_server.cpython-39.pyc,, -gevent/tests/__pycache__/test__example_webproxy.cpython-39.pyc,, -gevent/tests/__pycache__/test__example_wsgiserver.cpython-39.pyc,, -gevent/tests/__pycache__/test__example_wsgiserver_ssl.cpython-39.pyc,, -gevent/tests/__pycache__/test__examples.cpython-39.pyc,, -gevent/tests/__pycache__/test__exc_info.cpython-39.pyc,, -gevent/tests/__pycache__/test__execmodules.cpython-39.pyc,, -gevent/tests/__pycache__/test__fileobject.cpython-39.pyc,, -gevent/tests/__pycache__/test__getaddrinfo_import.cpython-39.pyc,, -gevent/tests/__pycache__/test__greenio.cpython-39.pyc,, -gevent/tests/__pycache__/test__greenlet.cpython-39.pyc,, -gevent/tests/__pycache__/test__greenletset.cpython-39.pyc,, -gevent/tests/__pycache__/test__greenness.cpython-39.pyc,, -gevent/tests/__pycache__/test__hub.cpython-39.pyc,, -gevent/tests/__pycache__/test__hub_join.cpython-39.pyc,, -gevent/tests/__pycache__/test__hub_join_timeout.cpython-39.pyc,, -gevent/tests/__pycache__/test__import_blocking_in_greenlet.cpython-39.pyc,, -gevent/tests/__pycache__/test__import_wait.cpython-39.pyc,, -gevent/tests/__pycache__/test__issue112.cpython-39.pyc,, -gevent/tests/__pycache__/test__issue1686.cpython-39.pyc,, -gevent/tests/__pycache__/test__issue1864.cpython-39.pyc,, -gevent/tests/__pycache__/test__issue230.cpython-39.pyc,, -gevent/tests/__pycache__/test__issue330.cpython-39.pyc,, -gevent/tests/__pycache__/test__issue467.cpython-39.pyc,, -gevent/tests/__pycache__/test__issue6.cpython-39.pyc,, -gevent/tests/__pycache__/test__issue600.cpython-39.pyc,, -gevent/tests/__pycache__/test__issue607.cpython-39.pyc,, -gevent/tests/__pycache__/test__issue639.cpython-39.pyc,, -gevent/tests/__pycache__/test__issue_728.cpython-39.pyc,, -gevent/tests/__pycache__/test__issues461_471.cpython-39.pyc,, -gevent/tests/__pycache__/test__iwait.cpython-39.pyc,, -gevent/tests/__pycache__/test__joinall.cpython-39.pyc,, -gevent/tests/__pycache__/test__local.cpython-39.pyc,, -gevent/tests/__pycache__/test__lock.cpython-39.pyc,, -gevent/tests/__pycache__/test__loop_callback.cpython-39.pyc,, -gevent/tests/__pycache__/test__makefile_ref.cpython-39.pyc,, -gevent/tests/__pycache__/test__memleak.cpython-39.pyc,, -gevent/tests/__pycache__/test__monkey.cpython-39.pyc,, -gevent/tests/__pycache__/test__monkey_builtins_future.cpython-39.pyc,, -gevent/tests/__pycache__/test__monkey_hub_in_thread.cpython-39.pyc,, -gevent/tests/__pycache__/test__monkey_logging.cpython-39.pyc,, -gevent/tests/__pycache__/test__monkey_module_run.cpython-39.pyc,, -gevent/tests/__pycache__/test__monkey_multiple_imports.cpython-39.pyc,, -gevent/tests/__pycache__/test__monkey_queue.cpython-39.pyc,, -gevent/tests/__pycache__/test__monkey_select.cpython-39.pyc,, -gevent/tests/__pycache__/test__monkey_selectors.cpython-39.pyc,, -gevent/tests/__pycache__/test__monkey_sigchld.cpython-39.pyc,, -gevent/tests/__pycache__/test__monkey_sigchld_2.cpython-39.pyc,, -gevent/tests/__pycache__/test__monkey_sigchld_3.cpython-39.pyc,, -gevent/tests/__pycache__/test__monkey_sigchld_wakeup_fd.cpython-39.pyc,, -gevent/tests/__pycache__/test__monkey_ssl_warning.cpython-39.pyc,, -gevent/tests/__pycache__/test__monkey_ssl_warning2.cpython-39.pyc,, -gevent/tests/__pycache__/test__monkey_ssl_warning3.cpython-39.pyc,, -gevent/tests/__pycache__/test__nondefaultloop.cpython-39.pyc,, -gevent/tests/__pycache__/test__order.cpython-39.pyc,, -gevent/tests/__pycache__/test__os.cpython-39.pyc,, -gevent/tests/__pycache__/test__pool.cpython-39.pyc,, -gevent/tests/__pycache__/test__pywsgi.cpython-39.pyc,, -gevent/tests/__pycache__/test__queue.cpython-39.pyc,, -gevent/tests/__pycache__/test__real_greenlet.cpython-39.pyc,, -gevent/tests/__pycache__/test__refcount.cpython-39.pyc,, -gevent/tests/__pycache__/test__refcount_core.cpython-39.pyc,, -gevent/tests/__pycache__/test__resolver_dnspython.cpython-39.pyc,, -gevent/tests/__pycache__/test__select.cpython-39.pyc,, -gevent/tests/__pycache__/test__selectors.cpython-39.pyc,, -gevent/tests/__pycache__/test__semaphore.cpython-39.pyc,, -gevent/tests/__pycache__/test__server.cpython-39.pyc,, -gevent/tests/__pycache__/test__server_pywsgi.cpython-39.pyc,, -gevent/tests/__pycache__/test__signal.cpython-39.pyc,, -gevent/tests/__pycache__/test__sleep0.cpython-39.pyc,, -gevent/tests/__pycache__/test__socket.cpython-39.pyc,, -gevent/tests/__pycache__/test__socket_close.cpython-39.pyc,, -gevent/tests/__pycache__/test__socket_dns.cpython-39.pyc,, -gevent/tests/__pycache__/test__socket_dns6.cpython-39.pyc,, -gevent/tests/__pycache__/test__socket_errors.cpython-39.pyc,, -gevent/tests/__pycache__/test__socket_ex.cpython-39.pyc,, -gevent/tests/__pycache__/test__socket_send_memoryview.cpython-39.pyc,, -gevent/tests/__pycache__/test__socket_ssl.cpython-39.pyc,, -gevent/tests/__pycache__/test__socket_timeout.cpython-39.pyc,, -gevent/tests/__pycache__/test__socketpair.cpython-39.pyc,, -gevent/tests/__pycache__/test__ssl.cpython-39.pyc,, -gevent/tests/__pycache__/test__subprocess.cpython-39.pyc,, -gevent/tests/__pycache__/test__subprocess_interrupted.cpython-39.pyc,, -gevent/tests/__pycache__/test__subprocess_poll.cpython-39.pyc,, -gevent/tests/__pycache__/test__systemerror.cpython-39.pyc,, -gevent/tests/__pycache__/test__thread.cpython-39.pyc,, -gevent/tests/__pycache__/test__threading.cpython-39.pyc,, -gevent/tests/__pycache__/test__threading_2.cpython-39.pyc,, -gevent/tests/__pycache__/test__threading_before_monkey.cpython-39.pyc,, -gevent/tests/__pycache__/test__threading_fork_from_dummy.cpython-39.pyc,, -gevent/tests/__pycache__/test__threading_holding_lock_while_monkey.cpython-39.pyc,, -gevent/tests/__pycache__/test__threading_monkey_in_thread.cpython-39.pyc,, -gevent/tests/__pycache__/test__threading_native_before_monkey.cpython-39.pyc,, -gevent/tests/__pycache__/test__threading_no_monkey.cpython-39.pyc,, -gevent/tests/__pycache__/test__threading_patched_local.cpython-39.pyc,, -gevent/tests/__pycache__/test__threading_vs_settrace.cpython-39.pyc,, -gevent/tests/__pycache__/test__threadpool.cpython-39.pyc,, -gevent/tests/__pycache__/test__threadpool_executor_patched.cpython-39.pyc,, -gevent/tests/__pycache__/test__timeout.cpython-39.pyc,, -gevent/tests/__pycache__/test__util.cpython-39.pyc,, -gevent/tests/_blocks_at_top_level.py,sha256=Hp36RFiC0djMSfvUHZsu8pVttpc7Hbmv_7VGq6xW630,48 -gevent/tests/_import_import_patch.py,sha256=IbgraY7KaPggcX1JNVkUQTTBSboegF_VWSDFJp38buI,28 -gevent/tests/_import_patch.py,sha256=_PWRiLjpsFyhT2CxTDIE9ZVS9gcCFqzQGFKel00zc2s,47 -gevent/tests/_import_wait.py,sha256=8353o30STWbRg53op9CWmTXfElU6VV4klLdqiq7Jmjg,570 -gevent/tests/_imports_at_top_level.py,sha256=9SCo81uRMT8xWbDFUBhbc_EwAoii9oygwOBSSNWfWWI,55 -gevent/tests/_imports_imports_at_top_level.py,sha256=VcIaDELcdgeEMqO_Cndy0XMjx05h5eG4_F_12giOSDs,345 -gevent/tests/badcert.pem,sha256=JioQeRZkHH8hGsWJjAF3U1zQvcWqhyzG6IOEJpTY9SE,1928 -gevent/tests/badkey.pem,sha256=gaBK9px_gG7DmrLKxfD6f6i-toAmARBTVfs-YGFRQF0,2162 -gevent/tests/getaddrinfo_module.py,sha256=oFyeNRywc3QO5HlpuV5DVcpUbml8hFn86pbWm_mGQX8,116 -gevent/tests/hosts_file.txt,sha256=07jEX3FicSKuiUJbQ_14H0MP8v7r35h_usGUmScPnSM,290909 -gevent/tests/https_svn_python_org_root.pem,sha256=wOB3Onnc62Iu9kEFd8GcHhd_suucYjpJNA3jyfHeJWA,2569 -gevent/tests/keycert.pem,sha256=r0KE1WH9eV6X4mUykpCY5Dm8_robBSi4zwMcGBPtMi4,1872 -gevent/tests/known_failures.py,sha256=t17aF5WG77u4DIXMuLVoNAzokx2nqi1CVrahQwU-kq0,17729 -gevent/tests/lock_tests.py,sha256=Oxi0uoEPVzA1NKP6t69fuezuHCZE0xQZbHBuMQtTwUs,21858 -gevent/tests/monkey_package/__init__.py,sha256=bvY5MXWih-w0IshrJmEKnPTI25R0eC_ma0Xa2bT3XCI,329 -gevent/tests/monkey_package/__main__.py,sha256=mJx6YRmYplQEY8Lb3hQOPrbIj2Z3mwrZY3wLL7p2zcM,363 -gevent/tests/monkey_package/__pycache__/__init__.cpython-39.pyc,, -gevent/tests/monkey_package/__pycache__/__main__.cpython-39.pyc,, -gevent/tests/monkey_package/__pycache__/issue1526_no_monkey.cpython-39.pyc,, -gevent/tests/monkey_package/__pycache__/issue1526_with_monkey.cpython-39.pyc,, -gevent/tests/monkey_package/__pycache__/issue302monkey.cpython-39.pyc,, -gevent/tests/monkey_package/__pycache__/script.cpython-39.pyc,, -gevent/tests/monkey_package/__pycache__/threadpool_monkey_patches.cpython-39.pyc,, -gevent/tests/monkey_package/__pycache__/threadpool_no_monkey.cpython-39.pyc,, -gevent/tests/monkey_package/issue1526_no_monkey.py,sha256=mDdY5_Y4IDBd8b-gjYNQKh8U4jb8Nn7eSEC_DM7lSxk,573 -gevent/tests/monkey_package/issue1526_with_monkey.py,sha256=5mbVockojXOZQZwQFaPrMVcg50T_vD1WRj07F6pOj_Y,666 -gevent/tests/monkey_package/issue302monkey.py,sha256=aitTDyrxJZI4EE_n6gg0o4AfHEQsFPfzQtVVmWMr6JQ,935 -gevent/tests/monkey_package/script.py,sha256=4q695hn_S3YA2aQh4TRyjVJ7QA9xlfqNTrezlUZkjVQ,427 -gevent/tests/monkey_package/threadpool_monkey_patches.py,sha256=0Glu2IugiK6rT6fYZbgqmGgciUjUX-6eannkqekzTi4,869 -gevent/tests/monkey_package/threadpool_no_monkey.py,sha256=c-bdOwTHjhBzlmcJMFyixL3Wjp-wXO4T1VZIGC3clGE,787 -gevent/tests/nullcert.pem,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 -gevent/tests/server.crt,sha256=LOyJ1muRGaDZapZQ9x3BRNGIrC4jKiiIyNZJvMM5eQI,1809 -gevent/tests/server.key,sha256=CXI8bo8kvTo3I_o0kVPabuQ0oHBsoNbgFVT1bWNTwOI,3272 -gevent/tests/sha256.pem,sha256=trYsA7FY0hyVoV1AoGNwZ_s6T89eiiOIFexoNRv029s,2065 -gevent/tests/test__GreenletExit.py,sha256=qHtC7KnjCG039F_VGDXnsrhyWaQXvfcmgnVB2Rfa_Vk,127 -gevent/tests/test___config.py,sha256=mCJfAOG9DEAU5RtUg_UgHwsB6f0x-KWTjHX9aTaS7d8,4889 -gevent/tests/test___ident.py,sha256=15ucVXe5y4hE9F--Y8fhxN9-WcGhXt2ehHMLTzDuDKs,2109 -gevent/tests/test___monitor.py,sha256=-hp7xNRmS3dnqgdfea9228hOUQ_IuG26WXTk2gsVZgE,12624 -gevent/tests/test___monkey_patching.py,sha256=2W6ZF3gTCSh9SgUjJUuX2OP1ZZCq9Vjsv20UPqgrXnY,3502 -gevent/tests/test__all__.py,sha256=DL-gj-gEaObUak2HpJbrkPstRhb3zUdZe-BNwe2h2r8,11386 -gevent/tests/test__api.py,sha256=zJF6cfQKnPscZio9ErpkY2Mn2NNPOzNnzX4J8ujx4ww,4550 -gevent/tests/test__api_timeout.py,sha256=is-HOBSQiMKPc67r41FqamL3KOF5BnfmtV8kW01JId4,6323 -gevent/tests/test__ares_host_result.py,sha256=f-ZJubI1wyzJExMifQnRFNpNcxkZ0Ykyp2W75jLjrqY,908 -gevent/tests/test__ares_timeout.py,sha256=65MC4NdPYJzbLO90FRjwtPuz3E_Y0JJm2Ld5aDcYLcU,1015 -gevent/tests/test__backdoor.py,sha256=4Zc2QxUXaJIiJIDLPgR9Y3H5tfUTba0jwM9VuKvTx1g,6900 -gevent/tests/test__close_backend_fd.py,sha256=6yssqISBW-rhKZx25iCDbE6gaLYAEBCTzPlchwzsB7Y,3865 -gevent/tests/test__compat.py,sha256=YBE4IJwtRozcCRqeZXY9dkxqjZ6m2xS0Pk1ceApjvnE,1439 -gevent/tests/test__contextvars.py,sha256=JUPQ3TzpSLTQkdRNr7g2OgEzmFIK5vd8ml2bF7BNTYc,31717 -gevent/tests/test__core.py,sha256=VDxOazcjEyhp4o094xQcKSupm-Qf0aDNN0o3Ja_UF7s,5618 -gevent/tests/test__core_async.py,sha256=X4CNU4Kroea9fyjlfd_l8HmMLKfvec-eE4qzqTPZNow,761 -gevent/tests/test__core_callback.py,sha256=occ-buOrq8DrbJ0GUzHeMVF-Qcuu5e4qnUPnrmqvq80,618 -gevent/tests/test__core_fork.py,sha256=i4WdiNIL_LWINMg38rnNakfCfVZiMkFgVo9wUsiXxH4,2738 -gevent/tests/test__core_loop_run.py,sha256=N6ZHGuVfrclHoKrL1R8T7BeObT9P28Ey2wfvyo_jGJs,494 -gevent/tests/test__core_stat.py,sha256=YvqLSe-9j5tIFC6MoPQhD5_0MdBtxrbVagp4o0jzpw8,3754 -gevent/tests/test__core_timer.py,sha256=e6VG-IHLiQ3OkrTOYGiLMX4VdU6RLG3UoA69uao2xG8,4330 -gevent/tests/test__core_watcher.py,sha256=ULftUAJqrMLYgzItmSzEosgeagKbI72m0oheKn14vYo,3573 -gevent/tests/test__destroy.py,sha256=fy9Gh1WH6URkLCTjVv2RzxljX6DDRZXmaCuUEHVCYf8,1765 -gevent/tests/test__destroy_default_loop.py,sha256=9KsDb5i7Nn4uFrNrfT_vMYLOG7VV6-hp46HGlFg06nc,2199 -gevent/tests/test__doctests.py,sha256=aZqNLQDOpyvFYkhmqgXyDRhtV3CnN50H4OnZkp0vC0E,3613 -gevent/tests/test__environ.py,sha256=i7sqbSsRVyM5ypN9obyVIMWKyATOs5FC3BrMNf_i5Sk,608 -gevent/tests/test__event.py,sha256=gSG_grgV1x3CfyZW6M5tH3MWTODn5L-9jR_3ekFNjPY,14026 -gevent/tests/test__events.py,sha256=wa8mZSnMCsZ_qX2ak0Lwy3RE0MqXfdaSevLv0PEzXFM,1465 -gevent/tests/test__example_echoserver.py,sha256=-yA1D31oUsERPoJlG_XtMswsjN7RHykVwF67lvKYKjs,1086 -gevent/tests/test__example_portforwarder.py,sha256=hIVFPP8CBapzR918PBlrZM_Zibt8OyzDdKD9V1vfgbw,2025 -gevent/tests/test__example_udp_client.py,sha256=VGDHP_cYMlxnDkqW1E1fs-WteLH_6O7euW3SYvA1Mvk,884 -gevent/tests/test__example_udp_server.py,sha256=ApnWzkhqlHXmELMwgviFr8jf2QU4obHYefWCq1t2zlY,513 -gevent/tests/test__example_webproxy.py,sha256=Tg4dVbS725yOQVoslPz3FpA6SFAoYKIPAhddwUvEvEs,807 -gevent/tests/test__example_wsgiserver.py,sha256=bavlc9OfdFdkyibxxGhBuhEFXOYcfyc_Jqg0P8gfQEo,3202 -gevent/tests/test__example_wsgiserver_ssl.py,sha256=Ztn83XeMTLENcZduhdE2hiGYitSvi0hEQLJaD1tLpdA,649 -gevent/tests/test__examples.py,sha256=F2tAzDtGDYz3mo9Y5u0UfgnXGUTSz6TbtxK_LzEJyFQ,3336 -gevent/tests/test__exc_info.py,sha256=mlK-oeSGfVP1dq6e78LWX50DgaFy_ulOF0NOZPRVhr4,1313 -gevent/tests/test__execmodules.py,sha256=Uf9jV4zIWoX5_aaeYUIcVgicbVxlgkCPywFiqAiidmg,1592 -gevent/tests/test__fileobject.py,sha256=Hm-RnEkGIEL_0J0JCbdexZ4YvWf9kCC9zraL9aW7pMQ,18985 -gevent/tests/test__getaddrinfo_import.py,sha256=eGmX5zaq-x9Or3UGtIZL8yqNN97yVBQx9zlehM3ogE4,463 -gevent/tests/test__greenio.py,sha256=vYzw_tSAAZxD0TjbKt_9wy_2KM3727YjUEdmcJ6GNvc,5523 -gevent/tests/test__greenlet.py,sha256=Ss8XMqjvhw1H4v-t1V1hymaE2ySsVvB9QElNS-6eqoU,33754 -gevent/tests/test__greenletset.py,sha256=NaIikUvwC7FcHjZQ24P3blp3iW4VaLImJfqH_E6mVuo,5032 -gevent/tests/test__greenness.py,sha256=YztEj8cMW3XkbTtoRJPv8K5yKugRwhlWy6szMKRwk2o,2790 -gevent/tests/test__hub.py,sha256=kT1T7tzDAZ1zmU3EsYGhGBqyYRv7acMVgTA3_BE1Ok0,13728 -gevent/tests/test__hub_join.py,sha256=-V1LjhFtZOAvCTWJsqxsLKFGicoDbp3NpojlS1EOZKc,3217 -gevent/tests/test__hub_join_timeout.py,sha256=E6Ul1xhZ1Ro7_IMx9QZBpf1zzWl1yrYWS11K25JyLho,2913 -gevent/tests/test__import_blocking_in_greenlet.py,sha256=BEEB6WrcXqFscxQxEIdMzlLVQ-KFvDlQ52yNlQWxIKs,1134 -gevent/tests/test__import_wait.py,sha256=-m2mg2urO-nNDTj3Ov0QNXuDmgr7rOCa7MKD-LT5cyA,252 -gevent/tests/test__issue112.py,sha256=OxamNgJF1QlKuirw_jJNYzpE84PgjYP2z1x27n61JQc,338 -gevent/tests/test__issue1686.py,sha256=5CIooK1MteQPtSWaWPpvyzMil_OLcvIYeHjIcZHlpxE,2878 -gevent/tests/test__issue1864.py,sha256=Xb3CcArxYDox-lCDpHOpwTkE5XXM3jK5zqUk3zyKGzk,1291 -gevent/tests/test__issue230.py,sha256=3zEzP5fLwLaHUeX0xNntV29AhhtHr_9t0cG1SPSa24c,500 -gevent/tests/test__issue330.py,sha256=qDbqSKfvZ4IdR_r7PwDAuCfTQuZEjLELSK1IvTowoaI,2333 -gevent/tests/test__issue467.py,sha256=PrqSlERQf8XttyiNB5NRZqEo8D0cmNTiO8qIdamRgPg,1205 -gevent/tests/test__issue6.py,sha256=OOBbWEwmA4zKxpF8jZ_5fm4E7uHKbqxP63FiE0ktU9w,1530 -gevent/tests/test__issue600.py,sha256=dKW-RzdzaJhVl8dClpBzLzgRjMn7BlqeTIiIB97R9cw,1386 -gevent/tests/test__issue607.py,sha256=-lQuJxVfIPDhrrf1G-2BpIbQqwDMygDeuRMh7vANGPM,1354 -gevent/tests/test__issue639.py,sha256=ExWDeXqUDqGTXF1rx6t1SQjac4GWKqZ2opusTpxgi1g,214 -gevent/tests/test__issue_728.py,sha256=1u6WSToRxMYe70aLU5vMhrWSZ_OHtwN9oP6L4UXXywg,212 -gevent/tests/test__issues461_471.py,sha256=_Xwj-ImGgYuTcWGxITACba3FGnRHmlXZxTDkkChriVg,3889 -gevent/tests/test__iwait.py,sha256=uzef1gKSo8dDbciyjZobklIXNDdc-B0ehEKb3iIn2Bg,1205 -gevent/tests/test__joinall.py,sha256=UAV56-NMPLhs8TBYJ-qcNAC8gT_ZoUAcOq22_qYEQZM,296 -gevent/tests/test__local.py,sha256=1iThKxhRmbTG5aH91kVNOEdU84CnsT3YMqjX3zY5WXU,11741 -gevent/tests/test__lock.py,sha256=tJOWhpvDE_aW4W777tkFMLrmpSel6Eqk6CCfoeWSe0s,2242 -gevent/tests/test__loop_callback.py,sha256=SUKmuaQh4sSC1fTyGv3zaTG1NkJN7T4EaJt-ezd_wT4,356 -gevent/tests/test__makefile_ref.py,sha256=N7COsXR3aH_9_Y11XtllHSTBuCnFHn7yV_0snuLK5zA,19545 -gevent/tests/test__memleak.py,sha256=Yq3tfWmbpgI5hYopozWEHSbP8Xs4lDqBBQ76in2mFxc,1466 -gevent/tests/test__monkey.py,sha256=uhlAPJ8PbC9jqzYTJE4KL1BeckalesljF9PMIC9gGiQ,6581 -gevent/tests/test__monkey_builtins_future.py,sha256=ZUJj7wWz9jEa9vDPSdEPrjqewiUwBspmtgh7RN8LymA,521 -gevent/tests/test__monkey_hub_in_thread.py,sha256=iMWv4a8Agy_llZypYxXo62kSB7LLTdNG5u9N_eHKIg8,520 -gevent/tests/test__monkey_logging.py,sha256=ZBbUvAqOam0Twekv_Mint1dWiWBt_ce9Y7L3JRCrqGU,1564 -gevent/tests/test__monkey_module_run.py,sha256=G-bHCowrKt4dDUgotEeB5rX8yVlDrfppIRGKYJIOdA8,4368 -gevent/tests/test__monkey_multiple_imports.py,sha256=QwmJJ4r3RXOQhti_5vj3Let0zllXzq4GwDY8NqzJUuQ,296 -gevent/tests/test__monkey_queue.py,sha256=d9m4mfBPMFa5bhuyNOOEMHEoBLc7bvlCz7Q3jbODULk,12337 -gevent/tests/test__monkey_select.py,sha256=U77pqLIX-2wCtdY7CxigfT0wgSTBqHs3e53eajJV45A,741 -gevent/tests/test__monkey_selectors.py,sha256=gootPuj6Hp_ZuT_ChQmjkR75TY9xNmTXNq0nTbRxEMU,2580 -gevent/tests/test__monkey_sigchld.py,sha256=U4L8AciJ-1-ivwMZlfIMkgpmoWFVxxlZri0bsJ_1vvo,2939 -gevent/tests/test__monkey_sigchld_2.py,sha256=zV1WsDX8dTQiW6XBOs0GQejZsq2obE2LA9Dil1eo_9Y,1774 -gevent/tests/test__monkey_sigchld_3.py,sha256=dlaDG9t4kPRfhT6anZRRCkltvQSKWNeKPOBd7doAgGo,1755 -gevent/tests/test__monkey_sigchld_wakeup_fd.py,sha256=MDcl2Rce9X4gqy-Hjjpa0ALmzu6zGaquAInXmbqPxGU,1096 -gevent/tests/test__monkey_ssl_warning.py,sha256=vvfhrq-1zurv3ERAaeiIotk1LARVAGeUy4UDdrde7Zk,1250 -gevent/tests/test__monkey_ssl_warning2.py,sha256=NRlZ8-s-doOC6xNkQbaiVPIaqOtFBfEmQzyrKsUukww,1255 -gevent/tests/test__monkey_ssl_warning3.py,sha256=WZEOHQoewYAuYJu0f8UMjpmRzaR0B-sf0wBhvaRKTEQ,1330 -gevent/tests/test__nondefaultloop.py,sha256=Y3IrgT8SF3SmO3A1IlvC0nF4GCqxzvKES0KqvO72crE,204 -gevent/tests/test__order.py,sha256=LXv2-H9xEL79OFJSXOF50Z3JUd1z-Srv9ouYgE081xU,1086 -gevent/tests/test__os.py,sha256=LwfUQomcRklQUKCLMhEUBksZPbp3T3yeGWXkHO0JnCk,5700 -gevent/tests/test__pool.py,sha256=oOf38RQcEVd8AQQuynwebNWLnQ2CRoXHV9hJWskmhrc,18351 -gevent/tests/test__pywsgi.py,sha256=1zFZ19XkfU1Aw_Al6cE85S_ROvUf-rUmxCE_j6twmxA,73437 -gevent/tests/test__queue.py,sha256=becknF4KwY1d2kc2saWCe83rLQ0jgiUAAxMRKX6eNOs,17294 -gevent/tests/test__real_greenlet.py,sha256=SoZQ8cY1wQFJnVmTFxuYvXo08KVyb99ZUqGDBUbo1C4,693 -gevent/tests/test__refcount.py,sha256=rqdMK4QiCLWTIblXbxvGJ2AWQimV91KDFmawHV-X5ik,5866 -gevent/tests/test__refcount_core.py,sha256=XiTmU2kYH-JkVINch2jpA1vGVKOc6ufdPW28DMNpo9c,600 -gevent/tests/test__resolver_dnspython.py,sha256=aA7rtaB273IaTG9whMwvtGwG8c42xTPtb4iH9gTR4DE,1117 -gevent/tests/test__select.py,sha256=07EgbGro92urXD1g7oPf0jNapuyM85Y1vpCIn7dpgcQ,10658 -gevent/tests/test__selectors.py,sha256=iI9Oi_Edd9FJXOWXXciB9VYDBBVdDrIO9snuq_yEx10,5763 -gevent/tests/test__semaphore.py,sha256=m-CHrKE_S5yyKd6O78b6j8AvmTFpgTVJtGT-b91nDvA,13756 -gevent/tests/test__server.py,sha256=Ma9-PnZ_iQMA583STRjU18vnMIK2KnlfatSE-ERrtZs,20199 -gevent/tests/test__server_pywsgi.py,sha256=0Fquqy69Xylu3UXATvd__Y9wTBXnohP9fdvEoUhGysI,3074 -gevent/tests/test__signal.py,sha256=8tfg7pa2MQmUjzKG93oNzuw630odMgFqPfyYwMFo4Vc,3635 -gevent/tests/test__sleep0.py,sha256=uoruOPjsaPk1m0thN_4UppH4kW4k9fHQXDuLXnc3u5k,139 -gevent/tests/test__socket.py,sha256=m60j5-Bljz24VIbGb6Xpt8jJXyMOlazvajFmB-oo4Uw,23341 -gevent/tests/test__socket_close.py,sha256=_lidh6C8SSup3avpXKUdv0Kkok1GiLbaC_5Dn6hkiRQ,1862 -gevent/tests/test__socket_dns.py,sha256=nbMzlGGtirDXCpnEBFlGfSp5DRVf6fdWezNelTWvkTc,35136 -gevent/tests/test__socket_dns6.py,sha256=ywDARvfurAx0rmfNC3JPt9K-KsnwDjDHe4wRqQ2giiY,3132 -gevent/tests/test__socket_errors.py,sha256=L6ZZymYkkYGq6V_S7lzdC2D1J-0jQkKF9_xytAldQN8,1869 -gevent/tests/test__socket_ex.py,sha256=RYT56ubUxD-e13wL1rG5NS9afx0gaqYfKcqzL0uS0T0,1110 -gevent/tests/test__socket_send_memoryview.py,sha256=xhNyL7y_TriGrMbJvKmbwEReUBMR_M6LKL0l0IarBbE,960 -gevent/tests/test__socket_ssl.py,sha256=X7iDcOwBbtX7e0B_JBXoSFI_dRzpQzVMGYpMQTswtf4,865 -gevent/tests/test__socket_timeout.py,sha256=_TqCsWOPrKNMJ8OFvKGjLIbiToDm7X1Y1wJxR39rJME,1351 -gevent/tests/test__socketpair.py,sha256=VKi94yATBBTzKsN7S7D1rpx-GropJf0qXRpw9GT43c0,951 -gevent/tests/test__ssl.py,sha256=nzZOrRT6JmQXbFWgYEf9PcSi42p_FC4HK39Rote78B8,5686 -gevent/tests/test__subprocess.py,sha256=SnybISDRGA9C0_J_uLjz-ERd7L8MR5TmI7Hb8Tz9M0s,20244 -gevent/tests/test__subprocess_interrupted.py,sha256=qNr4GCwg-xhLrZLGHnprQILnj0g08-GozvYClSR_uE0,1922 -gevent/tests/test__subprocess_poll.py,sha256=AFlQJZcNCfDKP5zwefoGmSFvPe_1cT5HpUu_VDbp4Lk,346 -gevent/tests/test__systemerror.py,sha256=lgUg-grJQ6VTNXjOTkQQGds6m7PmtoPgddG-tYURYsU,3295 -gevent/tests/test__thread.py,sha256=xhyh6Z_HQzh2kqSjdoPoEdUURzj8A2B2l1dbXpuv1yc,780 -gevent/tests/test__threading.py,sha256=R6eAMnNIMQE757HL6JdwKaCFQq21HD4uPCen5iRCghc,2586 -gevent/tests/test__threading_2.py,sha256=siCGN_RcFgNB6_FsItZPx4sQDS8bV7-RxyULssCgEoQ,23757 -gevent/tests/test__threading_before_monkey.py,sha256=DhdEFVUY6LTb-74I3KgiFExW-aFvSn_B8jTvMS_NjWo,714 -gevent/tests/test__threading_fork_from_dummy.py,sha256=Ds0y3KgYqLzQnjUuAeu2WmpBtabpMF9qA4n6weoirwQ,2181 -gevent/tests/test__threading_holding_lock_while_monkey.py,sha256=5IWkIjTs1eRlphtDF0cCINz16M6tUi9hZMB-R_eVMIw,411 -gevent/tests/test__threading_monkey_in_thread.py,sha256=dLCRkphMFk1EGuB2d44kdDq0MI2aE5CWEZR7rFArD1E,2075 -gevent/tests/test__threading_native_before_monkey.py,sha256=KvQaAWQe78cGVYT-T2MAh6T4s7YUZdza8-vqxS4YJp0,2157 -gevent/tests/test__threading_no_monkey.py,sha256=FkY93eRfkpZjsbEzLbJLvtI9-POMbAGYd3IpJE8peHw,806 -gevent/tests/test__threading_patched_local.py,sha256=0EaAtlORHJjfxkUZzGKL1lOh-OY9hZa1R6MoUE0eSHo,675 -gevent/tests/test__threading_vs_settrace.py,sha256=vsRpAqYimfePGGqyTj-8M-SpGmwVN01JQ6yROkKBjl8,5023 -gevent/tests/test__threadpool.py,sha256=FhfeW0JZ5U_e84B8Q3JIb6KBxXKFkGSD6RsYVNHMMoM,24825 -gevent/tests/test__threadpool_executor_patched.py,sha256=KihwMAZ_hQfZBhnxv_CCx8HJnvdQaKxxaMuuJkV9IiM,386 -gevent/tests/test__timeout.py,sha256=OA6toC5Q8aQ99Kewy9Q6FlQc-bfeXXa5d32dGWcvs0I,4628 -gevent/tests/test__util.py,sha256=8T3EPIPWlOQtAylapMTLjz32ZQyCudhRlchXx-EGSGQ,10705 -gevent/tests/test_server.crt,sha256=QIKfCQ-jpwWvzwJLO-eOSqT2TTSEVE-HLcC1wzs-YNw,1809 -gevent/tests/test_server.key,sha256=5yU4QY75gVWwTt4TE5EKkiOhENEwO0eP9oG3WTB0dtk,3268 -gevent/tests/tests_that_dont_do_leakchecks.txt,sha256=dzRXEFB_7uZlFI5ANA1VCfYCd9HTINqDTi1BcIkzxOY,223 -gevent/tests/tests_that_dont_monkeypatch.txt,sha256=PH8kQY8hpSlwzXJkJQpTsczkNZ13uUxkWM-Hl4Cz-wQ,647 -gevent/tests/tests_that_dont_use_resolver.txt,sha256=nhsAcj2CwFEsEtmfROY3NFiIe7Xqpb3AK1I-nQK6f2A,3184 -gevent/tests/wrongcert.pem,sha256=6n4u7wcalNKCtnMsq7J3Y7uOiez901ZLiH38oE0jGUM,1880 -gevent/thread.py,sha256=sx3Mqg315mMN8oEOSh8ohdwvg9Vc-vimFq-22eKHVe8,11784 -gevent/threading.py,sha256=pZLUJglbkRJmNSpZCw-bznxhHHAc8W1O3vo8Q1O3Zsg,19405 -gevent/threadpool.py,sha256=iQ90WLeFsm1XUM_cI_WehtKGLh9BJ-r-fgubPvsyTEo,30975 -gevent/time.py,sha256=C0eRlHq0rBxy9tC_SsIywkYaBNlwO1bc04qFi2OceB4,491 -gevent/timeout.py,sha256=7fYPJJkfZm5yUY54NhGAIzuj5vclm79NRf2Lwvo175E,13682 -gevent/util.py,sha256=lZoYCZDZdkBQYd8wSCbbwdkVW0VTVx_cikkX1lxMDmg,22571 -gevent/win32util.py,sha256=WBk_YNf_kk3QF3PMUdScqgM_PreF4OBhfXq2W5264n0,3637 diff --git a/venv/lib/python3.9/site-packages/gevent-26.4.0.dist-info/REQUESTED b/venv/lib/python3.9/site-packages/gevent-26.4.0.dist-info/REQUESTED deleted file mode 100644 index e69de29..0000000 diff --git a/venv/lib/python3.9/site-packages/gevent-26.4.0.dist-info/WHEEL b/venv/lib/python3.9/site-packages/gevent-26.4.0.dist-info/WHEEL deleted file mode 100644 index c6f756b..0000000 --- a/venv/lib/python3.9/site-packages/gevent-26.4.0.dist-info/WHEEL +++ /dev/null @@ -1,5 +0,0 @@ -Wheel-Version: 1.0 -Generator: setuptools (82.0.1) -Root-Is-Purelib: false -Tag: cp39-cp39-linux_x86_64 - diff --git a/venv/lib/python3.9/site-packages/gevent-26.4.0.dist-info/entry_points.txt b/venv/lib/python3.9/site-packages/gevent-26.4.0.dist-info/entry_points.txt deleted file mode 100644 index d5fe662..0000000 --- a/venv/lib/python3.9/site-packages/gevent-26.4.0.dist-info/entry_points.txt +++ /dev/null @@ -1,2 +0,0 @@ -[gevent.plugins.monkey.will_patch_all] -signal_os_incompat = gevent.monkey:_subscribe_signal_os diff --git a/venv/lib/python3.9/site-packages/gevent-26.4.0.dist-info/licenses/LICENSE b/venv/lib/python3.9/site-packages/gevent-26.4.0.dist-info/licenses/LICENSE deleted file mode 100644 index b767c24..0000000 --- a/venv/lib/python3.9/site-packages/gevent-26.4.0.dist-info/licenses/LICENSE +++ /dev/null @@ -1,25 +0,0 @@ -MIT License - -Except when otherwise stated (look at the beginning of each file) the software -and the documentation in this project are copyrighted by: - - Denis Bilenko and the contributors, http://www.gevent.org - -Permission is hereby granted, free of charge, to any person obtaining -a copy of this software and associated documentation files (the -"Software"), to deal in the Software without restriction, including -without limitation the rights to use, copy, modify, merge, publish, -distribute, sublicense, and/or sell copies of the Software, and to -permit persons to whom the Software is furnished to do so, subject to -the following conditions: - -The above copyright notice and this permission notice shall be -included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/venv/lib/python3.9/site-packages/gevent-26.4.0.dist-info/top_level.txt b/venv/lib/python3.9/site-packages/gevent-26.4.0.dist-info/top_level.txt deleted file mode 100644 index 4a63abe..0000000 --- a/venv/lib/python3.9/site-packages/gevent-26.4.0.dist-info/top_level.txt +++ /dev/null @@ -1 +0,0 @@ -gevent diff --git a/venv/lib/python3.9/site-packages/gevent/__init__.py b/venv/lib/python3.9/site-packages/gevent/__init__.py deleted file mode 100644 index 637e0b4..0000000 --- a/venv/lib/python3.9/site-packages/gevent/__init__.py +++ /dev/null @@ -1,114 +0,0 @@ -# Copyright (c) 2009-2012 Denis Bilenko. See LICENSE for details. -""" -gevent is a coroutine-based Python networking library that uses greenlet -to provide a high-level synchronous API on top of libev event loop. - -See http://www.gevent.org/ for the documentation. - -.. versionchanged:: 1.3a2 - Add the `config` object. -""" - -from __future__ import absolute_import - -from collections import namedtuple - -_version_info = namedtuple('version_info', - ('major', 'minor', 'micro', 'releaselevel', 'serial')) - -#: The programatic version identifier. The fields have (roughly) the -#: same meaning as :data:`sys.version_info` -#: .. deprecated:: 1.2 -#: Use ``pkg_resources.parse_version(__version__)`` (or the equivalent -#: ``packaging.version.Version(__version__)``). -version_info = _version_info(20, 0, 0, 'dev', 0) # XXX: Remove me - -#: The human-readable PEP 440 version identifier. -#: Use ``pkg_resources.parse_version(__version__)`` or -#: ``packaging.version.Version(__version__)`` to get a machine-usable -#: value. -__version__ = '26.4.0' - - -__all__ = [ - 'Greenlet', - 'GreenletExit', - 'Timeout', - 'config', # Added in 1.3a2 - 'fork', - 'get_hub', - 'getcurrent', - 'getswitchinterval', - 'idle', - 'iwait', - 'joinall', - 'kill', - 'killall', - 'reinit', - 'setswitchinterval', - 'signal_handler', - 'sleep', - 'spawn', - 'spawn_later', - 'spawn_raw', - 'wait', - 'with_timeout', -] - - -import sys -if sys.platform == 'win32': - # trigger WSAStartup call - import socket # pylint:disable=unused-import,useless-suppression - del socket - - -# Floating point number, in number of seconds, -# like time.time -getswitchinterval = sys.getswitchinterval -setswitchinterval = sys.setswitchinterval - -from gevent._config import config -from gevent._hub_local import get_hub -from gevent._hub_primitives import iwait_on_objects as iwait -from gevent._hub_primitives import wait_on_objects as wait - -from gevent.greenlet import Greenlet, joinall, killall -spawn = Greenlet.spawn -spawn_later = Greenlet.spawn_later -#: The singleton configuration object for gevent. - -from gevent.timeout import Timeout, with_timeout -from gevent.hub import getcurrent, GreenletExit, spawn_raw, sleep, idle, kill, reinit -try: - from gevent.os import fork -except ImportError: - __all__.remove('fork') - -# This used to be available as gevent.signal; that broke in 1.1b4 but -# a temporary alias was added (See -# https://github.com/gevent/gevent/issues/648). It was ugly and complex and -# caused confusion, so it was removed in 1.5. See https://github.com/gevent/gevent/issues/1529 -from gevent.hub import signal as signal_handler - -# the following makes hidden imports visible to freezing tools like -# py2exe. see https://github.com/gevent/gevent/issues/181 -# This is not well maintained or tested, though, so it likely becomes -# outdated on each major release. - -def __dependencies_for_freezing(): # pragma: no cover - # pylint:disable=unused-import, import-outside-toplevel - from gevent import core - from gevent import resolver_thread - from gevent import resolver_ares - from gevent import socket as _socket - from gevent import threadpool - from gevent import thread - from gevent import threading - from gevent import select - from gevent import subprocess - import pprint - import traceback - import signal as _signal - -del __dependencies_for_freezing diff --git a/venv/lib/python3.9/site-packages/gevent/_abstract_linkable.py b/venv/lib/python3.9/site-packages/gevent/_abstract_linkable.py deleted file mode 100644 index 5443f6f..0000000 --- a/venv/lib/python3.9/site-packages/gevent/_abstract_linkable.py +++ /dev/null @@ -1,554 +0,0 @@ -# -*- coding: utf-8 -*- -# cython: auto_pickle=False,embedsignature=True,always_allow_keywords=False -""" -Internal use only base class for objects -that can be waited on and then asked to notify (wake up) -waiters. Examples include locks, events, semaphores. - -gevent has the generic concept of "linkable" objects, or the "linkable" -protocol, which is the ``link`` and ``rawlink`` methods. (Actually sending -the notification is up to the implementation of the individual -objects.) `gevent.greenlet.Greenlet` implements this protocol but -does not extend this object (TODO: It probably should.) -""" -import sys -from gc import get_objects - -from greenlet import greenlet -from greenlet import error as greenlet_error - -from gevent._compat import thread_mod_name -from gevent._hub_local import get_hub_noargs as get_hub -from gevent._hub_local import get_hub_if_exists - -from gevent.exceptions import InvalidSwitchError -from gevent.exceptions import InvalidThreadUseError -from gevent.timeout import Timeout - -locals()['getcurrent'] = __import__('greenlet').getcurrent -locals()['greenlet_init'] = lambda: None - -__all__ = [ - 'AbstractLinkable', -] - -# Need the real get_ident. We're imported early enough during monkey-patching -# that we can be sure nothing is monkey patched yet. -_get_thread_ident = __import__(thread_mod_name).get_ident -_allocate_thread_lock = __import__(thread_mod_name).allocate_lock - -class _FakeNotifier(object): - __slots__ = ( - 'pending', - ) - - def __init__(self): - self.pending = False - -def get_roots_and_hubs(): - from gevent.hub import Hub # delay import - return { - x.parent: x - for x in get_objects() - # Make sure to only find hubs that have a loop - # and aren't destroyed. If we don't do that, we can - # get an old hub that no longer works leading to issues in - # combined test cases. - if isinstance(x, Hub) and x.loop is not None - } - - -class AbstractLinkable(object): - # Encapsulates the standard parts of the linking and notifying - # protocol common to both repeatable events (Event, Semaphore) and - # one-time events (AsyncResult). - # - # With a few careful exceptions, instances of this object can only - # be used from a single thread. The exception is that certain methods - # may be used from multiple threads IFF: - # - # 1. They are documented as safe for that purpose; AND - # 2a. This object is compiled with Cython and thus is holding the GIL - # for the entire duration of the method; OR - # 2b. A subclass ensures that a Python-level native thread lock is held - # for the duration of the method; this is necessary in pure-Python mode. - # The only known implementation of such - # a subclass is for Semaphore. AND - # 3. The subclass that calls ``capture_hub`` catches - # and handles ``InvalidThreadUseError`` - # - # TODO: As of gevent 1.5, we use the same datastructures and almost - # the same algorithm as Greenlet. See about unifying them more. - - __slots__ = ( - 'hub', - '_links', - '_notifier', - '_notify_all', - '__weakref__' - ) - - def __init__(self, hub=None): - # Before this implementation, AsyncResult and Semaphore - # maintained the order of notifications, but Event did not. - - # In gevent 1.3, before Semaphore extended this class, that - # was changed to not maintain the order. It was done because - # Event guaranteed to only call callbacks once (a set) but - # AsyncResult had no such guarantees. When Semaphore was - # changed to extend this class, it lost its ordering - # guarantees. Unfortunately, that made it unfair. There are - # rare cases that this can starve a greenlet - # (https://github.com/gevent/gevent/issues/1487) and maybe - # even lead to deadlock (not tested). - - # So in gevent 1.5 we go back to maintaining order. But it's - # still important not to make duplicate calls, and it's also - # important to avoid O(n^2) behaviour that can result from - # naive use of a simple list due to the need to handle removed - # links in the _notify_links loop. Cython has special support for - # built-in sets, lists, and dicts, but not ordereddict. Rather than - # use two data structures, or a dict({link: order}), we simply use a - # list and remove objects as we go, keeping track of them so as not to - # have duplicates called. This makes `unlink` O(n), but we can avoid - # calling it in the common case in _wait_core (even so, the number of - # waiters should usually be pretty small) - self._links = [] - self._notifier = None - # This is conceptually a class attribute, defined here for ease of access in - # cython. If it's true, when notifiers fire, all existing callbacks are called. - # If its false, we only call callbacks as long as ready() returns true. - self._notify_all = True - # we don't want to do get_hub() here to allow defining module-level objects - # without initializing the hub. However, for multiple-thread safety, as soon - # as a waiting method is entered, even if it won't have to wait, we - # need to grab the hub and assign ownership. But we don't want to grab one prematurely. - # The example is three threads, the main thread and two worker threads; if we create - # a Semaphore in the main thread but only use it in the two threads, if we had grabbed - # the main thread's hub, the two worker threads would have a dependency on it, meaning that - # if the main event loop is blocked, the worker threads might get blocked too. - self.hub = hub - - def linkcount(self): - # For testing: how many objects are linked to this one? - return len(self._links) - - def ready(self): - # Instances must define this - raise NotImplementedError - - def rawlink(self, callback): - """ - Register a callback to call when this object is ready. - - *callback* will be called in the :class:`Hub - `, so it must not use blocking gevent API. - *callback* will be passed one argument: this instance. - """ - if not callable(callback): - raise TypeError('Expected callable: %r' % (callback, )) - self._links.append(callback) - self._check_and_notify() - - def unlink(self, callback): - """Remove the callback set by :meth:`rawlink`""" - try: - self._links.remove(callback) - except ValueError: - pass - - if not self._links and self._notifier is not None and self._notifier.pending: - # If we currently have one queued, but not running, de-queue it. - # This will break a reference cycle. - # (self._notifier -> self._notify_links -> self) - # If it's actually running, though, (and we're here as a result of callbacks) - # we don't want to change it; it needs to finish what its doing - # so we don't attempt to start a fresh one or swap it out from underneath the - # _notify_links method. - self._notifier.stop() - - def _allocate_lock(self): - return _allocate_thread_lock() - - def _getcurrent(self): - return getcurrent() # pylint:disable=undefined-variable - - def _get_thread_ident(self): - return _get_thread_ident() - - def _capture_hub(self, create): - # Subclasses should call this as the first action from any - # public method that could, in theory, block and switch - # to the hub. This may release the GIL. It may - # raise InvalidThreadUseError if the result would - - # First, detect a dead hub and drop it. - while 1: - my_hub = self.hub - if my_hub is None: - break - if my_hub.dead: # dead is a property, could release GIL - # back, holding GIL - if self.hub is my_hub: - self.hub = None - my_hub = None - break - else: - break - - if self.hub is None: - # This next line might release the GIL. - current_hub = get_hub() if create else get_hub_if_exists() - - # We have the GIL again. Did anything change? If so, - # we lost the race. - if self.hub is None: - self.hub = current_hub - - if self.hub is not None and self.hub.thread_ident != _get_thread_ident(): - raise InvalidThreadUseError( - self.hub, - get_hub_if_exists(), - getcurrent() # pylint:disable=undefined-variable - ) - return self.hub - - def _check_and_notify(self): - # If this object is ready to be notified, begin the process. - if self.ready() and self._links and not self._notifier: - hub = None - try: - hub = self._capture_hub(False) # Must create, we need it. - except InvalidThreadUseError: - # The current hub doesn't match self.hub. That's OK, - # we still want to start the notifier in the thread running - # self.hub (because the links probably contains greenlet.switch - # calls valid only in that hub) - pass - if hub is not None: - self._notifier = hub.loop.run_callback(self._notify_links, []) - else: - # Hmm, no hub. We must be the only thing running. Then its OK - # to just directly call the callbacks. - self._notifier = 1 - try: - self._notify_links([]) - finally: - self._notifier = None - - def _notify_link_list(self, links): - # The core of the _notify_links method to notify - # links in order. Lets the ``links`` list be mutated, - # and only notifies up to the last item in the list, in case - # objects are added to it. - if not links: - # HMM. How did we get here? Running two threads at once? - # Seen once on Py27/Win/Appveyor - # https://ci.appveyor.com/project/jamadden/gevent/builds/36875645/job/9wahj9ft4h4qa170 - return [] - - only_while_ready = not self._notify_all - final_link = links[-1] - done = set() # of ids - hub = self.hub if self.hub is not None else get_hub_if_exists() - unswitched = [] - while links: # remember this can be mutated - if only_while_ready and not self.ready(): - break - - link = links.pop(0) # Cython optimizes using list internals - id_link = id(link) - if id_link not in done: - # XXX: JAM: What was I thinking? This doesn't make much sense, - # there's a good chance `link` will be deallocated, and its id() will - # be free to be reused. This also makes looping difficult, you have to - # create new functions inside a loop rather than just once outside the loop. - done.add(id_link) - try: - self._drop_lock_for_switch_out() - try: - link(self) - except greenlet_error: - # couldn't switch to a greenlet, we must be - # running in a different thread. back on the list it goes for next time. - unswitched.append(link) - finally: - self._acquire_lock_for_switch_in() - - except: # pylint:disable=bare-except - # We're running in the hub, errors must not escape. - if hub is not None: - hub.handle_error((link, self), *sys.exc_info()) - else: - import traceback - traceback.print_exc() - - if link is final_link: - break - return unswitched - - def _notify_links(self, arrived_while_waiting): - # This method must hold the GIL, or be guarded with the lock that guards - # this object. Thus, while we are notifying objects, an object from another - # thread simply cannot arrive and mutate ``_links`` or ``arrived_while_waiting`` - - # ``arrived_while_waiting`` is a list of greenlet.switch methods - # to call. These were objects that called wait() while we were processing, - # and which would have run *before* those that had actually waited - # and blocked. Instead of returning True immediately, we add them to this - # list so they wait their turn. - - # We release self._notifier here when done invoking links. - # The object itself becomes false in a boolean way as soon - # as this method returns. - notifier = self._notifier - if notifier is None: - # XXX: How did we get here? - self._check_and_notify() - return - # Early links are allowed to remove later links, and links - # are allowed to add more links, thus we must not - # make a copy of our the ``_links`` list, we must traverse it and - # mutate in place. - # - # We were ready() at the time this callback was scheduled; we - # may not be anymore, and that status may change during - # callback processing. Some of our subclasses (Event) will - # want to notify everyone who was registered when the status - # became true that it was once true, even though it may not be - # any more. In that case, we must not keep notifying anyone that's - # newly added after that, even if we go ready again. - try: - unswitched = self._notify_link_list(self._links) - # Now, those that arrived after we had begun the notification - # process. Follow the same rules, stop with those that are - # added so far to prevent starvation. - if arrived_while_waiting: - un2 = self._notify_link_list(arrived_while_waiting) - unswitched.extend(un2) - - # Anything left needs to go back on the main list. - self._links.extend(arrived_while_waiting) - finally: - # We should not have created a new notifier even if callbacks - # released us because we loop through *all* of our links on the - # same callback while self._notifier is still true. - # However, one of our callbacks could have called ``os.fork``, - # which invokes ``_at_fork_reinit`` and destroys the notifier and - # hub *while this method is running*. - assert self._notifier is notifier or ( - self._notifier is None and self.hub is None - ), (self, self._notifier, notifier) - self._notifier = None - # TODO: Maybe we should intelligently reset self.hub to - # free up thread affinity? In case of a pathological situation where - # one object was used from one thread once & first, but usually is - # used by another thread. - # - # BoundedSemaphore does this. - # Now we may be ready or not ready. If we're ready, which - # could have happened during the last link we called, then we - # must have more links than we started with. We need to schedule the - # wakeup. - self._check_and_notify() - if unswitched: - self._handle_unswitched_notifications(unswitched) - - - def _handle_unswitched_notifications(self, unswitched): - # Given a list of callable objects that raised - # ``greenlet.error`` when we called them: If we can determine - # that it is a parked greenlet (the callablle is a - # ``greenlet.switch`` method) and we can determine the hub - # that the greenlet belongs to (either its parent, or, in the - # case of a main greenlet, find a hub with the same parent as - # this greenlet object) then: - - # Move this to be a callback in that thread. - # (This relies on holding the GIL *or* ``Hub.loop.run_callback`` being - # thread-safe! Note that the CFFI implementations are definitely - # NOT thread-safe. TODO: Make them? Or an alternative?) - # - # Otherwise, print some error messages. - - # TODO: Inline this for individual links. That handles the - # "only while ready" case automatically. Be careful about locking in that case. - # - # TODO: Add a 'strict' mode that prevents doing this dance, since it's - # inherently not safe. - root_greenlets = None - printed_tb = False - only_while_ready = not self._notify_all - - while unswitched: - if only_while_ready and not self.ready(): - self.__print_unswitched_warning(unswitched, printed_tb) - break - - link = unswitched.pop(0) - - hub = None # Also serves as a "handled?" flag - # Is it a greenlet.switch method? - if (getattr(link, '__name__', None) == 'switch' - and isinstance(getattr(link, '__self__', None), greenlet)): - glet = link.__self__ - parent = glet.parent - - while parent is not None: - if hasattr(parent, 'loop'): # Assuming the hub. - hub = glet.parent - break - parent = glet.parent - - if hub is None: - if root_greenlets is None: - root_greenlets = get_roots_and_hubs() - hub = root_greenlets.get(glet) - - if hub is not None and hub.loop is not None: - hub.loop.run_callback_threadsafe(link, self) - if hub is None or hub.loop is None: - # We couldn't handle it - self.__print_unswitched_warning(link, printed_tb) - printed_tb = True - - - def __print_unswitched_warning(self, link, printed_tb): - print('gevent: error: Unable to switch to greenlet', link, - 'from', self, '; crossing thread boundaries is not allowed.', - file=sys.stderr) - - if not printed_tb: - printed_tb = True - print( - 'gevent: error: ' - 'This is a result of using gevent objects from multiple threads,', - 'and is a bug in the calling code.', file=sys.stderr) - - import traceback - traceback.print_stack() - - def _quiet_unlink_all(self, obj): - if obj is None: - return - - self.unlink(obj) - if self._notifier is not None and self._notifier.args: - try: - self._notifier.args[0].remove(obj) - except ValueError: - pass - - def __wait_to_be_notified(self, rawlink): # pylint:disable=too-many-branches - resume_this_greenlet = getcurrent().switch # pylint:disable=undefined-variable - if rawlink: - self.rawlink(resume_this_greenlet) - else: - self._notifier.args[0].append(resume_this_greenlet) - - try: - self._switch_to_hub(self.hub) - # If we got here, we were automatically unlinked already. - resume_this_greenlet = None - finally: - self._quiet_unlink_all(resume_this_greenlet) - - def _switch_to_hub(self, the_hub): - self._drop_lock_for_switch_out() - try: - result = the_hub.switch() - finally: - self._acquire_lock_for_switch_in() - if result is not self: # pragma: no cover - raise InvalidSwitchError( - 'Invalid switch into %s.wait(): %r' % ( - self.__class__.__name__, - result, - ) - ) - - def _acquire_lock_for_switch_in(self): - return - - def _drop_lock_for_switch_out(self): - return - - def _wait_core(self, timeout, catch=Timeout): - """ - The core of the wait implementation, handling switching and - linking. - - This method is NOT safe to call from multiple threads. - - ``self.hub`` must be initialized before entering this method. - The hub that is set is considered the owner and cannot be changed - while this method is running. It must only be called from the thread - where ``self.hub`` is the current hub. - - If *catch* is set to ``()``, a timeout that elapses will be - allowed to be raised. - - :return: A true value if the wait succeeded without timing out. - That is, a true return value means we were notified and control - resumed in this greenlet. - """ - with Timeout._start_new_or_dummy(timeout) as timer: # Might release - # We already checked above (_wait()) if we're ready() - try: - self.__wait_to_be_notified( - True,# Use rawlink() - ) - return True - except catch as ex: - if ex is not timer: - raise - # test_set_and_clear and test_timeout in test_threading - # rely on the exact return values, not just truthish-ness - return False - - def _wait_return_value(self, waited, wait_success): - # pylint:disable=unused-argument - # Subclasses should override this to return a value from _wait. - # By default we return None. - return None # pragma: no cover all extent subclasses override - - def _wait(self, timeout=None): - # Watch where we could potentially release the GIL. - self._capture_hub(True) # Must create, we must have an owner. Might release - - if self.ready(): # *might* release, if overridden in Python. - result = self._wait_return_value(False, False) # pylint:disable=assignment-from-none - if self._notifier: - # We're already notifying waiters; one of them must have run - # and switched to this greenlet, which arrived here. Alternately, - # we could be in a separate thread (but we're holding the GIL/object lock) - self.__wait_to_be_notified(False) # Use self._notifier.args[0] instead of self.rawlink - - return result - - gotit = self._wait_core(timeout) - return self._wait_return_value(True, gotit) - - def _at_fork_reinit(self): - """ - This method was added in Python 3.9 and is called by logging.py - ``_after_at_fork_child_reinit_locks`` on Lock objects. - - It is also called from threading.py, ``_after_fork`` in - ``_reset_internal_locks``, and that can hit ``Event`` objects. - - Subclasses should reset themselves to an initial state. This - includes unlocking/releasing, if possible. This method detaches from the - previous hub and drops any existing notifier. - """ - self.hub = None - self._notifier = None - -def _init(): - greenlet_init() # pylint:disable=undefined-variable - -_init() - - -from gevent._util import import_c_accel -import_c_accel(globals(), 'gevent.__abstract_linkable') diff --git a/venv/lib/python3.9/site-packages/gevent/_compat.py b/venv/lib/python3.9/site-packages/gevent/_compat.py deleted file mode 100644 index b992a38..0000000 --- a/venv/lib/python3.9/site-packages/gevent/_compat.py +++ /dev/null @@ -1,147 +0,0 @@ -# -*- coding: utf-8 -*- -""" -internal gevent python 2/python 3 bridges. Not for external use. -""" - -from __future__ import print_function, absolute_import, division - -## Important: This module should generally not have any other gevent -## imports (the exception is _util_py2) - -import sys -import os - - -PY311 = sys.version_info[:2] >= (3, 11) -PY312 = sys.version_info[:2] >= (3, 12) -PY313 = sys.version_info[:2] >= (3, 13) -PY314 = sys.version_info[:2] >= (3, 14) -PYPY = hasattr(sys, 'pypy_version_info') -WIN = sys.platform.startswith("win") -LINUX = sys.platform.startswith('linux') -OSX = MAC = sys.platform == 'darwin' - - -GLOBAL_PURE_PYTHON = bool(PYPY or os.environ.get('PURE_PYTHON')) -# .. versionchanged:: 25.9.1 -# -# GEVENT_PURE_PYTHON previously was treated like PURE_PYTHON, -# meaning any value at all would disable extensions. -# Now, we want to treat GEVENT_PURE_PYTHON as a comma-separated list of -# module names for which we disable the acceleration, but we want to be -# compatible with previous values, like so: -# -# - GEVENT_PURE_PYTHON=1 -# GEVENT_PURE_PYTHON=all -# GEVENT_PURE_PYTHON=some_string -# Disable all extensions -# - GEVENT_PURE_PYTHON=gevent.queue -# Disable the extension ONLY for gevent.queue -# - GEVENT_PURE_PYTHON=gevent.queue,gevent.hub -# Disable the extension for those two modules only -# - PURE_PYTHON= -# Disable all extensions. -# -# CAUTION: Not all configurations of mixing python/C modules -# will necessarily work together. None of them are tested. -# Some are certainly safe to disable independently, like gevent.queue. -_GEVENT_PURE_PYTHON = os.environ.get('GEVENT_PURE_PYTHON') -if _GEVENT_PURE_PYTHON and 'gevent.' not in _GEVENT_PURE_PYTHON: - GLOBAL_PURE_PYTHON = True - -#: ..deprecated:: 25.9.1 -PURE_PYTHON = GLOBAL_PURE_PYTHON - -def pure_python_module(mod_name): - if GLOBAL_PURE_PYTHON: - pure = True - elif not _GEVENT_PURE_PYTHON: - pure = False - else: - pure = mod_name in _GEVENT_PURE_PYTHON.split(',') - return pure - - -## Types - - -string_types = (str,) -integer_types = (int,) -text_type = str -native_path_types = (str, bytes) -thread_mod_name = '_thread' - -hostname_types = tuple(set(string_types + (bytearray, bytes))) - -def NativeStrIO(): - import io - return io.BytesIO() if str is bytes else io.StringIO() - - -from abc import ABC # pylint:disable=unused-import - - -## Exceptions - -def reraise(t, value, tb=None): # pylint:disable=unused-argument - if value.__traceback__ is not tb and tb is not None: - raise value.with_traceback(tb) - raise value -def exc_clear(): - pass - - - -## import locks -try: - # In Python 3.4 and newer in CPython and PyPy3, - # imp.acquire_lock and imp.release_lock are delegated to - # '_imp'. (Which is also used by importlib.) 'imp' itself is - # deprecated. Avoid that warning. - import _imp as imp -except ImportError: - import imp # pylint:disable=deprecated-module -imp_acquire_lock = imp.acquire_lock -imp_release_lock = imp.release_lock - -## Functions -iteritems = dict.items -itervalues = dict.values -xrange = range -izip = zip - - -## The __fspath__ protocol -from os import PathLike # pylint:disable=unused-import -from os import fspath -_fspath = fspath -from os import fsencode # pylint:disable=unused-import -from os import fsdecode # pylint:disable=unused-import - -## Clocks -# Python 3.3+ (PEP 418) -from time import perf_counter -from time import get_clock_info -from time import monotonic -perf_counter = perf_counter -monotonic = monotonic -get_clock_info = get_clock_info - - -## Monitoring -def get_this_psutil_process(): - # Depends on psutil. Defer the import until needed, who knows what - # it imports (psutil imports subprocess which on Python 3 imports - # selectors. This can expose issues with monkey-patching.) - # Returns a freshly queried object each time. - try: - from psutil import Process, AccessDenied - # Make sure it works (why would we be denied access to our own process?) - try: - proc = Process() - proc.memory_full_info() - except AccessDenied: # pragma: no cover - proc = None - except ImportError: - proc = None - return proc diff --git a/venv/lib/python3.9/site-packages/gevent/_config.py b/venv/lib/python3.9/site-packages/gevent/_config.py deleted file mode 100644 index 70cbc82..0000000 --- a/venv/lib/python3.9/site-packages/gevent/_config.py +++ /dev/null @@ -1,753 +0,0 @@ -# Copyright (c) 2018 gevent. See LICENSE for details. -""" -gevent tunables. - -This should be used as ``from gevent import config``. That variable -is an object of :class:`Config`. - -.. versionadded:: 1.3a2 - -.. versionchanged:: 22.08.0 - Invoking this module like ``python -m gevent._config`` will - print a help message about available configuration properties. - This is handy to quickly look for environment variables. -""" - -import importlib -import os -import textwrap - -from gevent._compat import string_types -from gevent._compat import WIN - -__all__ = [ - 'config', -] - -ALL_SETTINGS = [] - -class SettingType(type): - # pylint:disable=bad-mcs-classmethod-argument - - def __new__(cls, name, bases, cls_dict): - if name == 'Setting': - return type.__new__(cls, name, bases, cls_dict) - - cls_dict["order"] = len(ALL_SETTINGS) - if 'name' not in cls_dict: - cls_dict['name'] = name.lower() - - if 'environment_key' not in cls_dict: - cls_dict['environment_key'] = 'GEVENT_' + cls_dict['name'].upper() - - - new_class = type.__new__(cls, name, bases, cls_dict) - new_class.fmt_desc(cls_dict.get("desc", "")) - new_class.__doc__ = new_class.desc - ALL_SETTINGS.append(new_class) - - if new_class.document: - setting_name = cls_dict['name'] - - def getter(self): - return self.settings[setting_name].get() - - def setter(self, value): # pragma: no cover - # The setter should never be hit, Config has a - # __setattr__ that would override. But for the sake - # of consistency we provide one. - self.settings[setting_name].set(value) - - prop = property(getter, setter, doc=new_class.__doc__) - - setattr(Config, cls_dict['name'], prop) - return new_class - - def fmt_desc(cls, desc): - desc = textwrap.dedent(desc).strip() - if hasattr(cls, 'shortname_map'): - desc += ( - "\n\nThis is an importable value. It can be " - "given as a string naming an importable object, " - "or a list of strings in preference order and the first " - "successfully importable object will be used. (Separate values " - "in the environment variable with commas.) " - "It can also be given as the callable object itself (in code). " - ) - if cls.shortname_map: - desc += "Shorthand names for default objects are %r" % (list(cls.shortname_map),) - if getattr(cls.validate, '__doc__'): - desc += '\n\n' + textwrap.dedent(cls.validate.__doc__).strip() - if isinstance(cls.default, str) and hasattr(cls, 'shortname_map'): - default = "`%s`" % (cls.default,) - else: - default = "`%r`" % (cls.default,) - desc += "\n\nThe default value is %s" % (default,) - desc += ("\n\nThe environment variable ``%s`` " - "can be used to control this." % (cls.environment_key,)) - setattr(cls, "desc", desc) - return desc - -def validate_invalid(value): - raise ValueError("Not a valid value: %r" % (value,)) - -def validate_bool(value): - """ - This is a boolean value. - - In the environment variable, it may be given as ``1``, ``true``, - ``on`` or ``yes`` for `True`, or ``0``, ``false``, ``off``, or - ``no`` for `False`. - """ - if isinstance(value, string_types): - value = value.lower().strip() - if value in ('1', 'true', 'on', 'yes'): - value = True - elif value in ('0', 'false', 'off', 'no') or not value: - value = False - else: - raise ValueError("Invalid boolean string: %r" % (value,)) - return bool(value) - -def validate_anything(value): - return value - -convert_str_value_as_is = validate_anything - -class Setting(metaclass=SettingType): - name = None - value = None - validate = staticmethod(validate_invalid) - default = None - environment_key = None - document = True - - desc = """\ - - A long ReST description. - - The first line should be a single sentence. - - """ - - def _convert(self, value): - if isinstance(value, string_types): - return value.split(',') - return value - - def _default(self): - result = os.environ.get(self.environment_key, self.default) - result = self._convert(result) - return result - - def get(self): - # If we've been specifically set, return it - if 'value' in self.__dict__: - return self.value - # Otherwise, read from the environment and reify - # so we return consistent results. - self.value = self.validate(self._default()) - return self.value - - def set(self, val): - self.value = self.validate(self._convert(val)) - - - -def make_settings(): - """ - Return fresh instances of all classes defined in `ALL_SETTINGS`. - """ - settings = {} - for setting_kind in ALL_SETTINGS: - setting = setting_kind() - assert setting.name not in settings - settings[setting.name] = setting - return settings - - -class Config(object): - """ - Global configuration for gevent. - - There is one instance of this object at ``gevent.config``. If you - are going to make changes in code, instead of using the documented - environment variables, you need to make the changes before using - any parts of gevent that might need those settings (unless otherwise - documented). For example:: - - >>> from gevent import config - >>> config.fileobject = 'thread' - - >>> from gevent import fileobject - >>> fileobject.FileObject.__name__ - 'FileObjectThread' - - .. versionadded:: 1.3a2 - - """ - - def __init__(self): - self.settings = make_settings() - - def __getattr__(self, name): - if name not in self.settings: - raise AttributeError("No configuration setting for: %r" % name) - return self.settings[name].get() - - def __setattr__(self, name, value): - if name != "settings" and name in self.settings: - self.set(name, value) - else: - super(Config, self).__setattr__(name, value) - - def set(self, name, value): - if name not in self.settings: - raise AttributeError("No configuration setting for: %r" % name) - self.settings[name].set(value) - - def __dir__(self): - return list(self.settings) - - def print_help(self): - for k, v in self.settings.items(): - print(k) - print(textwrap.indent(v.__doc__.lstrip(), ' ' * 4)) - print() - - -class ImportableSetting(object): - - def _import_one_of(self, candidates): - assert isinstance(candidates, list) - if not candidates: - raise ImportError('Cannot import from empty list') - - for item in candidates[:-1]: - try: - return self._import_one(item) - except ImportError: - pass - - return self._import_one(candidates[-1]) - - def _import_one(self, path, _MISSING=object()): - if not isinstance(path, string_types): - return path - - if '.' not in path or '/' in path: - raise ImportError("Cannot import %r. " - "Required format: [package.]module.class. " - "Or choose from %r" - % (path, list(self.shortname_map))) - - - module, item = path.rsplit('.', 1) - module = importlib.import_module(module) - x = getattr(module, item, _MISSING) - if x is _MISSING: - raise ImportError('Cannot import %r from %r' % (item, module)) - return x - - shortname_map = {} - - def validate(self, value): - if isinstance(value, type): - return value - return self._import_one_of([self.shortname_map.get(x, x) for x in value]) - - def get_options(self): - result = {} - for name, val in self.shortname_map.items(): - try: - result[name] = self._import_one(val) - except ImportError as e: - result[name] = e - return result - - -class BoolSettingMixin(object): - validate = staticmethod(validate_bool) - # Don't do string-to-list conversion. - _convert = staticmethod(convert_str_value_as_is) - - -class IntSettingMixin(object): - # Don't do string-to-list conversion. - def _convert(self, value): - if value: - return int(value) - - validate = staticmethod(validate_anything) - - -class _PositiveValueMixin(object): - - def validate(self, value): - if value is not None and value <= 0: - raise ValueError("Must be positive") - return value - - -class FloatSettingMixin(_PositiveValueMixin): - def _convert(self, value): - if value: - return float(value) - - -class ByteCountSettingMixin(_PositiveValueMixin): - - _MULTIPLES = { - # All keys must be the same size. - 'kb': 1024, - 'mb': 1024 * 1024, - 'gb': 1024 * 1024 * 1024, - } - - _SUFFIX_SIZE = 2 - - def _convert(self, value): - if not value or not isinstance(value, str): - return value - value = value.lower() - for s, m in self._MULTIPLES.items(): - if value[-self._SUFFIX_SIZE:] == s: - return int(value[:-self._SUFFIX_SIZE]) * m - return int(value) - - -class Resolver(ImportableSetting, Setting): - - desc = """\ - The callable that will be used to create - :attr:`gevent.hub.Hub.resolver`. - - See :doc:`dns` for more information. - """ - - default = [ - 'thread', - 'dnspython', - 'ares', - 'block', - ] - - shortname_map = { - 'ares': 'gevent.resolver.ares.Resolver', - 'thread': 'gevent.resolver.thread.Resolver', - 'block': 'gevent.resolver.blocking.Resolver', - 'dnspython': 'gevent.resolver.dnspython.Resolver', - } - - - -class Threadpool(ImportableSetting, Setting): - - desc = """\ - The kind of threadpool we use. - """ - - default = 'gevent.threadpool.ThreadPool' - - -class ThreadpoolIdleTaskTimeout(FloatSettingMixin, Setting): - document = True - name = 'threadpool_idle_task_timeout' - environment_key = 'GEVENT_THREADPOOL_IDLE_TASK_TIMEOUT' - - desc = """\ - How long threads in the default threadpool (used for - DNS by default) are allowed to be idle before exiting. - - Use -1 for no timeout. - - .. versionadded:: 22.08.0 - """ - - # This value is picked pretty much arbitrarily. - # We want to balance performance (keeping threads around) - # with memory/cpu usage (letting threads go). - default = 5.0 - -class Loop(ImportableSetting, Setting): - - desc = """\ - The kind of the loop we use. - - On Windows, this defaults to libuv, while on - other platforms it defaults to libev. - - """ - - default = [ - 'libev-cext', - 'libev-cffi', - 'libuv-cffi', - ] if not WIN else [ - 'libuv-cffi', - 'libev-cext', - 'libev-cffi', - ] - - shortname_map = { # pylint:disable=dict-init-mutate - 'libev-cext': 'gevent.libev.corecext.loop', - 'libev-cffi': 'gevent.libev.corecffi.loop', - 'libuv-cffi': 'gevent.libuv.loop.loop', - } - - shortname_map['libuv'] = shortname_map['libuv-cffi'] - - -class FormatContext(ImportableSetting, Setting): - name = 'format_context' - - # using pprint.pformat can override custom __repr__ methods on dict/list - # subclasses, which can be a security concern - default = 'pprint.saferepr' - - -class LibevBackend(Setting): - name = 'libev_backend' - environment_key = 'GEVENT_BACKEND' - - desc = """\ - The backend for libev, such as 'select' - """ - - default = None - - validate = staticmethod(validate_anything) - - -class FileObject(ImportableSetting, Setting): - desc = """\ - The kind of ``FileObject`` we will use. - - See :mod:`gevent.fileobject` for a detailed description. - - """ - environment_key = 'GEVENT_FILE' - - default = [ - 'posix', - 'thread', - ] - - shortname_map = { - 'thread': 'gevent._fileobjectcommon.FileObjectThread', - 'posix': 'gevent._fileobjectposix.FileObjectPosix', - 'block': 'gevent._fileobjectcommon.FileObjectBlock' - } - - -class WatchChildren(BoolSettingMixin, Setting): - desc = """\ - Should we *not* watch children with the event loop watchers? - - This is an advanced setting. - - See :mod:`gevent.os` for a detailed description. - """ - name = 'disable_watch_children' - environment_key = 'GEVENT_NOWAITPID' - default = False - - -class TraceMalloc(IntSettingMixin, Setting): - name = 'trace_malloc' - environment_key = 'PYTHONTRACEMALLOC' - default = False - - desc = """\ - Should FFI objects track their allocation? - - This is only useful for low-level debugging. - - On Python 3, this environment variable is built in to the - interpreter, and it may also be set with the ``-X - tracemalloc`` command line argument. - - On Python 2, gevent interprets this argument and adds extra - tracking information for FFI objects. - """ - - -class TrackGreenletTree(BoolSettingMixin, Setting): - name = 'track_greenlet_tree' - environment_key = 'GEVENT_TRACK_GREENLET_TREE' - default = True - - desc = """\ - Should `Greenlet` objects track their spawning tree? - - Setting this to a false value will make spawning `Greenlet` - objects and using `spawn_raw` faster, but the - ``spawning_greenlet``, ``spawn_tree_locals`` and ``spawning_stack`` - will not be captured. Setting this to a false value can also - reduce memory usage because capturing the stack captures - some information about Python frames. - - .. versionadded:: 1.3b1 - """ - - -## Monitoring settings -# All env keys should begin with GEVENT_MONITOR - -class MonitorThread(BoolSettingMixin, Setting): - name = 'monitor_thread' - environment_key = 'GEVENT_MONITOR_THREAD_ENABLE' - default = False - - desc = """\ - Should each hub start a native OS thread to monitor - for problems? - - Such a thread will periodically check to see if the event loop - is blocked for longer than `max_blocking_time`, producing output on - the hub's exception stream (stderr by default) if it detects this condition. - - If this setting is true, then this thread will be created - the first time the hub is switched to, - or you can call :meth:`gevent.hub.Hub.start_periodic_monitoring_thread` at any - time to create it (from the same thread that will run the hub). That function - will return an instance of :class:`gevent.events.IPeriodicMonitorThread` - to which you can add your own monitoring functions. That function - also emits an event of :class:`gevent.events.PeriodicMonitorThreadStartedEvent`. - - .. seealso:: `max_blocking_time` - - .. versionadded:: 1.3b1 - """ - -class MaxBlockingTime(FloatSettingMixin, Setting): - name = 'max_blocking_time' - # This environment key doesn't follow the convention because it's - # meant to match a key used by existing projects - environment_key = 'GEVENT_MAX_BLOCKING_TIME' - default = 0.1 - - desc = """\ - If the `monitor_thread` is enabled, this is - approximately how long (in seconds) - the event loop will be allowed to block before a warning is issued. - - This function depends on using `greenlet.settrace`, so installing - your own trace function after starting the monitoring thread will - cause this feature to misbehave unless you call the function - returned by `greenlet.settrace`. If you install a tracing function *before* - the monitoring thread is started, it will still be called. - - .. note:: In the unlikely event of creating and using multiple different - gevent hubs in the same native thread in a short period of time, - especially without destroying the hubs, false positives may be reported. - - .. versionadded:: 1.3b1 - """ - - -class PrintBlockingReports(BoolSettingMixin, Setting): - name = 'print_blocking_reports' - default = True - - environment_key = 'GEVENT_MONITOR_PRINT_BLOCKING_REPORTS' - desc = """\ - If `monitor_thread` is enabled, and gevent detects a hub blocked - for more than `max_blocking_time`, should gevent print a detailed - report about the block? - - The report is generated and notifications are broadcast whether - or not the report is printed. - - .. versionadded:: 25.4.1 - """ - - -class MonitorMemoryPeriod(FloatSettingMixin, Setting): - name = 'memory_monitor_period' - - environment_key = 'GEVENT_MONITOR_MEMORY_PERIOD' - default = 5 - - desc = """\ - If `monitor_thread` is enabled, this is approximately how long - (in seconds) we will go between checking the processes memory usage. - - Checking the memory usage is relatively expensive on some operating - systems, so this should not be too low. gevent will place a floor - value on it. - """ - -class MonitorMemoryMaxUsage(ByteCountSettingMixin, Setting): - name = 'max_memory_usage' - - environment_key = 'GEVENT_MONITOR_MEMORY_MAX' - default = None - - desc = """\ - If `monitor_thread` is enabled, - then if memory usage exceeds this amount (in bytes), events will - be emitted. See `gevent.events`. In the environment variable, you can use - a suffix of 'kb', 'mb' or 'gb' to specify the value in kilobytes, megabytes - or gigibytes. - - There is no default value for this setting. If you wish to - cap memory usage, you must choose a value. - """ - -# The ares settings are all interpreted by -# gevent/resolver/ares.pyx, so we don't do -# any validation here. - -class AresSettingMixin(object): - - document = False - - @property - def kwarg_name(self): - return self.name[5:] - - validate = staticmethod(validate_anything) - - _convert = staticmethod(convert_str_value_as_is) - -class AresFlags(AresSettingMixin, Setting): - name = 'ares_flags' - default = None - environment_key = 'GEVENTARES_FLAGS' - -class AresTimeout(AresSettingMixin, Setting): - document = True - name = 'ares_timeout' - default = None - environment_key = 'GEVENTARES_TIMEOUT' - desc = """\ - - .. deprecated:: 1.3a2 - Prefer the :attr:`resolver_timeout` setting. If both are set, - the results are not defined. - """ - -class AresTries(AresSettingMixin, Setting): - name = 'ares_tries' - default = None - environment_key = 'GEVENTARES_TRIES' - -class AresNdots(AresSettingMixin, Setting): - name = 'ares_ndots' - default = None - environment_key = 'GEVENTARES_NDOTS' - -class AresUDPPort(AresSettingMixin, Setting): - name = 'ares_udp_port' - default = None - environment_key = 'GEVENTARES_UDP_PORT' - -class AresTCPPort(AresSettingMixin, Setting): - name = 'ares_tcp_port' - default = None - environment_key = 'GEVENTARES_TCP_PORT' - -class AresServers(AresSettingMixin, Setting): - document = True - name = 'ares_servers' - default = None - environment_key = 'GEVENTARES_SERVERS' - desc = """\ - A list of strings giving the IP addresses of nameservers for the ares resolver. - - In the environment variable, these strings are separated by commas. - - .. deprecated:: 1.3a2 - Prefer the :attr:`resolver_nameservers` setting. If both are set, - the results are not defined. - """ - -# Generic nameservers, works for dnspython and ares. -class ResolverNameservers(AresSettingMixin, Setting): - document = True - name = 'resolver_nameservers' - default = None - environment_key = 'GEVENT_RESOLVER_NAMESERVERS' - desc = """\ - A list of strings giving the IP addresses of nameservers for the (non-system) resolver. - - In the environment variable, these strings are separated by commas. - - .. rubric:: Resolver Behaviour - - * blocking - - Ignored - - * Threaded - - Ignored - - * dnspython - - If this setting is not given, the dnspython resolver will - load nameservers to use from ``/etc/resolv.conf`` - or the Windows registry. This setting replaces any nameservers read - from those means. Note that the file and registry are still read - for other settings. - - .. caution:: dnspython does not validate the members of the list. - An improper address (such as a hostname instead of IP) has - undefined results, including hanging the process. - - * ares - - Similar to dnspython, but with more platform and compile-time - options. ares validates that the members of the list are valid - addresses. - """ - - # Normal string-to-list rules. But still validate_anything. - _convert = Setting._convert - - # TODO: In the future, support reading a resolv.conf file - # *other* than /etc/resolv.conf, and do that both on Windows - # and other platforms. Also offer the option to disable the system - # configuration entirely. - - @property - def kwarg_name(self): - return 'servers' - -# Generic timeout, works for dnspython and ares -class ResolverTimeout(FloatSettingMixin, AresSettingMixin, Setting): - document = True - name = 'resolver_timeout' - environment_key = 'GEVENT_RESOLVER_TIMEOUT' - desc = """\ - The total amount of time that the DNS resolver will spend making queries. - - Only the ares and dnspython resolvers support this. - - .. versionadded:: 1.3a2 - """ - - @property - def kwarg_name(self): - return 'timeout' - -config = Config() - -# Go ahead and attempt to import the loop when this class is -# instantiated. The hub won't work if the loop can't be found. This -# can solve problems with the class being imported from multiple -# threads at once, leading to one of the imports failing. -# factories are themselves handled lazily. See #687. - -# Don't cache it though, in case the user re-configures through the -# API. - -try: - Loop().get() -except ImportError: # pragma: no cover - pass - - -if __name__ == '__main__': - config.print_help() diff --git a/venv/lib/python3.9/site-packages/gevent/_ffi/__init__.py b/venv/lib/python3.9/site-packages/gevent/_ffi/__init__.py deleted file mode 100644 index 56f1e96..0000000 --- a/venv/lib/python3.9/site-packages/gevent/_ffi/__init__.py +++ /dev/null @@ -1,27 +0,0 @@ -""" -Internal helpers for FFI implementations. -""" -from __future__ import print_function, absolute_import - -import os -import sys - -def _dbg(*args, **kwargs): - # pylint:disable=unused-argument - pass - -#_dbg = print - -def _pid_dbg(*args, **kwargs): - kwargs['file'] = sys.stderr - print(os.getpid(), *args, **kwargs) - -CRITICAL = 1 -ERROR = 3 -DEBUG = 5 -TRACE = 9 - -GEVENT_DEBUG_LEVEL = vars()[os.getenv("GEVENT_DEBUG", 'CRITICAL').upper()] - -if GEVENT_DEBUG_LEVEL >= TRACE: - _dbg = _pid_dbg diff --git a/venv/lib/python3.9/site-packages/gevent/_ffi/callback.py b/venv/lib/python3.9/site-packages/gevent/_ffi/callback.py deleted file mode 100644 index 38ddda1..0000000 --- a/venv/lib/python3.9/site-packages/gevent/_ffi/callback.py +++ /dev/null @@ -1,57 +0,0 @@ -from __future__ import absolute_import -from __future__ import print_function - -from zope.interface import implementer - -from gevent._interfaces import ICallback - -__all__ = [ - 'callback', -] - - -@implementer(ICallback) -class callback(object): - - __slots__ = ('callback', 'args') - - def __init__(self, cb, args): - self.callback = cb - self.args = args - - def stop(self): - self.callback = None - self.args = None - - close = stop - - # Note that __nonzero__ and pending are different - # bool() is used in contexts where we need to know whether to schedule another callback, - # so it's true if it's pending or currently running - # 'pending' has the same meaning as libev watchers: it is cleared before actually - # running the callback - - def __bool__(self): - # it's nonzero if it's pending or currently executing - # NOTE: This depends on loop._run_callbacks setting the args property - # to None. - return self.args is not None - - @property - def pending(self): - return self.callback is not None - - def _format(self): - return '' - - def __repr__(self): - result = "<%s at 0x%x" % (self.__class__.__name__, id(self)) - if self.pending: - result += " pending" - if self.callback is not None: - result += " callback=%r" % (self.callback, ) - if self.args is not None: - result += " args=%r" % (self.args, ) - if self.callback is None and self.args is None: - result += " stopped" - return result + ">" diff --git a/venv/lib/python3.9/site-packages/gevent/_ffi/loop.py b/venv/lib/python3.9/site-packages/gevent/_ffi/loop.py deleted file mode 100644 index 3d84193..0000000 --- a/venv/lib/python3.9/site-packages/gevent/_ffi/loop.py +++ /dev/null @@ -1,798 +0,0 @@ -""" -Basic loop implementation for ffi-based cores. -""" -# pylint: disable=too-many-lines, protected-access, redefined-outer-name, not-callable -from __future__ import absolute_import, print_function - -from collections import deque -import sys -import os -import traceback - -from gevent._ffi import _dbg -from gevent._ffi import GEVENT_DEBUG_LEVEL -from gevent._ffi import TRACE -from gevent._ffi.callback import callback -from gevent._compat import PYPY -from gevent.exceptions import HubDestroyed - -from gevent import getswitchinterval - -__all__ = [ - 'AbstractLoop', - 'assign_standard_callbacks', -] - - -class _EVENTSType(object): - def __repr__(self): - return 'gevent.core.EVENTS' - -EVENTS = GEVENT_CORE_EVENTS = _EVENTSType() - - -class _DiscardedSet(frozenset): - __slots__ = () - - def discard(self, o): - "Does nothing." - -##### -## Note on CFFI objects, callbacks and the lifecycle of watcher objects -# -# Each subclass of `watcher` allocates a C structure of the -# appropriate type e.g., struct gevent_ev_io and holds this pointer in -# its `_gwatcher` attribute. When that watcher instance is garbage -# collected, then the C structure is also freed. The C structure is -# passed to libev from the watcher's start() method and then to the -# appropriate C callback function, e.g., _gevent_ev_io_callback, which -# passes it back to python's _python_callback where we need the -# watcher instance. Therefore, as long as that callback is active (the -# watcher is started), the watcher instance must not be allowed to get -# GC'd---any access at the C level or even the FFI level to the freed -# memory could crash the process. -# -# However, the typical idiom calls for writing something like this: -# loop.io(fd, python_cb).start() -# thus forgetting the newly created watcher subclass and allowing it to be immediately -# GC'd. To combat this, when the watcher is started, it places itself into the loop's -# `_keepaliveset`, and it only removes itself when the watcher's `stop()` method is called. -# Often, this is the *only* reference keeping the watcher object, and hence its C structure, -# alive. -# -# This is slightly complicated by the fact that the python-level -# callback, called from the C callback, could choose to manually stop -# the watcher. When we return to the C level callback, we now have an -# invalid pointer, and attempting to pass it back to Python (e.g., to -# handle an error) could crash. Hence, _python_callback, -# _gevent_io_callback, and _python_handle_error cooperate to make sure -# that the watcher instance stays in the loops `_keepaliveset` while -# the C code could be running---and if it gets removed, to not call back -# to Python again. -# See also https://github.com/gevent/gevent/issues/676 -#### -class AbstractCallbacks(object): - - - def __init__(self, ffi): - self.ffi = ffi - self.callbacks = [] - if GEVENT_DEBUG_LEVEL < TRACE: - self.from_handle = ffi.from_handle - - def from_handle(self, handle): # pylint:disable=method-hidden - x = self.ffi.from_handle(handle) - return x - - def python_callback(self, handle, revents): - """ - Returns an integer having one of three values: - - - -1 - An exception occurred during the callback and you must call - :func:`_python_handle_error` to deal with it. The Python watcher - object will have the exception tuple saved in ``_exc_info``. - - 1 - Everything went according to plan. You should check to see if the native - watcher is still active, and call :func:`python_stop` if it is not. This will - clean up the memory. Finding the watcher still active at the event loop level, - but not having stopped itself at the gevent level is a buggy scenario and - shouldn't happen. - - 2 - Everything went according to plan, but the watcher has already - been stopped. Its memory may no longer be valid. - - This function should never return 0, as that's the default value that - Python exceptions will produce. - """ - #_dbg("Running callback", handle) - orig_ffi_watcher = None - orig_loop = None - try: - # Even dereferencing the handle needs to be inside the try/except; - # if we don't return normally (e.g., a signal) then we wind up going - # to the 'onerror' handler (unhandled_onerror), which - # is not what we want; that can permanently wedge the loop depending - # on which callback was executing. - # XXX: See comments in that function. We may be able to restart and do better? - if not handle: - # Hmm, a NULL handle. That's not supposed to happen. - # We can easily get into a loop if we deref it and allow that - # to raise. - _dbg("python_callback got null handle") - return 1 - the_watcher = self.from_handle(handle) - orig_ffi_watcher = the_watcher._watcher - orig_loop = the_watcher.loop - args = the_watcher.args - if args is None: - # Legacy behaviour from corecext: convert None into () - # See test__core_watcher.py - args = _NOARGS - if args and args[0] == GEVENT_CORE_EVENTS: - args = (revents, ) + args[1:] - the_watcher.callback(*args) # None here means we weren't started - except: # pylint:disable=bare-except - # It's possible for ``the_watcher`` to be undefined (UnboundLocalError) - # if we threw an exception (signal) on the line that created that variable. - # This is typically the case with a signal under libuv - try: - the_watcher - except UnboundLocalError: - the_watcher = self.from_handle(handle) - - # It may not be safe to do anything with `handle` or `orig_ffi_watcher` - # anymore. If the watcher closed or stopped itself *before* throwing the exception, - # then the `handle` and `orig_ffi_watcher` may no longer be valid. Attempting to - # e.g., dereference the handle is likely to crash the process. - the_watcher._exc_info = sys.exc_info() - - - # If it hasn't been stopped, we need to make sure its - # memory stays valid so we can stop it at the native level if needed. - # If its loop is gone, it has already been stopped, - # see https://github.com/gevent/gevent/issues/1295 for a case where - # that happened, as well as issue #1482 - if ( - # The last thing it does. Full successful close. - the_watcher.loop is None - # Only a partial close. We could leak memory and even crash later. - or the_watcher._handle is None - ): - # Prevent unhandled_onerror from using the invalid handle - handle = None - exc_info = the_watcher._exc_info - del the_watcher._exc_info - try: - if orig_loop is not None: - orig_loop.handle_error(the_watcher, *exc_info) - else: - self.unhandled_onerror(*exc_info) - except: - print("WARNING: gevent: Error when handling error", - file=sys.stderr) - traceback.print_exc() - # Signal that we're closed, no need to do more. - return 2 - - # Keep it around so we can close it later. - the_watcher.loop._keepaliveset.add(the_watcher) - return -1 - - if (the_watcher.loop is not None - and the_watcher in the_watcher.loop._keepaliveset - and the_watcher._watcher is orig_ffi_watcher): - # It didn't stop itself, *and* it didn't stop itself, reset - # its watcher, and start itself again. libuv's io watchers - # multiplex and may do this. - - # The normal, expected scenario when we find the watcher still - # in the keepaliveset is that it is still active at the event loop - # level, so we don't expect that python_stop gets called. - #_dbg("The watcher has not stopped itself, possibly still active", the_watcher) - return 1 - return 2 # it stopped itself - - def python_handle_error(self, handle, _revents): - _dbg("Handling error for handle", handle) - if not handle: - return - # No exceptions should escape this method. - - try: - # Prior to 3.14, you could just ``return`` out of a finally - # block to quash any active exception. This was deemed Bad - # in PEP765, so now we have to add an extra level - # of indentation. Sigh. - try: - watcher = self.from_handle(handle) - exc_info = watcher._exc_info - del watcher._exc_info - # In the past, we passed the ``watcher`` itself as the context, - # which typically meant that the Hub would just print - # the exception. This is a problem because sometimes we can't - # detect signals until late in ``python_callback``; specifically, - # test_selectors.py:DefaultSelectorTest.test_select_interrupt_exc - # installs a SIGALRM handler that raises an exception. That exception can happen - # before we enter ``python_callback`` or at any point within it because of the way - # libuv swallows signals. By passing None, we get the exception prapagated into - # the main greenlet (which is probably *also* not what we always want, but - # I see no way to distinguish the cases). - watcher.loop.handle_error(None, *exc_info) - finally: - # XXX Since we're here on an error condition, and we - # made sure that the watcher object was put in loop._keepaliveset, - # what about not stopping the watcher? Looks like a possible - # memory leak? - # XXX: This used to do "if revents & (libev.EV_READ | libev.EV_WRITE)" - # before stopping. Why? - try: - watcher.stop() - except: # pylint:disable=bare-except - watcher.loop.handle_error(watcher, *sys.exc_info()) - except: # pylint: disable=bare-except - pass - return - - def unhandled_onerror(self, t, v, tb): - # This is supposed to be called for signals, etc. - # This is the onerror= value for CFFI. - # If we return None, C will get a value of 0/NULL; - # if we raise, CFFI will print the exception and then - # return 0/NULL; (unless error= was configured) - # If things go as planned, we return the value that asks - # C to call back and check on if the watcher needs to be closed or - # not. - - # XXX: TODO: Could this cause events to be lost? Maybe we need to return - # a value that causes the C loop to try the callback again? - # at least for signals under libuv, which are delivered at very odd times. - # Hopefully the event still shows up when we poll the next time. - watcher = None - handle = tb.tb_frame.f_locals.get('handle') if tb is not None else None - if handle: # handle could be NULL - watcher = self.from_handle(handle) - if watcher is not None: - watcher.loop.handle_error(None, t, v, tb) - return 1 - - # Raising it causes a lot of noise from CFFI - print("WARNING: gevent: Unhandled error with no watcher", - file=sys.stderr) - traceback.print_exception(t, v, tb) - - def python_stop(self, handle): - if not handle: # pragma: no cover - print( - "WARNING: gevent: Unable to dereference handle; not stopping watcher. " - "Native resources may leak. This is most likely a bug in gevent.", - file=sys.stderr) - # The alternative is to crash with no helpful information - # NOTE: Raising exceptions here does nothing, they're swallowed by CFFI. - # Since the C level passed in a null pointer, even dereferencing the handle - # will just produce some exceptions. - return - watcher = self.from_handle(handle) - watcher.stop() - - if not PYPY: - def python_check_callback(self, watcher_ptr): # pylint:disable=unused-argument - # If we have the onerror callback, this is a no-op; all the real - # work to rethrow the exception is done by the onerror callback - - # NOTE: Unlike the rest of the functions, this is called with a pointer - # to the C level structure, *not* a pointer to the void* that represents a - # for the Python Watcher object. - pass - else: # PyPy - # On PyPy, we need the function to have some sort of body, otherwise - # the signal exceptions don't always get caught, *especially* with - # libuv (however, there's no reason to expect this to only be a libuv - # issue; it's just that we don't depend on the periodic signal timer - # under libev, so the issue is much more pronounced under libuv) - # test_socket's test_sendall_interrupted can hang. - # See https://github.com/gevent/gevent/issues/1112 - - def python_check_callback(self, watcher_ptr): # pylint:disable=unused-argument - # Things we've tried that *don't* work: - # greenlet.getcurrent() - # 1 + 1 - try: - raise MemoryError() - except MemoryError: - pass - - def python_prepare_callback(self, watcher_ptr): - loop = self._find_loop_from_c_watcher(watcher_ptr) - if loop is None: # pragma: no cover - print("WARNING: gevent: running prepare callbacks from a destroyed handle: ", - watcher_ptr) - return - loop._run_callbacks() - - def check_callback_onerror(self, t, v, tb): - loop = None - watcher_ptr = self._find_watcher_ptr_in_traceback(tb) - if watcher_ptr: - loop = self._find_loop_from_c_watcher(watcher_ptr) - if loop is not None: - # None as the context argument causes the exception to be raised - # in the main greenlet. - loop.handle_error(None, t, v, tb) - return None - raise v # Let CFFI print - - def _find_loop_from_c_watcher(self, watcher_ptr): - raise NotImplementedError() - - def _find_watcher_ptr_in_traceback(self, tb): - return tb.tb_frame.f_locals['watcher_ptr'] if tb is not None else None - - -def assign_standard_callbacks(ffi, lib, callbacks_class, extras=()): # pylint:disable=unused-argument - """ - Given the typical *ffi* and *lib* arguments, and a subclass of :class:`AbstractCallbacks` - in *callbacks_class*, set up the ``def_extern`` Python callbacks from C - into an instance of *callbacks_class*. - - :param tuple extras: If given, this is a sequence of ``(name, error_function)`` - additional callbacks to register. Each *name* is an attribute of - the *callbacks_class* instance. (Each element cas also be just a *name*.) - :return: The *callbacks_class* instance. This object must be kept alive, - typically at module scope. - """ - # callbacks keeps these cdata objects alive at the python level - callbacks = callbacks_class(ffi) - extras = [extra if len(extra) == 2 else (extra, None) for extra in extras] - extras = tuple((getattr(callbacks, name), error) for name, error in extras) - for (func, error_func) in ( - (callbacks.python_callback, None), - (callbacks.python_handle_error, None), - (callbacks.python_stop, None), - (callbacks.python_check_callback, callbacks.check_callback_onerror), - (callbacks.python_prepare_callback, callbacks.check_callback_onerror) - ) + extras: - # The name of the callback function matches the 'extern Python' declaration. - error_func = error_func or callbacks.unhandled_onerror - callback = ffi.def_extern(onerror=error_func)(func) - # keep alive the cdata - # (def_extern returns the original function, and it requests that - # the function be "global", so maybe it keeps a hard reference to it somewhere now - # unlike ffi.callback(), and we don't need to do this?) - callbacks.callbacks.append(callback) - - # At this point, the library C variable (static function, actually) - # is filled in. - - return callbacks - - - -basestring = (bytes, str) -integer_types = (int,) - - -_NOARGS = () - - -class AbstractLoop(object): - # pylint:disable=too-many-public-methods,too-many-instance-attributes - - # How many callbacks we should run between checking against the - # switch interval. - CALLBACK_CHECK_COUNT = 50 - - error_handler = None - - _CHECK_POINTER = None - - _TIMER_POINTER = None - _TIMER_CALLBACK_SIG = None - - _PREPARE_POINTER = None - - starting_timer_may_update_loop_time = False - - # Subclasses should set this in __init__ to reflect - # whether they were the default loop. - _default = None - - _keepaliveset = _DiscardedSet() - _threadsafe_async = None - - def __init__(self, ffi, lib, watchers, flags=None, default=None): - self._ffi = ffi - self._lib = lib - self._ptr = None - self._handle_to_self = self._ffi.new_handle(self) # XXX: Reference cycle? - self._watchers = watchers - self._in_callback = False - self._callbacks = deque() - # Stores python watcher objects while they are started - self._keepaliveset = set() - self._init_loop_and_aux_watchers(flags, default) - - def _init_loop_and_aux_watchers(self, flags=None, default=None): - self._ptr = self._init_loop(flags, default) - - # self._check is a watcher that runs in each iteration of the - # mainloop, just after the blocking call. It's point is to handle - # signals. It doesn't run watchers or callbacks, it just exists to give - # CFFI a chance to raise signal exceptions so we can handle them. - self._check = self._ffi.new(self._CHECK_POINTER) - self._check.data = self._handle_to_self - self._init_and_start_check() - - # self._prepare is a watcher that runs in each iteration of the mainloop, - # just before the blocking call. It's where we run deferred callbacks - # from self.run_callback. This cooperates with _setup_for_run_callback() - # to schedule self._timer0 if needed. - self._prepare = self._ffi.new(self._PREPARE_POINTER) - self._prepare.data = self._handle_to_self - self._init_and_start_prepare() - - # A timer we start and stop on demand. If we have callbacks, - # too many to run in one iteration of _run_callbacks, we turn this - # on so as to have the next iteration of the run loop return to us - # as quickly as possible. - # TODO: There may be a more efficient way to do this using ev_timer_again; - # see the "ev_timer" section of the ev manpage (http://linux.die.net/man/3/ev) - # Alternatively, setting the ev maximum block time may also work. - self._timer0 = self._ffi.new(self._TIMER_POINTER) - self._timer0.data = self._handle_to_self - self._init_callback_timer() - - self._threadsafe_async = self.async_(ref=False) - # No need to do anything with this on ``fork()``, both libev and libuv - # take care of creating a new pipe in their respective ``loop_fork()`` methods. - self._threadsafe_async.start(lambda: None) - # TODO: We may be able to do something nicer and use the existing python_callback - # combined with onerror and the class check/timer/prepare to simplify things - # and unify our handling - - def _init_loop(self, flags, default): - """ - Called by __init__ to create or find the loop. The return value - is assigned to self._ptr. - """ - raise NotImplementedError() - - def _init_and_start_check(self): - raise NotImplementedError() - - def _init_and_start_prepare(self): - raise NotImplementedError() - - def _init_callback_timer(self): - raise NotImplementedError() - - def _stop_callback_timer(self): - raise NotImplementedError() - - def _start_callback_timer(self): - raise NotImplementedError() - - def _check_callback_handle_error(self, t, v, tb): - self.handle_error(None, t, v, tb) - - def _run_callbacks(self): # pylint:disable=too-many-branches - # When we're running callbacks, its safe for timers to - # update the notion of the current time (because if we're here, - # we're not running in a timer callback that may let other timers - # run; this is mostly an issue for libuv). - - # That's actually a bit of a lie: on libev, self._timer0 really is - # a timer, and so sometimes this is running in a timer callback, not - # a prepare callback. But that's OK, libev doesn't suffer from cascading - # timer expiration and its safe to update the loop time at any - # moment there. - self.starting_timer_may_update_loop_time = True - try: - count = self.CALLBACK_CHECK_COUNT - now = self.now() - expiration = now + getswitchinterval() - self._stop_callback_timer() - while self._callbacks: - cb = self._callbacks.popleft() # pylint:disable=assignment-from-no-return - count -= 1 - self.unref() # XXX: libuv doesn't have a global ref count! - callback = cb.callback - cb.callback = None - args = cb.args - if callback is None or args is None: - # it's been stopped - continue - - try: - callback(*args) - except: # pylint:disable=bare-except - # If we allow an exception to escape this method (while we are running the ev callback), - # then CFFI will print the error and libev will continue executing. - # There are two problems with this. The first is that the code after - # the loop won't run. The second is that any remaining callbacks scheduled - # for this loop iteration will be silently dropped; they won't run, but they'll - # also not be *stopped* (which is not a huge deal unless you're looking for - # consistency or checking the boolean/pending status; the loop doesn't keep - # a reference to them like it does to watchers...*UNLESS* the callback itself had - # a reference to a watcher; then I don't know what would happen, it depends on - # the state of the watcher---a leak or crash is not totally inconceivable). - # The Cython implementation in core.ppyx uses gevent_call from callbacks.c - # to run the callback, which uses gevent_handle_error to handle any errors the - # Python callback raises...it unconditionally simply prints any error raised - # by loop.handle_error and clears it, so callback handling continues. - # We take a similar approach (but are extra careful about printing) - try: - self.handle_error(cb, *sys.exc_info()) - except: # pylint:disable=bare-except - try: - print("Exception while handling another error", file=sys.stderr) - traceback.print_exc() - except: # pylint:disable=bare-except - pass # Nothing we can do here - finally: - # NOTE: this must be reset here, because cb.args is used as a flag in - # the callback class so that bool(cb) of a callback that has been run - # becomes False - cb.args = None - - # We've finished running one group of callbacks - # but we may have more, so before looping check our - # switch interval. - if count == 0 and self._callbacks: - count = self.CALLBACK_CHECK_COUNT - self.update_now() - if self.now() >= expiration: - now = 0 - break - - # Update the time before we start going again, if we didn't - # just do so. - if now != 0: - self.update_now() - - if self._callbacks: - self._start_callback_timer() - finally: - self.starting_timer_may_update_loop_time = False - - def _stop_aux_watchers(self): - if self._threadsafe_async is not None: - self._threadsafe_async.close() - self._threadsafe_async = None - - def destroy(self): - ptr = self.ptr - if ptr: - try: - if not self._can_destroy_loop(ptr): - return False - self._stop_aux_watchers() - self._destroy_loop(ptr) - finally: - # not ffi.NULL, we don't want something that can be - # passed to C and crash later. This will create nice friendly - # TypeError from CFFI. - self._ptr = None - del self._handle_to_self - del self._callbacks - del self._keepaliveset - - return True - - def _can_destroy_loop(self, ptr): - raise NotImplementedError() - - def _destroy_loop(self, ptr): - raise NotImplementedError() - - @property - def ptr(self): - # Use this when you need to be sure the pointer is valid. - return self._ptr - - @property - def WatcherType(self): - return self._watchers.watcher - - @property - def MAXPRI(self): - return 1 - - @property - def MINPRI(self): - return 1 - - def _handle_syserr(self, message, errno): - try: - errno = os.strerror(errno) - except: # pylint:disable=bare-except - traceback.print_exc() - try: - message = '%s: %s' % (message, errno) - except: # pylint:disable=bare-except - traceback.print_exc() - self.handle_error(None, SystemError, SystemError(message), None) - - def handle_error(self, context, type, value, tb): - if type is HubDestroyed: - self._callbacks.clear() - self.break_() - return - - handle_error = None - error_handler = self.error_handler - if error_handler is not None: - # we do want to do getattr every time so that setting Hub.handle_error property just works - handle_error = getattr(error_handler, 'handle_error', error_handler) - handle_error(context, type, value, tb) - else: - self._default_handle_error(context, type, value, tb) - - def _default_handle_error(self, context, type, value, tb): # pylint:disable=unused-argument - # note: Hub sets its own error handler so this is not used by gevent - # this is here to make core.loop usable without the rest of gevent - # Should cause the loop to stop running. - traceback.print_exception(type, value, tb) - - - def run(self, nowait=False, once=False): - raise NotImplementedError() - - def reinit(self): - raise NotImplementedError() - - def ref(self): - # XXX: libuv doesn't do it this way - raise NotImplementedError() - - def unref(self): - raise NotImplementedError() - - def break_(self, how=None): - raise NotImplementedError() - - def verify(self): - pass - - def now(self): - raise NotImplementedError() - - def update_now(self): - raise NotImplementedError() - - def update(self): - import warnings - warnings.warn("'update' is deprecated; use 'update_now'", - DeprecationWarning, - stacklevel=2) - self.update_now() - - def __repr__(self): - return '<%s.%s at 0x%x %s>' % ( - self.__class__.__module__, - self.__class__.__name__, - id(self), - self._format() - ) - - @property - def default(self): - return self._default if self.ptr else False - - @property - def iteration(self): - return -1 - - @property - def depth(self): - return -1 - - @property - def backend_int(self): - return 0 - - @property - def backend(self): - return "default" - - @property - def pendingcnt(self): - return 0 - - def io(self, fd, events, ref=True, priority=None): - return self._watchers.io(self, fd, events, ref, priority) - - def closing_fd(self, fd): # pylint:disable=unused-argument - return False - - def timer(self, after, repeat=0.0, ref=True, priority=None): - return self._watchers.timer(self, after, repeat, ref, priority) - - def signal(self, signum, ref=True, priority=None): - return self._watchers.signal(self, signum, ref, priority) - - def idle(self, ref=True, priority=None): - return self._watchers.idle(self, ref, priority) - - def prepare(self, ref=True, priority=None): - return self._watchers.prepare(self, ref, priority) - - def check(self, ref=True, priority=None): - return self._watchers.check(self, ref, priority) - - def fork(self, ref=True, priority=None): - return self._watchers.fork(self, ref, priority) - - def async_(self, ref=True, priority=None): - return self._watchers.async_(self, ref, priority) - - # Provide BWC for those that can use 'async' as is - locals()['async'] = async_ - - if sys.platform != "win32": - - def child(self, pid, trace=0, ref=True): - return self._watchers.child(self, pid, trace, ref) - - def install_sigchld(self): - pass - - def stat(self, path, interval=0.0, ref=True, priority=None): - return self._watchers.stat(self, path, interval, ref, priority) - - def callback(self, priority=None): - return callback(self, priority) - - def _setup_for_run_callback(self): - raise NotImplementedError() - - def run_callback(self, func, *args): - # If we happen to already be running callbacks (inside - # _run_callbacks), this could happen almost immediately, - # without the loop cycling. - cb = callback(func, args) - self._callbacks.append(cb) # Relying on the GIL for this to be threadsafe - self._setup_for_run_callback() # XXX: This may not be threadsafe. - return cb - - def run_callback_threadsafe(self, func, *args): - cb = self.run_callback(func, *args) - self._threadsafe_async.send() - return cb - - def _format(self): - ptr = self.ptr - if not ptr: - return 'destroyed' - msg = "backend=" + self.backend - msg += ' ptr=' + str(ptr) - if self.default: - msg += ' default' - msg += ' pending=%s' % self.pendingcnt - msg += self._format_details() - return msg - - def _format_details(self): - msg = '' - fileno = self.fileno() # pylint:disable=assignment-from-none - try: - activecnt = self.activecnt - except AttributeError: - activecnt = None - if activecnt is not None: - msg += ' ref=' + repr(activecnt) - if fileno is not None: - msg += ' fileno=' + repr(fileno) - #if sigfd is not None and sigfd != -1: - # msg += ' sigfd=' + repr(sigfd) - msg += ' callbacks=' + str(len(self._callbacks)) - return msg - - def fileno(self): - return None - - @property - def activecnt(self): - if not self.ptr: - raise ValueError('operation on destroyed loop') - return 0 diff --git a/venv/lib/python3.9/site-packages/gevent/_ffi/watcher.py b/venv/lib/python3.9/site-packages/gevent/_ffi/watcher.py deleted file mode 100644 index 4c372f3..0000000 --- a/venv/lib/python3.9/site-packages/gevent/_ffi/watcher.py +++ /dev/null @@ -1,649 +0,0 @@ -""" -Useful base classes for watchers. The available -watchers will depend on the specific event loop. -""" -# pylint:disable=not-callable -from __future__ import absolute_import, print_function - -import signal as signalmodule -import functools -import warnings - -from gevent._config import config -from gevent._util import LazyOnClass - -try: - from tracemalloc import get_object_traceback - - def tracemalloc(init): - # PYTHONTRACEMALLOC env var controls this on Python 3. - return init -except ImportError: # Python < 3.4 - - if config.trace_malloc: - # Use the same env var to turn this on for Python 2 - import traceback - - class _TB(object): - __slots__ = ('lines',) - - def __init__(self, lines): - # These end in newlines, which we don't want for consistency - self.lines = [x.rstrip() for x in lines] - - def format(self): - return self.lines - - def tracemalloc(init): - @functools.wraps(init) - def traces(self, *args, **kwargs): - init(self, *args, **kwargs) - self._captured_malloc = _TB(traceback.format_stack()) - return traces - - def get_object_traceback(obj): - return obj._captured_malloc - - else: - def get_object_traceback(_obj): - return None - - def tracemalloc(init): - return init - -from gevent._compat import fsencode - -from gevent._ffi import _dbg # pylint:disable=unused-import -from gevent._ffi import GEVENT_DEBUG_LEVEL -from gevent._ffi import DEBUG -from gevent._ffi.loop import GEVENT_CORE_EVENTS -from gevent._ffi.loop import _NOARGS - -ALLOW_WATCHER_DEL = GEVENT_DEBUG_LEVEL >= DEBUG - -__all__ = [ - -] - -try: - ResourceWarning # pylint:disable=used-before-assignment -except NameError: - class ResourceWarning(Warning): - "Python 2 fallback" - -class _NoWatcherResult(int): - - def __repr__(self): - return "" - -_NoWatcherResult = _NoWatcherResult(0) - -def events_to_str(event_field, all_events): - result = [] - for (flag, string) in all_events: - c_flag = flag - if event_field & c_flag: - result.append(string) - event_field &= (~c_flag) - if not event_field: - break - if event_field: - result.append(hex(event_field)) - return '|'.join(result) - - -def not_while_active(func): - @functools.wraps(func) - def nw(self, *args, **kwargs): - if self.active: - raise ValueError("not while active") - func(self, *args, **kwargs) - return nw - -def only_if_watcher(func): - @functools.wraps(func) - def if_w(self): - if self._watcher: - return func(self) - return _NoWatcherResult - return if_w - - -class AbstractWatcherType(type): - """ - Base metaclass for watchers. - - To use, you will: - - - subclass the watcher class defined from this type. - - optionally subclass this type - """ - # pylint:disable=bad-mcs-classmethod-argument - - _FFI = None - _LIB = None - - def __new__(cls, name, bases, cls_dict): - if name != 'watcher' and not cls_dict.get('_watcher_skip_ffi'): - cls._fill_watcher(name, bases, cls_dict) - if '__del__' in cls_dict and not ALLOW_WATCHER_DEL: # pragma: no cover - raise TypeError("CFFI watchers are not allowed to have __del__") - return type.__new__(cls, name, bases, cls_dict) - - @classmethod - def _fill_watcher(cls, name, bases, cls_dict): - # TODO: refactor smaller - # pylint:disable=too-many-locals - if name.endswith('_'): - # Strip trailing _ added to avoid keyword duplications - # e.g., async_ - name = name[:-1] - - def _mro_get(attr, bases, error=True): - for b in bases: - try: - return getattr(b, attr) - except AttributeError: - continue - if error: # pragma: no cover - raise AttributeError(attr) - _watcher_prefix = cls_dict.get('_watcher_prefix') or _mro_get('_watcher_prefix', bases) - - if '_watcher_type' not in cls_dict: - watcher_type = _watcher_prefix + '_' + name - cls_dict['_watcher_type'] = watcher_type - elif not cls_dict['_watcher_type'].startswith(_watcher_prefix): - watcher_type = _watcher_prefix + '_' + cls_dict['_watcher_type'] - cls_dict['_watcher_type'] = watcher_type - - active_name = _watcher_prefix + '_is_active' - - def _watcher_is_active(self): - return getattr(self._LIB, active_name) - - LazyOnClass.lazy(cls_dict, _watcher_is_active) - - watcher_struct_name = cls_dict.get('_watcher_struct_name') - if not watcher_struct_name: - watcher_struct_pattern = (cls_dict.get('_watcher_struct_pattern') - or _mro_get('_watcher_struct_pattern', bases, False) - or 'struct %s') - watcher_struct_name = watcher_struct_pattern % (watcher_type,) - - def _watcher_struct_pointer_type(self): - return self._FFI.typeof(watcher_struct_name + ' *') - - LazyOnClass.lazy(cls_dict, _watcher_struct_pointer_type) - - callback_name = (cls_dict.get('_watcher_callback_name') - or _mro_get('_watcher_callback_name', bases, False) - or '_gevent_generic_callback') - - def _watcher_callback(self): - return self._FFI.addressof(self._LIB, callback_name) - - LazyOnClass.lazy(cls_dict, _watcher_callback) - - def _make_meth(name, watcher_name): - def meth(self): - lib_name = self._watcher_type + '_' + name - return getattr(self._LIB, lib_name) - meth.__name__ = watcher_name - return meth - - for meth_name in 'start', 'stop', 'init': - watcher_name = '_watcher' + '_' + meth_name - if watcher_name not in cls_dict: - LazyOnClass.lazy(cls_dict, _make_meth(meth_name, watcher_name)) - - def new_handle(cls, obj): - return cls._FFI.new_handle(obj) - - def new(cls, kind): - return cls._FFI.new(kind) - -class watcher(metaclass=AbstractWatcherType): - - _callback = None - _args = None - _watcher = None - # self._handle has a reference to self, keeping it alive. - # We must keep self._handle alive for ffi.from_handle() to be - # able to work. We only fill this in when we are started, - # and when we are stopped we destroy it. - # NOTE: This is a GC cycle, so we keep it around for as short - # as possible. - _handle = None - - @tracemalloc - def __init__(self, _loop, ref=True, priority=None, args=_NOARGS): - self.loop = _loop - self.__init_priority = priority - self.__init_args = args - self.__init_ref = ref - self._watcher_full_init() - - - def _watcher_full_init(self): - priority = self.__init_priority - ref = self.__init_ref - args = self.__init_args - - self._watcher_create(ref) - - if priority is not None: - self._watcher_ffi_set_priority(priority) - - try: - self._watcher_ffi_init(args) - except: - # Let these be GC'd immediately. - # If we keep them around to when *we* are gc'd, - # they're probably invalid, meaning any native calls - # we do then to close() them are likely to fail - self._watcher = None - raise - self._watcher_ffi_set_init_ref(ref) - - @classmethod - def _watcher_ffi_close(cls, ffi_watcher): - pass - - def _watcher_create(self, ref): # pylint:disable=unused-argument - self._watcher = self._watcher_new() - - def _watcher_new(self): - return type(self).new(self._watcher_struct_pointer_type) # pylint:disable=no-member - - def _watcher_ffi_set_init_ref(self, ref): - pass - - def _watcher_ffi_set_priority(self, priority): - pass - - def _watcher_ffi_init(self, args): - raise NotImplementedError() - - def _watcher_ffi_start(self): - raise NotImplementedError() - - def _watcher_ffi_stop(self): - self._watcher_stop(self.loop.ptr, self._watcher) - - def _watcher_ffi_ref(self): - raise NotImplementedError() - - def _watcher_ffi_unref(self): - raise NotImplementedError() - - def _watcher_ffi_start_unref(self): - # While a watcher is active, we don't keep it - # referenced. This allows a timer, for example, to be started, - # and still allow the loop to end if there is nothing - # else to do. see test__order.TestSleep0 for one example. - self._watcher_ffi_unref() - - def _watcher_ffi_stop_ref(self): - self._watcher_ffi_ref() - - # A string identifying the type of libev object we watch, e.g., 'ev_io' - # This should be a class attribute. - _watcher_type = None - # A class attribute that is the callback on the libev object that init's the C struct, - # e.g., libev.ev_io_init. If None, will be set by _init_subclasses. - _watcher_init = None - # A class attribute that is the callback on the libev object that starts the C watcher, - # e.g., libev.ev_io_start. If None, will be set by _init_subclasses. - _watcher_start = None - # A class attribute that is the callback on the libev object that stops the C watcher, - # e.g., libev.ev_io_stop. If None, will be set by _init_subclasses. - _watcher_stop = None - # A cffi ctype object identifying the struct pointer we create. - # This is a class attribute set based on the _watcher_type - _watcher_struct_pointer_type = None - # The attribute of the libev object identifying the custom - # callback function for this type of watcher. This is a class - # attribute set based on the _watcher_type in _init_subclasses. - _watcher_callback = None - _watcher_is_active = None - - def close(self): - if self._watcher is None: - return - - self.stop() - _watcher = self._watcher - self._watcher = None - self._watcher_set_data(_watcher, self._FFI.NULL) # pylint: disable=no-member - self._watcher_ffi_close(_watcher) - self.loop = None - - def _watcher_set_data(self, the_watcher, data): - # This abstraction exists for the sole benefit of - # libuv.watcher.stat, which "subclasses" uv_handle_t. - # Can we do something to avoid this extra function call? - the_watcher.data = data - return data - - def __enter__(self): - return self - - def __exit__(self, t, v, tb): - self.close() - - if ALLOW_WATCHER_DEL: - def __del__(self): - if self._watcher: - tb = get_object_traceback(self) - tb_msg = '' - if tb is not None: - tb_msg = '\n'.join(tb.format()) - tb_msg = '\nTraceback:\n' + tb_msg - warnings.warn("Failed to close watcher %r%s" % (self, tb_msg), - ResourceWarning) - - # may fail if __init__ did; will be harmlessly printed - self.close() - - __in_repr = False - - def __repr__(self): - basic = "<%s at 0x%x" % (self.__class__.__name__, id(self)) - if self.__in_repr: - return basic + '>' - # Running child watchers have been seen to have a - # recursive repr in ``self.args``, thanks to ``gevent.os.fork_and_watch`` - # passing the watcher as an argument to its callback. - self.__in_repr = True - try: - result = '%s%s' % (basic, self._format()) - if self.pending: - result += " pending" - if self.callback is not None: - fself = getattr(self.callback, '__self__', None) - if fself is self: - result += " callback=" % (self.callback.__name__) - else: - result += " callback=%r" % (self.callback, ) - if self.args is not None: - result += " args=%r" % (self.args, ) - if self.callback is None and self.args is None: - result += " stopped" - result += " watcher=%s" % (self._watcher) - result += " handle=%s" % (self._watcher_handle) - result += " ref=%s" % (self.ref) - return result + ">" - finally: - self.__in_repr = False - - @property - def _watcher_handle(self): - if self._watcher: - return self._watcher.data - - def _format(self): - return '' - - @property - def ref(self): - raise NotImplementedError() - - def _get_callback(self): - return self._callback if '_callback' in self.__dict__ else None - - def _set_callback(self, cb): - if not callable(cb) and cb is not None: - raise TypeError("Expected callable, not %r" % (cb, )) - if cb is None: - if '_callback' in self.__dict__: - del self._callback - else: - self._callback = cb - callback = property(_get_callback, _set_callback) - - def _get_args(self): - return self._args - - def _set_args(self, args): - if not isinstance(args, tuple) and args is not None: - raise TypeError("args must be a tuple or None") - if args is None: - if '_args' in self.__dict__: - del self._args - else: - self._args = args - - args = property(_get_args, _set_args) - - def start(self, callback, *args): - if callback is None: - raise TypeError('callback must be callable, not None') - self.callback = callback - self.args = args or _NOARGS - self.loop._keepaliveset.add(self) - self._handle = self._watcher_set_data(self._watcher, type(self).new_handle(self)) # pylint:disable=no-member - self._watcher_ffi_start() - self._watcher_ffi_start_unref() - - def stop(self): - if self.callback is None: - assert self.loop is None or self not in self.loop._keepaliveset - return - self.callback = None - # Only after setting the signal to make this idempotent do - # we move ahead. - self._watcher_ffi_stop_ref() - self._watcher_ffi_stop() - self.loop._keepaliveset.discard(self) - self._handle = None - self._watcher_set_data(self._watcher, self._FFI.NULL) # pylint:disable=no-member - - self.args = None - - def _get_priority(self): - return None - - @not_while_active - def _set_priority(self, priority): - pass - - priority = property(_get_priority, _set_priority) - - - @property - def active(self): - if self._watcher is not None and self._watcher_is_active(self._watcher): - return True - return False - - @property - def pending(self): - return False - - - -class IoMixin(object): - - EVENT_MASK = 0 - - def __init__(self, loop, fd, events, ref=True, priority=None, _args=None): - # Win32 only works with sockets, and only when we use libuv, because - # we don't use _open_osfhandle. See libuv/watchers.py:io for a description. - self._validate_fd(fd) - - if events & ~self.EVENT_MASK: - raise ValueError('illegal event mask: %r' % events) - self._fd = fd - super(IoMixin, self).__init__(loop, ref=ref, priority=priority, - args=_args or (fd, events)) - - @classmethod - def _validate_fd(cls, fd): - if fd < 0: - raise ValueError('fd must be non-negative: %r' % fd) - - def start(self, callback, *args, **kwargs): - args = args or _NOARGS - if kwargs.get('pass_events'): - args = (GEVENT_CORE_EVENTS, ) + args - super(IoMixin, self).start(callback, *args) - - def _format(self): - return ' fd=%d' % self._fd - -class TimerMixin(object): - _watcher_type = 'timer' - - def __init__(self, loop, after=0.0, repeat=0.0, ref=True, priority=None): - if repeat < 0.0: - raise ValueError("repeat must be positive or zero: %r" % repeat) - self._after = after - self._repeat = repeat - super(TimerMixin, self).__init__(loop, ref=ref, priority=priority, args=(after, repeat)) - - def start(self, callback, *args, **kw): - update = kw.get("update", self.loop.starting_timer_may_update_loop_time) - if update: - # Quoth the libev doc: "This is a costly operation and is - # usually done automatically within ev_run(). This - # function is rarely useful, but when some event callback - # runs for a very long time without entering the event - # loop, updating libev's idea of the current time is a - # good idea." - - # 1.3 changed the default for this to False *unless* the loop is - # running a callback; see libuv for details. Note that - # starting Timeout objects still sets this to true. - - self.loop.update_now() - super(TimerMixin, self).start(callback, *args) - - def again(self, callback, *args, **kw): - raise NotImplementedError() - - -class SignalMixin(object): - _watcher_type = 'signal' - - def __init__(self, loop, signalnum, ref=True, priority=None): - if signalnum < 1 or signalnum >= signalmodule.NSIG: - raise ValueError('illegal signal number: %r' % signalnum) - # still possible to crash on one of libev's asserts: - # 1) "libev: ev_signal_start called with illegal signal number" - # EV_NSIG might be different from signal.NSIG on some platforms - # 2) "libev: a signal must not be attached to two different loops" - # we probably could check that in LIBEV_EMBED mode, but not in general - self._signalnum = signalnum - super(SignalMixin, self).__init__(loop, ref=ref, priority=priority, args=(signalnum, )) - - -class IdleMixin(object): - _watcher_type = 'idle' - - -class PrepareMixin(object): - _watcher_type = 'prepare' - - -class CheckMixin(object): - _watcher_type = 'check' - - -class ForkMixin(object): - _watcher_type = 'fork' - - -class AsyncMixin(object): - _watcher_type = 'async' - - def send(self): - raise NotImplementedError() - - def send_ignoring_arg(self, _ignored): - """ - Calling compatibility with ``greenlet.switch(arg)`` - as used by waiters that have ``rawlink``. - - This is an advanced method, not usually needed. - """ - return self.send() - - @property - def pending(self): - raise NotImplementedError() - - -class ChildMixin(object): - - # hack for libuv which doesn't extend watcher - _CALL_SUPER_INIT = True - - def __init__(self, loop, pid, trace=0, ref=True): - if not loop.default: - raise TypeError('child watchers are only available on the default loop') - loop.install_sigchld() - self._pid = pid - if self._CALL_SUPER_INIT: - super(ChildMixin, self).__init__(loop, ref=ref, args=(pid, trace)) - - def _format(self): - return ' pid=%r rstatus=%r' % (self.pid, self.rstatus) - - @property - def pid(self): - return self._pid - - @property - def rpid(self): - # The received pid, the result of the waitpid() call. - return self._rpid - - _rpid = None - _rstatus = 0 - - @property - def rstatus(self): - return self._rstatus - -class StatMixin(object): - - @staticmethod - def _encode_path(path): - return fsencode(path) - - def __init__(self, _loop, path, interval=0.0, ref=True, priority=None): - # Store the encoded path in the same attribute that corecext does - self._paths = self._encode_path(path) - - # Keep the original path to avoid re-encoding, especially on Python 3 - self._path = path - - # Although CFFI would automatically convert a bytes object into a char* when - # calling ev_stat_init(..., char*, ...), on PyPy the char* pointer is not - # guaranteed to live past the function call. On CPython, only with a constant/interned - # bytes object is the pointer guaranteed to last path the function call. (And since - # Python 3 is pretty much guaranteed to produce a newly-encoded bytes object above, thats - # rarely the case). Therefore, we must keep a reference to the produced cdata object - # so that the struct ev_stat_watcher's `path` pointer doesn't become invalid/deallocated - self._cpath = self._FFI.new('char[]', self._paths) - - self._interval = interval - super(StatMixin, self).__init__(_loop, ref=ref, priority=priority, - args=(self._cpath, - interval)) - - @property - def path(self): - return self._path - - @property - def attr(self): - raise NotImplementedError - - @property - def prev(self): - raise NotImplementedError - - @property - def interval(self): - return self._interval diff --git a/venv/lib/python3.9/site-packages/gevent/_fileobjectcommon.py b/venv/lib/python3.9/site-packages/gevent/_fileobjectcommon.py deleted file mode 100644 index 0aa2d65..0000000 --- a/venv/lib/python3.9/site-packages/gevent/_fileobjectcommon.py +++ /dev/null @@ -1,697 +0,0 @@ -""" -gevent internals. -""" -from __future__ import absolute_import, print_function, division - -try: - from errno import EBADF -except ImportError: - EBADF = 9 - -import io -import functools -import sys -import os - -from gevent.hub import _get_hub_noargs as get_hub -from gevent._compat import integer_types -from gevent._compat import reraise -from gevent._compat import fspath -from gevent.lock import Semaphore, DummySemaphore - -class cancel_wait_ex(IOError): - - def __init__(self): - IOError.__init__( - self, - EBADF, 'File descriptor was closed in another greenlet') - -class FileObjectClosed(IOError): - - def __init__(self): - IOError.__init__( - self, - EBADF, 'Bad file descriptor (FileObject was closed)') - -class UniversalNewlineBytesWrapper(io.TextIOWrapper): - """ - Uses TextWrapper to decode universal newlines, but returns the - results as bytes. - - This is for Python 2 where the 'rU' mode did that. - """ - mode = None - def __init__(self, fobj, line_buffering): - # latin-1 has the ability to round-trip arbitrary bytes. - io.TextIOWrapper.__init__(self, fobj, encoding='latin-1', - newline=None, - line_buffering=line_buffering) - - def read(self, *args, **kwargs): - result = io.TextIOWrapper.read(self, *args, **kwargs) - return result.encode('latin-1') - - def readline(self, limit=-1): - result = io.TextIOWrapper.readline(self, limit) - return result.encode('latin-1') - - def __iter__(self): - # readlines() is implemented in terms of __iter__ - # and TextIOWrapper.__iter__ checks that readline returns - # a unicode object, which we don't, so we override - return self - - def __next__(self): - line = self.readline() - if not line: - raise StopIteration - return line - - next = __next__ - - -class FlushingBufferedWriter(io.BufferedWriter): - - def write(self, b): - ret = io.BufferedWriter.write(self, b) - self.flush() - return ret - - -class WriteallMixin(object): - - def writeall(self, value): - """ - Similar to :meth:`socket.socket.sendall`, ensures that all the contents of - *value* have been written (though not necessarily flushed) before returning. - - Returns the length of *value*. - - .. versionadded:: 20.12.0 - """ - # Do we need to play the same get_memory games we do with sockets? - # And what about chunking for large values? See _socketcommon.py - write = super(WriteallMixin, self).write - - total = len(value) - while value: - l = len(value) - w = write(value) - if w == l: - break - value = value[w:] - return total - - -class FileIO(io.FileIO): - """A subclass that we can dynamically assign __class__ for.""" - __slots__ = () - - -class WriteIsWriteallMixin(WriteallMixin): - - def write(self, value): - return self.writeall(value) - - -class WriteallFileIO(WriteIsWriteallMixin, io.FileIO): - pass - - -class OpenDescriptor(object): # pylint:disable=too-many-instance-attributes - """ - Interprets the arguments to `open`. Internal use only. - - Originally based on code in the stdlib's _pyio.py (Python implementation of - the :mod:`io` module), but modified for gevent: - - - Native strings are returned on Python 2 when neither - 'b' nor 't' are in the mode string and no encoding is specified. - - Universal newlines work in that mode. - - Allows externally unbuffered text IO. - - :keyword bool atomic_write: If true, then if the opened, wrapped, stream - is unbuffered (meaning that ``write`` can produce short writes and the return - value needs to be checked), then the implementation will be adjusted so that - ``write`` behaves like Python 2 on a built-in file object and writes the - entire value. Only set this on Python 2; the only intended user is - :class:`gevent.subprocess.Popen`. - """ - - @staticmethod - def _collapse_arg(pref_name, preferred_val, old_name, old_val, default): - # We could play tricks with the callers ``locals()`` to avoid having to specify - # the name (which we only use for error handling) but ``locals()`` may be slow and - # inhibit JIT (on PyPy), so we just write it out long hand. - if preferred_val is not None and old_val is not None: - raise TypeError("Cannot specify both %s=%s and %s=%s" % ( - pref_name, preferred_val, - old_name, old_val - )) - if preferred_val is None and old_val is None: - return default - return preferred_val if preferred_val is not None else old_val - - def __init__(self, fobj, mode='r', bufsize=None, close=None, - encoding=None, errors=None, newline=None, - buffering=None, closefd=None, - atomic_write=False): - # Based on code in the stdlib's _pyio.py from 3.8. - # pylint:disable=too-many-locals,too-many-branches,too-many-statements - - closefd = self._collapse_arg('closefd', closefd, 'close', close, True) - del close - buffering = self._collapse_arg('buffering', buffering, 'bufsize', bufsize, -1) - del bufsize - - if not hasattr(fobj, 'fileno'): - if not isinstance(fobj, integer_types): - # Not a fd. Support PathLike on Python 2 and Python <= 3.5. - fobj = fspath(fobj) - if not isinstance(fobj, (str, bytes) + integer_types): # pragma: no cover - raise TypeError("invalid file: %r" % fobj) - if isinstance(fobj, (str, bytes)): - closefd = True - - if not isinstance(mode, str): - raise TypeError("invalid mode: %r" % mode) - if not isinstance(buffering, integer_types): - raise TypeError("invalid buffering: %r" % buffering) - if encoding is not None and not isinstance(encoding, str): - raise TypeError("invalid encoding: %r" % encoding) - if errors is not None and not isinstance(errors, str): - raise TypeError("invalid errors: %r" % errors) - - modes = set(mode) - if modes - set("axrwb+tU") or len(mode) > len(modes): - raise ValueError("invalid mode: %r" % mode) - - creating = "x" in modes - reading = "r" in modes - writing = "w" in modes - appending = "a" in modes - updating = "+" in modes - text = "t" in modes - binary = "b" in modes - universal = 'U' in modes - - can_write = creating or writing or appending or updating - - if universal: - if can_write: - raise ValueError("mode U cannot be combined with 'x', 'w', 'a', or '+'") - # Just because the stdlib deprecates this, no need for us to do so as well. - # Especially not while we still support Python 2. - # import warnings - # warnings.warn("'U' mode is deprecated", - # DeprecationWarning, 4) - reading = True - if text and binary: - raise ValueError("can't have text and binary mode at once") - if creating + reading + writing + appending > 1: - raise ValueError("can't have read/write/append mode at once") - if not (creating or reading or writing or appending): - raise ValueError("must have exactly one of read/write/append mode") - if binary and encoding is not None: - raise ValueError("binary mode doesn't take an encoding argument") - if binary and errors is not None: - raise ValueError("binary mode doesn't take an errors argument") - if binary and newline is not None: - raise ValueError("binary mode doesn't take a newline argument") - if binary and buffering == 1: - import warnings - warnings.warn("line buffering (buffering=1) isn't supported in binary " - "mode, the default buffer size will be used", - RuntimeWarning, 4) - - self._fobj = fobj - self.fileio_mode = ( - (creating and "x" or "") - + (reading and "r" or "") - + (writing and "w" or "") - + (appending and "a" or "") - + (updating and "+" or "") - ) - self.mode = self.fileio_mode + ('t' if text else '') + ('b' if binary else '') - - self.creating = creating - self.reading = reading - self.writing = writing - self.appending = appending - self.updating = updating - self.text = text - self.binary = binary - self.can_write = can_write - self.can_read = reading or updating - self.native = ( - not self.text and not self.binary # Neither t nor b given. - and not encoding and not errors # And no encoding or error handling either. - ) - self.universal = universal - - self.buffering = buffering - self.encoding = encoding - self.errors = errors - self.newline = newline - self.closefd = closefd - self.atomic_write = atomic_write - - default_buffer_size = io.DEFAULT_BUFFER_SIZE - - _opened = None - _opened_raw = None - - def is_fd(self): - return isinstance(self._fobj, integer_types) - - def opened(self): - """ - Return the :meth:`wrapped` file object. - """ - if self._opened is None: - raw = self.opened_raw() - try: - self._opened = self.__wrapped(raw) - except: - # XXX: This might be a bug? Could we wind up closing - # something we shouldn't close? - raw.close() - raise - return self._opened - - def _raw_object_is_new(self, raw): - return self._fobj is not raw - - def opened_raw(self): - if self._opened_raw is None: - self._opened_raw = self._do_open_raw() - return self._opened_raw - - def _do_open_raw(self): - if hasattr(self._fobj, 'fileno'): - return self._fobj - # io.FileIO doesn't allow assigning to its __class__, - # and we can't know for sure here whether we need the atomic write() - # method or not (it depends on the layers on top of us), - # so we use a subclass that *does* allow assigning. - return FileIO(self._fobj, self.fileio_mode, self.closefd) - - @staticmethod - def is_buffered(stream): - return ( - # buffering happens internally in the text codecs - isinstance(stream, (io.BufferedIOBase, io.TextIOBase)) - or (hasattr(stream, 'buffer') and stream.buffer is not None) - ) - - @classmethod - def buffer_size_for_stream(cls, stream): - result = cls.default_buffer_size - try: - bs = os.fstat(stream.fileno()).st_blksize - except (OSError, AttributeError): - pass - else: - if bs > 1: - result = bs - return result - - def __buffered(self, stream, buffering): - if self.updating: - Buffer = io.BufferedRandom - elif self.creating or self.writing or self.appending: - Buffer = io.BufferedWriter - elif self.reading: - Buffer = io.BufferedReader - else: # prgama: no cover - raise ValueError("unknown mode: %r" % self.mode) - - try: - result = Buffer(stream, buffering) - except AttributeError: - # Python 2 file() objects don't have the readable/writable - # attributes. But they handle their own buffering. - result = stream - - return result - - def _make_atomic_write(self, result, raw): - # The idea was to swizzle the class with one that defines - # write() to call writeall(). This avoids setting any - # attribute on the return object, avoids an additional layer - # of proxying, and avoids any reference cycles (if setting a - # method on the object). - # - # However, this is not possible with the built-in io classes - # (static types defined in C cannot have __class__ assigned). - # Fortunately, we need this only for the specific case of - # opening a file descriptor (subprocess.py) on Python 2, in - # which we fully control the types involved. - # - # So rather than attempt that, we only implement exactly what we need. - if result is not raw or self._raw_object_is_new(raw): - if result.__class__ is FileIO: - result.__class__ = WriteallFileIO - else: # pragma: no cover - raise NotImplementedError( - "Don't know how to make %s have atomic write. " - "Please open a gevent issue with your use-case." % ( - result - ) - ) - return result - - def __wrapped(self, raw): - """ - Wraps the raw IO object (`RawIOBase` or `io.TextIOBase`) in - buffers, text decoding, and newline handling. - """ - if self.binary and isinstance(raw, io.TextIOBase): - # Can't do it. The TextIO object will have its own buffer, and - # trying to read from the raw stream or the buffer without going through - # the TextIO object is likely to lead to problems with the codec. - raise ValueError("Unable to perform binary IO on top of text IO stream") - - result = raw - buffering = self.buffering - - line_buffering = False - if buffering == 1 or buffering < 0 and raw.isatty(): - buffering = -1 - line_buffering = True - if buffering < 0: - buffering = self.buffer_size_for_stream(result) - - if buffering < 0: # pragma: no cover - raise ValueError("invalid buffering size") - - if buffering != 0 and not self.is_buffered(result): - # Need to wrap our own buffering around it. If it - # is already buffered, don't do so. - result = self.__buffered(result, buffering) - - if not self.binary: - # Either native or text at this point. - # Python 2 and text mode, or Python 3 and either text or native (both are the same) - if not isinstance(raw, io.TextIOBase): - # Avoid double-wrapping a TextIOBase in another TextIOWrapper. - # That tends not to work. See https://github.com/gevent/gevent/issues/1542 - result = io.TextIOWrapper(result, self.encoding, self.errors, self.newline, - line_buffering) - - if result is not raw or self._raw_object_is_new(raw): - # Set the mode, if possible, but only if we created a new - # object. - try: - result.mode = self.mode - except (AttributeError, TypeError): - # AttributeError: No such attribute - # TypeError: Readonly attribute (py2) - pass - - if ( - self.atomic_write - and not self.is_buffered(result) - and not isinstance(result, WriteIsWriteallMixin) - ): - # Let subclasses have a say in how they make this atomic, and - # whether or not they do so even if we're actually returning the raw object. - result = self._make_atomic_write(result, raw) - - return result - - -class _ClosedIO(object): - # Used for FileObjectBase._io when FOB.close() - # is called. Lets us drop references to ``_io`` - # for GC/resource cleanup reasons, but keeps some useful - # information around. - __slots__ = ('name',) - - def __init__(self, io_obj): - try: - self.name = io_obj.name - except AttributeError: - pass - - def __getattr__(self, name): - if name == 'name': - # We didn't set it in __init__ because there wasn't one - raise AttributeError - raise FileObjectClosed - - def __bool__(self): - return False - __nonzero__ = __bool__ - - -class FileObjectBase(object): - """ - Internal base class to ensure a level of consistency - between :class:`~.FileObjectPosix`, :class:`~.FileObjectThread` - and :class:`~.FileObjectBlock`. - """ - - # List of methods we delegate to the wrapping IO object, if they - # implement them and we do not. - _delegate_methods = ( - # General methods - 'flush', - 'fileno', - 'writable', - 'readable', - 'seek', - 'seekable', - 'tell', - - # Read - 'read', - 'readline', - 'readlines', - 'read1', - 'readinto', - - # Write. - # Note that we do not extend WriteallMixin, - # so writeall will be copied, if it exists, and - # wrapped. - 'write', - 'writeall', - 'writelines', - 'truncate', - ) - - - _io = None - - def __init__(self, descriptor): - # type: (OpenDescriptor) -> None - self._io = descriptor.opened() - # We don't actually use this property ourself, but we save it (and - # pass it along) for compatibility. - self._close = descriptor.closefd - self._do_delegate_methods() - - - io = property(lambda s: s._io, - # Historically we either hand-wrote all the delegation methods - # to use self.io, or we simply used __getattr__ to look them up at - # runtime. This meant people could change the io attribute on the fly - # and it would mostly work (subprocess.py used to do that). We don't recommend - # that, but we still support it. - lambda s, nv: setattr(s, '_io', nv) or s._do_delegate_methods()) - - def _do_delegate_methods(self): - for meth_name in self._delegate_methods: - meth = getattr(self._io, meth_name, None) - implemented_by_class = hasattr(type(self), meth_name) - if meth and not implemented_by_class: - setattr(self, meth_name, self._wrap_method(meth)) - elif hasattr(self, meth_name) and not implemented_by_class: - delattr(self, meth_name) - - def _wrap_method(self, method): - """ - Wrap a method we're copying into our dictionary from the underlying - io object to do something special or different, if necessary. - """ - return method - - @property - def closed(self): - """True if the file is closed""" - return isinstance(self._io, _ClosedIO) - - def close(self): - if isinstance(self._io, _ClosedIO): - return - - fobj = self._io - self._io = _ClosedIO(self._io) - try: - self._do_close(fobj, self._close) - finally: - fobj = None - # Remove delegate methods to drop remaining references to - # _io. - d = self.__dict__ - for meth_name in self._delegate_methods: - d.pop(meth_name, None) - - def _do_close(self, fobj, closefd): - raise NotImplementedError() - - def __getattr__(self, name): - return getattr(self._io, name) - - def __repr__(self): - return '<%s at 0x%x %s_fobj=%r%s>' % ( - self.__class__.__name__, - id(self), - 'closed' if self.closed else '', - self.io, - self._extra_repr() - ) - - def _extra_repr(self): - return '' - - def __enter__(self): - return self - - def __exit__(self, *args): - self.close() - - def __iter__(self): - return self - - def __next__(self): - line = self.readline() - if not line: - raise StopIteration - return line - - next = __next__ - - def __bool__(self): - return True - - __nonzero__ = __bool__ - - -class FileObjectBlock(FileObjectBase): - """ - FileObjectBlock() - - A simple synchronous wrapper around a file object. - - Adds no concurrency or gevent compatibility. - """ - - def __init__(self, fobj, *args, **kwargs): - descriptor = OpenDescriptor(fobj, *args, **kwargs) - FileObjectBase.__init__(self, descriptor) - - def _do_close(self, fobj, closefd): - fobj.close() - - -class FileObjectThread(FileObjectBase): - """ - FileObjectThread() - - A file-like object wrapping another file-like object, performing all blocking - operations on that object in a background thread. - - .. caution:: - Attempting to change the threadpool or lock of an existing FileObjectThread - has undefined consequences. - - .. versionchanged:: 1.1b1 - The file object is closed using the threadpool. Note that whether or - not this action is synchronous or asynchronous is not documented. - """ - - def __init__(self, *args, **kwargs): - """ - :keyword bool lock: If True (the default) then all operations will - be performed one-by-one. Note that this does not guarantee that, if using - this file object from multiple threads/greenlets, operations will be performed - in any particular order, only that no two operations will be attempted at the - same time. You can also pass your own :class:`gevent.lock.Semaphore` to synchronize - file operations with an external resource. - :keyword bool closefd: If True (the default) then when this object is closed, - the underlying object is closed as well. If *fobj* is a path, then - *closefd* must be True. - """ - lock = kwargs.pop('lock', True) - threadpool = kwargs.pop('threadpool', None) - descriptor = OpenDescriptor(*args, **kwargs) - - self.threadpool = threadpool or get_hub().threadpool - self.lock = lock - if self.lock is True: - self.lock = Semaphore() - elif not self.lock: - self.lock = DummySemaphore() - if not hasattr(self.lock, '__enter__'): - raise TypeError('Expected a Semaphore or boolean, got %r' % type(self.lock)) - - self.__io_holder = [descriptor.opened()] # signal for _wrap_method - FileObjectBase.__init__(self, descriptor) - - def _do_close(self, fobj, closefd): - self.__io_holder[0] = None # for _wrap_method - try: - with self.lock: - self.threadpool.apply(fobj.flush) - finally: - if closefd: - # Note that we're not taking the lock; older code - # did fobj.close() without going through the threadpool at all, - # so acquiring the lock could potentially introduce deadlocks - # that weren't present before. Avoiding the lock doesn't make - # the existing race condition any worse. - # We wrap the close in an exception handler and re-raise directly - # to avoid the (common, expected) IOError from being logged by the pool - def close(_fobj=fobj): - try: - _fobj.close() - except: # pylint:disable=bare-except - # pylint:disable-next=return-in-finally - return sys.exc_info() - finally: - _fobj = None - del fobj - - exc_info = self.threadpool.apply(close) - del close - - if exc_info: - reraise(*exc_info) - - def _do_delegate_methods(self): - FileObjectBase._do_delegate_methods(self) - self.__io_holder[0] = self._io - - def _extra_repr(self): - return ' threadpool=%r' % (self.threadpool,) - - def _wrap_method(self, method): - # NOTE: We are careful to avoid introducing a refcycle - # within self. Our wrapper cannot refer to self. - io_holder = self.__io_holder - lock = self.lock - threadpool = self.threadpool - - @functools.wraps(method) - def thread_method(*args, **kwargs): - if io_holder[0] is None: - # This is different than FileObjectPosix, etc, - # because we want to save the expensive trip through - # the threadpool. - raise FileObjectClosed - with lock: - return threadpool.apply(method, args, kwargs) - - return thread_method diff --git a/venv/lib/python3.9/site-packages/gevent/_fileobjectposix.py b/venv/lib/python3.9/site-packages/gevent/_fileobjectposix.py deleted file mode 100644 index 2087a6f..0000000 --- a/venv/lib/python3.9/site-packages/gevent/_fileobjectposix.py +++ /dev/null @@ -1,344 +0,0 @@ -from __future__ import absolute_import -from __future__ import print_function -import os -import sys - - -from io import BytesIO -from io import DEFAULT_BUFFER_SIZE -from io import FileIO -from io import RawIOBase -from io import UnsupportedOperation - -from gevent._compat import reraise -from gevent._fileobjectcommon import cancel_wait_ex -from gevent._fileobjectcommon import FileObjectBase -from gevent._fileobjectcommon import OpenDescriptor -from gevent._fileobjectcommon import WriteIsWriteallMixin -from gevent._hub_primitives import wait_on_watcher -from gevent.hub import get_hub -from gevent.os import _read -from gevent.os import _write -from gevent.os import _close -from gevent.os import ignored_errors -from gevent.os import make_nonblocking - - -class GreenFileDescriptorIO(RawIOBase): - # Internal, undocumented, class. All that's documented is that this - # is a IOBase object. Constructor is private. - - # Note that RawIOBase has a __del__ method that calls - # self.close(). (In C implementations like CPython, this is - # the type's tp_dealloc slot; prior to Python 3, the object doesn't - # appear to have a __del__ method, even though it functionally does) - - _read_watcher = None - _write_watcher = None - _closed = False - _seekable = None - _keep_alive = None # An object that needs to live as long as we do. - - def __init__(self, fileno, open_descriptor, closefd=True): - RawIOBase.__init__(self) - - self._closefd = closefd - self._fileno = fileno - self.name = fileno - self.mode = open_descriptor.fileio_mode - make_nonblocking(fileno) - readable = open_descriptor.can_read - writable = open_descriptor.can_write - - self.hub = get_hub() - io_watcher = self.hub.loop.io - try: - if readable: - self._read_watcher = io_watcher(fileno, 1) - - if writable: - self._write_watcher = io_watcher(fileno, 2) - except: - # If anything goes wrong, it's important to go ahead and - # close these watchers *now*, especially under libuv, so - # that they don't get eventually reclaimed by the garbage - # collector at some random time, thanks to the C level - # slot (even though we don't seem to have any actual references - # at the Python level). Previously, if we didn't close now, - # that random close in the future would cause issues if we had duplicated - # the fileno (if a wrapping with statement had closed an open fileobject, - # for example) - - # test__fileobject can show a failure if this doesn't happen - # TRAVIS=true GEVENT_LOOP=libuv python -m gevent.tests.test__fileobject \ - # TestFileObjectPosix.test_seek TestFileObjectThread.test_bufsize_0 - self.close() - raise - - def isatty(self): - # TODO: Couldn't we just subclass FileIO? - f = FileIO(self._fileno, 'r', False) - try: - return f.isatty() - finally: - f.close() - - def readable(self): - return self._read_watcher is not None - - def writable(self): - return self._write_watcher is not None - - def seekable(self): - if self._seekable is None: - try: - os.lseek(self._fileno, 0, os.SEEK_CUR) - except OSError: - self._seekable = False - else: - self._seekable = True - return self._seekable - - def fileno(self): - return self._fileno - - @property - def closed(self): - return self._closed - - def __destroy_events(self): - read_event = self._read_watcher - write_event = self._write_watcher - hub = self.hub - self.hub = self._read_watcher = self._write_watcher = None - - hub.cancel_waits_close_and_then( - (read_event, write_event), - cancel_wait_ex, - self.__finish_close, - self._closefd, - self._fileno, - self._keep_alive - ) - - def close(self): - if self._closed: - return - self.flush() - # TODO: Can we use 'read_event is not None and write_event is - # not None' to mean _closed? - self._closed = True - try: - self.__destroy_events() - finally: - self._fileno = self._keep_alive = None - - @staticmethod - def __finish_close(closefd, fileno, keep_alive): - try: - if closefd: - _close(fileno) - finally: - if hasattr(keep_alive, 'close'): - keep_alive.close() - - # RawIOBase provides a 'read' method that will call readall() if - # the `size` was missing or -1 and otherwise call readinto(). We - # want to take advantage of this to avoid single byte reads when - # possible. This is highlighted by a bug in BufferedIOReader that - # calls read() in a loop when its readall() method is invoked; - # this was fixed in Python 3.3, but we still need our workaround for 2.7. See - # https://github.com/gevent/gevent/issues/675) - def __read(self, n): - if self._read_watcher is None: - raise UnsupportedOperation('read') - while 1: - try: - return _read(self._fileno, n) - except OSError as ex: - if ex.args[0] not in ignored_errors: - raise - wait_on_watcher(self._read_watcher, None, None, self.hub) - - def readall(self): - ret = BytesIO() - while True: - try: - data = self.__read(DEFAULT_BUFFER_SIZE) - except cancel_wait_ex: - # We were closed while reading. A buffered reader - # just returns what it has handy at that point, - # so we do to. - data = None - if not data: - break - ret.write(data) - return ret.getvalue() - - def readinto(self, b): - data = self.__read(len(b)) - n = len(data) - try: - b[:n] = data - except TypeError as err: - import array - if not isinstance(b, array.array): - raise err - b[:n] = array.array(b'b', data) - return n - - def write(self, b): - if self._write_watcher is None: - raise UnsupportedOperation('write') - while True: - try: - return _write(self._fileno, b) - except OSError as ex: - if ex.args[0] not in ignored_errors: - raise - wait_on_watcher(self._write_watcher, None, None, self.hub) - - def seek(self, offset, whence=0): - try: - return os.lseek(self._fileno, offset, whence) - except IOError: # pylint:disable=try-except-raise - raise - except OSError as ex: # pylint:disable=duplicate-except - # Python 2.x - # make sure on Python 2.x we raise an IOError - # as documented for RawIOBase. - # See https://github.com/gevent/gevent/issues/1323 - reraise(IOError, IOError(*ex.args), sys.exc_info()[2]) - - def __repr__(self): - return "<%s at 0x%x fileno=%s mode=%r>" % ( - type(self).__name__, id(self), self._fileno, self.mode - ) - - -class GreenFileDescriptorIOWriteall(WriteIsWriteallMixin, - GreenFileDescriptorIO): - pass - - -class GreenOpenDescriptor(OpenDescriptor): - - def _do_open_raw(self): - if self.is_fd(): - fileio = GreenFileDescriptorIO(self._fobj, self, closefd=self.closefd) - else: - # Either an existing file object or a path string (which - # we open to get a file object). In either case, the other object - # owns the descriptor and we must not close it. - closefd = False - - raw = OpenDescriptor._do_open_raw(self) - - fileno = raw.fileno() - fileio = GreenFileDescriptorIO(fileno, self, closefd=closefd) - fileio._keep_alive = raw - # We can usually do better for a name, though. - try: - fileio.name = raw.name - except AttributeError: - del fileio.name - return fileio - - def _make_atomic_write(self, result, raw): - # Our return value from _do_open_raw is always a new - # object that we own, so we're always free to change - # the class. - assert result is not raw or self._raw_object_is_new(raw) - if result.__class__ is GreenFileDescriptorIO: - result.__class__ = GreenFileDescriptorIOWriteall - else: - result = OpenDescriptor._make_atomic_write(self, result, raw) - return result - - -class FileObjectPosix(FileObjectBase): - """ - FileObjectPosix() - - A file-like object that operates on non-blocking files but - provides a synchronous, cooperative interface. - - .. caution:: - This object is only effective wrapping files that can be used meaningfully - with :func:`select.select` such as sockets and pipes. - - In general, on most platforms, operations on regular files - (e.g., ``open('a_file.txt')``) are considered non-blocking - already, even though they can take some time to complete as - data is copied to the kernel and flushed to disk: this time - is relatively bounded compared to sockets or pipes, though. - A :func:`~os.read` or :func:`~os.write` call on such a file - will still effectively block for some small period of time. - Therefore, wrapping this class around a regular file is - unlikely to make IO gevent-friendly: reading or writing large - amounts of data could still block the event loop. - - If you'll be working with regular files and doing IO in large - chunks, you may consider using - :class:`~gevent.fileobject.FileObjectThread` or - :func:`~gevent.os.tp_read` and :func:`~gevent.os.tp_write` to bypass this - concern. - - .. tip:: - Although this object provides a :meth:`fileno` method and so - can itself be passed to :func:`fcntl.fcntl`, setting the - :data:`os.O_NONBLOCK` flag will have no effect (reads will - still block the greenlet, although other greenlets can run). - However, removing that flag *will cause this object to no - longer be cooperative* (other greenlets will no longer run). - - You can use the internal ``fileio`` attribute of this object - (a :class:`io.RawIOBase`) to perform non-blocking byte reads. - Note, however, that once you begin directly using this - attribute, the results from using methods of *this* object - are undefined, especially in text mode. (See :issue:`222`.) - - .. versionchanged:: 1.1 - Now uses the :mod:`io` package internally. Under Python 2, previously - used the undocumented class :class:`socket._fileobject`. This provides - better file-like semantics (and portability to Python 3). - .. versionchanged:: 1.2a1 - Document the ``fileio`` attribute for non-blocking reads. - .. versionchanged:: 1.2a1 - - A bufsize of 0 in write mode is no longer forced to be 1. - Instead, the underlying buffer is flushed after every write - operation to simulate a bufsize of 0. In gevent 1.0, a - bufsize of 0 was flushed when a newline was written, while - in gevent 1.1 it was flushed when more than one byte was - written. Note that this may have performance impacts. - .. versionchanged:: 1.3a1 - On Python 2, enabling universal newlines no longer forces unicode - IO. - .. versionchanged:: 1.5 - The default value for *mode* was changed from ``rb`` to ``r``. This is consistent - with :func:`open`, :func:`io.open`, and :class:`~.FileObjectThread`, which is the - default ``FileObject`` on some platforms. - .. versionchanged:: 1.5 - Stop forcing buffering. Previously, given a ``buffering=0`` argument, - *buffering* would be set to 1, and ``buffering=1`` would be forced to - the default buffer size. This was a workaround for a long-standing concurrency - issue. Now the *buffering* argument is interpreted as intended. - """ - - default_bufsize = DEFAULT_BUFFER_SIZE - - def __init__(self, *args, **kwargs): - descriptor = GreenOpenDescriptor(*args, **kwargs) - FileObjectBase.__init__(self, descriptor) - # This attribute is documented as available for non-blocking reads. - self.fileio = descriptor.opened_raw() - - def _do_close(self, fobj, closefd): - try: - fobj.close() - # self.fileio already knows whether or not to close the - # file descriptor - self.fileio.close() - finally: - self.fileio = None diff --git a/venv/lib/python3.9/site-packages/gevent/_gevent_c_abstract_linkable.cpython-39-x86_64-linux-gnu.so b/venv/lib/python3.9/site-packages/gevent/_gevent_c_abstract_linkable.cpython-39-x86_64-linux-gnu.so deleted file mode 100755 index 4dfb433..0000000 Binary files a/venv/lib/python3.9/site-packages/gevent/_gevent_c_abstract_linkable.cpython-39-x86_64-linux-gnu.so and /dev/null differ diff --git a/venv/lib/python3.9/site-packages/gevent/_gevent_c_greenlet_primitives.cpython-39-x86_64-linux-gnu.so b/venv/lib/python3.9/site-packages/gevent/_gevent_c_greenlet_primitives.cpython-39-x86_64-linux-gnu.so deleted file mode 100755 index 9720d4b..0000000 Binary files a/venv/lib/python3.9/site-packages/gevent/_gevent_c_greenlet_primitives.cpython-39-x86_64-linux-gnu.so and /dev/null differ diff --git a/venv/lib/python3.9/site-packages/gevent/_gevent_c_hub_local.cpython-39-x86_64-linux-gnu.so b/venv/lib/python3.9/site-packages/gevent/_gevent_c_hub_local.cpython-39-x86_64-linux-gnu.so deleted file mode 100755 index 13e92ec..0000000 Binary files a/venv/lib/python3.9/site-packages/gevent/_gevent_c_hub_local.cpython-39-x86_64-linux-gnu.so and /dev/null differ diff --git a/venv/lib/python3.9/site-packages/gevent/_gevent_c_hub_primitives.cpython-39-x86_64-linux-gnu.so b/venv/lib/python3.9/site-packages/gevent/_gevent_c_hub_primitives.cpython-39-x86_64-linux-gnu.so deleted file mode 100755 index 690cea5..0000000 Binary files a/venv/lib/python3.9/site-packages/gevent/_gevent_c_hub_primitives.cpython-39-x86_64-linux-gnu.so and /dev/null differ diff --git a/venv/lib/python3.9/site-packages/gevent/_gevent_c_ident.cpython-39-x86_64-linux-gnu.so b/venv/lib/python3.9/site-packages/gevent/_gevent_c_ident.cpython-39-x86_64-linux-gnu.so deleted file mode 100755 index 75e2741..0000000 Binary files a/venv/lib/python3.9/site-packages/gevent/_gevent_c_ident.cpython-39-x86_64-linux-gnu.so and /dev/null differ diff --git a/venv/lib/python3.9/site-packages/gevent/_gevent_c_imap.cpython-39-x86_64-linux-gnu.so b/venv/lib/python3.9/site-packages/gevent/_gevent_c_imap.cpython-39-x86_64-linux-gnu.so deleted file mode 100755 index a16b8e9..0000000 Binary files a/venv/lib/python3.9/site-packages/gevent/_gevent_c_imap.cpython-39-x86_64-linux-gnu.so and /dev/null differ diff --git a/venv/lib/python3.9/site-packages/gevent/_gevent_c_semaphore.cpython-39-x86_64-linux-gnu.so b/venv/lib/python3.9/site-packages/gevent/_gevent_c_semaphore.cpython-39-x86_64-linux-gnu.so deleted file mode 100755 index fb62592..0000000 Binary files a/venv/lib/python3.9/site-packages/gevent/_gevent_c_semaphore.cpython-39-x86_64-linux-gnu.so and /dev/null differ diff --git a/venv/lib/python3.9/site-packages/gevent/_gevent_c_tracer.cpython-39-x86_64-linux-gnu.so b/venv/lib/python3.9/site-packages/gevent/_gevent_c_tracer.cpython-39-x86_64-linux-gnu.so deleted file mode 100755 index 1d75961..0000000 Binary files a/venv/lib/python3.9/site-packages/gevent/_gevent_c_tracer.cpython-39-x86_64-linux-gnu.so and /dev/null differ diff --git a/venv/lib/python3.9/site-packages/gevent/_gevent_c_waiter.cpython-39-x86_64-linux-gnu.so b/venv/lib/python3.9/site-packages/gevent/_gevent_c_waiter.cpython-39-x86_64-linux-gnu.so deleted file mode 100755 index c5fb2f3..0000000 Binary files a/venv/lib/python3.9/site-packages/gevent/_gevent_c_waiter.cpython-39-x86_64-linux-gnu.so and /dev/null differ diff --git a/venv/lib/python3.9/site-packages/gevent/_gevent_cevent.cpython-39-x86_64-linux-gnu.so b/venv/lib/python3.9/site-packages/gevent/_gevent_cevent.cpython-39-x86_64-linux-gnu.so deleted file mode 100755 index 803c49c..0000000 Binary files a/venv/lib/python3.9/site-packages/gevent/_gevent_cevent.cpython-39-x86_64-linux-gnu.so and /dev/null differ diff --git a/venv/lib/python3.9/site-packages/gevent/_gevent_cgreenlet.cpython-39-x86_64-linux-gnu.so b/venv/lib/python3.9/site-packages/gevent/_gevent_cgreenlet.cpython-39-x86_64-linux-gnu.so deleted file mode 100755 index f15973f..0000000 Binary files a/venv/lib/python3.9/site-packages/gevent/_gevent_cgreenlet.cpython-39-x86_64-linux-gnu.so and /dev/null differ diff --git a/venv/lib/python3.9/site-packages/gevent/_gevent_clocal.cpython-39-x86_64-linux-gnu.so b/venv/lib/python3.9/site-packages/gevent/_gevent_clocal.cpython-39-x86_64-linux-gnu.so deleted file mode 100755 index ec54929..0000000 Binary files a/venv/lib/python3.9/site-packages/gevent/_gevent_clocal.cpython-39-x86_64-linux-gnu.so and /dev/null differ diff --git a/venv/lib/python3.9/site-packages/gevent/_gevent_cqueue.cpython-39-x86_64-linux-gnu.so b/venv/lib/python3.9/site-packages/gevent/_gevent_cqueue.cpython-39-x86_64-linux-gnu.so deleted file mode 100755 index 55c01b5..0000000 Binary files a/venv/lib/python3.9/site-packages/gevent/_gevent_cqueue.cpython-39-x86_64-linux-gnu.so and /dev/null differ diff --git a/venv/lib/python3.9/site-packages/gevent/_greenlet_primitives.py b/venv/lib/python3.9/site-packages/gevent/_greenlet_primitives.py deleted file mode 100644 index 7637c84..0000000 --- a/venv/lib/python3.9/site-packages/gevent/_greenlet_primitives.py +++ /dev/null @@ -1,132 +0,0 @@ -# -*- coding: utf-8 -*- -# copyright (c) 2018 gevent. See LICENSE. -# cython: auto_pickle=False,embedsignature=True,always_allow_keywords=False -""" -A collection of primitives used by the hub, and suitable for -compilation with Cython because of their frequency of use. - -""" -from __future__ import absolute_import -from __future__ import division -from __future__ import print_function - -from weakref import ref as wref -from gc import get_objects - -from greenlet import greenlet - -from gevent.exceptions import BlockingSwitchOutError - - -# In Cython, we define these as 'cdef inline' functions. The -# compilation unit cannot have a direct assignment to them (import -# is assignment) without generating a 'lvalue is not valid target' -# error. -locals()['getcurrent'] = __import__('greenlet').getcurrent -locals()['greenlet_init'] = lambda: None -locals()['_greenlet_switch'] = greenlet.switch - - -__all__ = [ - 'TrackedRawGreenlet', - 'SwitchOutGreenletWithLoop', -] - -class TrackedRawGreenlet(greenlet): - - def __init__(self, function, parent): - greenlet.__init__(self, function, parent) - # See greenlet.py's Greenlet class. We capture the cheap - # parts to maintain the tree structure, but we do not capture - # the stack because that's too expensive for 'spawn_raw'. - - current = getcurrent() # pylint:disable=undefined-variable - self.spawning_greenlet = wref(current) - # See Greenlet for how trees are maintained. - try: - self.spawn_tree_locals = current.spawn_tree_locals - except AttributeError: - self.spawn_tree_locals = {} - if current.parent: - current.spawn_tree_locals = self.spawn_tree_locals - - -class SwitchOutGreenletWithLoop(TrackedRawGreenlet): - # Subclasses must define: - # - self.loop - - # This class defines loop in its .pxd for Cython. This lets us avoid - # circular dependencies with the hub. - - def switch(self): - switch_out = getattr(getcurrent(), 'switch_out', None) # pylint:disable=undefined-variable - if switch_out is not None: - switch_out() - return _greenlet_switch(self) # pylint:disable=undefined-variable - - def switch_out(self): - raise BlockingSwitchOutError('Impossible to call blocking function in the event loop callback') - - -def get_reachable_greenlets(): - # We compile this loop with Cython so that it's faster, and so that - # the GIL isn't dropped at unpredictable times during the loop. - # Dropping the GIL could lead to accessing partly constructed objects - # in undefined states (particularly, tuples). This helps close a hole - # where a `SystemError: Objects/tupleobject.c bad argument to internal function` - # could get raised. (Note that this probably doesn't completely close the hole, - # if other threads have dropped the GIL, but hopefully the speed makes that - # more rare.) See https://github.com/gevent/gevent/issues/1302 - return [ - x for x in get_objects() - if isinstance(x, greenlet) and not getattr(x, 'greenlet_tree_is_ignored', False) - ] - -# Cache the global memoryview so cython can optimize. -_memoryview = memoryview -try: - if isinstance(__builtins__, dict): - # Pure-python mode on CPython - _buffer = __builtins__['buffer'] - else: - # Cythonized mode, or PyPy - _buffer = __builtins__.buffer -except (AttributeError, KeyError): - # Python 3. - _buffer = memoryview - -def get_memory(data): - # On Python 2, memoryview(memoryview()) can leak in some cases, - # notably when an io.BufferedWriter object produced the memoryview. - # So we need to check to see if we already have one before we convert. - # We do this in Cython to mitigate the performance cost (which turns out to be a - # net win.) - - # We don't specifically test for this leak. - - # https://github.com/gevent/gevent/issues/1318 - try: - mv = _memoryview(data) if not isinstance(data, _memoryview) else data - if mv.shape: - return mv - # No shape, probably working with a ctypes object, - # or something else exotic that supports the buffer interface - return mv.tobytes() - except TypeError: - # fixes "python2.7 array.array doesn't support memoryview used in - # gevent.socket.send" issue - # (http://code.google.com/p/gevent/issues/detail?id=94) - if _buffer is _memoryview: - # Py3 - raise - return _buffer(data) - - - -def _init(): - greenlet_init() # pylint:disable=undefined-variable - -_init() - -from gevent._util import import_c_accel -import_c_accel(globals(), 'gevent.__greenlet_primitives') diff --git a/venv/lib/python3.9/site-packages/gevent/_hub_local.py b/venv/lib/python3.9/site-packages/gevent/_hub_local.py deleted file mode 100644 index b2c36c9..0000000 --- a/venv/lib/python3.9/site-packages/gevent/_hub_local.py +++ /dev/null @@ -1,154 +0,0 @@ -# -*- coding: utf-8 -*- -# copyright 2018 gevent. See LICENSE -""" -Maintains the thread local hub. - -""" -from __future__ import absolute_import -from __future__ import division -from __future__ import print_function - - -import _thread - -__all__ = [ - 'get_hub', - 'get_hub_noargs', - 'get_hub_if_exists', -] - -# These must be the "real" native thread versions, -# not monkey-patched. -# We are imported early enough (by gevent/__init__) that -# we can rely on not being monkey-patched in any way yet. -assert 'gevent' not in str(_thread._local) -class _Threadlocal(_thread._local): - - def __init__(self): - # Use a class with an initializer so that we can test - # for 'is None' instead of catching AttributeError, making - # the code cleaner and possibly solving some corner cases - # (like #687). - # - # However, under some weird circumstances, it _seems_ like the - # __init__ method doesn't get called properly ("seems" is the - # keyword). We've seen at least one instance - # (https://github.com/gevent/gevent/issues/1961) of - # ``AttributeError: '_Threadlocal' object has no attribute # 'hub'`` - # which should be impossible unless: - # - # - Someone manually deletes the attribute - # - The _threadlocal object itself is in the process of being - # deleted. The C ``tp_clear`` slot for it deletes the ``__dict__`` - # of each instance in each thread (and/or the ``tp_clear`` of ``dict`` itself - # clears the instance). Now, how we could be getting - # cleared while still being used is unclear, but clearing is part of - # circular garbage collection, and in the bug report it looks like we're inside a - # weakref finalizer or ``__del__`` method, which could suggest that - # garbage collection is happening. - # - # See https://github.com/gevent/gevent/issues/1961 - # and ``get_hub_if_exists()`` - super(_Threadlocal, self).__init__() - self.Hub = None - self.loop = None - self.hub = None - -_threadlocal = _Threadlocal() - -Hub = None # Set when gevent.hub is imported - -def get_hub_class(): - """Return the type of hub to use for the current thread. - - If there's no type of hub for the current thread yet, 'gevent.hub.Hub' is used. - """ - try: - hubtype = _threadlocal.Hub - except AttributeError: - hubtype = None - - if hubtype is None: - hubtype = _threadlocal.Hub = Hub - return hubtype - -def set_default_hub_class(hubtype): - global Hub - Hub = hubtype - -def get_hub(): - """ - Return the hub for the current thread. - - If a hub does not exist in the current thread, a new one is - created of the type returned by :func:`get_hub_class`. - - .. deprecated:: 1.3b1 - The ``*args`` and ``**kwargs`` arguments are deprecated. They were - only used when the hub was created, and so were non-deterministic---to be - sure they were used, *all* callers had to pass them, or they were order-dependent. - Use ``set_hub`` instead. - - .. versionchanged:: 1.5a3 - The *args* and *kwargs* arguments are now completely ignored. - - .. versionchanged:: 23.7.0 - The long-deprecated ``args`` and ``kwargs`` parameters are no - longer accepted. - """ - # See get_hub_if_exists - try: - hub = _threadlocal.hub - except AttributeError: - hub = None - if hub is None: - hubtype = get_hub_class() - hub = _threadlocal.hub = hubtype() - return hub - -# For Cython purposes, we need to duplicate get_hub into this function so it -# can be directly called. -def get_hub_noargs(): - # See get_hub_if_exists - try: - hub = _threadlocal.hub - except AttributeError: - hub = None - if hub is None: - hubtype = get_hub_class() - hub = _threadlocal.hub = hubtype() - return hub - -def get_hub_if_exists(): - """ - Return the hub for the current thread. - - Return ``None`` if no hub has been created yet. - """ - # Attempt a band-aid for the poorly-understood behaviour - # seen in https://github.com/gevent/gevent/issues/1961 - # where the ``hub`` attribute has gone missing. - try: - return _threadlocal.hub - except AttributeError: - # XXX: I'd really like to report this, but I'm not sure how - # that can be done safely (because I don't know how we get - # here in the first place). We may be in a place where imports - # are unsafe, or the interpreter is shutting down, or the - # thread is exiting, or... - return None - - - - -def set_hub(hub): - _threadlocal.hub = hub - -def get_loop(): - return _threadlocal.loop - -def set_loop(loop): - _threadlocal.loop = loop - -from gevent._util import import_c_accel -import_c_accel(globals(), 'gevent.__hub_local') diff --git a/venv/lib/python3.9/site-packages/gevent/_hub_primitives.py b/venv/lib/python3.9/site-packages/gevent/_hub_primitives.py deleted file mode 100644 index 5650ad1..0000000 --- a/venv/lib/python3.9/site-packages/gevent/_hub_primitives.py +++ /dev/null @@ -1,427 +0,0 @@ -# -*- coding: utf-8 -*- -# copyright (c) 2018 gevent. See LICENSE. -# cython: auto_pickle=False,embedsignature=True,always_allow_keywords=False,binding=True -""" -A collection of primitives used by the hub, and suitable for -compilation with Cython because of their frequency of use. - - -""" -from __future__ import absolute_import -from __future__ import division -from __future__ import print_function - -import traceback - -from gevent.exceptions import InvalidSwitchError -from gevent.exceptions import ConcurrentObjectUseError - -from gevent import _greenlet_primitives -from gevent import _waiter -from gevent._util import _NONE -from gevent._hub_local import get_hub_noargs as get_hub -from gevent.timeout import Timeout - -# In Cython, we define these as 'cdef inline' functions. The -# compilation unit cannot have a direct assignment to them (import -# is assignment) without generating a 'lvalue is not valid target' -# error. -locals()['getcurrent'] = __import__('greenlet').getcurrent -locals()['greenlet_init'] = lambda: None -locals()['Waiter'] = _waiter.Waiter -locals()['MultipleWaiter'] = _waiter.MultipleWaiter -locals()['SwitchOutGreenletWithLoop'] = _greenlet_primitives.SwitchOutGreenletWithLoop - -__all__ = [ - 'WaitOperationsGreenlet', - 'iwait_on_objects', - 'wait_on_objects', - 'wait_read', - 'wait_write', - 'wait_readwrite', -] - -class WaitOperationsGreenlet(SwitchOutGreenletWithLoop): # pylint:disable=undefined-variable - - def wait(self, watcher): - """ - Wait until the *watcher* (which must not be started) is ready. - - The current greenlet will be unscheduled during this time. - """ - waiter = Waiter(self) # pylint:disable=undefined-variable - watcher.start(waiter.switch, waiter) - try: - result = waiter.get() - if result is not waiter: - raise InvalidSwitchError( - 'Invalid switch into %s: got %r (expected %r; waiting on %r with %r)' % ( - getcurrent(), # pylint:disable=undefined-variable - result, - waiter, - self, - watcher - ) - ) - finally: - watcher.stop() - - def cancel_waits_close_and_then(self, watchers, exc_kind, then, *then_args): - deferred = [] - for watcher in watchers: - if watcher is None: - continue - if watcher.callback is None: - watcher.close() - else: - deferred.append(watcher) - if deferred: - self.loop.run_callback(self._cancel_waits_then, deferred, exc_kind, then, then_args) - else: - then(*then_args) - - def _cancel_waits_then(self, watchers, exc_kind, then, then_args): - for watcher in watchers: - self._cancel_wait(watcher, exc_kind, True) - then(*then_args) - - def cancel_wait(self, watcher, error, close_watcher=False): - """ - Cancel an in-progress call to :meth:`wait` by throwing the given *error* - in the waiting greenlet. - - .. versionchanged:: 1.3a1 - Added the *close_watcher* parameter. If true, the watcher - will be closed after the exception is thrown. The watcher should then - be discarded. Closing the watcher is important to release native resources. - .. versionchanged:: 1.3a2 - Allow the *watcher* to be ``None``. No action is taken in that case. - - """ - if watcher is None: - # Presumably already closed. - # See https://github.com/gevent/gevent/issues/1089 - return - - if watcher.callback is not None: - self.loop.run_callback(self._cancel_wait, watcher, error, close_watcher) - return - - if close_watcher: - watcher.close() - - def _cancel_wait(self, watcher, error, close_watcher): - # Running in the hub. Switches to the waiting greenlet to raise - # the error; assuming the waiting greenlet dies, switches back - # to this (because the waiting greenlet's parent is the hub.) - - # We have to check again to see if it was still active by the time - # our callback actually runs. - active = watcher.active - cb = watcher.callback - if close_watcher: - watcher.close() - if active: - # The callback should be greenlet.switch(). It may or may not be None. - glet = getattr(cb, '__self__', None) - if glet is not None: - glet.throw(error) - - -class _WaitIterator(object): - - def __init__(self, objects, hub, timeout, count): - self._hub = hub - self._waiter = MultipleWaiter(hub) # pylint:disable=undefined-variable - self._switch = self._waiter.switch - self._timeout = timeout - self._objects = objects - - self._timer = None - self._begun = False - - # Even if we're only going to return 1 object, - # we must still rawlink() *all* of them, so that no - # matter which one finishes first we find it. - self._count = len(objects) if count is None else min(count, len(objects)) - - def _begin(self): - if self._begun: - return - - self._begun = True - - # XXX: If iteration doesn't actually happen, we - # could leave these links around! - for obj in self._objects: - obj.rawlink(self._switch) - - if self._timeout is not None: - self._timer = self._hub.loop.timer(self._timeout, priority=-1) - self._timer.start(self._switch, self) - - def __iter__(self): - return self - - def __next__(self): - self._begin() - - if self._count == 0: - # Exhausted - self._cleanup() - raise StopIteration() - - self._count -= 1 - try: - item = self._waiter.get() - self._waiter.clear() - if item is self: - # Timer expired, no more - self._cleanup() - raise StopIteration() - return item - except: - self._cleanup() - raise - - next = __next__ - - def _cleanup(self): - if self._timer is not None: - self._timer.close() - self._timer = None - - objs = self._objects - self._objects = () - for aobj in objs: - unlink = getattr(aobj, 'unlink', None) - if unlink is not None: - try: - unlink(self._switch) - except: # pylint:disable=bare-except - traceback.print_exc() - - def __enter__(self): - return self - - def __exit__(self, typ, value, tb): - self._cleanup() - - -def iwait_on_objects(objects, timeout=None, count=None): - """ - Iteratively yield *objects* as they are ready, until all (or *count*) are ready - or *timeout* expired. - - If you will only be consuming a portion of the *objects*, you should - do so inside a ``with`` block on this object to avoid leaking resources:: - - with gevent.iwait((a, b, c)) as it: - for i in it: - if i is a: - break - - :param objects: A sequence (supporting :func:`len`) containing objects - implementing the wait protocol (rawlink() and unlink()). - :keyword int count: If not `None`, then a number specifying the maximum number - of objects to wait for. If ``None`` (the default), all objects - are waited for. - :keyword float timeout: If given, specifies a maximum number of seconds - to wait. If the timeout expires before the desired waited-for objects - are available, then this method returns immediately. - - .. seealso:: :func:`wait` - - .. versionchanged:: 1.1a1 - Add the *count* parameter. - .. versionchanged:: 1.1a2 - No longer raise :exc:`LoopExit` if our caller switches greenlets - in between items yielded by this function. - .. versionchanged:: 1.4 - Add support to use the returned object as a context manager. - """ - # QQQ would be nice to support iterable here that can be generated slowly (why?) - hub = get_hub() - if objects is None: - return [hub.join(timeout=timeout)] - return _WaitIterator(objects, hub, timeout, count) - - -def wait_on_objects(objects=None, timeout=None, count=None): - """ - Wait for *objects* to become ready or for event loop to finish. - - If *objects* is provided, it must be a list containing objects - implementing the wait protocol (rawlink() and unlink() methods): - - - :class:`gevent.Greenlet` instance - - :class:`gevent.event.Event` instance - - :class:`gevent.lock.Semaphore` instance - - :class:`gevent.subprocess.Popen` instance - - If *objects* is ``None`` (the default), ``wait()`` blocks until - the current event loop has nothing to do (or until *timeout* passes): - - - all greenlets have finished - - all servers were stopped - - all event loop watchers were stopped. - - If *count* is ``None`` (the default), wait for all *objects* - to become ready. - - If *count* is a number, wait for (up to) *count* objects to become - ready. (For example, if count is ``1`` then the function exits - when any object in the list is ready). - - If *timeout* is provided, it specifies the maximum number of - seconds ``wait()`` will block. - - Returns the list of ready objects, in the order in which they were - ready. - - .. seealso:: :func:`iwait` - """ - if objects is None: - hub = get_hub() - return hub.join(timeout=timeout) # pylint:disable= - return list(iwait_on_objects(objects, timeout, count)) - -_timeout_error = Exception - -def set_default_timeout_error(e): - global _timeout_error - _timeout_error = e - -def _primitive_wait(watcher, timeout, timeout_exc, hub): - if watcher.callback is not None: - raise ConcurrentObjectUseError('This socket is already used by another greenlet: %r' - % (watcher.callback, )) - - if hub is None: - hub = get_hub() - - if timeout is None: - hub.wait(watcher) - return - - timeout = Timeout._start_new_or_dummy( - timeout, - (timeout_exc - if timeout_exc is not _NONE or timeout is None - else _timeout_error('timed out'))) - - with timeout: - hub.wait(watcher) - -# Suitable to be bound as an instance method -def wait_on_socket(socket, watcher, timeout_exc=None): - if socket is None or watcher is None: - # test__hub TestCloseSocketWhilePolling, on Python 2; Python 3 - # catches the EBADF differently. - raise ConcurrentObjectUseError("The socket has already been closed by another greenlet") - _primitive_wait(watcher, socket.timeout, - timeout_exc if timeout_exc is not None else _NONE, - socket.hub) - -def wait_on_watcher(watcher, timeout=None, timeout_exc=_NONE, hub=None): - """ - wait(watcher, timeout=None, [timeout_exc=None]) -> None - - Block the current greenlet until *watcher* is ready. - - If *timeout* is non-negative, then *timeout_exc* is raised after - *timeout* second has passed. - - If :func:`cancel_wait` is called on *watcher* by another greenlet, - raise an exception in this blocking greenlet - (``socket.error(EBADF, 'File descriptor was closed in another - greenlet')`` by default). - - :param watcher: An event loop watcher, most commonly an IO watcher obtained from - :meth:`gevent.core.loop.io` - :keyword timeout_exc: The exception to raise if the timeout expires. - By default, a :class:`socket.timeout` exception is raised. - If you pass a value for this keyword, it is interpreted as for - :class:`gevent.timeout.Timeout`. - - :raises ~gevent.hub.ConcurrentObjectUseError: If the *watcher* is - already started. - """ - _primitive_wait(watcher, timeout, timeout_exc, hub) - - -def wait_read(fileno, timeout=None, timeout_exc=_NONE): - """ - wait_read(fileno, timeout=None, [timeout_exc=None]) -> None - - Block the current greenlet until *fileno* is ready to read. - - For the meaning of the other parameters and possible exceptions, - see :func:`wait`. - - .. seealso:: :func:`cancel_wait` - """ - hub = get_hub() - io = hub.loop.io(fileno, 1) - try: - return wait_on_watcher(io, timeout, timeout_exc, hub) - finally: - io.close() - - -def wait_write(fileno, timeout=None, timeout_exc=_NONE, event=_NONE): - """ - wait_write(fileno, timeout=None, [timeout_exc=None]) -> None - - Block the current greenlet until *fileno* is ready to write. - - For the meaning of the other parameters and possible exceptions, - see :func:`wait`. - - .. deprecated:: 1.1 - The keyword argument *event* is ignored. Applications should not pass this parameter. - In the future, doing so will become an error. - - .. seealso:: :func:`cancel_wait` - """ - # pylint:disable=unused-argument - hub = get_hub() - io = hub.loop.io(fileno, 2) - try: - return wait_on_watcher(io, timeout, timeout_exc, hub) - finally: - io.close() - - -def wait_readwrite(fileno, timeout=None, timeout_exc=_NONE, event=_NONE): - """ - wait_readwrite(fileno, timeout=None, [timeout_exc=None]) -> None - - Block the current greenlet until *fileno* is ready to read or - write. - - For the meaning of the other parameters and possible exceptions, - see :func:`wait`. - - .. deprecated:: 1.1 - The keyword argument *event* is ignored. Applications should not pass this parameter. - In the future, doing so will become an error. - - .. seealso:: :func:`cancel_wait` - """ - # pylint:disable=unused-argument - hub = get_hub() - io = hub.loop.io(fileno, 3) - try: - return wait_on_watcher(io, timeout, timeout_exc, hub) - finally: - io.close() - - -def _init(): - greenlet_init() # pylint:disable=undefined-variable - -_init() - -from gevent._util import import_c_accel -import_c_accel(globals(), 'gevent.__hub_primitives') diff --git a/venv/lib/python3.9/site-packages/gevent/_ident.py b/venv/lib/python3.9/site-packages/gevent/_ident.py deleted file mode 100644 index 5fb763c..0000000 --- a/venv/lib/python3.9/site-packages/gevent/_ident.py +++ /dev/null @@ -1,82 +0,0 @@ -# -*- coding: utf-8 -*- -# Copyright 2018 gevent contributors. See LICENSE for details. -# cython: auto_pickle=False,embedsignature=True,always_allow_keywords=False - -from __future__ import absolute_import -from __future__ import division -from __future__ import print_function - - -from weakref import WeakKeyDictionary -from weakref import ref - -from heapq import heappop -from heapq import heappush - -__all__ = [ - 'IdentRegistry', -] - -class ValuedWeakRef(ref): - """ - A weak ref with an associated value. - """ - - __slots__ = ('value',) - - -class IdentRegistry(object): - """ - Maintains a unique mapping of (small) non-negative integer identifiers - to objects that can be weakly referenced. - - It is guaranteed that no two objects will have the the same - identifier at the same time, as long as those objects are - also uniquely hashable. - """ - - def __init__(self): - # {obj -> (ident, wref(obj))} - self._registry = WeakKeyDictionary() - - # A heap of numbers that have been used and returned - self._available_idents = [] - - def get_ident(self, obj): - """ - Retrieve the identifier for *obj*, creating one - if necessary. - """ - - try: - return self._registry[obj][0] - except KeyError: - pass - - if self._available_idents: - # Take the smallest free number - ident = heappop(self._available_idents) - else: - # Allocate a bigger one - ident = len(self._registry) - - vref = ValuedWeakRef(obj, self._return_ident) - vref.value = ident # pylint:disable=assigning-non-slot,attribute-defined-outside-init - self._registry[obj] = (ident, vref) - return ident - - def _return_ident(self, vref): - # By the time this is called, self._registry has been - # updated - if heappush is not None: - # Under some circumstances we can get called - # when the interpreter is shutting down, and globals - # aren't available any more. - heappush(self._available_idents, vref.value) - - def __len__(self): - return len(self._registry) - - -from gevent._util import import_c_accel -import_c_accel(globals(), 'gevent.__ident') diff --git a/venv/lib/python3.9/site-packages/gevent/_imap.py b/venv/lib/python3.9/site-packages/gevent/_imap.py deleted file mode 100644 index dd6cb00..0000000 --- a/venv/lib/python3.9/site-packages/gevent/_imap.py +++ /dev/null @@ -1,226 +0,0 @@ -# -*- coding: utf-8 -*- -# Copyright (c) 2018 gevent -# cython: auto_pickle=False,embedsignature=True,always_allow_keywords=False,infer_types=True - -""" -Iterators across greenlets or AsyncResult objects. - -""" -from __future__ import absolute_import -from __future__ import division -from __future__ import print_function - - -from gevent import lock -from gevent import queue - - -__all__ = [ - 'IMapUnordered', - 'IMap', -] - -locals()['Greenlet'] = __import__('gevent').Greenlet -locals()['Semaphore'] = lock.Semaphore -locals()['UnboundQueue'] = queue.UnboundQueue - - -class Failure(object): - __slots__ = ('exc', 'raise_exception') - - def __init__(self, exc, raise_exception=None): - self.exc = exc - self.raise_exception = raise_exception - - -def _raise_exc(failure): - # For cython. - if failure.raise_exception: - failure.raise_exception() - else: - raise failure.exc - -class IMapUnordered(Greenlet): # pylint:disable=undefined-variable - """ - At iterator of map results. - """ - - def __init__(self, func, iterable, spawn, maxsize=None, _zipped=False): - """ - An iterator that. - - :param callable spawn: The function we use to create new greenlets. - :keyword int maxsize: If given and not-None, specifies the maximum number of - finished results that will be allowed to accumulated awaiting the reader; - more than that number of results will cause map function greenlets to begin - to block. This is most useful is there is a great disparity in the speed of - the mapping code and the consumer and the results consume a great deal of resources. - Using a bound is more computationally expensive than not using a bound. - - .. versionchanged:: 1.1b3 - Added the *maxsize* parameter. - """ - Greenlet.__init__(self) # pylint:disable=undefined-variable - self.spawn = spawn - self._zipped = _zipped - self.func = func - self.iterable = iterable - self.queue = UnboundQueue() # pylint:disable=undefined-variable - - - if maxsize: - # Bounding the queue is not enough if we want to keep from - # accumulating objects; the result value will be around as - # the greenlet's result, blocked on self.queue.put(), and - # we'll go on to spawn another greenlet, which in turn can - # create the result. So we need a semaphore to prevent a - # greenlet from exiting while the queue is full so that we - # don't spawn the next greenlet (assuming that self.spawn - # is of course bounded). (Alternatively we could have the - # greenlet itself do the insert into the pool, but that - # takes some rework). - # - # Given the use of a semaphore at this level, sizing the queue becomes - # redundant, and that lets us avoid having to use self.link() instead - # of self.rawlink() to avoid having blocking methods called in the - # hub greenlet. - self._result_semaphore = Semaphore(maxsize) # pylint:disable=undefined-variable - else: - self._result_semaphore = None - - self._outstanding_tasks = 0 - # The index (zero based) of the maximum number of - # results we will have. - self._max_index = -1 - self.finished = False - - - # We're iterating in a different greenlet than we're running. - def __iter__(self): - return self - - def __next__(self): - if self._result_semaphore is not None: - self._result_semaphore.release() - value = self._inext() - if isinstance(value, Failure): - _raise_exc(value) - return value - - next = __next__ # Py2 - - def _inext(self): - return self.queue.get() - - def _ispawn(self, func, item, item_index): - if self._result_semaphore is not None: - self._result_semaphore.acquire() - self._outstanding_tasks += 1 - g = self.spawn(func, item) if not self._zipped else self.spawn(func, *item) - g._imap_task_index = item_index - g.rawlink(self._on_result) - return g - - def _run(self): # pylint:disable=method-hidden - try: - func = self.func - for item in self.iterable: - self._max_index += 1 - self._ispawn(func, item, self._max_index) - self._on_finish(None) - except BaseException as e: - self._on_finish(e) - raise - finally: - self.spawn = None - self.func = None - self.iterable = None - self._result_semaphore = None - - def _on_result(self, greenlet): - # This method will be called in the hub greenlet (we rawlink) - self._outstanding_tasks -= 1 - count = self._outstanding_tasks - finished = self.finished - ready = self.ready() - put_finished = False - - if ready and count <= 0 and not finished: - finished = self.finished = True - put_finished = True - - if greenlet.successful(): - self.queue.put(self._iqueue_value_for_success(greenlet)) - else: - self.queue.put(self._iqueue_value_for_failure(greenlet)) - - if put_finished: - self.queue.put(self._iqueue_value_for_self_finished()) - - def _on_finish(self, exception): - # Called in this greenlet. - if self.finished: - return - - if exception is not None: - self.finished = True - self.queue.put(self._iqueue_value_for_self_failure(exception)) - return - - if self._outstanding_tasks <= 0: - self.finished = True - self.queue.put(self._iqueue_value_for_self_finished()) - - def _iqueue_value_for_success(self, greenlet): - return greenlet.value - - def _iqueue_value_for_failure(self, greenlet): - return Failure(greenlet.exception, getattr(greenlet, '_raise_exception')) - - def _iqueue_value_for_self_finished(self): - return Failure(StopIteration()) - - def _iqueue_value_for_self_failure(self, exception): - return Failure(exception, self._raise_exception) - - -class IMap(IMapUnordered): - # A specialization of IMapUnordered that returns items - # in the order in which they were generated, not - # the order in which they finish. - - def __init__(self, *args, **kwargs): - # The result dictionary: {index: value} - self._results = {} - - # The index of the result to return next. - self.index = 0 - IMapUnordered.__init__(self, *args, **kwargs) - - def _inext(self): - try: - value = self._results.pop(self.index) - except KeyError: - # Wait for our index to finish. - while 1: - index, value = self.queue.get() - if index == self.index: - break - self._results[index] = value - self.index += 1 - return value - - def _iqueue_value_for_success(self, greenlet): - return (greenlet._imap_task_index, IMapUnordered._iqueue_value_for_success(self, greenlet)) - - def _iqueue_value_for_failure(self, greenlet): - return (greenlet._imap_task_index, IMapUnordered._iqueue_value_for_failure(self, greenlet)) - - def _iqueue_value_for_self_finished(self): - return (self._max_index + 1, IMapUnordered._iqueue_value_for_self_finished(self)) - - def _iqueue_value_for_self_failure(self, exception): - return (self._max_index + 1, IMapUnordered._iqueue_value_for_self_failure(self, exception)) - -from gevent._util import import_c_accel -import_c_accel(globals(), 'gevent.__imap') diff --git a/venv/lib/python3.9/site-packages/gevent/_interfaces.py b/venv/lib/python3.9/site-packages/gevent/_interfaces.py deleted file mode 100644 index 321e251..0000000 --- a/venv/lib/python3.9/site-packages/gevent/_interfaces.py +++ /dev/null @@ -1,323 +0,0 @@ -# -*- coding: utf-8 -*- -# Copyright (c) 2018 gevent contributors. See LICENSE for details. -""" -Interfaces gevent uses that don't belong any one place. - -This is not a public module, these interfaces are not -currently exposed to the public, they mostly exist for -documentation and testing purposes. - -.. versionadded:: 1.3b2 - -""" -from __future__ import absolute_import -from __future__ import division -from __future__ import print_function - -import sys - -from zope.interface import Interface -from zope.interface import Attribute - -_text_type = type(u'') - -try: - from zope import schema -except ImportError: # pragma: no cover - class _Field(Attribute): - __allowed_kw__ = ('readonly', 'min',) - def __init__(self, description, required=False, **kwargs): - description = u"%s (required? %s)" % (description, required) - assert isinstance(description, _text_type) - for k in self.__allowed_kw__: - kwargs.pop(k, None) - if kwargs: - raise TypeError("Unexpected keyword arguments: %r" % (kwargs,)) - Attribute.__init__(self, description) - - class schema(object): - Bool = _Field - Float = _Field - - -# pylint:disable=no-method-argument, unused-argument, no-self-argument -# pylint:disable=inherit-non-class - -__all__ = [ - 'ILoop', - 'IWatcher', - 'ICallback', -] - -class ILoop(Interface): - """ - The common interface expected for all event loops. - - .. caution:: - This is an internal, low-level interface. It may change - between minor versions of gevent. - - .. rubric:: Watchers - - The methods that create event loop watchers are `io`, `timer`, - `signal`, `idle`, `prepare`, `check`, `fork`, `async_`, `child`, - `stat`. These all return various types of :class:`IWatcher`. - - All of those methods have one or two common arguments. *ref* is a - boolean saying whether the event loop is allowed to exit even if - this watcher is still started. *priority* is event loop specific. - """ - - default = schema.Bool( - description=u"Boolean indicating whether this is the default loop", - required=True, - readonly=True, - ) - - approx_timer_resolution = schema.Float( - description=u"Floating point number of seconds giving (approximately) the minimum " - "resolution of a timer (and hence the minimun value the sleep can sleep for). " - "On libuv, this is fixed by the library, but on libev it is just a guess " - "and the actual value is system dependent.", - required=True, - min=0.0, - readonly=True, - ) - - def run(nowait=False, once=False): - """ - Run the event loop. - - This is usually called automatically by the hub greenlet, but - in special cases (when the hub is *not* running) you can use - this to control how the event loop runs (for example, to integrate - it with another event loop). - """ - - def now(): - """ - now() -> float - - Return the loop's notion of the current time. - - This may not necessarily be related to :func:`time.time` (it - may have a different starting point), but it must be expressed - in fractional seconds (the same *units* used by :func:`time.time`). - """ - - def update_now(): - """ - Update the loop's notion of the current time. - - .. versionadded:: 1.3 - In the past, this available as ``update``. This is still available as - an alias but will be removed in the future. - """ - - def destroy(): - """ - Clean up resources used by this loop. - - If you create loops - (especially loops that are not the default) you *should* call - this method when you are done with the loop. - - .. caution:: - - As an implementation note, the libev C loop implementation has a - finalizer (``__del__``) that destroys the object, but the libuv - and libev CFFI implementations do not. The C implementation may change. - - """ - - def io(fd, events, ref=True, priority=None): - """ - Create and return a new IO watcher for the given *fd*. - - *events* is a bitmask specifying which events to watch - for. 1 means read, and 2 means write. - - *fd* should be valid. If it is not, this method _should_ - throw an OSError EBADF. - """ - - def closing_fd(fd): - """ - Inform the loop that the file descriptor *fd* is about to be closed. - - The loop may choose to schedule events to be delivered to any active - IO watchers for the fd. libev does this so that the active watchers - can be closed. - - :return: A boolean value that's true if active IO watchers were - queued to run. Closing the FD should be deferred until the next - run of the eventloop with a check watcher (callbacks may be - run immediately if we were already running callbacks when this was - added, and it needs to come after the loop). - """ - - def timer(after, repeat=0.0, ref=True, priority=None): - """ - Create and return a timer watcher that will fire after *after* seconds. - - If *repeat* is given, the timer will continue to fire every *repeat* seconds. - """ - - def signal(signum, ref=True, priority=None): - """ - Create and return a signal watcher for the signal *signum*, - one of the constants defined in :mod:`signal`. - - This is platform and event loop specific. - """ - - def idle(ref=True, priority=None): - """ - Create and return a watcher that fires when the event loop is idle. - """ - - def prepare(ref=True, priority=None): - """ - Create and return a watcher that fires before the event loop - polls for IO. - - .. caution:: This method is not supported by libuv. - """ - - def check(ref=True, priority=None): - """ - Create and return a watcher that fires after the event loop - polls for IO. - """ - - def fork(ref=True, priority=None): - """ - Create a watcher that fires when the process forks. - - Availability: Unix. - """ - - def async_(ref=True, priority=None): - """ - Create a watcher that fires when triggered, possibly - from another thread. - - .. versionchanged:: 1.3 - This was previously just named ``async``; for compatibility - with Python 3.7 where ``async`` is a keyword it was renamed. - On older versions of Python the old name is still around, but - it will be removed in the future. - """ - - if sys.platform != "win32": - - def child(pid, trace=0, ref=True): - """ - Create a watcher that fires for events on the child with process ID *pid*. - - This is platform specific and not available on Windows. - - Availability: Unix. - """ - - def stat(path, interval=0.0, ref=True, priority=None): - """ - Create a watcher that monitors the filesystem item at *path*. - - If the operating system doesn't support event notifications - from the filesystem, poll for changes every *interval* seconds. - """ - - def run_callback(func, *args): - """ - Run the *func* passing it *args* at the next opportune moment. - - The next opportune moment may be the next iteration of the event loop, - the current iteration, or some other time in the future. - - Returns a :class:`ICallback` object. See that documentation for - important caveats. - - .. seealso:: :meth:`asyncio.loop.call_soon` - The :mod:`asyncio` equivalent. - """ - - def run_callback_threadsafe(func, *args): - """ - Like :meth:`run_callback`, but for use from *outside* the - thread that is running this loop. - - This not only schedules the *func* to run, it also causes the - loop to notice that the *func* has been scheduled (e.g., it causes - the loop to wake up). - - .. versionadded:: 21.1.0 - - .. seealso:: :meth:`asyncio.loop.call_soon_threadsafe` - The :mod:`asyncio` equivalent. - """ - -class IWatcher(Interface): - """ - An event loop watcher. - - These objects call their *callback* function when the event - loop detects the event has happened. - - .. important:: You *must* call :meth:`close` when you are - done with this object to avoid leaking native resources. - """ - - def start(callback, *args, **kwargs): - """ - Have the event loop begin watching for this event. - - When the event is detected, *callback* will be called with - *args*. - - .. caution:: - - Not all watchers accept ``**kwargs``, - and some watchers define special meanings for certain keyword args. - """ - - def stop(): - """ - Have the event loop stop watching this event. - - In the future you may call :meth:`start` to begin watching - again. - """ - - def close(): - """ - Dispose of any native resources associated with the watcher. - - If we were active, stop. - - Attempting to operate on this object after calling close is - undefined. You should dispose of any references you have to it - after calling this method. - """ - -class ICallback(Interface): - """ - Represents a function that will be run some time in the future. - - Callback functions run in the hub, and as such they cannot use - gevent's blocking API; any exception they raise cannot be caught. - """ - - pending = schema.Bool(description=u"Has this callback run yet?", - readonly=True) - - def stop(): - """ - If this object is still `pending`, cause it to - no longer be `pending`; the function will not be run. - """ - - def close(): - """ - An alias of `stop`. - """ diff --git a/venv/lib/python3.9/site-packages/gevent/_monitor.py b/venv/lib/python3.9/site-packages/gevent/_monitor.py deleted file mode 100644 index 8bac288..0000000 --- a/venv/lib/python3.9/site-packages/gevent/_monitor.py +++ /dev/null @@ -1,327 +0,0 @@ -# Copyright (c) 2018 gevent. See LICENSE for details. -from __future__ import print_function, absolute_import, division - -import os -import sys - -from weakref import ref as wref - -from greenlet import getcurrent - -from gevent import config as GEVENT_CONFIG -from gevent.monkey import get_original -from gevent.events import notify -from gevent.events import EventLoopBlocked -from gevent.events import MemoryUsageThresholdExceeded -from gevent.events import MemoryUsageUnderThreshold -from gevent.events import IPeriodicMonitorThread -from gevent.events import implementer - -from gevent._tracer import GreenletTracer -from gevent._compat import thread_mod_name -from gevent._compat import perf_counter -from gevent._compat import get_this_psutil_process - - - -__all__ = [ - 'PeriodicMonitoringThread', -] - -get_thread_ident = get_original(thread_mod_name, 'get_ident') -start_new_thread = get_original(thread_mod_name, 'start_new_thread') -thread_sleep = get_original('time', 'sleep') - - - -class MonitorWarning(RuntimeWarning): - """The type of warnings we emit.""" - - -class _MonitorEntry(object): - - __slots__ = ('function', 'period', 'last_run_time') - - def __init__(self, function, period): - self.function = function - self.period = period - self.last_run_time = 0 - - def __eq__(self, other): - return self.function == other.function and self.period == other.period - - def __hash__(self): - return hash((self.function, self.period)) - - def __repr__(self): - return repr((self.function, self.period, self.last_run_time)) - - -@implementer(IPeriodicMonitorThread) -class PeriodicMonitoringThread(object): - # This doesn't extend threading.Thread because that gets monkey-patched. - # We use the low-level 'start_new_thread' primitive instead. - - # The amount of seconds we will sleep when we think we have nothing - # to do. - inactive_sleep_time = 2.0 - - # The absolute minimum we will sleep, regardless of - # what particular monitoring functions want to say. - min_sleep_time = 0.005 - - # The minimum period in seconds at which we will check memory usage. - # Getting memory usage is fairly expensive. - min_memory_monitor_period = 2 - - # A list of _MonitorEntry objects: [(function(hub), period, last_run_time))] - # The first entry is always our entry for self.monitor_blocking - _monitoring_functions = None - - # The calculated min sleep time for the monitoring functions list. - _calculated_sleep_time = None - - # A boolean value that also happens to capture the - # memory usage at the time we exceeded the threshold. Reset - # to 0 when we go back below. - _memory_exceeded = 0 - - # The instance of GreenletTracer we're using - _greenlet_tracer = None - - def __init__(self, hub): - self._hub_wref = wref(hub, self._on_hub_gc) - self.should_run = True - - # Must be installed in the thread that the hub is running in; - # the trace function is threadlocal - assert get_thread_ident() == hub.thread_ident - self._greenlet_tracer = GreenletTracer() - - self._monitoring_functions = [_MonitorEntry(self.monitor_blocking, - GEVENT_CONFIG.max_blocking_time)] - self._calculated_sleep_time = GEVENT_CONFIG.max_blocking_time - # Create the actual monitoring thread. This is effectively a "daemon" - # thread. - self.monitor_thread_ident = start_new_thread(self, ()) - - # We must track the PID to know if your thread has died after a fork - self.pid = os.getpid() - - def _on_fork(self): - # Pseudo-standard method that resolver_ares and threadpool - # also have, called by hub.reinit() - pid = os.getpid() - if pid != self.pid: - self.pid = pid - self.monitor_thread_ident = start_new_thread(self, ()) - - @property - def hub(self): - return self._hub_wref() - - - def monitoring_functions(self): - # Return a list of _MonitorEntry objects - - # Update max_blocking_time each time. - mbt = GEVENT_CONFIG.max_blocking_time # XXX: Events so we know when this changes. - if mbt != self._monitoring_functions[0].period: - self._monitoring_functions[0].period = mbt - self._calculated_sleep_time = min(x.period for x in self._monitoring_functions) - return self._monitoring_functions - - def add_monitoring_function(self, function, period): - if not callable(function): - raise ValueError("function must be callable") - - if period is None: - # Remove. - self._monitoring_functions = [ - x for x in self._monitoring_functions - if x.function != function - ] - elif period <= 0: - raise ValueError("Period must be positive.") - else: - # Add or update period - entry = _MonitorEntry(function, period) - self._monitoring_functions = [ - x if x.function != function else entry - for x in self._monitoring_functions - ] - if entry not in self._monitoring_functions: - self._monitoring_functions.append(entry) - self._calculated_sleep_time = min(x.period for x in self._monitoring_functions) - - def calculate_sleep_time(self): - min_sleep = self._calculated_sleep_time - if min_sleep <= 0: - # Everyone wants to be disabled. Sleep for a longer period of - # time than usual so we don't spin unnecessarily. We might be - # enabled again in the future. - return self.inactive_sleep_time - return max((min_sleep, self.min_sleep_time)) - - def kill(self): - if not self.should_run: - # Prevent overwriting trace functions. - return - # Stop this monitoring thread from running. - self.should_run = False - # Uninstall our tracing hook - self._greenlet_tracer.kill() - - def _on_hub_gc(self, _): - self.kill() - - def __call__(self): - # The function that runs in the monitoring thread. - # We cannot use threading.current_thread because it would - # create an immortal DummyThread object. - getcurrent().gevent_monitoring_thread = wref(self) - - try: - while self.should_run: - functions = self.monitoring_functions() - assert functions - sleep_time = self.calculate_sleep_time() - - thread_sleep(sleep_time) - - # Make sure the hub is still around, and still active, - # and keep it around while we are here. - hub = self.hub - if not hub: - self.kill() - - if self.should_run: - this_run = perf_counter() - for entry in functions: - f = entry.function - period = entry.period - last_run = entry.last_run_time - if period and last_run + period <= this_run: - entry.last_run_time = this_run - f(hub) - del hub # break our reference to hub while we sleep - - except SystemExit: - pass - except: # pylint:disable=bare-except - # We're a daemon thread, so swallow any exceptions that get here - # during interpreter shutdown. - if not sys or not sys.stderr: # pragma: no cover - # Interpreter is shutting down - pass - else: - hub = self.hub - if hub is not None: - # XXX: This tends to do bad things like end the process, because we - # try to switch *threads*, which can't happen. Need something better. - hub.handle_error(self, *sys.exc_info()) - - def monitor_blocking(self, hub): - # Called periodically to see if the trace function has - # fired to switch greenlets. If not, we will print - # the greenlet tree. - - # For tests, we return a true value when we think we found something - # blocking - - did_block = self._greenlet_tracer.did_block_hub(hub) - if not did_block: - return - - active_greenlet = did_block[1] # pylint:disable=unsubscriptable-object - report = self._greenlet_tracer.did_block_hub_report( - hub, active_greenlet, - dict(greenlet_stacks=False, current_thread_ident=self.monitor_thread_ident)) - - # Notify the event first. ``report`` is a mutable list, so the event listeners - # may mutate it to add or remove information. - notify(EventLoopBlocked(active_greenlet, - GEVENT_CONFIG.max_blocking_time, report, - hub=hub)) - - # Do the actual reporting in a separate function so that - # it can be overridden at runtime, for example, to use a dedicated - # file. If you find this useful enough that the interface should be formalized, - # please file an issue. - return self._show_blocking_report(hub, report, active_greenlet) - - - def _show_blocking_report(self, hub, report, active_greenlet): - if GEVENT_CONFIG.print_blocking_reports: - stream = hub.exception_stream - for line in report: - # Printing line by line may interleave with other things, - # but it should also prevent a "reentrant call to print" - # when the report is large. - print(line, file=stream) - return (active_greenlet, report) - - def ignore_current_greenlet_blocking(self): - self._greenlet_tracer.ignore_current_greenlet_blocking() - - def monitor_current_greenlet_blocking(self): - self._greenlet_tracer.monitor_current_greenlet_blocking() - - def _get_process(self): # pylint:disable=method-hidden - proc = get_this_psutil_process() - self._get_process = lambda: proc - return proc - - def can_monitor_memory_usage(self): - return self._get_process() is not None - - def install_monitor_memory_usage(self): - # Start monitoring memory usage, if possible. - # If not possible, emit a warning. - if not self.can_monitor_memory_usage(): - import warnings - warnings.warn("Unable to monitor memory usage. Install psutil.", - MonitorWarning) - return - - self.add_monitoring_function(self.monitor_memory_usage, - max(GEVENT_CONFIG.memory_monitor_period, - self.min_memory_monitor_period)) - - def monitor_memory_usage(self, _hub): - max_allowed = GEVENT_CONFIG.max_memory_usage - if not max_allowed: - # They disabled it. - return -1 # value for tests - - rusage = self._get_process().memory_full_info() - # uss only documented available on Windows, Linux, and OS X. - # If not available, fall back to rss as an aproximation. - mem_usage = getattr(rusage, 'uss', 0) or rusage.rss - - event = None # Return value for tests - - if mem_usage > max_allowed: - if mem_usage > self._memory_exceeded: - # We're still growing - event = MemoryUsageThresholdExceeded( - mem_usage, max_allowed, rusage) - notify(event) - self._memory_exceeded = mem_usage - else: - # we're below. Were we above it last time? - if self._memory_exceeded: - event = MemoryUsageUnderThreshold( - mem_usage, max_allowed, rusage, self._memory_exceeded) - notify(event) - self._memory_exceeded = 0 - - return event - - def __repr__(self): - return '<%s at %s in thread %s greenlet %r for %r>' % ( - self.__class__.__name__, - hex(id(self)), - hex(self.monitor_thread_ident), - getcurrent(), - self._hub_wref()) diff --git a/venv/lib/python3.9/site-packages/gevent/_patcher.py b/venv/lib/python3.9/site-packages/gevent/_patcher.py deleted file mode 100644 index d5b69cb..0000000 --- a/venv/lib/python3.9/site-packages/gevent/_patcher.py +++ /dev/null @@ -1,252 +0,0 @@ -# Copyright 2018 gevent. See LICENSE for details. - -# Portions of the following are inspired by code from eventlet. I -# believe they are distinct enough that no eventlet copyright would -# apply (they are not a copy or substantial portion of the eventlot -# code). - -# Added in gevent 1.3a2. Not public in that release. - -from __future__ import absolute_import, print_function - -import importlib -import sys - - -from gevent._compat import iteritems -from gevent._compat import imp_acquire_lock -from gevent._compat import imp_release_lock - - -from gevent.builtins import __import__ as g_import - - -MAPPING = { - 'gevent.local': '_threading_local', - 'gevent.socket': 'socket', - 'gevent.select': 'select', - 'gevent.selectors': 'selectors', - 'gevent.ssl': 'ssl', - 'gevent.thread': '_thread', - 'gevent.subprocess': 'subprocess', - 'gevent.os': 'os', - 'gevent.threading': 'threading', - 'gevent.builtins': 'builtins', - 'gevent.signal': 'signal', - 'gevent.time': 'time', - 'gevent.queue': 'queue', - 'gevent.contextvars': 'contextvars', -} - -OPTIONAL_STDLIB_MODULES = frozenset() -_PATCH_PREFIX = '__g_patched_module_' - -def _collect_stdlib_gevent_modules(): - """ - Return a map from standard library name to - imported gevent module that provides the same API. - - Optional modules are skipped if they cannot be imported. - """ - result = {} - - for gevent_name, stdlib_name in iteritems(MAPPING): - try: - result[stdlib_name] = importlib.import_module(gevent_name) - except ImportError: - if stdlib_name in OPTIONAL_STDLIB_MODULES: - continue - raise - return result - - -class _SysModulesPatcher(object): - - def __init__(self, importing, extra_all=lambda mod_name: ()): - # Permanent state. - self.extra_all = extra_all - self.importing = importing - # green modules, replacing regularly imported modules. - # This begins as the gevent list of modules, and - # then gets extended with green things from the tree we import. - self._green_modules = _collect_stdlib_gevent_modules() - - ## Transient, reset each time we're called. - # The set of things imported before we began. - self._t_modules_to_restore = {} - - def _save(self): - self._t_modules_to_restore = {} - - # Copy all the things we know we are going to overwrite. - for modname in self._green_modules: - self._t_modules_to_restore[modname] = sys.modules.get(modname, None) - - # Copy anything else in the import tree. - for modname, mod in list(iteritems(sys.modules)): - if modname.startswith(self.importing): - self._t_modules_to_restore[modname] = mod - # And remove it. If it had been imported green, it will - # be put right back. Otherwise, it was imported "manually" - # outside this process and isn't green. - del sys.modules[modname] - - # Cover the target modules so that when you import the module it - # sees only the patched versions - for name, mod in iteritems(self._green_modules): - sys.modules[name] = mod - - def _restore(self): - # Anything from the same package tree we imported this time - # needs to be saved so we can restore it later, and so it doesn't - # leak into the namespace. - - for modname, mod in list(iteritems(sys.modules)): - if modname.startswith(self.importing): - self._green_modules[modname] = mod - del sys.modules[modname] - - # Now, what we saved at the beginning needs to be restored. - for modname, mod in iteritems(self._t_modules_to_restore): - if mod is not None: - sys.modules[modname] = mod - else: - try: - del sys.modules[modname] - except KeyError: - pass - - def __exit__(self, t, v, tb): - try: - self._restore() - finally: - imp_release_lock() - self._t_modules_to_restore = None - - - def __enter__(self): - imp_acquire_lock() - self._save() - return self - - module = None - - def __call__(self, after_import_hook): - if self.module is None: - with self: - self.module = self.import_one(self.importing, after_import_hook) - # Circular reference. Someone must keep a reference to this module alive - # for it to be visible. We record it in sys.modules to be that someone, and - # to aid debugging. In the past, we worked with multiple completely separate - # invocations of `import_patched`, but we no longer do. - self.module.__gevent_patcher__ = self - sys.modules[_PATCH_PREFIX + self.importing] = self.module - return self - - def import_one(self, module_name, after_import_hook): - patched_name = _PATCH_PREFIX + module_name - if patched_name in sys.modules: - return sys.modules[patched_name] - - assert module_name.startswith(self.importing) - sys.modules.pop(module_name, None) - - module = g_import(module_name, {}, {}, module_name.split('.')[:-1]) - self.module = module - # On Python 3, we could probably do something much nicer with the - # import machinery? Set the __loader__ or __finder__ or something like that? - self._import_all([module]) - after_import_hook(module) - return module - - def _import_all(self, queue): - # Called while monitoring for patch changes. - while queue: - module = queue.pop(0) - name = module.__name__ - mod_all = tuple(getattr(module, '__all__', ())) + self.extra_all(name) - for attr_name in mod_all: - try: - getattr(module, attr_name) - except AttributeError: - module_name = module.__name__ + '.' + attr_name - new_module = g_import(module_name, {}, {}, attr_name) - setattr(module, attr_name, new_module) - queue.append(new_module) - - -def import_patched(module_name, - extra_all=lambda mod_name: (), - after_import_hook=lambda module: None): - """ - Import *module_name* with gevent monkey-patches active, - and return an object holding the greened module as *module*. - - Any sub-modules that were imported by the package are also - saved. - - .. versionchanged:: 1.5a4 - If the module defines ``__all__``, then each of those - attributes/modules is also imported as part of the same transaction, - recursively. The order of ``__all__`` is respected. Anything passed in - *extra_all* (which must be in the same namespace tree) is also imported. - - .. versionchanged:: 1.5a4 - You must now do all patching for a given module tree - with one call to this method, or at least by using the returned - object. - """ - - with cached_platform_architecture(): - # Save the current module state, and restore on exit, - # capturing desirable changes in the modules package. - patcher = _SysModulesPatcher(module_name, extra_all) - patcher(after_import_hook) - return patcher - - -class cached_platform_architecture(object): - """ - Context manager that caches ``platform.architecture``. - - Some things that load shared libraries (like Cryptodome, via - dnspython) invoke ``platform.architecture()`` for each one. That - in turn wants to fork and run commands , which in turn wants to - call ``threading._after_fork`` if the GIL has been initialized. - All of that means that certain imports done early may wind up - wanting to have the hub initialized potentially much earlier than - before. - - Part of the fix is to observe when that happens and delay - initializing parts of gevent until as late as possible (e.g., we - delay importing and creating the resolver until the hub needs it, - unless explicitly configured). - - The rest of the fix is to avoid the ``_after_fork`` issues by - first caching the results of platform.architecture before doing - patched imports. - - (See events.py for similar issues with platform, and - test__threading_2.py for notes about threading._after_fork if the - GIL has been initialized) - """ - - _arch_result = None - _orig_arch = None - _platform = None - - def __enter__(self): - import platform - self._platform = platform - self._arch_result = platform.architecture() - self._orig_arch = platform.architecture - def arch(*args, **kwargs): - if not args and not kwargs: - return self._arch_result - return self._orig_arch(*args, **kwargs) - platform.architecture = arch - return self - - def __exit__(self, *_args): - self._platform.architecture = self._orig_arch - self._platform = None diff --git a/venv/lib/python3.9/site-packages/gevent/_semaphore.py b/venv/lib/python3.9/site-packages/gevent/_semaphore.py deleted file mode 100644 index 0b262c3..0000000 --- a/venv/lib/python3.9/site-packages/gevent/_semaphore.py +++ /dev/null @@ -1,527 +0,0 @@ -# cython: auto_pickle=False,embedsignature=True,always_allow_keywords=False -### -# This file is ``gevent._semaphore`` so that it can be compiled by Cython -# individually. However, this is not the place to import from. Everyone, -# gevent internal code included, must import from ``gevent.lock``. -# The only exception are .pxd files which need access to the -# C code; the PURE_PYTHON things that have to happen and which are -# handled in ``gevent.lock``, do not apply to them. -### -from __future__ import print_function, absolute_import, division - -__all__ = [ - 'Semaphore', - 'BoundedSemaphore', -] - -from time import sleep as _native_sleep - -from gevent._compat import monotonic -from gevent.exceptions import InvalidThreadUseError -from gevent.exceptions import LoopExit -from gevent.timeout import Timeout - -def _get_linkable(): - x = __import__('gevent._abstract_linkable') - return x._abstract_linkable.AbstractLinkable -locals()['AbstractLinkable'] = _get_linkable() -del _get_linkable - -from gevent._hub_local import get_hub_if_exists -from gevent._hub_local import get_hub -from gevent.hub import spawn_raw - -class _LockReleaseLink(object): - __slots__ = ( - 'lock', - ) - - def __init__(self, lock): - self.lock = lock - - def __call__(self, _): - self.lock.release() - -_UNSET = object() -_MULTI = object() - -class Semaphore(AbstractLinkable): # pylint:disable=undefined-variable - """ - Semaphore(value=1) -> Semaphore - - .. seealso:: :class:`BoundedSemaphore` for a safer version that prevents - some classes of bugs. If unsure, most users should opt for `BoundedSemaphore`. - - A semaphore manages a counter representing the number of `release` - calls minus the number of `acquire` calls, plus an initial value. - The `acquire` method blocks if necessary until it can return - without making the counter negative. A semaphore does not track ownership - by greenlets; any greenlet can call `release`, whether or not it has previously - called `acquire`. - - If not given, ``value`` defaults to 1. - - The semaphore is a context manager and can be used in ``with`` statements. - - This Semaphore's ``__exit__`` method does not call the trace function - on CPython, but does under PyPy. - - .. versionchanged:: 1.4.0 - Document that the order in which waiters are awakened is not specified. It was not - specified previously, but due to CPython implementation quirks usually went in FIFO order. - .. versionchanged:: 1.5a3 - Waiting greenlets are now awakened in the order in which they waited. - .. versionchanged:: 1.5a3 - The low-level ``rawlink`` method (most users won't use this) now automatically - unlinks waiters before calling them. - .. versionchanged:: 20.12.0 - Improved support for multi-threaded usage. When multi-threaded usage is detected, - instances will no longer create the thread's hub if it's not present. - - .. versionchanged:: 24.2.1 - Uses Python 3 native lock timeouts for cross-thread operations instead - of spinning. - """ - - __slots__ = ( - 'counter', - # long integer, signed (Py2) or unsigned (Py3); see comments - # in the .pxd file for why we store as Python object. Set to ``_UNSET`` - # initially. Set to the ident of the first thread that - # acquires us. If we later see a different thread ident, set - # to ``_MULTI``. - '_multithreaded', - ) - - def __init__(self, value=1, hub=None): - self.counter = value - if self.counter < 0: # Do the check after Cython native int conversion - raise ValueError("semaphore initial value must be >= 0") - super(Semaphore, self).__init__(hub) - self._notify_all = False - self._multithreaded = _UNSET - - def __str__(self): - return '<%s at 0x%x counter=%s _links[%s]>' % ( - self.__class__.__name__, - id(self), - self.counter, - self.linkcount() - ) - - def locked(self): - """ - Return a boolean indicating whether the semaphore can be - acquired (`False` if the semaphore *can* be acquired). Most - useful with binary semaphores (those with an initial value of 1). - - :rtype: bool - """ - return self.counter <= 0 - - def release(self): - """ - Release the semaphore, notifying any waiters if needed. There - is no return value. - - .. note:: - - This can be used to over-release the semaphore. - (Release more times than it has been acquired or was initially - created with.) - - This is usually a sign of a bug, but under some circumstances it can be - used deliberately, for example, to model the arrival of additional - resources. - - :rtype: None - """ - self.counter += 1 - self._check_and_notify() - return self.counter - - def ready(self): - """ - Return a boolean indicating whether the semaphore can be - acquired (`True` if the semaphore can be acquired). - - :rtype: bool - """ - return self.counter > 0 - - def _start_notify(self): - self._check_and_notify() - - def _wait_return_value(self, waited, wait_success): - if waited: - return wait_success - # We didn't even wait, we must be good to go. - # XXX: This is probably dead code, we're careful not to go into the wait - # state if we don't expect to need to - return True - - def wait(self, timeout=None): - """ - Wait until it is possible to acquire this semaphore, or until the optional - *timeout* elapses. - - .. note:: If this semaphore was initialized with a *value* of 0, - this method will block forever if no timeout is given. - - :keyword float timeout: If given, specifies the maximum amount of seconds - this method will block. - :return: A number indicating how many times the semaphore can be acquired - before blocking. *This could be 0,* if other waiters acquired - the semaphore. - :rtype: int - """ - if self.counter > 0: - return self.counter - - self._wait(timeout) # return value irrelevant, whether we got it or got a timeout - return self.counter - - def acquire(self, blocking=True, timeout=None): - """ - acquire(blocking=True, timeout=None) -> bool - - Acquire the semaphore. - - .. note:: If this semaphore was initialized with a *value* of 0, - this method will block forever (unless a timeout is given or blocking is - set to false). - - :keyword bool blocking: If True (the default), this function will block - until the semaphore is acquired. - :keyword float timeout: If given, and *blocking* is true, - specifies the maximum amount of seconds - this method will block. - :return: A `bool` indicating whether the semaphore was acquired. - If ``blocking`` is True and ``timeout`` is None (the default), then - (so long as this semaphore was initialized with a size greater than 0) - this will always return True. If a timeout was given, and it expired before - the semaphore was acquired, False will be returned. (Note that this can still - raise a ``Timeout`` exception, if some other caller had already started a timer.) - """ - # pylint:disable=too-many-return-statements,too-many-branches - # Sadly, the body of this method is rather complicated. - if self._multithreaded is _UNSET: - self._multithreaded = self._get_thread_ident() - elif self._multithreaded != self._get_thread_ident(): - self._multithreaded = _MULTI - - # We conceptually now belong to the hub of the thread that - # called this, whether or not we have to block. Note that we - # cannot force it to be created yet, because Semaphore is used - # by importlib.ModuleLock which is used when importing the hub - # itself! This also checks for cross-thread issues. - invalid_thread_use = None - try: - self._capture_hub(False) - except InvalidThreadUseError as e: - # My hub belongs to some other thread. We didn't release the GIL/object lock - # by raising the exception, so we know this is still true. - invalid_thread_use = e.args - e = None - if not self.counter and blocking: - # We would need to block. So coordinate with the main hub. - return self.__acquire_from_other_thread(invalid_thread_use, blocking, timeout) - - if self.counter > 0: - self.counter -= 1 - return True - - if not blocking: - return False - - if self._multithreaded is not _MULTI and self.hub is None: # pylint:disable=access-member-before-definition - self.hub = get_hub() # pylint:disable=attribute-defined-outside-init - - if self.hub is None and not invalid_thread_use: - # Someone else is holding us. There's not a hub here, - # nor is there a hub in that thread. We'll need to use regular locks. - # This will be unfair to yet a third thread that tries to use us with greenlets. - return self.__acquire_from_other_thread( - (None, None, self._getcurrent(), "NoHubs"), - blocking, - timeout - ) - - # self._wait may drop both the GIL and the _lock_lock. - # By the time we regain control, both have been reacquired. - try: - success = self._wait(timeout) - except LoopExit as ex: - args = ex.args - ex = None - if self.counter: - success = True - else: - # Avoid using ex.hub property to keep holding the GIL - if len(args) == 3 and args[1].main_hub: - # The main hub, meaning the main thread. We probably can do nothing with this. - raise - return self.__acquire_from_other_thread( - (self.hub, get_hub_if_exists(), self._getcurrent(), "LoopExit"), - blocking, - timeout) - - if not success: - assert timeout is not None - # Our timer expired. - return False - - # Neither our timer or another one expired, so we blocked until - # awoke. Therefore, the counter is ours - assert self.counter > 0, (self.counter, blocking, timeout, success,) - self.counter -= 1 - return True - - _py3k_acquire = acquire # PyPy needs this; it must be static for Cython - - def __enter__(self): - self.acquire() - - def __exit__(self, t, v, tb): - self.release() - - def _handle_unswitched_notifications(self, unswitched): - # If we fail to switch to a greenlet in another thread to send - # a notification, just re-queue it, in the hopes that the - # other thread will eventually run notifications itself. - # - # We CANNOT do what the ``super()`` does and actually allow - # this notification to get run sometime in the future by - # scheduling a callback in the other thread. The algorithm - # that we use to handle cross-thread locking/unlocking was - # designed before the schedule-a-callback mechanism was - # implemented. If we allow this to be run as a callback, we - # can find ourself the victim of ``InvalidSwitchError`` (or - # worse, silent corruption) because the switch can come at an - # unexpected time: *after* the destination thread has already - # acquired the lock. - # - # This manifests in a fairly reliable test failure, - # ``gevent.tests.test__semaphore`` - # ``TestSemaphoreMultiThread.test_dueling_threads_with_hub``, - # but ONLY when running in PURE_PYTHON mode. - # - # TODO: Maybe we can rewrite that part of the algorithm to be friendly to - # running the callbacks? - self._links.extend(unswitched) - - def __add_link(self, link): - if not self._notifier: - self.rawlink(link) - else: - self._notifier.args[0].append(link) - - def __acquire_from_other_thread(self, ex_args, blocking, timeout): - assert blocking - # Some other hub owns this object. We must ask it to wake us - # up. In general, we can't use a Python-level ``Lock`` because - # - # (1) it doesn't support a timeout on all platforms; and - # (2) we don't want to block this hub from running. - # - # So we need to do so in a way that cooperates with *two* - # hubs. That's what an async watcher is built for. - # - # Of course, if we don't actually have two hubs, then we must find some other - # solution. That involves using a lock. - - # We have to take an action that drops the GIL and drops the object lock - # to allow the main thread (the thread for our hub) to advance. - owning_hub = ex_args[0] - hub_for_this_thread = ex_args[1] - current_greenlet = ex_args[2] - - if owning_hub is None and hub_for_this_thread is None: - return self.__acquire_without_hubs(timeout) - - if hub_for_this_thread is None: - # Probably a background worker thread. We don't want to create - # the hub if not needed, and since it didn't exist there are no - # other greenlets that we could yield to anyway, so there's nothing - # to block and no reason to try to avoid blocking, so using a native - # lock is the simplest way to go. - return self.__acquire_using_other_hub(owning_hub, timeout) - - # We have a hub we don't want to block. Use an async watcher - # and ask the next releaser of this object to wake us up. - return self.__acquire_using_two_hubs(hub_for_this_thread, - current_greenlet, - timeout) - - def __acquire_using_two_hubs(self, - hub_for_this_thread, - current_greenlet, - timeout): - # Allocating and starting the watcher *could* release the GIL. - # with the libev corcext, allocating won't, but starting briefly will. - # With other backends, allocating might, and starting might also. - # So... - watcher = hub_for_this_thread.loop.async_() - send = watcher.send_ignoring_arg - watcher.start(current_greenlet.switch, self) - try: - with Timeout._start_new_or_dummy(timeout) as timer: - # ... now that we're back holding the GIL, we need to verify our - # state. - try: - while 1: - if self.counter > 0: - self.counter -= 1 - assert self.counter >= 0, (self,) - return True - - self.__add_link(send) - - # Releases the object lock - self._switch_to_hub(hub_for_this_thread) - # We waited and got notified. We should be ready now, so a non-blocking - # acquire() should succeed. But sometimes we get spurious notifications? - # It's not entirely clear how. So we need to loop until we get it, or until - # the timer expires - result = self.acquire(0) - if result: - return result - except Timeout as tex: - if tex is not timer: - raise - return False - finally: - self._quiet_unlink_all(send) - watcher.stop() - watcher.close() - - def __acquire_from_other_thread_cb(self, results, blocking, timeout, thread_lock): - try: - result = self.acquire(blocking, timeout) - results.append(result) - finally: - thread_lock.release() - return result - - def __acquire_using_other_hub(self, owning_hub, timeout): - assert owning_hub is not get_hub_if_exists() - thread_lock = self._allocate_lock() - thread_lock.acquire() - results = [] - - owning_hub.loop.run_callback_threadsafe( - spawn_raw, - self.__acquire_from_other_thread_cb, - results, - 1, # blocking, - timeout, # timeout, - thread_lock) - - # We MUST use a blocking acquire here, or at least be sure we keep going - # until we acquire it. If we timed out waiting here, - # just before the callback runs, then we would be out of sync. - self.__spin_on_native_lock(thread_lock, None) - return results[0] - - def __acquire_without_hubs(self, timeout): - thread_lock = self._allocate_lock() - thread_lock.acquire() - absolute_expiration = 0 - begin = 0 - if timeout: - absolute_expiration = monotonic() + timeout - - # Cython won't compile a lambda here - link = _LockReleaseLink(thread_lock) - while 1: - self.__add_link(link) - if absolute_expiration: - begin = monotonic() - - got_native = self.__spin_on_native_lock(thread_lock, timeout) - self._quiet_unlink_all(link) - if got_native: - if self.acquire(0): - return True - if absolute_expiration: - now = monotonic() - if now >= absolute_expiration: - return False - duration = now - begin - timeout -= duration - if timeout <= 0: - return False - - def __spin_on_native_lock(self, thread_lock, timeout): - self._drop_lock_for_switch_out() - try: - # Unlike Python 2, Python 3 thread locks - # can be interrupted when blocking, with or - # without a timeout. Python 2 didn't even - # support a timeout for non -blocking. - if timeout: - return thread_lock.acquire(True, timeout) - - return thread_lock.acquire() - finally: - self._acquire_lock_for_switch_in() - - -class BoundedSemaphore(Semaphore): - """ - BoundedSemaphore(value=1) -> BoundedSemaphore - - A bounded semaphore checks to make sure its current value doesn't - exceed its initial value. If it does, :class:`ValueError` is - raised. In most situations semaphores are used to guard resources - with limited capacity. If the semaphore is released too many times - it's a sign of a bug. - - If not given, *value* defaults to 1. - """ - - __slots__ = ( - '_initial_value', - ) - - #: For monkey-patching, allow changing the class of error we raise - _OVER_RELEASE_ERROR = ValueError - - def __init__(self, *args, **kwargs): - Semaphore.__init__(self, *args, **kwargs) - self._initial_value = self.counter - - def release(self): - """ - Like :meth:`Semaphore.release`, but raises :class:`ValueError` - if the semaphore is being over-released. - """ - if self.counter >= self._initial_value: - raise self._OVER_RELEASE_ERROR("Semaphore released too many times") - counter = Semaphore.release(self) - # When we are absolutely certain that no one holds this semaphore, - # release our hub and go back to floating. This assists in cross-thread - # uses. - if counter == self._initial_value: - self.hub = None # pylint:disable=attribute-defined-outside-init - return counter - - def _at_fork_reinit(self): - super(BoundedSemaphore, self)._at_fork_reinit() - self.counter = self._initial_value - - -# By building the semaphore with Cython under PyPy, we get -# atomic operations (specifically, exiting/releasing), at the -# cost of some speed (one trivial semaphore micro-benchmark put the pure-python version -# at around 1s and the compiled version at around 4s). Some clever subclassing -# and having only the bare minimum be in cython might help reduce that penalty. -# NOTE: You must use version 0.23.4 or later to avoid a memory leak. -# https://mail.python.org/pipermail/cython-devel/2015-October/004571.html -# However, that's all for naught on up to and including PyPy 4.0.1 which -# have some serious crashing bugs with GC interacting with cython. -# It hasn't been tested since then, and PURE_PYTHON is assumed to be true -# for PyPy in all cases anyway, so this does nothing. - -from gevent._util import import_c_accel -import_c_accel(globals(), 'gevent.__semaphore') diff --git a/venv/lib/python3.9/site-packages/gevent/_socket3.py b/venv/lib/python3.9/site-packages/gevent/_socket3.py deleted file mode 100644 index 555ec61..0000000 --- a/venv/lib/python3.9/site-packages/gevent/_socket3.py +++ /dev/null @@ -1,663 +0,0 @@ -# Port of Python 3.3's socket module to gevent -""" -Python 3 socket module. -""" -# Our import magic sadly makes this warning useless -# pylint: disable=undefined-variable -# pylint: disable=too-many-statements,too-many-branches -# pylint: disable=too-many-public-methods,unused-argument -from __future__ import absolute_import -import io -import os - - -from gevent import _socketcommon -from gevent._util import copy_globals -from gevent._compat import PYPY -import _socket -from os import dup - - -copy_globals(_socketcommon, globals(), - names_to_ignore=_socketcommon.__extensions__, - dunder_names_to_keep=()) - - -__socket__ = _socketcommon.__socket__ -__implements__ = _socketcommon._implements -__extensions__ = _socketcommon.__extensions__ -__imports__ = _socketcommon.__imports__ -__dns__ = _socketcommon.__dns__ - - -SocketIO = __socket__.SocketIO # pylint:disable=no-member - - -class _closedsocket(object): - __slots__ = ('family', 'type', 'proto', 'orig_fileno', 'description') - - def __init__(self, family, type, proto, orig_fileno, description): - self.family = family - self.type = type - self.proto = proto - self.orig_fileno = orig_fileno - self.description = description - - def fileno(self): - return -1 - - def close(self): - "No-op" - - detach = fileno - - def _dummy(*args, **kwargs): # pylint:disable=no-method-argument,unused-argument,no-self-argument - raise OSError(EBADF, 'Bad file descriptor') - # All _delegate_methods must also be initialized here. - send = recv = recv_into = sendto = recvfrom = recvfrom_into = _dummy - getsockname = _dummy - - def __bool__(self): - return False - - __getattr__ = _dummy - - def __repr__(self): - return "" % ( - id(self), - self.orig_fileno, - self.description, - ) - -class _wrefsocket(_socket.socket): - # Plain stdlib socket.socket objects subclass _socket.socket - # and add weakref ability. The ssl module, for one, counts on this. - # We don't create socket.socket objects (because they may have been - # monkey patched to be the object from this module), but we still - # need to make sure what we do create can be weakrefd. - - __slots__ = ("__weakref__", ) - - if PYPY: - # server.py unwraps the socket object to get the raw _sock; - # it depends on having a timeout property alias, which PyPy does not - # provide. - timeout = property(lambda s: s.gettimeout(), - lambda s, nv: s.settimeout(nv)) - - -class socket(_socketcommon.SocketMixin): - """ - gevent `socket.socket `_ - for Python 3. - - This object should have the same API as the standard library socket linked to above. Not all - methods are specifically documented here; when they are they may point out a difference - to be aware of or may document a method the standard library does not. - """ - - # Subclasses can set this to customize the type of the - # native _socket.socket we create. It MUST be a subclass - # of _wrefsocket. (gevent internal usage only) - _gevent_sock_class = _wrefsocket - - __slots__ = ( - '_io_refs', - '_closed', - ) - - # Take the same approach as socket2: wrap a real socket object, - # don't subclass it. This lets code that needs the raw _sock (not tied to the hub) - # get it. This shows up in tests like test__example_udp_server. - - # In 3.7, socket changed to auto-detecting family, type, and proto - # when given a fileno. - def __init__(self, family=-1, type=-1, proto=-1, fileno=None): - super().__init__() - self._closed = False - if fileno is None: - if family == -1: - family = AddressFamily.AF_INET - if type == -1: - type = SOCK_STREAM - if proto == -1: - proto = 0 - self._sock = self._gevent_sock_class(family, type, proto, fileno) - self.timeout = None - - self._io_refs = 0 - _socket.socket.setblocking(self._sock, False) - fileno = _socket.socket.fileno(self._sock) - self.hub = get_hub() - io_class = self.hub.loop.io - self._read_event = io_class(fileno, 1) - self._write_event = io_class(fileno, 2) - self.timeout = _socket.getdefaulttimeout() - - def __getattr__(self, name): - return getattr(self._sock, name) - - def _accept(self): - # Python 3.11 started checking for this method on the class object, - # so we need to explicitly delegate. - return self._sock._accept() - - if hasattr(_socket, 'SOCK_NONBLOCK'): - # Only defined under Linux - @property - def type(self): - # See https://github.com/gevent/gevent/pull/399 - if self.timeout != 0.0: - return self._sock.type & ~_socket.SOCK_NONBLOCK # pylint:disable=no-member - return self._sock.type - - def __enter__(self): - return self - - def __exit__(self, *args): - if not self._closed: - self.close() - - def __repr__(self): - """Wrap __repr__() to reveal the real class name.""" - try: - s = repr(self._sock) - except Exception as ex: # pylint:disable=broad-except - # Observed on Windows Py3.3, printing the repr of a socket - # that just suffered a ConnectionResetError [WinError 10054]: - # "OverflowError: no printf formatter to display the socket descriptor in decimal" - # Not sure what the actual cause is or if there's a better way to handle this - s = '' % ex - - if s.startswith(" socket object - - Return a new socket object connected to the same system resource. - """ - fd = dup(self.fileno()) - sock = self.__class__(self.family, self.type, self.proto, fileno=fd) - sock.settimeout(self.gettimeout()) - return sock - - def accept(self): - """accept() -> (socket object, address info) - - Wait for an incoming connection. Return a new socket - representing the connection, and the address of the client. - For IP sockets, the address info is a pair (hostaddr, port). - """ - while True: - try: - fd, addr = self._accept() - break - except BlockingIOError: - if self.timeout == 0.0: - raise - self._wait(self._read_event) - sock = socket(self.family, self.type, self.proto, fileno=fd) - # Python Issue #7995: if no default timeout is set and the listening - # socket had a (non-zero) timeout, force the new socket in blocking - # mode to override platform-specific socket flags inheritance. - # XXX do we need to do this? - if getdefaulttimeout() is None and self.gettimeout(): - sock.setblocking(True) - return sock, addr - - def makefile(self, mode="r", buffering=None, *, - encoding=None, errors=None, newline=None): - """Return an I/O stream connected to the socket - - The arguments are as for io.open() after the filename, - except the only mode characters supported are 'r', 'w' and 'b'. - The semantics are similar too. - """ - # XXX refactor to share code? We ought to be able to use our FileObject, - # adding the appropriate amount of refcounting. At the very least we can use our - # OpenDescriptor to handle the parsing. - for c in mode: - if c not in {"r", "w", "b"}: - raise ValueError("invalid mode %r (only r, w, b allowed)") - writing = "w" in mode - reading = "r" in mode or not writing - assert reading or writing - binary = "b" in mode - rawmode = "" - if reading: - rawmode += "r" - if writing: - rawmode += "w" - raw = SocketIO(self, rawmode) - self._io_refs += 1 - if buffering is None: - buffering = -1 - if buffering < 0: - buffering = io.DEFAULT_BUFFER_SIZE - if buffering == 0: - if not binary: - raise ValueError("unbuffered streams must be binary") - return raw - if reading and writing: - buffer = io.BufferedRWPair(raw, raw, buffering) - elif reading: - buffer = io.BufferedReader(raw, buffering) - else: - assert writing - buffer = io.BufferedWriter(raw, buffering) - if binary: - return buffer - text = io.TextIOWrapper(buffer, encoding, errors, newline) - text.mode = mode - return text - - def _decref_socketios(self): - # Called by SocketIO when it is closed. - if self._io_refs > 0: - self._io_refs -= 1 - if self._closed: - self.close() - - def _drop_ref_on_close(self, sock): - # Send the close event to wake up any watchers we don't know about - # so that (hopefully) they can be closed before we destroy - # the FD and invalidate them. We may be in the hub running pending - # callbacks now, or this may take until the next iteration. - should_defer = self.hub.loop.closing_fd(sock.fileno()) - # Schedule the actual close to happen after that, but only if needed. - # (If we always defer, we wind up closing things much later than expected.) - # Note that if we're in the middle of running callbacks, simply scheduling - # a callback with ``run_callback`` could result in the callback being - # called IMMEDIATELY, which completely defeats the point. - if should_defer: - check = self.hub.loop.check() - def cb(s): - try: - s.close() - except OSError: - pass - finally: - check.stop() - check.close() - check.start(cb, sock) - else: - # Note that if the file descriptor got closed (``os.close``) - # closing the socket will now raise OSError: EBADF. The - # stdlib does the same. - sock.close() - - - def _detach_socket(self, reason): - if not self._sock: - return - - # Break any references to the underlying socket object. Tested - # by test__refcount. (Why does this matter?). Be sure to - # preserve our same family/type/proto if possible (if we - # don't, we can get TypeError instead of OSError; see - # test_socket.SendmsgUDP6Test.testSendmsgAfterClose)... but - # this isn't always possible (see test_socket.test_unknown_socket_family_repr) - sock = self._sock - family = -1 - type = -1 - proto = -1 - fileno = None - try: - family = sock.family - type = sock.type - proto = sock.proto - fileno = sock.fileno() - except OSError: - pass - # Break any reference to the loop.io objects. Our fileno, - # which they were tied to, is about to be free to be reused, so these - # objects are no longer functional. - # pylint:disable-next=superfluous-parens - self._drop_events_and_close(closefd=(reason == 'closed')) - - self._sock = _closedsocket(family, type, proto, fileno, reason) - - def _real_close(self, _ss=_socket.socket): - # This function should not reference any globals. See Python issue #808164. - if not self._sock: - return - - self._detach_socket('closed') - - - def close(self): - # This function should not reference any globals. See Python issue #808164. - self._closed = True - if self._io_refs <= 0: - self._real_close() - - @property - def closed(self): - return self._closed - - def detach(self): - """ - detach() -> file descriptor - - Close the socket object without closing the underlying file - descriptor. The object cannot be used after this call; when the - real file descriptor is closed, the number that was previously - used here may be reused. The fileno() method, after this call, - will return an invalid socket id. - - The previous descriptor is returned. - - .. versionchanged:: 1.5 - - Also immediately drop any native event loop resources. - """ - self._closed = True - sock = self._sock - self._detach_socket('detached') - return sock.detach() - - if hasattr(_socket.socket, 'recvmsg'): - # Only on Unix; PyPy 3.5 5.10.0 provides sendmsg and recvmsg, but not - # recvmsg_into (at least on os x) - - def recvmsg(self, *args): - while True: - try: - return self._sock.recvmsg(*args) - except error as ex: - if ex.args[0] != EWOULDBLOCK or self.timeout == 0.0: - raise - self._wait(self._read_event) - - if hasattr(_socket.socket, 'recvmsg_into'): - - def recvmsg_into(self, buffers, *args): - while True: - try: - if args: - # The C code is sensitive about whether extra arguments are - # passed or not. - return self._sock.recvmsg_into(buffers, *args) - return self._sock.recvmsg_into(buffers) - except error as ex: - if ex.args[0] != EWOULDBLOCK or self.timeout == 0.0: - raise - self._wait(self._read_event) - - if hasattr(_socket.socket, 'sendmsg'): - # Only on Unix - def sendmsg(self, buffers, ancdata=(), flags=0, address=None): - try: - return self._sock.sendmsg(buffers, ancdata, flags, address) - except error as ex: - if flags & getattr(_socket, 'MSG_DONTWAIT', 0): - # Enable non-blocking behaviour - # XXX: Do all platforms that have sendmsg have MSG_DONTWAIT? - raise - - if ex.args[0] != EWOULDBLOCK or self.timeout == 0.0: - raise - self._wait(self._write_event) - try: - return self._sock.sendmsg(buffers, ancdata, flags, address) - except error as ex2: - if ex2.args[0] == EWOULDBLOCK: - return 0 - raise - - - # sendfile: new in 3.5. But there's no real reason to not - # support it everywhere. Note that we can't use os.sendfile() - # because it's not cooperative. - def _sendfile_use_sendfile(self, file, offset=0, count=None): - # This is called directly by tests - raise __socket__._GiveupOnSendfile() # pylint:disable=no-member - - def _sendfile_use_send(self, file, offset=0, count=None): - self._check_sendfile_params(file, offset, count) - if self.gettimeout() == 0: - raise ValueError("non-blocking sockets are not supported") - if offset: - file.seek(offset) - blocksize = min(count, 8192) if count else 8192 - total_sent = 0 - # localize variable access to minimize overhead - file_read = file.read - sock_send = self.send - try: - while True: - if count: - blocksize = min(count - total_sent, blocksize) - if blocksize <= 0: - break - data = memoryview(file_read(blocksize)) - if not data: - break # EOF - while True: - try: - sent = sock_send(data) - except BlockingIOError: - continue - else: - total_sent += sent - if sent < len(data): - data = data[sent:] - else: - break - return total_sent - finally: - if total_sent > 0 and hasattr(file, 'seek'): - file.seek(offset + total_sent) - - def _check_sendfile_params(self, file, offset, count): - if 'b' not in getattr(file, 'mode', 'b'): - raise ValueError("file should be opened in binary mode") - if not self.type & SOCK_STREAM: - raise ValueError("only SOCK_STREAM type sockets are supported") - if count is not None: - if not isinstance(count, int): - raise TypeError( - "count must be a positive integer (got {!r})".format(count)) - if count <= 0: - raise ValueError( - "count must be a positive integer (got {!r})".format(count)) - - def sendfile(self, file, offset=0, count=None): - """sendfile(file[, offset[, count]]) -> sent - - Send a file until EOF is reached by using high-performance - os.sendfile() and return the total number of bytes which - were sent. - *file* must be a regular file object opened in binary mode. - If os.sendfile() is not available (e.g. Windows) or file is - not a regular file socket.send() will be used instead. - *offset* tells from where to start reading the file. - If specified, *count* is the total number of bytes to transmit - as opposed to sending the file until EOF is reached. - File position is updated on return or also in case of error in - which case file.tell() can be used to figure out the number of - bytes which were sent. - The socket must be of SOCK_STREAM type. - Non-blocking sockets are not supported. - - .. versionadded:: 1.1rc4 - Added in Python 3.5, but available under all Python 3 versions in - gevent. - """ - return self._sendfile_use_send(file, offset, count) - - - if os.name == 'nt': - def get_inheritable(self): - return os.get_handle_inheritable(self.fileno()) - - def set_inheritable(self, inheritable): - os.set_handle_inheritable(self.fileno(), inheritable) - else: - def get_inheritable(self): - return os.get_inheritable(self.fileno()) - - def set_inheritable(self, inheritable): - os.set_inheritable(self.fileno(), inheritable) - - get_inheritable.__doc__ = "Get the inheritable flag of the socket" - set_inheritable.__doc__ = "Set the inheritable flag of the socket" - - - -SocketType = socket - - -def fromfd(fd, family, type, proto=0): - """ fromfd(fd, family, type[, proto]) -> socket object - - Create a socket object from a duplicate of the given file - descriptor. The remaining arguments are the same as for socket(). - """ - nfd = dup(fd) - return socket(family, type, proto, nfd) - - -if hasattr(_socket.socket, "share"): - def fromshare(info): - """ fromshare(info) -> socket object - - Create a socket object from a the bytes object returned by - socket.share(pid). - """ - return socket(0, 0, 0, info) - - __implements__.append('fromshare') - - -def _fallback_socketpair(family=AF_INET, type=SOCK_STREAM, proto=0): - # We originally used https://gist.github.com/4325783, by Geert Jansen. (Public domain.) - # We took it from 3.6 release, confirmed unchanged in 3.7 and - # 3.8a1. Expected to be used only on Win. Added to Win/3.5. - # It is always available as `socket._fallback_socketpair` from at least 3.9, - # We would like to stop carrying around our own implementation, but - # using _fallback_socketpair directly would only work if we are monkey patched. - - # Current version taken from 3.13rc2 - - # PyPy doesn't name its fallback `_fallback_socketpair`, it uses - # an older copy of socket.py. - _LOCALHOST = '127.0.0.1' - _LOCALHOST_V6 = '::1' - - if family == AF_INET: - host = _LOCALHOST - elif family == AF_INET6: - host = _LOCALHOST_V6 - else: - raise ValueError("Only AF_INET and AF_INET6 socket address families " - "are supported") - if type != SOCK_STREAM: - raise ValueError("Only SOCK_STREAM socket type is supported") - if proto != 0: - raise ValueError("Only protocol zero is supported") - - # We create a connected TCP socket. Note the trick with - # setblocking(False) that prevents us from having to create a thread. - lsock = socket(family, type, proto) - try: - lsock.bind((host, 0)) - lsock.listen() - # On IPv6, ignore flow_info and scope_id - addr, port = lsock.getsockname()[:2] - csock = socket(family, type, proto) - try: - csock.setblocking(False) - try: - csock.connect((addr, port)) - except (BlockingIOError, InterruptedError): - pass - csock.setblocking(True) - ssock, _ = lsock.accept() - except: - csock.close() - raise - finally: - lsock.close() - - # Authenticating avoids using a connection from something else - # able to connect to {host}:{port} instead of us. - # We expect only AF_INET and AF_INET6 families. - try: - if ( - ssock.getsockname() != csock.getpeername() - or csock.getsockname() != ssock.getpeername() - ): - raise ConnectionError("Unexpected peer connection") - except: - # getsockname() and getpeername() can fail - # if either socket isn't connected. - ssock.close() - csock.close() - raise - - return (ssock, csock) - -if hasattr(__socket__, _fallback_socketpair.__name__): - __implements__.append(_fallback_socketpair.__name__) - -if hasattr(_socket, "socketpair"): - - def socketpair(family=None, type=SOCK_STREAM, proto=0): - """socketpair([family[, type[, proto]]]) -> (socket object, socket object) - - Create a pair of socket objects from the sockets returned by the platform - socketpair() function. - The arguments are the same as for socket() except the default family is - AF_UNIX if defined on the platform; otherwise, the default is AF_INET. - - .. versionchanged:: 1.2 - All Python 3 versions on Windows supply this function (natively - supplied by Python 3.5 and above). - """ - if family is None: - try: - family = AF_UNIX - except NameError: - family = AF_INET - a, b = _socket.socketpair(family, type, proto) - a = socket(family, type, proto, a.detach()) - b = socket(family, type, proto, b.detach()) - return a, b - -else: # pragma: no cover - socketpair = _fallback_socketpair - - - -__all__ = __implements__ + __extensions__ + __imports__ -if _fallback_socketpair.__name__ in __all__: - __all__.remove(_fallback_socketpair.__name__) - -__version_specific__ = ( - # Python 3.7b1+ - 'close', - # Python 3.10rc1+ - 'TCP_KEEPALIVE', - 'TCP_KEEPCNT', -) -for _x in __version_specific__: - if hasattr(__socket__, _x): - vars()[_x] = getattr(__socket__, _x) - if _x not in __all__: - __all__.append(_x) -del _x diff --git a/venv/lib/python3.9/site-packages/gevent/_socketcommon.py b/venv/lib/python3.9/site-packages/gevent/_socketcommon.py deleted file mode 100644 index 5ba0b35..0000000 --- a/venv/lib/python3.9/site-packages/gevent/_socketcommon.py +++ /dev/null @@ -1,749 +0,0 @@ -# Copyright (c) 2009-2014 Denis Bilenko and gevent contributors. See LICENSE for details. -from __future__ import absolute_import - -# standard functions and classes that this module re-implements in a gevent-aware way: -_implements = [ - 'create_connection', - 'socket', - 'SocketType', - 'fromfd', - 'socketpair', -] - -__dns__ = [ - 'getaddrinfo', - 'gethostbyname', - 'gethostbyname_ex', - 'gethostbyaddr', - 'getnameinfo', - 'getfqdn', -] - -_implements += __dns__ - -# non-standard functions that this module provides: -__extensions__ = [ - 'cancel_wait', - 'wait_read', - 'wait_write', - 'wait_readwrite', -] - -# standard functions and classes that this module re-imports -__imports__ = [ - 'error', - 'gaierror', - 'herror', - 'htonl', - 'htons', - 'ntohl', - 'ntohs', - 'inet_aton', - 'inet_ntoa', - 'inet_pton', - 'inet_ntop', - 'timeout', - 'gethostname', - 'getprotobyname', - 'getservbyname', - 'getservbyport', - 'getdefaulttimeout', - 'setdefaulttimeout', - # Windows: - 'errorTab', - # Python 3 - 'AddressFamily', - 'SocketKind', - 'CMSG_LEN', - 'CMSG_SPACE', - 'dup', - 'if_indextoname', - 'if_nameindex', - 'if_nametoindex', - 'sethostname', - 'create_server', - 'has_dualstack_ipv6', - 'recv_fds', - 'send_fds', -] - - -import time - -from gevent._hub_local import get_hub_noargs as get_hub -from gevent._compat import string_types, integer_types -from gevent._compat import WIN as is_windows -from gevent._compat import OSX as is_macos -from gevent._compat import exc_clear -from gevent._util import copy_globals -from gevent._greenlet_primitives import get_memory as _get_memory -from gevent._hub_primitives import wait_on_socket as _wait_on_socket - -from gevent.timeout import Timeout - - -# pylint:disable=no-name-in-module,unused-import -if is_windows: - # no such thing as WSAEPERM or error code 10001 according to winsock.h or MSDN - from errno import WSAEINVAL as EINVAL - from errno import WSAEWOULDBLOCK as EWOULDBLOCK - from errno import WSAEINPROGRESS as EINPROGRESS - from errno import WSAEALREADY as EALREADY - from errno import WSAEISCONN as EISCONN - from gevent.win32util import formatError as strerror - EAGAIN = EWOULDBLOCK -else: - from errno import EINVAL - from errno import EWOULDBLOCK - from errno import EINPROGRESS - from errno import EALREADY - from errno import EAGAIN - from errno import EISCONN - from os import strerror - -try: - from errno import EBADF -except ImportError: - EBADF = 9 - -try: - from errno import EHOSTUNREACH -except ImportError: - EHOSTUNREACH = -1 - -try: - from errno import ECONNREFUSED -except ImportError: - ECONNREFUSED = -1 - -# macOS can return EPROTOTYPE when writing to a socket that is shutting -# Down. Retrying the write should return the expected EPIPE error. -# Downstream classes (like pywsgi) know how to handle/ignore EPIPE. -# This set is used by socket.send() to decide whether the write should -# be retried. The default is to retry only on EWOULDBLOCK. Here we add -# EPROTOTYPE on macOS to handle this platform-specific race condition. -GSENDAGAIN = (EWOULDBLOCK,) -if is_macos: - from errno import EPROTOTYPE - GSENDAGAIN += (EPROTOTYPE,) - -import _socket -_realsocket = _socket.socket -import socket as __socket__ - - -_SocketError = __socket__.error - -_name = _value = None -__imports__ = copy_globals(__socket__, globals(), - only_names=__imports__, - ignore_missing_names=True) - -for _name in __socket__.__all__: - _value = getattr(__socket__, _name) - if isinstance(_value, (integer_types, string_types)): - globals()[_name] = _value - __imports__.append(_name) - -del _name, _value - -_timeout_error = timeout # pylint: disable=undefined-variable - -from gevent import _hub_primitives -_hub_primitives.set_default_timeout_error(_timeout_error) - -wait = _hub_primitives.wait_on_watcher -wait_read = _hub_primitives.wait_read -wait_write = _hub_primitives.wait_write -wait_readwrite = _hub_primitives.wait_readwrite - -#: The exception raised by default on a call to :func:`cancel_wait` -class cancel_wait_ex(error): # pylint: disable=undefined-variable - def __init__(self): - super(cancel_wait_ex, self).__init__( - EBADF, - 'File descriptor was closed in another greenlet') - - -def cancel_wait(watcher, error=cancel_wait_ex): - """See :meth:`gevent.hub.Hub.cancel_wait`""" - get_hub().cancel_wait(watcher, error) - - -def gethostbyname(hostname): - """ - gethostbyname(host) -> address - - Return the IP address (a string of the form '255.255.255.255') for a host. - - .. seealso:: :doc:`/dns` - """ - return get_hub().resolver.gethostbyname(hostname) - - -def gethostbyname_ex(hostname): - """ - gethostbyname_ex(host) -> (name, aliaslist, addresslist) - - Return the true host name, a list of aliases, and a list of IP addresses, - for a host. The host argument is a string giving a host name or IP number. - Resolve host and port into list of address info entries. - - .. seealso:: :doc:`/dns` - """ - return get_hub().resolver.gethostbyname_ex(hostname) - -def getaddrinfo(host, port, family=0, type=0, proto=0, flags=0): - """ - Resolve host and port into list of address info entries. - - Translate the host/port argument into a sequence of 5-tuples that contain - all the necessary arguments for creating a socket connected to that service. - host is a domain name, a string representation of an IPv4/v6 address or - None. port is a string service name such as 'http', a numeric port number or - None. By passing None as the value of host and port, you can pass NULL to - the underlying C API. - - The family, type and proto arguments can be optionally specified in order to - narrow the list of addresses returned. Passing zero as a value for each of - these arguments selects the full range of results. - - .. seealso:: :doc:`/dns` - """ - # Also, on Python 3, we need to translate into the special enums. - # Our lower-level resolvers, including the thread and blocking, which use _socket, - # function simply with integers. - addrlist = get_hub().resolver.getaddrinfo(host, port, family, type, proto, flags) - result = [ - # pylint:disable=undefined-variable - (_intenum_converter(af, AddressFamily), - _intenum_converter(socktype, SocketKind), - proto, canonname, sa) - for af, socktype, proto, canonname, sa - in addrlist - ] - return result - -def _intenum_converter(value, enum_klass): - try: - return enum_klass(value) - except ValueError: # pragma: no cover - return value - - -def gethostbyaddr(ip_address): - """ - gethostbyaddr(ip_address) -> (name, aliaslist, addresslist) - - Return the true host name, a list of aliases, and a list of IP addresses, - for a host. The host argument is a string giving a host name or IP number. - - .. seealso:: :doc:`/dns` - """ - return get_hub().resolver.gethostbyaddr(ip_address) - - -def getnameinfo(sockaddr, flags): - """ - getnameinfo(sockaddr, flags) -> (host, port) - - Get host and port for a sockaddr. - - .. seealso:: :doc:`/dns` - """ - return get_hub().resolver.getnameinfo(sockaddr, flags) - - -def getfqdn(name=''): - """Get fully qualified domain name from name. - - An empty argument is interpreted as meaning the local host. - - First the hostname returned by gethostbyaddr() is checked, then - possibly existing aliases. In case no FQDN is available, hostname - from gethostname() is returned. - - .. versionchanged:: 23.7.0 - The IPv6 generic address '::' now returns the result of - ``gethostname``, like the IPv4 address '0.0.0.0'. - """ - # pylint: disable=undefined-variable - name = name.strip() - # IPv6 added in a late Python 3.10/3.11 patch release. - # https://github.com/python/cpython/issues/100374 - if not name or name in ('0.0.0.0', '::'): - name = gethostname() - try: - hostname, aliases, _ = gethostbyaddr(name) - except error: - pass - else: - aliases.insert(0, hostname) - for name in aliases: # EWW! pylint:disable=redefined-argument-from-local - if isinstance(name, bytes): - if b'.' in name: - break - elif '.' in name: - break - else: - name = hostname - return name - -def __send_chunk(socket, data_memory, flags, timeleft, end, timeout=_timeout_error): - """ - Send the complete contents of ``data_memory`` before returning. - This is the core loop around :meth:`send`. - - :param timeleft: Either ``None`` if there is no timeout involved, - or a float indicating the timeout to use. - :param end: Either ``None`` if there is no timeout involved, or - a float giving the absolute end time. - :return: An updated value for ``timeleft`` (or None) - :raises timeout: If ``timeleft`` was given and elapsed while - sending this chunk. - """ - data_sent = 0 - len_data_memory = len(data_memory) - started_timer = 0 - while data_sent < len_data_memory: - chunk = data_memory[data_sent:] - if timeleft is None: - data_sent += socket.send(chunk, flags) - elif started_timer and timeleft <= 0: - # Check before sending to guarantee a check - # happens even if each chunk successfully sends its data - # (especially important for SSL sockets since they have large - # buffers). But only do this if we've actually tried to - # send something once to avoid spurious timeouts on non-blocking - # sockets. - raise timeout('timed out') - else: - started_timer = 1 - data_sent += socket.send(chunk, flags, timeout=timeleft) - timeleft = end - time.time() - - return timeleft - -def _sendall(socket, data_memory, flags, - SOL_SOCKET=__socket__.SOL_SOCKET, # pylint:disable=no-member - SO_SNDBUF=__socket__.SO_SNDBUF): # pylint:disable=no-member - """ - Send the *data_memory* (which should be a memoryview) - using the gevent *socket*, performing well on PyPy. - """ - - # On PyPy up through 5.10.0, both PyPy2 and PyPy3, subviews - # (slices) of a memoryview() object copy the underlying bytes the - # first time the builtin socket.send() method is called. On a - # non-blocking socket (that thus calls socket.send() many times) - # with a large input, this results in many repeated copies of an - # ever smaller string, depending on the networking buffering. For - # example, if each send() can process 1MB of a 50MB input, and we - # naively pass the entire remaining subview each time, we'd copy - # 49MB, 48MB, 47MB, etc, thus completely killing performance. To - # workaround this problem, we work in reasonable, fixed-size - # chunks. This results in a 10x improvement to bench_sendall.py, - # while having no measurable impact on CPython (since it doesn't - # copy at all the only extra overhead is a few python function - # calls, which is negligible for large inputs). - - # On one macOS machine, PyPy3 5.10.1 produced ~ 67.53 MB/s before this change, - # and ~ 616.01 MB/s after. - - # See https://bitbucket.org/pypy/pypy/issues/2091/non-blocking-socketsend-slow-gevent - - # Too small of a chunk (the socket's buf size is usually too - # small) results in reduced perf due to *too many* calls to send and too many - # small copies. With a buffer of 143K (the default on my system), for - # example, bench_sendall.py yields ~264MB/s, while using 1MB yields - # ~653MB/s (matching CPython). 1MB is arbitrary and might be better - # chosen, say, to match a page size? - - len_data_memory = len(data_memory) - if not len_data_memory: - # Don't try to send empty data at all, no point, and breaks ssl - # See issue 719 - return 0 - - - chunk_size = max(socket.getsockopt(SOL_SOCKET, SO_SNDBUF), 1024 * 1024) - - data_sent = 0 - end = None - timeleft = None - if socket.timeout is not None: - timeleft = socket.timeout - end = time.time() + timeleft - - while data_sent < len_data_memory: - chunk_end = min(data_sent + chunk_size, len_data_memory) - chunk = data_memory[data_sent:chunk_end] - - timeleft = __send_chunk(socket, chunk, flags, timeleft, end) - data_sent += len(chunk) # Guaranteed it sent the whole thing - -# pylint:disable=no-member -_RESOLVABLE_FAMILIES = (__socket__.AF_INET,) -if __socket__.has_ipv6: - _RESOLVABLE_FAMILIES += (__socket__.AF_INET6,) - -def _resolve_addr(sock, address): - # Internal method: resolve the AF_INET[6] address using - # getaddrinfo. - if sock.family not in _RESOLVABLE_FAMILIES or not isinstance(address, tuple): - return address - # address is (host, port) (ipv4) or (host, port, flowinfo, scopeid) (ipv6). - # If it's already resolved, no need to go through getaddrinfo() again. - # That can lose precision (e.g., on IPv6, it can lose scopeid). The standard library - # does this in socketmodule.c:setipaddr. (This is only part of the logic, the real - # thing is much more complex.) - try: - if __socket__.inet_pton(sock.family, address[0]): - return address - except AttributeError: # pragma: no cover - # inet_pton might not be available. - pass - except _SocketError: - # Not parseable, needs resolved. - pass - - - # We don't pass the port to getaddrinfo because the C - # socket module doesn't either (on some systems its - # illegal to do that without also passing socket type and - # protocol). Instead we join the port back at the end. - # See https://github.com/gevent/gevent/issues/1252 - host, port = address[:2] - r = getaddrinfo(host, None, sock.family) - address = r[0][-1] - if len(address) == 2: - address = (address[0], port) - else: - address = (address[0], port, address[2], address[3]) - return address - - -timeout_default = object() - -class SocketMixin(object): - # pylint:disable=too-many-public-methods - __slots__ = ( - 'hub', - 'timeout', - '_read_event', - '_write_event', - '_sock', - '__weakref__', - ) - - def __init__(self): - # Writing: - # (self.a, self.b) = (None,) * 2 - # generates the fastest bytecode. But At least on PyPy, - # where the SSLSocket subclass has a timeout property, - # it results in the settimeout() method getting the tuple - # as the value, not the unpacked None. - self._read_event = None - self._write_event = None - self._sock = None - self.hub = None - self.timeout = None - - def _drop_events_and_close(self, closefd=True, _cancel_wait_ex=cancel_wait_ex): - hub = self.hub - read_event = self._read_event - write_event = self._write_event - self._read_event = self._write_event = None - hub.cancel_waits_close_and_then( - (read_event, write_event), - _cancel_wait_ex, - # Pass the socket to keep it alive until such time as - # the waiters are guaranteed to be closed. - self._drop_ref_on_close if closefd else id, - self._sock - ) - - def _drop_ref_on_close(self, sock): - raise NotImplementedError - - def _get_ref(self): - return self._read_event.ref or self._write_event.ref - - def _set_ref(self, value): - self._read_event.ref = value - self._write_event.ref = value - - ref = property(_get_ref, _set_ref) - - _wait = _wait_on_socket - - ### - # Common methods defined here need to be added to the - # API documentation specifically. - ### - - def settimeout(self, howlong): - if howlong is not None: - try: - f = howlong.__float__ - except AttributeError: - raise TypeError('a float is required', howlong, type(howlong)) - howlong = f() - if howlong < 0.0: - raise ValueError('Timeout value out of range') - # avoid recursion with any property on self.timeout - SocketMixin.timeout.__set__(self, howlong) - - def gettimeout(self): - # avoid recursion with any property on self.timeout - return SocketMixin.timeout.__get__(self, type(self)) - - def setblocking(self, flag): - # Beginning in 3.6.0b3 this is supposed to raise - # if the file descriptor is closed, but the test for it - # involves closing the fileno directly. Since we - # don't touch the fileno here, it doesn't make sense for - # us. - if flag: - self.timeout = None - else: - self.timeout = 0.0 - - def shutdown(self, how): - if how == 0: # SHUT_RD - self.hub.cancel_wait(self._read_event, cancel_wait_ex) - elif how == 1: # SHUT_WR - self.hub.cancel_wait(self._write_event, cancel_wait_ex) - else: - self.hub.cancel_wait(self._read_event, cancel_wait_ex) - self.hub.cancel_wait(self._write_event, cancel_wait_ex) - self._sock.shutdown(how) - - # pylint:disable-next=undefined-variable - family = property(lambda self: _intenum_converter(self._sock.family, AddressFamily)) - # pylint:disable-next=undefined-variable - type = property(lambda self: _intenum_converter(self._sock.type, SocketKind)) - proto = property(lambda self: self._sock.proto) - - def fileno(self): - return self._sock.fileno() - - def getsockname(self): - return self._sock.getsockname() - - def getpeername(self): - return self._sock.getpeername() - - def bind(self, address): - return self._sock.bind(address) - - def listen(self, *args): - return self._sock.listen(*args) - - def getsockopt(self, *args): - return self._sock.getsockopt(*args) - - def setsockopt(self, *args): - return self._sock.setsockopt(*args) - - if hasattr(__socket__.socket, 'ioctl'): # os.name == 'nt' - def ioctl(self, *args): - return self._sock.ioctl(*args) - if hasattr(__socket__.socket, 'sleeptaskw'): # os.name == 'riscos - def sleeptaskw(self, *args): - return self._sock.sleeptaskw(*args) - - def getblocking(self): - """ - Returns whether the socket will approximate blocking - behaviour. - - .. versionadded:: 1.3a2 - Added in Python 3.7. - """ - return self.timeout != 0.0 - - def connect(self, address): - """ - Connect to *address*. - - .. versionchanged:: 20.6.0 - If the host part of the address includes an IPv6 scope ID, - it will be used instead of ignored, if the platform supplies - :func:`socket.inet_pton`. - """ - # In the standard library, ``connect`` and ``connect_ex`` are implemented - # in C, and they both call a C function ``internal_connect`` to do the real - # work. This means that it is a visible behaviour difference to have our - # Python implementation of ``connect_ex`` simply call ``connect``: - # it could be overridden in a subclass or at runtime! Because of our exception handling, - # this can make a difference for known subclasses like SSLSocket. - self._internal_connect(address) - - def connect_ex(self, address): - """ - Connect to *address*, returning a result code. - - .. versionchanged:: 23.7.0 - No longer uses an overridden ``connect`` method on - this object. Instead, like the standard library, this method always - uses a non-replacable internal connection function. - """ - try: - return self._internal_connect(address) or 0 - except __socket__.timeout: - return EAGAIN - except __socket__.gaierror: # pylint:disable=try-except-raise - # gaierror/overflowerror/typerror is not silenced by connect_ex; - # gaierror extends error so catch it first - raise - except _SocketError as ex: - # Python 3: error is now OSError and it has various subclasses. - # Only those that apply to actually connecting are silenced by - # connect_ex. - # On Python 3, we want to check ex.errno; on Python 2 - # there is no such attribute, we need to look at the first - # argument. - try: - err = ex.errno - except AttributeError: - err = ex.args[0] - if err: - return err - raise - - def _internal_connect(self, address): - # Like the C function ``internal_connect``, not meant to be overridden, - # but exposed for testing. - if self.timeout == 0.0: - return self._sock.connect(address) - address = _resolve_addr(self._sock, address) - with Timeout._start_new_or_dummy(self.timeout, __socket__.timeout("timed out")): - while 1: - err = self.getsockopt(__socket__.SOL_SOCKET, __socket__.SO_ERROR) - if err: - raise _SocketError(err, strerror(err)) - result = self._sock.connect_ex(address) - - if not result or result == EISCONN: - break - if (result in (EWOULDBLOCK, EINPROGRESS, EALREADY)) or (result == EINVAL and is_windows): - self._wait(self._write_event) - else: - if (isinstance(address, tuple) - and address[0] == 'fe80::1' - and result == EHOSTUNREACH): - # On Python 3.7 on mac, we see EHOSTUNREACH - # returned for this link-local address, but it really is - # supposed to be ECONNREFUSED according to the standard library - # tests (test_socket.NetworkConnectionNoServer.test_create_connection) - # (On previous versions, that code passed the '127.0.0.1' IPv4 address, so - # ipv6 link locals were never a factor; 3.7 passes 'localhost'.) - # It is something of a mystery how the stdlib socket code doesn't - # produce EHOSTUNREACH---I (JAM) can't see how socketmodule.c would avoid - # that. The normal connect just calls connect_ex much like we do. - result = ECONNREFUSED - raise _SocketError(result, strerror(result)) - - def recv(self, *args): - while 1: - try: - return self._sock.recv(*args) - except _SocketError as ex: - if ex.args[0] != EWOULDBLOCK or self.timeout == 0.0: - raise - # QQQ without clearing exc_info test__refcount.test_clean_exit fails - exc_clear() # Python 2 - self._wait(self._read_event) - - def recvfrom(self, *args): - while 1: - try: - return self._sock.recvfrom(*args) - except _SocketError as ex: - if ex.args[0] != EWOULDBLOCK or self.timeout == 0.0: - raise - exc_clear() # Python 2 - self._wait(self._read_event) - - def recvfrom_into(self, *args): - while 1: - try: - return self._sock.recvfrom_into(*args) - except _SocketError as ex: - if ex.args[0] != EWOULDBLOCK or self.timeout == 0.0: - raise - exc_clear() # Python 2 - self._wait(self._read_event) - - def recv_into(self, *args): - while 1: - try: - return self._sock.recv_into(*args) - except _SocketError as ex: - if ex.args[0] != EWOULDBLOCK or self.timeout == 0.0: - raise - exc_clear() # Python 2 - self._wait(self._read_event) - - def sendall(self, data, flags=0): - # this sendall is also reused by gevent.ssl.SSLSocket subclass, - # so it should not call self._sock methods directly - data_memory = _get_memory(data) - return _sendall(self, data_memory, flags) - - def sendto(self, *args): - try: - return self._sock.sendto(*args) - except _SocketError as ex: - if ex.args[0] != EWOULDBLOCK or self.timeout == 0.0: - raise - exc_clear() - self._wait(self._write_event) - - try: - return self._sock.sendto(*args) - except _SocketError as ex2: - if ex2.args[0] == EWOULDBLOCK: - exc_clear() - return 0 - raise - - def send(self, data, flags=0, timeout=timeout_default): - if timeout is timeout_default: - timeout = self.timeout - try: - return self._sock.send(data, flags) - except _SocketError as ex: - if ex.args[0] not in GSENDAGAIN or timeout == 0.0: - raise - exc_clear() - self._wait(self._write_event) - try: - return self._sock.send(data, flags) - except _SocketError as ex2: - if ex2.args[0] == EWOULDBLOCK: - exc_clear() - return 0 - raise - - @classmethod - def _fixup_docstrings(cls): - for k, v in vars(cls).items(): - if k.startswith('_'): - continue - if not hasattr(v, '__doc__') or v.__doc__: - continue - smeth = getattr(__socket__.socket, k, None) - if not smeth or not smeth.__doc__: - continue - - try: - v.__doc__ = smeth.__doc__ - except (AttributeError, TypeError): - # slots can't have docs. Py2 raises TypeError, - # Py3 raises AttributeError - continue - -SocketMixin._fixup_docstrings() -del SocketMixin._fixup_docstrings diff --git a/venv/lib/python3.9/site-packages/gevent/_tblib.py b/venv/lib/python3.9/site-packages/gevent/_tblib.py deleted file mode 100644 index 47fe7fc..0000000 --- a/venv/lib/python3.9/site-packages/gevent/_tblib.py +++ /dev/null @@ -1,383 +0,0 @@ -# -*- coding: utf-8 -*- -# A vendored version of part of https://github.com/ionelmc/python-tblib -# pylint:disable=redefined-outer-name,reimported,function-redefined,bare-except,no-else-return,broad-except -#### -# Copyright (c) 2013-2016, Ionel Cristian Mărieș -# All rights reserved. - -# Redistribution and use in source and binary forms, with or without modification, are permitted provided that the -# following conditions are met: - -# 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following -# disclaimer. - -# 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following -# disclaimer in the documentation and/or other materials provided with the distribution. - -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, -# INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, -# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF -# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -#### - - -# __init__.py -import re -import sys -from types import CodeType - -__version__ = '2.0.0' -__all__ = 'Traceback', 'TracebackParseError', 'Frame', 'Code' - -FRAME_RE = re.compile(r'^\s*File "(?P.+)", line (?P\d+)(, in (?P.+))?$') - - -class _AttrDict(dict): - __slots__ = () - - def __getattr__(self, name): - try: - return self[name] - except KeyError: - raise AttributeError(name) from None - - -# noinspection PyPep8Naming -class __traceback_maker(Exception): - pass - - -class TracebackParseError(Exception): - pass - - -class Code: - """ - Class that replicates just enough of the builtin Code object to enable serialization and traceback rendering. - """ - - co_code = None - - def __init__(self, code): - self.co_filename = code.co_filename - self.co_name = code.co_name - self.co_argcount = 0 - self.co_kwonlyargcount = 0 - self.co_varnames = () - self.co_nlocals = 0 - self.co_stacksize = 0 - self.co_flags = 64 - self.co_firstlineno = 0 - - -class Frame: - """ - Class that replicates just enough of the builtin Frame object to enable serialization and traceback rendering. - """ - - def __init__(self, frame): - self.f_locals = {} - self.f_globals = {k: v for k, v in frame.f_globals.items() if k in ('__file__', '__name__')} - self.f_code = Code(frame.f_code) - self.f_lineno = frame.f_lineno - - def clear(self): - """ - For compatibility with PyPy 3.5; - clear() was added to frame in Python 3.4 - and is called by traceback.clear_frames(), which - in turn is called by unittest.TestCase.assertRaises - """ - - -class Traceback: - """ - Class that wraps builtin Traceback objects. - """ - - tb_next = None - - def __init__(self, tb): - self.tb_frame = Frame(tb.tb_frame) - # noinspection SpellCheckingInspection - self.tb_lineno = int(tb.tb_lineno) - - # Build in place to avoid exceeding the recursion limit - tb = tb.tb_next - prev_traceback = self - cls = type(self) - while tb is not None: - traceback = object.__new__(cls) - traceback.tb_frame = Frame(tb.tb_frame) - traceback.tb_lineno = int(tb.tb_lineno) - prev_traceback.tb_next = traceback - prev_traceback = traceback - tb = tb.tb_next - - def as_traceback(self): - """ - Convert to a builtin Traceback object that is usable for raising or rendering a stacktrace. - """ - current = self - top_tb = None - tb = None - while current: - f_code = current.tb_frame.f_code - code = compile('\n' * (current.tb_lineno - 1) + 'raise __traceback_maker', current.tb_frame.f_code.co_filename, 'exec') - if hasattr(code, 'replace'): - # Python 3.8 and newer - code = code.replace(co_argcount=0, co_filename=f_code.co_filename, co_name=f_code.co_name, co_freevars=(), co_cellvars=()) - else: - code = CodeType( - 0, - code.co_kwonlyargcount, - code.co_nlocals, - code.co_stacksize, - code.co_flags, - code.co_code, - code.co_consts, - code.co_names, - code.co_varnames, - f_code.co_filename, - f_code.co_name, - code.co_firstlineno, - code.co_lnotab, - (), - (), - ) - - # noinspection PyBroadException - try: - exec(code, dict(current.tb_frame.f_globals), {}) # noqa: S102 - except Exception: - next_tb = sys.exc_info()[2].tb_next - if top_tb is None: - top_tb = next_tb - if tb is not None: - tb.tb_next = next_tb - tb = next_tb - del next_tb - - current = current.tb_next - try: - return top_tb - finally: - del top_tb - del tb - - to_traceback = as_traceback - - def as_dict(self): - """ - Converts to a dictionary representation. You can serialize the result to JSON as it only has - builtin objects like dicts, lists, ints or strings. - """ - if self.tb_next is None: - tb_next = None - else: - tb_next = self.tb_next.to_dict() - - code = { - 'co_filename': self.tb_frame.f_code.co_filename, - 'co_name': self.tb_frame.f_code.co_name, - } - frame = { - 'f_globals': self.tb_frame.f_globals, - 'f_code': code, - 'f_lineno': self.tb_frame.f_lineno, - } - return { - 'tb_frame': frame, - 'tb_lineno': self.tb_lineno, - 'tb_next': tb_next, - } - - to_dict = as_dict - - @classmethod - def from_dict(cls, dct): - """ - Creates an instance from a dictionary with the same structure as ``.as_dict()`` returns. - """ - if dct['tb_next']: - tb_next = cls.from_dict(dct['tb_next']) - else: - tb_next = None - - code = _AttrDict( - co_filename=dct['tb_frame']['f_code']['co_filename'], - co_name=dct['tb_frame']['f_code']['co_name'], - ) - frame = _AttrDict( - f_globals=dct['tb_frame']['f_globals'], - f_code=code, - f_lineno=dct['tb_frame']['f_lineno'], - ) - tb = _AttrDict( - tb_frame=frame, - tb_lineno=dct['tb_lineno'], - tb_next=tb_next, - ) - return cls(tb) - - @classmethod - def from_string(cls, string, strict=True): - """ - Creates an instance by parsing a stacktrace. Strict means that parsing stops when lines are not indented by at least two spaces - anymore. - """ - frames = [] - header = strict - - for line in string.splitlines(): - line = line.rstrip() - if header: - if line == 'Traceback (most recent call last):': - header = False - continue - frame_match = FRAME_RE.match(line) - if frame_match: - frames.append(frame_match.groupdict()) - elif line.startswith(' '): - pass - elif strict: - break # traceback ended - - if frames: - previous = None - for frame in reversed(frames): - previous = _AttrDict( - frame, - tb_frame=_AttrDict( - frame, - f_globals=_AttrDict( - __file__=frame['co_filename'], - __name__='?', - ), - f_code=_AttrDict(frame), - f_lineno=int(frame['tb_lineno']), - ), - tb_next=previous, - ) - return cls(previous) - else: - raise TracebackParseError('Could not find any frames in %r.' % string) - -# pickling_support.py -# gevent: Trying the dict support, so maybe we don't even need this -# at all. - -import sys -from types import TracebackType -#from . import Frame # gevent -#from . import Traceback # gevent - -# gevent: defer -# if sys.version_info.major >= 3: -# import copyreg -# else: -# import copy_reg as copyreg - - -def unpickle_traceback(tb_frame, tb_lineno, tb_next): - ret = object.__new__(Traceback) - ret.tb_frame = tb_frame - ret.tb_lineno = tb_lineno - ret.tb_next = tb_next - return ret.as_traceback() - - -def pickle_traceback(tb): - return unpickle_traceback, (Frame(tb.tb_frame), tb.tb_lineno, tb.tb_next and Traceback(tb.tb_next)) - - -def unpickle_exception(func, args, cause, tb): - inst = func(*args) - inst.__cause__ = cause - inst.__traceback__ = tb - return inst - - -def pickle_exception(obj): - # All exceptions, unlike generic Python objects, define __reduce_ex__ - # __reduce_ex__(4) should be no different from __reduce_ex__(3). - # __reduce_ex__(5) could bring benefits in the unlikely case the exception - # directly contains buffers, but PickleBuffer objects will cause a crash when - # running on protocol=4, and there's no clean way to figure out the current - # protocol from here. Note that any object returned by __reduce_ex__(3) will - # still be pickled with protocol 5 if pickle.dump() is running with it. - rv = obj.__reduce_ex__(3) - if isinstance(rv, str): - raise TypeError('str __reduce__ output is not supported') - assert isinstance(rv, tuple) - assert len(rv) >= 2 - - return (unpickle_exception, rv[:2] + (obj.__cause__, obj.__traceback__)) + rv[2:] - - -def _get_subclasses(cls): - # Depth-first traversal of all direct and indirect subclasses of cls - to_visit = [cls] - while to_visit: - this = to_visit.pop() - yield this - to_visit += list(this.__subclasses__()) - - -def install(*exc_classes_or_instances): - import copyreg - copyreg.pickle(TracebackType, pickle_traceback) - - if sys.version_info.major < 3: - # Dummy decorator? - if len(exc_classes_or_instances) == 1: - exc = exc_classes_or_instances[0] - if isinstance(exc, type) and issubclass(exc, BaseException): - return exc - return - - if not exc_classes_or_instances: - for exception_cls in _get_subclasses(BaseException): - copyreg.pickle(exception_cls, pickle_exception) - return - - for exc in exc_classes_or_instances: - if isinstance(exc, BaseException): - while exc is not None: - copyreg.pickle(type(exc), pickle_exception) - exc = exc.__cause__ - elif isinstance(exc, type) and issubclass(exc, BaseException): - copyreg.pickle(exc, pickle_exception) - # Allow using @install as a decorator for Exception classes - if len(exc_classes_or_instances) == 1: - return exc - else: - raise TypeError('Expected subclasses or instances of BaseException, got %s' % (type(exc))) - -# gevent API -_installed = False -# 2025-04-14 On Python 3.14a7, attempting to do *anything* (get its type, print it,...) -# with a traceback object that has been reconstituted from one that tblib pickled will -# crash the interpreter. The current HEAD of upstream _tblib can't pass its tests on 3.14 -# and also crashes the interpreter. Our temporary fix is to disable this functionality on -# 3.14. While we're in early testing, limit it to exact versions known to be broken, just -# in case we find that it gets fixed in CPython itself. -_broken_tblib_pickle = sys.version_info == (3, 14, 0, 'alpha', 7) -def dump_traceback(tb): - from pickle import dumps - if tb is None or _broken_tblib_pickle: - return dumps(None) - tb = Traceback(tb) - return dumps(tb.to_dict()) - - -def load_traceback(s): - from pickle import loads - as_dict = loads(s) - if as_dict is None: - return None - tb = Traceback.from_dict(as_dict) - return tb.as_traceback() diff --git a/venv/lib/python3.9/site-packages/gevent/_threading.py b/venv/lib/python3.9/site-packages/gevent/_threading.py deleted file mode 100644 index 86cf734..0000000 --- a/venv/lib/python3.9/site-packages/gevent/_threading.py +++ /dev/null @@ -1,234 +0,0 @@ -""" -A small selection of primitives that always work with -native threads. This has very limited utility and is -targeted only for the use of gevent's threadpool. -""" -from __future__ import absolute_import - -from collections import deque - -from gevent import monkey -from gevent._compat import thread_mod_name - -__all__ = [ - 'Lock', - 'Queue', - 'EmptyTimeout', -] - - -start_new_thread, Lock, get_thread_ident, = monkey.get_original(thread_mod_name, [ - 'start_new_thread', 'allocate_lock', 'get_ident', -]) - - -# We want to support timeouts on locks. In this way, we can allow idle threads to -# expire from a thread pool. On Python 3, this is native behaviour; on Python 2, -# we have to emulate it. For Python 3, we want this to have the lowest possible overhead, -# so we'd prefer to use a direct call, rather than go through a wrapper. But we also -# don't want to allocate locks at import time because..., so we swizzle out the method -# at runtime. -# -# -# In all cases, a timeout value of -1 means "infinite". Sigh. -def acquire_with_timeout(lock, timeout=-1): - globals()['acquire_with_timeout'] = type(lock).acquire - return lock.acquire(timeout=timeout) - - -class _Condition(object): - # We could use libuv's ``uv_cond_wait`` to implement this whole - # class and get native timeouts and native performance everywhere. - - # pylint:disable=method-hidden - - __slots__ = ( - '_lock', - '_waiters', - ) - - def __init__(self, lock): - # This lock is used to protect our own data structures; - # calls to ``wait`` and ``notify_one`` *must* be holding this - # lock. - self._lock = lock - self._waiters = [] - - # No need to special case for _release_save and - # _acquire_restore; those are only used for RLock, and - # we don't use those. - - def __enter__(self): - return self._lock.__enter__() - - def __exit__(self, t, v, tb): - return self._lock.__exit__(t, v, tb) - - def __repr__(self): - return "" % (self._lock, len(self._waiters)) - - def wait(self, wait_lock, timeout=-1, _wait_for_notify=acquire_with_timeout): - # This variable is for the monitoring utils to know that - # this is an idle frame and shouldn't be counted. - gevent_threadpool_worker_idle = True # pylint:disable=unused-variable - - # The _lock must be held. - # The ``wait_lock`` must be *un*owned, so the timeout doesn't apply there. - # Take that lock now. - wait_lock.acquire() - self._waiters.append(wait_lock) - - self._lock.release() - try: - # We're already holding this native lock, so when we try to acquire it again, - # that won't work and we'll block until someone calls notify_one() (which might - # have already happened). - notified = _wait_for_notify(wait_lock, timeout) - finally: - self._lock.acquire() - - # Now that we've acquired _lock again, no one can call notify_one(), or this - # method. - if not notified: - # We need to come out of the waiters list. IF we're still there; it's - # possible that between the call to _acquire() returning False, - # and the time that we acquired _lock, someone did a ``notify_one`` - # and released the lock. For that reason, do a non-blocking acquire() - notified = wait_lock.acquire(False) - if not notified: - # Well narf. No go. We must stil be in the waiters list, so take us out - self._waiters.remove(wait_lock) - # We didn't get notified, but we're still holding a lock that we - # need to release. - wait_lock.release() - else: - # We got notified, so we need to reset. - wait_lock.release() - return notified - - def notify_one(self): - # The lock SHOULD be owned, but we don't check that. - try: - waiter = self._waiters.pop() - except IndexError: - # Nobody around - pass - else: - # The owner of the ``waiter`` is blocked on - # acquiring it again, so when we ``release`` it, it - # is free to be scheduled and resume. - waiter.release() - -class EmptyTimeout(Exception): - """Raised from :meth:`Queue.get` if no item is available in the timeout.""" - - -class Queue(object): - """ - Create a queue object. - - The queue is always infinite size. - """ - - __slots__ = ('_queue', '_mutex', '_not_empty', 'unfinished_tasks') - - def __init__(self): - self._queue = deque() - # mutex must be held whenever the queue is mutating. All methods - # that acquire mutex must release it before returning. mutex - # is shared between the three conditions, so acquiring and - # releasing the conditions also acquires and releases mutex. - self._mutex = Lock() - # Notify not_empty whenever an item is added to the queue; a - # thread waiting to get is notified then. - self._not_empty = _Condition(self._mutex) - - self.unfinished_tasks = 0 - - def task_done(self): - """Indicate that a formerly enqueued task is complete. - - Used by Queue consumer threads. For each get() used to fetch a task, - a subsequent call to task_done() tells the queue that the processing - on the task is complete. - - If a join() is currently blocking, it will resume when all items - have been processed (meaning that a task_done() call was received - for every item that had been put() into the queue). - - Raises a ValueError if called more times than there were items - placed in the queue. - """ - with self._mutex: - unfinished = self.unfinished_tasks - 1 - if unfinished <= 0: - if unfinished < 0: - raise ValueError( - 'task_done() called too many times; %s remaining tasks' % ( - self.unfinished_tasks - ) - ) - self.unfinished_tasks = unfinished - - def qsize(self, len=len): - """Return the approximate size of the queue (not reliable!).""" - return len(self._queue) - - def empty(self): - """Return True if the queue is empty, False otherwise (not reliable!).""" - return not self.qsize() - - def full(self): - """Return True if the queue is full, False otherwise (not reliable!).""" - return False - - def put(self, item): - """Put an item into the queue. - """ - with self._mutex: - self._queue.append(item) - self.unfinished_tasks += 1 - self._not_empty.notify_one() - - def get(self, cookie, timeout=-1): - """ - Remove and return an item from the queue. - - If *timeout* is given, and is not -1, then we will - attempt to wait for only that many seconds to get an item. - If those seconds elapse and no item has become available, - raises :class:`EmptyTimeout`. - """ - with self._mutex: - while not self._queue: - # Temporarily release our mutex and wait for someone - # to wake us up. There *should* be an item in the queue - # after that. - notified = self._not_empty.wait(cookie, timeout) - # Ok, we're holding the mutex again, so our state is guaranteed stable. - # It's possible that in the brief window where we didn't hold the lock, - # someone put something in the queue, and if so, we can take it. - if not notified and not self._queue: - raise EmptyTimeout - item = self._queue.popleft() - return item - - def allocate_cookie(self): - """ - Create and return the *cookie* to pass to `get()`. - - Each thread that will use `get` needs a distinct cookie. - """ - return Lock() - - def kill(self): - """ - Call to destroy this object. - - Use this when it's not possible to safely drain the queue, e.g., - after a fork when the locks are in an uncertain state. - """ - self._queue = None - self._mutex = None - self._not_empty = None - self.unfinished_tasks = None diff --git a/venv/lib/python3.9/site-packages/gevent/_tracer.py b/venv/lib/python3.9/site-packages/gevent/_tracer.py deleted file mode 100644 index b271017..0000000 --- a/venv/lib/python3.9/site-packages/gevent/_tracer.py +++ /dev/null @@ -1,182 +0,0 @@ -# Copyright (c) 2018 gevent. See LICENSE for details. -# cython: auto_pickle=False,embedsignature=True,always_allow_keywords=False -from __future__ import print_function, absolute_import, division - -import sys -import traceback - -from greenlet import settrace -from greenlet import getcurrent - -from gevent.util import format_run_info - -from gevent._compat import perf_counter -from gevent._util import gmctime - - -__all__ = [ - 'GreenletTracer', - 'HubSwitchTracer', - 'MaxSwitchTracer', -] - -# Recall these classes are cython compiled, so -# class variable declarations are bad. - - -class GreenletTracer(object): - def __init__(self): - # A counter, incremented by the greenlet trace function - # we install on every greenlet switch. This is reset when the - # periodic monitoring thread runs. - - self.greenlet_switch_counter = 0 - - # The greenlet last switched to. - self.active_greenlet = None - - # The trace function that was previously installed, - # if any. - # NOTE: Calling a class instance is cheaper than - # calling a bound method (at least when compiled with cython) - # even when it redirects to another function. - prev_trace = settrace(self) - - self.previous_trace_function = prev_trace - - self._killed = False - - def kill(self): - # Must be called in the monitored thread. - if not self._killed: - self._killed = True - settrace(self.previous_trace_function) - self.previous_trace_function = None - - def _trace(self, event, args): - # This function runs in the thread we are monitoring. - self.greenlet_switch_counter += 1 - if event in ('switch', 'throw'): - # args is (origin, target). This is the only defined - # case - self.active_greenlet = args[1] - else: - self.active_greenlet = None - if self.previous_trace_function is not None: - self.previous_trace_function(event, args) - - def __call__(self, event, args): - return self._trace(event, args) - - def did_block_hub(self, hub): - # Check to see if we have blocked since the last call to this - # method. Returns a true value if we blocked (not in the hub), - # a false value if everything is fine. - - # This may be called in the same thread being traced or a - # different thread; if a different thread, there is a race - # condition with this being incremented in the thread we're - # monitoring, but probably not often enough to lead to - # annoying false positives. - - active_greenlet = self.active_greenlet - did_switch = self.greenlet_switch_counter != 0 - self.greenlet_switch_counter = 0 - - if did_switch or active_greenlet is None or active_greenlet is hub: - # Either we switched, or nothing is running (we got a - # trace event we don't know about or were requested to - # ignore), or we spent the whole time in the hub, blocked - # for IO. Nothing to report. - return False - return True, active_greenlet - - def ignore_current_greenlet_blocking(self): - # Don't pay attention to the current greenlet. - self.active_greenlet = None - - def monitor_current_greenlet_blocking(self): - self.active_greenlet = getcurrent() - - def did_block_hub_report(self, hub, active_greenlet, format_kwargs): - # XXX: On Python 2 with greenlet 1.0a1, '%s' formatting a greenlet - # results in a unicode object. This is a bug in greenlet, I think. - # https://github.com/python-greenlet/greenlet/issues/218 - report = ['=' * 80, - '\n%s : Greenlet %s appears to be blocked' % - (gmctime(), str(active_greenlet))] - report.append(" Reported by %s" % (self,)) - try: - frame = sys._current_frames()[hub.thread_ident] - except KeyError: - # The thread holding the hub has died. Perhaps we shouldn't - # even report this? - stack = ["Unknown: No thread found for hub %r\n" % (hub,)] - else: - stack = traceback.format_stack(frame) - report.append('Blocked Stack (for thread id %s):' % (hex(hub.thread_ident),)) - report.append(''.join(stack)) - report.append("Info:") - report.extend(format_run_info(**format_kwargs)) - - return report - - -class _HubTracer(GreenletTracer): - def __init__(self, hub, max_blocking_time): - GreenletTracer.__init__(self) - self.max_blocking_time = max_blocking_time - self.hub = hub - - def kill(self): - self.hub = None - GreenletTracer.kill(self) - - -class HubSwitchTracer(_HubTracer): - # A greenlet tracer that records the last time we switched *into* the hub. - - def __init__(self, hub, max_blocking_time): - _HubTracer.__init__(self, hub, max_blocking_time) - self.last_entered_hub = 0 - - def _trace(self, event, args): - GreenletTracer._trace(self, event, args) - if self.active_greenlet is self.hub: - self.last_entered_hub = perf_counter() - - def did_block_hub(self, hub): - if perf_counter() - self.last_entered_hub > self.max_blocking_time: - return True, self.active_greenlet - - -class MaxSwitchTracer(_HubTracer): - # A greenlet tracer that records the maximum time between switches, - # not including time spent in the hub. - - def __init__(self, hub, max_blocking_time): - _HubTracer.__init__(self, hub, max_blocking_time) - self.last_switch = perf_counter() - self.max_blocking = 0 - - def _trace(self, event, args): - old_active = self.active_greenlet - GreenletTracer._trace(self, event, args) - if old_active is not self.hub and old_active is not None: - # If we're switching out of the hub, the blocking - # time doesn't count. - switched_at = perf_counter() - self.max_blocking = max(self.max_blocking, - switched_at - self.last_switch) - - def did_block_hub(self, hub): - if self.max_blocking == 0: - # We never switched. Check the time now - self.max_blocking = perf_counter() - self.last_switch - - if self.max_blocking > self.max_blocking_time: - return True, self.active_greenlet - - -from gevent._util import import_c_accel -import_c_accel(globals(), 'gevent.__tracer') diff --git a/venv/lib/python3.9/site-packages/gevent/_util.py b/venv/lib/python3.9/site-packages/gevent/_util.py deleted file mode 100644 index 5da3612..0000000 --- a/venv/lib/python3.9/site-packages/gevent/_util.py +++ /dev/null @@ -1,351 +0,0 @@ -# -*- coding: utf-8 -*- -""" -internal gevent utilities, not for external use. -""" - -# Be very careful not to import anything that would cause issues with -# monkey-patching. - -from __future__ import print_function, absolute_import, division - -from gevent._compat import iteritems - - -class _NONE(object): - """ - A special object you must never pass to any gevent API. - Used as a marker object for keyword arguments that cannot have the - builtin None (because that might be a valid value). - """ - __slots__ = () - - def __repr__(self): - return '' - -_NONE = _NONE() - -WRAPPER_ASSIGNMENTS = ('__module__', '__name__', '__qualname__', '__doc__', - '__annotations__') -WRAPPER_UPDATES = ('__dict__',) -def update_wrapper(wrapper, - wrapped, - assigned=WRAPPER_ASSIGNMENTS, - updated=WRAPPER_UPDATES): - """ - Based on code from the standard library ``functools``, but - doesn't perform any of the troublesome imports. - - functools imports RLock from _thread for purposes of the - ``lru_cache``, making it problematic to use from gevent. - - The other imports are somewhat heavy: abc, collections, types. - """ - for attr in assigned: - try: - value = getattr(wrapped, attr) - except AttributeError: - pass - else: - setattr(wrapper, attr, value) - for attr in updated: - getattr(wrapper, attr).update(getattr(wrapped, attr, {})) - # Issue #17482: set __wrapped__ last so we don't inadvertently copy it - # from the wrapped function when updating __dict__ - wrapper.__wrapped__ = wrapped - # Return the wrapper so this can be used as a decorator via partial() - return wrapper - - -def copy_globals(source, - globs, - only_names=None, - ignore_missing_names=False, - names_to_ignore=(), - dunder_names_to_keep=('__implements__', '__all__', '__imports__'), - cleanup_globs=True): - """ - Copy attributes defined in ``source.__dict__`` to the dictionary - in globs (which should be the caller's :func:`globals`). - - Names that start with ``__`` are ignored (unless they are in - *dunder_names_to_keep*). Anything found in *names_to_ignore* is - also ignored. - - If *only_names* is given, only those attributes will be - considered. In this case, *ignore_missing_names* says whether or - not to raise an :exc:`AttributeError` if one of those names can't - be found. - - If *cleanup_globs* has a true value, then common things imported but - not used at runtime are removed, including this function. - - Returns a list of the names copied; this should be assigned to ``__imports__``. - """ - if only_names: - if ignore_missing_names: - items = ((k, getattr(source, k, _NONE)) for k in only_names) - else: - items = ((k, getattr(source, k)) for k in only_names) - else: - items = iteritems(source.__dict__) - - copied = [] - for key, value in items: - if value is _NONE: - continue - if key in names_to_ignore: - continue - if key.startswith("__") and key not in dunder_names_to_keep: - continue - globs[key] = value - copied.append(key) - - if cleanup_globs: - if 'copy_globals' in globs: - del globs['copy_globals'] - - return copied - -def import_c_accel(globs, cname): - """ - Import the C-accelerator for the *cname* - and copy its globals. - - The *cname* should be hardcoded to match the expected - C accelerator module. - - Unless PURE_PYTHON is set (in the environment or automatically - on PyPy), then the C-accelerator is required. - """ - if not cname.startswith('gevent._gevent_c'): - # Old module code that hasn't been updated yet. - cname = cname.replace('gevent._', - 'gevent._gevent_c') - - name = globs.get('__name__') - - if not name or name == cname: - # Do nothing if we're being exec'd as a file (no name) - # or we're running from the C extension - return - - - from gevent._compat import pure_python_module - if pure_python_module(name): - return - - import importlib - import warnings - with warnings.catch_warnings(): - # Python 3.7 likes to produce - # "ImportWarning: can't resolve - # package from __spec__ or __package__, falling back on - # __name__ and __path__" - # when we load cython compiled files. This is probably a bug in - # Cython, but it doesn't seem to have any consequences, it's - # just annoying to see and can mess up our unittests. - warnings.simplefilter('ignore', ImportWarning) - mod = importlib.import_module(cname) - - # By adopting the entire __dict__, we get a more accurate - # __file__ and module repr, plus we don't leak any imported - # things we no longer need. - globs.clear() - globs.update(mod.__dict__) - - if 'import_c_accel' in globs: - del globs['import_c_accel'] - - -class Lazy(object): - """ - A non-data descriptor used just like @property. The - difference is the function value is assigned to the instance - dict the first time it is accessed and then the function is never - called again. - - Contrast with `readproperty`. - """ - def __init__(self, func): - self.data = (func, func.__name__) - update_wrapper(self, func) - - def __get__(self, inst, class_): - if inst is None: - return self - - func, name = self.data - value = func(inst) - inst.__dict__[name] = value - return value - -class readproperty(object): - """ - A non-data descriptor similar to :class:`property`. - - The difference is that the property can be assigned to directly, - without invoking a setter function. When the property is assigned - to, it is cached in the instance and the function is not called on - that instance again. - - Contrast with `Lazy`, which caches the result of the function in the - instance the first time it is called and never calls the function on that - instance again. - """ - - def __init__(self, func): - self.func = func - update_wrapper(self, func) - - def __get__(self, inst, class_): - if inst is None: - return self - - return self.func(inst) - -class LazyOnClass(object): - """ - Similar to `Lazy`, but stores the value in the class. - - This is useful when the getter is expensive and conceptually - a shared class value, but we don't want import-time side-effects - such as expensive imports because it may not always be used. - - Probably doesn't mix well with inheritance? - """ - - @classmethod - def lazy(cls, cls_dict, func): - "Put a LazyOnClass object in *cls_dict* with the same name as *func*" - cls_dict[func.__name__] = cls(func) - - def __init__(self, func, name=None): - self.name = name or func.__name__ - self.func = func - - def __get__(self, inst, klass): - if inst is None: # pragma: no cover - return self - - val = self.func(inst) - setattr(klass, self.name, val) - return val - - -def gmctime(): - """ - Returns the current time as a string in RFC3339 format. - """ - import time - return time.strftime("%Y-%m-%dT%H:%M:%SZ", time.gmtime()) - - -### -# Release automation. -# -# Most of this is to integrate zest.releaser with towncrier. There is -# a plugin package that can do the same: -# https://github.com/collective/zestreleaser.towncrier -### - -def prereleaser_middle(data): # pragma: no cover - """ - zest.releaser prerelease middle hook for gevent. - - The prerelease step: - - asks you for a version number - updates the setup.py or version.txt and the - CHANGES/HISTORY/CHANGELOG file (with either - this new version - number and offers to commit those changes to git - - The middle hook: - - All data dictionary items are available and some questions - (like new version number) have been asked. - No filesystem changes have been made yet. - - It is our job to finish up the filesystem changes needed, including: - - - Calling towncrier to handle CHANGES.rst - - Add the version number to ``versionadded``, ``versionchanged`` and - ``deprecated`` directives in Python source. - """ - if data['name'] != 'gevent': - # We are specified in ``setup.cfg``, not ``setup.py``, so we do not - # come into play for other projects, only this one. We shouldn't - # need this check, but there it is. - return - - import re - import os - import subprocess - from gevent.testing import modules - - new_version = data['new_version'] - - # Generate CHANGES.rst, remove old news entries. - subprocess.check_call([ - 'towncrier', - 'build', - '--version', data['new_version'], - '--yes' - ]) - - data['update_history'] = False # Because towncrier already did. - - # But unstage it; we want it to show in the diff zest.releaser will do - subprocess.check_call([ - 'git', - 'restore', - '--staged', - 'CHANGES.rst', - ]) - - # Put the version number in source files. - regex = re.compile(b'.. (versionchanged|versionadded|deprecated):: NEXT') - if not isinstance(new_version, bytes): - new_version_bytes = new_version.encode('ascii') - else: - new_version_bytes = new_version - new_version_bytes = new_version.encode('ascii') - replacement = br'.. \1:: %s' % (new_version_bytes,) - # TODO: This should also look in the docs/ directory at - # *.rst - for path, _ in modules.walk_modules( - # Start here - basedir=os.path.join(data['reporoot'], 'src', 'gevent'), - # Include sub-dirs - recursive=True, - # Include tests - include_tests=True, - # and other things usually excluded - excluded_modules=(), - # Don't return build binaries - include_so=False, - # Don't try to import things; we want all files. - check_optional=False, - ): - with open(path, 'rb') as f: - contents = f.read() - new_contents, count = regex.subn(replacement, contents) - if count: - print("Replaced version NEXT in", path) - with open(path, 'wb') as f: - f.write(new_contents) - -def postreleaser_before(data): # pragma: no cover - """ - Prevents zest.releaser from modifying the CHANGES.rst to add the - 'no changes yet' section; towncrier is in charge of CHANGES.rst. - - Needs zest.releaser 6.15.0. - """ - if data['name'] != 'gevent': - # We are specified in ``setup.cfg``, not ``setup.py``, so we do not - # come into play for other projects, only this one. We shouldn't - # need this check, but there it is. - return - - data['update_history'] = False diff --git a/venv/lib/python3.9/site-packages/gevent/_waiter.py b/venv/lib/python3.9/site-packages/gevent/_waiter.py deleted file mode 100644 index f081d04..0000000 --- a/venv/lib/python3.9/site-packages/gevent/_waiter.py +++ /dev/null @@ -1,207 +0,0 @@ -# -*- coding: utf-8 -*- -# copyright 2018 gevent -# cython: auto_pickle=False,embedsignature=True,always_allow_keywords=False -""" -Low-level waiting primitives. - -""" -from __future__ import absolute_import -from __future__ import division -from __future__ import print_function - -import sys - -from gevent._hub_local import get_hub_noargs as get_hub -from gevent.exceptions import ConcurrentObjectUseError - -__all__ = [ - 'Waiter', -] - -_NONE = object() - -locals()['getcurrent'] = __import__('greenlet').getcurrent -locals()['greenlet_init'] = lambda: None - - -class Waiter(object): - """ - A low level communication utility for greenlets. - - Waiter is a wrapper around greenlet's ``switch()`` and ``throw()`` calls that makes them somewhat safer: - - * switching will occur only if the waiting greenlet is executing :meth:`get` method currently; - * any error raised in the greenlet is handled inside :meth:`switch` and :meth:`throw` - * if :meth:`switch`/:meth:`throw` is called before the receiver calls :meth:`get`, then :class:`Waiter` - will store the value/exception. The following :meth:`get` will return the value/raise the exception. - - The :meth:`switch` and :meth:`throw` methods must only be called from the :class:`Hub` greenlet. - The :meth:`get` method must be called from a greenlet other than :class:`Hub`. - - >>> from gevent.hub import Waiter - >>> from gevent import get_hub - >>> result = Waiter() - >>> timer = get_hub().loop.timer(0.1) - >>> timer.start(result.switch, 'hello from Waiter') - >>> result.get() # blocks for 0.1 seconds - 'hello from Waiter' - >>> timer.close() - - If switch is called before the greenlet gets a chance to call :meth:`get` then - :class:`Waiter` stores the value. - - >>> from gevent.time import sleep - >>> result = Waiter() - >>> timer = get_hub().loop.timer(0.1) - >>> timer.start(result.switch, 'hi from Waiter') - >>> sleep(0.2) - >>> result.get() # returns immediately without blocking - 'hi from Waiter' - >>> timer.close() - - .. warning:: - - This is a limited and dangerous way to communicate between - greenlets. It can easily leave a greenlet unscheduled forever - if used incorrectly. Consider using safer classes such as - :class:`gevent.event.Event`, :class:`gevent.event.AsyncResult`, - or :class:`gevent.queue.Queue`. - """ - - __slots__ = ['hub', 'greenlet', 'value', '_exception'] - - def __init__(self, hub=None): - self.hub = get_hub() if hub is None else hub - self.greenlet = None - self.value = None - self._exception = _NONE - - def clear(self): - self.greenlet = None - self.value = None - self._exception = _NONE - - def __str__(self): - if self._exception is _NONE: - return '<%s greenlet=%s>' % (type(self).__name__, self.greenlet) - if self._exception is None: - return '<%s greenlet=%s value=%r>' % (type(self).__name__, self.greenlet, self.value) - return '<%s greenlet=%s exc_info=%r>' % (type(self).__name__, self.greenlet, self.exc_info) - - def ready(self): - """Return true if and only if it holds a value or an exception""" - return self._exception is not _NONE - - def successful(self): - """Return true if and only if it is ready and holds a value""" - return self._exception is None - - @property - def exc_info(self): - "Holds the exception info passed to :meth:`throw` if :meth:`throw` was called. Otherwise ``None``." - if self._exception is not _NONE: - return self._exception - - def switch(self, value): - """ - Switch to the greenlet if one's available. Otherwise store the - *value*. - - .. versionchanged:: 1.3b1 - The *value* is no longer optional. - """ - greenlet = self.greenlet - if greenlet is None: - self.value = value - self._exception = None - else: - if getcurrent() is not self.hub: # pylint:disable=undefined-variable - raise AssertionError("Can only use Waiter.switch method from the Hub greenlet") - switch = greenlet.switch - try: - switch(value) - except: # pylint:disable=bare-except - self.hub.handle_error(switch, *sys.exc_info()) - - def switch_args(self, *args): - return self.switch(args) - - def throw(self, *throw_args): - """Switch to the greenlet with the exception. If there's no greenlet, store the exception.""" - greenlet = self.greenlet - if greenlet is None: - self._exception = throw_args - else: - if getcurrent() is not self.hub: # pylint:disable=undefined-variable - raise AssertionError("Can only use Waiter.switch method from the Hub greenlet") - throw = greenlet.throw - try: - throw(*throw_args) - except: # pylint:disable=bare-except - self.hub.handle_error(throw, *sys.exc_info()) - - def get(self): - """If a value/an exception is stored, return/raise it. Otherwise until switch() or throw() is called.""" - if self._exception is not _NONE: - if self._exception is None: - return self.value - getcurrent().throw(*self._exception) # pylint:disable=undefined-variable - else: - if self.greenlet is not None: - raise ConcurrentObjectUseError('This Waiter is already used by %r' % (self.greenlet, )) - self.greenlet = getcurrent() # pylint:disable=undefined-variable - try: - return self.hub.switch() - finally: - self.greenlet = None - - def __call__(self, source): - if source.exception is None: - self.switch(source.value) - else: - self.throw(source.exception) - - # can also have a debugging version, that wraps the value in a tuple (self, value) in switch() - # and unwraps it in wait() thus checking that switch() was indeed called - - - -class MultipleWaiter(Waiter): - """ - An internal extension of Waiter that can be used if multiple objects - must be waited on, and there is a chance that in between waits greenlets - might be switched out. All greenlets that switch to this waiter - will have their value returned. - - This does not handle exceptions or throw methods. - """ - __slots__ = ['_values'] - - def __init__(self, hub=None): - Waiter.__init__(self, hub) - # we typically expect a relatively small number of these to be outstanding. - # since we pop from the left, a deque might be slightly - # more efficient, but since we're in the hub we avoid imports if - # we can help it to better support monkey-patching, and delaying the import - # here can be impractical (see https://github.com/gevent/gevent/issues/652) - self._values = [] - - def switch(self, value): - self._values.append(value) - Waiter.switch(self, True) - - def get(self): - if not self._values: - Waiter.get(self) - Waiter.clear(self) - - return self._values.pop(0) - -def _init(): - greenlet_init() # pylint:disable=undefined-variable - -_init() - - -from gevent._util import import_c_accel -import_c_accel(globals(), 'gevent.__waiter') diff --git a/venv/lib/python3.9/site-packages/gevent/ares.py b/venv/lib/python3.9/site-packages/gevent/ares.py deleted file mode 100644 index 2236b2a..0000000 --- a/venv/lib/python3.9/site-packages/gevent/ares.py +++ /dev/null @@ -1,10 +0,0 @@ -"""Backwards compatibility alias for :mod:`gevent.resolver.cares`. - -.. deprecated:: 1.3 - Use :mod:`gevent.resolver.cares` -""" -# pylint:disable=no-name-in-module,import-error -from gevent.resolver.cares import * # pylint:disable=wildcard-import,unused-wildcard-import, -import gevent.resolver.cares as _cares -__all__ = _cares.__all__ # pylint:disable=c-extension-no-member -del _cares diff --git a/venv/lib/python3.9/site-packages/gevent/backdoor.py b/venv/lib/python3.9/site-packages/gevent/backdoor.py deleted file mode 100644 index 61a82ca..0000000 --- a/venv/lib/python3.9/site-packages/gevent/backdoor.py +++ /dev/null @@ -1,264 +0,0 @@ -# Copyright (c) 2009-2014, gevent contributors -# Based on eventlet.backdoor Copyright (c) 2005-2006, Bob Ippolito -""" -Interactive greenlet-based network console that can be used in any process. - -The :class:`BackdoorServer` provides a REPL inside a running process. As -long as the process is monkey-patched, the ``BackdoorServer`` can coexist -with other elements of the process. - -.. seealso:: :class:`code.InteractiveConsole` -""" -from __future__ import print_function, absolute_import -import sys -import socket -from code import InteractiveConsole - -from gevent.greenlet import Greenlet -from gevent.hub import getcurrent -from gevent.server import StreamServer -from gevent.pool import Pool - - -__all__ = [ - 'BackdoorServer', -] - -try: - sys.ps1 -except AttributeError: - sys.ps1 = '>>> ' -try: - sys.ps2 -except AttributeError: - sys.ps2 = '... ' - -class _Greenlet_stdreplace(Greenlet): - # A greenlet that replaces sys.std[in/out/err] while running. - - __slots__ = ( - 'stdin', - 'stdout', - 'prev_stdin', - 'prev_stdout', - 'prev_stderr', - ) - - def __init__(self, *args, **kwargs): - Greenlet.__init__(self, *args, **kwargs) - self.stdin = None - self.stdout = None - self.prev_stdin = None - self.prev_stdout = None - self.prev_stderr = None - - def switch(self, *args, **kw): - if self.stdin is not None: - self.switch_in() - Greenlet.switch(self, *args, **kw) - - def switch_in(self): - self.prev_stdin = sys.stdin - self.prev_stdout = sys.stdout - self.prev_stderr = sys.stderr - - sys.stdin = self.stdin - sys.stdout = self.stdout - sys.stderr = self.stdout - - def switch_out(self): - sys.stdin = self.prev_stdin - sys.stdout = self.prev_stdout - sys.stderr = self.prev_stderr - - self.prev_stdin = self.prev_stdout = self.prev_stderr = None - - def throw(self, *args, **kwargs): - # pylint:disable=arguments-differ - if self.prev_stdin is None and self.stdin is not None: - self.switch_in() - Greenlet.throw(self, *args, **kwargs) - - def run(self): - try: - return Greenlet.run(self) - finally: - # Make sure to restore the originals. - self.switch_out() - - -class BackdoorServer(StreamServer): - """ - Provide a backdoor to a program for debugging purposes. - - .. warning:: This backdoor provides no authentication and makes no - attempt to limit what remote users can do. Anyone that - can access the server can take any action that the running - python process can. Thus, while you may bind to any interface, for - security purposes it is recommended that you bind to one - only accessible to the local machine, e.g., - 127.0.0.1/localhost. - - Basic usage:: - - from gevent.backdoor import BackdoorServer - server = BackdoorServer(('127.0.0.1', 5001), - banner="Hello from gevent backdoor!", - locals={'foo': "From defined scope!"}) - server.serve_forever() - - In a another terminal, connect with...:: - - $ telnet 127.0.0.1 5001 - Trying 127.0.0.1... - Connected to 127.0.0.1. - Escape character is '^]'. - Hello from gevent backdoor! - >> print(foo) - From defined scope! - - .. versionchanged:: 1.2a1 - Spawned greenlets are now tracked in a pool and killed when the server - is stopped. - """ - - def __init__(self, listener, locals=None, banner=None, **server_args): - """ - :keyword locals: If given, a dictionary of "builtin" values that will be available - at the top-level. - :keyword banner: If geven, a string that will be printed to each connecting user. - """ - group = Pool(greenlet_class=_Greenlet_stdreplace) # no limit on number - StreamServer.__init__(self, listener, spawn=group, **server_args) - _locals = {'__doc__': None, '__name__': '__console__'} - if locals: - _locals.update(locals) - self.locals = _locals - - self.banner = banner - self.stderr = sys.stderr - - def _create_interactive_locals(self): - # Create and return a *new* locals dictionary based on self.locals, - # and set any new entries in it. (InteractiveConsole does not - # copy its locals value) - _locals = self.locals.copy() - # __builtins__ may either be the __builtin__ module or - # __builtin__.__dict__; in the latter case typing - # locals() at the backdoor prompt spews out lots of - # useless stuff - try: - import __builtin__ - _locals["__builtins__"] = __builtin__ - except ImportError: - import builtins # pylint:disable=import-error - _locals["builtins"] = builtins - _locals['__builtins__'] = builtins - return _locals - - def handle(self, conn, _address): # pylint: disable=method-hidden - """ - Interact with one remote user. - - .. versionchanged:: 1.1b2 Each connection gets its own - ``locals`` dictionary. Previously they were shared in a - potentially unsafe manner. - """ - try: - conn.setsockopt(socket.SOL_TCP, socket.TCP_NODELAY, True) - except OSError: - pass - - raw_file = conn.makefile(mode="r") - getcurrent().stdin = _StdIn(conn, raw_file) - getcurrent().stdout = _StdErr(conn, raw_file) - - # Swizzle the inputs - getcurrent().switch_in() - try: - console = InteractiveConsole(self._create_interactive_locals()) - # Beginning in 3.6, the console likes to print "now exiting " - # but probably our socket is already closed, so this just causes problems. - console.interact(banner=self.banner, exitmsg='') # pylint:disable=unexpected-keyword-arg - - except SystemExit: - # raised by quit(); obviously this cannot propagate. - pass - finally: - raw_file.close() - conn.close() - -class _BaseFileLike(object): - - # Python 2 likes to test for this before writing to stderr. - softspace = None - encoding = 'utf-8' - - __slots__ = ( - 'sock', - 'fobj', - 'fileno', - ) - - def __init__(self, sock, stdin): - self.sock = sock - self.fobj = stdin - # On Python 3, The builtin input() function (used by the - # default InteractiveConsole) calls fileno() on - # sys.stdin. If it's the same as the C stdin's fileno, - # and isatty(fd) (C function call) returns true, - # and all of that is also true for stdout, then input() will use - # PyOS_Readline to get the input. - # - # On Python 2, the sys.stdin object has to extend the file() - # class, and return true from isatty(fileno(sys.stdin.f_fp)) - # (where f_fp is a C-level FILE* member) to use PyOS_Readline. - # - # If that doesn't hold, both versions fall back to reading and writing - # using sys.stdout.write() and sys.stdin.readline(). - self.fileno = sock.fileno - - def __getattr__(self, name): - return getattr(self.fobj, name) - - def close(self): - pass - - -class _StdErr(_BaseFileLike): - """ - A file-like object that wraps the result of socket.makefile (composition - instead of inheritance lets us work identically under CPython and PyPy). - - We write directly to the socket, avoiding the buffering that the text-oriented - makefile would want to do (otherwise we'd be at the mercy of waiting on a - flush() to get called for the remote user to see data); this beats putting - the file in binary mode and translating everywhere with a non-default - encoding. - """ - - def flush(self): - "Does nothing. raw_input() calls this, only on Python 3." - - def write(self, data): - if not isinstance(data, bytes): - data = data.encode(self.encoding) - self.sock.sendall(data) - -class _StdIn(_BaseFileLike): - # Like _StdErr, but for stdin. - - def readline(self, *a): - try: - return self.fobj.readline(*a).replace("\r\n", "\n") - except UnicodeError: - # Typically, under python 3, a ^C on the other end - return '' - -if __name__ == '__main__': - if not sys.argv[1:]: - print('USAGE: %s PORT [banner]' % sys.argv[0]) - else: - BackdoorServer(('127.0.0.1', int(sys.argv[1])), - banner=(sys.argv[2] if len(sys.argv) > 2 else None), - locals={'hello': 'world'}).serve_forever() diff --git a/venv/lib/python3.9/site-packages/gevent/baseserver.py b/venv/lib/python3.9/site-packages/gevent/baseserver.py deleted file mode 100644 index e52a4e2..0000000 --- a/venv/lib/python3.9/site-packages/gevent/baseserver.py +++ /dev/null @@ -1,443 +0,0 @@ -"""Base class for implementing servers""" -# Copyright (c) 2009-2012 Denis Bilenko. See LICENSE for details. -from __future__ import print_function -from __future__ import absolute_import -from __future__ import division - -import sys -import _socket -import errno - -from gevent.greenlet import Greenlet -from gevent.event import Event -from gevent.hub import get_hub -from gevent._compat import string_types -from gevent._compat import integer_types -from gevent._compat import xrange - - - -__all__ = ['BaseServer'] - - -# We define a helper function to handle closing the socket in -# do_handle; We'd like to bind it to a kwarg to avoid *any* lookups at -# all, but that's incompatible with the calling convention of -# do_handle. On CPython, this is ~20% faster than creating and calling -# a closure and ~10% faster than using a @staticmethod. (In theory, we -# could create a closure only once in set_handle, to wrap self._handle, -# but this is safer from a backwards compat standpoint.) -# we also avoid unpacking the *args tuple when calling/spawning this object -# for a tiny improvement (benchmark shows a wash) -def _handle_and_close_when_done(handle, close, args_tuple): - try: - return handle(*args_tuple) - finally: - close(*args_tuple) - - -class BaseServer(object): - """ - An abstract base class that implements some common functionality for the servers in gevent. - - :param listener: Either be an address that the server should bind - on or a :class:`gevent.socket.socket` instance that is already - bound (and put into listening mode in case of TCP socket). - - :keyword handle: If given, the request handler. The request - handler can be defined in a few ways. Most commonly, - subclasses will implement a ``handle`` method as an - instance method. Alternatively, a function can be passed - as the ``handle`` argument to the constructor. In either - case, the handler can later be changed by calling - :meth:`set_handle`. - - When the request handler returns, the socket used for the - request will be closed. Therefore, the handler must not return if - the socket is still in use (for example, by manually spawned greenlets). - - :keyword spawn: If provided, is called to create a new - greenlet to run the handler. By default, - :func:`gevent.spawn` is used (meaning there is no - artificial limit on the number of concurrent requests). Possible values for *spawn*: - - - a :class:`gevent.pool.Pool` instance -- ``handle`` will be executed - using :meth:`gevent.pool.Pool.spawn` only if the pool is not full. - While it is full, no new connections are accepted; - - :func:`gevent.spawn_raw` -- ``handle`` will be executed in a raw - greenlet which has a little less overhead then :class:`gevent.Greenlet` instances spawned by default; - - ``None`` -- ``handle`` will be executed right away, in the :class:`Hub` greenlet. - ``handle`` cannot use any blocking functions as it would mean switching to the :class:`Hub`. - - an integer -- a shortcut for ``gevent.pool.Pool(integer)`` - - .. versionchanged:: 1.1a1 - When the *handle* function returns from processing a connection, - the client socket will be closed. This resolves the non-deterministic - closing of the socket, fixing ResourceWarnings under Python 3 and PyPy. - .. versionchanged:: 1.5 - Now a context manager that returns itself and calls :meth:`stop` on exit. - - """ - # pylint: disable=too-many-instance-attributes,bare-except,broad-except - - #: The number of seconds to sleep in case there was an error in accept() call. - #: For consecutive errors the delay will double until it reaches max_delay. - #: When accept() finally succeeds the delay will be reset to min_delay again. - min_delay = 0.01 - - #: The maximum number of seconds to sleep in case there was an error in - #: accept() call. - max_delay = 1 - - #: Sets the maximum number of consecutive accepts that a process may perform on - #: a single wake up. High values give higher priority to high connection rates, - #: while lower values give higher priority to already established connections. - #: Default is 100. - #: - #: Note that, in case of multiple working processes on the same - #: listening socket, it should be set to a lower value. (pywsgi.WSGIServer sets it - #: to 1 when ``environ["wsgi.multiprocess"]`` is true) - #: - #: This is equivalent to libuv's `uv_tcp_simultaneous_accepts - #: `_ - #: value. Setting the environment variable UV_TCP_SINGLE_ACCEPT to a true value - #: (usually 1) changes the default to 1 (in libuv only; this does not affect gevent). - max_accept = 100 - - _spawn = Greenlet.spawn - - #: the default timeout that we wait for the client connections to close in stop() - stop_timeout = 1 - - fatal_errors = (errno.EBADF, errno.EINVAL, errno.ENOTSOCK) - - def __init__(self, listener, handle=None, spawn='default'): - self._stop_event = Event() - self._stop_event.set() - self._watcher = None - self._timer = None - self._handle = None - # XXX: FIXME: Subclasses rely on the presence or absence of the - # `socket` attribute to determine whether we are open/should be opened. - # Instead, have it be None. - # XXX: In general, the state management here is confusing. Lots of stuff is - # deferred until the various ``set_`` methods are called, and it's not documented - # when it's safe to call those - self.pool = None # can be set from ``spawn``; overrides self.full() - try: - self.set_listener(listener) - self.set_spawn(spawn) - self.set_handle(handle) - self.delay = self.min_delay - self.loop = get_hub().loop - if self.max_accept < 1: - raise ValueError('max_accept must be positive int: %r' % (self.max_accept, )) - except: - self.close() - raise - - def __enter__(self): - return self - - def __exit__(self, *args): - self.stop() - - def set_listener(self, listener): - if hasattr(listener, 'accept'): - if hasattr(listener, 'do_handshake'): - raise TypeError('Expected a regular socket, not SSLSocket: %r' % (listener, )) - self.family = listener.family - self.address = listener.getsockname() - self.socket = listener - else: - self.family, self.address = parse_address(listener) - - def set_spawn(self, spawn): - if spawn == 'default': - self.pool = None - self._spawn = self._spawn - elif hasattr(spawn, 'spawn'): - self.pool = spawn - self._spawn = spawn.spawn - elif isinstance(spawn, integer_types): - from gevent.pool import Pool - self.pool = Pool(spawn) - self._spawn = self.pool.spawn - else: - self.pool = None - self._spawn = spawn - if hasattr(self.pool, 'full'): - self.full = self.pool.full - if self.pool is not None: - self.pool._semaphore.rawlink(self._start_accepting_if_started) - - def set_handle(self, handle): - if handle is not None: - self.handle = handle - if hasattr(self, 'handle'): - self._handle = self.handle - else: - raise TypeError("'handle' must be provided") - - def _start_accepting_if_started(self, _event=None): - if self.started: - self.start_accepting() - - def start_accepting(self): - if self._watcher is None: - # just stop watcher without creating a new one? - self._watcher = self.loop.io(self.socket.fileno(), 1) - self._watcher.start(self._do_read) - - def stop_accepting(self): - if self._watcher is not None: - self._watcher.stop() - self._watcher.close() - self._watcher = None - if self._timer is not None: - self._timer.stop() - self._timer.close() - self._timer = None - - def do_handle(self, *args): - spawn = self._spawn - handle = self._handle - close = self.do_close - - try: - if spawn is None: - _handle_and_close_when_done(handle, close, args) - else: - spawn(_handle_and_close_when_done, handle, close, args) - except: - close(*args) - raise - - def do_close(self, *args): - pass - - def do_read(self): - raise NotImplementedError() - - def _do_read(self): - for _ in xrange(self.max_accept): - if self.full(): - self.stop_accepting() - if self.pool is not None: - self.pool._semaphore.rawlink(self._start_accepting_if_started) - return - try: - args = self.do_read() - self.delay = self.min_delay - if not args: - return - except: - self.loop.handle_error(self, *sys.exc_info()) - ex = sys.exc_info()[1] - if self.is_fatal_error(ex): - self.close() - sys.stderr.write('ERROR: %s failed with %s\n' % (self, str(ex) or repr(ex))) - return - if self.delay >= 0: - self.stop_accepting() - self._timer = self.loop.timer(self.delay) - self._timer.start(self._start_accepting_if_started) - self.delay = min(self.max_delay, self.delay * 2) - break - else: - try: - self.do_handle(*args) - except: - self.loop.handle_error((args[1:], self), *sys.exc_info()) - if self.delay >= 0: - self.stop_accepting() - self._timer = self.loop.timer(self.delay) - self._timer.start(self._start_accepting_if_started) - self.delay = min(self.max_delay, self.delay * 2) - break - - def full(self): # pylint: disable=method-hidden - # If a Pool is given for to ``set_spawn`` (the *spawn* argument - # of the constructor) it will replace this method. - return False - - def __repr__(self): - return '<%s at %s %s>' % (type(self).__name__, hex(id(self)), self._formatinfo()) - - def __str__(self): - return '<%s %s>' % (type(self).__name__, self._formatinfo()) - - def _formatinfo(self): - if hasattr(self, 'socket'): - try: - fileno = self.socket.fileno() - except Exception as ex: - fileno = str(ex) - result = 'fileno=%s ' % fileno - else: - result = '' - try: - if isinstance(self.address, tuple) and len(self.address) == 2: - result += 'address=%s:%s' % self.address - else: - result += 'address=%s' % (self.address, ) - except Exception as ex: - result += str(ex) or '' - - handle = self.__dict__.get('handle') - if handle is not None: - fself = getattr(handle, '__self__', None) - try: - if fself is self: - # Checks the __self__ of the handle in case it is a bound - # method of self to prevent recursively defined reprs. - handle_repr = '' % ( - self.__class__.__name__, - handle.__name__, - ) - else: - handle_repr = repr(handle) - - result += ' handle=' + handle_repr - except Exception as ex: - result += str(ex) or '' - - return result - - @property - def server_host(self): - """IP address that the server is bound to (string).""" - if isinstance(self.address, tuple): - return self.address[0] - - @property - def server_port(self): - """Port that the server is bound to (an integer).""" - if isinstance(self.address, tuple): - return self.address[1] - - def init_socket(self): - """ - If the user initialized the server with an address rather than - socket, then this function must create a socket, bind it, and - put it into listening mode. - - It is not supposed to be called by the user, it is called by :meth:`start` before starting - the accept loop. - """ - - @property - def started(self): - return not self._stop_event.is_set() - - def start(self): - """Start accepting the connections. - - If an address was provided in the constructor, then also create a socket, - bind it and put it into the listening mode. - """ - self.init_socket() - self._stop_event.clear() - try: - self.start_accepting() - except: - self.close() - raise - - def close(self): - """Close the listener socket and stop accepting.""" - self._stop_event.set() - try: - self.stop_accepting() - finally: - try: - self.socket.close() - except Exception: - pass - finally: - self.__dict__.pop('socket', None) - self.__dict__.pop('handle', None) - self.__dict__.pop('_handle', None) - self.__dict__.pop('_spawn', None) - self.__dict__.pop('full', None) - if self.pool is not None: - self.pool._semaphore.unlink(self._start_accepting_if_started) - # If the pool's semaphore had a notifier already started, - # there's a reference cycle we're a part of - # (self->pool->semaphere-hub callback->semaphore) - # But we can't destroy self.pool, because self.stop() - # calls this method, and then wants to join self.pool() - - @property - def closed(self): - return not hasattr(self, 'socket') - - def stop(self, timeout=None): - """ - Stop accepting the connections and close the listening socket. - - If the server uses a pool to spawn the requests, then - :meth:`stop` also waits for all the handlers to exit. If there - are still handlers executing after *timeout* has expired - (default 1 second, :attr:`stop_timeout`), then the currently - running handlers in the pool are killed. - - If the server does not use a pool, then this merely stops accepting connections; - any spawned greenlets that are handling requests continue running until - they naturally complete. - """ - self.close() - if timeout is None: - timeout = self.stop_timeout - if self.pool: - self.pool.join(timeout=timeout) - self.pool.kill(block=True, timeout=1) - - - def serve_forever(self, stop_timeout=None): - """Start the server if it hasn't been already started and wait until it's stopped.""" - # add test that serve_forever exists on stop() - if not self.started: - self.start() - try: - self._stop_event.wait() - finally: - Greenlet.spawn(self.stop, timeout=stop_timeout).join() - - def is_fatal_error(self, ex): - return isinstance(ex, _socket.error) and ex.args[0] in self.fatal_errors - - -def _extract_family(host): - if host.startswith('[') and host.endswith(']'): - host = host[1:-1] - return _socket.AF_INET6, host - return _socket.AF_INET, host - - -def _parse_address(address): - if isinstance(address, tuple): - if not address[0] or ':' in address[0]: - return _socket.AF_INET6, address - return _socket.AF_INET, address - - if ((isinstance(address, string_types) and ':' not in address) - or isinstance(address, integer_types)): # noqa (pep8 E129) - # Just a port - return _socket.AF_INET6, ('', int(address)) - - if not isinstance(address, string_types): - raise TypeError('Expected tuple or string, got %s' % type(address)) - - host, port = address.rsplit(':', 1) - family, host = _extract_family(host) - if host == '*': - host = '' - return family, (host, int(port)) - - -def parse_address(address): - try: - return _parse_address(address) - except ValueError as ex: # pylint:disable=try-except-raise - raise ValueError('Failed to parse address %r: %s' % (address, ex)) diff --git a/venv/lib/python3.9/site-packages/gevent/builtins.py b/venv/lib/python3.9/site-packages/gevent/builtins.py deleted file mode 100644 index 6223f4a..0000000 --- a/venv/lib/python3.9/site-packages/gevent/builtins.py +++ /dev/null @@ -1,122 +0,0 @@ -# Copyright (c) 2015 gevent contributors. See LICENSE for details. -"""gevent friendly implementations of builtin functions.""" -from __future__ import absolute_import - -import weakref - -from gevent.lock import RLock -from gevent._compat import imp_acquire_lock -from gevent._compat import imp_release_lock - - - -import builtins as __gbuiltins__ -_allowed_module_name_types = (str,) -__target__ = 'builtins' - -_import = __gbuiltins__.__import__ - -# We need to protect imports both across threads and across greenlets. -# And the order matters. Note that under 3.4, the global import lock -# and imp module are deprecated. It seems that in all Py3 versions, a -# module lock is used such that this fix is not necessary. - -# We emulate the per-module locking system under Python 2 in order to -# avoid issues acquiring locks in multiple-level-deep imports -# that attempt to use the gevent blocking API at runtime; using one lock -# could lead to a LoopExit error as a greenlet attempts to block on it while -# it's already held by the main greenlet (issue #798). - -# We base this approach on a simplification of what `importlib._bootstrap` -# does; notably, we don't check for deadlocks - -_g_import_locks = {} # name -> wref of RLock - -__lock_imports = True - - -def __module_lock(name): - # Return the lock for the given module, creating it if necessary. - # It will be removed when no longer needed. - # Nothing in this function yields, so we're multi-greenlet safe - # (But not multi-threading safe.) - # XXX: What about on PyPy, where the GC is asynchronous (not ref-counting)? - # (Does it stop-the-world first?) - lock = None - try: - lock = _g_import_locks[name]() - except KeyError: - pass - - if lock is None: - lock = RLock() - - def cb(_): - # We've seen a KeyError on PyPy on RPi2 - _g_import_locks.pop(name, None) - _g_import_locks[name] = weakref.ref(lock, cb) - return lock - - -def __import__(*args, **kwargs): - """ - __import__(name, globals=None, locals=None, fromlist=(), level=0) -> object - - Normally python protects imports against concurrency by doing some locking - at the C level (at least, it does that in CPython). This function just - wraps the normal __import__ functionality in a recursive lock, ensuring that - we're protected against greenlet import concurrency as well. - """ - if args and not issubclass(type(args[0]), _allowed_module_name_types): - # if a builtin has been acquired as a bound instance method, - # python knows not to pass 'self' when the method is called. - # No such protection exists for monkey-patched builtins, - # however, so this is necessary. - args = args[1:] - - if not __lock_imports: - return _import(*args, **kwargs) - - module_lock = __module_lock(args[0]) # Get a lock for the module name - imp_acquire_lock() - try: - module_lock.acquire() - try: - result = _import(*args, **kwargs) - finally: - module_lock.release() - finally: - imp_release_lock() - return result - - -def _unlock_imports(): - """ - Internal function, called when gevent needs to perform imports - lazily, but does not know the state of the system. It may be impossible - to take the import lock because there are no other running greenlets, for - example. This causes a monkey-patched __import__ to avoid taking any locks. - until the corresponding call to lock_imports. This should only be done for limited - amounts of time and when the set of imports is statically known to be "safe". - """ - global __lock_imports - # This could easily become a list that we push/pop from or an integer - # we increment if we need to do this recursively, but we shouldn't get - # that complex. - __lock_imports = False - - -def _lock_imports(): - global __lock_imports - __lock_imports = True - - -__implements__ = [] -__import__ = _import -__all__ = __implements__ - - -from gevent._util import copy_globals - -__imports__ = copy_globals(__gbuiltins__, globals(), - names_to_ignore=__implements__) diff --git a/venv/lib/python3.9/site-packages/gevent/contextvars.py b/venv/lib/python3.9/site-packages/gevent/contextvars.py deleted file mode 100644 index 31dcbdd..0000000 --- a/venv/lib/python3.9/site-packages/gevent/contextvars.py +++ /dev/null @@ -1,348 +0,0 @@ -# -*- coding: utf-8 -*- -""" -Cooperative ``contextvars`` module. - -This module was added to Python 3.7. The gevent version is available -on all supported versions of Python. However, see an important note -about gevent 20.9. - -Context variables are like greenlet-local variables, just more -inconvenient to use. They were designed to work around limitations in -:mod:`asyncio` and are rarely needed by greenlet-based code. - -The primary difference is that snapshots of the state of all context -variables in a given greenlet can be taken, and later restored for -execution; modifications to context variables are "scoped" to the -duration that a particular context is active. (This state-restoration -support is rarely useful for greenlets because instead of always -running "tasks" sequentially within a single thread like `asyncio` -does, greenlet-based code usually spawns new greenlets to handle each -task.) - -The gevent implementation is based on the Python reference implementation -from :pep:`567` and doesn't have much optimization. In particular, setting -context values isn't constant time. - -.. versionadded:: 1.5a3 -.. versionchanged:: 20.9.0 - On Python 3.7 and above, this module is no longer monkey-patched - in place of the standard library version. - gevent depends on greenlet 0.4.17 which includes support for context variables. - This means that any number of greenlets can be running any number of asyncio tasks - each with their own context variables. This module is only greenlet aware, not - asyncio task aware, so its use is not recommended on Python 3.7 and above. - - On previous versions of Python, this module continues to be a solution for - backporting code. It is also available if you wish to use the contextvar API - in a strictly greenlet-local manner. -""" -from __future__ import absolute_import -from __future__ import division -from __future__ import print_function - - -__all__ = [ - 'ContextVar', - 'Context', - 'copy_context', - 'Token', -] - -try: - from collections.abc import Mapping -except ImportError: - from collections import Mapping # pylint:disable=deprecated-class - - -from gevent._util import _NONE -from gevent.local import local - -__stdlib_expected__ = __all__ -__implements__ = __stdlib_expected__ - -# In the reference implementation, the interpreter level OS thread state -# is modified to contain a pointer to the current context. Obviously we can't -# touch that here because we're not tied to CPython's internals; plus, of course, -# we want to operate with greenlets, not OS threads. So we use a greenlet-local object -# to store the active context. -class _ContextState(local): - - def __init__(self): - self.context = Context() - - -def _not_base_type(cls): - # This is not given in the PEP but is tested in test_context. - # Assign this method to __init_subclass__ in each type that can't - # be subclassed. (This only works in 3.6+, but context vars are only in - # 3.7+) - raise TypeError("not an acceptable base type") - -class _ContextData(object): - """ - A copy-on-write immutable mapping from ContextVar - keys to arbitrary values. Setting values requires a - copy, making it O(n), not O(1). - """ - - # In theory, the HAMT used by the stdlib contextvars module could - # be used: It's often available at _testcapi.hamt() (see - # test_context). We'd need to be sure to add a correct __hash__ - # method to ContextVar to make that work well. (See - # Python/context.c:contextvar_generate_hash.) - - __slots__ = ( - '_mapping', - ) - - def __init__(self): - self._mapping = {} - - def __getitem__(self, key): - return self._mapping[key] - - def __contains__(self, key): - return key in self._mapping - - def __len__(self): - return len(self._mapping) - - def __iter__(self): - return iter(self._mapping) - - def set(self, key, value): - copy = _ContextData() - copy._mapping = self._mapping.copy() - copy._mapping[key] = value - return copy - - def delete(self, key): - copy = _ContextData() - copy._mapping = self._mapping.copy() - del copy._mapping[key] - return copy - - -class ContextVar(object): - """ - Implementation of :class:`contextvars.ContextVar`. - """ - - __slots__ = ( - '_name', - '_default', - ) - - def __init__(self, name, default=_NONE): - self._name = name - self._default = default - - __init_subclass__ = classmethod(_not_base_type) - - @classmethod - def __class_getitem__(cls, _): - # For typing support: ContextVar[str]. - # Not in the PEP. - # sigh. - return cls - - @property - def name(self): - return self._name - - def get(self, default=_NONE): - context = _context_state.context - try: - return context[self] - except KeyError: - pass - - if default is not _NONE: - return default - - if self._default is not _NONE: - return self._default - - raise LookupError - - def set(self, value): - context = _context_state.context - return context._set_value(self, value) - - def reset(self, token): - token._reset(self) - - def __repr__(self): - # This is not captured in the PEP but is tested by test_context - return '<%s.%s name=%r default=%r at 0x%x>' % ( - type(self).__module__, - type(self).__name__, - self._name, - self._default, - id(self) - ) - - -class Token(object): - """ - Opaque implementation of :class:`contextvars.Token`. - """ - - MISSING = _NONE - - __slots__ = ( - '_context', - '_var', - '_old_value', - '_used', - ) - - def __init__(self, context, var, old_value): - self._context = context - self._var = var - self._old_value = old_value - self._used = False - - __init_subclass__ = classmethod(_not_base_type) - - @property - def var(self): - """ - A read-only attribute pointing to the variable that created the token - """ - return self._var - - @property - def old_value(self): - """ - A read-only attribute set to the value the variable had before - the ``set()`` call, or to :attr:`MISSING` if the variable wasn't set - before. - """ - return self._old_value - - def _reset(self, var): - if self._used: - raise RuntimeError("Taken has already been used once") - - if self._var is not var: - raise ValueError("Token was created by a different ContextVar") - - if self._context is not _context_state.context: - raise ValueError("Token was created in a different Context") - - self._used = True - if self._old_value is self.MISSING: - self._context._delete(var) - else: - self._context._reset_value(var, self._old_value) - - def __repr__(self): - # This is not captured in the PEP but is tested by test_context - return '<%s.%s%s var=%r at 0x%x>' % ( - type(self).__module__, - type(self).__name__, - ' used' if self._used else '', - self._var, - id(self), - ) - -class Context(Mapping): - """ - Implementation of :class:`contextvars.Context` - """ - - __slots__ = ( - '_data', - '_prev_context', - ) - - def __init__(self): - """ - Creates an empty context. - """ - self._data = _ContextData() - self._prev_context = None - - __init_subclass__ = classmethod(_not_base_type) - - def run(self, function, *args, **kwargs): - if self._prev_context is not None: - raise RuntimeError( - "Cannot enter context; %s is already entered" % (self,) - ) - - self._prev_context = _context_state.context - try: - _context_state.context = self - return function(*args, **kwargs) - finally: - _context_state.context = self._prev_context - self._prev_context = None - - def copy(self): - """ - Return a shallow copy. - """ - result = Context() - result._data = self._data - return result - - ### - # Operations used by ContextVar and Token - ### - - def _set_value(self, var, value): - try: - old_value = self._data[var] - except KeyError: - old_value = Token.MISSING - - self._data = self._data.set(var, value) - return Token(self, var, old_value) - - def _delete(self, var): - self._data = self._data.delete(var) - - def _reset_value(self, var, old_value): - self._data = self._data.set(var, old_value) - - # Note that all Mapping methods, including Context.__getitem__ and - # Context.get, ignore default values for context variables (i.e. - # ContextVar.default). This means that for a variable var that was - # created with a default value and was not set in the context: - # - # - context[var] raises a KeyError, - # - var in context returns False, - # - the variable isn't included in context.items(), etc. - - # Checking the type of key isn't part of the PEP but is tested by - # test_context.py. - @staticmethod - def __check_key(key): - if type(key) is not ContextVar: # pylint:disable=unidiomatic-typecheck - raise TypeError("ContextVar key was expected") - - def __getitem__(self, key): - self.__check_key(key) - return self._data[key] - - def __contains__(self, key): - self.__check_key(key) - return key in self._data - - def __len__(self): - return len(self._data) - - def __iter__(self): - return iter(self._data) - - -def copy_context(): - """ - Return a shallow copy of the current context. - """ - return _context_state.context.copy() - - -_context_state = _ContextState() diff --git a/venv/lib/python3.9/site-packages/gevent/core.py b/venv/lib/python3.9/site-packages/gevent/core.py deleted file mode 100644 index 906e739..0000000 --- a/venv/lib/python3.9/site-packages/gevent/core.py +++ /dev/null @@ -1,20 +0,0 @@ -# Copyright (c) 2009-2015 Denis Bilenko and gevent contributors. See LICENSE for details. -""" -Deprecated; this does not reflect all the possible options -and its interface varies. - -.. versionchanged:: 1.3a2 - Deprecated. -""" -from __future__ import absolute_import - -import sys - -from gevent._config import config -from gevent._util import copy_globals - -_core = sys.modules[config.loop.__module__] - -copy_globals(_core, globals()) - -__all__ = _core.__all__ # pylint:disable=no-member diff --git a/venv/lib/python3.9/site-packages/gevent/event.py b/venv/lib/python3.9/site-packages/gevent/event.py deleted file mode 100644 index 12d72f8..0000000 --- a/venv/lib/python3.9/site-packages/gevent/event.py +++ /dev/null @@ -1,429 +0,0 @@ -# Copyright (c) 2009-2016 Denis Bilenko, gevent contributors. See LICENSE for details. -# cython: auto_pickle=False,embedsignature=True,always_allow_keywords=False,infer_types=True - -"""Basic synchronization primitives: Event and AsyncResult""" -from __future__ import print_function - -from gevent._util import _NONE -from gevent._compat import reraise -from gevent._tblib import dump_traceback, load_traceback - -from gevent.timeout import Timeout - - -__all__ = [ - 'Event', - 'AsyncResult', -] - -def _get_linkable(): - x = __import__('gevent._abstract_linkable') - return x._abstract_linkable.AbstractLinkable -locals()['AbstractLinkable'] = _get_linkable() -del _get_linkable - - -class Event(AbstractLinkable): # pylint:disable=undefined-variable - """ - A synchronization primitive that allows one greenlet to wake up - one or more others. It has the same interface as - :class:`threading.Event` but works across greenlets. - - .. important:: - This object is for communicating among greenlets within the - same thread *only*! Do not try to use it to communicate across threads. - - An event object manages an internal flag that can be set to true - with the :meth:`set` method and reset to false with the - :meth:`clear` method. The :meth:`wait` method blocks until the - flag is true; as soon as the flag is set to true, all greenlets - that are currently blocked in a call to :meth:`wait` will be scheduled - to awaken. - - Note that the flag may be cleared and set many times before - any individual greenlet runs; all the greenlet can know for sure is that the - flag was set *at least once* while it was waiting. - If the greenlet cares whether the flag is still - set, it must check with :meth:`ready` and possibly call back into - :meth:`wait` again. - - .. note:: - - The exact order and timing in which waiting greenlets are awakened is not determined. - - Once the event is set, other greenlets may run before any waiting greenlets - are awakened. - - While the code here will awaken greenlets in the order in which they - waited, each such greenlet that runs may in turn cause other greenlets - to run. - - These details may change in the future. - - .. versionchanged:: 1.5a3 - - Waiting greenlets are now awakened in - the order in which they waited. - - .. versionchanged:: 1.5a3 - - The low-level ``rawlink`` method (most users won't use this) now - automatically unlinks waiters before calling them. - - .. versionchanged:: 20.5.1 - - Callers to ``wait`` that find the event already set will now run - after any other waiters that had to block. See :issue:`1520`. - """ - - __slots__ = ('_flag',) - - def __init__(self): - super(Event, self).__init__() - self._flag = False - - def __str__(self): - return '<%s.%s at 0x%x %s _links[%s]>' % ( - self.__class__.__module__, - self.__class__.__name__, - id(self), - 'set' if self._flag else 'clear', - self.linkcount() - ) - - def is_set(self): - """Return true if and only if the internal flag is true.""" - return self._flag - - def isSet(self): - # makes it a better drop-in replacement for threading.Event - return self._flag - - def ready(self): - # makes it compatible with AsyncResult and Greenlet (for - # example in wait()) - return self._flag - - def set(self): - """ - Set the internal flag to true. - - All greenlets waiting for it to become true are awakened in - some order at some time in the future. Greenlets that call - :meth:`wait` once the flag is true will not block at all - (until :meth:`clear` is called). - """ - self._flag = True - self._check_and_notify() - - def clear(self): - """ - Reset the internal flag to false. - - Subsequently, threads calling :meth:`wait` will block until - :meth:`set` is called to set the internal flag to true again. - """ - self._flag = False - - def _wait_return_value(self, waited, wait_success): - # To avoid the race condition outlined in http://bugs.python.org/issue13502, - # if we had to wait, then we need to return whether or not - # the condition got changed. Otherwise we simply echo - # the current state of the flag (which should be true) - if not waited: - flag = self._flag - assert flag, "if we didn't wait we should already be set" - return flag - - return wait_success - - def wait(self, timeout=None): - """ - Block until this object is :meth:`ready`. - - If the internal flag is true on entry, return immediately. Otherwise, - block until another thread (greenlet) calls :meth:`set` to set the flag to true, - or until the optional *timeout* expires. - - When the *timeout* argument is present and not ``None``, it should be a - floating point number specifying a timeout for the operation in seconds - (or fractions thereof). - - :return: This method returns true if and only if the internal flag has been set to - true, either before the wait call or after the wait starts, so it will - always return ``True`` except if a timeout is given and the operation - times out. - - .. versionchanged:: 1.1 - The return value represents the flag during the elapsed wait, not - just after it elapses. This solves a race condition if one greenlet - sets and then clears the flag without switching, while other greenlets - are waiting. When the waiters wake up, this will return True; previously, - they would still wake up, but the return value would be False. This is most - noticeable when the *timeout* is present. - """ - return self._wait(timeout) - - def _reset_internal_locks(self): # pragma: no cover - # for compatibility with threading.Event - # Exception AttributeError: AttributeError("'Event' object has no attribute '_reset_internal_locks'",) - # in ignored - pass - - - -class AsyncResult(AbstractLinkable): # pylint:disable=undefined-variable - """ - A one-time event that stores a value or an exception. - - Like :class:`Event` it wakes up all the waiters when :meth:`set` - or :meth:`set_exception` is called. Waiters may receive the passed - value or exception by calling :meth:`get` instead of :meth:`wait`. - An :class:`AsyncResult` instance cannot be reset. - - .. important:: - This object is for communicating among greenlets within the - same thread *only*! Do not try to use it to communicate across threads. - - To pass a value call :meth:`set`. Calls to :meth:`get` (those that - are currently blocking as well as those made in the future) will - return the value:: - - >>> from gevent.event import AsyncResult - >>> result = AsyncResult() - >>> result.set(100) - >>> result.get() - 100 - - To pass an exception call :meth:`set_exception`. This will cause - :meth:`get` to raise that exception:: - - >>> result = AsyncResult() - >>> result.set_exception(RuntimeError('failure')) - >>> result.get() - Traceback (most recent call last): - ... - RuntimeError: failure - - :class:`AsyncResult` implements :meth:`__call__` and thus can be - used as :meth:`link` target:: - - >>> import gevent - >>> result = AsyncResult() - >>> gevent.spawn(lambda : 1/0).link(result) - >>> try: - ... result.get() - ... except ZeroDivisionError: - ... print('ZeroDivisionError') - ZeroDivisionError - - .. note:: - - The order and timing in which waiting greenlets are awakened is not determined. - As an implementation note, in gevent 1.1 and 1.0, waiting greenlets are awakened in a - undetermined order sometime *after* the current greenlet yields to the event loop. Other greenlets - (those not waiting to be awakened) may run between the current greenlet yielding and - the waiting greenlets being awakened. These details may change in the future. - - .. versionchanged:: 1.1 - - The exact order in which waiting greenlets - are awakened is not the same as in 1.0. - - .. versionchanged:: 1.1 - - Callbacks :meth:`linked ` to this object are required to - be hashable, and duplicates are merged. - - .. versionchanged:: 1.5a3 - - Waiting greenlets are now awakened in the order in which they - waited. - - .. versionchanged:: 1.5a3 - - The low-level ``rawlink`` method - (most users won't use this) now automatically unlinks waiters - before calling them. - """ - - __slots__ = ('_value', '_exc_info', '_imap_task_index') - - def __init__(self): - super(AsyncResult, self).__init__() - self._value = _NONE - self._exc_info = () - - @property - def _exception(self): - return self._exc_info[1] if self._exc_info else _NONE - - @property - def value(self): - """ - Holds the value passed to :meth:`set` if :meth:`set` was called. Otherwise, - ``None`` - """ - return self._value if self._value is not _NONE else None - - @property - def exc_info(self): - """ - The three-tuple of exception information if :meth:`set_exception` was called. - """ - if self._exc_info: - return (self._exc_info[0], self._exc_info[1], load_traceback(self._exc_info[2])) - return () - - def __str__(self): - result = '<%s ' % (self.__class__.__name__, ) - if self.value is not None or self._exception is not _NONE: - result += 'value=%r ' % self.value - if self._exception is not None and self._exception is not _NONE: - result += 'exception=%r ' % self._exception - if self._exception is _NONE: - result += 'unset ' - return result + ' _links[%s]>' % self.linkcount() - - def ready(self): - """Return true if and only if it holds a value or an exception""" - return self._exc_info or self._value is not _NONE - - def successful(self): - """Return true if and only if it is ready and holds a value""" - return self._value is not _NONE - - @property - def exception(self): - """Holds the exception instance passed to :meth:`set_exception` if :meth:`set_exception` was called. - Otherwise ``None``.""" - if self._exc_info: - return self._exc_info[1] - - def set(self, value=None): - """Store the value and wake up any waiters. - - All greenlets blocking on :meth:`get` or :meth:`wait` are awakened. - Subsequent calls to :meth:`wait` and :meth:`get` will not block at all. - """ - self._value = value - self._check_and_notify() - - def set_exception(self, exception, exc_info=None): - """Store the exception and wake up any waiters. - - All greenlets blocking on :meth:`get` or :meth:`wait` are awakened. - Subsequent calls to :meth:`wait` and :meth:`get` will not block at all. - - :keyword tuple exc_info: If given, a standard three-tuple of type, value, :class:`traceback` - as returned by :func:`sys.exc_info`. This will be used when the exception - is re-raised to propagate the correct traceback. - """ - if exc_info: - self._exc_info = (exc_info[0], exc_info[1], dump_traceback(exc_info[2])) - else: - self._exc_info = (type(exception), exception, dump_traceback(None)) - - self._check_and_notify() - - def _raise_exception(self): - reraise(*self.exc_info) - - def get(self, block=True, timeout=None): - """Return the stored value or raise the exception. - - If this instance already holds a value or an exception, return or raise it immediately. - Otherwise, block until another greenlet calls :meth:`set` or :meth:`set_exception` or - until the optional timeout occurs. - - When the *timeout* argument is present and not ``None``, it should be a - floating point number specifying a timeout for the operation in seconds - (or fractions thereof). If the *timeout* elapses, the *Timeout* exception will - be raised. - - :keyword bool block: If set to ``False`` and this instance is not ready, - immediately raise a :class:`Timeout` exception. - """ - if self._value is not _NONE: - return self._value - if self._exc_info: - return self._raise_exception() - - if not block: - # Not ready and not blocking, so immediately timeout - raise Timeout() - - self._capture_hub(True) - - # Wait, raising a timeout that elapses - self._wait_core(timeout, ()) - - # by definition we are now ready - return self.get(block=False) - - def get_nowait(self): - """ - Return the value or raise the exception without blocking. - - If this object is not yet :meth:`ready `, raise - :class:`gevent.Timeout` immediately. - """ - return self.get(block=False) - - def _wait_return_value(self, waited, wait_success): - # pylint:disable=unused-argument - # Always return the value. Since this is a one-shot event, - # no race condition should reset it. - return self.value - - def wait(self, timeout=None): - """Block until the instance is ready. - - If this instance already holds a value, it is returned immediately. If this - instance already holds an exception, ``None`` is returned immediately. - - Otherwise, block until another greenlet calls :meth:`set` or :meth:`set_exception` - (at which point either the value or ``None`` will be returned, respectively), - or until the optional timeout expires (at which point ``None`` will also be - returned). - - When the *timeout* argument is present and not ``None``, it should be a - floating point number specifying a timeout for the operation in seconds - (or fractions thereof). - - .. note:: If a timeout is given and expires, ``None`` will be returned - (no timeout exception will be raised). - - """ - return self._wait(timeout) - - # link protocol - def __call__(self, source): - if source.successful(): - self.set(source.value) - else: - self.set_exception(source.exception, getattr(source, 'exc_info', None)) - - # Methods to make us more like concurrent.futures.Future - - def result(self, timeout=None): - return self.get(timeout=timeout) - - set_result = set - - def done(self): - return self.ready() - - # we don't support cancelling - - def cancel(self): - return False - - def cancelled(self): - return False - - # exception is a method, we use it as a property - - -from gevent._util import import_c_accel -import_c_accel(globals(), 'gevent._event') diff --git a/venv/lib/python3.9/site-packages/gevent/events.py b/venv/lib/python3.9/site-packages/gevent/events.py deleted file mode 100644 index c14c9fd..0000000 --- a/venv/lib/python3.9/site-packages/gevent/events.py +++ /dev/null @@ -1,516 +0,0 @@ -# -*- coding: utf-8 -*- -# Copyright 2018 gevent. See LICENSE for details. -""" -Publish/subscribe event infrastructure. - -When certain "interesting" things happen during the lifetime of the -process, gevent will "publish" an event (an object). That event is -delivered to interested "subscribers" (functions that take one -parameter, the event object). - -Higher level frameworks may take this foundation and build richer -models on it. - -:mod:`zope.event` will be used to provide the functionality of -`notify` and `subscribers`. See :mod:`zope.event.classhandler` for a -simple class-based approach to subscribing to a filtered list of -events, and see `zope.component -`_ for a -much higher-level, flexible system. If you are using one of these -systems, you generally will not want to directly modify `subscribers`. - -.. versionadded:: 1.3b1 - -.. versionchanged:: 23.7.0 - Now uses :mod:`importlib.metadata` instead of :mod:`pkg_resources` - to locate entry points. -""" -from __future__ import absolute_import -from __future__ import division -from __future__ import print_function - - -__all__ = [ - 'subscribers', - - # monitor thread - 'IEventLoopBlocked', - 'EventLoopBlocked', - 'IMemoryUsageThresholdExceeded', - 'MemoryUsageThresholdExceeded', - 'IMemoryUsageUnderThreshold', - 'MemoryUsageUnderThreshold', - - # Hub - 'IPeriodicMonitorThread', - 'IPeriodicMonitorThreadStartedEvent', - 'PeriodicMonitorThreadStartedEvent', - - # monkey - 'IGeventPatchEvent', - 'GeventPatchEvent', - 'IGeventWillPatchEvent', - 'DoNotPatch', - 'GeventWillPatchEvent', - 'IGeventDidPatchEvent', - 'IGeventWillPatchModuleEvent', - 'GeventWillPatchModuleEvent', - 'IGeventDidPatchModuleEvent', - 'GeventDidPatchModuleEvent', - 'IGeventWillPatchAllEvent', - 'GeventWillPatchAllEvent', - 'IGeventDidPatchBuiltinModulesEvent', - 'GeventDidPatchBuiltinModulesEvent', - 'IGeventDidPatchAllEvent', - 'GeventDidPatchAllEvent', -] - -# pylint:disable=no-self-argument,inherit-non-class -import platform - -from zope.interface import Interface -from zope.interface import Attribute -from zope.interface import implementer - -from zope.event import subscribers -from zope.event import notify - - - -#: Applications may register for notification of events by appending a -#: callable to the ``subscribers`` list. -#: -#: Each subscriber takes a single argument, which is the event object -#: being published. -#: -#: Exceptions raised by subscribers will be propagated *without* running -#: any remaining subscribers. -#: -#: This is an alias for `zope.event.subscribers`; prefer to use -#: that attribute directly. -subscribers = subscribers - -try: - # Cache the platform info. pkg_resources uses - # platform.machine() for environment markers, and - # platform.machine() wants to call os.popen('uname'), which is - # broken on Py2 when the gevent child signal handler is - # installed. (see test__monkey_sigchild_2.py) - platform.uname() -except: # pylint:disable=bare-except - pass -finally: - del platform - -def notify_and_call_entry_points(event): - notify(event) - from importlib import metadata - import sys - # This used to use the old ``pkg_resources.iter_entry_points(group,name=None)`` - # API, passing it just the first argument, ``group=event.ENTRY_POINT_NAME``. - # In other words, we don't care about the ``name``. - if sys.version_info[:2] >= (3, 10): - # pylint:disable-next=unexpected-keyword-arg - # The only thing you can do with this is iterate it to get - # EntryPoint objects. (e.g., accessing by index raises a warning) - entry_points = metadata.entry_points(group=event.ENTRY_POINT_NAME) - else: - # Prior to 3.10, we have to do this all manually (keyword selection - # was introduced in 3.10; in 3.9 and before, entry_points returns a plain - # ``dict``). Using it like this is deprecated in 3.10, so to avoid warnings - # we have to write it twice. - # - # Prior to 3.9, there is no ``.module`` attribute, so if we - # needed that we'd have to look at the complete ``.value`` - # attribute. - ep_dict = metadata.entry_points() - __traceback_info__ = ep_dict - # On Python 3.8, we can get duplicate EntryPoint objects; it is unclear - # why. Drop them into a set to make sure we only get one. - # - # Running a more recent pylint flags the non-existence of ``get`` - # pylint:disable=no-member - entry_points = set( - ep - for ep - in ep_dict.get(event.ENTRY_POINT_NAME, ()) - ) - - for plugin in entry_points: - subscriber = plugin.load() - subscriber(event) - - -class IPeriodicMonitorThread(Interface): - """ - The contract for the periodic monitoring thread that is started - by the hub. - """ - - def add_monitoring_function(function, period): - """ - Schedule the *function* to be called approximately every *period* fractional seconds. - - The *function* receives one argument, the hub being monitored. It is called - in the monitoring thread, *not* the hub thread. It **must not** attempt to - use the gevent asynchronous API. - - If the *function* is already a monitoring function, then its *period* - will be updated for future runs. - - If the *period* is ``None``, then the function will be removed. - - A *period* less than or equal to zero is not allowed. - """ - -class IPeriodicMonitorThreadStartedEvent(Interface): - """ - The event emitted when a hub starts a periodic monitoring thread. - - You can use this event to add additional monitoring functions. - """ - - monitor = Attribute("The instance of `IPeriodicMonitorThread` that was started.") - -@implementer(IPeriodicMonitorThreadStartedEvent) -class PeriodicMonitorThreadStartedEvent(object): - """ - The implementation of :class:`IPeriodicMonitorThreadStartedEvent`. - - .. versionchanged:: 24.11.1 - Now actually implements the promised interface. - """ - - #: The name of the setuptools entry point that is called when this - #: event is emitted. - ENTRY_POINT_NAME = 'gevent.plugins.hub.periodic_monitor_thread_started' - - def __init__(self, monitor): - self.monitor = monitor - -class IEventLoopBlocked(Interface): - """ - The event emitted when the event loop is blocked. - - This event is emitted in the monitor thread. - - .. versionchanged:: 24.11.1 - Add the *hub* attribute. - """ - - greenlet = Attribute("The greenlet that appeared to be blocking the loop.") - blocking_time = Attribute("The approximate time in seconds the loop has been blocked.") - info = Attribute("A list of string lines providing extra info. You may modify this list.") - hub = Attribute("""If not None, the hub being blocked.""") - -@implementer(IEventLoopBlocked) -class EventLoopBlocked(object): - """ - The event emitted when the event loop is blocked. - - Implements `IEventLoopBlocked`. - """ - - def __init__(self, greenlet, blocking_time, info, *, hub=None): - self.greenlet = greenlet - self.blocking_time = blocking_time - self.info = info - self.hub = hub - -class IMemoryUsageThresholdExceeded(Interface): - """ - The event emitted when the memory usage threshold is exceeded. - - This event is emitted only while memory continues to grow - above the threshold. Only if the condition or stabilized is corrected (memory - usage drops) will the event be emitted in the future. - - This event is emitted in the monitor thread. - """ - - mem_usage = Attribute("The current process memory usage, in bytes.") - max_allowed = Attribute("The maximum allowed memory usage, in bytes.") - memory_info = Attribute("The tuple of memory usage stats return by psutil.") - -class _AbstractMemoryEvent(object): - - def __init__(self, mem_usage, max_allowed, memory_info): - self.mem_usage = mem_usage - self.max_allowed = max_allowed - self.memory_info = memory_info - - def __repr__(self): - return "<%s used=%d max=%d details=%r>" % ( - self.__class__.__name__, - self.mem_usage, - self.max_allowed, - self.memory_info, - ) - -@implementer(IMemoryUsageThresholdExceeded) -class MemoryUsageThresholdExceeded(_AbstractMemoryEvent): - """ - Implementation of `IMemoryUsageThresholdExceeded`. - """ - - -class IMemoryUsageUnderThreshold(Interface): - """ - The event emitted when the memory usage drops below the - threshold after having previously been above it. - - This event is emitted only the first time memory usage is detected - to be below the threshold after having previously been above it. - If memory usage climbs again, a `IMemoryUsageThresholdExceeded` - event will be broadcast, and then this event could be broadcast again. - - This event is emitted in the monitor thread. - """ - - mem_usage = Attribute("The current process memory usage, in bytes.") - max_allowed = Attribute("The maximum allowed memory usage, in bytes.") - max_memory_usage = Attribute("The memory usage that caused the previous " - "IMemoryUsageThresholdExceeded event.") - memory_info = Attribute("The tuple of memory usage stats return by psutil.") - - -@implementer(IMemoryUsageUnderThreshold) -class MemoryUsageUnderThreshold(_AbstractMemoryEvent): - """ - Implementation of `IMemoryUsageUnderThreshold`. - """ - - def __init__(self, mem_usage, max_allowed, memory_info, max_usage): - super(MemoryUsageUnderThreshold, self).__init__(mem_usage, max_allowed, memory_info) - self.max_memory_usage = max_usage - - -class IGeventPatchEvent(Interface): - """ - The root for all monkey-patch events gevent emits. - """ - - source = Attribute("The source object containing the patches.") - target = Attribute("The destination object to be patched.") - -@implementer(IGeventPatchEvent) -class GeventPatchEvent(object): - """ - Implementation of `IGeventPatchEvent`. - """ - - def __init__(self, source, target): - self.source = source - self.target = target - - def __repr__(self): - return '<%s source=%r target=%r at %x>' % (self.__class__.__name__, - self.source, - self.target, - id(self)) - -class IGeventWillPatchEvent(IGeventPatchEvent): - """ - An event emitted *before* gevent monkey-patches something. - - If a subscriber raises `DoNotPatch`, then patching this particular - item will not take place. - """ - - -class DoNotPatch(BaseException): - """ - Subscribers to will-patch events can raise instances - of this class to tell gevent not to patch that particular item. - """ - - -@implementer(IGeventWillPatchEvent) -class GeventWillPatchEvent(GeventPatchEvent): - """ - Implementation of `IGeventWillPatchEvent`. - """ - -class IGeventDidPatchEvent(IGeventPatchEvent): - """ - An event emitted *after* gevent has patched something. - """ - -@implementer(IGeventDidPatchEvent) -class GeventDidPatchEvent(GeventPatchEvent): - """ - Implementation of `IGeventDidPatchEvent`. - """ - -class IGeventWillPatchModuleEvent(IGeventWillPatchEvent): - """ - An event emitted *before* gevent begins patching a specific module. - - Both *source* and *target* attributes are module objects. - """ - - module_name = Attribute("The name of the module being patched. " - "This is the same as ``target.__name__``.") - - target_item_names = Attribute("The list of item names to patch. " - "This can be modified in place with caution.") - -@implementer(IGeventWillPatchModuleEvent) -class GeventWillPatchModuleEvent(GeventWillPatchEvent): - """ - Implementation of `IGeventWillPatchModuleEvent`. - """ - - #: The name of the setuptools entry point that is called when this - #: event is emitted. - ENTRY_POINT_NAME = 'gevent.plugins.monkey.will_patch_module' - - def __init__(self, module_name, source, target, items): - super(GeventWillPatchModuleEvent, self).__init__(source, target) - self.module_name = module_name - self.target_item_names = items - - -class IGeventDidPatchModuleEvent(IGeventDidPatchEvent): - """ - An event emitted *after* gevent has completed patching a specific - module. - """ - - module_name = Attribute("The name of the module being patched. " - "This is the same as ``target.__name__``.") - - -@implementer(IGeventDidPatchModuleEvent) -class GeventDidPatchModuleEvent(GeventDidPatchEvent): - """ - Implementation of `IGeventDidPatchModuleEvent`. - """ - - #: The name of the setuptools entry point that is called when this - #: event is emitted. - ENTRY_POINT_NAME = 'gevent.plugins.monkey.did_patch_module' - - def __init__(self, module_name, source, target): - super(GeventDidPatchModuleEvent, self).__init__(source, target) - self.module_name = module_name - -# TODO: Maybe it would be useful for the the module patch events -# to have an attribute telling if they're being done during patch_all? - -class IGeventWillPatchAllEvent(IGeventWillPatchEvent): - """ - An event emitted *before* gevent begins patching the system. - - Following this event will be a series of - `IGeventWillPatchModuleEvent` and `IGeventDidPatchModuleEvent` for - each patched module. - - Once the gevent builtin modules have been processed, - `IGeventDidPatchBuiltinModulesEvent` will be emitted. Processing - this event is an ideal time for third-party modules to be imported - and patched (which may trigger its own will/did patch module - events). - - Finally, a `IGeventDidPatchAllEvent` will be sent. - - If a subscriber to this event raises `DoNotPatch`, no patching - will be done. - - The *source* and *target* attributes have undefined values. - """ - - patch_all_arguments = Attribute( - "A dictionary of all the arguments to `gevent.monkey.patch_all`. " - "This dictionary should not be modified. " - ) - - patch_all_kwargs = Attribute( - "A dictionary of the extra arguments to `gevent.monkey.patch_all`. " - "This dictionary should not be modified. " - ) - - def will_patch_module(module_name): - """ - Return whether the module named *module_name* will be patched. - """ - -class _PatchAllMixin(object): - def __init__(self, patch_all_arguments, patch_all_kwargs): - super(_PatchAllMixin, self).__init__(None, None) - self._patch_all_arguments = patch_all_arguments - self._patch_all_kwargs = patch_all_kwargs - - @property - def patch_all_arguments(self): - return self._patch_all_arguments.copy() - - @property - def patch_all_kwargs(self): - return self._patch_all_kwargs.copy() - - def __repr__(self): - return '<%s %r at %x>' % (self.__class__.__name__, - self._patch_all_arguments, - id(self)) - -@implementer(IGeventWillPatchAllEvent) -class GeventWillPatchAllEvent(_PatchAllMixin, GeventWillPatchEvent): - """ - Implementation of `IGeventWillPatchAllEvent`. - """ - - #: The name of the setuptools entry point that is called when this - #: event is emitted. - ENTRY_POINT_NAME = 'gevent.plugins.monkey.will_patch_all' - - def will_patch_module(self, module_name): - return self.patch_all_arguments.get(module_name) - -class IGeventDidPatchBuiltinModulesEvent(IGeventDidPatchEvent): - """ - Event emitted *after* the builtin modules have been patched. - - If you're going to monkey-patch a third-party library, this is - usually the event to listen for. - - The values of the *source* and *target* attributes are undefined. - """ - - patch_all_arguments = Attribute( - "A dictionary of all the arguments to `gevent.monkey.patch_all`. " - "This dictionary should not be modified. " - ) - - patch_all_kwargs = Attribute( - "A dictionary of the extra arguments to `gevent.monkey.patch_all`. " - "This dictionary should not be modified. " - ) - -@implementer(IGeventDidPatchBuiltinModulesEvent) -class GeventDidPatchBuiltinModulesEvent(_PatchAllMixin, GeventDidPatchEvent): - """ - Implementation of `IGeventDidPatchBuiltinModulesEvent`. - """ - - #: The name of the setuptools entry point that is called when this - #: event is emitted. - ENTRY_POINT_NAME = 'gevent.plugins.monkey.did_patch_builtins' - -class IGeventDidPatchAllEvent(IGeventDidPatchEvent): - """ - Event emitted after gevent has patched all modules, both builtin - and those provided by plugins/subscribers. - - The values of the *source* and *target* attributes are undefined. - """ - -@implementer(IGeventDidPatchAllEvent) -class GeventDidPatchAllEvent(_PatchAllMixin, GeventDidPatchEvent): - """ - Implementation of `IGeventDidPatchAllEvent`. - """ - - #: The name of the setuptools entry point that is called when this - #: event is emitted. - ENTRY_POINT_NAME = 'gevent.plugins.monkey.did_patch_all' diff --git a/venv/lib/python3.9/site-packages/gevent/exceptions.py b/venv/lib/python3.9/site-packages/gevent/exceptions.py deleted file mode 100644 index 6fcb766..0000000 --- a/venv/lib/python3.9/site-packages/gevent/exceptions.py +++ /dev/null @@ -1,133 +0,0 @@ -# -*- coding: utf-8 -*- -# copyright 2018 gevent -""" -Exceptions. - -.. versionadded:: 1.3b1 - -""" - -from greenlet import GreenletExit - -__all__ = [ - 'LoopExit', -] - - -class LoopExit(Exception): - """ - Exception thrown when the hub finishes running (`gevent.hub.Hub.run` - would return). - - In a normal application, this is never thrown or caught - explicitly. The internal implementation of functions like - :meth:`gevent.hub.Hub.join` and :func:`gevent.joinall` may catch it, but user code - generally should not. - - .. caution:: - Errors in application programming can also lead to this exception being - raised. Some examples include (but are not limited too): - - - greenlets deadlocking on a lock; - - using a socket or other gevent object with native thread - affinity from a different thread - - """ - - @property - def hub(self): - """ - The (optional) hub that raised the error. - - .. versionadded:: 20.12.0 - """ - # XXX: Note that semaphore.py does this manually. - if len(self.args) == 3: # From the hub - return self.args[1] - - def __repr__(self): - # pylint:disable=unsubscriptable-object - if len(self.args) == 3: # From the hub - import pprint - return ( - "%s\n" - "\tHub: %s\n" - "\tHandles:\n%s" - ) % ( - self.args[0], - self.args[1], - pprint.pformat(self.args[2]) - ) - return Exception.__repr__(self) - - def __str__(self): - return repr(self) - -class BlockingSwitchOutError(AssertionError): - """ - Raised when a gevent synchronous function is called from a - low-level event loop callback. - - This is usually a programming error. - """ - - -class InvalidSwitchError(AssertionError): - """ - Raised when the event loop returns control to a greenlet in an - unexpected way. - - This is usually a bug in gevent, greenlet, or the event loop. - """ - -class ConcurrentObjectUseError(AssertionError): - """ - Raised when an object is used (waited on) by two greenlets - independently, meaning the object was entered into a blocking - state by one greenlet and then another while still blocking in the - first one. - - This is usually a programming error. - - .. seealso:: `gevent.socket.wait` - """ - -class InvalidThreadUseError(RuntimeError): - """ - Raised when an object is used from a different thread than - the one it is bound to. - - Some objects, such as gevent sockets, semaphores, and threadpools, - are tightly bound to their hub and its loop. The hub and loop - are not thread safe, with a few exceptions. Attempting to use - such objects from a different thread is an error, and may cause - problems ranging from incorrect results to memory corruption - and a crashed process. - - In some cases, gevent catches this "accidentally", and the result is - a `LoopExit`. In some cases, gevent doesn't catch this at all. - - In other cases (typically when the consequences are suspected to - be more on the more severe end of the scale, and when the operation in - question is already relatively heavyweight), gevent explicitly checks - for this usage and will raise this exception when it is detected. - - .. versionadded:: 1.5a3 - """ - - -class HubDestroyed(GreenletExit): - """ - Internal exception, raised when we're trying to destroy the - hub and we want the loop to stop running callbacks now. - - This must not be subclassed; the type is tested by identity. - - Clients outside of gevent must not raise this exception. - - .. versionadded:: 20.12.0 - """ - - def __init__(self, destroy_loop): - GreenletExit.__init__(self, destroy_loop) - self.destroy_loop = destroy_loop diff --git a/venv/lib/python3.9/site-packages/gevent/fileobject.py b/venv/lib/python3.9/site-packages/gevent/fileobject.py deleted file mode 100644 index 68e438d..0000000 --- a/venv/lib/python3.9/site-packages/gevent/fileobject.py +++ /dev/null @@ -1,85 +0,0 @@ -""" -Wrappers to make file-like objects cooperative. - -.. class:: FileObject(fobj, mode='r', buffering=-1, closefd=True, encoding=None, errors=None, newline=None) - - The main entry point to the file-like gevent-compatible behaviour. It - will be defined to be the best available implementation. - - All the parameters are as for :func:`io.open`. - - :param fobj: Usually a file descriptor of a socket. Can also be - another object with a ``fileno()`` method, or an object that can - be passed to ``io.open()`` (e.g., a file system path). If the object - is not a socket, the results will vary based on the platform and the - type of object being opened. - - All supported versions of Python allow :class:`os.PathLike` objects. - - .. versionchanged:: 1.5 - Accept str and ``PathLike`` objects for *fobj* on all versions of Python. - .. versionchanged:: 1.5 - Add *encoding*, *errors* and *newline* arguments. - .. versionchanged:: 1.5 - Accept *closefd* and *buffering* instead of *close* and *bufsize* arguments. - The latter remain for backwards compatibility. - -There are two main implementations of ``FileObject``. On all systems, -there is :class:`FileObjectThread` which uses the built-in native -threadpool to avoid blocking the entire interpreter. On UNIX systems -(those that support the :mod:`fcntl` module), there is also -:class:`FileObjectPosix` which uses native non-blocking semantics. - -A third class, :class:`FileObjectBlock`, is simply a wrapper that -executes everything synchronously (and so is not gevent-compatible). -It is provided for testing and debugging purposes. - -All classes have the same signature; some may accept extra keyword arguments. - -Configuration -============= - -You may change the default value for ``FileObject`` using the -``GEVENT_FILE`` environment variable. Set it to ``posix``, ``thread``, -or ``block`` to choose from :class:`FileObjectPosix`, -:class:`FileObjectThread` and :class:`FileObjectBlock`, respectively. -You may also set it to the fully qualified class name of another -object that implements the file interface to use one of your own -objects. - -.. note:: - - The environment variable must be set at the time this module - is first imported. - -Classes -======= -""" -from __future__ import absolute_import - -from gevent._config import config - -__all__ = [ - 'FileObjectPosix', - 'FileObjectThread', - 'FileObjectBlock', - 'FileObject', -] - -try: - from fcntl import fcntl -except ImportError: - __all__.remove("FileObjectPosix") -else: - del fcntl - from gevent._fileobjectposix import FileObjectPosix - -from gevent._fileobjectcommon import FileObjectThread -from gevent._fileobjectcommon import FileObjectBlock - - -# None of the possible objects can live in this module because -# we would get an import cycle and the config couldn't be set from code. -# TODO: zope.hookable would be great for allowing this to be imported -# without requiring configuration but still being very fast. -FileObject = config.fileobject diff --git a/venv/lib/python3.9/site-packages/gevent/greenlet.py b/venv/lib/python3.9/site-packages/gevent/greenlet.py deleted file mode 100644 index 262c7f9..0000000 --- a/venv/lib/python3.9/site-packages/gevent/greenlet.py +++ /dev/null @@ -1,1204 +0,0 @@ -# Copyright (c) 2009-2012 Denis Bilenko. See LICENSE for details. -# cython: auto_pickle=False,embedsignature=True,always_allow_keywords=False -# pylint:disable=too-many-lines -from __future__ import absolute_import, print_function, division - -from sys import _getframe as sys_getframe -from sys import exc_info as sys_exc_info -from weakref import ref as wref - -# XXX: How to get cython to let us rename this as RawGreenlet -# like we prefer? -from greenlet import greenlet -from greenlet import GreenletExit - -from gevent._compat import reraise -from gevent._compat import PYPY as _PYPY -from gevent._tblib import dump_traceback -from gevent._tblib import load_traceback - -from gevent.exceptions import InvalidSwitchError - -from gevent._hub_primitives import iwait_on_objects as iwait -from gevent._hub_primitives import wait_on_objects as wait - -from gevent.timeout import Timeout - -from gevent._config import config as GEVENT_CONFIG -from gevent._util import readproperty -from gevent._hub_local import get_hub_noargs as get_hub -from gevent import _waiter - - -__all__ = [ - 'Greenlet', - 'joinall', - 'killall', -] - - -# In Cython, we define these as 'cdef inline' functions. The -# compilation unit cannot have a direct assignment to them (import -# is assignment) without generating a 'lvalue is not valid target' -# error. -locals()['getcurrent'] = __import__('greenlet').getcurrent -locals()['greenlet_init'] = lambda: None -locals()['Waiter'] = _waiter.Waiter -# With Cython, this raises a TypeError if the parent is *not* -# the hub (SwitchOutGreenletWithLoop); in pure-Python, we will -# very likely get an AttributeError immediately after when we access `loop`; -# The TypeError message is more informative on Python 2. -# This must ONLY be called when we know that `s` is not None and is in fact a greenlet -# object (e.g., when called on `self`) -locals()['get_my_hub'] = lambda s: s.parent -# This must also ONLY be called when we know that S is not None and is in fact a greenlet -# object (including the result of getcurrent()) -locals()['get_generic_parent'] = lambda s: s.parent - -# Frame access -locals()['Gevent_PyFrame_GetCode'] = lambda frame: frame.f_code -locals()['Gevent_PyFrame_GetLineNumber'] = lambda frame: frame.f_lineno -locals()['Gevent_PyFrame_GetBack'] = lambda frame: frame.f_back - - -if _PYPY: - import _continuation # pylint:disable=import-error - _continulet = _continuation.continulet - - -class SpawnedLink(object): - """ - A wrapper around link that calls it in another greenlet. - - Can be called only from main loop. - """ - __slots__ = ['callback'] - - def __init__(self, callback): - if not callable(callback): - raise TypeError("Expected callable: %r" % (callback, )) - self.callback = callback - - def __call__(self, source): - g = greenlet(self.callback, get_hub()) - g.switch(source) - - def __hash__(self): - return hash(self.callback) - - def __eq__(self, other): - return self.callback == getattr(other, 'callback', other) - - def __str__(self): - return str(self.callback) - - def __repr__(self): - return repr(self.callback) - - def __getattr__(self, item): - assert item != 'callback' - return getattr(self.callback, item) - - -class SuccessSpawnedLink(SpawnedLink): - """A wrapper around link that calls it in another greenlet only if source succeed. - - Can be called only from main loop. - """ - __slots__ = [] - - def __call__(self, source): - if source.successful(): - return SpawnedLink.__call__(self, source) - - -class FailureSpawnedLink(SpawnedLink): - """A wrapper around link that calls it in another greenlet only if source failed. - - Can be called only from main loop. - """ - __slots__ = [] - - def __call__(self, source): - if not source.successful(): - return SpawnedLink.__call__(self, source) - -class _Frame(object): - - __slots__ = ('f_code', 'f_lineno', 'f_back') - - def __init__(self): - self.f_code = None - self.f_back = None - self.f_lineno = 0 - - @property - def f_globals(self): - return None - - -def _extract_stack(limit): - try: - frame = sys_getframe() - except ValueError: - # In certain embedded cases that directly use the Python C api - # to call Greenlet.spawn (e.g., uwsgi) this can raise - # `ValueError: call stack is not deep enough`. This is because - # the Cython stack frames for Greenlet.spawn -> - # Greenlet.__init__ -> _extract_stack are all on the C level, - # not the Python level. - # See https://github.com/gevent/gevent/issues/1212 - frame = None - - newest_Frame = None - newer_Frame = None - - while limit and frame is not None: - limit -= 1 - older_Frame = _Frame() - # Arguments are always passed to the constructor as Python objects, - # meaning we wind up boxing the f_lineno just to unbox it if we pass it. - # It's faster to simply assign once the object is created. - older_Frame.f_code = Gevent_PyFrame_GetCode(frame) # pylint:disable=undefined-variable - older_Frame.f_lineno = Gevent_PyFrame_GetLineNumber(frame) # pylint:disable=undefined-variable - if newer_Frame is not None: - newer_Frame.f_back = older_Frame - newer_Frame = older_Frame - if newest_Frame is None: - newest_Frame = newer_Frame - - frame = Gevent_PyFrame_GetBack(frame) # pylint:disable=undefined-variable - - return newest_Frame - - -_greenlet__init__ = greenlet.__init__ - -class Greenlet(greenlet): - """ - A light-weight cooperatively-scheduled execution unit. - """ - # pylint:disable=too-many-public-methods,too-many-instance-attributes - - spawning_stack_limit = 10 - - # pylint:disable=keyword-arg-before-vararg,super-init-not-called - def __init__(self, run=None, *args, **kwargs): - """ - :param args: The arguments passed to the ``run`` function. - :param kwargs: The keyword arguments passed to the ``run`` function. - :keyword callable run: The callable object to run. If not given, this object's - `_run` method will be invoked (typically defined by subclasses). - - .. versionchanged:: 1.1b1 - The ``run`` argument to the constructor is now verified to be a callable - object. Previously, passing a non-callable object would fail after the greenlet - was spawned. - - .. versionchanged:: 1.3b1 - The ``GEVENT_TRACK_GREENLET_TREE`` configuration value may be set to - a false value to disable ``spawn_tree_locals``, ``spawning_greenlet``, - and ``spawning_stack``. The first two will be None in that case, and the - latter will be empty. - - .. versionchanged:: 1.5 - Greenlet objects are now more careful to verify that their ``parent`` is really - a gevent hub, raising a ``TypeError`` earlier instead of an ``AttributeError`` later. - - .. versionchanged:: 20.12.1 - Greenlet objects now function as context managers. Exiting the ``with`` suite - ensures that the greenlet has completed by :meth:`joining ` - the greenlet (blocking, with - no timeout). If the body of the suite raises an exception, the greenlet is - :meth:`killed ` with the default arguments and not joined in that case. - """ - # The attributes are documented in the .rst file - - # greenlet.greenlet(run=None, parent=None) - # Calling it with both positional arguments instead of a keyword - # argument (parent=get_hub()) speeds up creation of this object ~30%: - # python -m timeit -s 'import gevent' 'gevent.Greenlet()' - # Python 3.5: 2.70usec with keywords vs 1.94usec with positional - # Python 3.4: 2.32usec with keywords vs 1.74usec with positional - # Python 3.3: 2.55usec with keywords vs 1.92usec with positional - # Python 2.7: 1.73usec with keywords vs 1.40usec with positional - - # Timings taken Feb 21 2018 prior to integration of #755 - # python -m perf timeit -s 'import gevent' 'gevent.Greenlet()' - # 3.6.4 : Mean +- std dev: 1.08 us +- 0.05 us - # 2.7.14 : Mean +- std dev: 1.44 us +- 0.06 us - # PyPy2 5.10.0: Mean +- std dev: 2.14 ns +- 0.08 ns - - # After the integration of spawning_stack, spawning_greenlet, - # and spawn_tree_locals on that same date: - # 3.6.4 : Mean +- std dev: 8.92 us +- 0.36 us -> 8.2x - # 2.7.14 : Mean +- std dev: 14.8 us +- 0.5 us -> 10.2x - # PyPy2 5.10.0: Mean +- std dev: 3.24 us +- 0.17 us -> 1.5x - - # Compiling with Cython gets us to these numbers: - # 3.6.4 : Mean +- std dev: 3.63 us +- 0.14 us - # 2.7.14 : Mean +- std dev: 3.37 us +- 0.20 us - # PyPy2 5.10.0 : Mean +- std dev: 4.44 us +- 0.28 us - - # Switching to reified frames and some more tuning gets us here: - # 3.7.2 : Mean +- std dev: 2.53 us +- 0.15 us - # 2.7.16 : Mean +- std dev: 2.35 us +- 0.12 us - # PyPy2 7.1 : Mean +- std dev: 11.6 us +- 0.4 us - - # Compared to the released 1.4 (tested at the same time): - # 3.7.2 : Mean +- std dev: 3.21 us +- 0.32 us - # 2.7.16 : Mean +- std dev: 3.11 us +- 0.19 us - # PyPy2 7.1 : Mean +- std dev: 12.3 us +- 0.8 us - - _greenlet__init__(self, None, get_hub()) - - if run is not None: - self._run = run - - # If they didn't pass a callable at all, then they must - # already have one. Note that subclassing to override the run() method - # itself has never been documented or supported. - if not callable(self._run): - raise TypeError("The run argument or self._run must be callable") - - self.args = args - self.kwargs = kwargs - self.value = None - - #: An event, such as a timer or a callback that fires. It is established in - #: start() and start_later() as those two objects, respectively. - #: Once this becomes non-None, the Greenlet cannot be started again. Conversely, - #: kill() and throw() check for non-None to determine if this object has ever been - #: scheduled for starting. A placeholder _cancelled_start_event is assigned by them to prevent - #: the greenlet from being started in the future, if necessary. - #: In the usual case, this transitions as follows: None -> event -> _start_completed_event. - #: A value of None means we've never been started. - self._start_event = None - - self._notifier = None - self._formatted_info = None - self._links = [] - self._ident = None - - # Initial state: None. - # Completed successfully: (None, None, None) - # Failed with exception: (t, v, dump_traceback(tb))) - self._exc_info = None - - if GEVENT_CONFIG.track_greenlet_tree: - spawner = getcurrent() # pylint:disable=undefined-variable - self.spawning_greenlet = wref(spawner) - try: - self.spawn_tree_locals = spawner.spawn_tree_locals - except AttributeError: - self.spawn_tree_locals = {} - if get_generic_parent(spawner) is not None: # pylint:disable=undefined-variable - # The main greenlet has no parent. - # Its children get separate locals. - spawner.spawn_tree_locals = self.spawn_tree_locals - - self.spawning_stack = _extract_stack(self.spawning_stack_limit) - # Don't copy the spawning greenlet's - # '_spawning_stack_frames' into ours. That's somewhat - # confusing, and, if we're not careful, a deep spawn tree - # can lead to excessive memory usage (an infinite spawning - # tree could lead to unbounded memory usage without care - # --- see https://github.com/gevent/gevent/issues/1371) - # The _spawning_stack_frames may be cleared out later if we access spawning_stack - else: - # None is the default for all of these in Cython, but we - # need to declare them for pure-Python mode. - self.spawning_greenlet = None - self.spawn_tree_locals = None - self.spawning_stack = None - - def _get_minimal_ident(self): - # Helper function for cython, to allow typing `reg` and making a - # C call to get_ident. - - # If we're being accessed from a hub different than the one running - # us, aka get_hub() is not self.parent, then calling hub.ident_registry.get_ident() - # may be quietly broken: it's not thread safe. - # If our parent is no longer the hub for whatever reason, this will raise a - # AttributeError or TypeError. - hub = get_my_hub(self) # pylint:disable=undefined-variable - - reg = hub.ident_registry - return reg.get_ident(self) - - @property - def minimal_ident(self): - """ - A small, unique non-negative integer that identifies this object. - - This is similar to :attr:`threading.Thread.ident` (and `id`) - in that as long as this object is alive, no other greenlet *in - this hub* will have the same id, but it makes a stronger - guarantee that the assigned values will be small and - sequential. Sometime after this object has died, the value - will be available for reuse. - - To get ids that are unique across all hubs, combine this with - the hub's (``self.parent``) ``minimal_ident``. - - Accessing this property from threads other than the thread running - this greenlet is not defined. - - .. versionadded:: 1.3a2 - - """ - # Not @Lazy, implemented manually because _ident is in the structure - # of the greenlet for fast access - if self._ident is None: - self._ident = self._get_minimal_ident() - return self._ident - - @readproperty - def name(self): - """ - The greenlet name. By default, a unique name is constructed using - the :attr:`minimal_ident`. You can assign a string to this - value to change it. It is shown in the `repr` of this object if it - has been assigned to or if the `minimal_ident` has already been generated. - - .. versionadded:: 1.3a2 - .. versionchanged:: 1.4 - Stop showing generated names in the `repr` when the ``minimal_ident`` - hasn't been requested. This reduces overhead and may be less confusing, - since ``minimal_ident`` can get reused. - """ - return 'Greenlet-%d' % (self.minimal_ident,) - - def _raise_exception(self): - reraise(*self.exc_info) - - @property - def loop(self): - # needed by killall - hub = get_my_hub(self) # pylint:disable=undefined-variable - return hub.loop - - def __bool__(self): - return self._start_event is not None and self._exc_info is None - - ### Lifecycle - - if _PYPY: - # oops - pypy's .dead relies on __nonzero__ which we overriden above - @property - def dead(self): - "Boolean indicating that the greenlet is dead and will not run again." - # pylint:disable=no-member - if self._greenlet__main: - return False - if getcurrent() is self: # pylint:disable=undefined-variable - return False - if self.__start_cancelled_by_kill() or self.__started_but_aborted(): - return True - - return self._greenlet__started and not _continulet.is_pending(self) - else: - @property - def dead(self): - """ - Boolean indicating that the greenlet is dead and will not run again. - - This is true if: - - 1. We were never started, but were :meth:`killed ` - immediately after creation (not possible with :meth:`spawn`); OR - 2. We were started, but were killed before running; OR - 3. We have run and terminated (by raising an exception out of the - started function or by reaching the end of the started function). - """ - # The currently running greenlet cannot be dead. This guard is - # needed because __started_but_aborted() can return a false True - # during the bootstrap phase: the event loop sets the start - # callback's pending to False before invoking the callback (which - # does the C-level switch), but run() only sets _start_event = - # _start_completed_event after the switch completes. During that - # window __started_but_aborted() incorrectly concludes the - # greenlet was aborted. - if getcurrent() is self: # pylint:disable=undefined-variable - return False - return ( - self.__start_cancelled_by_kill() - or self.__started_but_aborted() - or greenlet.dead.__get__(self) - ) - - def __never_started_or_killed(self): - return self._start_event is None - - def __start_pending(self): - return ( - self._start_event is not None - and (self._start_event.pending or getattr(self._start_event, 'active', False)) - ) - - def __start_cancelled_by_kill(self): - return self._start_event is _cancelled_start_event - - def __start_completed(self): - return self._start_event is _start_completed_event - - def __started_but_aborted(self): - return ( - not self.__never_started_or_killed() # we have been started or killed - and not self.__start_cancelled_by_kill() # we weren't killed, so we must have been started - and not self.__start_completed() # the start never completed - and not self.__start_pending() # and we're not pending, so we must have been aborted - ) - - def __cancel_start(self): - if self._start_event is None: - # prevent self from ever being started in the future - self._start_event = _cancelled_start_event - # cancel any pending start event - # NOTE: If this was a real pending start event, this will leave a - # "dangling" callback/timer object in the hub.loop.callbacks list; - # depending on where we are in the event loop, it may even be in a local - # variable copy of that list (in _run_callbacks). This isn't a problem, - # except for the leak-tests. - self._start_event.stop() - self._start_event.close() - - def __handle_death_before_start(self, args): - # args is (t, v, tb) or simply t or v. - # The last two cases are transformed into (t, v, None); - # if the single argument is an exception type, a new instance - # is created; if the single argument is not an exception type and also - # not an exception, it is wrapped in a BaseException (this is not - # documented, but should result in better behaviour in the event of a - # user error---instead of silently printing something to stderr, we still - # kill the greenlet). - if self._exc_info is None and self.dead: - # the greenlet was never switched to before and it will - # never be; _report_error was not called, the result was - # not set, and the links weren't notified. Let's do it - # here. - # - # checking that self.dead is true is essential, because - # throw() does not necessarily kill the greenlet (if the - # exception raised by throw() is caught somewhere inside - # the greenlet). - if len(args) == 1: - arg = args[0] - if isinstance(arg, type) and issubclass(arg, BaseException): - args = (arg, arg(), None) - else: - args = (type(arg), arg, None) - elif not args: - args = (GreenletExit, GreenletExit(), None) - if not issubclass(args[0], BaseException): - # Random non-type, non-exception arguments. - args = (BaseException, BaseException(args), None) - assert issubclass(args[0], BaseException) - self.__report_error(args) - - @property - def started(self): - # DEPRECATED - return bool(self) - - def ready(self): - """ - Return a true value if and only if the greenlet has finished - execution. - - .. versionchanged:: 1.1 - This function is only guaranteed to return true or false *values*, not - necessarily the literal constants ``True`` or ``False``. - """ - return self.dead or self._exc_info is not None - - def successful(self): - """ - Return a true value if and only if the greenlet has finished execution - successfully, that is, without raising an error. - - .. tip:: A greenlet that has been killed with the default - :class:`GreenletExit` exception is considered successful. - That is, ``GreenletExit`` is not considered an error. - - .. note:: This function is only guaranteed to return true or false *values*, - not necessarily the literal constants ``True`` or ``False``. - """ - return self._exc_info is not None and self._exc_info[1] is None - - def __repr__(self): - classname = self.__class__.__name__ - # If no name has been assigned, don't generate one, including a minimal_ident, - # if not necessary. This reduces the use of weak references and associated - # overhead. - if 'name' not in self.__dict__ and self._ident is None: - name = ' ' - else: - name = ' "%s" ' % (self.name,) - result = '<%s%sat %s' % (classname, name, hex(id(self))) - formatted = self._formatinfo() - if formatted: - result += ': ' + formatted - return result + '>' - - - def _formatinfo(self): - info = self._formatted_info - if info is not None: - return info - - # Are we running an arbitrary function provided to the constructor, - # or did a subclass override _run? - func = self._run - im_self = getattr(func, '__self__', None) - if im_self is self: - funcname = '_run' - elif im_self is not None: - funcname = repr(func) - else: - funcname = getattr(func, '__name__', '') or repr(func) - - result = funcname - args = [] - if self.args: - args = [repr(x)[:50] for x in self.args] - if self.kwargs: - args.extend(['%s=%s' % (key, repr(value)[:50]) for (key, value) in self.kwargs.items()]) - if args: - result += '(' + ', '.join(args) + ')' - # it is important to save the result here, because once the greenlet exits '_run' attribute will be removed - self._formatted_info = result - return result - - @property - def exception(self): - """ - Holds the exception instance raised by the function if the - greenlet has finished with an error. Otherwise ``None``. - """ - return self._exc_info[1] if self._exc_info is not None else None - - @property - def exc_info(self): - """ - Holds the exc_info three-tuple raised by the function if the - greenlet finished with an error. Otherwise a false value. - - .. note:: This is a provisional API and may change. - - .. versionadded:: 1.1 - """ - ei = self._exc_info - if ei is not None and ei[0] is not None: - return ( - ei[0], - ei[1], - # The pickled traceback may be None if we couldn't pickle it. - load_traceback(ei[2]) if ei[2] else None - ) - - def throw(self, *args): - """Immediately switch into the greenlet and raise an exception in it. - - Should only be called from the HUB, otherwise the current greenlet is left unscheduled forever. - To raise an exception in a safe manner from any greenlet, use :meth:`kill`. - - If a greenlet was started but never switched to yet, then also - a) cancel the event that will start it - b) fire the notifications as if an exception was raised in a greenlet - """ - self.__cancel_start() - - try: - if not self.dead: - # Prevent switching into a greenlet *at all* if we had never - # started it. Usually this is the same thing that happens by throwing, - # but if this is done from the hub with nothing else running, prevents a - # LoopExit. - greenlet.throw(self, *args) - finally: - self.__handle_death_before_start(args) - - def start(self): - """Schedule the greenlet to run in this loop iteration""" - if self._start_event is None: - _call_spawn_callbacks(self) - hub = get_my_hub(self) # pylint:disable=undefined-variable - self._start_event = hub.loop.run_callback(self.switch) - - def start_later(self, seconds): - """ - start_later(seconds) -> None - - Schedule the greenlet to run in the future loop iteration - *seconds* later - """ - if self._start_event is None: - _call_spawn_callbacks(self) - hub = get_my_hub(self) # pylint:disable=undefined-variable - self._start_event = hub.loop.timer(seconds) - self._start_event.start(self.switch) - - @staticmethod - def add_spawn_callback(callback): - """ - add_spawn_callback(callback) -> None - - Set up a *callback* to be invoked when :class:`Greenlet` objects - are started. - - The invocation order of spawn callbacks is unspecified. Adding the - same callback more than one time will not cause it to be called more - than once. - - .. versionadded:: 1.4.0 - """ - global _spawn_callbacks - if _spawn_callbacks is None: # pylint:disable=used-before-assignment - _spawn_callbacks = set() - _spawn_callbacks.add(callback) - - @staticmethod - def remove_spawn_callback(callback): - """ - remove_spawn_callback(callback) -> None - - Remove *callback* function added with :meth:`Greenlet.add_spawn_callback`. - This function will not fail if *callback* has been already removed or - if *callback* was never added. - - .. versionadded:: 1.4.0 - """ - global _spawn_callbacks - if _spawn_callbacks is not None: - _spawn_callbacks.discard(callback) - if not _spawn_callbacks: - _spawn_callbacks = None - - @classmethod - def spawn(cls, *args, **kwargs): - """ - spawn(function, *args, **kwargs) -> Greenlet - - Create a new :class:`Greenlet` object and schedule it to run ``function(*args, **kwargs)``. - This can be used as ``gevent.spawn`` or ``Greenlet.spawn``. - - The arguments are passed to :meth:`Greenlet.__init__`. - - .. versionchanged:: 1.1b1 - If a *function* is given that is not callable, immediately raise a :exc:`TypeError` - instead of spawning a greenlet that will raise an uncaught TypeError. - """ - g = cls(*args, **kwargs) - g.start() - return g - - @classmethod - def spawn_later(cls, seconds, *args, **kwargs): - """ - spawn_later(seconds, function, *args, **kwargs) -> Greenlet - - Create and return a new `Greenlet` object scheduled to run ``function(*args, **kwargs)`` - in a future loop iteration *seconds* later. This can be used as ``Greenlet.spawn_later`` - or ``gevent.spawn_later``. - - The arguments are passed to :meth:`Greenlet.__init__`. - - .. versionchanged:: 1.1b1 - If an argument that's meant to be a function (the first argument in *args*, or the ``run`` keyword ) - is given to this classmethod (and not a classmethod of a subclass), - it is verified to be callable. Previously, the spawned greenlet would have failed - when it started running. - """ - if cls is Greenlet and not args and 'run' not in kwargs: - raise TypeError("") - g = cls(*args, **kwargs) - g.start_later(seconds) - return g - - def _maybe_kill_before_start(self, exception): - # Helper for Greenlet.kill(), and also for killall() - self.__cancel_start() - self.__free() - dead = self.dead - if dead: - if isinstance(exception, tuple) and len(exception) == 3: - args = exception - else: - args = (exception,) - self.__handle_death_before_start(args) - return dead - - def kill(self, exception=GreenletExit, block=True, timeout=None): - """ - Raise the ``exception`` in the greenlet. - - If ``block`` is ``True`` (the default), wait until the greenlet - dies or the optional timeout expires; this may require switching - greenlets. - If block is ``False``, the current greenlet is not unscheduled. - - This function always returns ``None`` and never raises an error. It - may be called multpile times on the same greenlet object, and may be - called on an unstarted or dead greenlet. - - .. note:: - - Depending on what this greenlet is executing and the state - of the event loop, the exception may or may not be raised - immediately when this greenlet resumes execution. It may - be raised on a subsequent green call, or, if this greenlet - exits before making such a call, it may not be raised at - all. As of 1.1, an example where the exception is raised - later is if this greenlet had called :func:`sleep(0) - `; an example where the exception is raised - immediately is if this greenlet had called - :func:`sleep(0.1) `. - - .. caution:: - - Use care when killing greenlets. If the code executing is not - exception safe (e.g., makes proper use of ``finally``) then an - unexpected exception could result in corrupted state. Using - a :meth:`link` or :meth:`rawlink` (cheaper) may be a safer way to - clean up resources. - - See also :func:`gevent.kill` and :func:`gevent.killall`. - - :keyword type exception: The type of exception to raise in the greenlet. The default - is :class:`GreenletExit`, which indicates a :meth:`successful` completion - of the greenlet. - - .. versionchanged:: 0.13.0 - *block* is now ``True`` by default. - .. versionchanged:: 1.1a2 - If this greenlet had never been switched to, killing it will - prevent it from *ever* being switched to. Links (:meth:`rawlink`) - will still be executed, though. - .. versionchanged:: 20.12.1 - If this greenlet is :meth:`ready`, immediately return instead of - requiring a trip around the event loop. - """ - if not self._maybe_kill_before_start(exception): - if self.ready(): - return - - waiter = Waiter() if block else None # pylint:disable=undefined-variable - hub = get_my_hub(self) # pylint:disable=undefined-variable - hub.loop.run_callback(_kill, self, exception, waiter) - if waiter is not None: - waiter.get() - self.join(timeout) - - def get(self, block=True, timeout=None): - """ - get(block=True, timeout=None) -> object - - Return the result the greenlet has returned or re-raise the - exception it has raised. - - If block is ``False``, raise :class:`gevent.Timeout` if the - greenlet is still alive. If block is ``True``, unschedule the - current greenlet until the result is available or the timeout - expires. In the latter case, :class:`gevent.Timeout` is - raised. - """ - if self.ready(): - if self.successful(): - return self.value - self._raise_exception() - if not block: - raise Timeout() - - switch = getcurrent().switch # pylint:disable=undefined-variable - self.rawlink(switch) - try: - t = Timeout._start_new_or_dummy(timeout) - try: - result = get_my_hub(self).switch() # pylint:disable=undefined-variable - if result is not self: - raise InvalidSwitchError('Invalid switch into Greenlet.get(): %r' % (result, )) - finally: - t.cancel() - except: - # unlinking in 'except' instead of finally is an optimization: - # if switch occurred normally then link was already removed in _notify_links - # and there's no need to touch the links set. - # Note, however, that if "Invalid switch" assert was removed and invalid switch - # did happen, the link would remain, causing another invalid switch later in this greenlet. - self.unlink(switch) - raise - - if self.ready(): - if self.successful(): - return self.value - self._raise_exception() - - def join(self, timeout=None): - """ - join(timeout=None) -> None - - Wait until the greenlet finishes or *timeout* expires. Return - ``None`` regardless. - """ - if self.ready(): - return - - switch = getcurrent().switch # pylint:disable=undefined-variable - self.rawlink(switch) - try: - t = Timeout._start_new_or_dummy(timeout) - try: - result = get_my_hub(self).switch() # pylint:disable=undefined-variable - if result is not self: - raise InvalidSwitchError('Invalid switch into Greenlet.join(): %r' % (result, )) - finally: - t.cancel() - except Timeout as ex: - self.unlink(switch) - if ex is not t: - raise - except: - self.unlink(switch) - raise - - def __enter__(self): - return self - - def __exit__(self, t, v, tb): - if t is None: - try: - self.join() - finally: - self.kill() - else: - self.kill((t, v, tb)) - - def __report_result(self, result): - self._exc_info = (None, None, None) - self.value = result - if self._links and not self._notifier: - hub = get_my_hub(self) # pylint:disable=undefined-variable - self._notifier = hub.loop.run_callback(self._notify_links) - - def __report_error(self, exc_info): - if isinstance(exc_info[1], GreenletExit): - self.__report_result(exc_info[1]) - return - - # Depending on the error, we may not be able to pickle it. - # In particular, RecursionError can be a problem. - try: - tb = dump_traceback(exc_info[2]) - except: # pylint:disable=bare-except - tb = None - self._exc_info = exc_info[0], exc_info[1], tb - - hub = get_my_hub(self) # pylint:disable=undefined-variable - if self._links and not self._notifier: - self._notifier = hub.loop.run_callback(self._notify_links) - - try: - hub.handle_error(self, *exc_info) - finally: - del exc_info - - def run(self): - try: - self.__cancel_start() - self._start_event = _start_completed_event - - try: - result = self._run(*self.args, **self.kwargs) - except: # pylint:disable=bare-except - self.__report_error(sys_exc_info()) - else: - self.__report_result(result) - finally: - self.__free() - - def __free(self): - try: - # It seems that Cython 0.29.13 sometimes miscompiles - # self.__dict__.pop('_run', None) ? When we moved this out of the - # inline finally: block in run(), we started getting strange - # exceptions from places that subclassed Greenlet. - del self._run - except AttributeError: - pass - self.args = () - self.kwargs.clear() - - def _run(self): - """ - Subclasses may override this method to take any number of - arguments and keyword arguments. - - .. versionadded:: 1.1a3 - Previously, if no callable object was - passed to the constructor, the spawned greenlet would later - fail with an AttributeError. - """ - # We usually override this in __init__ - # pylint: disable=method-hidden - return - - def has_links(self): - return len(self._links) - - def rawlink(self, callback): - """ - Register a callable to be executed when the greenlet finishes - execution. - - The *callback* will be called with this instance as an - argument. - - The *callback* will be called even if linked after the greenlet - is already ready(). - - .. caution:: - The *callback* will be called in the hub and - **MUST NOT** raise an exception. - """ - if not callable(callback): - raise TypeError('Expected callable: %r' % (callback, )) - self._links.append(callback) # pylint:disable=no-member - if self.ready() and self._links and not self._notifier: - hub = get_my_hub(self) # pylint:disable=undefined-variable - self._notifier = hub.loop.run_callback(self._notify_links) - - def link(self, callback, SpawnedLink=SpawnedLink): - """ - Link greenlet's completion to a callable. - - The *callback* will be called with this instance as an - argument once this greenlet is dead. A callable is called in - its own :class:`greenlet.greenlet` (*not* a - :class:`Greenlet`). - - The *callback* will be called even if linked after the greenlet - is already ready(). - """ - # XXX: Is the redefinition of SpawnedLink supposed to just be an - # optimization, or do people use it? It's not documented - # pylint:disable=redefined-outer-name - self.rawlink(SpawnedLink(callback)) - - def unlink(self, callback): - """Remove the callback set by :meth:`link` or :meth:`rawlink`""" - try: - self._links.remove(callback) # pylint:disable=no-member - except ValueError: - pass - - def unlink_all(self): - """ - Remove all the callbacks. - - .. versionadded:: 1.3a2 - """ - del self._links[:] - - def link_value(self, callback, SpawnedLink=SuccessSpawnedLink): - """ - Like :meth:`link` but *callback* is only notified when the greenlet - has completed successfully. - """ - # pylint:disable=redefined-outer-name - self.link(callback, SpawnedLink=SpawnedLink) - - def link_exception(self, callback, SpawnedLink=FailureSpawnedLink): - """ - Like :meth:`link` but *callback* is only notified when the - greenlet dies because of an unhandled exception. - """ - # pylint:disable=redefined-outer-name - self.link(callback, SpawnedLink=SpawnedLink) - - def _notify_links(self): - while self._links: - # Early links are allowed to remove later links - # before we get to them, and they're also allowed to - # add new links, so we have to be careful about iterating. - - # We don't expect this list to be very large, so the time spent - # manipulating it should be small. a deque is probably not justified. - # Cython has optimizations to transform this into a memmove anyway. - link = self._links.pop(0) - try: - link(self) - except: # pylint:disable=bare-except, undefined-variable - get_my_hub(self).handle_error((link, self), *sys_exc_info()) - - -class _dummy_event(object): - __slots__ = ('pending', 'active') - - def __init__(self): - self.pending = self.active = False - - def stop(self): - pass - - def start(self, cb): # pylint:disable=unused-argument - raise AssertionError("Cannot start the dummy event") - - def close(self): - pass - -_cancelled_start_event = _dummy_event() -_start_completed_event = _dummy_event() - - -# This is *only* called as a callback from the hub via Greenlet.kill(), -# and its first argument is the Greenlet. So we can be sure about the types. -def _kill(glet, exception, waiter): - try: - if isinstance(exception, tuple) and len(exception) == 3: - glet.throw(*exception) - else: - glet.throw(exception) - except: # pylint:disable=bare-except, undefined-variable - # XXX do we need this here? - get_my_hub(glet).handle_error(glet, *sys_exc_info()) - if waiter is not None: - waiter.switch(None) - - -def joinall(greenlets, timeout=None, raise_error=False, count=None): - """ - Wait for the ``greenlets`` to finish. - - :param greenlets: A sequence (supporting :func:`len`) of greenlets to wait for. - :keyword float timeout: If given, the maximum number of seconds to wait. - :keyword bool raise_error: If True, immediately raise the first exception - encountered in any greenlet. If False (default), exceptions are - stored in the greenlet and not raised. - :keyword int count: If not `None`, then a number specifying the maximum number - of greenlets to wait for. If ``None`` (the default), all greenlets - are waited for. - :return: A sequence of the greenlets that finished before the timeout (if any) - expired. - """ - if not raise_error: - return wait(greenlets, timeout=timeout, count=count) - - done = [] - for obj in iwait(greenlets, timeout=timeout, count=count): - if getattr(obj, 'exception', None) is not None: - if hasattr(obj, '_raise_exception'): - obj._raise_exception() - else: - raise obj.exception - done.append(obj) - return done - - -def _killall3(greenlets, exception, waiter): - diehards = [] - for g in greenlets: - if not g.dead: - try: - g.throw(exception) - except: # pylint:disable=bare-except, undefined-variable - get_my_hub(g).handle_error(g, *sys_exc_info()) - if not g.dead: - diehards.append(g) - waiter.switch(diehards) - - -def _killall(greenlets, exception): - for g in greenlets: - if not g.dead: - try: - g.throw(exception) - except: # pylint:disable=bare-except, undefined-variable - get_my_hub(g).handle_error(g, *sys_exc_info()) - - -def _call_spawn_callbacks(gr): - if _spawn_callbacks is not None: - for cb in _spawn_callbacks: - cb(gr) - - -_spawn_callbacks = None - - -def killall(greenlets, exception=GreenletExit, block=True, timeout=None): - """ - Forceably terminate all the *greenlets* by causing them to raise *exception*. - - .. caution:: Use care when killing greenlets. If they are not prepared for exceptions, - this could result in corrupted state. - - :param greenlets: A **bounded** iterable of the non-None greenlets to terminate. - *All* the items in this iterable must be greenlets that belong to the same hub, - which should be the hub for this current thread. If this is a generator or iterator - that switches greenlets, the results are undefined. - :keyword exception: The type of exception to raise in the greenlets. By default this is - :class:`GreenletExit`. - :keyword bool block: If True (the default) then this function only returns when all the - greenlets are dead; the current greenlet is unscheduled during that process. - If greenlets ignore the initial exception raised in them, - then they will be joined (with :func:`gevent.joinall`) and allowed to die naturally. - If False, this function returns immediately and greenlets will raise - the exception asynchronously. - :keyword float timeout: A time in seconds to wait for greenlets to die. If given, it is - only honored when ``block`` is True. - :raise Timeout: If blocking and a timeout is given that elapses before - all the greenlets are dead. - - .. versionchanged:: 1.1a2 - *greenlets* can be any iterable of greenlets, like an iterator or a set. - Previously it had to be a list or tuple. - .. versionchanged:: 1.5a3 - Any :class:`Greenlet` in the *greenlets* list that hadn't been switched to before - calling this method will never be switched to. This makes this function - behave like :meth:`Greenlet.kill`. This does not apply to raw greenlets. - .. versionchanged:: 1.5a3 - Now accepts raw greenlets created by :func:`gevent.spawn_raw`. - """ - - need_killed = [] - for glet in greenlets: - # Quick pass through to prevent any greenlet from - # actually being switched to if it hasn't already. - # (Previously we called ``list(greenlets)`` so we're still - # linear.) - # - # We don't use glet.kill() here because we don't want to schedule - # any callbacks in the loop; we're about to handle that more directly. - try: - cancel = glet._maybe_kill_before_start - except AttributeError: - need_killed.append(glet) - else: - if not cancel(exception): - need_killed.append(glet) - - if not need_killed: - return - - loop = glet.loop # pylint:disable=undefined-loop-variable - if block: - waiter = Waiter() # pylint:disable=undefined-variable - loop.run_callback(_killall3, need_killed, exception, waiter) - t = Timeout._start_new_or_dummy(timeout) - try: - alive = waiter.get() - if alive: - joinall(alive, raise_error=False) - finally: - t.cancel() - else: - loop.run_callback(_killall, need_killed, exception) - -def _init(): - greenlet_init() # pylint:disable=undefined-variable - -_init() - -from gevent._util import import_c_accel -import_c_accel(globals(), 'gevent._greenlet') diff --git a/venv/lib/python3.9/site-packages/gevent/hub.py b/venv/lib/python3.9/site-packages/gevent/hub.py deleted file mode 100644 index 6a6726b..0000000 --- a/venv/lib/python3.9/site-packages/gevent/hub.py +++ /dev/null @@ -1,909 +0,0 @@ -# Copyright (c) 2009-2015 Denis Bilenko. See LICENSE for details. -""" -Event-loop hub. -""" -from __future__ import absolute_import, print_function -# XXX: FIXME: Refactor to make this smaller -# pylint:disable=too-many-lines -from functools import partial as _functools_partial - -import sys -import traceback - - -from greenlet import greenlet as RawGreenlet -from greenlet import getcurrent -from greenlet import GreenletExit -from greenlet import error as GreenletError - -__all__ = [ - 'getcurrent', - 'GreenletExit', - 'spawn_raw', - 'sleep', - 'kill', - 'signal', - 'reinit', - 'get_hub', - 'Hub', - 'Waiter', -] - -from gevent._config import config as GEVENT_CONFIG -from gevent._compat import thread_mod_name -from gevent._compat import reraise -from gevent._util import readproperty -from gevent._util import Lazy -from gevent._util import gmctime -from gevent._ident import IdentRegistry - -from gevent._hub_local import get_hub -from gevent._hub_local import get_loop -from gevent._hub_local import set_hub -from gevent._hub_local import set_loop -from gevent._hub_local import get_hub_if_exists as _get_hub -from gevent._hub_local import get_hub_noargs as _get_hub_noargs -from gevent._hub_local import set_default_hub_class - -from gevent._greenlet_primitives import TrackedRawGreenlet -from gevent._hub_primitives import WaitOperationsGreenlet - -# Export -from gevent import _hub_primitives -wait = _hub_primitives.wait_on_objects -iwait = _hub_primitives.iwait_on_objects - - -from gevent.exceptions import LoopExit -from gevent.exceptions import HubDestroyed - -from gevent._waiter import Waiter - - -# Need the real get_ident. We're imported early enough (by gevent/__init__.py) -# that we can be sure nothing is monkey patched yet. -get_thread_ident = __import__(thread_mod_name).get_ident -MAIN_THREAD_IDENT = get_thread_ident() # XXX: Assuming import is done on the main thread. - - - -def spawn_raw(function, *args, **kwargs): - """ - Create a new :class:`greenlet.greenlet` object and schedule it to - run ``function(*args, **kwargs)``. - - This returns a raw :class:`~greenlet.greenlet` which does not have all the useful - methods that :class:`gevent.Greenlet` has. Typically, applications - should prefer :func:`~gevent.spawn`, but this method may - occasionally be useful as an optimization if there are many - greenlets involved. - - .. versionchanged:: 1.1a3 - Verify that ``function`` is callable, raising a TypeError if not. Previously, - the spawned greenlet would have failed the first time it was switched to. - - .. versionchanged:: 1.1b1 - If *function* is not callable, immediately raise a :exc:`TypeError` - instead of spawning a greenlet that will raise an uncaught TypeError. - - .. versionchanged:: 1.1rc2 - Accept keyword arguments for ``function`` as previously (incorrectly) - documented. Note that this may incur an additional expense. - - .. versionchanged:: 1.3a2 - Populate the ``spawning_greenlet`` and ``spawn_tree_locals`` - attributes of the returned greenlet. - - .. versionchanged:: 1.3b1 - *Only* populate ``spawning_greenlet`` and ``spawn_tree_locals`` - if ``GEVENT_TRACK_GREENLET_TREE`` is enabled (the default). If not enabled, - those attributes will not be set. - - .. versionchanged:: 1.5a3 - The returned greenlet always has a *loop* attribute matching the - current hub's loop. This helps it work better with more gevent APIs. - """ - if not callable(function): - raise TypeError("function must be callable") - - # The hub is always the parent. - hub = _get_hub_noargs() - loop = hub.loop - - factory = TrackedRawGreenlet if GEVENT_CONFIG.track_greenlet_tree else RawGreenlet - - # The callback class object that we use to run this doesn't - # accept kwargs (and those objects are heavily used, as well as being - # implemented twice in core.ppyx and corecffi.py) so do it with a partial - if kwargs: - function = _functools_partial(function, *args, **kwargs) - g = factory(function, hub) - loop.run_callback(g.switch) - else: - g = factory(function, hub) - loop.run_callback(g.switch, *args) - g.loop = hub.loop - return g - - -def sleep(seconds=0, ref=True): - """ - Put the current greenlet to sleep for at least *seconds*. - - *seconds* may be specified as an integer, or a float if fractional - seconds are desired. - - .. tip:: In the current implementation, a value of 0 (the default) - means to yield execution to any other runnable greenlets, but - this greenlet may be scheduled again before the event loop - cycles (in an extreme case, a greenlet that repeatedly sleeps - with 0 can prevent greenlets that are ready to do I/O from - being scheduled for some (small) period of time); a value greater than - 0, on the other hand, will delay running this greenlet until - the next iteration of the loop. - - If *ref* is False, the greenlet running ``sleep()`` will not prevent :func:`gevent.wait` - from exiting. - - .. versionchanged:: 1.3a1 - Sleeping with a value of 0 will now be bounded to approximately block the - loop for no longer than :func:`gevent.getswitchinterval`. - - .. seealso:: :func:`idle` - """ - hub = _get_hub_noargs() - loop = hub.loop - if seconds <= 0: - waiter = Waiter(hub) - loop.run_callback(waiter.switch, None) - waiter.get() - else: - with loop.timer(seconds, ref=ref) as t: - # Sleeping is expected to be an "absolute" measure with - # respect to time.time(), not a relative measure, so it's - # important to update the loop's notion of now before we start - loop.update_now() - hub.wait(t) - - -def idle(priority=0): - """ - Cause the calling greenlet to wait until the event loop is idle. - - Idle is defined as having no other events of the same or higher - *priority* pending. That is, as long as sockets, timeouts or even - signals of the same or higher priority are being processed, the loop - is not idle. - - .. seealso:: :func:`sleep` - """ - hub = _get_hub_noargs() - with hub.loop.idle() as watcher: - if priority: - watcher.priority = priority - hub.wait(watcher) - - -def kill(greenlet, exception=GreenletExit): - """ - Kill greenlet asynchronously. The current greenlet is not unscheduled. - - .. note:: - - The method :meth:`Greenlet.kill` method does the same and - more (and the same caveats listed there apply here). However, the MAIN - greenlet - the one that exists initially - does not have a - ``kill()`` method, and neither do any created with :func:`spawn_raw`, - so you have to use this function. - - .. caution:: Use care when killing greenlets. If they are not prepared for - exceptions, this could result in corrupted state. - - .. versionchanged:: 1.1a2 - If the ``greenlet`` has a :meth:`kill ` method, calls it. This prevents a - greenlet from being switched to for the first time after it's been - killed but not yet executed. - """ - if not greenlet.dead: - if hasattr(greenlet, 'kill'): - # dealing with gevent.greenlet.Greenlet. Use it, especially - # to avoid allowing one to be switched to for the first time - # after it's been killed - greenlet.kill(exception=exception, block=False) - else: - _get_hub_noargs().loop.run_callback(greenlet.throw, exception) - - -class signal(object): - """ - signal_handler(signalnum, handler, *args, **kwargs) -> object - - Call the *handler* with the *args* and *kwargs* when the process - receives the signal *signalnum*. - - The *handler* will be run in a new greenlet when the signal is - delivered. - - This returns an object with the useful method ``cancel``, which, - when called, will prevent future deliveries of *signalnum* from - calling *handler*. It's best to keep the returned object alive - until you call ``cancel``. - - .. note:: - - This may not operate correctly with ``SIGCHLD`` if libev child - watchers are used (as they are by default with - `gevent.os.fork`). See :mod:`gevent.signal` for a more - general purpose solution. - - .. versionchanged:: 1.2a1 - - The ``handler`` argument is required to - be callable at construction time. - - .. versionchanged:: 20.5.1 - The ``cancel`` method now properly cleans up all native resources, - and drops references to all the arguments of this function. - """ - # This is documented as a function, not a class, - # so we're free to change implementation details. - - greenlet_class = None - - def __init__(self, signalnum, handler, *args, **kwargs): - if not callable(handler): - raise TypeError("signal handler must be callable.") - - self.hub = _get_hub_noargs() - self.watcher = self.hub.loop.signal(signalnum, ref=False) - self.handler = handler - self.args = args - self.kwargs = kwargs - if self.greenlet_class is None: - from gevent import Greenlet - type(self).greenlet_class = Greenlet - self.greenlet_class = Greenlet - - self.watcher.start(self._start) - - ref = property( - lambda self: self.watcher.ref, - lambda self, nv: setattr(self.watcher, 'ref', nv) - ) - - def cancel(self): - if self.watcher is not None: - self.watcher.stop() - # Must close the watcher at a deterministic time, otherwise - # when CFFI reclaims the memory, the native loop might still - # have some reference to it; if anything tries to touch it - # we can wind up writing to memory that is no longer valid, - # leading to a wide variety of crashes. - self.watcher.close() - self.watcher = None - self.handler = None - self.args = None - self.kwargs = None - self.hub = None - self.greenlet_class = None - - def _start(self): - # TODO: Maybe this should just be Greenlet.spawn()? - try: - greenlet = self.greenlet_class(self.handle) - greenlet.switch() - except: # pylint:disable=bare-except - self.hub.handle_error(None, *sys._exc_info()) # pylint:disable=no-member - - def handle(self): - try: - self.handler(*self.args, **self.kwargs) - except: # pylint:disable=bare-except - self.hub.handle_error(None, *sys.exc_info()) - - -def reinit(hub=None): - """ - reinit() -> None - - Prepare the gevent hub to run in a new (forked) process. - - This should be called *immediately* after :func:`os.fork` in the - child process. This is done automatically by - :func:`gevent.os.fork` or if the :mod:`os` module has been - monkey-patched. If this function is not called in a forked - process, symptoms may include hanging of functions like - :func:`socket.getaddrinfo`, and the hub's threadpool is unlikely - to work. - - .. note:: Registered fork watchers may or may not run before - this function (and thus ``gevent.os.fork``) return. If they have - not run, they will run "soon", after an iteration of the event loop. - You can force this by inserting a few small (but non-zero) calls to :func:`sleep` - after fork returns. (As of gevent 1.1 and before, fork watchers will - not have run, but this may change in the future.) - - .. note:: This function may be removed in a future major release - if the fork process can be more smoothly managed. - - .. warning:: See remarks in :func:`gevent.os.fork` about greenlets - and event loop watchers in the child process. - """ - # Note the signature line in the docstring: hub is not a public param. - - # The loop reinit function in turn calls libev's ev_loop_fork - # function. - hub = _get_hub() if hub is None else hub - if hub is None: - return - - # Note that we reinit the existing loop, not destroy it. - # See https://github.com/gevent/gevent/issues/200. - hub.loop.reinit() - # libev's fork watchers are slow to fire because the only fire - # at the beginning of a loop; due to our use of callbacks that - # run at the end of the loop, that may be too late. The - # threadpool and resolvers depend on the fork handlers being - # run (specifically, the threadpool will fail in the forked - # child if there were any threads in it, which there will be - # if the resolver_thread was in use (the default) before the - # fork.) - # - # If the forked process wants to use the threadpool or - # resolver immediately (in a queued callback), it would hang. - # - # The below is a workaround. Fortunately, all of these - # methods are idempotent and can be called multiple times - # following a fork if the suddenly started working, or were - # already working on some platforms. Other threadpools and fork handlers - # will be called at an arbitrary time later ('soon') - for obj in (hub._threadpool, hub._resolver, hub.periodic_monitoring_thread): - getattr(obj, '_on_fork', lambda: None)() - - # TODO: We'd like to sleep for a non-zero amount of time to force the loop to make a - # pass around before returning to this greenlet. That will allow any - # user-provided fork watchers to run. (Two calls are necessary.) HOWEVER, if - # we do this, certain tests that heavily mix threads and forking, - # like 2.7/test_threading:test_reinit_tls_after_fork, fail. It's not immediately clear - # why. - #sleep(0.00001) - #sleep(0.00001) - - -class Hub(WaitOperationsGreenlet): - """ - A greenlet that runs the event loop. - - It is created automatically by :func:`get_hub`. - - .. rubric:: Switching - - Every time this greenlet (i.e., the event loop) is switched *to*, - if the current greenlet has a ``switch_out`` method, it will be - called. This allows a greenlet to take some cleanup actions before - yielding control. This method should not call any gevent blocking - functions. - """ - - #: If instances of these classes are raised into the event loop, - #: they will be propagated out to the main greenlet (where they will - #: usually be caught by Python itself) - SYSTEM_ERROR = (KeyboardInterrupt, SystemExit, SystemError) - - #: Instances of these classes are not considered to be errors and - #: do not get logged/printed when raised by the event loop. - NOT_ERROR = (GreenletExit, SystemExit) - - #: The size we use for our threadpool. Either use a subclass - #: for this, or change it immediately after creating the hub. - threadpool_size = 10 - - # An instance of PeriodicMonitoringThread, if started. - periodic_monitoring_thread = None - - # The ident of the thread we were created in, which should be the - # thread that we run in. - thread_ident = None - - #: A string giving the name of this hub. Useful for associating hubs - #: with particular threads. Printed as part of the default repr. - #: - #: .. versionadded:: 1.3b1 - name = '' - - # NOTE: We cannot define a class-level 'loop' attribute - # because that conflicts with the slot we inherit from the - # Cythonized-bases. - - # This is the source for our 'minimal_ident' property. We don't use a - # IdentRegistry because we've seen some crashes having to do with - # clearing weak references on shutdown in Windows (see known_failures.py). - # This gives us slightly different semantics than a greenlet's minimal_ident - # (notably, there can be holes) but we never documented this object's minimal_ident, - # and there should be few enough hub's over the lifetime of a process so as not - # to matter much. - _hub_counter = 0 - - def __init__(self, loop=None, default=None): - WaitOperationsGreenlet.__init__(self, None, None) - self.thread_ident = get_thread_ident() - if hasattr(loop, 'run'): - if default is not None: - raise TypeError("Unexpected argument: default") - self.loop = loop - elif get_loop() is not None: - # Reuse a loop instance previously set by - # destroying a hub without destroying the associated - # loop. See #237 and #238. - self.loop = get_loop() - else: - if default is None and self.thread_ident != MAIN_THREAD_IDENT: - default = False - - if loop is None: - loop = self.backend - self.loop = self.loop_class(flags=loop, default=default) # pylint:disable=not-callable - self._resolver = None - self._threadpool = None - self.format_context = GEVENT_CONFIG.format_context - - Hub._hub_counter += 1 - self.minimal_ident = Hub._hub_counter - - @Lazy - def ident_registry(self): - return IdentRegistry() - - @property - def loop_class(self): - return GEVENT_CONFIG.loop - - @property - def backend(self): - return GEVENT_CONFIG.libev_backend - - @property - def main_hub(self): - """ - Is this the hub for the main thread? - - .. versionadded:: 1.3b1 - """ - return self.thread_ident == MAIN_THREAD_IDENT - - def __repr__(self): - if self.loop is None: - info = 'destroyed' - else: - try: - info = self.loop._format() - except Exception as ex: # pylint:disable=broad-except - info = str(ex) or repr(ex) or 'error' - result = '<%s %r at 0x%x %s' % ( - self.__class__.__name__, - self.name, - id(self), - info) - if self._resolver is not None: - result += ' resolver=%r' % self._resolver - if self._threadpool is not None: - result += ' threadpool=%r' % self._threadpool - result += ' thread_ident=%s' % (hex(self.thread_ident), ) - return result + '>' - - def _normalize_exception(self, t, v, tb): - # Allow passing in all None if the caller doesn't have - # easy access to sys.exc_info() - if (t, v, tb) == (None, None, None): - t, v, tb = sys.exc_info() - - if isinstance(v, str): - # Cython can raise errors where the value is a plain string - # e.g., AttributeError, "_semaphore.Semaphore has no attr", - v = t(v) - - return t, v, tb - - def handle_error(self, context, type, value, tb): - """ - Called by the event loop when an error occurs. The default - action is to print the exception to the :attr:`exception - stream `. - - The arguments ``type``, ``value``, and ``tb`` are the standard - tuple as returned by :func:`sys.exc_info`. (Note that when - this is called, it may not be safe to call - :func:`sys.exc_info`.) - - Errors that are :attr:`not errors ` are not - printed. - - Errors that are :attr:`system errors ` are - passed to :meth:`handle_system_error` after being printed. - - Applications can set a property on the hub instance with this - same signature to override the error handling provided by this - class. This is an advanced usage and requires great care. This - function *must not* raise any exceptions. - - :param context: If this is ``None``, indicates a system error - that should generally result in exiting the loop and being - thrown to the parent greenlet. - """ - type, value, tb = self._normalize_exception(type, value, tb) - - if type is HubDestroyed: - # We must continue propagating this for it to properly - # exit. - reraise(type, value, tb) - - if not issubclass(type, self.NOT_ERROR): - self.print_exception(context, type, value, tb) - if context is None or issubclass(type, self.SYSTEM_ERROR): - self.handle_system_error(type, value, tb) - - def handle_system_error(self, type, value, tb=None): - """ - Called from `handle_error` when the exception type is determined - to be a :attr:`system error `. - - System errors cause the exception to be raised in the main - greenlet (the parent of this hub). - - .. versionchanged:: 20.5.1 - Allow passing the traceback to associate with the - exception if it is rethrown into the main greenlet. - """ - current = getcurrent() - if current is self or current is self.parent or self.loop is None: - self.parent.throw(type, value, tb) - else: - # in case system error was handled and life goes on - # switch back to this greenlet as well - cb = None - try: - cb = self.loop.run_callback(current.switch) - except: # pylint:disable=bare-except - traceback.print_exc(file=self.exception_stream) - try: - self.parent.throw(type, value, tb) - finally: - if cb is not None: - cb.stop() - - @readproperty - def exception_stream(self): - """ - The stream to which exceptions will be written. - Defaults to ``sys.stderr`` unless assigned. Assigning a - false (None) value disables printing exceptions. - - .. versionadded:: 1.2a1 - """ - # Unwrap any FileObjectThread we have thrown around sys.stderr - # (because it can't be used in the hub). Tricky because we are - # called in error situations when it's not safe to import. - # Be careful not to access sys if we're in the process of interpreter - # shutdown. - stderr = sys.stderr if sys else None # pylint:disable=using-constant-test - if type(stderr).__name__ == 'FileObjectThread': - stderr = stderr.io # pylint:disable=no-member - return stderr - - def print_exception(self, context, t, v, tb): - # Python 3 does not gracefully handle None value or tb in - # traceback.print_exception() as previous versions did. - # pylint:disable=no-member - errstream = self.exception_stream - if not errstream: # pragma: no cover - # If the error stream is gone, such as when the sys dict - # gets cleared during interpreter shutdown, - # don't cause follow-on errors. - # See https://github.com/gevent/gevent/issues/1295 - return - - t, v, tb = self._normalize_exception(t, v, tb) - - if v is None: - errstream.write('%s\n' % t.__name__) - else: - traceback.print_exception(t, v, tb, file=errstream) - del tb - - try: - errstream.write(gmctime()) - errstream.write(' ' if context is not None else '\n') - except: # pylint:disable=bare-except - # Possible not safe to import under certain - # error conditions in Python 2 - pass - - if context is not None: - if not isinstance(context, str): - try: - context = self.format_context(context) - except: # pylint:disable=bare-except - traceback.print_exc(file=self.exception_stream) - context = repr(context) - errstream.write('%s failed with %s\n\n' % (context, getattr(t, '__name__', 'exception'), )) - - - def run(self): - """ - Entry-point to running the loop. This method is called automatically - when the hub greenlet is scheduled; do not call it directly. - - :raises gevent.exceptions.LoopExit: If the loop finishes running. This means - that there are no other scheduled greenlets, and no active - watchers or servers. In some situations, this indicates a - programming error. - """ - assert self is getcurrent(), 'Do not call Hub.run() directly' - self.start_periodic_monitoring_thread() - while 1: - loop = self.loop - loop.error_handler = self - try: - loop.run() - finally: - loop.error_handler = None # break the refcount cycle - - # This function must never return, as it will cause - # switch() in the parent greenlet to return an unexpected - # value. This can show up as unexpected failures e.g., - # from Waiters raising AssertionError or MulitpleWaiter - # raising invalid IndexError. - # - # It is still possible to kill this greenlet with throw. - # However, in that case switching to it is no longer safe, - # as switch will return immediately. - # - # Note that there's a problem with simply doing - # ``self.parent.throw()`` and never actually exiting this - # greenlet: The greenlet tends to stay alive. This is - # because throwing the exception captures stack frames - # (regardless of what we do with the argument) and those - # get saved. In addition to this object having - # ``gr_frame`` pointing to this method, which contains - # ``self``, which points to the parent, and both of which point to - # an internal thread state dict that points back to the current greenlet for the thread, - # which is likely to be the parent: a cycle. - # - # We can't have ``join()`` tell us to finish, because we - # need to be able to resume after this throw. The only way - # to dispose of the greenlet is to use ``self.destroy()``. - - debug = [] - if hasattr(loop, 'debug'): - debug = loop.debug() - loop = None - - self.parent.throw(LoopExit('This operation would block forever', - self, - debug)) - # Execution could resume here if another blocking API call is made - # in the same thread and the hub hasn't been destroyed, so clean - # up anything left. - debug = None - - def start_periodic_monitoring_thread(self): - if self.periodic_monitoring_thread is None and GEVENT_CONFIG.monitor_thread: - # Note that it is possible for one real thread to - # (temporarily) wind up with multiple monitoring threads, - # if hubs are started and stopped within the thread. This shows up - # in the threadpool tests. The monitoring threads will eventually notice their - # hub object is gone. - from gevent._monitor import PeriodicMonitoringThread - from gevent.events import PeriodicMonitorThreadStartedEvent - from gevent.events import notify_and_call_entry_points - self.periodic_monitoring_thread = PeriodicMonitoringThread(self) - - if self.main_hub: - self.periodic_monitoring_thread.install_monitor_memory_usage() - - notify_and_call_entry_points(PeriodicMonitorThreadStartedEvent( - self.periodic_monitoring_thread)) - - return self.periodic_monitoring_thread - - def join(self, timeout=None): - """ - Wait for the event loop to finish. Exits only when there - are no more spawned greenlets, started servers, active - timeouts or watchers. - - .. caution:: This doesn't clean up all resources associated - with the hub. For that, see :meth:`destroy`. - - :param float timeout: If *timeout* is provided, wait no longer - than the specified number of seconds. - - :return: `True` if this method returns because the loop - finished execution. Or `False` if the timeout - expired. - """ - assert getcurrent() is self.parent, "only possible from the MAIN greenlet" - if self.dead: - return True - - waiter = Waiter(self) - - if timeout is not None: - timeout = self.loop.timer(timeout, ref=False) - timeout.start(waiter.switch, None) - - try: - try: - # Switch to the hub greenlet and let it continue. - # Since we're the parent greenlet of the hub, when it exits - # by `parent.throw(LoopExit)`, control will resume here. - # If the timer elapses, however, ``waiter.switch()`` is called and - # again control resumes here, but without an exception. - waiter.get() - except LoopExit: - # Control will immediately be returned to this greenlet. - return True - finally: - # Clean up as much junk as we can. There is a small cycle in the frames, - # and it won't be GC'd. - # this greenlet -> this frame - # this greenlet -> the exception that was thrown - # the exception that was thrown -> a bunch of other frames, including this frame. - # some frame calling self.run() -> self - del waiter # this frame -> waiter -> self - del self # this frame -> self - if timeout is not None: - timeout.stop() - timeout.close() - del timeout - return False - - def destroy(self, destroy_loop=None): - """ - Destroy this hub and clean up its resources. - - If you manually create hubs, or you use a hub or the gevent - blocking API from multiple native threads, you *should* call this - method before disposing of the hub object reference. Ideally, - this should be called from the same thread running the hub, but - it can be called from other threads after that thread has exited. - - Once this is done, it is impossible to continue running the - hub. Attempts to use the blocking gevent API with pre-existing - objects from this native thread and bound to this hub will fail. - - .. versionchanged:: 20.5.1 - Attempt to ensure that Python stack frames and greenlets referenced by this - hub are cleaned up. This guarantees that switching to the hub again - is not safe after this. (It was never safe, but it's even less safe.) - - Note that this only works if the hub is destroyed in the same thread it - is running in. If the hub is destroyed by a different thread - after a ``fork()``, for example, expect some garbage to leak. - """ - if destroy_loop is None: - destroy_loop = not self.loop.default - - if self.periodic_monitoring_thread is not None: - self.periodic_monitoring_thread.kill() - self.periodic_monitoring_thread = None - if self._resolver is not None: - self._resolver.close() - del self._resolver - if self._threadpool is not None: - self._threadpool.kill() - del self._threadpool - - # Let the frame be cleaned up by causing the run() function to - # exit. This is the only way to guarantee that the hub itself - # and the main greenlet, if this was a secondary thread, get - # cleaned up. Otherwise there are likely to be reference - # cycles still around. We MUST do this before we destroy the - # loop; if we destroy the loop and then switch into the hub, - # things will go VERY, VERY wrong (because we will have destroyed - # the C datastructures in the middle of the C function that's - # using them; the best we can hope for is a segfault). - try: - self.throw(HubDestroyed(destroy_loop)) - except LoopExit: - # Expected. - pass - except GreenletError: - # Must be coming from a different thread. - # Note that python stack frames are likely to leak - # in this case. - pass - - if destroy_loop: - if get_loop() is self.loop: - # Don't let anyone try to reuse this - set_loop(None) - self.loop.destroy() - else: - # Store in case another hub is created for this - # thread. - set_loop(self.loop) - - self.loop = None - if _get_hub() is self: - set_hub(None) - - - - # XXX: We can probably simplify the resolver and threadpool properties. - - @property - def resolver_class(self): - return GEVENT_CONFIG.resolver - - def _get_resolver(self): - if self._resolver is None: - self._resolver = self.resolver_class(hub=self) # pylint:disable=not-callable - return self._resolver - - def _set_resolver(self, value): - self._resolver = value - - def _del_resolver(self): - self._resolver = None - - resolver = property(_get_resolver, _set_resolver, _del_resolver, - """ - The DNS resolver that the socket functions will use. - - .. seealso:: :doc:`/dns` - """) - - - @property - def threadpool_class(self): - return GEVENT_CONFIG.threadpool - - def _get_threadpool(self): - if self._threadpool is None: - # pylint:disable=not-callable - self._threadpool = self.threadpool_class( - self.threadpool_size, - hub=self, - idle_task_timeout=GEVENT_CONFIG.threadpool_idle_task_timeout - ) - return self._threadpool - - def _set_threadpool(self, value): - self._threadpool = value - - def _del_threadpool(self): - self._threadpool = None - - threadpool = property(_get_threadpool, _set_threadpool, _del_threadpool, - """ - The threadpool associated with this hub. - - Usually this is a - :class:`gevent.threadpool.ThreadPool`, but - you :attr:`can customize that - `. - - Use this object to schedule blocking - (non-cooperative) operations in a different - thread to prevent them from halting the event loop. - """) - - -set_default_hub_class(Hub) - - - -class linkproxy(object): - __slots__ = ['callback', 'obj'] - - def __init__(self, callback, obj): - self.callback = callback - self.obj = obj - - def __call__(self, *args): - callback = self.callback - obj = self.obj - self.callback = None - self.obj = None - callback(obj) diff --git a/venv/lib/python3.9/site-packages/gevent/libev/__init__.py b/venv/lib/python3.9/site-packages/gevent/libev/__init__.py deleted file mode 100644 index 412d64c..0000000 --- a/venv/lib/python3.9/site-packages/gevent/libev/__init__.py +++ /dev/null @@ -1,7 +0,0 @@ -# -*- coding: utf-8 -*- -from __future__ import absolute_import -from __future__ import division -from __future__ import print_function - -# Nothing public here -__all__ = [] diff --git a/venv/lib/python3.9/site-packages/gevent/libev/_corecffi.abi3.so b/venv/lib/python3.9/site-packages/gevent/libev/_corecffi.abi3.so deleted file mode 100755 index c932a9b..0000000 Binary files a/venv/lib/python3.9/site-packages/gevent/libev/_corecffi.abi3.so and /dev/null differ diff --git a/venv/lib/python3.9/site-packages/gevent/libev/_corecffi_build.py b/venv/lib/python3.9/site-packages/gevent/libev/_corecffi_build.py deleted file mode 100644 index 5c400fc..0000000 --- a/venv/lib/python3.9/site-packages/gevent/libev/_corecffi_build.py +++ /dev/null @@ -1,126 +0,0 @@ -# pylint: disable=no-member - -# This module is only used to create and compile the gevent._corecffi module; -# nothing should be directly imported from it except `ffi`, which should only be -# used for `ffi.compile()`; programs should import gevent._corecfffi. -# However, because we are using "out-of-line" mode, it is necessary to examine -# this file to know what functions are created and available on the generated -# module. -from __future__ import absolute_import, print_function -import sys -import os -import os.path # pylint:disable=no-name-in-module -from cffi import FFI - -sys.path.append(".") -try: - import _setuplibev - import _setuputils -except ImportError: - print("This file must be imported with setup.py in the current working dir.") - raise - -thisdir = os.path.dirname(os.path.abspath(__file__)) -parentdir = os.path.abspath(os.path.join(thisdir, '..')) -setup_dir = os.path.abspath(os.path.join(thisdir, '..', '..', '..')) - - -__all__ = [] - - -ffi = FFI() -distutils_ext = _setuplibev.build_extension() - -def read_source(name): - # pylint:disable=unspecified-encoding - with open(os.path.join(thisdir, name), 'r') as f: - return f.read() - -# cdef goes to the cffi library and determines what can be used in -# Python. -_cdef = read_source('_corecffi_cdef.c') - -# These defines and uses help keep the C file readable and lintable by -# C tools. -_cdef = _cdef.replace('#define GEVENT_STRUCT_DONE int', '') -_cdef = _cdef.replace("GEVENT_STRUCT_DONE _;", '...;') - -_cdef = _cdef.replace('#define GEVENT_ST_NLINK_T int', - 'typedef int... nlink_t;') -_cdef = _cdef.replace('GEVENT_ST_NLINK_T', 'nlink_t') - -if _setuplibev.LIBEV_EMBED: - # Arrange access to the loop internals - _cdef += """ -struct ev_loop { - int backend_fd; - int activecnt; - ...; -}; - """ - -# arrange to be configured. -_setuputils.ConfiguringBuildExt.gevent_add_pre_run_action(distutils_ext.configure) - - -if sys.platform.startswith('win'): - # We must have the vfd_open, etc, functions on - # Windows. But on other platforms, going through - # CFFI to just return the file-descriptor is slower - # than just doing it in Python, so we check for and - # workaround their absence in corecffi.py - _cdef += """ -typedef int... vfd_socket_t; -int vfd_open(vfd_socket_t); -vfd_socket_t vfd_get(int); -void vfd_free(int); -""" - -# source goes to the C compiler -_source = read_source('_corecffi_source.c') - -macros = list(distutils_ext.define_macros) -try: - # We need the data pointer. - macros.remove(('EV_COMMON', '')) -except ValueError: - pass - -ffi.cdef(_cdef) -ffi.set_source( - 'gevent.libev._corecffi', - _source, - include_dirs=distutils_ext.include_dirs + [ - thisdir, # "libev.h" - parentdir, # _ffi/alloc.c - ], - define_macros=macros, - undef_macros=distutils_ext.undef_macros, - libraries=distutils_ext.libraries, -) - -if __name__ == '__main__': - # XXX: Note, on Windows, we would need to specify the external libraries - # that should be linked in, such as ws2_32 and (because libev_vfd.h makes - # Python.h calls) the proper Python library---at least for PyPy. I never got - # that to work though, and calling python functions is strongly discouraged - # from CFFI code. - - # On macOS to make the non-embedded case work correctly, against - # our local copy of libev: - # - # 1) configure and make libev - # 2) CPPFLAGS=-Ideps/libev/ LDFLAGS=-Ldeps/libev/.libs GEVENTSETUP_EMBED_LIBEV=0 \ - # python setup.py build_ext -i - # 3) export DYLD_LIBRARY_PATH=`pwd`/deps/libev/.libs - # - # The DYLD_LIBRARY_PATH is because the linker hard-codes - # /usr/local/lib/libev.4.dylib in the corecffi.so dylib, because - # that's the "install name" of the libev dylib that was built. - # Adding a -rpath to the LDFLAGS doesn't change things. - # This can be fixed with `install_name_tool`: - # - # 3) install_name_tool -change /usr/local/lib/libev.4.dylib \ - # `pwd`/deps/libev/.libs/libev.4.dylib \ - # src/gevent/libev/_corecffi.abi3.so - ffi.compile(verbose=True) diff --git a/venv/lib/python3.9/site-packages/gevent/libev/corecext.cpython-39-x86_64-linux-gnu.so b/venv/lib/python3.9/site-packages/gevent/libev/corecext.cpython-39-x86_64-linux-gnu.so deleted file mode 100755 index c266d7c..0000000 Binary files a/venv/lib/python3.9/site-packages/gevent/libev/corecext.cpython-39-x86_64-linux-gnu.so and /dev/null differ diff --git a/venv/lib/python3.9/site-packages/gevent/libev/corecffi.py b/venv/lib/python3.9/site-packages/gevent/libev/corecffi.py deleted file mode 100644 index 1abd68f..0000000 --- a/venv/lib/python3.9/site-packages/gevent/libev/corecffi.py +++ /dev/null @@ -1,470 +0,0 @@ -# pylint: disable=too-many-lines, protected-access, redefined-outer-name, not-callable -# pylint: disable=no-member -from __future__ import absolute_import, print_function -import sys - -# pylint: disable=undefined-all-variable -__all__ = [ - 'get_version', - 'get_header_version', - 'supported_backends', - 'recommended_backends', - 'embeddable_backends', - 'time', - 'loop', -] - -from zope.interface import implementer - -from gevent._interfaces import ILoop - -from gevent.libev import _corecffi # pylint:disable=no-name-in-module,import-error - -ffi = _corecffi.ffi # pylint:disable=no-member -libev = _corecffi.lib # pylint:disable=no-member - -if hasattr(libev, 'vfd_open'): - # Must be on windows - # pylint:disable=c-extension-no-member - assert sys.platform.startswith("win"), "vfd functions only needed on windows" - vfd_open = libev.vfd_open - vfd_free = libev.vfd_free - vfd_get = libev.vfd_get -else: - vfd_open = vfd_free = vfd_get = lambda fd: fd - -libev.gevent_set_ev_alloc() - -##### -## NOTE on Windows: -# The C implementation does several things specially for Windows; -# a possibly incomplete list is: -# -# - the loop runs a periodic signal checker; -# - the io watcher constructor is different and it has a destructor; -# - the child watcher is not defined -# -# The CFFI implementation does none of these things, and so -# is possibly NOT FUNCTIONALLY CORRECT on Win32 -##### - - -from gevent._ffi.loop import AbstractCallbacks -from gevent._ffi.loop import assign_standard_callbacks - -class _Callbacks(AbstractCallbacks): - # pylint:disable=arguments-differ,arguments-renamed - - def python_check_callback(self, *args): - # There's a pylint bug (pylint 2.9.3, astroid 2.6.2) that causes pylint to crash - # with an AttributeError on certain types of arguments-differ errors - # But code in _ffi/loop depends on being able to find the watcher_ptr - # argument is the local frame. BUT it gets invoked before the function body runs. - # Hence the override of _find_watcher_ptr_in_traceback. - # pylint:disable=unused-variable - _loop, watcher_ptr, _events = args - AbstractCallbacks.python_check_callback(self, watcher_ptr) - - def _find_watcher_ptr_in_traceback(self, tb): - if tb is not None: - l = tb.tb_frame.f_locals - if 'watcher_ptr' in l: - return l['watcher_ptr'] - if 'args' in l and len(l['args']) == 3: - return l['args'][1] - return AbstractCallbacks._find_watcher_ptr_in_traceback(self, tb) - - def python_prepare_callback(self, _loop_ptr, watcher_ptr, _events): - AbstractCallbacks.python_prepare_callback(self, watcher_ptr) - - def _find_loop_from_c_watcher(self, watcher_ptr): - loop_handle = ffi.cast('struct ev_watcher*', watcher_ptr).data - return self.from_handle(loop_handle) - -_callbacks = assign_standard_callbacks(ffi, libev, _Callbacks) - - -UNDEF = libev.EV_UNDEF -NONE = libev.EV_NONE -READ = libev.EV_READ -WRITE = libev.EV_WRITE -TIMER = libev.EV_TIMER -PERIODIC = libev.EV_PERIODIC -SIGNAL = libev.EV_SIGNAL -CHILD = libev.EV_CHILD -STAT = libev.EV_STAT -IDLE = libev.EV_IDLE -PREPARE = libev.EV_PREPARE -CHECK = libev.EV_CHECK -EMBED = libev.EV_EMBED -FORK = libev.EV_FORK -CLEANUP = libev.EV_CLEANUP -ASYNC = libev.EV_ASYNC -CUSTOM = libev.EV_CUSTOM -ERROR = libev.EV_ERROR - -READWRITE = libev.EV_READ | libev.EV_WRITE - -MINPRI = libev.EV_MINPRI -MAXPRI = libev.EV_MAXPRI - -BACKEND_PORT = libev.EVBACKEND_PORT -BACKEND_KQUEUE = libev.EVBACKEND_KQUEUE -BACKEND_EPOLL = libev.EVBACKEND_EPOLL -BACKEND_POLL = libev.EVBACKEND_POLL -BACKEND_SELECT = libev.EVBACKEND_SELECT -FORKCHECK = libev.EVFLAG_FORKCHECK -NOINOTIFY = libev.EVFLAG_NOINOTIFY -SIGNALFD = libev.EVFLAG_SIGNALFD -NOSIGMASK = libev.EVFLAG_NOSIGMASK - - -from gevent._ffi.loop import EVENTS -GEVENT_CORE_EVENTS = EVENTS - - -def get_version(): - return 'libev-%d.%02d' % (libev.ev_version_major(), libev.ev_version_minor()) - - -def get_header_version(): - return 'libev-%d.%02d' % (libev.EV_VERSION_MAJOR, libev.EV_VERSION_MINOR) - -# This list backends in the order they are actually tried by libev, -# as defined in loop_init. The names must be lower case. -_flags = [ - # IOCP --- not supported/used. - (libev.EVBACKEND_PORT, 'port'), - (libev.EVBACKEND_KQUEUE, 'kqueue'), - (libev.EVBACKEND_IOURING, 'linux_iouring'), - (libev.EVBACKEND_LINUXAIO, "linux_aio"), - (libev.EVBACKEND_EPOLL, 'epoll'), - (libev.EVBACKEND_POLL, 'poll'), - (libev.EVBACKEND_SELECT, 'select'), - - (libev.EVFLAG_NOENV, 'noenv'), - (libev.EVFLAG_FORKCHECK, 'forkcheck'), - (libev.EVFLAG_SIGNALFD, 'signalfd'), - (libev.EVFLAG_NOSIGMASK, 'nosigmask') -] - -_flags_str2int = dict((string, flag) for (flag, string) in _flags) - - - -def _flags_to_list(flags): - result = [] - for code, value in _flags: - if flags & code: - result.append(value) - flags &= ~code - if not flags: - break - if flags: - result.append(flags) - return result - -if sys.version_info[0] >= 3: - basestring = (bytes, str) - integer_types = (int,) -else: - import __builtin__ # pylint:disable=import-error - basestring = (__builtin__.basestring,) - integer_types = (int, __builtin__.long) - - -def _flags_to_int(flags): - # Note, that order does not matter, libev has its own predefined order - if not flags: - return 0 - if isinstance(flags, integer_types): - return flags - result = 0 - try: - if isinstance(flags, basestring): - flags = flags.split(',') - for value in flags: - value = value.strip().lower() - if value: - result |= _flags_str2int[value] - except KeyError as ex: - raise ValueError('Invalid backend or flag: %s\nPossible values: %s' % (ex, ', '.join(sorted(_flags_str2int.keys())))) - return result - - -def _str_hex(flag): - if isinstance(flag, integer_types): - return hex(flag) - return str(flag) - - -def _check_flags(flags): - as_list = [] - flags &= libev.EVBACKEND_MASK - if not flags: - return - if not flags & libev.EVBACKEND_ALL: - raise ValueError('Invalid value for backend: 0x%x' % flags) - if not flags & libev.ev_supported_backends(): - as_list = [_str_hex(x) for x in _flags_to_list(flags)] - raise ValueError('Unsupported backend: %s' % '|'.join(as_list)) - - -def supported_backends(): - return _flags_to_list(libev.ev_supported_backends()) - - -def recommended_backends(): - return _flags_to_list(libev.ev_recommended_backends()) - - -def embeddable_backends(): - return _flags_to_list(libev.ev_embeddable_backends()) - - -def time(): - return libev.ev_time() - -from gevent._ffi.loop import AbstractLoop - - -from gevent.libev import watcher as _watchers -_events_to_str = _watchers._events_to_str # exported - - -@implementer(ILoop) -class loop(AbstractLoop): - # pylint:disable=too-many-public-methods - - # libuv parameters simply won't accept anything lower than 1ms - # (0.001s), but libev takes fractional seconds. In practice, on - # one machine, libev can sleep for very small periods of time: - # - # sleep(0.00001) -> 0.000024 - # sleep(0.0001) -> 0.000156 - # sleep(0.001) -> 0.00136 (which is comparable to libuv) - - approx_timer_resolution = 0.00001 - - error_handler = None - - _CHECK_POINTER = 'struct ev_check *' - - _PREPARE_POINTER = 'struct ev_prepare *' - - _TIMER_POINTER = 'struct ev_timer *' - - def __init__(self, flags=None, default=None): - AbstractLoop.__init__(self, ffi, libev, _watchers, flags, default) - self._default = bool(libev.ev_is_default_loop(self._ptr)) - - def _init_loop(self, flags, default): - c_flags = _flags_to_int(flags) - _check_flags(c_flags) - c_flags |= libev.EVFLAG_NOENV - c_flags |= libev.EVFLAG_FORKCHECK - if default is None: - default = True - if default: - ptr = libev.gevent_ev_default_loop(c_flags) - if not ptr: - raise SystemError("ev_default_loop(%s) failed" % (c_flags, )) - else: - ptr = libev.ev_loop_new(c_flags) - if not ptr: - raise SystemError("ev_loop_new(%s) failed" % (c_flags, )) - if default or SYSERR_CALLBACK is None: - set_syserr_cb(self._handle_syserr) - - # Mark this loop as being used. - libev.ev_set_userdata(ptr, ptr) - return ptr - - def _init_and_start_check(self): - libev.ev_check_init(self._check, libev.python_check_callback) - self._check.data = self._handle_to_self - libev.ev_check_start(self._ptr, self._check) - self.unref() - - def _init_and_start_prepare(self): - libev.ev_prepare_init(self._prepare, libev.python_prepare_callback) - libev.ev_prepare_start(self._ptr, self._prepare) - self.unref() - - def _init_callback_timer(self): - libev.ev_timer_init(self._timer0, libev.gevent_noop, 0.0, 0.0) - - def _stop_callback_timer(self): - libev.ev_timer_stop(self._ptr, self._timer0) - - def _start_callback_timer(self): - libev.ev_timer_start(self._ptr, self._timer0) - - def _stop_aux_watchers(self): - super(loop, self)._stop_aux_watchers() - if libev.ev_is_active(self._prepare): - self.ref() - libev.ev_prepare_stop(self._ptr, self._prepare) - if libev.ev_is_active(self._check): - self.ref() - libev.ev_check_stop(self._ptr, self._check) - if libev.ev_is_active(self._timer0): - libev.ev_timer_stop(self._timer0) - - def _setup_for_run_callback(self): - # XXX: libuv needs to start the callback timer to be sure - # that the loop wakes up and calls this. Our C version doesn't - # do this. - # self._start_callback_timer() - self.ref() # we should go through the loop now - - def destroy(self): - if self._ptr: - super(loop, self).destroy() - # pylint:disable=comparison-with-callable - if globals()["SYSERR_CALLBACK"] == self._handle_syserr: - set_syserr_cb(None) - - - def _can_destroy_loop(self, ptr): - # Is it marked as destroyed? - return libev.ev_userdata(ptr) - - def _destroy_loop(self, ptr): - # Mark as destroyed. - libev.ev_set_userdata(ptr, ffi.NULL) - libev.ev_loop_destroy(ptr) - - libev.gevent_zero_prepare(self._prepare) - libev.gevent_zero_check(self._check) - libev.gevent_zero_timer(self._timer0) - - del self._prepare - del self._check - del self._timer0 - - - @property - def MAXPRI(self): - return libev.EV_MAXPRI - - @property - def MINPRI(self): - return libev.EV_MINPRI - - def _default_handle_error(self, context, type, value, tb): # pylint:disable=unused-argument - super(loop, self)._default_handle_error(context, type, value, tb) - libev.ev_break(self._ptr, libev.EVBREAK_ONE) - - def run(self, nowait=False, once=False): - flags = 0 - if nowait: - flags |= libev.EVRUN_NOWAIT - if once: - flags |= libev.EVRUN_ONCE - - libev.ev_run(self._ptr, flags) - - def reinit(self): - libev.ev_loop_fork(self._ptr) - - def ref(self): - libev.ev_ref(self._ptr) - - def unref(self): - libev.ev_unref(self._ptr) - - def break_(self, how=libev.EVBREAK_ONE): - libev.ev_break(self._ptr, how) - - def verify(self): - libev.ev_verify(self._ptr) - - def now(self): - return libev.ev_now(self._ptr) - - def update_now(self): - libev.ev_now_update(self._ptr) - - def __repr__(self): - return '<%s at 0x%x %s>' % (self.__class__.__name__, id(self), self._format()) - - @property - def iteration(self): - return libev.ev_iteration(self._ptr) - - @property - def depth(self): - return libev.ev_depth(self._ptr) - - @property - def backend_int(self): - return libev.ev_backend(self._ptr) - - @property - def backend(self): - backend = libev.ev_backend(self._ptr) - for key, value in _flags: - if key == backend: - return value - return backend - - @property - def pendingcnt(self): - return libev.ev_pending_count(self._ptr) - - def closing_fd(self, fd): - pending_before = libev.ev_pending_count(self._ptr) - libev.ev_feed_fd_event(self._ptr, fd, 0xFFFF) - pending_after = libev.ev_pending_count(self._ptr) - return pending_after > pending_before - - if sys.platform != "win32": - - def install_sigchld(self): - libev.gevent_install_sigchld_handler() - - def reset_sigchld(self): - libev.gevent_reset_sigchld_handler() - - def fileno(self): - if self._ptr and LIBEV_EMBED: - # If we don't embed, we can't access these fields, - # the type is opaque - fd = self._ptr.backend_fd - if fd >= 0: - return fd - - @property - def activecnt(self): - if not self._ptr: - raise ValueError('operation on destroyed loop') - if LIBEV_EMBED: - return self._ptr.activecnt - return -1 - - -@ffi.def_extern() -def _syserr_cb(msg): - try: - msg = ffi.string(msg) - SYSERR_CALLBACK(msg, ffi.errno) - except: - set_syserr_cb(None) - raise # let cffi print the traceback - - -def set_syserr_cb(callback): - global SYSERR_CALLBACK - if callback is None: - libev.ev_set_syserr_cb(ffi.NULL) - SYSERR_CALLBACK = None - elif callable(callback): - libev.ev_set_syserr_cb(libev._syserr_cb) - SYSERR_CALLBACK = callback - else: - raise TypeError('Expected callable or None, got %r' % (callback, )) - -SYSERR_CALLBACK = None - -LIBEV_EMBED = libev.LIBEV_EMBED diff --git a/venv/lib/python3.9/site-packages/gevent/libev/watcher.py b/venv/lib/python3.9/site-packages/gevent/libev/watcher.py deleted file mode 100644 index 5a44cef..0000000 --- a/venv/lib/python3.9/site-packages/gevent/libev/watcher.py +++ /dev/null @@ -1,294 +0,0 @@ -# pylint: disable=too-many-lines, protected-access, redefined-outer-name, not-callable -# pylint: disable=no-member -import sys -import errno - -from gevent.libev import _corecffi # pylint:disable=no-name-in-module,import-error - -# Nothing public here -__all__ = [] - - -ffi = _corecffi.ffi # pylint:disable=no-member -libev = _corecffi.lib # pylint:disable=no-member - -if hasattr(libev, 'vfd_open'): - # Must be on windows - # pylint:disable=c-extension-no-member - assert sys.platform.startswith("win"), "vfd functions only needed on windows" - vfd_open = libev.vfd_open - vfd_free = libev.vfd_free - vfd_get = libev.vfd_get -else: - vfd_open = vfd_free = vfd_get = lambda fd: fd - -##### -## NOTE on Windows: -# The C implementation does several things specially for Windows; -# a possibly incomplete list is: -# -# - the loop runs a periodic signal checker; -# - the io watcher constructor is different and it has a destructor; -# - the child watcher is not defined -# -# The CFFI implementation does none of these things, and so -# is possibly NOT FUNCTIONALLY CORRECT on Win32 -##### -_NOARGS = () -_events = [(libev.EV_READ, 'READ'), - (libev.EV_WRITE, 'WRITE'), - (libev.EV__IOFDSET, '_IOFDSET'), - (libev.EV_PERIODIC, 'PERIODIC'), - (libev.EV_SIGNAL, 'SIGNAL'), - (libev.EV_CHILD, 'CHILD'), - (libev.EV_STAT, 'STAT'), - (libev.EV_IDLE, 'IDLE'), - (libev.EV_PREPARE, 'PREPARE'), - (libev.EV_CHECK, 'CHECK'), - (libev.EV_EMBED, 'EMBED'), - (libev.EV_FORK, 'FORK'), - (libev.EV_CLEANUP, 'CLEANUP'), - (libev.EV_ASYNC, 'ASYNC'), - (libev.EV_CUSTOM, 'CUSTOM'), - (libev.EV_ERROR, 'ERROR')] - -from gevent._ffi import watcher as _base - -def _events_to_str(events): - return _base.events_to_str(events, _events) - - - -class watcher(_base.watcher): - _FFI = ffi - _LIB = libev - _watcher_prefix = 'ev' - - # Flags is a bitfield with the following meaning: - # 0000 -> default, referenced (when active) - # 0010 -> ev_unref has been called - # 0100 -> not referenced; independent of 0010 - _flags = 0 - - def __init__(self, _loop, ref=True, priority=None, args=_base._NOARGS): - if ref: - self._flags = 0 - else: - self._flags = 4 - - super(watcher, self).__init__(_loop, ref=ref, priority=priority, args=args) - - def _watcher_ffi_set_priority(self, priority): - libev.ev_set_priority(self._watcher, priority) - - def _watcher_ffi_init(self, args): - self._watcher_init(self._watcher, - self._watcher_callback, - *args) - - def _watcher_ffi_start(self): - self._watcher_start(self.loop._ptr, self._watcher) - - def _watcher_ffi_ref(self): - if self._flags & 2: # we've told libev we're not referenced - self.loop.ref() - self._flags &= ~2 - - def _watcher_ffi_unref(self): - if self._flags & 6 == 4: - # We're not referenced, but we haven't told libev that - self.loop.unref() - self._flags |= 2 # now we've told libev - - def _get_ref(self): - return not self._flags & 4 - - def _set_ref(self, value): - if value: - if not self._flags & 4: - return # ref is already True - if self._flags & 2: # ev_unref was called, undo - self.loop.ref() - self._flags &= ~6 # do not want unref, no outstanding unref - else: - if self._flags & 4: - return # ref is already False - self._flags |= 4 # we're not referenced - if not self._flags & 2 and libev.ev_is_active(self._watcher): - # we haven't told libev we're not referenced, but it thinks we're - # active so we need to undo that - self.loop.unref() - self._flags |= 2 # libev knows we're not referenced - - ref = property(_get_ref, _set_ref) - - - def _get_priority(self): - return libev.ev_priority(self._watcher) - - @_base.not_while_active - def _set_priority(self, priority): - libev.ev_set_priority(self._watcher, priority) - - priority = property(_get_priority, _set_priority) - - def feed(self, revents, callback, *args): - self.callback = callback - self.args = args or _NOARGS - if self._flags & 6 == 4: - self.loop.unref() - self._flags |= 2 - libev.ev_feed_event(self.loop._ptr, self._watcher, revents) - if not self._flags & 1: - # Py_INCREF(self) - self._flags |= 1 - - @property - def pending(self): - return bool(self._watcher and libev.ev_is_pending(self._watcher)) - - -class io(_base.IoMixin, watcher): - - EVENT_MASK = libev.EV__IOFDSET | libev.EV_READ | libev.EV_WRITE - - @classmethod - def _validate_fd(cls, fd): - super()._validate_fd(fd) - if libev.gevent_check_fd_valid(fd) == -1: - raise OSError(errno.EBADF, "Invalid file descriptor %r" % (fd,)) - - def _get_fd(self): - return vfd_get(self._watcher.fd) - - @_base.not_while_active - def _set_fd(self, fd): - self._validate_fd(fd) - vfd = vfd_open(fd) - vfd_free(self._watcher.fd) - self._watcher_init(self._watcher, self._watcher_callback, vfd, self._watcher.events) - - fd = property(_get_fd, _set_fd) - - def _get_events(self): - return self._watcher.events - - @_base.not_while_active - def _set_events(self, events): - self._watcher_init(self._watcher, self._watcher_callback, self._watcher.fd, events) - - events = property(_get_events, _set_events) - - @property - def events_str(self): - return _events_to_str(self._watcher.events) - - def _format(self): - return ' fd=%s events=%s' % (self.fd, self.events_str) - - -class timer(_base.TimerMixin, watcher): - - @property - def at(self): - return self._watcher.at - - def again(self, callback, *args, **kw): - # Exactly the same as start(), just with a different initializer - # function - self._watcher_start = libev.ev_timer_again - try: - self.start(callback, *args, **kw) - finally: - del self._watcher_start - - -class signal(_base.SignalMixin, watcher): - pass - -class idle(_base.IdleMixin, watcher): - pass - -class prepare(_base.PrepareMixin, watcher): - pass - -class check(_base.CheckMixin, watcher): - pass - -class fork(_base.ForkMixin, watcher): - pass - - -class async_(_base.AsyncMixin, watcher): - - def send(self): - libev.ev_async_send(self.loop._ptr, self._watcher) - - @property - def pending(self): - return self._watcher is not None and bool(libev.ev_async_pending(self._watcher)) - -# Provide BWC for those that have async -locals()['async'] = async_ - -class _ClosedWatcher(object): - __slots__ = ('pid', 'rpid', 'rstatus') - - def __init__(self, other): - self.pid = other.pid - self.rpid = other.rpid - self.rstatus = other.rstatus - - def __bool__(self): - return False - __nonzero__ = __bool__ - -class child(_base.ChildMixin, watcher): - _watcher_type = 'child' - - def close(self): - # Capture the properties we defer to our _watcher, because - # we're about to discard it. - closed_watcher = _ClosedWatcher(self._watcher) - super(child, self).close() - self._watcher = closed_watcher - - @property - def pid(self): - return self._watcher.pid - - @property - def rpid(self): - return self._watcher.rpid - - @rpid.setter - def rpid(self, value): - self._watcher.rpid = value - - @property - def rstatus(self): - return self._watcher.rstatus - - @rstatus.setter - def rstatus(self, value): - self._watcher.rstatus = value - - -class stat(_base.StatMixin, watcher): - _watcher_type = 'stat' - - @property - def attr(self): - if not self._watcher.attr.st_nlink: - return - return self._watcher.attr - - @property - def prev(self): - if not self._watcher.prev.st_nlink: - return - return self._watcher.prev - - @property - def interval(self): - return self._watcher.interval diff --git a/venv/lib/python3.9/site-packages/gevent/libuv/__init__.py b/venv/lib/python3.9/site-packages/gevent/libuv/__init__.py deleted file mode 100644 index 412d64c..0000000 --- a/venv/lib/python3.9/site-packages/gevent/libuv/__init__.py +++ /dev/null @@ -1,7 +0,0 @@ -# -*- coding: utf-8 -*- -from __future__ import absolute_import -from __future__ import division -from __future__ import print_function - -# Nothing public here -__all__ = [] diff --git a/venv/lib/python3.9/site-packages/gevent/libuv/_corecffi.abi3.so b/venv/lib/python3.9/site-packages/gevent/libuv/_corecffi.abi3.so deleted file mode 100755 index b60e77f..0000000 Binary files a/venv/lib/python3.9/site-packages/gevent/libuv/_corecffi.abi3.so and /dev/null differ diff --git a/venv/lib/python3.9/site-packages/gevent/libuv/_corecffi_build.py b/venv/lib/python3.9/site-packages/gevent/libuv/_corecffi_build.py deleted file mode 100644 index 86e5049..0000000 --- a/venv/lib/python3.9/site-packages/gevent/libuv/_corecffi_build.py +++ /dev/null @@ -1,334 +0,0 @@ -# pylint: disable=no-member - -# This module is only used to create and compile the gevent.libuv._corecffi module; -# nothing should be directly imported from it except `ffi`, which should only be -# used for `ffi.compile()`; programs should import gevent._corecfffi. -# However, because we are using "out-of-line" mode, it is necessary to examine -# this file to know what functions are created and available on the generated -# module. -from __future__ import absolute_import, print_function -import os -import os.path # pylint:disable=no-name-in-module -import platform -import sys - -from cffi import FFI - -sys.path.append(".") - -try: - import _setuputils -except ImportError: - print("This file must be imported with setup.py in the current working dir.") - raise - - -__all__ = [] - -WIN = sys.platform.startswith('win32') -LIBUV_EMBED = _setuputils.should_embed('libuv') - - -ffi = FFI() - -thisdir = os.path.dirname(os.path.abspath(__file__)) -parentdir = os.path.abspath(os.path.join(thisdir, '..')) -setup_py_dir = os.path.abspath(os.path.join(thisdir, '..', '..', '..')) -libuv_dir = os.path.abspath(os.path.join(setup_py_dir, 'deps', 'libuv')) - -def read_source(name): - # pylint:disable=unspecified-encoding - with open(os.path.join(thisdir, name), 'r') as f: - return f.read() - -_cdef = read_source('_corecffi_cdef.c') -_source = read_source('_corecffi_source.c') - -# These defines and uses help keep the C file readable and lintable by -# C tools. -_cdef = _cdef.replace('#define GEVENT_STRUCT_DONE int', '') -_cdef = _cdef.replace("GEVENT_STRUCT_DONE _;", '...;') - -# nlink_t is not used in libuv. -_cdef = _cdef.replace('#define GEVENT_ST_NLINK_T int', - '') -_cdef = _cdef.replace('GEVENT_ST_NLINK_T', 'nlink_t') - - -_cdef = _cdef.replace('#define GEVENT_UV_OS_SOCK_T int', '') -# uv_os_sock_t is int on POSIX and SOCKET on Win32, but socket is -# just another name for handle, which is just another name for 'void*' -# which we will treat as an 'unsigned long' or 'unsigned long long' -# since it comes through 'fileno()' where it has been cast as an int. -# See class watcher.io -_void_pointer_as_integer = 'intptr_t' -_cdef = _cdef.replace("GEVENT_UV_OS_SOCK_T", 'int' if not WIN else _void_pointer_as_integer) - - - - -LIBUV_INCLUDE_DIRS = [ - os.path.join(libuv_dir, 'include'), - os.path.join(libuv_dir, 'src'), -] - -# Initially based on https://github.com/saghul/pyuv/blob/v1.x/setup_libuv.py - -def _libuv_source(rel_path): - # Certain versions of setuptools, notably on windows, are *very* - # picky about what we feed to sources= "setup() arguments must - # *always* be /-separated paths relative to the setup.py - # directory, *never* absolute paths." POSIX doesn't have that issue. - path = os.path.join('deps', 'libuv', 'src', rel_path) - return path - -LIBUV_SOURCES = [ - _libuv_source('fs-poll.c'), - _libuv_source('inet.c'), - _libuv_source('threadpool.c'), - _libuv_source('uv-common.c'), - _libuv_source('version.c'), - _libuv_source('uv-data-getter-setters.c'), - _libuv_source('timer.c'), - _libuv_source('idna.c'), - _libuv_source('strscpy.c'), - # Added between 1.42.0 and 1.44.2; only used - # on unix in that release, but generic - _libuv_source('strtok.c'), - _libuv_source('thread-common.c'), -] - -if WIN: - LIBUV_SOURCES += [ - _libuv_source('win/async.c'), - _libuv_source('win/core.c'), - _libuv_source('win/detect-wakeup.c'), - _libuv_source('win/dl.c'), - _libuv_source('win/error.c'), - _libuv_source('win/fs-event.c'), - _libuv_source('win/fs.c'), - # getaddrinfo.c refers to ConvertInterfaceIndexToLuid - # and ConvertInterfaceLuidToNameA, which are supposedly in iphlpapi.h - # and iphlpapi.lib/dll. But on Windows 10 with Python 3.5 and VC 14 (Visual Studio 2015), - # I get an undefined warning from the compiler for those functions and - # a link error from the linker, so this file can't be included. - # This is possibly because the functions are defined for Windows Vista, and - # Python 3.5 builds with at earlier SDK? - # Fortunately we don't use those functions. - #_libuv_source('win/getaddrinfo.c'), - # getnameinfo.c refers to uv__getaddrinfo_translate_error from - # getaddrinfo.c, which we don't have. - #_libuv_source('win/getnameinfo.c'), - _libuv_source('win/handle.c'), - _libuv_source('win/loop-watcher.c'), - _libuv_source('win/pipe.c'), - _libuv_source('win/poll.c'), - _libuv_source('win/process-stdio.c'), - _libuv_source('win/process.c'), - _libuv_source('win/signal.c'), - _libuv_source('win/snprintf.c'), - _libuv_source('win/stream.c'), - _libuv_source('win/tcp.c'), - _libuv_source('win/thread.c'), - _libuv_source('win/tty.c'), - _libuv_source('win/udp.c'), - _libuv_source('win/util.c'), - _libuv_source('win/winapi.c'), - _libuv_source('win/winsock.c'), - ] -else: - LIBUV_SOURCES += [ - _libuv_source('unix/async.c'), - _libuv_source('unix/core.c'), - _libuv_source('unix/dl.c'), - _libuv_source('unix/fs.c'), - _libuv_source('unix/getaddrinfo.c'), - _libuv_source('unix/getnameinfo.c'), - _libuv_source('unix/loop-watcher.c'), - _libuv_source('unix/loop.c'), - _libuv_source('unix/pipe.c'), - _libuv_source('unix/poll.c'), - _libuv_source('unix/process.c'), - _libuv_source('unix/signal.c'), - _libuv_source('unix/stream.c'), - _libuv_source('unix/tcp.c'), - _libuv_source('unix/thread.c'), - _libuv_source('unix/tty.c'), - _libuv_source('unix/udp.c'), - ] - - -if sys.platform.startswith('linux'): - LIBUV_SOURCES += [ - _libuv_source('unix/procfs-exepath.c'), - _libuv_source('unix/proctitle.c'), - _libuv_source('unix/random-sysctl-linux.c'), - _libuv_source('unix/linux.c'), - ] -elif sys.platform == 'darwin': - LIBUV_SOURCES += [ - _libuv_source('unix/bsd-ifaddrs.c'), - _libuv_source('unix/darwin.c'), - _libuv_source('unix/darwin-proctitle.c'), - _libuv_source('unix/fsevents.c'), - _libuv_source('unix/kqueue.c'), - _libuv_source('unix/proctitle.c'), - ] -elif sys.platform.startswith(('freebsd', 'dragonfly')): # pragma: no cover - # Not tested - LIBUV_SOURCES += [ - _libuv_source('unix/bsd-ifaddrs.c'), - _libuv_source('unix/freebsd.c'), - _libuv_source('unix/kqueue.c'), - _libuv_source('unix/posix-hrtime.c'), - _libuv_source('unix/bsd-proctitle.c'), - ] -elif sys.platform.startswith('openbsd'): # pragma: no cover - # Not tested - LIBUV_SOURCES += [ - _libuv_source('unix/bsd-ifaddrs.c'), - _libuv_source('unix/kqueue.c'), - _libuv_source('unix/openbsd.c'), - _libuv_source('unix/posix-hrtime.c'), - _libuv_source('unix/bsd-proctitle.c'), - ] -elif sys.platform.startswith('netbsd'): # pragma: no cover - # Not tested - LIBUV_SOURCES += [ - _libuv_source('unix/bsd-ifaddrs.c'), - _libuv_source('unix/kqueue.c'), - _libuv_source('unix/netbsd.c'), - _libuv_source('unix/posix-hrtime.c'), - _libuv_source('unix/bsd-proctitle.c'), - ] -elif sys.platform.startswith('sunos'): # pragma: no cover - # Not tested. - LIBUV_SOURCES += [ - _libuv_source('unix/no-proctitle.c'), - _libuv_source('unix/sunos.c'), - ] -elif sys.platform.startswith('aix'): # pragma: no cover - # Not tested. - LIBUV_SOURCES += [ - _libuv_source('unix/aix.c'), - _libuv_source('unix/aix-common.c'), - ] -elif sys.platform.startswith('haiku'): # pragma: no cover - # Not tested - LIBUV_SOURCES += [ - _libuv_source('unix/haiku.c') - ] -elif sys.platform.startswith('cygwin'): # pragma: no cover - # Not tested. - - # Based on Cygwin package sources /usr/src/libuv-1.32.0-1.src/libuv-1.32.0/Makefile.am - # Apparently the same upstream at https://github.com/libuv/libuv/blob/v1.x/Makefile.am - LIBUV_SOURCES += [ - _libuv_source('unix/cygwin.c'), - _libuv_source('unix/bsd-ifaddrs.c'), - _libuv_source('unix/no-fsevents.c'), - _libuv_source('unix/no-proctitle.c'), - _libuv_source('unix/posix-hrtime.c'), - _libuv_source('unix/posix-poll.c'), - _libuv_source('unix/procfs-exepath.c'), - _libuv_source('unix/sysinfo-loadavg.c'), - _libuv_source('unix/sysinfo-memory.c'), - ] - - -LIBUV_MACROS = [ - ('LIBUV_EMBED', int(LIBUV_EMBED)), -] - -def _define_macro(name, value): - LIBUV_MACROS.append((name, value)) - -LIBUV_LIBRARIES = [] - -def _add_library(name): - LIBUV_LIBRARIES.append(name) - -if sys.platform != 'win32': - _define_macro('_LARGEFILE_SOURCE', 1) - _define_macro('_FILE_OFFSET_BITS', 64) - -if sys.platform.startswith('linux'): - _add_library('dl') - _add_library('rt') - _define_macro('_GNU_SOURCE', 1) - _define_macro('_POSIX_C_SOURCE', '200112') -elif sys.platform == 'darwin': - _define_macro('_DARWIN_USE_64_BIT_INODE', 1) - _define_macro('_DARWIN_UNLIMITED_SELECT', 1) -elif sys.platform.startswith('netbsd'): # pragma: no cover - _add_library('kvm') -elif sys.platform.startswith('sunos'): # pragma: no cover - _define_macro('__EXTENSIONS__', 1) - _define_macro('_XOPEN_SOURCE', 500) - _define_macro('_REENTRANT', 1) - _add_library('kstat') - _add_library('nsl') - _add_library('sendfile') - _add_library('socket') - if platform.release() == '5.10': - # https://github.com/libuv/libuv/issues/1458 - # https://github.com/giampaolo/psutil/blob/4d6a086411c77b7909cce8f4f141bbdecfc0d354/setup.py#L298-L300 - _define_macro('SUNOS_NO_IFADDRS', '') -elif sys.platform.startswith('aix'): # pragma: no cover - _define_macro('_LINUX_SOURCE_COMPAT', 1) - if os.uname().sysname != 'OS400': - _add_library('perfstat') -elif WIN: - # All other gevent .pyd files link to the specific minor-version Python - # DLL, so we should do the same here. In virtual environments that don't - # contain the major-version python?.dll stub, _corecffi.pyd would otherwise - # cause the Windows DLL loader to search the entire PATH for a DLL with - # that name. This might end up bringing a second, ABI-incompatible Python - # version into the process, which can easily lead to crashes. - # See https://github.com/gevent/gevent/pull/1814/files - _define_macro('_CFFI_NO_LIMITED_API', 1) - - _define_macro('_GNU_SOURCE', 1) - _define_macro('WIN32', 1) - _define_macro('_CRT_SECURE_NO_DEPRECATE', 1) - _define_macro('_CRT_NONSTDC_NO_DEPRECATE', 1) - _define_macro('_CRT_SECURE_NO_WARNINGS', 1) - _define_macro('_WIN32_WINNT', '0x0602') - _define_macro('WIN32_LEAN_AND_MEAN', 1) - - _add_library('advapi32') - _add_library('dbghelp') - _add_library('iphlpapi') - _add_library('ole32') - _add_library('psapi') - _add_library('shell32') - _add_library('user32') - _add_library('userenv') - _add_library('ws2_32') - -if not LIBUV_EMBED: - del LIBUV_SOURCES[:] - del LIBUV_INCLUDE_DIRS[:] - _add_library('uv') - -LIBUV_INCLUDE_DIRS.append(parentdir) - -ffi.cdef(_cdef) -ffi.set_source( - 'gevent.libuv._corecffi', - _source, - sources=LIBUV_SOURCES, - depends=LIBUV_SOURCES, - include_dirs=LIBUV_INCLUDE_DIRS, - libraries=list(LIBUV_LIBRARIES), - define_macros=list(LIBUV_MACROS), - extra_compile_args=list(_setuputils.IGNORE_THIRD_PARTY_WARNINGS), -) - -if __name__ == '__main__': - # See notes in libev/_corecffi_build.py for how to test this. - # - # Other than the obvious directory changes, the changes are: - # - # CPPFLAGS=-Ideps/libuv/include/ -Isrc/gevent/ - ffi.compile(verbose=True) diff --git a/venv/lib/python3.9/site-packages/gevent/libuv/loop.py b/venv/lib/python3.9/site-packages/gevent/libuv/loop.py deleted file mode 100644 index 19afb14..0000000 --- a/venv/lib/python3.9/site-packages/gevent/libuv/loop.py +++ /dev/null @@ -1,746 +0,0 @@ -""" -libuv loop implementation -""" -import errno -import os -import signal -from collections import defaultdict -from collections import namedtuple - -from zope.interface import implementer - -from gevent import getcurrent -from gevent._ffi.loop import AbstractCallbacks -from gevent._ffi.loop import AbstractLoop -from gevent._ffi.loop import assign_standard_callbacks -from gevent._interfaces import ILoop -from gevent.exceptions import LoopExit -from gevent.libuv import _corecffi # pylint:disable=no-name-in-module,import-error - -ffi = _corecffi.ffi -libuv = _corecffi.lib - -__all__ = [ -] - - -class _Callbacks(AbstractCallbacks): - - def _find_loop_from_c_watcher(self, watcher_ptr): - loop_handle = ffi.cast('uv_handle_t*', watcher_ptr).data - return self.from_handle(loop_handle) if loop_handle else None - - def python_sigchld_callback(self, watcher_ptr, _signum): - self.from_handle(ffi.cast('uv_handle_t*', watcher_ptr).data)._sigchld_callback() - - def python_timer0_callback(self, watcher_ptr): - return self.python_prepare_callback(watcher_ptr) - - def python_queue_callback(self, watcher_ptr, revents): - watcher_handle = watcher_ptr.data - the_watcher = self.from_handle(watcher_handle) - - the_watcher.loop._queue_callback(watcher_ptr, revents) - - -_callbacks = assign_standard_callbacks( - ffi, libuv, _Callbacks, - [ - 'python_sigchld_callback', - 'python_timer0_callback', - 'python_queue_callback', - ] -) - -from gevent._ffi.loop import EVENTS - -GEVENT_CORE_EVENTS = EVENTS # export - -from gevent.libuv import watcher as _watchers # pylint:disable=no-name-in-module - -_events_to_str = _watchers._events_to_str # export - -READ = libuv.UV_READABLE -WRITE = libuv.UV_WRITABLE - -def get_version(): - uv_bytes = ffi.string(libuv.uv_version_string()) - if not isinstance(uv_bytes, str): - # Py3 - uv_str = uv_bytes.decode("ascii") - else: - uv_str = uv_bytes - - return 'libuv-' + uv_str - -def get_header_version(): - return 'libuv-%d.%d.%d' % (libuv.UV_VERSION_MAJOR, libuv.UV_VERSION_MINOR, libuv.UV_VERSION_PATCH) - -def supported_backends(): - return ['default'] - -libuv.gevent_set_uv_alloc() - -@implementer(ILoop) -class loop(AbstractLoop): - - # libuv parameters simply won't accept anything lower than 1ms. In - # practice, looping on gevent.sleep(0.001) takes about 0.00138 s - # (+- 0.000036s) - approx_timer_resolution = 0.001 # 1ms - - # It's relatively more expensive to break from the callback loop - # because we don't do it "inline" from C, we're looping in Python - CALLBACK_CHECK_COUNT = max(AbstractLoop.CALLBACK_CHECK_COUNT, 100) - - # Defines the maximum amount of time the loop will sleep waiting for IO, - # which is also the interval at which signals are checked and handled. - SIGNAL_CHECK_INTERVAL_MS = 300 - - error_handler = None - - _CHECK_POINTER = 'uv_check_t *' - - _PREPARE_POINTER = 'uv_prepare_t *' - _PREPARE_CALLBACK_SIG = "void(*)(void*)" - - _TIMER_POINTER = _CHECK_POINTER # This is poorly named. It's for the callback "timer" - - def __init__(self, flags=None, default=None): - AbstractLoop.__init__(self, ffi, libuv, _watchers, flags, default) - self._child_watchers = defaultdict(list) - self._io_watchers = {} - self._fork_watchers = set() - self._pid = os.getpid() - # pylint:disable-next=superfluous-parens - self._default = (self._ptr == libuv.uv_default_loop()) - self._queued_callbacks = [] - - def _queue_callback(self, watcher_ptr, revents): - self._queued_callbacks.append((watcher_ptr, revents)) - - def _init_loop(self, flags, default): - if default is None: - default = True - # Unlike libev, libuv creates a new default - # loop automatically if the old default loop was - # closed. - - if default: - # XXX: If the default loop had been destroyed, this - # will create a new one, but we won't destroy it - ptr = libuv.uv_default_loop() - else: - ptr = libuv.uv_loop_new() - - - if not ptr: - raise SystemError("Failed to get loop") - - # Track whether or not any object has destroyed - # this loop. See _can_destroy_default_loop - ptr.data = self._handle_to_self - return ptr - - _signal_idle = None - - @property - def ptr(self): - if not self._ptr: - return None - if self._ptr and not self._ptr.data: - # Another instance of the Python loop destroyed - # the C loop. It was probably the default. - self._ptr = None - return self._ptr - - def _init_and_start_check(self): - libuv.uv_check_init(self.ptr, self._check) - libuv.uv_check_start(self._check, libuv.python_check_callback) - libuv.uv_unref(self._check) - - # We also have to have an idle watcher to be able to handle - # signals in a timely manner. Without them, libuv won't loop again - # and call into its check and prepare handlers. - # Note that this basically forces us into a busy-loop - # XXX: As predicted, using an idle watcher causes our process - # to eat 100% CPU time. We instead use a timer with a max of a .3 second - # delay to notice signals. Note that this timeout also implements fork - # watchers, effectively. - - # XXX: Perhaps we could optimize this to notice when there are other - # timers in the loop and start/stop it then. When we have a callback - # scheduled, this should also be the same and unnecessary? - # libev does takes this basic approach on Windows. - self._signal_idle = ffi.new("uv_timer_t*") - libuv.uv_timer_init(self.ptr, self._signal_idle) - self._signal_idle.data = self._handle_to_self - sig_cb = ffi.cast('void(*)(uv_timer_t*)', libuv.python_check_callback) - libuv.uv_timer_start(self._signal_idle, - sig_cb, - self.SIGNAL_CHECK_INTERVAL_MS, - self.SIGNAL_CHECK_INTERVAL_MS) - libuv.uv_unref(self._signal_idle) - - def __check_and_die(self): - if not self.ptr: - # We've been destroyed during the middle of self.run(). - # This method is being called into from C, and it's not - # safe to go back to C (Windows in particular can abort - # the process with "GetQueuedCompletionStatusEx: (6) The - # handle is invalid.") So switch to the parent greenlet. - getcurrent().parent.throw(LoopExit('Destroyed during run')) - - def _run_callbacks(self): - self.__check_and_die() - # Manually handle fork watchers. - curpid = os.getpid() - if curpid != self._pid: - self._pid = curpid - for watcher in self._fork_watchers: - watcher._on_fork() - - - # The contents of queued_callbacks at this point should be timers - # that expired when the loop began along with any idle watchers. - # We need to run them so that any manual callbacks they want to schedule - # get added to the list and ran next before we go on to poll for IO. - # This is critical for libuv on linux: closing a socket schedules some manual - # callbacks to actually stop the watcher; if those don't run before - # we poll for IO, then libuv can abort the process for the closed file descriptor. - - # XXX: There's still a race condition here because we may not run *all* the manual - # callbacks. We need a way to prioritize those. - - # Running these before the manual callbacks lead to some - # random test failures. In test__event.TestEvent_SetThenClear - # we would get a LoopExit sometimes. The problem occurred when - # a timer expired on entering the first loop; we would process - # it there, and then process the callback that it created - # below, leaving nothing for the loop to do. Having the - # self.run() manually process manual callbacks before - # continuing solves the problem. (But we must still run callbacks - # here again.) - self._prepare_ran_callbacks = self.__run_queued_callbacks() - - super(loop, self)._run_callbacks() - - def _init_and_start_prepare(self): - libuv.uv_prepare_init(self.ptr, self._prepare) - libuv.uv_prepare_start(self._prepare, libuv.python_prepare_callback) - libuv.uv_unref(self._prepare) - - def _init_callback_timer(self): - libuv.uv_check_init(self.ptr, self._timer0) - - def _stop_callback_timer(self): - libuv.uv_check_stop(self._timer0) - - def _start_callback_timer(self): - # The purpose of the callback timer is to ensure that we run - # callbacks as soon as possible on the next iteration of the event loop. - - # In libev, we set a 0 duration timer with a no-op callback. - # This executes immediately *after* the IO poll is done (it - # actually determines the time that the IO poll will block - # for), so having the timer present simply spins the loop, and - # our normal prepare watcher kicks in to run the callbacks. - - # In libuv, however, timers are run *first*, before prepare - # callbacks and before polling for IO. So a no-op 0 duration - # timer actually does *nothing*. (Also note that libev queues all - # watchers found during IO poll to run at the end (I think), while libuv - # runs them in uv__io_poll itself.) - - # From the loop inside uv_run: - # while True: - # uv__update_time(loop); - # uv__run_timers(loop); - # # we don't use pending watchers. They are how libuv - # # implements the pipe/udp/tcp streams. - # ran_pending = uv__run_pending(loop); - # uv__run_idle(loop); - # uv__run_prepare(loop); - # ... - # uv__io_poll(loop, timeout); # <--- IO watchers run here! - # uv__run_check(loop); - - # libev looks something like this (pseudo code because the real code is - # hard to read): - # - # do { - # run_fork_callbacks(); - # run_prepare_callbacks(); - # timeout = min(time of all timers or normal block time) - # io_poll() # <--- Only queues IO callbacks - # update_now(); calculate_expired_timers(); - # run callbacks in this order: (although specificying priorities changes it) - # check - # stat - # child - # signal - # timer - # io - # } - - # So instead of running a no-op and letting the side-effect of spinning - # the loop run the callbacks, we must explicitly run them here. - - # If we don't, test__systemerror:TestCallback will be flaky, failing - # one time out of ~20, depending on timing. - - # To get them to run immediately after this current loop, - # we use a check watcher, instead of a 0 duration timer entirely. - # If we use a 0 duration timer, we can get stuck in a timer loop. - # Python 3.6 fails in test_ftplib.py - - # As a final note, if we have not yet entered the loop *at - # all*, and a timer was created with a duration shorter than - # the amount of time it took for us to enter the loop in the - # first place, it may expire and get called before our callback - # does. This could also lead to test__systemerror:TestCallback - # appearing to be flaky. - - # As yet another final note, if we are currently running a - # timer callback, meaning we're inside uv__run_timers() in C, - # and the Python starts a new timer, if the Python code then - # update's the loop's time, it's possible that timer will - # expire *and be run in the same iteration of the loop*. This - # is trivial to do: In sequential code, anything after - # `gevent.sleep(0.1)` is running in a timer callback. Starting - # a new timer---e.g., another gevent.sleep() call---will - # update the time, *before* uv__run_timers exits, meaning - # other timers get a chance to run before our check or prepare - # watcher callbacks do. Therefore, we do indeed have to have a 0 - # timer to run callbacks---it gets inserted before any other user - # timers---ideally, this should be especially careful about how much time - # it runs for. - - # AND YET: We can't actually do that. We get timeouts that I haven't fully - # investigated if we do. Probably stuck in a timer loop. - - # As a partial remedy to this, unlike libev, our timer watcher - # class doesn't update the loop time by default. - - libuv.uv_check_start(self._timer0, libuv.python_timer0_callback) - - - def _stop_aux_watchers(self): - super(loop, self)._stop_aux_watchers() - assert self._prepare - assert self._check - assert self._signal_idle - libuv.uv_prepare_stop(self._prepare) - libuv.uv_ref(self._prepare) # Why are we doing this? - - libuv.uv_check_stop(self._check) - libuv.uv_ref(self._check) - - libuv.uv_timer_stop(self._signal_idle) - libuv.uv_ref(self._signal_idle) - - libuv.uv_check_stop(self._timer0) - - def _setup_for_run_callback(self): - self._start_callback_timer() - libuv.uv_ref(self._timer0) - - def _can_destroy_loop(self, ptr): - return ptr - - def __close_loop(self, ptr): - closed_failed = 1 - - while closed_failed: - closed_failed = libuv.uv_loop_close(ptr) - if not closed_failed: - break - - if closed_failed != libuv.UV_EBUSY: - raise SystemError("Unknown close failure reason", closed_failed) - # We already closed all the handles. Run the loop - # once to let them be cut off from the loop. - ran_has_more_callbacks = libuv.uv_run(ptr, libuv.UV_RUN_ONCE) - if ran_has_more_callbacks: - libuv.uv_run(ptr, libuv.UV_RUN_NOWAIT) - - - def _destroy_loop(self, ptr): - # We're being asked to destroy a loop that's, potentially, at - # the time it was constructed, was the default loop. If loop - # objects were constructed more than once, it may have already - # been destroyed, though. We track this in the data member. - data = ptr.data - ptr.data = ffi.NULL - try: - if data: - libuv.uv_stop(ptr) - libuv.gevent_close_all_handles(ptr) - finally: - ptr.data = ffi.NULL - - try: - if data: - self.__close_loop(ptr) - finally: - # Destroy the native resources *after* we have closed - # the loop. If we do it before, walking the handles - # attached to the loop is likely to segfault. - # Note that these may have been closed already if the default loop was shared. - if data: - libuv.gevent_zero_check(self._check) - libuv.gevent_zero_check(self._timer0) - libuv.gevent_zero_prepare(self._prepare) - libuv.gevent_zero_timer(self._signal_idle) - libuv.gevent_zero_loop(ptr) - - del self._check - del self._prepare - del self._signal_idle - del self._timer0 - - # Destroy any watchers we're still holding on to. - del self._io_watchers - del self._fork_watchers - del self._child_watchers - - _HandleState = namedtuple("HandleState", - ['handle', - 'type', - 'watcher', - 'ref', - 'active', - 'closing']) - def debug(self): - """ - Return all the handles that are open and their ref status. - """ - if not self.ptr: - return ["Loop has been destroyed"] - - handle_state = self._HandleState - handles = [] - - # XXX: Convert this to a modern callback. - def walk(handle, _arg): - data = handle.data - if data: - watcher = ffi.from_handle(data) - else: - watcher = None - handles.append(handle_state(handle, - ffi.string(libuv.uv_handle_type_name(handle.type)), - watcher, - libuv.uv_has_ref(handle), - libuv.uv_is_active(handle), - libuv.uv_is_closing(handle))) - - libuv.uv_walk(self.ptr, - ffi.callback("void(*)(uv_handle_t*,void*)", - walk), - ffi.NULL) - return handles - - def ref(self): - pass - - def unref(self): - # XXX: Called by _run_callbacks. - pass - - def break_(self, how=None): - if self.ptr: - libuv.uv_stop(self.ptr) - - def reinit(self): - # TODO: How to implement? We probably have to simply - # re-__init__ this whole class? Does it matter? - # OR maybe we need to uv_walk() and close all the handles? - - # XXX: libuv < 1.12 simply CANNOT handle a fork unless you immediately - # exec() in the child. There are multiple calls to abort() that - # will kill the child process: - # - The OS X poll implementation (kqueue) aborts on an error return - # value; since kqueue FDs can't be inherited, then the next call - # to kqueue in the child will fail and get aborted; fork() is likely - # to be called during the gevent loop, meaning we're deep inside the - # runloop already, so we can't even close the loop that we're in: - # it's too late, the next call to kqueue is already scheduled. - # - The threadpool, should it be in use, also aborts - # (https://github.com/joyent/libuv/pull/1136) - # - There global shared state that breaks signal handling - # and leads to an abort() in the child, EVEN IF the loop in the parent - # had already been closed - # (https://github.com/joyent/libuv/issues/1405) - - # In 1.12, the uv_loop_fork function was added (by gevent!) - libuv.uv_loop_fork(self.ptr) - - _prepare_ran_callbacks = False - - def __run_queued_callbacks(self): - if not self._queued_callbacks: - return False - - cbs = self._queued_callbacks[:] - del self._queued_callbacks[:] - - for watcher_ptr, arg in cbs: - handle = watcher_ptr.data - if not handle: - # It's been stopped and possibly closed - assert not libuv.uv_is_active(watcher_ptr) - continue - val = _callbacks.python_callback(handle, arg) - if val == -1: # Failure. - _callbacks.python_handle_error(handle, arg) - elif val == 1: # Success, and we may need to close the Python watcher. - if not libuv.uv_is_active(watcher_ptr): - # The callback closed the native watcher resources. Good. - # It's *supposed* to also reset the .data handle to NULL at - # that same time. If it resets it to something else, we're - # re-using the same watcher object, and that's not correct either. - # On Windows in particular, if the .data handle is changed because - # the IO multiplexer is being restarted, trying to dereference the - # *old* handle can crash with an FFI error. - handle_after_callback = watcher_ptr.data - try: - if handle_after_callback and handle_after_callback == handle: - _callbacks.python_stop(handle_after_callback) - finally: - watcher_ptr.data = ffi.NULL - return True - - - def run(self, nowait=False, once=False): - # we can only respect one flag or the other. - # nowait takes precedence because it can't block - mode = libuv.UV_RUN_DEFAULT - if once: - mode = libuv.UV_RUN_ONCE - if nowait: - mode = libuv.UV_RUN_NOWAIT - - if mode == libuv.UV_RUN_DEFAULT: - while self._ptr and self._ptr.data: - # This is here to better preserve order guarantees. - # See _run_callbacks for details. - - # It may get run again from the prepare watcher, so - # potentially we could take twice as long as the - # switch interval. - # If we have *lots* of callbacks to run, we may not actually - # get through them all before we're requested to poll for IO; - # so in that case, just spin the loop once (UV_RUN_NOWAIT) and - # go again. - self._run_callbacks() - self._prepare_ran_callbacks = False - - # UV_RUN_ONCE will poll for IO, blocking for up to the time needed - # for the next timer to expire. Worst case, that's our _signal_idle - # timer, about 1/3 second. UV_RUN_ONCE guarantees that some forward progress - # is made, either by an IO watcher or a timer. - # - # In contrast, UV_RUN_NOWAIT makes no such guarantee, it only polls for IO once and - # immediately returns; it does not update the loop time or timers after - # polling for IO. - run_mode = ( - libuv.UV_RUN_ONCE - if not self._callbacks and not self._queued_callbacks - else libuv.UV_RUN_NOWAIT - ) - - ran_status = libuv.uv_run(self._ptr, run_mode) - # Note that we run queued callbacks when the prepare watcher runs, - # thus accounting for timers that expired before polling for IO, - # and idle watchers. This next call should get IO callbacks and - # callbacks from timers that expired *after* polling for IO. - ran_callbacks = self.__run_queued_callbacks() - - if not ran_status and not ran_callbacks and not self._prepare_ran_callbacks: - # A return of 0 means there are no referenced and - # active handles. The loop is over. - # If we didn't run any callbacks, then we couldn't schedule - # anything to switch in the future, so there's no point - # running again. - return ran_status - return 0 # Somebody closed the loop - - result = libuv.uv_run(self._ptr, mode) - self.__run_queued_callbacks() - return result - - def now(self): - self.__check_and_die() - # libuv's now is expressed as an integer number of - # milliseconds, so to get it compatible with time.time units - # that this method is supposed to return, we have to divide by 1000.0 - now = libuv.uv_now(self.ptr) - return now / 1000.0 - - def update_now(self): - self.__check_and_die() - libuv.uv_update_time(self.ptr) - - def fileno(self): - if self.ptr: - fd = libuv.uv_backend_fd(self._ptr) - if fd >= 0: - return fd - - _sigchld_watcher = None - _sigchld_callback_ffi = None - - def install_sigchld(self): - if not self.default: - return - - if self._sigchld_watcher: - return - - self._sigchld_watcher = ffi.new('uv_signal_t*') - libuv.uv_signal_init(self.ptr, self._sigchld_watcher) - self._sigchld_watcher.data = self._handle_to_self - # Don't let this keep the loop alive - libuv.uv_unref(self._sigchld_watcher) - - libuv.uv_signal_start(self._sigchld_watcher, - libuv.python_sigchld_callback, - signal.SIGCHLD) - - def reset_sigchld(self): - if not self.default or not self._sigchld_watcher: - return - - libuv.uv_signal_stop(self._sigchld_watcher) - # Must go through this to manage the memory lifetime - # correctly. Alternately, we could just stop it and restart - # it in install_sigchld? - _watchers.watcher._watcher_ffi_close(self._sigchld_watcher) - del self._sigchld_watcher - - - def _sigchld_callback(self): - # Signals can arrive at (relatively) any time. To eliminate - # race conditions, and behave more like libev, we "queue" - # sigchld to run when we run callbacks. - while True: - try: - pid, status, _usage = os.wait3(os.WNOHANG) - except OSError: - # Python 3 raises ChildProcessError - break - - if pid == 0: - break - children_watchers = self._child_watchers.get(pid, []) + self._child_watchers.get(0, []) - for watcher in children_watchers: - self.run_callback(watcher._set_waitpid_status, pid, status) - - # Don't invoke child watchers for 0 more than once - self._child_watchers[0] = [] - - def _register_child_watcher(self, watcher): - self._child_watchers[watcher._pid].append(watcher) - - def _unregister_child_watcher(self, watcher): - try: - # stop() should be idempotent - self._child_watchers[watcher._pid].remove(watcher) - except ValueError: - pass - - # Now's a good time to clean up any dead watchers we don't need - # anymore - for pid in list(self._child_watchers): - if not self._child_watchers[pid]: - del self._child_watchers[pid] - - def io(self, fd, events, ref=True, priority=None): - # We rely on hard references here and explicit calls to - # close() on the returned object to correctly manage - # the watcher lifetimes. - - io_watchers = self._io_watchers - try: - io_watcher = io_watchers[fd] - assert io_watcher._multiplex_watchers, ("IO Watcher %s unclosed but should be dead" % io_watcher) - except KeyError: - # Start the watcher with just the events that we're interested in. - # as multiplexers are added, the real event mask will be updated to keep in sync. - # If we watch for too much, we get spurious wakeups and busy loops. - io_watcher = self._watchers.io(self, fd, 0) - io_watchers[fd] = io_watcher - watcher_id = id(io_watcher) - io_watcher._no_more_watchers = lambda: ( - # Don't capture the watcher in the lambda vars, - # avoid a cycle. - io_watchers.pop(fd) - if id(io_watchers.get(fd)) == watcher_id - else None - ) - - return io_watcher.multiplex(events) - - def closing_fd(self, fd): # pylint:disable=unused-argument - try: - watcher = self._io_watchers[fd] - except KeyError: - return False - # It's active if any multiplexed watcher has been started; this corresponds to a - # call to ``uv_poll_start``; until the call to ``uv_poll_stop``, it is not safe to - # close the file descriptor. Returning true here (``watcher.active``) means that - # it can't be closed immediately and must wait until we have a loop iteration. - # Non-started watchers (``not watcher.active``) are safe to close immediately, - # though if you try to do anything with that file descriptor - - - must_defer = watcher.active - # Destroy the ability to use this watcher to create future sub-watchers; - # that way, if we try to use this FD again for a new watcher, and - # it is actually invalid, we get the right exception at construction time. - # Only do this if we're actually going to be deferring the close; if we close - # immediately, open a new socket, and request a watcher for it, we could get this watcher - # object back because FDs get reused and the second socket very likely - # has the same FD as the original socket. - if must_defer: - # At this point, if the watcher is active, libev feeds a - # synthetic event to it with ``ev_feed_fd_event``. This doesn't - # actually do any IO, it just schedules the object for a callback - # on the next loop iteration, so that any greenlets that are blocked - # get woken up. We have to implement that ourself. - def do_it(watcher): - try: - watcher._io_callback(0xFFFFFFFF) - watcher.stop() - watcher.close_all() - # Clean up our patches to disconnect them from this - # loop completely. - if '_check_fd_valid' in vars(watcher): - del watcher._check_fd_valid - if '_no_more_watchers' in vars(watcher): - del watcher._no_more_watchers - assert self._io_watchers.get(fd) is not watcher - finally: - check.stop() - check.close() - - check = self.check() - check.start(do_it, watcher) - def not_valid(): - raise OSError( - errno.EBADF, - "The file descriptor %s is in the process of being closed." % (fd,)) - watcher._check_fd_valid = not_valid - return must_defer - - - def prepare(self, ref=True, priority=None): - # We run arbitrary code in python_prepare_callback. That could switch - # greenlets. If it does that while also manipulating the active prepare - # watchers, we could corrupt the process state, since the prepare watcher - # queue is iterated on the stack (on unix). We could workaround this by implementing - # prepare watchers in pure Python. - # See https://github.com/gevent/gevent/issues/1126 - raise TypeError("prepare watchers are not currently supported in libuv. " - "If you need them, please contact the maintainers.") diff --git a/venv/lib/python3.9/site-packages/gevent/libuv/watcher.py b/venv/lib/python3.9/site-packages/gevent/libuv/watcher.py deleted file mode 100644 index b28ba83..0000000 --- a/venv/lib/python3.9/site-packages/gevent/libuv/watcher.py +++ /dev/null @@ -1,800 +0,0 @@ -# pylint: disable=too-many-lines, protected-access, redefined-outer-name, not-callable -# pylint: disable=no-member - -import functools -import sys - -from gevent.libuv import _corecffi # pylint:disable=no-name-in-module,import-error - -# Nothing public here -__all__ = [] - -ffi = _corecffi.ffi -libuv = _corecffi.lib - -from gevent._ffi import watcher as _base -from gevent._ffi import _dbg -from gevent.os import _check_fd_valid - -# A set of uv_handle_t* CFFI objects. Kept around -# to keep the memory alive until libuv is done with them. -class _ClosingWatchers(dict): - __slots__ = () - - def remove(self, obj): - try: - del self[obj] - except KeyError: # pragma: no cover - # This has been seen to happen if the module is executed twice - # and so the callback doesn't match the storage seen by watcher objects. - print( - 'gevent error: Unable to remove closing watcher from keepaliveset. ' - 'Has the module state been corrupted or executed more than once?', - file=sys.stderr - ) - -_closing_watchers = _ClosingWatchers() - - -# In debug mode, it would be nice to be able to clear the memory of -# the watcher (its size determined by -# libuv.uv_handle_size(ffi_watcher.type)) using memset so that if we -# are using it after it's supposedly been closed and deleted, we'd -# catch it sooner. BUT doing so breaks test__threadpool. We get errors -# about `pthread_mutex_lock[3]: Invalid argument` (and sometimes we -# crash) suggesting either that we're writing on memory that doesn't -# belong to us, somehow, or that we haven't actually lost all -# references... -_uv_close_callback = ffi.def_extern(name='_uv_close_callback')( - _closing_watchers.remove -) - - -_events = [(libuv.UV_READABLE, "READ"), - (libuv.UV_WRITABLE, "WRITE")] - -def _events_to_str(events): # export - return _base.events_to_str(events, _events) - - - -class UVFuncallError(ValueError): - pass - -class libuv_error_wrapper(object): - # Makes sure that everything stored as a function - # on the wrapper instances (classes, actually, - # because this is used by the metaclass) - # checks its return value and raises an error. - # This expects that everything we call has an int - # or void return value and follows the conventions - # of error handling (that negative values are errors) - def __init__(self, uv): - self._libuv = uv - - def __getattr__(self, name): - libuv_func = getattr(self._libuv, name) - - @functools.wraps(libuv_func) - def wrap(*args, **kwargs): - if args and isinstance(args[0], watcher): - args = args[1:] - res = libuv_func(*args, **kwargs) - if res is not None and res < 0: - kind = UVFuncallError - if res == libuv.UV_EBADF: - kind = lambda msg: OSError(abs(res), msg) - raise kind( - str(ffi.string(libuv.uv_err_name(res)).decode('ascii') - + ' ' - + ffi.string(libuv.uv_strerror(res)).decode('ascii')) - + " Args: " + repr(args) + " KWARGS: " + repr(kwargs) - + " UVError: " + str(res) - ) - return res - - setattr(self, name, wrap) - - return wrap - - -class ffi_unwrapper(object): - # undoes the wrapping of libuv_error_wrapper for - # the methods used by the metaclass that care - - def __init__(self, ff): - self._ffi = ff - - def __getattr__(self, name): - return getattr(self._ffi, name) - - def addressof(self, lib, name): - assert isinstance(lib, libuv_error_wrapper) - return self._ffi.addressof(libuv, name) - - -class watcher(_base.watcher): - _FFI = ffi_unwrapper(ffi) - _LIB = libuv_error_wrapper(libuv) - - _watcher_prefix = 'uv' - _watcher_struct_pattern = '%s_t' - - @classmethod - def _watcher_ffi_close(cls, ffi_watcher): - # Managing the lifetime of _watcher is tricky. - # They have to be uv_close()'d, but that only - # queues them to be closed in the *next* loop iteration. - # The memory must stay valid for at least that long, - # or assert errors are triggered. We can't use a ffi.gc() - # pointer to queue the uv_close, because by the time the - # destructor is called, there's no way to keep the memory alive - # and it could be re-used. - # So here we resort to resurrecting the pointer object out - # of our scope, keeping it alive past this object's lifetime. - # We then use the uv_close callback to handle removing that - # reference. There's no context passed to the close callback, - # so we have to do this globally. - - # Sadly, doing this causes crashes if there were multiple - # watchers for a given FD, so we have to take special care - # about that. See https://github.com/gevent/gevent/issues/790#issuecomment-208076604 - - # Note that this cannot be a __del__ method, because we store - # the CFFI handle to self on self, which is a cycle, and - # objects with a __del__ method cannot be collected on CPython < 3.4 - - # Instead, this is arranged as a callback to GC when the - # watcher class dies. Obviously it's important to keep the ffi - # watcher alive. - # We can pass in "subclasses" of uv_handle_t that line up at the C level, - # but that don't in CFFI without a cast. But be careful what we use the cast - # for, don't pass it back to C. - ffi_handle_watcher = cls._FFI.cast('uv_handle_t*', ffi_watcher) - ffi_handle_watcher.data = ffi.NULL - - if ffi_handle_watcher.type and not libuv.uv_is_closing(ffi_watcher): - # If the type isn't set, we were never properly initialized, - # and trying to close it results in libuv terminating the process. - # Sigh. Same thing if it's already in the process of being - # closed. - _closing_watchers[ffi_handle_watcher] = ffi_watcher - libuv.uv_close(ffi_watcher, libuv._uv_close_callback) - - def _watcher_ffi_set_init_ref(self, ref): - self.ref = ref - - def _watcher_ffi_init(self, args): - # TODO: we could do a better job chokepointing this - return self._watcher_init(self.loop.ptr, - self._watcher, - *args) - - def _watcher_ffi_start(self): - self._watcher_start(self._watcher, self._watcher_callback) - - def _watcher_ffi_stop(self): - if self._watcher: - # The multiplexed io watcher deletes self._watcher - # when it closes down. If that's in the process of - # an error handler, AbstractCallbacks.unhandled_onerror - # will try to close us again. - self._watcher_stop(self._watcher) - - @_base.only_if_watcher - def _watcher_ffi_ref(self): - libuv.uv_ref(self._watcher) - - @_base.only_if_watcher - def _watcher_ffi_unref(self): - libuv.uv_unref(self._watcher) - - def _watcher_ffi_start_unref(self): - pass - - def _watcher_ffi_stop_ref(self): - pass - - def _get_ref(self): - # Convert 1/0 to True/False - if self._watcher is None: - return None - return bool(libuv.uv_has_ref(self._watcher)) - - def _set_ref(self, value): - if value: - self._watcher_ffi_ref() - else: - self._watcher_ffi_unref() - - ref = property(_get_ref, _set_ref) - - def feed(self, _revents, _callback, *_args): - # pylint:disable-next=broad-exception-raised - raise Exception("Not implemented") - -class io(_base.IoMixin, watcher): - _watcher_type = 'poll' - _watcher_callback_name = '_gevent_poll_callback2' - - # On Windows is critical to be able to garbage collect these - # objects in a timely fashion so that they don't get reused - # for multiplexing completely different sockets. This is because - # uv_poll_init_socket does a lot of setup for the socket to make - # polling work. If get reused for another socket that has the same - # fileno, things break badly. (In theory this could be a problem - # on posix too, but in practice it isn't). - - # TODO: We should probably generalize this to all - # ffi watchers. Avoiding GC cycles as much as possible - # is a good thing, and potentially allocating new handles - # as needed gets us better memory locality. - - # Especially on Windows, we must also account for the case that a - # reference to this object has leaked (e.g., the socket object is - # still around), but the fileno has been closed and a new one - # opened. We must still get a new native watcher at that point. We - # handle this case by simply making sure that we don't even have - # a native watcher until the object is started, and we shut it down - # when the object is stopped. - - # XXX: I was able to solve at least Windows test_ftplib.py issues - # with more of a careful use of io objects in socket.py, so - # delaying this entirely is at least temporarily on hold. Instead - # sticking with the _watcher_create function override for the - # moment. - - # XXX: Note 2: Moving to a deterministic close model, which was necessary - # for PyPy, also seems to solve the Windows issues. So we're completely taking - # this object out of the loop's registration; we don't want GC callbacks and - # uv_close anywhere *near* this object. - - _watcher_registers_with_loop_on_create = False - - EVENT_MASK = libuv.UV_READABLE | libuv.UV_WRITABLE | libuv.UV_DISCONNECT - - _multiplex_watchers = () - - def __init__(self, loop, fd, events, ref=True, priority=None): - super(io, self).__init__(loop, fd, events, ref=ref, priority=priority, _args=(fd,)) - self._fd = fd - self._events = events - self._multiplex_watchers = [] - - def _get_fd(self): - return self._fd - - @_base.not_while_active - def _set_fd(self, fd): - self._fd = fd - self._watcher_ffi_init((fd,)) - - def _get_events(self): - return self._events - - def _set_events(self, events): - if events == self._events: - return - self._events = events - if self.active: - # We're running but libuv specifically says we can - # call start again to change our event mask. - assert self._handle is not None - self._watcher_start(self._watcher, self._events, self._watcher_callback) - - events = property(_get_events, _set_events) - - def _watcher_ffi_start(self): - self._watcher_start(self._watcher, self._events, self._watcher_callback) - - if sys.platform.startswith('win32'): - # uv_poll can only handle sockets on Windows, but the plain - # uv_poll_init we call on POSIX assumes that the fileno - # argument is already a C fileno, as created by - # _get_osfhandle. C filenos are limited resources, must be - # closed with _close. So there are lifetime issues with that: - # calling the C function _close to dispose of the fileno - # *also* closes the underlying win32 handle, possibly - # prematurely. (XXX: Maybe could do something with weak - # references? But to what?) - - # All libuv wants to do with the fileno in uv_poll_init is - # turn it back into a Win32 SOCKET handle. - - # Now, libuv provides uv_poll_init_socket, which instead of - # taking a C fileno takes the SOCKET, avoiding the need to dance with - # the C runtime. - - # It turns out that SOCKET (win32 handles in general) can be - # represented with `intptr_t`. It further turns out that - # CPython *directly* exposes the SOCKET handle as the value of - # fileno (32-bit PyPy does some munging on it, which should - # rarely matter). So we can pass socket.fileno() through - # to uv_poll_init_socket. - - # See _corecffi_build. - _watcher_init = watcher._LIB.uv_poll_init_socket - - - class _multiplexwatcher(object): - - callback = None - args = () - pass_events = False - ref = True - - def __init__(self, events, watcher): - self._events = events - - # References: - # These objects must keep the original IO object alive; - # the IO object SHOULD NOT keep these alive to avoid cycles - # We MUST NOT rely on GC to clean up the IO objects, but the explicit - # calls to close(); see _multiplex_closed. - self._watcher_ref = watcher - - events = property( - lambda self: self._events, - _base.not_while_active(lambda self, nv: setattr(self, '_events', nv))) - - def start(self, callback, *args, **kwargs): - self.pass_events = kwargs.get("pass_events") - self.callback = callback - self.args = args - - watcher = self._watcher_ref - if watcher is not None: - if not watcher.active: - watcher._io_start() - else: - # Make sure we're in the event mask - watcher._calc_and_update_events() - - def stop(self): - self.callback = None - self.pass_events = None - self.args = None - watcher = self._watcher_ref - if watcher is not None: - watcher._io_maybe_stop() - - def close(self): - if self._watcher_ref is not None: - self._watcher_ref._multiplex_closed(self) - self._watcher_ref = None - - @property - def active(self): - return self.callback is not None - - @property - def _watcher(self): - # For testing. - return self._watcher_ref._watcher - - # ares.pyx depends on this property, - # and test__core uses it too - fd = property(lambda self: getattr(self._watcher_ref, '_fd', -1), - lambda self, nv: self._watcher_ref._set_fd(nv)) - - def _io_maybe_stop(self): - self._calc_and_update_events() - for w in self._multiplex_watchers: - if w.callback is not None: - # There's still a reference to it, and it's started, - # so we can't stop. - return - # If we get here, nothing was started - # so we can take ourself out of the polling set - self.stop() - - def _io_start(self): - self._calc_and_update_events() - self.start(self._io_callback, pass_events=True) - - def _calc_and_update_events(self): - events = 0 - for watcher in self._multiplex_watchers: - if watcher.callback is not None: - # Only ask for events that are active. - events |= watcher.events - self._set_events(events) - - - def _check_fd_valid(self): - # Replaced by the event loop while we're being closed - # to raise an exception. - _check_fd_valid(self._fd) - - def multiplex(self, events): - # libuv validates the FD when a watcher is originally - # created, but it may have gone invalid. Re-do the validation - # check here so we can raise the proper OSError. - self._check_fd_valid() - watcher = self._multiplexwatcher(events, self) - self._multiplex_watchers.append(watcher) - self._calc_and_update_events() - return watcher - - def close(self): - super(io, self).close() - # Return to a tuple so that we can't accidentally start - # anything new; this is also how we detect closing - # of the master before closing the multiplexed watchers. - try: - del self._multiplex_watchers - except AttributeError: - # Be idempotent - pass - - def close_all(self): - for w in list(self._multiplex_watchers): - w.stop() - w.close() - assert not self._multiplex_watchers - self.close() - - def _multiplex_closed(self, watcher): - try: - self._multiplex_watchers.remove(watcher) - except AttributeError: # pragma: no cover - # Oh no, one of the sub-watchers wasn't closed - # before the master watcher was. This shouldn't normally - # be possible unless you're using the same file descriptor - # in multiple socket objects and you close one of them. Then - # see ``lopp.closing_fd`` - return - - if not self._multiplex_watchers: - self.stop() # should already be stopped - self._no_more_watchers() - # It is absolutely critical that we control when the call - # to uv_close() gets made. uv_close() of a uv_poll_t - # handle winds up calling uv__platform_invalidate_fd, - # which, as the name implies, destroys any outstanding - # events for the *fd* that haven't been delivered yet, and also removes - # the *fd* from the poll set. So if this happens later, at some - # non-deterministic time when (cyclic or otherwise) GC runs, - # *and* we've opened a new watcher for the fd, that watcher will - # suddenly and mysteriously stop seeing events. So we do this now; - # this method is smart enough not to close the handle twice. - self.close() - else: - self._calc_and_update_events() - - def _no_more_watchers(self): - # The loop sets this on an individual watcher to delete it from - # the active list where it keeps hard references. - pass - - def _io_callback(self, events): - if events < 0: - # actually a status error code - _dbg("Callback error on", self._fd, - ffi.string(libuv.uv_err_name(events)), - ffi.string(libuv.uv_strerror(events))) - # XXX: We've seen one half of a FileObjectPosix pair - # (the read side of a pipe) report errno 11 'bad file descriptor' - # after the write side was closed and its watcher removed. But - # we still need to attempt to read from it to clear out what's in - # its buffers--if we return with the watcher inactive before proceeding to wake up - # the reader, we get a LoopExit. So we can't return here and arguably shouldn't print it - # either. The negative events mask will match the watcher's mask. - # See test__fileobject.py:Test.test_newlines for an example. - - # On Windows (at least with PyPy), we can get ENOTSOCK (socket operation on non-socket) - # if a socket gets closed. If we don't pass the events on, we hang. - # See test__makefile_ref.TestSSL for examples. - # return - - for watcher in self._multiplex_watchers: - if not watcher.callback: - # Stopped - continue - assert watcher._watcher_ref is self, (self, watcher._watcher_ref) - - send_event = (events & watcher.events) or events < 0 - if send_event: - if not watcher.pass_events: - watcher.callback(*watcher.args) - else: - watcher.callback(events, *watcher.args) - -class _SimulatedWithAsyncMixin(object): - _watcher_skip_ffi = True - - def __init__(self, loop, *args, **kwargs): - self._async = loop.async_() - try: - super(_SimulatedWithAsyncMixin, self).__init__(loop, *args, **kwargs) - except: - self._async.close() - raise - - def _watcher_create(self, _args): - return - - @property - def _watcher_handle(self): - return None - - def _watcher_ffi_init(self, _args): - return - - def _watcher_ffi_set_init_ref(self, ref): - self._async.ref = ref - - @property - def active(self): - return self._async.active - - def start(self, cb, *args): - assert self._async is not None - self._register_loop_callback() - self.callback = cb - self.args = args - self._async.start(cb, *args) - - def stop(self): - self._unregister_loop_callback() - self.callback = None - self.args = None - if self._async is not None: - # If we're stop() after close(). - # That should be allowed. - self._async.stop() - - def close(self): - if self._async is not None: - a = self._async - self._async = None - a.close() - - def _register_loop_callback(self): - # called from start() - raise NotImplementedError() - - def _unregister_loop_callback(self): - # called from stop - raise NotImplementedError() - -class fork(_SimulatedWithAsyncMixin, - _base.ForkMixin, - watcher): - # We'll have to implement this one completely manually. - _watcher_skip_ffi = False - - def _register_loop_callback(self): - self.loop._fork_watchers.add(self) - - def _unregister_loop_callback(self): - try: - # stop() should be idempotent - self.loop._fork_watchers.remove(self) - except KeyError: - pass - - def _on_fork(self): - self._async.send() - - -class child(_SimulatedWithAsyncMixin, - _base.ChildMixin, - watcher): - _watcher_skip_ffi = True - # We'll have to implement this one completely manually. - # Our approach is to use a SIGCHLD handler and the original - # os.waitpid call. - - # On Unix, libuv's uv_process_t and uv_spawn use SIGCHLD, - # just like libev does for its child watchers. So - # we're not adding any new SIGCHLD related issues not already - # present in libev. - - - def _register_loop_callback(self): - self.loop._register_child_watcher(self) - - def _unregister_loop_callback(self): - self.loop._unregister_child_watcher(self) - - def _set_waitpid_status(self, pid, status): - self._rpid = pid - self._rstatus = status - self._async.send() - - -class async_(_base.AsyncMixin, watcher): - _watcher_callback_name = '_gevent_async_callback0' - - # libuv async watchers are different than all other watchers: - # They don't have a separate start/stop method (presumably - # because of race conditions). Simply initing them places them - # into the active queue. - # - # In the past, we sent a NULL C callback to the watcher, trusting - # that no one would call send() without actually starting us (or after - # closing us); doing so would crash. But we don't want to delay - # initing the struct because it will crash in uv_close() when we get GC'd, - # and send() will also crash. Plus that complicates our lifecycle (managing - # the memory). - # - # Now, we always init the correct C callback, and use a dummy - # Python callback that gets replaced when we are started and - # stopped. This prevents mistakes from being crashes. - _callback = lambda: None - - def _watcher_ffi_init(self, args): - # NOTE: uv_async_init is NOT idempotent. Calling it more than - # once adds the uv_async_t to the internal queue multiple times, - # and uv_close only cleans up one of them, meaning that we tend to - # crash. Thus we have to be very careful not to allow that. - return self._watcher_init(self.loop.ptr, self._watcher, - self._watcher_callback) - - def _watcher_ffi_start(self): - pass - - def _watcher_ffi_stop(self): - pass - - def send(self): - assert self._callback is not async_._callback, "Sending to a closed watcher" - if libuv.uv_is_closing(self._watcher): - # pylint:disable-next=broad-exception-raised - raise Exception("Closing handle") - libuv.uv_async_send(self._watcher) - - @property - def pending(self): - return None - -locals()['async'] = async_ - -class timer(_base.TimerMixin, watcher): - - _watcher_callback_name = '_gevent_timer_callback0' - - # In libuv, timer callbacks continue running while any timer is - # expired, including newly added timers. Newly added non-zero - # timers (especially of small duration) can be seen to be expired - # if the loop time is updated while we are in a timer callback. - # This can lead to us being stuck running timers for a terribly - # long time, which is not good. So default to not updating the - # time. - - # Also, newly-added timers of 0 duration can *also* stall the - # loop, because they'll be seen to be expired immediately. - # Updating the time can prevent that, *if* there was already a - # timer for a longer duration scheduled. - - # To mitigate the above problems, our loop implementation turns - # zero duration timers into check watchers instead using OneShotCheck. - # This ensures the loop cycles. Of course, the 'again' method does - # nothing on them and doesn't exist. In practice that's not an issue. - - _again = False - - def _watcher_ffi_init(self, args): - self._watcher_init(self.loop.ptr, self._watcher) - self._after, self._repeat = args - if self._after and self._after < 0.001: - import warnings - # XXX: The stack level is hard to determine, could be getting here - # through a number of different ways. - warnings.warn("libuv only supports millisecond timer resolution; " - "all times less will be set to 1 ms", - stacklevel=6) - # The alternative is to effectively pass in int(0.1) == 0, which - # means no sleep at all, which leads to excessive wakeups - self._after = 0.001 - if self._repeat and self._repeat < 0.001: - import warnings - warnings.warn("libuv only supports millisecond timer resolution; " - "all times less will be set to 1 ms", - stacklevel=6) - self._repeat = 0.001 - - def _watcher_ffi_start(self): - if self._again: - libuv.uv_timer_again(self._watcher) - else: - try: - self._watcher_start(self._watcher, self._watcher_callback, - int(self._after * 1000), - int(self._repeat * 1000)) - except ValueError: - # in case of non-ints in _after/_repeat - raise TypeError() - - def again(self, callback, *args, **kw): - if not self.active: - # If we've never been started, this is the same as starting us. - # libuv makes the distinction, libev doesn't. - self.start(callback, *args, **kw) - return - - self._again = True - try: - self.start(callback, *args, **kw) - finally: - del self._again - - -class stat(_base.StatMixin, watcher): - _watcher_type = 'fs_poll' - _watcher_struct_name = 'gevent_fs_poll_t' - _watcher_callback_name = '_gevent_fs_poll_callback3' - - def _watcher_set_data(self, the_watcher, data): - the_watcher.handle.data = data - return data - - def _watcher_ffi_init(self, args): - return self._watcher_init(self.loop.ptr, self._watcher) - - MIN_STAT_INTERVAL = 0.1074891 # match libev; 0.0 is default - - def _watcher_ffi_start(self): - # libev changes this when the watcher is started - self._interval = max(self._interval, self.MIN_STAT_INTERVAL) - self._watcher_start(self._watcher, self._watcher_callback, - self._cpath, - int(self._interval * 1000)) - - @property - def _watcher_handle(self): - return self._watcher.handle.data - - @property - def attr(self): - if not self._watcher.curr.st_nlink: - return - return self._watcher.curr - - @property - def prev(self): - if not self._watcher.prev.st_nlink: - return - return self._watcher.prev - - -class signal(_base.SignalMixin, watcher): - _watcher_callback_name = '_gevent_signal_callback1' - - def _watcher_ffi_init(self, args): - self._watcher_init(self.loop.ptr, self._watcher) - self.ref = False # libev doesn't ref these by default - - - def _watcher_ffi_start(self): - self._watcher_start(self._watcher, self._watcher_callback, - self._signalnum) - - -class idle(_base.IdleMixin, watcher): - # Because libuv doesn't support priorities, idle watchers are - # potentially quite a bit different than under libev - _watcher_callback_name = '_gevent_idle_callback0' - - -class check(_base.CheckMixin, watcher): - _watcher_callback_name = '_gevent_check_callback0' - -class OneShotCheck(check): - - _watcher_skip_ffi = True - - def __make_cb(self, func): - stop = self.stop - @functools.wraps(func) - def cb(*args): - stop() - return func(*args) - return cb - - def start(self, callback, *args): - return check.start(self, self.__make_cb(callback), *args) - -class prepare(_base.PrepareMixin, watcher): - _watcher_callback_name = '_gevent_prepare_callback0' diff --git a/venv/lib/python3.9/site-packages/gevent/local.py b/venv/lib/python3.9/site-packages/gevent/local.py deleted file mode 100644 index cbb0be0..0000000 --- a/venv/lib/python3.9/site-packages/gevent/local.py +++ /dev/null @@ -1,610 +0,0 @@ -# cython: auto_pickle=False,embedsignature=True,always_allow_keywords=False -""" -Greenlet-local objects. - -This module is based on `_threading_local.py`__ from the standard -library of Python 3.4. - -__ https://github.com/python/cpython/blob/3.4/Lib/_threading_local.py - -Greenlet-local objects support the management of greenlet-local data. -If you have data that you want to be local to a greenlet, simply create -a greenlet-local object and use its attributes: - - >>> import gevent - >>> from gevent.local import local - >>> mydata = local() - >>> mydata.number = 42 - >>> mydata.number - 42 - -You can also access the local-object's dictionary: - - >>> mydata.__dict__ - {'number': 42} - >>> mydata.__dict__.setdefault('widgets', []) - [] - >>> mydata.widgets - [] - -What's important about greenlet-local objects is that their data are -local to a greenlet. If we access the data in a different greenlet: - - >>> log = [] - >>> def f(): - ... items = list(mydata.__dict__.items()) - ... items.sort() - ... log.append(items) - ... mydata.number = 11 - ... log.append(mydata.number) - >>> greenlet = gevent.spawn(f) - >>> greenlet.join() - >>> log - [[], 11] - -we get different data. Furthermore, changes made in the other greenlet -don't affect data seen in this greenlet: - - >>> mydata.number - 42 - -Of course, values you get from a local object, including a __dict__ -attribute, are for whatever greenlet was current at the time the -attribute was read. For that reason, you generally don't want to save -these values across greenlets, as they apply only to the greenlet they -came from. - -You can create custom local objects by subclassing the local class: - - >>> class MyLocal(local): - ... number = 2 - ... initialized = False - ... def __init__(self, **kw): - ... if self.initialized: - ... raise SystemError('__init__ called too many times') - ... self.initialized = True - ... self.__dict__.update(kw) - ... def squared(self): - ... return self.number ** 2 - -This can be useful to support default values, methods and -initialization. Note that if you define an __init__ method, it will be -called each time the local object is used in a separate greenlet. This -is necessary to initialize each greenlet's dictionary. - -Now if we create a local object: - - >>> mydata = MyLocal(color='red') - -Now we have a default number: - - >>> mydata.number - 2 - -an initial color: - - >>> mydata.color - 'red' - >>> del mydata.color - -And a method that operates on the data: - - >>> mydata.squared() - 4 - -As before, we can access the data in a separate greenlet: - - >>> log = [] - >>> greenlet = gevent.spawn(f) - >>> greenlet.join() - >>> log - [[('color', 'red'), ('initialized', True)], 11] - -without affecting this greenlet's data: - - >>> mydata.number - 2 - >>> mydata.color - Traceback (most recent call last): - ... - AttributeError: 'MyLocal' object has no attribute 'color' - -Note that subclasses can define slots, but they are not greenlet -local. They are shared across greenlets:: - - >>> class MyLocal(local): - ... __slots__ = 'number' - - >>> mydata = MyLocal() - >>> mydata.number = 42 - >>> mydata.color = 'red' - -So, the separate greenlet: - - >>> greenlet = gevent.spawn(f) - >>> greenlet.join() - -affects what we see: - - >>> mydata.number - 11 - ->>> del mydata - -.. versionchanged:: 1.1a2 - Update the implementation to match Python 3.4 instead of Python 2.5. - This results in locals being eligible for garbage collection as soon - as their greenlet exits. - -.. versionchanged:: 1.2.3 - Use a weak-reference to clear the greenlet link we establish in case - the local object dies before the greenlet does. - -.. versionchanged:: 1.3a1 - Implement the methods for attribute access directly, handling - descriptors directly here. This allows removing the use of a lock - and facilitates greatly improved performance. - -.. versionchanged:: 1.3a1 - The ``__init__`` method of subclasses of ``local`` is no longer - called with a lock held. CPython does not use such a lock in its - native implementation. This could potentially show as a difference - if code that uses multiple dependent attributes in ``__slots__`` - (which are shared across all greenlets) switches during ``__init__``. - -""" -from __future__ import print_function - -from copy import copy -from weakref import ref - - -locals()['getcurrent'] = __import__('greenlet').getcurrent -locals()['greenlet_init'] = lambda: None - -__all__ = [ - "local", -] - -# The key used in the Thread objects' attribute dicts. -# We keep it a string for speed but make it unlikely to clash with -# a "real" attribute. -key_prefix = '_gevent_local_localimpl_' - -# The overall structure is as follows: -# For each local() object: -# greenlet.__dict__[key_prefix + str(id(local))] -# => _localimpl.dicts[id(greenlet)] => (ref(greenlet), {}) - -# That final tuple is actually a localimpl_dict_entry object. - -def all_local_dicts_for_greenlet(greenlet): - """ - Internal debug helper for getting the local values associated - with a greenlet. This is subject to change or removal at any time. - - :return: A list of ((type, id), {}) pairs, where the first element - is the type and id of the local object and the second object is its - instance dictionary, as seen from this greenlet. - - .. versionadded:: 1.3a2 - """ - - result = [] - id_greenlet = id(greenlet) - greenlet_dict = greenlet.__dict__ - for k, v in greenlet_dict.items(): - if not k.startswith(key_prefix): - continue - local_impl = v() - if local_impl is None: - continue - entry = local_impl.dicts.get(id_greenlet) - if entry is None: - # Not yet used in this greenlet. - continue - assert entry.wrgreenlet() is greenlet - result.append((local_impl.localtypeid, entry.localdict)) - - return result - - -class _wrefdict(dict): - """A dict that can be weak referenced""" - -class _greenlet_deleted(object): - """ - A weakref callback for when the greenlet - is deleted. - - If the greenlet is a `gevent.greenlet.Greenlet` and - supplies ``rawlink``, that will be used instead of a - weakref. - """ - __slots__ = ('idt', 'wrdicts') - - def __init__(self, idt, wrdicts): - self.idt = idt - self.wrdicts = wrdicts - - def __call__(self, _unused): - dicts = self.wrdicts() - if dicts: - dicts.pop(self.idt, None) - -class _local_deleted(object): - __slots__ = ('key', 'wrthread', 'greenlet_deleted') - - def __init__(self, key, wrthread, greenlet_deleted): - self.key = key - self.wrthread = wrthread - self.greenlet_deleted = greenlet_deleted - - def __call__(self, _unused): - thread = self.wrthread() - if thread is not None: - try: - unlink = thread.unlink - except AttributeError: - pass - else: - unlink(self.greenlet_deleted) - del thread.__dict__[self.key] - -class _localimpl(object): - """A class managing thread-local dicts""" - __slots__ = ('key', 'dicts', - 'localargs', 'localkwargs', - 'localtypeid', - '__weakref__',) - - def __init__(self, args, kwargs, local_type, id_local): - self.key = key_prefix + str(id(self)) - # { id(greenlet) -> _localimpl_dict_entry(ref(greenlet), greenlet-local dict) } - self.dicts = _wrefdict() - self.localargs = args - self.localkwargs = kwargs - self.localtypeid = local_type, id_local - - # We need to create the thread dict in anticipation of - # __init__ being called, to make sure we don't call it - # again ourselves. MUST do this before setting any attributes. - greenlet = getcurrent() # pylint:disable=undefined-variable - _localimpl_create_dict(self, greenlet, id(greenlet)) - -class _localimpl_dict_entry(object): - """ - The object that goes in the ``dicts`` of ``_localimpl`` - object for each thread. - """ - # This is a class, not just a tuple, so that cython can optimize - # attribute access - __slots__ = ('wrgreenlet', 'localdict') - - def __init__(self, wrgreenlet, localdict): - self.wrgreenlet = wrgreenlet - self.localdict = localdict - -# We use functions instead of methods so that they can be cdef'd in -# local.pxd; if they were cdef'd as methods, they would cause -# the creation of a pointer and a vtable. This happens -# even if we declare the class @cython.final. functions thus save memory overhead -# (but not pointer chasing overhead; the vtable isn't used when we declare -# the class final). - - -def _localimpl_create_dict(self, greenlet, id_greenlet): - """Create a new dict for the current thread, and return it.""" - localdict = {} - key = self.key - - wrdicts = ref(self.dicts) - - # When the greenlet is deleted, remove the local dict. - # Note that this is suboptimal if the greenlet object gets - # caught in a reference loop. We would like to be called - # as soon as the OS-level greenlet ends instead. - - # If we are working with a gevent.greenlet.Greenlet, we - # can pro-actively clear out with a link, avoiding the - # issue described above. Use rawlink to avoid spawning any - # more greenlets. - greenlet_deleted = _greenlet_deleted(id_greenlet, wrdicts) - - rawlink = getattr(greenlet, 'rawlink', None) - if rawlink is not None: - rawlink(greenlet_deleted) - wrthread = ref(greenlet) - else: - wrthread = ref(greenlet, greenlet_deleted) - - - # When the localimpl is deleted, remove the thread attribute. - local_deleted = _local_deleted(key, wrthread, greenlet_deleted) - - - wrlocal = ref(self, local_deleted) - greenlet.__dict__[key] = wrlocal - - self.dicts[id_greenlet] = _localimpl_dict_entry(wrthread, localdict) - return localdict - - -_marker = object() - -def _local_get_dict(self): - impl = self._local__impl - # Cython can optimize dict[], but not dict.get() - greenlet = getcurrent() # pylint:disable=undefined-variable - idg = id(greenlet) - try: - entry = impl.dicts[idg] - dct = entry.localdict - except KeyError: - dct = _localimpl_create_dict(impl, greenlet, idg) - self.__init__(*impl.localargs, **impl.localkwargs) - return dct - -def _init(): - greenlet_init() # pylint:disable=undefined-variable - -_local_attrs = { - '_local__impl', - '_local_type_get_descriptors', - '_local_type_set_or_del_descriptors', - '_local_type_del_descriptors', - '_local_type_set_descriptors', - '_local_type', - '_local_type_vars', - '__class__', - '__cinit__', -} - -class local(object): - """ - An object whose attributes are greenlet-local. - """ - __slots__ = tuple(_local_attrs - {'__class__', '__cinit__'}) - - def __cinit__(self, *args, **kw): # pylint:disable=bad-dunder-name - if args or kw: - if type(self).__init__ == object.__init__: # pylint:disable=comparison-with-callable - raise TypeError("Initialization arguments are not supported", args, kw) - impl = _localimpl(args, kw, type(self), id(self)) - # pylint:disable=attribute-defined-outside-init - self._local__impl = impl - get, dels, sets_or_dels, sets = _local_find_descriptors(self) - self._local_type_get_descriptors = get - self._local_type_set_or_del_descriptors = sets_or_dels - self._local_type_del_descriptors = dels - self._local_type_set_descriptors = sets - self._local_type = type(self) - self._local_type_vars = set(dir(self._local_type)) - - def __getattribute__(self, name): # pylint:disable=too-many-return-statements - if name in _local_attrs: - # The _local__impl, __cinit__, etc, won't be hit by the - # Cython version, if we've done things right. If we haven't, - # they will be, and this will produce an error. - return object.__getattribute__(self, name) - - dct = _local_get_dict(self) - - if name == '__dict__': - return dct - # If there's no possible way we can switch, because this - # attribute is *not* found in the class where it might be a - # data descriptor (property), and it *is* in the dict - # then we don't need to swizzle the dict and take the lock. - - # We don't have to worry about people overriding __getattribute__ - # because if they did, the dict-swizzling would only last as - # long as we were in here anyway. - # Similarly, a __getattr__ will still be called by _oga() if needed - # if it's not in the dict. - - # Optimization: If we're not subclassed, then - # there can be no descriptors except for methods, which will - # never need to use __dict__. - if self._local_type is local: - return dct[name] if name in dct else object.__getattribute__(self, name) - - # NOTE: If this is a descriptor, this will invoke its __get__. - # A broken descriptor that doesn't return itself when called with - # a None for the instance argument could mess us up here. - # But this is faster than a loop over mro() checking each class __dict__ - # manually. - if name in dct: - if name not in self._local_type_vars: - # If there is a dict value, and nothing in the type, - # it can't possibly be a descriptor, so it is just returned. - return dct[name] - - # It's in the type *and* in the dict. If the type value is - # a data descriptor (defines __get__ *and* either __set__ or - # __delete__), then the type wins. If it's a non-data descriptor - # (defines just __get__), then the instance wins. If it's not a - # descriptor at all (doesn't have __get__), the instance wins. - # NOTE that the docs for descriptors say that these methods must be - # defined on the *class* of the object in the type. - if name not in self._local_type_get_descriptors: - # Entirely not a descriptor. Instance wins. - return dct[name] - if name in self._local_type_set_or_del_descriptors: - # A data descriptor. - # arbitrary code execution while these run. If they touch self again, - # they'll call back into us and we'll repeat the dance. - type_attr = getattr(self._local_type, name) - return type(type_attr).__get__(type_attr, self, self._local_type) - # Last case is a non-data descriptor. Instance wins. - return dct[name] - - if name in self._local_type_vars: - # Not in the dictionary, but is found in the type. It could be - # a non-data descriptor still. Some descriptors, like @staticmethod, - # return objects (functions, in this case), that are *themselves* - # descriptors, which when invoked, again, would do the wrong thing. - # So we can't rely on getattr() on the type for them, we have to - # look through the MRO dicts ourself. - if name not in self._local_type_get_descriptors: - # Not a descriptor, can't execute code. So all we need is - # the return value of getattr() on our type. - return getattr(self._local_type, name) - - for base in self._local_type.mro(): - bd = base.__dict__ - if name in bd: - attr_on_type = bd[name] - result = type(attr_on_type).__get__(attr_on_type, self, self._local_type) - return result - - # It wasn't in the dict and it wasn't in the type. - # So the next step is to invoke type(self)__getattr__, if it - # exists, otherwise raise an AttributeError. - # we will invoke type(self).__getattr__ or raise an attribute error. - if hasattr(self._local_type, '__getattr__'): - return self._local_type.__getattr__(self, name) - raise AttributeError("%r object has no attribute '%s'" - % (self._local_type.__name__, name)) - - def __setattr__(self, name, value): - if name == '__dict__': - raise AttributeError( - "%r object attribute '__dict__' is read-only" - % type(self)) - - if name in _local_attrs: - object.__setattr__(self, name, value) - return - - dct = _local_get_dict(self) - - if self._local_type is local: - # Optimization: If we're not subclassed, we can't - # have data descriptors, so this goes right in the dict. - dct[name] = value - return - - if name in self._local_type_vars: - if name in self._local_type_set_descriptors: - type_attr = getattr(self._local_type, name, _marker) - # A data descriptor, like a property or a slot. - type(type_attr).__set__(type_attr, self, value) - return - # Otherwise it goes directly in the dict - dct[name] = value - - def __delattr__(self, name): - if name == '__dict__': - raise AttributeError( - "%r object attribute '__dict__' is read-only" - % self.__class__.__name__) - - if name in self._local_type_vars: - if name in self._local_type_del_descriptors: - # A data descriptor, like a property or a slot. - type_attr = getattr(self._local_type, name, _marker) - type(type_attr).__delete__(type_attr, self) - return - # Otherwise it goes directly in the dict - - # Begin inlined function _get_dict() - dct = _local_get_dict(self) - - try: - del dct[name] - except KeyError: - raise AttributeError(name) - - def __copy__(self): - impl = self._local__impl - entry = impl.dicts[id(getcurrent())] # pylint:disable=undefined-variable - - dct = entry.localdict - duplicate = copy(dct) - - cls = type(self) - instance = cls(*impl.localargs, **impl.localkwargs) - _local__copy_dict_from(instance, impl, duplicate) - return instance - -def _local__copy_dict_from(self, impl, duplicate): - current = getcurrent() # pylint:disable=undefined-variable - currentId = id(current) - new_impl = self._local__impl - assert new_impl is not impl - entry = new_impl.dicts[currentId] - new_impl.dicts[currentId] = _localimpl_dict_entry(entry.wrgreenlet, duplicate) - -def _local_find_descriptors(self): - type_self = type(self) - gets = set() - dels = set() - set_or_del = set() - sets = set() - mro = list(type_self.mro()) - - for attr_name in dir(type_self): - # Conventionally, descriptors when called on a class - # return themself, but not all do. Notable exceptions are - # in the zope.interface package, where things like __provides__ - # return other class attributes. So we can't use getattr, and instead - # walk up the dicts - for base in mro: - bd = base.__dict__ - if attr_name in bd: - attr = bd[attr_name] - break - else: - raise AttributeError(attr_name) - - type_attr = type(attr) - if hasattr(type_attr, '__get__'): - gets.add(attr_name) - if hasattr(type_attr, '__delete__'): - dels.add(attr_name) - set_or_del.add(attr_name) - if hasattr(type_attr, '__set__'): - sets.add(attr_name) - - return (gets, dels, set_or_del, sets) - -# Cython doesn't let us use __new__, it requires -# __cinit__. But we need __new__ if we're not compiled -# (e.g., on PyPy). So we set it at runtime. Cython -# will raise an error if we're compiled. -def __new__(cls, *args, **kw): - self = super(local, cls).__new__(cls) # pylint:disable=no-value-for-parameter - # We get the cls in *args for some reason - # too when we do it this way....except on PyPy3, which does - # not *unless* it's wrapped in a classmethod (which it is) - self.__cinit__(*args[1:], **kw) - return self - -if local.__module__ == 'gevent.local': - # PyPy2/3 and CPython handle adding a __new__ to the class - # in different ways. In CPython and PyPy3, it must be wrapped with classmethod; - # in PyPy2 < 7.3.3, it must not. In either case, the args that get passed to - # it are stil wrong. - # - # Prior to Python 3.10, Cython-compiled classes were immutable and - # raised a TypeError on assignment to __new__, and we relied on that - # to detect the compiled version; but that breaks in - # 3.10 as classes are now mutable. (See - # https://github.com/cython/cython/issues/4326). - # - # That's OK; post https://github.com/gevent/gevent/issues/1480, the Cython-compiled - # module has a different name than the pure-Python version and we can check for that. - # It's not as direct, but it works. - # So here we're not compiled - local.__new__ = classmethod(__new__) -else: # pragma: no cover - # Make sure we revisit in case of changes to the (accelerator) module names. - if local.__module__ != 'gevent._gevent_clocal': # pylint:disable=else-if-used - raise AssertionError("Module names changed (local: %r; __name__: %r); revisit this code" % ( - local.__module__, __name__) ) - -_init() - -from gevent._util import import_c_accel -import_c_accel(globals(), 'gevent._local') diff --git a/venv/lib/python3.9/site-packages/gevent/lock.py b/venv/lib/python3.9/site-packages/gevent/lock.py deleted file mode 100644 index dcded38..0000000 --- a/venv/lib/python3.9/site-packages/gevent/lock.py +++ /dev/null @@ -1,380 +0,0 @@ -# Copyright (c) 2009-2012 Denis Bilenko. See LICENSE for details. -""" -Locking primitives. - -These include semaphores with arbitrary bounds (:class:`Semaphore` and -its safer subclass :class:`BoundedSemaphore`) and a semaphore with -infinite bounds (:class:`DummySemaphore`), along with a reentrant lock -(:class:`RLock`) with the same API as :class:`threading.RLock`. -""" -from __future__ import absolute_import -from __future__ import print_function - -from gevent.hub import getcurrent -from gevent._compat import PURE_PYTHON - -# This is the one exception to the rule of where to -# import Semaphore, obviously -from gevent import monkey -from gevent._semaphore import Semaphore -from gevent._semaphore import BoundedSemaphore - - -__all__ = [ - 'Semaphore', - 'BoundedSemaphore', - 'DummySemaphore', - 'RLock', -] - -# On PyPy, we don't compile the Semaphore class with Cython. Under -# Cython, each individual method holds the GIL for its entire -# duration, ensuring that no other thread can interrupt us in an -# unsafe state (only when we _wait do we call back into Python and -# allow switching threads; this is broken down into the -# _drop_lock_for_switch_out and _acquire_lock_for_switch_in methods). -# Simulate that here through the use of a manual lock. (We use a -# separate lock for each semaphore to allow sys.settrace functions to -# use locks *other* than the one being traced.) This, of course, must -# also hold for PURE_PYTHON mode when no optional C extensions are -# used. - -_allocate_lock, _get_ident = monkey.get_original( - ('_thread', 'thread'), - ('allocate_lock', 'get_ident') -) - -def atomic(meth): - def m(self, *args): - with self._atomic: - return meth(self, *args) - return m - - -class _GILLock(object): - __slots__ = ( - '_owned_thread_id', - '_gil', - '_atomic', - '_recursion_depth', - ) - # Don't allow re-entry to these functions in a single thread, as - # can happen if a sys.settrace is used. (XXX: What does that even - # mean? Our original implementation that did that has been - # replaced by something more robust) - # - # This is essentially a variant of the (pure-Python) RLock from the - # standard library. - def __init__(self): - self._owned_thread_id = None - self._gil = _allocate_lock() - self._atomic = _allocate_lock() - self._recursion_depth = 0 - - @atomic - def acquire(self): - current_tid = _get_ident() - if self._owned_thread_id == current_tid: - self._recursion_depth += 1 - return True - - # Not owned by this thread. Only one thread will make it through this point. - while 1: - self._atomic.release() - try: - self._gil.acquire() - finally: - self._atomic.acquire() - if self._owned_thread_id is None: - break - - self._owned_thread_id = current_tid - self._recursion_depth = 1 - return True - - @atomic - def release(self): - current_tid = _get_ident() - if current_tid != self._owned_thread_id: - raise RuntimeError("%s: Releasing lock not owned by you. You: 0x%x; Owner: 0x%x" % ( - self, - current_tid, self._owned_thread_id or 0, - )) - - self._recursion_depth -= 1 - - if not self._recursion_depth: - self._owned_thread_id = None - self._gil.release() - - def __enter__(self): - self.acquire() - - def __exit__(self, t, v, tb): - self.release() - - def locked(self): - return self._gil.locked() - -class _AtomicSemaphoreMixin(object): - # Behaves as though the GIL was held for the duration of acquire, wait, - # and release, just as if we were in Cython. - # - # acquire, wait, and release all acquire the lock on entry and release it - # on exit. acquire and wait can call _wait, which must release it on entry - # and re-acquire it for them on exit. - # - # Note that this does *NOT*, in-and-of itself, make semaphores safe to use from multiple threads - __slots__ = () - def __init__(self, *args, **kwargs): - self._lock_lock = _GILLock() # pylint:disable=assigning-non-slot - super(_AtomicSemaphoreMixin, self).__init__(*args, **kwargs) - - def _acquire_lock_for_switch_in(self): - self._lock_lock.acquire() - - def _drop_lock_for_switch_out(self): - self._lock_lock.release() - - def _notify_links(self, arrived_while_waiting): - with self._lock_lock: - return super(_AtomicSemaphoreMixin, self)._notify_links(arrived_while_waiting) - - def release(self): - with self._lock_lock: - return super(_AtomicSemaphoreMixin, self).release() - - def acquire(self, blocking=True, timeout=None): - with self._lock_lock: - return super(_AtomicSemaphoreMixin, self).acquire(blocking, timeout) - - _py3k_acquire = acquire - - def wait(self, timeout=None): - with self._lock_lock: - return super(_AtomicSemaphoreMixin, self).wait(timeout) - -class _AtomicSemaphore(_AtomicSemaphoreMixin, Semaphore): - __doc__ = Semaphore.__doc__ - __slots__ = ( - '_lock_lock', - ) - - -class _AtomicBoundedSemaphore(_AtomicSemaphoreMixin, BoundedSemaphore): - __doc__ = BoundedSemaphore.__doc__ - __slots__ = ( - '_lock_lock', - ) - - def release(self): # pylint:disable=useless-super-delegation - # This method is duplicated here so that it can get - # properly documented. - return super(_AtomicBoundedSemaphore, self).release() - - -def _fixup_docstrings(): - for c in _AtomicSemaphore, _AtomicBoundedSemaphore: - b = c.__mro__[2] - assert b.__name__.endswith('Semaphore') and 'Atomic' not in b.__name__ - assert c.__doc__ == b.__doc__ - for m in 'acquire', 'release', 'wait': - c_meth = getattr(c, m) - b_meth = getattr(b, m) - c_meth.__doc__ = b_meth.__doc__ - -_fixup_docstrings() -del _fixup_docstrings - - -if PURE_PYTHON: - Semaphore = _AtomicSemaphore - Semaphore.__name__ = 'Semaphore' - BoundedSemaphore = _AtomicBoundedSemaphore - BoundedSemaphore.__name__ = 'BoundedSemaphore' - - -class DummySemaphore(object): - """ - DummySemaphore(value=None) -> DummySemaphore - - An object with the same API as :class:`Semaphore`, - initialized with "infinite" initial value. None of its - methods ever block. - - This can be used to parameterize on whether or not to actually - guard access to a potentially limited resource. If the resource is - actually limited, such as a fixed-size thread pool, use a real - :class:`Semaphore`, but if the resource is unbounded, use an - instance of this class. In that way none of the supporting code - needs to change. - - Similarly, it can be used to parameterize on whether or not to - enforce mutual exclusion to some underlying object. If the - underlying object is known to be thread-safe itself mutual - exclusion is not needed and a ``DummySemaphore`` can be used, but - if that's not true, use a real ``Semaphore``. - """ - - # Internally this is used for exactly the purpose described in the - # documentation. gevent.pool.Pool uses it instead of a Semaphore - # when the pool size is unlimited, and - # gevent.fileobject.FileObjectThread takes a parameter that - # determines whether it should lock around IO to the underlying - # file object. - - def __init__(self, value=None): - """ - .. versionchanged:: 1.1rc3 - Accept and ignore a *value* argument for compatibility with Semaphore. - """ - - def __str__(self): - return '<%s>' % self.__class__.__name__ - - def locked(self): - """A DummySemaphore is never locked so this always returns False.""" - return False - - def ready(self): - """A DummySemaphore is never locked so this always returns True.""" - return True - - def release(self): - """Releasing a dummy semaphore does nothing.""" - - def rawlink(self, callback): - # XXX should still work and notify? - pass - - def unlink(self, callback): - pass - - def wait(self, timeout=None): # pylint:disable=unused-argument - """Waiting for a DummySemaphore returns immediately.""" - return 1 - - def acquire(self, blocking=True, timeout=None): - """ - A DummySemaphore can always be acquired immediately so this always - returns True and ignores its arguments. - - .. versionchanged:: 1.1a1 - Always return *true*. - """ - # pylint:disable=unused-argument - return True - - def __enter__(self): - pass - - def __exit__(self, typ, val, tb): - pass - - -class RLock(object): - """ - A mutex that can be acquired more than once by the same greenlet. - - A mutex can only be locked by one greenlet at a time. A single greenlet - can `acquire` the mutex as many times as desired, though. Each call to - `acquire` must be paired with a matching call to `release`. - - It is an error for a greenlet that has not acquired the mutex - to release it. - - Instances are context managers. - """ - - __slots__ = ( - '_block', - '_owner', - '_count', - '__weakref__', - ) - - def __init__(self, hub=None): - """ - .. versionchanged:: 20.5.1 - Add the ``hub`` argument. - """ - self._block = Semaphore(1, hub) - self._owner = None - self._count = 0 - - def __repr__(self): - return "<%s at 0x%x _block=%s _count=%r _owner=%r)>" % ( - self.__class__.__name__, - id(self), - self._block, - self._count, - self._owner) - - def acquire(self, blocking=True, timeout=None): - """ - Acquire the mutex, blocking if *blocking* is true, for up to - *timeout* seconds. - - .. versionchanged:: 1.5a4 - Added the *timeout* parameter. - - :return: A boolean indicating whether the mutex was acquired. - """ - me = getcurrent() - if self._owner is me: - self._count += 1 - return 1 - rc = self._block.acquire(blocking, timeout) - if rc: - self._owner = me - self._count = 1 - return rc - - def __enter__(self): - return self.acquire() - - def release(self): - """ - Release the mutex. - - Only the greenlet that originally acquired the mutex can - release it. - """ - if self._owner is not getcurrent(): - raise RuntimeError("cannot release un-acquired lock. Owner: %r Current: %r" % ( - self._owner, getcurrent() - )) - self._count = count = self._count - 1 # pylint:disable=consider-using-augmented-assign - if not count: - self._owner = None - self._block.release() - - def __exit__(self, typ, value, tb): - self.release() - - def locked(self): - """ - Return a boolean indicating whether this object is locked right now. - - .. versionadded:: 25.4.1 - """ - return self._count > 0 - - # Internal methods used by condition variables - - def _acquire_restore(self, count_owner): - count, owner = count_owner - self._block.acquire() - self._count = count - self._owner = owner - - def _release_save(self): - count = self._count - self._count = 0 - owner = self._owner - self._owner = None - self._block.release() - return (count, owner) - - def _is_owned(self): - return self._owner is getcurrent() diff --git a/venv/lib/python3.9/site-packages/gevent/monkey/__init__.py b/venv/lib/python3.9/site-packages/gevent/monkey/__init__.py deleted file mode 100644 index fef6b50..0000000 --- a/venv/lib/python3.9/site-packages/gevent/monkey/__init__.py +++ /dev/null @@ -1,745 +0,0 @@ -# Copyright (c) 2009-2012 Denis Bilenko. See LICENSE for details. -# pylint: disable=redefined-outer-name,too-many-lines -""" -Make the standard library cooperative. - -The primary purpose of this module is to carefully patch, in place, -portions of the standard library with gevent-friendly functions that -behave in the same way as the original (at least as closely as possible). - -The primary interface to this is the :func:`patch_all` function, which -performs all the available patches. It accepts arguments to limit the -patching to certain modules, but most programs **should** use the -default values as they receive the most wide-spread testing, and some monkey -patches have dependencies on others. - -Patching **should be done as early as possible** in the lifecycle of the -program. For example, the main module (the one that tests against -``__main__`` or is otherwise the first imported) should begin with -this code, ideally before any other imports:: - - from gevent import monkey - monkey.patch_all() - -A corollary of the above is that patching **should be done on the main -thread** and **should be done while the program is single-threaded**. - -.. tip:: - - Some frameworks, such as gunicorn, handle monkey-patching for you. - Check their documentation to be sure. - -.. warning:: - - Patching too late can lead to unreliable behaviour (for example, some - modules may still use blocking sockets) or even errors. - -.. tip:: - - Be sure to read the documentation for each patch function to check for - known incompatibilities. - -Querying -======== - -Sometimes it is helpful to know if objects have been monkey-patched, and in -advanced cases even to have access to the original standard library functions. This -module provides functions for that purpose. - -- :func:`is_module_patched` -- :func:`is_object_patched` -- :func:`get_original` - -.. _plugins: - -Plugins and Events -================== - -Beginning in gevent 1.3, events are emitted during the monkey patching process. -These events are delivered first to :mod:`gevent.events` subscribers, and then -to `setuptools entry points`_. - -The following events are defined. They are listed in (roughly) the order -that a call to :func:`patch_all` will emit them. - -- :class:`gevent.events.GeventWillPatchAllEvent` -- :class:`gevent.events.GeventWillPatchModuleEvent` -- :class:`gevent.events.GeventDidPatchModuleEvent` -- :class:`gevent.events.GeventDidPatchBuiltinModulesEvent` -- :class:`gevent.events.GeventDidPatchAllEvent` - -Each event class documents the corresponding setuptools entry point name. The -entry points will be called with a single argument, the same instance of -the class that was sent to the subscribers. - -You can subscribe to the events to monitor the monkey-patching process and -to manipulate it, for example by raising :exc:`gevent.events.DoNotPatch`. - -You can also subscribe to the events to provide additional patching beyond what -gevent distributes, either for additional standard library modules, or -for third-party packages. The suggested time to do this patching is in -the subscriber for :class:`gevent.events.GeventDidPatchBuiltinModulesEvent`. -For example, to automatically patch `psycopg2`_ using `psycogreen`_ -when the call to :func:`patch_all` is made, you could write code like this:: - - # mypackage.py - def patch_psycopg(event): - from psycogreen.gevent import patch_psycopg - patch_psycopg() - -In your ``setup.py`` you would register it like this:: - - from setuptools import setup - setup( - ... - entry_points={ - 'gevent.plugins.monkey.did_patch_builtins': [ - 'psycopg2 = mypackage:patch_psycopg', - ], - }, - ... - ) - -For more complex patching, gevent provides a helper method -that you can call to replace attributes of modules with attributes of your -own modules. This function also takes care of emitting the appropriate events. - -- :func:`patch_module` - -.. _setuptools entry points: http://setuptools.readthedocs.io/en/latest/setuptools.html#dynamic-discovery-of-services-and-plugins -.. _psycopg2: https://pypi.python.org/pypi/psycopg2 -.. _psycogreen: https://pypi.python.org/pypi/psycogreen - -Use as a module -=============== - -Sometimes it is useful to run existing python scripts or modules that -were not built to be gevent aware under gevent. To do so, this module -can be run as the main module, passing the script and its arguments. -For details, see the :func:`main` function. - -.. versionchanged:: 1.3b1 - Added support for plugins and began emitting will/did patch events. -""" - -import sys - -#### -# gevent developers: IMPORTANT: Keep imports -# as limited and localized as possible to avoid -# interfering with the monkey-patch process. -# This is why many imports are nested inside functions. -# -# This applies for this entire package. -### - -__all__ = [ - 'patch_all', - 'patch_builtins', - 'patch_dns', - 'patch_os', - 'patch_queue', - 'patch_select', - 'patch_signal', - 'patch_socket', - 'patch_ssl', - 'patch_subprocess', - 'patch_sys', - 'patch_thread', - 'patch_time', - # query functions - 'get_original', - 'is_module_patched', - 'is_object_patched', - - # 'is_anything_patched', <- see docstring - - # plugin API - 'patch_module', - # module functions - 'main', - # Errors and warnings - 'MonkeyPatchWarning', -] - -WIN = sys.platform.startswith("win") -PY314 = sys.version_info[:2] >= (3, 14) - -# Unused imports may be removed in a major release after 2024-10. -# Used private imports may be renamed or removed or changed -# in an incompatible way at that time. - - - -from ._errors import MonkeyPatchWarning - -from ._util import _notify_patch -from ._util import _ignores_DoNotPatch - -from ._state import saved -from ._state import is_module_patched -from ._state import is_object_patched - -# Never documented as a public API, but -# potentially in use by third parties -# given the naming convention. -from ._state import is_anything_patched # pylint:disable=unused-import -from ._errors import _BadImplements # pylint:disable=unused-import - - - -from .api import get_original -from .api import patch_module - - - -# These are not part of the documented public API, -# but they could be used by plugins. TODO: Do we -# want to make them public with __all__? -from .api import patch_item -from .api import remove_item - - - - - - - - -from ._util import _check_availability -from ._util import _patch_module -from ._util import _queue_warning -from ._util import _process_warnings - - - -def _patch_sys_std(name): - from gevent.fileobject import FileObjectThread - orig = getattr(sys, name) - if not isinstance(orig, FileObjectThread): - patch_item(sys, name, FileObjectThread(orig)) - -@_ignores_DoNotPatch -def patch_sys(stdin=True, stdout=True, stderr=True): # pylint:disable=unused-argument - """ - Patch sys.std[in,out,err] to use a cooperative IO via a - threadpool. - - This is relatively dangerous and can have unintended consequences - such as hanging the process or `misinterpreting control keys`_ - when :func:`input` and :func:`raw_input` are used. :func:`patch_all` - does *not* call this function by default. - - This method does nothing on Python 3. The Python 3 interpreter - wants to flush the TextIOWrapper objects that make up - stderr/stdout at shutdown time, but using a threadpool at that - time leads to a hang. - - .. _`misinterpreting control keys`: https://github.com/gevent/gevent/issues/274 - - .. deprecated:: 23.7.0 - Does nothing on any supported version. - """ - return - -@_ignores_DoNotPatch -def patch_os(): - """ - Replace :func:`os.fork` with :func:`gevent.fork`, and, on POSIX, - :func:`os.waitpid` with :func:`gevent.os.waitpid` (if the - environment variable ``GEVENT_NOWAITPID`` is not defined). Does - nothing if fork is not available. - - .. caution:: This method must be used with :func:`patch_signal` to have proper `SIGCHLD` - handling and thus correct results from ``waitpid``. - :func:`patch_all` calls both by default. - - .. caution:: For `SIGCHLD` handling to work correctly, the event loop must run. - The easiest way to help ensure this is to use :func:`patch_all`. - """ - _patch_module('os') - - -@_ignores_DoNotPatch -def patch_queue(): - """ - Patch objects in :mod:`queue`. - - This replaces ``SimpleQueue``, ``PriorityQueue``, ``Queue`` - and ``LifoQueue`` with their gevent equivalents. - - .. versionadded:: 1.3.5 - - .. versionchanged:: 25.4.1 - In addition to ``SimpleQueue``, now also patches - ``Queue``, ``PriorityQueue`` and ``LifoQueue``.` - - Note that only documented attributes are the same between - gevent and the standard library. Internal implementation details - are very different. - """ - from gevent._config import validate_bool - import os - - # IMPORTANT: If you use this, please file an issue! - # This may be removed after October 2025. - DISABLE_QUEUE_PATCH = os.environ.get('GEVENT_MONKEY_DISABLE_QUEUE_QUEUE', 'false') - DISABLE_QUEUE_PATCH = validate_bool(DISABLE_QUEUE_PATCH) - - _patch_module('queue', items=[ - 'SimpleQueue', - 'PriorityQueue', - 'LifoQueue', - ] + (['Queue',] if not DISABLE_QUEUE_PATCH else []) - ) - - -@_ignores_DoNotPatch -def patch_time(): - """ - Replace :func:`time.sleep` with :func:`gevent.sleep`. - """ - _patch_module('time') - -@_ignores_DoNotPatch -def patch_contextvars(): - """ - Replaces the implementations of :mod:`contextvars` with - :mod:`gevent.contextvars`. - - On Python 3.7 and above, this is a standard library module. On - earlier versions, a backport that uses the same distribution name - and import name is available on PyPI (though this is not - recommended). If that is installed, it will be patched. - - .. versionchanged:: 20.04.0 - Clarify that the backport is also patched. - - .. versionchanged:: 20.9.0 - This now does nothing on Python 3.7 and above. - gevent now depends on greenlet 0.4.17, which - natively handles switching context vars when greenlets are switched. - Older versions of Python that have the backport installed will - still be patched. - - .. deprecated:: 23.7.0 - Does nothing on any supported version. - """ - return - - - -@_ignores_DoNotPatch -def patch_thread(threading=True, _threading_local=True, Event=True, logging=True, - existing_locks=True, - _warnings=None): - """ - patch_thread(threading=True, _threading_local=True, Event=True, logging=True, existing_locks=True) -> None - - Replace the standard :mod:`thread` module to make it greenlet-based. - - :keyword bool threading: When True (the default), - also patch :mod:`threading`. - :keyword bool _threading_local: When True (the default), - also patch :class:`_threading_local.local`. - :keyword bool logging: When True (the default), also patch locks - taken if the logging module has been configured. - - :keyword bool existing_locks: When True (the default), and the - process is still single threaded, make sure that any - :class:`threading.RLock` (and, under Python 3, :class:`importlib._bootstrap._ModuleLock`) - instances that are currently locked can be properly unlocked. **Important**: This is a - best-effort attempt and, on certain implementations, may not detect all - locks. It is important to monkey-patch extremely early in the startup process. - Setting this to False is not recommended, especially on Python 2. - - .. caution:: - Monkey-patching :mod:`thread` and using - :class:`multiprocessing.Queue` or - :class:`concurrent.futures.ProcessPoolExecutor` (which uses a - ``Queue``) will hang the process. - - Monkey-patching with this function and using - sub-interpreters (and advanced C-level API) and threads may be - unstable on certain platforms. - - .. versionchanged:: 1.1b1 - Add *logging* and *existing_locks* params. - .. versionchanged:: 1.3a2 - ``Event`` defaults to True. - """ - if sys.version_info[:2] < (3, 13): - from ._patch_thread_lt313 import Patcher - else: - from ._patch_thread_gte313 import Patcher - patch = Patcher(threading=threading, _threading_local=_threading_local, Event=Event, - logging=logging, existing_locks=existing_locks, _warnings=_warnings) - patch() - - -@_ignores_DoNotPatch -def patch_socket(dns=True, aggressive=True): - """ - Replace the standard socket object with gevent's cooperative - sockets. - - :keyword bool dns: When true (the default), also patch address - resolution functions in :mod:`socket`. See :doc:`/dns` for details. - """ - from gevent import socket - # Note: although it seems like it's not strictly necessary to monkey patch 'create_connection', - # it's better to do it. If 'create_connection' was not monkey patched, but the rest of socket module - # was, create_connection would still use "green" getaddrinfo and "green" socket. - # However, because gevent.socket.socket.connect is a Python function, the exception raised by it causes - # _socket object to be referenced by the frame, thus causing the next invocation of bind(source_address) to fail. - if dns: - items = socket.__implements__ # pylint:disable=no-member - else: - items = set(socket.__implements__) - set(socket.__dns__) # pylint:disable=no-member - _patch_module('socket', items=items) - if aggressive: - if 'ssl' not in socket.__implements__: # pylint:disable=no-member - remove_item(socket, 'ssl') - -@_ignores_DoNotPatch -def patch_dns(): - """ - Replace :doc:`DNS functions ` in :mod:`socket` with - cooperative versions. - - This is only useful if :func:`patch_socket` has been called and is - done automatically by that method if requested. - """ - from gevent import socket - _patch_module('socket', items=socket.__dns__) # pylint:disable=no-member - - -def _find_module_refs(to, excluding_names=()): - # Looks specifically for module-level references, - # i.e., 'from foo import Bar'. We define a module reference - # as a dict (subclass) that also has a __name__ attribute. - # This does not handle subclasses, but it does find them. - # Returns two sets. The first is modules (name, file) that were - # found. The second is subclasses that were found. - gc = __import__('gc') - direct_ref_modules = set() - subclass_modules = set() - - def report(mod): - return mod['__name__'], mod.get('__file__', '') - - for r in gc.get_referrers(to): - if isinstance(r, dict) and '__name__' in r: - if r['__name__'] in excluding_names: - continue - - for v in r.values(): - if v is to: - direct_ref_modules.add(report(r)) - elif isinstance(r, type) and to in r.__bases__ and 'gevent.' not in r.__module__: - subclass_modules.add(r) - - return direct_ref_modules, subclass_modules - -@_ignores_DoNotPatch -def patch_ssl(_warnings=None, _first_time=True): - """ - patch_ssl() -> None - - Replace :class:`ssl.SSLSocket` object and socket wrapping functions in - :mod:`ssl` with cooperative versions. - - This is only useful if :func:`patch_socket` has been called. - - It is important to call this function before :mod:`ssl` has been imported. - For more information, see :mod:`gevent.ssl`. - """ - may_need_warning = ( - _first_time - and 'ssl' in sys.modules - and hasattr(sys.modules['ssl'], 'SSLContext')) - # Previously, we didn't warn on Python 2 if pkg_resources has been imported - # because that imports ssl and it's commonly used for namespace packages, - # which typically means we're still in some early part of the import cycle. - # However, with our new more discriminating check, that no longer seems to be a problem. - # Prior to 3.6, we don't have the RecursionError problem, and prior to 3.7 we don't have the - # SSLContext.sslsocket_class/SSLContext.sslobject_class problem. - - gevent_mod, _ = _patch_module('ssl', _warnings=_warnings) - if may_need_warning: - direct_ref_modules, subclass_modules = _find_module_refs( - gevent_mod.orig_SSLContext, - excluding_names=('ssl', 'gevent.ssl', 'gevent._ssl3', 'gevent._sslgte279')) - if direct_ref_modules or subclass_modules: - # Normally you don't want to have dynamic warning strings, because - # the cache in the warning module is based on the string. But we - # specifically only do this the first time we patch ourself, so it's - # ok. - direct_ref_mod_str = subclass_str = '' - if direct_ref_modules: - direct_ref_mod_str = 'Modules that had direct imports (NOT patched): %s. ' % ([ - "%s (%s)" % (name, fname) - for name, fname in direct_ref_modules - ]) - if subclass_modules: - subclass_str = 'Subclasses (NOT patched): %s. ' % ([ - str(t) for t in subclass_modules - ]) - _queue_warning( - 'Monkey-patching ssl after ssl has already been imported ' - 'may lead to errors, including RecursionError on Python 3.6. ' - 'It may also silently lead to incorrect behaviour on Python 3.7. ' - 'Please monkey-patch earlier. ' - 'See https://github.com/gevent/gevent/issues/1016. ' - + direct_ref_mod_str + subclass_str, - _warnings) - - -@_ignores_DoNotPatch -def patch_select(aggressive=True): - """ - Replace :func:`select.select` with :func:`gevent.select.select` - and :func:`select.poll` with :class:`gevent.select.poll` (where available). - - If ``aggressive`` is true (the default), also remove other - blocking functions from :mod:`select` . - - - :func:`select.epoll` - - :func:`select.kqueue` - - :func:`select.kevent` - - :func:`select.devpoll` (Python 3.5+) - """ - _patch_module('select', - _patch_kwargs={'aggressive': aggressive}) - -@_ignores_DoNotPatch -def patch_selectors(aggressive=True): - """ - Replace :class:`selectors.DefaultSelector` with - :class:`gevent.selectors.GeventSelector`. - - If ``aggressive`` is true (the default), also remove other - blocking classes :mod:`selectors`: - - - :class:`selectors.EpollSelector` - - :class:`selectors.KqueueSelector` - - :class:`selectors.DevpollSelector` (Python 3.5+) - - On Python 2, the :mod:`selectors2` module is used instead - of :mod:`selectors` if it is available. If this module cannot - be imported, no patching is done and :mod:`gevent.selectors` is - not available. - - In :func:`patch_all`, the *select* argument controls both this function - and :func:`patch_select`. - - .. versionadded:: 20.6.0 - """ - try: - _check_availability('selectors') - except ImportError: # pragma: no cover - return - - _patch_module('selectors', - _patch_kwargs={'aggressive': aggressive}) - - -@_ignores_DoNotPatch -def patch_subprocess(): - """ - Replace :func:`subprocess.call`, :func:`subprocess.check_call`, - :func:`subprocess.check_output` and :class:`subprocess.Popen` with - :mod:`cooperative versions `. - - .. note:: - On Windows under Python 3, the API support may not completely match - the standard library. - - .. note:: - On macOS, this changes the :mod:`multiprocessing` start method to 'fork'. - It defaults to 'spawn'. - - .. note:: - On Python 3.14+ and platforms other than macOS and Windows, this - changes the :mod:`multiprocessing` start method to 'fork'. - It defaults to 'forkserver'. - """ - _patch_module('subprocess') - -@_ignores_DoNotPatch -def patch_builtins(): - """ - Make the builtin :func:`__import__` function `greenlet safe`_ under Python 2. - - .. note:: - This does nothing under Python 3 as it is not necessary. Python 3 features - improved import locks that are per-module, not global. - - .. _greenlet safe: https://github.com/gevent/gevent/issues/108 - - .. deprecated:: 23.7.0 - Does nothing on any supported platform. - """ - - -@_ignores_DoNotPatch -def patch_signal(): - """ - Make the :func:`signal.signal` function work with a :func:`monkey-patched os `. - - .. caution:: This method must be used with :func:`patch_os` to have proper ``SIGCHLD`` - handling. :func:`patch_all` calls both by default. - - .. caution:: For proper ``SIGCHLD`` handling, you must yield to the event loop. - Using :func:`patch_all` is the easiest way to ensure this. - - .. seealso:: :mod:`gevent.signal` - """ - _patch_module("signal") - - -def _check_repatching(**module_settings): - _warnings = [] - key = '_gevent_saved_patch_all_module_settings' - - del module_settings['kwargs'] - currently_patched = saved.setdefault(key, {}) - first_time = not currently_patched - if not first_time and currently_patched != module_settings: - _queue_warning("Patching more than once will result in the union of all True" - " parameters being patched", - _warnings) - - to_patch = {} - for k, v in module_settings.items(): - # If we haven't seen the setting at all, record it and echo it. - # If we have seen the setting, but it became true, record it and echo it. - if k not in currently_patched: - to_patch[k] = currently_patched[k] = v - elif v and not currently_patched[k]: - to_patch[k] = currently_patched[k] = True - - return _warnings, first_time, to_patch - - -def _subscribe_signal_os(will_patch_all): - if will_patch_all.will_patch_module('signal') and not will_patch_all.will_patch_module('os'): - warnings = will_patch_all._warnings # Internal - _queue_warning('Patching signal but not os will result in SIGCHLD handlers' - ' installed after this not being called and os.waitpid may not' - ' function correctly if gevent.subprocess is used. This may raise an' - ' error in the future.', - warnings) - -def patch_all(socket=True, dns=True, time=True, select=True, thread=True, os=True, ssl=True, - subprocess=True, sys=False, aggressive=True, Event=True, - builtins=True, signal=True, - queue=True, contextvars=True, - **kwargs): - """ - Do all of the default monkey patching (calls every other applicable - function in this module). - - :return: A true value if patching all modules wasn't cancelled, a false - value if it was. - - .. versionchanged:: 1.1 - Issue a :mod:`warning ` if this function is called multiple times - with different arguments. The second and subsequent calls will only add more - patches, they can never remove existing patches by setting an argument to ``False``. - .. versionchanged:: 1.1 - Issue a :mod:`warning ` if this function is called with ``os=False`` - and ``signal=True``. This will cause SIGCHLD handlers to not be called. This may - be an error in the future. - .. versionchanged:: 1.3a2 - ``Event`` defaults to True. - .. versionchanged:: 1.3b1 - Defined the return values. - .. versionchanged:: 1.3b1 - Add ``**kwargs`` for the benefit of event subscribers. CAUTION: gevent may add - and interpret additional arguments in the future, so it is suggested to use prefixes - for kwarg values to be interpreted by plugins, for example, `patch_all(mylib_futures=True)`. - .. versionchanged:: 1.3.5 - Add *queue*, defaulting to True, for Python 3.7. - .. versionchanged:: 1.5 - Remove the ``httplib`` argument. Previously, setting it raised a ``ValueError``. - .. versionchanged:: 1.5a3 - Add the ``contextvars`` argument. - .. versionchanged:: 1.5 - Better handling of patching more than once. - """ - # pylint:disable=too-many-locals,too-many-branches - - # Check to see if they're changing the patched list - _warnings, first_time, modules_to_patch = _check_repatching(**locals()) - - if not modules_to_patch: - # Nothing to do. Either the arguments were identical to what - # we previously did, or they specified false values - # for things we had previously patched. - _process_warnings(_warnings) - return - - for k, v in modules_to_patch.items(): - locals()[k] = v - - from gevent import events - try: - _notify_patch(events.GeventWillPatchAllEvent(modules_to_patch, kwargs), _warnings) - except events.DoNotPatch: - return False - - # order is important - if os: - patch_os() - if thread: - patch_thread(Event=Event, _warnings=_warnings) - if time: - # time must be patched after thread, some modules used by thread - # need access to the real time.sleep function. - patch_time() - - # sys must be patched after thread. in other cases threading._shutdown will be - # initiated to _MainThread with real thread ident - if sys: - patch_sys() - if socket: - patch_socket(dns=dns, aggressive=aggressive) - if select: - if not PY314: - patch_select(aggressive=aggressive) - patch_selectors(aggressive=aggressive) - else: - # 3.14 changes the selector module to actually try to _use_ - # each selector to figure out which one to use by default. - # If we patch ``select`` before patching ``selectors``, - # that results in using ``gevent.select`` as the implementation, - # and that results in creating the hub. Monkey-patching isn't supposed to - # create the hub, so reverse order here. This _should_ be safe for all - # versions, but just to be sure, don't swap it on old versions. - patch_selectors(aggressive=aggressive) - patch_select(aggressive=aggressive) - if ssl: - patch_ssl(_warnings=_warnings, _first_time=first_time) - if subprocess: - patch_subprocess() - if builtins: - patch_builtins() - if signal: - patch_signal() - if queue: - patch_queue() - if contextvars: - patch_contextvars() - - _notify_patch(events.GeventDidPatchBuiltinModulesEvent(modules_to_patch, kwargs), _warnings) - _notify_patch(events.GeventDidPatchAllEvent(modules_to_patch, kwargs), _warnings) - - _process_warnings(_warnings) - return True - -def __getattr__(name): - if name == 'main': - from ._main import main - return main - raise AttributeError(name) diff --git a/venv/lib/python3.9/site-packages/gevent/monkey/__main__.py b/venv/lib/python3.9/site-packages/gevent/monkey/__main__.py deleted file mode 100644 index be7e86a..0000000 --- a/venv/lib/python3.9/site-packages/gevent/monkey/__main__.py +++ /dev/null @@ -1,2 +0,0 @@ -from ._main import main -main() diff --git a/venv/lib/python3.9/site-packages/gevent/monkey/_errors.py b/venv/lib/python3.9/site-packages/gevent/monkey/_errors.py deleted file mode 100644 index f9d88a0..0000000 --- a/venv/lib/python3.9/site-packages/gevent/monkey/_errors.py +++ /dev/null @@ -1,26 +0,0 @@ -# -*- coding: utf-8 -*- -""" -Exception classes and errors that this package may raise. - -""" -import logging - -logger = logging.getLogger(__name__) - -class _BadImplements(AttributeError): - """ - Raised when ``__implements__`` is incorrect. - """ - - def __init__(self, module): - AttributeError.__init__( - self, - "Module %r has a bad or missing value for __implements__" % (module,) - ) - -class MonkeyPatchWarning(RuntimeWarning): - """ - The type of warnings we issue. - - .. versionadded:: 1.3a2 - """ diff --git a/venv/lib/python3.9/site-packages/gevent/monkey/_main.py b/venv/lib/python3.9/site-packages/gevent/monkey/_main.py deleted file mode 100644 index 306cf87..0000000 --- a/venv/lib/python3.9/site-packages/gevent/monkey/_main.py +++ /dev/null @@ -1,117 +0,0 @@ -# -*- coding: utf-8 -*- -""" -The real functionality to run this package as a main module. - -""" - - -def main(): - # TODO: Now that this is its own module, see if - # we can refactor. - # pylint:disable=too-many-locals - import sys - from . import patch_all - - args = {} - argv = sys.argv[1:] - verbose = False - run_fn = "run_path" - script_help, patch_all_args, modules = _get_script_help() - while argv and argv[0].startswith('--'): - option = argv[0][2:] - if option == 'verbose': - verbose += 1 - elif option == 'module': - run_fn = "run_module" - elif option.startswith('no-') and option.replace('no-', '') in patch_all_args: - args[option[3:]] = False - elif option in patch_all_args: - args[option] = True - if option in modules: - for module in modules: - args.setdefault(module, False) - else: - sys.exit(script_help + '\n\n' + 'Cannot patch %r' % option) - del argv[0] - # TODO: break on -- - if verbose: - import pprint - import os - print('gevent.monkey.patch_all(%s)' % ', '.join('%s=%s' % item for item in args.items())) - print('sys.version=%s' % (sys.version.strip().replace('\n', ' '), )) - print('sys.path=%s' % pprint.pformat(sys.path)) - print('sys.modules=%s' % pprint.pformat(sorted(sys.modules.keys()))) - print('cwd=%s' % os.getcwd()) - - if not argv: - print(script_help) - return - - sys.argv[:] = argv - # Make sure that we don't get imported again under a different - # name (usually it's ``__main__`` here) because that could lead to - # double-patching, and making monkey.get_original() not work. - try: - mod_name = __spec__.name - except NameError: - # Py2: __spec__ is not defined as standard - mod_name = 'gevent.monkey' - sys.modules[mod_name] = sys.modules[__name__] - # On Python 2, we have to set the gevent.monkey attribute - # manually; putting gevent.monkey into sys.modules stops the - # import machinery from making that connection, and ``from gevent - # import monkey`` is broken. On Python 3 (.8 at least) that's not - # necessary. - assert 'gevent.monkey' in sys.modules - - # Running ``patch_all()`` will load pkg_resources entry point plugins - # which may attempt to import ``gevent.monkey``, so it is critical that - # we have established the correct saved module name first. - patch_all(**args) - - import runpy - # Use runpy.run_path to closely (exactly) match what the - # interpreter does given 'python '. This includes allowing - # passing .pyc/.pyo files and packages with a __main__ and - # potentially even zip files. Previously we used exec, which only - # worked if we directly read a python source file. - run_meth = getattr(runpy, run_fn) - return run_meth(sys.argv[0], run_name='__main__') - - -def _get_script_help(): - # pylint:disable=deprecated-method - import inspect - from . import patch_all - getter = inspect.getfullargspec - - patch_all_args = getter(patch_all)[0] - modules = [x for x in patch_all_args if 'patch_' + x in globals()] - script_help = """gevent.monkey - monkey patch the standard modules to use gevent. - -USAGE: ``python -m gevent.monkey [MONKEY OPTIONS] [--module] (script|module) [SCRIPT OPTIONS]`` - -If no MONKEY OPTIONS are present, monkey patches all the modules as if by calling ``patch_all()``. -You can exclude a module with --no-, e.g. --no-thread. You can -specify a module to patch with --, e.g. --socket. In the latter -case only the modules specified on the command line will be patched. - -The default behavior is to execute the script passed as argument. If you wish -to run a module instead, pass the `--module` argument before the module name. - -.. versionchanged:: 1.3b1 - The *script* argument can now be any argument that can be passed to `runpy.run_path`, - just like the interpreter itself does, for example a package directory containing ``__main__.py``. - Previously it had to be the path to - a .py source file. - -.. versionchanged:: 1.5 - The `--module` option has been added. - -MONKEY OPTIONS: ``--verbose %s``""" % ', '.join('--[no-]%s' % m for m in modules) - return script_help, patch_all_args, modules - -main.__doc__ = _get_script_help()[0] - -if __name__ == '__main__': - main() diff --git a/venv/lib/python3.9/site-packages/gevent/monkey/_patch_thread_common.py b/venv/lib/python3.9/site-packages/gevent/monkey/_patch_thread_common.py deleted file mode 100644 index e707431..0000000 --- a/venv/lib/python3.9/site-packages/gevent/monkey/_patch_thread_common.py +++ /dev/null @@ -1,320 +0,0 @@ -# -*- coding: utf-8 -*- -""" -The implementation of thread patching for Python versions -prior to 3.13. - -Internal use only. -""" -import sys - -from gevent.exceptions import LoopExit - -from ._state import is_object_patched -from ._util import _notify_patch -from ._util import _patch_module -from ._util import _queue_warning - - -def _patch_existing_locks(threading): - if len(list(threading.enumerate())) != 1: - return - # This is used to protect internal data structures for enumerate. - # It's acquired when threads are started and when they're stopped. - # Stopping a thread checks a Condition, which on Python 2 wants to test - # _is_owned of its (patched) Lock. Since our LockType doesn't have - # _is_owned, it tries to acquire the lock non-blocking; that triggers a - # switch. If the next thing in the callback list was a thread that needed - # to start or end, we wouldn't be able to acquire this native lock - # because it was being held already; we couldn't switch either, so we'd - # block permanently. - threading._active_limbo_lock = threading._allocate_lock() - try: - tid = threading.get_ident() - except AttributeError: - tid = threading._get_ident() - rlock_type = type(threading.RLock()) - try: - import importlib._bootstrap - except ImportError: - class _ModuleLock(object): - pass - else: - _ModuleLock = importlib._bootstrap._ModuleLock # python 2 pylint: disable=no-member - # It might be possible to walk up all the existing stack frames to find - # locked objects...at least if they use `with`. To be sure, we look at every object - # Since we're supposed to be done very early in the process, there shouldn't be - # too many. - - # Note that the C implementation of locks, at least on some - # versions of CPython, cannot be found and cannot be fixed (they simply - # don't show up to GC; see https://github.com/gevent/gevent/issues/1354) - - # By definition there's only one thread running, so the various - # owner attributes were the old (native) thread id. Make it our - # current greenlet id so that when it wants to unlock and compare - # self.__owner with _get_ident(), they match. - gc = __import__('gc') - for o in gc.get_objects(): - if isinstance(o, rlock_type): - for owner_name in ( - '_owner', # Python 3 or backported PyPy2 - '_RLock__owner', # Python 2 - ): - if hasattr(o, owner_name): - if getattr(o, owner_name) is not None: - setattr(o, owner_name, tid) - break - else: # pragma: no cover - raise AssertionError( - "Unsupported Python implementation; " - "Found unknown lock implementation.", - vars(o) - ) - elif isinstance(o, _ModuleLock): - if o.owner is not None: - o.owner = tid - - - -class BasePatcher: - # Description of the hang: - # There is an incompatibility with patching 'thread' and the 'multiprocessing' module: - # The problem is that multiprocessing.queues.Queue uses a half-duplex multiprocessing.Pipe, - # which is implemented with os.pipe() and _multiprocessing.Connection. os.pipe isn't patched - # by gevent, as it returns just a fileno. _multiprocessing.Connection is an internal implementation - # class implemented in C, which exposes a 'poll(timeout)' method; under the covers, this issues a - # (blocking) select() call: hence the need for a real thread. Except for that method, we could - # almost replace Connection with gevent.fileobject.SocketAdapter, plus a trivial - # patch to os.pipe (below). Sigh, so close. (With a little work, we could replicate that method) - - # import os - # import fcntl - # os_pipe = os.pipe - # def _pipe(): - # r, w = os_pipe() - # fcntl.fcntl(r, fcntl.F_SETFL, os.O_NONBLOCK) - # fcntl.fcntl(w, fcntl.F_SETFL, os.O_NONBLOCK) - # return r, w - # os.pipe = _pipe - - gevent_threading_mod = None - gevent_thread_mod = None - - thread_mod = None - threading_mod = None - orig_current_thread = None - main_thread = None - orig_shutdown = None - - def __init__(self, threading=True, _threading_local=True, Event=True, logging=True, - existing_locks=True, - _warnings=None): - self.threading = threading - self.threading_local = _threading_local - self.Event = Event - self.logging = logging - self.existing_locks = existing_locks - self.warnings = _warnings - - - - def __call__(self): - # The 'threading' module copies some attributes from the - # thread module the first time it is imported. If we patch 'thread' - # before that happens, then we store the wrong values in 'saved', - # So if we're going to patch threading, we either need to import it - # before we patch thread, or manually clean up the attributes that - # are in trouble. The latter is tricky because of the different names - # on different versions. - - - self.threading_mod = __import__('threading') - # Capture the *real* current thread object before - # we start returning DummyThread objects, for comparison - # to the main thread. - self.orig_current_thread = self.threading_mod.current_thread() - self.main_thread = self.threading_mod.main_thread() - self.orig_shutdown = self.threading_mod._shutdown - - gevent_thread_mod, thread_mod = _patch_module('thread', - _warnings=self.warnings, - _notify_did_subscribers=False) - - - if self.threading: - self.patch_threading_event_logging_existing_locks() - - if self.threading_local: - self.patch__threading_local() - - if self.threading: - self.patch_active_threads() - - - # Issue 18808 changes the nature of Thread.join() to use - # locks. This means that a greenlet spawned in the main thread - # (which is already running) cannot wait for the main thread---it - # hangs forever. We patch around this if possible. See also - # gevent.threading. - already_patched = is_object_patched('threading', '_shutdown') - - if self.orig_current_thread == self.threading_mod.main_thread() and not already_patched: - self.patch_threading_shutdown_on_main_thread_not_already_patched() - self.patch_main_thread_cleanup() - - elif not already_patched: - self.patch_shutdown_not_on_main_thread() - - from gevent import events - _notify_patch(events.GeventDidPatchModuleEvent('thread', - gevent_thread_mod, - thread_mod)) - if self.gevent_threading_mod is not None: - _notify_patch(events.GeventDidPatchModuleEvent('threading', - self.gevent_threading_mod, - self.threading_mod)) - - def patch_threading_event_logging_existing_locks(self): - - self.gevent_threading_mod, patched_mod = _patch_module( - 'threading', - _warnings=self.warnings, - _notify_did_subscribers=False) - - assert patched_mod is self.threading_mod - - if self.Event: - self.patch_event() - - if self.existing_locks: - _patch_existing_locks(self.threading_mod) - - if self.logging and 'logging' in sys.modules: - self.patch_logging() - - def patch_event(self): - from gevent.event import Event - - from .api import patch_item - patch_item(self.threading_mod, 'Event', Event) - # Python 2 had `Event` as a function returning - # the private class `_Event`. Some code may be relying - # on that. - if hasattr(self.threading_mod, '_Event'): - patch_item(self.threading_mod, '_Event', Event) - - def patch_logging(self): - from .api import patch_item - logging = __import__('logging') - patch_item(logging, '_lock', self.threading_mod.RLock()) - for wr in logging._handlerList: - # In py26, these are actual handlers, not weakrefs - handler = wr() if callable(wr) else wr - if handler is None: - continue - if not hasattr(handler, 'lock'): - raise TypeError("Unknown/unsupported handler %r" % handler) - handler.lock = self.threading_mod.RLock() - - def patch__threading_local(self): - _threading_local = __import__('_threading_local') - from gevent.local import local - - from .api import patch_item - patch_item(_threading_local, 'local', local) - - def patch_active_threads(self): - raise NotImplementedError - - def patch_threading_shutdown_on_main_thread_not_already_patched(self): - raise NotImplementedError - - def patch_main_thread_cleanup(self): - # We create a bit of a reference cycle here, - # so main_thread doesn't get to be collected in a timely way. - # Not good. Take it out of dangling so we don't get - # warned about it. - main_thread = self.main_thread - self.threading_mod._dangling.remove(main_thread) - - # Patch up the ident of the main thread to match. This - # matters if threading was imported before monkey-patching - # thread - oldid = main_thread.ident - main_thread._ident = self.threading_mod.get_ident() - if oldid in self.threading_mod._active: - self.threading_mod._active[main_thread.ident] = self.threading_mod._active[oldid] - if oldid != main_thread.ident: - del self.threading_mod._active[oldid] - - def patch_shutdown_not_on_main_thread(self): - _queue_warning("Monkey-patching not on the main thread; " - "threading.main_thread().join() will hang from a greenlet", - self.warnings) - - from .api import patch_item - - main_thread = self.main_thread - threading_mod = self.threading_mod - get_ident = self.threading_mod.get_ident - orig_shutdown = self.orig_shutdown - def _shutdown(): - # We've patched get_ident but *did not* patch the - # main_thread.ident value. Beginning in Python 3.9.8 - # and then later releases (3.10.1, probably), the - # _main_thread object is only _stop() if the ident of - # the current thread (the *real* main thread) matches - # the ident of the _main_thread object. But without doing that, - # the main thread's shutdown lock (threading._shutdown_locks) is never - # removed *or released*, thus hanging the interpreter. - # XXX: There's probably a better way to do this. Probably need to take a - # step back and look at the whole picture. - main_thread._ident = get_ident() - try: - orig_shutdown() - except LoopExit: # pragma: no cover - pass - patch_item(threading_mod, '_shutdown', orig_shutdown) - patch_item(threading_mod, '_shutdown', _shutdown) - - @staticmethod # Static to be sure we don't accidentally capture `self` and keep it alive - def _make_existing_non_main_thread_join_func(thread, thread_greenlet, threading_mod): - from time import time - - from gevent.hub import sleep - - # TODO: This is almost the algorithm that the 3.13 _ThreadHandle class - # employs. UNIFY them. - def join(timeout=None): - end = None - if threading_mod.current_thread() is thread: - raise RuntimeError("Cannot join current thread") - if thread_greenlet is not None and thread_greenlet.dead: - return - # You may ask: Why not call thread_greenlet.join()? - # Well, in the one case we actually have a greenlet, it's the - # low-level greenlet.greenlet object for the main thread, which - # doesn't have a join method. - # - # You may ask: Why not become the main greenlet's *parent* - # so you can get notified when it finishes? Because you can't - # create a greenlet cycle (the current greenlet is a descendent - # of the parent), and nor can you set a greenlet's parent to None, - # so there can only ever be one greenlet with a parent of None: the main - # greenlet, the one we need to watch. - # - # You may ask: why not swizzle out the problematic lock on the main thread - # into a gevent friendly lock? Well, the interpreter actually depends on that - # for the main thread in threading._shutdown; see below. - - if not thread.is_alive(): - return - - if timeout: - end = time() + timeout - - while thread.is_alive(): - if end is not None and time() > end: - return - sleep(0.01) - return join diff --git a/venv/lib/python3.9/site-packages/gevent/monkey/_patch_thread_gte313.py b/venv/lib/python3.9/site-packages/gevent/monkey/_patch_thread_gte313.py deleted file mode 100644 index b03105c..0000000 --- a/venv/lib/python3.9/site-packages/gevent/monkey/_patch_thread_gte313.py +++ /dev/null @@ -1,105 +0,0 @@ -# -*- coding: utf-8 -*- -""" -The implementation of thread patching for Python versions -after 3.13. - -Internal use only. -""" -import sys - -from gevent.exceptions import LoopExit - -from ._patch_thread_common import BasePatcher - - -class Patcher(BasePatcher): - - - def patch_active_threads(self): - from gevent.threading import main_native_thread - - for thread in self.threading_mod._active.values(): - if thread == main_native_thread(): - from gevent.thread import _ThreadHandle - from greenlet import getcurrent - thread._after_fork = lambda new_ident=None: new_ident - handle = _ThreadHandle() - handle._set_greenlet(getcurrent()) - handle_attr = '_handle' - if hasattr(thread, '_os_thread_handle'): - handle_attr = '_os_thread_handle' - setattr(thread, handle_attr, handle) - thread._ident = handle.ident - assert thread.ident == getattr(thread, handle_attr).ident - continue - thread.join = self._make_existing_non_main_thread_join_func(thread, - None, - self.threading_mod) - - def patch_threading_shutdown_on_main_thread_not_already_patched(self): - import greenlet - - from .api import patch_item - - main_thread = self.main_thread - threading_mod = self.threading_mod - orig_shutdown = self.orig_shutdown - _greenlet = main_thread._greenlet = greenlet.getcurrent() - handle_attr = '_handle' - if hasattr(main_thread, '_os_thread_handle'): - handle_attr = '_os_thread_handle' - def _shutdown(): - # Release anyone trying to join() me, - # and let us switch to them. - getattr(main_thread, handle_attr)._set_done() - from gevent import sleep - try: - sleep() - except: # pylint:disable=bare-except - # A greenlet could have .kill() us - # or .throw() to us. I'm the main greenlet, - # there's no where else for this to go. - from gevent import get_hub - get_hub().print_exception(_greenlet, *sys.exc_info()) - - # Now, this may have resulted in us getting stopped - # if some other greenlet actually just ran there. - # That's not good, we're not supposed to be stopped - # when we enter _shutdown. - class FakeHandle: - def is_done(self): - return False - def _set_done(self): - return - def join(self): - return - setattr(main_thread, handle_attr, FakeHandle()) - assert main_thread.is_alive() - # main_thread._is_stopped = False - # main_thread._tstate_lock = main_thread.__real_tstate_lock - # main_thread.__real_tstate_lock = None - # The only truly blocking native shutdown lock to - # acquire should be our own (hopefully), and the call to - # _stop that orig_shutdown makes will discard it. - - # XXX: What if more get spawned? - for t in list(threading_mod.enumerate()): - if t.daemon or t is main_thread: - continue - while t.is_alive(): - # 3.13.3 and >= 3.13.4 name this different - handle = getattr(t, handle_attr) - try: - handle.join(0.001) - except RuntimeError: - # Joining ourself. - handle._set_done() - break - - try: - orig_shutdown() - except LoopExit: # pragma: no cover - pass - patch_item(threading_mod, '_shutdown', self.orig_shutdown) - - patch_item(self.threading_mod, '_shutdown', _shutdown) diff --git a/venv/lib/python3.9/site-packages/gevent/monkey/_patch_thread_lt313.py b/venv/lib/python3.9/site-packages/gevent/monkey/_patch_thread_lt313.py deleted file mode 100644 index 43979e5..0000000 --- a/venv/lib/python3.9/site-packages/gevent/monkey/_patch_thread_lt313.py +++ /dev/null @@ -1,81 +0,0 @@ -# -*- coding: utf-8 -*- -""" -The implementation of thread patching for Python versions -prior to 3.13. - -Internal use only. -""" -import sys -from gevent.exceptions import LoopExit - -from ._patch_thread_common import BasePatcher - - -class Patcher(BasePatcher): - - def patch_active_threads(self): - from gevent.threading import main_native_thread - threading_mod = self.threading_mod - for thread in threading_mod._active.values(): - if thread == main_native_thread(): - continue - thread.join = self._make_existing_non_main_thread_join_func(thread, None, threading_mod) - - - def patch_threading_shutdown_on_main_thread_not_already_patched(self): - import greenlet - from .api import patch_item - threading_mod = self.threading_mod - main_thread = self.main_thread - orig_shutdown = self.orig_shutdown - - _greenlet = main_thread._greenlet = greenlet.getcurrent() - main_thread._gevent_real_tstate_lock = main_thread._tstate_lock - assert main_thread._gevent_real_tstate_lock is not None - # The interpreter will call threading._shutdown - # when the main thread exits and is about to - # go away. It is called *in* the main thread. This - # is a perfect place to notify other greenlets that - # the main thread is done. We do this by overriding the - # lock of the main thread during operation, and only restoring - # it to the native blocking version at shutdown time - # (the interpreter also has a reference to this lock in a - # C data structure). - main_thread._tstate_lock = threading_mod.Lock() - main_thread._tstate_lock.acquire() - - def _shutdown(): - # Release anyone trying to join() me, - # and let us switch to them. - if not main_thread._tstate_lock: - return - - main_thread._tstate_lock.release() - from gevent import sleep - try: - sleep() - except: # pylint:disable=bare-except - # A greenlet could have .kill() us - # or .throw() to us. I'm the main greenlet, - # there's no where else for this to go. - from gevent import get_hub - get_hub().print_exception(_greenlet, *sys.exc_info()) - - # Now, this may have resulted in us getting stopped - # if some other greenlet actually just ran there. - # That's not good, we're not supposed to be stopped - # when we enter _shutdown. - main_thread._is_stopped = False - main_thread._tstate_lock = main_thread._gevent_real_tstate_lock - main_thread._gevent_real_tstate_lock = None - # The only truly blocking native shutdown lock to - # acquire should be our own (hopefully), and the call to - # _stop that orig_shutdown makes will discard it. - - try: - orig_shutdown() - except LoopExit: # pragma: no cover - pass - patch_item(threading_mod, '_shutdown', orig_shutdown) - - patch_item(threading_mod, '_shutdown', _shutdown) diff --git a/venv/lib/python3.9/site-packages/gevent/monkey/_state.py b/venv/lib/python3.9/site-packages/gevent/monkey/_state.py deleted file mode 100644 index d3315ac..0000000 --- a/venv/lib/python3.9/site-packages/gevent/monkey/_state.py +++ /dev/null @@ -1,70 +0,0 @@ -# -*- coding: utf-8 -*- -""" -State management and query functions for tracking and discovering what -has been patched. -""" -import logging - -logger = logging.getLogger(__name__) - - -# maps module name -> {attribute name: original item} -# e.g. "time" -> {"sleep": built-in function sleep} -# NOT A PUBLIC API. However, third-party monkey-patchers may be using -# it? TODO: Provide better API for them. -saved:dict = {} - - -def is_module_patched(mod_name): - """ - Check if a module has been replaced with a cooperative version. - - :param str mod_name: The name of the standard library module, - e.g., ``'socket'``. - - """ - return mod_name in saved - - -def is_object_patched(mod_name, item_name): - """ - Check if an object in a module has been replaced with a - cooperative version. - - :param str mod_name: The name of the standard library module, - e.g., ``'socket'``. - :param str item_name: The name of the attribute in the module, - e.g., ``'create_connection'``. - - """ - return is_module_patched(mod_name) and item_name in saved[mod_name] - - -def is_anything_patched(): - """ - Check if this module has done any patching in the current process. - This is currently only used in gevent tests. - - Not currently a documented, public API, because I'm not convinced - it is 100% reliable in the event of third-party patch functions that - don't use ``saved``. - - .. versionadded:: 21.1.0 - """ - return bool(saved) - -def _get_original(name, items): - d = saved.get(name, {}) - values = [] - module = None - for item in items: - if item in d: - values.append(d[item]) - else: - if module is None: - module = __import__(name) - values.append(getattr(module, item)) - return values - -def _save(module, attr_name, item): - saved.setdefault(module.__name__, {}).setdefault(attr_name, item) diff --git a/venv/lib/python3.9/site-packages/gevent/monkey/_util.py b/venv/lib/python3.9/site-packages/gevent/monkey/_util.py deleted file mode 100644 index ca12e06..0000000 --- a/venv/lib/python3.9/site-packages/gevent/monkey/_util.py +++ /dev/null @@ -1,105 +0,0 @@ -# -*- coding: utf-8 -*- -""" -Utilities used in patching. - -Internal use only. - -""" -import sys - - -def _notify_patch(event, _warnings=None): - # Raises DoNotPatch if we're not supposed to patch - from gevent.events import notify_and_call_entry_points - - event._warnings = _warnings - notify_and_call_entry_points(event) - -def _ignores_DoNotPatch(func): - - from functools import wraps - - @wraps(func) - def ignores(*args, **kwargs): - from gevent.events import DoNotPatch - try: - return func(*args, **kwargs) - except DoNotPatch: - return False - - return ignores - -def _check_availability(name): - """ - Test that the source and target modules for *name* are - available and return them. - - :raise ImportError: If the source or target cannot be imported. - :return: The tuple ``(gevent_module, target_module, target_module_name)`` - """ - # Always import the gevent module first. This helps us be sure we can - # use regular imports in gevent files (when we can't use gevent.monkey.get_original()) - gevent_module = getattr(__import__('gevent.' + name), name) - target_module_name = getattr(gevent_module, '__target__', name) - target_module = __import__(target_module_name) - - return gevent_module, target_module, target_module_name - - -def _patch_module(name, - items=None, - _warnings=None, - _patch_kwargs=None, - _notify_will_subscribers=True, - _notify_did_subscribers=True, - _call_hooks=True): - - from .api import patch_module - - gevent_module, target_module, target_module_name = _check_availability(name) - - patch_module(target_module, gevent_module, items=items, - _warnings=_warnings, _patch_kwargs=_patch_kwargs, - _notify_will_subscribers=_notify_will_subscribers, - _notify_did_subscribers=_notify_did_subscribers, - _call_hooks=_call_hooks) - - # On Python 2, the `futures` package will install - # a bunch of modules with the same name as those from Python 3, - # such as `_thread`; primarily these just do `from thread import *`, - # meaning we have alternate references. If that's already been imported, - # we need to attempt to patch that too. - - # Be sure to keep the original states matching also. - - alternate_names = getattr(gevent_module, '__alternate_targets__', ()) - from ._state import saved # TODO: Add apis for these use cases. - for alternate_name in alternate_names: - alternate_module = sys.modules.get(alternate_name) - if alternate_module is not None and alternate_module is not target_module: - saved.pop(alternate_name, None) - patch_module(alternate_module, gevent_module, items=items, - _warnings=_warnings, - _notify_will_subscribers=False, - _notify_did_subscribers=False, - _call_hooks=False) - saved[alternate_name] = saved[target_module_name] - - return gevent_module, target_module - - -def _queue_warning(message, _warnings): - # Queues a warning to show after the monkey-patching process is all done. - # Done this way to avoid extra imports during the process itself, just - # in case. If we're calling a function one-off (unusual) go ahead and do it - if _warnings is None: - _process_warnings([message]) - else: - _warnings.append(message) - - -def _process_warnings(_warnings): - import warnings - from ._errors import MonkeyPatchWarning - for warning in _warnings: - warnings.warn(warning, MonkeyPatchWarning, stacklevel=3) diff --git a/venv/lib/python3.9/site-packages/gevent/monkey/api.py b/venv/lib/python3.9/site-packages/gevent/monkey/api.py deleted file mode 100644 index 66642cf..0000000 --- a/venv/lib/python3.9/site-packages/gevent/monkey/api.py +++ /dev/null @@ -1,199 +0,0 @@ -# -*- coding: utf-8 -*- -""" -Higher level functions that comprise parts of -the public monkey patching API. - - -""" - - -def get_original(mod_name, item_name): - """ - Retrieve the original object from a module. - - If the object has not been patched, then that object will still be - retrieved. - - :param str|sequence mod_name: The name of the standard library module, - e.g., ``'socket'``. Can also be a sequence of standard library - modules giving alternate names to try, e.g., ``('thread', '_thread')``; - the first importable module will supply all *item_name* items. - :param str|sequence item_name: A string or sequence of strings naming the - attribute(s) on the module ``mod_name`` to return. - - :return: The original value if a string was given for - ``item_name`` or a sequence of original values if a - sequence was passed. - """ - from ._state import _get_original - - mod_names = [mod_name] if isinstance(mod_name, str) else mod_name - if isinstance(item_name, str): - item_names = [item_name] - unpack = True - else: - item_names = item_name - unpack = False - - for mod in mod_names: - try: - result = _get_original(mod, item_names) - except ImportError: - if mod is mod_names[-1]: - raise - else: - return result[0] if unpack else result - -_NONE = object() - -def patch_item(module, attr, newitem): - from ._state import _save - - olditem = getattr(module, attr, _NONE) - if olditem is not _NONE: - _save(module, attr, olditem) - setattr(module, attr, newitem) - - -def remove_item(module, attr): - from ._state import _save - - olditem = getattr(module, attr, _NONE) - if olditem is _NONE: - return - _save(module, attr, olditem) - - delattr(module, attr) - -def patch_module(target_module, source_module, items=None, - _warnings=None, - _patch_kwargs=None, - _notify_will_subscribers=True, - _notify_did_subscribers=True, - _call_hooks=True): - """ - patch_module(target_module, source_module, items=None) - - Replace attributes in *target_module* with the attributes of the - same name in *source_module*. - - The *source_module* can provide some attributes to customize the process: - - * ``__implements__`` is a list of attribute names to copy; if not present, - the *items* keyword argument is mandatory. ``__implements__`` must only have - names from the standard library module in it. - * ``_gevent_will_monkey_patch(target_module, items, warn, **kwargs)`` - * ``_gevent_did_monkey_patch(target_module, items, warn, **kwargs)`` - These two functions in the *source_module* are called *if* they exist, - before and after copying attributes, respectively. The "will" function - may modify *items*. The value of *warn* is a function that should be called - with a single string argument to issue a warning to the user. If the "will" - function raises :exc:`gevent.events.DoNotPatch`, no patching will be done. These functions - are called before any event subscribers or plugins. - - :keyword list items: A list of attribute names to replace. If - not given, this will be taken from the *source_module* ``__implements__`` - attribute. - :return: A true value if patching was done, a false value if patching was canceled. - - .. versionadded:: 1.3b1 - """ - from gevent import events - from ._errors import _BadImplements - from ._util import _notify_patch - - if items is None: - try: - items = source_module.__implements__ - except AttributeError as e: - raise _BadImplements(source_module) from e - - if items is None: - raise _BadImplements(source_module) - - try: - if _call_hooks: - __call_module_hook(source_module, 'will', target_module, items, _warnings) - if _notify_will_subscribers: - _notify_patch( - events.GeventWillPatchModuleEvent(target_module.__name__, source_module, - target_module, items), - _warnings) - except events.DoNotPatch: - return False - - # Undocumented, internal use: If the module defines - # `_gevent_do_monkey_patch(patch_request: _GeventDoPatchRequest)` call that; - # the module is responsible for its own patching. - do_patch = getattr( - source_module, - '_gevent_do_monkey_patch', - _GeventDoPatchRequest.default_patch_items - ) - request = _GeventDoPatchRequest(target_module, source_module, items, _patch_kwargs) - do_patch(request) - - if _call_hooks: - __call_module_hook(source_module, 'did', target_module, items, _warnings) - - if _notify_did_subscribers: - # We allow turning off the broadcast of the 'did' event for the benefit - # of our internal functions which need to do additional work (besides copying - # attributes) before their patch can be considered complete. - _notify_patch( - events.GeventDidPatchModuleEvent(target_module.__name__, source_module, - target_module) - ) - - return True - -class _GeventDoPatchRequest(object): - - get_original = staticmethod(get_original) - - def __init__(self, - target_module, - source_module, - items, - patch_kwargs): - self.target_module = target_module - self.source_module = source_module - self.items = items - self.patch_kwargs = patch_kwargs or {} - - def __repr__(self): - return '<%s target=%r source=%r items=%r kwargs=%r>' % ( - self.__class__.__name__, - self.target_module, - self.source_module, - self.items, - self.patch_kwargs - ) - - def default_patch_items(self): - for attr in self.items: - patch_item(self.target_module, attr, getattr(self.source_module, attr)) - - def remove_item(self, target_module, *items): - if isinstance(target_module, str): - items = (target_module,) + items - target_module = self.target_module - - for item in items: - remove_item(target_module, item) - -def __call_module_hook(gevent_module, name, module, items, _warnings): - # This function can raise DoNotPatch on 'will' - - def warn(message): - from ._util import _queue_warning - _queue_warning(message, _warnings) - - func_name = '_gevent_' + name + '_monkey_patch' - try: - func = getattr(gevent_module, func_name) - except AttributeError: - func = lambda *args: None - - - func(module, items, warn) diff --git a/venv/lib/python3.9/site-packages/gevent/os.py b/venv/lib/python3.9/site-packages/gevent/os.py deleted file mode 100644 index c3b5221..0000000 --- a/venv/lib/python3.9/site-packages/gevent/os.py +++ /dev/null @@ -1,670 +0,0 @@ -""" -Low-level operating system functions from :mod:`os`. - -Cooperative I/O -=============== - -This module provides cooperative versions of :func:`os.read` and -:func:`os.write`. These functions are *not* monkey-patched; you -must explicitly call them or monkey patch them yourself. - -POSIX functions ---------------- - -On POSIX, non-blocking IO is available. - -- :func:`nb_read` -- :func:`nb_write` -- :func:`make_nonblocking` - -All Platforms -------------- - -On non-POSIX platforms (e.g., Windows), non-blocking IO is not -available. On those platforms (and on POSIX), cooperative IO can -be done with the threadpool. - -- :func:`tp_read` -- :func:`tp_write` - -Child Processes -=============== - -The functions :func:`fork` and (on POSIX) :func:`forkpty` and :func:`waitpid` can be used -to manage child processes. - -.. warning:: - - Forking a process that uses greenlets does not eliminate all non-running - greenlets. Any that were scheduled in the hub of the forking thread in the parent - remain scheduled in the child; compare this to how normal threads operate. (This behaviour - may change is a subsequent major release.) -""" - -from __future__ import absolute_import - -import os -from stat import S_ISREG - -from gevent.hub import _get_hub_noargs as get_hub -from gevent.hub import reinit -from gevent.event import Event -from gevent._config import config -from gevent._util import copy_globals -import errno - -EAGAIN = getattr(errno, 'EAGAIN', 11) - -try: - import fcntl -except ImportError: - fcntl = None - -__implements__ = ['fork',] -__extensions__ = ['tp_read', 'tp_write'] - -_read = os.read -_write = os.write -_close = os.close -_fstat = os.fstat - - -ignored_errors = [EAGAIN, errno.EINTR] - - -# An escape hatch (set to False) if you have problems with -# close on regular files because you are trying to poll on it. If you -# need this please let the maintainers know! -_NO_DEFER_REG_FILE = True - -if fcntl: - def _check_fd_valid(fd): - # see libev/check_valid_fd.c. This is what libev does; - # libuv is much more sophisticated. - return fcntl.fcntl(fd, fcntl.F_GETFD) -else: - def _check_fd_valid(fd): # pylint: disable=unused-argument - # Windows. Nothing we can reliably use here across - # all event loops. We need to write some code and make it part - # of the event loop interface. - pass - -if fcntl: - _closing_fd_to_event = {} - __implements__ += ['close',] - - def close(fd): - """ - Close a file descriptor. - - This function cooperates with gevent to avoid crashing - the process if you (accidentally) call it while you're - still performing IO on the file descriptor; for example, if you have it - registered with a ``Selector`` implementation, which documents - that you *must* unregister FDs before closing them. - - If the *fd* refers to a regular file, this cooperation is *not* - used. This is because trying to use gevent to poll on regular - files doesn't work and shouldn't be done. We assume that everyone - is following the rules. - - .. caution:: - This function is not intended for use on Windows. - - .. versionadded:: 25.8.1 - """ - # TODO: Should we limit this method (after the _fstat) to - # just...sockets, fifo, pipe,...and actually I think the list goes - # on. But at any rate, even though it usually doesn't make any - # sense, you CAN create IO watchers for regular files, so in - # theory you could run into the problems we're fixing (issue 2100) - # even with a regular file. I consider that very unlikely though. - # Temp escape hatch if needed. - - # First, check to see if it's invalid already, because - # the stdlib throws OSError in this case; fstat does - # the same. - # - # Our C code uses ``fcntl(F_GETFD)``, use that. - # But we also want to know if the file is regular, so - # we stat it as well. - _check_fd_valid(fd) - stats = _fstat(fd) - if S_ISREG(stats.st_mode) and _NO_DEFER_REG_FILE: - return _close(fd) - - hub = get_hub() - loop = hub.loop - - if fd in _closing_fd_to_event: - # If this is the second time we're closing the same - # FD number, and the fd is still in our map, it means our - # check watcher hasn't run yet, which means if we return - # immediately and anyone tries to do something with that - # fd (read, stat, whatever), it might STILL BE VALID. That's - # bad, and breaks some tests. So wait for it to really be - # closed. - event = _closing_fd_to_event.pop(fd, None) - if event is not None: - # Wake the loop up, let it know we've got - # stuff to do. This is necessary on libev, - # because if the *fd* didn't actually have any active - # watchers, then when we call ``closing_fd``, - # the call it makes to ``ev_feed_fd_event`` silently - # does nothing. This should actually be needed only - # rarely (e.g., when there are no other greenlets and no - # scheduled timers, etc, i.e. hub is idle). - # This showed up in ``test_asyncore.py: - # FileWrapperTest.test_close_twice`` - # Without this, we would just hang. - with loop.idle() as watcher: - hub.wait(watcher) - - # Now our event SHOULD be set, because the check watcher - # SHOULD have run. But don't do an unbounded wait, just in - # case. Getting a weird error with a FD (most likely an - # OSError because it will be closed) is better than - # hanging the process forever. - event.wait(0.001) # arbitrary amount of time - - # Closing twice should raise OSError - raise OSError(errno.EBADF) - - # Ok, first time we're closing this FD. (If it was the - # second, EVEN IF the fd had already come out of the - # map so we failed that check, the _fstat call should - # have raised a OSError. - - loop.closing_fd(fd) - check = loop.check() - event = Event() - _closing_fd_to_event[fd] = event - # Unlike closing sockets, we don't check the return value, - # and always defer it. This is because this case doesn't - # necessarily have access to any active watchers (yet) - def cb(fd): - # If they closed the FD through some other mechanism, - # such as a socket.close, it will be invalid now. - try: - _close(fd) - except OSError: - pass - finally: - event.set() - _closing_fd_to_event.pop(fd, None) - check.stop() - check.close() - check.start(cb, fd) - - - __extensions__ += ['make_nonblocking', 'nb_read', 'nb_write',] - - def make_nonblocking(fd): - """Put the file descriptor *fd* into non-blocking mode if - possible. - - :return: A boolean value that evaluates to True if successful. - """ - flags = fcntl.fcntl(fd, fcntl.F_GETFL, 0) - if not bool(flags & os.O_NONBLOCK): - fcntl.fcntl(fd, fcntl.F_SETFL, flags | os.O_NONBLOCK) - return True - - def nb_read(fd, n): - """ - Read up to *n* bytes from file descriptor *fd*. Return a - byte string containing the bytes read, which may be shorter than - *n*. If end-of-file is reached, an empty string is returned. - - The descriptor must be in non-blocking mode. - """ - hub = None - event = None - try: - while 1: - try: - result = _read(fd, n) - return result - except OSError as e: - if e.errno not in ignored_errors: - raise - if hub is None: - hub = get_hub() - event = hub.loop.io(fd, 1) - hub.wait(event) - finally: - if event is not None: - event.close() - event = None - hub = None - - - def nb_write(fd, buf): - """ - Write some number of bytes from buffer *buf* to file - descriptor *fd*. Return the number of bytes written, which may - be less than the length of *buf*. - - The file descriptor must be in non-blocking mode. - """ - hub = None - event = None - try: - while 1: - try: - result = _write(fd, buf) - return result - except OSError as e: - if e.errno not in ignored_errors: - raise - if hub is None: - hub = get_hub() - event = hub.loop.io(fd, 2) - hub.wait(event) - finally: - if event is not None: - event.close() - event = None - hub = None - - -def tp_read(fd, n): - """Read up to *n* bytes from file descriptor *fd*. Return a string - containing the bytes read. If end-of-file is reached, an empty string - is returned. - - Reading is done using the threadpool. - """ - return get_hub().threadpool.apply(_read, (fd, n)) - - -def tp_write(fd, buf): - """Write bytes from buffer *buf* to file descriptor *fd*. Return the - number of bytes written. - - Writing is done using the threadpool. - """ - return get_hub().threadpool.apply(_write, (fd, buf)) - - -if hasattr(os, 'fork'): - # pylint:disable=function-redefined,redefined-outer-name - - _raw_fork = os.fork - - def fork_gevent(): - """ - Forks the process using :func:`os.fork` and prepares the - child process to continue using gevent before returning. - - .. note:: - - The PID returned by this function may not be waitable with - either the original :func:`os.waitpid` or this module's - :func:`waitpid` and it may not generate SIGCHLD signals if - libev child watchers are or ever have been in use. For - example, the :mod:`gevent.subprocess` module uses libev - child watchers (which parts of gevent use libev child - watchers is subject to change at any time). Most - applications should use :func:`fork_and_watch`, which is - monkey-patched as the default replacement for - :func:`os.fork` and implements the ``fork`` function of - this module by default, unless the environment variable - ``GEVENT_NOWAITPID`` is defined before this module is - imported. - - .. versionadded:: 1.1b2 - """ - import warnings - # The simple `catch_warnings(action='ignore', category=DeprecationWarning)` - # is only available in 3.11+. - with warnings.catch_warnings(): - warnings.simplefilter('ignore', DeprecationWarning) - result = _raw_fork() - if not result: - reinit() - return result - - def fork(): - """ - A wrapper for :func:`fork_gevent` for non-POSIX platforms. - """ - return fork_gevent() - - if hasattr(os, 'forkpty'): - _raw_forkpty = os.forkpty - - def forkpty_gevent(): - """ - Forks the process using :func:`os.forkpty` and prepares the - child process to continue using gevent before returning. - - Returns a tuple (pid, master_fd). The `master_fd` is *not* put into - non-blocking mode. - - Availability: Some Unix systems. - - .. seealso:: This function has the same limitations as :func:`fork_gevent`. - - .. versionadded:: 1.1b5 - """ - pid, master_fd = _raw_forkpty() - if not pid: - reinit() - return pid, master_fd - - forkpty = forkpty_gevent - - __implements__.append('forkpty') - __extensions__.append("forkpty_gevent") - - if hasattr(os, 'WNOWAIT') or hasattr(os, 'WNOHANG'): - # We can only do this on POSIX - import time - - _waitpid = os.waitpid - _WNOHANG = os.WNOHANG - - # replaced by the signal module. - _on_child_hook = lambda: None - - # {pid -> watcher or tuple(pid, rstatus, timestamp)} - _watched_children = {} - - def _on_child(watcher, callback): - # XXX: Could handle tracing here by not stopping - # until the pid is terminated - watcher.stop() - try: - _watched_children[watcher.pid] = (watcher.pid, watcher.rstatus, time.time()) - if callback: - callback(watcher) - # dispatch an "event"; used by gevent.signal.signal - _on_child_hook() - # now is as good a time as any to reap children - _reap_children() - finally: - watcher.close() - - def _reap_children(timeout=60): - # Remove all the dead children that haven't been waited on - # for the *timeout* seconds. - # Some platforms queue delivery of SIGCHLD for all children that die; - # in that case, a well-behaved application should call waitpid() for each - # signal. - # Some platforms (linux) only guarantee one delivery if multiple children - # die. On that platform, the well-behave application calls waitpid() in a loop - # until it gets back -1, indicating no more dead children need to be waited for. - # In either case, waitpid should be called the same number of times as dead children, - # thus removing all the watchers when a SIGCHLD arrives. The (generous) timeout - # is to work with applications that neglect to call waitpid and prevent "unlimited" - # growth. - # Note that we don't watch for the case of pid wraparound. That is, we fork a new - # child with the same pid as an existing watcher, but the child is already dead, - # just not waited on yet. - now = time.time() - oldest_allowed = now - timeout - dead = [ - pid for pid, val - in _watched_children.items() - if isinstance(val, tuple) and val[2] < oldest_allowed - ] - for pid in dead: - del _watched_children[pid] - - def waitpid(pid, options): - """ - Wait for a child process to finish. - - If the child process was spawned using - :func:`fork_and_watch`, then this function behaves - cooperatively. If not, it *may* have race conditions; see - :func:`fork_gevent` for more information. - - The arguments are as for the underlying - :func:`os.waitpid`. Some combinations of *options* may not - be supported cooperatively (as of 1.1 that includes - WUNTRACED). Using a *pid* of 0 to request waiting on only processes - from the current process group is not cooperative. A *pid* of -1 - to wait for any child is non-blocking, but may or may not - require a trip around the event loop, depending on whether any children - have already terminated but not been waited on. - - Availability: POSIX. - - .. versionadded:: 1.1b1 - .. versionchanged:: 1.2a1 - More cases are handled in a cooperative manner. - """ - # pylint: disable=too-many-return-statements - # XXX Does not handle tracing children - - # So long as libev's loop doesn't run, it's OK to add - # child watchers. The SIGCHLD handler only feeds events - # for the next iteration of the loop to handle. (And the - # signal handler itself is only called from the next loop - # iteration.) - - if pid <= 0: - # magic functions for multiple children. - if pid == -1: - # Any child. If we have one that we're watching - # and that finished, we will use that one, - # preferring the oldest. Otherwise, let the OS - # take care of it. - finished_at = None - for k, v in _watched_children.items(): - if ( - isinstance(v, tuple) - and (finished_at is None or v[2] < finished_at) - ): - pid = k - finished_at = v[2] - - if pid <= 0: - # We didn't have one that was ready. If there are - # no funky options set, and the pid was -1 - # (meaning any process, not 0, which means process - # group--- libev doesn't know about process - # groups) then we can use a child watcher of pid 0; otherwise, - # pass through to the OS. - if pid == -1 and options == 0: - hub = get_hub() - with hub.loop.child(0, False) as watcher: - hub.wait(watcher) - return watcher.rpid, watcher.rstatus - # There were funky options/pid, so we must go to the OS. - return _waitpid(pid, options) - - if pid in _watched_children: - # yes, we're watching it - - # Note that the remainder of this code must be careful to NOT - # yield to the event loop except at well known times, or - # we have a race condition between the _on_child callback and the - # code here that could lead to a process to hang. - if options & _WNOHANG or isinstance(_watched_children[pid], tuple): - # We're either asked not to block, or it already finished, in which - # case blocking doesn't matter - result = _watched_children[pid] - if isinstance(result, tuple): - # it finished. libev child watchers - # are one-shot - del _watched_children[pid] - return result[:2] - # it's not finished - return (0, 0) - - # Ok, we need to "block". Do so via a watcher so that we're - # cooperative. We know it's our child, etc, so this should work. - watcher = _watched_children[pid] - # We can't start a watcher that's already started, - # so we can't reuse the existing watcher. Notice that the - # old watcher must not have fired already, or during this time, but - # only after we successfully `start()` the watcher. So this must - # not yield to the event loop. - with watcher.loop.child(pid, False) as new_watcher: - get_hub().wait(new_watcher) - # Ok, so now the new watcher is done. That means - # the old watcher's callback (_on_child) should - # have fired, potentially taking this child out of - # _watched_children (but that could depend on how - # many callbacks there were to run, so use the - # watcher object directly; libev sets all the - # watchers at the same time). - return watcher.rpid, watcher.rstatus - - # we're not watching it and it may not even be our child, - # so we must go to the OS to be sure to get the right semantics (exception) - # XXX - # libuv has a race condition because the signal - # handler is a Python function, so the InterruptedError - # is raised before the signal handler runs and calls the - # child watcher - # we're not watching it - return _waitpid(pid, options) - - def _watch_child(pid, callback=None, loop=None, ref=False): - loop = loop or get_hub().loop - watcher = loop.child(pid, ref=ref) - _watched_children[pid] = watcher - watcher.start(_on_child, watcher, callback) - - def fork_and_watch(callback=None, loop=None, ref=False, fork=fork_gevent): - """ - Fork a child process and start a child watcher for it in the parent process. - - This call cooperates with :func:`waitpid` to enable cooperatively waiting - for children to finish. When monkey-patching, these functions are patched in as - :func:`os.fork` and :func:`os.waitpid`, respectively. - - In the child process, this function calls :func:`gevent.hub.reinit` before returning. - - Availability: POSIX. - - :keyword callback: If given, a callable that will be called with the child watcher - when the child finishes. - :keyword loop: The loop to start the watcher in. Defaults to the - loop of the current hub. - :keyword fork: The fork function. Defaults to :func:`the one defined in this - module ` (which automatically calls :func:`gevent.hub.reinit`). - Pass the builtin :func:`os.fork` function if you do not need to - initialize gevent in the child process. - - .. versionadded:: 1.1b1 - .. seealso:: - :func:`gevent.monkey.get_original` To access the builtin :func:`os.fork`. - """ - pid = fork() - if pid: - # parent - _watch_child(pid, callback, loop, ref) - return pid - - __extensions__.append('fork_and_watch') - __extensions__.append('fork_gevent') - - if 'forkpty' in __implements__: - def forkpty_and_watch(callback=None, loop=None, ref=False, forkpty=forkpty_gevent): - """ - Like :func:`fork_and_watch`, except using :func:`forkpty_gevent`. - - Availability: Some Unix systems. - - .. versionadded:: 1.1b5 - """ - result = [] - - def _fork(): - pid_and_fd = forkpty() - result.append(pid_and_fd) - return pid_and_fd[0] - fork_and_watch(callback, loop, ref, _fork) - return result[0] - - __extensions__.append('forkpty_and_watch') - - # Watch children by default - if not config.disable_watch_children: - # Broken out into separate functions instead of simple name aliases - # for documentation purposes. - def fork(*args, **kwargs): - """ - Forks a child process and starts a child watcher for it in the - parent process so that ``waitpid`` and SIGCHLD work as expected. - - This implementation of ``fork`` is a wrapper for :func:`fork_and_watch` - when the environment variable ``GEVENT_NOWAITPID`` is *not* defined. - This is the default and should be used by most applications. - - .. versionchanged:: 1.1b2 - """ - # take any args to match fork_and_watch - return fork_and_watch(*args, **kwargs) - - if 'forkpty' in __implements__: - def forkpty(*args, **kwargs): - """ - Like :func:`fork`, but using :func:`forkpty_gevent`. - - This implementation of ``forkpty`` is a wrapper for :func:`forkpty_and_watch` - when the environment variable ``GEVENT_NOWAITPID`` is *not* defined. - This is the default and should be used by most applications. - - .. versionadded:: 1.1b5 - """ - # take any args to match fork_and_watch - return forkpty_and_watch(*args, **kwargs) - __implements__.append("waitpid") - - if hasattr(os, 'posix_spawn'): - _raw_posix_spawn = os.posix_spawn - _raw_posix_spawnp = os.posix_spawnp - - def posix_spawn(*args, **kwargs): - pid = _raw_posix_spawn(*args, **kwargs) - _watch_child(pid) - return pid - - def posix_spawnp(*args, **kwargs): - pid = _raw_posix_spawnp(*args, **kwargs) - _watch_child(pid) - return pid - - __implements__.append("posix_spawn") - __implements__.append("posix_spawnp") - else: - def fork(): - """ - Forks a child process, initializes gevent in the child, - but *does not* prepare the parent to wait for the child or receive SIGCHLD. - - This implementation of ``fork`` is a wrapper for :func:`fork_gevent` - when the environment variable ``GEVENT_NOWAITPID`` *is* defined. - This is not recommended for most applications. - """ - return fork_gevent() - - if 'forkpty' in __implements__: - def forkpty(): - """ - Like :func:`fork`, but using :func:`os.forkpty` - - This implementation of ``forkpty`` is a wrapper for :func:`forkpty_gevent` - when the environment variable ``GEVENT_NOWAITPID`` *is* defined. - This is not recommended for most applications. - - .. versionadded:: 1.1b5 - """ - return forkpty_gevent() - __extensions__.append("waitpid") - -else: - __implements__.remove('fork') - - -__imports__ = copy_globals(os, globals(), - names_to_ignore=__implements__ + __extensions__, - dunder_names_to_keep=()) - -__all__ = list(set(__implements__ + __extensions__)) diff --git a/venv/lib/python3.9/site-packages/gevent/pool.py b/venv/lib/python3.9/site-packages/gevent/pool.py deleted file mode 100644 index 4119579..0000000 --- a/venv/lib/python3.9/site-packages/gevent/pool.py +++ /dev/null @@ -1,677 +0,0 @@ -# Copyright (c) 2009-2011 Denis Bilenko. See LICENSE for details. -""" -Managing greenlets in a group. - -The :class:`Group` class in this module abstracts a group of running -greenlets. When a greenlet dies, it's automatically removed from the -group. All running greenlets in a group can be waited on with -:meth:`Group.join`, or all running greenlets can be killed with -:meth:`Group.kill`. - -The :class:`Pool` class, which is a subclass of :class:`Group`, -provides a way to limit concurrency: its :meth:`spawn ` -method blocks if the number of greenlets in the pool has already -reached the limit, until there is a free slot. -""" -from __future__ import print_function, absolute_import, division - - -from gevent.hub import GreenletExit, getcurrent, kill as _kill -from gevent.greenlet import joinall, Greenlet -from gevent.queue import Full as QueueFull -from gevent.timeout import Timeout -from gevent.event import Event -from gevent.lock import Semaphore, DummySemaphore - -from gevent._compat import izip -from gevent._imap import IMap -from gevent._imap import IMapUnordered - -__all__ = [ - 'Group', - 'Pool', - 'PoolFull', -] - - - - -class GroupMappingMixin(object): - # Internal, non-public API class. - # Provides mixin methods for implementing mapping pools. Subclasses must define: - - __slots__ = () - - def spawn(self, func, *args, **kwargs): - """ - A function that runs *func* with *args* and *kwargs*, potentially - asynchronously. Return a value with a ``get`` method that blocks - until the results of func are available, and a ``rawlink`` method - that calls a callback when the results are available. - - If this object has an upper bound on how many asyncronously executing - tasks can exist, this method may block until a slot becomes available. - """ - raise NotImplementedError() - - def _apply_immediately(self): - """ - should the function passed to apply be called immediately, - synchronously? - """ - raise NotImplementedError() - - def _apply_async_use_greenlet(self): - """ - Should apply_async directly call Greenlet.spawn(), bypassing - `spawn`? - - Return true when self.spawn would block. - """ - raise NotImplementedError() - - def _apply_async_cb_spawn(self, callback, result): - """ - Run the given callback function, possibly - asynchronously, possibly synchronously. - """ - raise NotImplementedError() - - def apply_cb(self, func, args=None, kwds=None, callback=None): - """ - :meth:`apply` the given *func(\\*args, \\*\\*kwds)*, and, if a *callback* is given, run it with the - results of *func* (unless an exception was raised.) - - The *callback* may be called synchronously or asynchronously. If called - asynchronously, it will not be tracked by this group. (:class:`Group` and :class:`Pool` - call it asynchronously in a new greenlet; :class:`~gevent.threadpool.ThreadPool` calls - it synchronously in the current greenlet.) - """ - result = self.apply(func, args, kwds) - if callback is not None: - self._apply_async_cb_spawn(callback, result) - return result - - def apply_async(self, func, args=None, kwds=None, callback=None): - """ - A variant of the :meth:`apply` method which returns a :class:`~.Greenlet` object. - - When the returned greenlet gets to run, it *will* call :meth:`apply`, - passing in *func*, *args* and *kwds*. - - If *callback* is specified, then it should be a callable which - accepts a single argument. When the result becomes ready - callback is applied to it (unless the call failed). - - This method will never block, even if this group is full (that is, - even if :meth:`spawn` would block, this method will not). - - .. caution:: The returned greenlet may or may not be tracked - as part of this group, so :meth:`joining ` this group is - not a reliable way to wait for the results to be available or - for the returned greenlet to run; instead, join the returned - greenlet. - - .. tip:: Because :class:`~.ThreadPool` objects do not track greenlets, the returned - greenlet will never be a part of it. To reduce overhead and improve performance, - :class:`Group` and :class:`Pool` may choose to track the returned - greenlet. These are implementation details that may change. - """ - if args is None: - args = () - if kwds is None: - kwds = {} - if self._apply_async_use_greenlet(): - # cannot call self.spawn() directly because it will block - # XXX: This is always the case for ThreadPool, but for Group/Pool - # of greenlets, this is only the case when they are full...hence - # the weasely language about "may or may not be tracked". Should we make - # Group/Pool always return true as well so it's never tracked by any - # implementation? That would simplify that logic, but could increase - # the total number of greenlets in the system and add a layer of - # overhead for the simple cases when the pool isn't full. - return Greenlet.spawn(self.apply_cb, func, args, kwds, callback) - - greenlet = self.spawn(func, *args, **kwds) - if callback is not None: - greenlet.link(pass_value(callback)) - return greenlet - - def apply(self, func, args=None, kwds=None): - """ - Rough quivalent of the :func:`apply()` builtin function blocking until - the result is ready and returning it. - - The ``func`` will *usually*, but not *always*, be run in a way - that allows the current greenlet to switch out (for example, - in a new greenlet or thread, depending on implementation). But - if the current greenlet or thread is already one that was - spawned by this pool, the pool may choose to immediately run - the `func` synchronously. - - Any exception ``func`` raises will be propagated to the caller of ``apply`` (that is, - this method will raise the exception that ``func`` raised). - """ - if args is None: - args = () - if kwds is None: - kwds = {} - if self._apply_immediately(): - return func(*args, **kwds) - return self.spawn(func, *args, **kwds).get() - - def __map(self, func, iterable): - return [g.get() for g in - [self.spawn(func, i) for i in iterable]] - - def map(self, func, iterable): - """Return a list made by applying the *func* to each element of - the iterable. - - .. seealso:: :meth:`imap` - """ - # We can't return until they're all done and in order. It - # wouldn't seem to much matter what order we wait on them in, - # so the simple, fast (50% faster than imap) solution would be: - - # return [g.get() for g in - # [self.spawn(func, i) for i in iterable]] - - # If the pool size is unlimited (or more than the len(iterable)), this - # is equivalent to imap (spawn() will never block, all of them run concurrently, - # we call get() in the order the iterable was given). - - # Now lets imagine the pool if is limited size. Suppose the - # func is time.sleep, our pool is limited to 3 threads, and - # our input is [10, 1, 10, 1, 1] We would start three threads, - # one to sleep for 10, one to sleep for 1, and the last to - # sleep for 10. We would block starting the fourth thread. At - # time 1, we would finish the second thread and start another - # one for time 1. At time 2, we would finish that one and - # start the last thread, and then begin executing get() on the first - # thread. - - # Because it's spawn that blocks, this is *also* equivalent to what - # imap would do. - - # The one remaining difference is that imap runs in its own - # greenlet, potentially changing the way the event loop runs. - # That's easy enough to do. - - g = Greenlet.spawn(self.__map, func, iterable) - return g.get() - - def map_cb(self, func, iterable, callback=None): - result = self.map(func, iterable) - if callback is not None: - callback(result) # pylint:disable=not-callable - return result - - def map_async(self, func, iterable, callback=None): - """ - A variant of the map() method which returns a Greenlet object that is executing - the map function. - - If callback is specified then it should be a callable which accepts a - single argument. - """ - return Greenlet.spawn(self.map_cb, func, iterable, callback) - - def __imap(self, cls, func, *iterables, **kwargs): - # Python 2 doesn't support the syntax that lets us mix varargs and - # a named kwarg, so we have to unpack manually - maxsize = kwargs.pop('maxsize', None) - if kwargs: - raise TypeError("Unsupported keyword arguments") - return cls.spawn(func, izip(*iterables), spawn=self.spawn, - _zipped=True, maxsize=maxsize) - - def imap(self, func, *iterables, **kwargs): - """ - imap(func, *iterables, maxsize=None) -> iterable - - An equivalent of :func:`itertools.imap`, operating in parallel. - The *func* is applied to each element yielded from each - iterable in *iterables* in turn, collecting the result. - - If this object has a bound on the number of active greenlets it can - contain (such as :class:`Pool`), then at most that number of tasks will operate - in parallel. - - :keyword int maxsize: If given and not-None, specifies the maximum number of - finished results that will be allowed to accumulate awaiting the reader; - more than that number of results will cause map function greenlets to begin - to block. This is most useful if there is a great disparity in the speed of - the mapping code and the consumer and the results consume a great deal of resources. - - .. note:: This is separate from any bound on the number of active parallel - tasks, though they may have some interaction (for example, limiting the - number of parallel tasks to the smallest bound). - - .. note:: Using a bound is slightly more computationally expensive than not using a bound. - - .. tip:: The :meth:`imap_unordered` method makes much better - use of this parameter. Some additional, unspecified, - number of objects may be required to be kept in memory - to maintain order by this function. - - :return: An iterable object. - - .. versionchanged:: 1.1b3 - Added the *maxsize* keyword parameter. - .. versionchanged:: 1.1a1 - Accept multiple *iterables* to iterate in parallel. - """ - return self.__imap(IMap, func, *iterables, **kwargs) - - def imap_unordered(self, func, *iterables, **kwargs): - """ - imap_unordered(func, *iterables, maxsize=None) -> iterable - - The same as :meth:`imap` except that the ordering of the results - from the returned iterator should be considered in arbitrary - order. - - This is lighter weight than :meth:`imap` and should be preferred if order - doesn't matter. - - .. seealso:: :meth:`imap` for more details. - """ - return self.__imap(IMapUnordered, func, *iterables, **kwargs) - - -class Group(GroupMappingMixin): - """ - Maintain a group of greenlets that are still running, without - limiting their number. - - Links to each item and removes it upon notification. - - Groups can be iterated to discover what greenlets they are tracking, - they can be tested to see if they contain a greenlet, and they know the - number (len) of greenlets they are tracking. If they are not tracking any - greenlets, they are False in a boolean context. - - .. attribute:: greenlet_class - - Either :class:`gevent.Greenlet` (the default) or a subclass. - These are the type of - object we will :meth:`spawn`. This can be - changed on an instance or in a subclass. - """ - - greenlet_class = Greenlet - - def __init__(self, *args): - assert len(args) <= 1, args - self.greenlets = set(*args) - if args: - for greenlet in args[0]: - greenlet.rawlink(self._discard) - # each item we kill we place in dying, to avoid killing the same greenlet twice - self.dying = set() - self._empty_event = Event() - self._empty_event.set() - - def __repr__(self): - return '<%s at 0x%x %s>' % (self.__class__.__name__, id(self), self.greenlets) - - def __len__(self): - """ - Answer how many greenlets we are tracking. Note that if we are empty, - we are False in a boolean context. - """ - return len(self.greenlets) - - def __contains__(self, item): - """ - Answer if we are tracking the given greenlet. - """ - return item in self.greenlets - - def __iter__(self): - """ - Iterate across all the greenlets we are tracking, in no particular order. - """ - return iter(self.greenlets) - - def add(self, greenlet): - """ - Begin tracking the *greenlet*. - - If this group is :meth:`full`, then this method may block - until it is possible to track the greenlet. - - Typically the *greenlet* should **not** be started when - it is added because if this object blocks in this method, - then the *greenlet* may run to completion before it is tracked. - """ - try: - rawlink = greenlet.rawlink - except AttributeError: - pass # non-Greenlet greenlet, like MAIN - else: - rawlink(self._discard) - self.greenlets.add(greenlet) - self._empty_event.clear() - - def _discard(self, greenlet): - self.greenlets.discard(greenlet) - self.dying.discard(greenlet) - if not self.greenlets: - self._empty_event.set() - - def discard(self, greenlet): - """ - Stop tracking the greenlet. - """ - self._discard(greenlet) - try: - unlink = greenlet.unlink - except AttributeError: - pass # non-Greenlet greenlet, like MAIN - else: - unlink(self._discard) - - def start(self, greenlet): - """ - Add the **unstarted** *greenlet* to the collection of greenlets - this group is monitoring, and then start it. - """ - self.add(greenlet) - greenlet.start() - - def spawn(self, *args, **kwargs): # pylint:disable=arguments-differ - """ - Begin a new greenlet with the given arguments (which are passed - to the greenlet constructor) and add it to the collection of greenlets - this group is monitoring. - - :return: The newly started greenlet. - """ - greenlet = self.greenlet_class(*args, **kwargs) - self.start(greenlet) - return greenlet - -# def close(self): -# """Prevents any more tasks from being submitted to the pool""" -# self.add = RaiseException("This %s has been closed" % self.__class__.__name__) - - def join(self, timeout=None, raise_error=False): - """ - Wait for this group to become empty *at least once*. - - If there are no greenlets in the group, returns immediately. - - .. note:: By the time the waiting code (the caller of this - method) regains control, a greenlet may have been added to - this group, and so this object may no longer be empty. (That - is, ``group.join(); assert len(group) == 0`` is not - guaranteed to hold.) This method only guarantees that the group - reached a ``len`` of 0 at some point. - - :keyword bool raise_error: If True (*not* the default), if any - greenlet that finished while the join was in progress raised - an exception, that exception will be raised to the caller of - this method. If multiple greenlets raised exceptions, which - one gets re-raised is not determined. Only greenlets currently - in the group when this method is called are guaranteed to - be checked for exceptions. - - :return bool: A value indicating whether this group became empty. - If the timeout is specified and the group did not become empty - during that timeout, then this will be a false value. Otherwise - it will be a true value. - - .. versionchanged:: 1.2a1 - Add the return value. - """ - greenlets = list(self.greenlets) if raise_error else () - result = self._empty_event.wait(timeout=timeout) - - for greenlet in greenlets: - if greenlet.exception is not None: - if hasattr(greenlet, '_raise_exception'): - greenlet._raise_exception() - raise greenlet.exception - - return result - - def kill(self, exception=GreenletExit, block=True, timeout=None): - """ - Kill all greenlets being tracked by this group. - """ - timer = Timeout._start_new_or_dummy(timeout) - try: - while self.greenlets: - for greenlet in list(self.greenlets): - if greenlet in self.dying: - continue - try: - kill = greenlet.kill - except AttributeError: - _kill(greenlet, exception) - else: - kill(exception, block=False) - self.dying.add(greenlet) - if not block: - break - joinall(self.greenlets) - except Timeout as ex: - if ex is not timer: - raise - finally: - timer.cancel() - - def killone(self, greenlet, exception=GreenletExit, block=True, timeout=None): - """ - If the given *greenlet* is running and being tracked by this group, - kill it. - """ - if greenlet not in self.dying and greenlet in self.greenlets: - greenlet.kill(exception, block=False) - self.dying.add(greenlet) - if block: - greenlet.join(timeout) - - def full(self): - """ - Return a value indicating whether this group can track more greenlets. - - In this implementation, because there are no limits on the number of - tracked greenlets, this will always return a ``False`` value. - """ - return False - - def wait_available(self, timeout=None): - """ - Block until it is possible to :meth:`spawn` a new greenlet. - - In this implementation, because there are no limits on the number - of tracked greenlets, this will always return immediately. - """ - - # MappingMixin methods - - def _apply_immediately(self): - # If apply() is called from one of our own - # worker greenlets, don't spawn a new one---if we're full, that - # could deadlock. - return getcurrent() in self - - def _apply_async_cb_spawn(self, callback, result): - Greenlet.spawn(callback, result) - - def _apply_async_use_greenlet(self): - # cannot call self.spawn() because it will block, so - # use a fresh, untracked greenlet that when run will - # (indirectly) call self.spawn() for us. - return self.full() - - - -class PoolFull(QueueFull): - """ - Raised when a Pool is full and an attempt was made to - add a new greenlet to it in non-blocking mode. - """ - - -class Pool(Group): - - def __init__(self, size=None, greenlet_class=None): - """ - Create a new pool. - - A pool is like a group, but the maximum number of members - is governed by the *size* parameter. - - :keyword int size: If given, this non-negative integer is the - maximum count of active greenlets that will be allowed in - this pool. A few values have special significance: - - * `None` (the default) places no limit on the number of - greenlets. This is useful when you want to track, but not limit, - greenlets. In general, a :class:`Group` - may be a more efficient way to achieve the same effect, but some things - need the additional abilities of this class (one example being the *spawn* - parameter of :class:`gevent.baseserver.BaseServer` and - its subclass :class:`gevent.pywsgi.WSGIServer`). - - * ``0`` creates a pool that can never have any active greenlets. Attempting - to spawn in this pool will block forever. This is only useful - if an application uses :meth:`wait_available` with a timeout and checks - :meth:`free_count` before attempting to spawn. - """ - if size is not None and size < 0: - raise ValueError('size must not be negative: %r' % (size, )) - Group.__init__(self) - self.size = size - if greenlet_class is not None: - self.greenlet_class = greenlet_class - if size is None: - factory = DummySemaphore - else: - factory = Semaphore - self._semaphore = factory(size) - - def wait_available(self, timeout=None): - """ - Wait until it's possible to spawn a greenlet in this pool. - - :param float timeout: If given, only wait the specified number - of seconds. - - .. warning:: If the pool was initialized with a size of 0, this - method will block forever unless a timeout is given. - - :return: A number indicating how many new greenlets can be put into - the pool without blocking. - - .. versionchanged:: 1.1a3 - Added the ``timeout`` parameter. - """ - return self._semaphore.wait(timeout=timeout) - - def full(self): - """ - Return a boolean indicating whether this pool is full, e.g. if - :meth:`add` would block. - - :return: False if there is room for new members, True if there isn't. - """ - return self.free_count() <= 0 - - def free_count(self): - """ - Return a number indicating *approximately* how many more members - can be added to this pool. - """ - if self.size is None: - return 1 - return max(0, self.size - len(self)) - - def start(self, greenlet, *args, **kwargs): # pylint:disable=arguments-differ - """ - start(greenlet, blocking=True, timeout=None) -> None - - Add the **unstarted** *greenlet* to the collection of greenlets - this group is monitoring and then start it. - - Parameters are as for :meth:`add`. - """ - self.add(greenlet, *args, **kwargs) - greenlet.start() - - def add(self, greenlet, blocking=True, timeout=None): # pylint:disable=arguments-differ - """ - Begin tracking the given **unstarted** greenlet, possibly blocking - until space is available. - - Usually you should call :meth:`start` to track and start the greenlet - instead of using this lower-level method, or :meth:`spawn` to - also create the greenlet. - - :keyword bool blocking: If True (the default), this function - will block until the pool has space or a timeout occurs. If - False, this function will immediately raise a Timeout if the - pool is currently full. - :keyword float timeout: The maximum number of seconds this - method will block, if ``blocking`` is True. (Ignored if - ``blocking`` is False.) - :raises PoolFull: if either ``blocking`` is False and the pool - was full, or if ``blocking`` is True and ``timeout`` was - exceeded. - - .. caution:: If the *greenlet* has already been started and - *blocking* is true, then the greenlet may run to completion - while the current greenlet blocks waiting to track it. This would - enable higher concurrency than desired. - - .. seealso:: :meth:`Group.add` - - .. versionchanged:: 1.3.0 Added the ``blocking`` and - ``timeout`` parameters. - """ - if not self._semaphore.acquire(blocking=blocking, timeout=timeout): - # We failed to acquire the semaphore. - # If blocking was True, then there was a timeout. If blocking was - # False, then there was no capacity. Either way, raise PoolFull. - raise PoolFull() - - try: - Group.add(self, greenlet) - except: - self._semaphore.release() - raise - - def _discard(self, greenlet): - Group._discard(self, greenlet) - self._semaphore.release() - - -class pass_value(object): - __slots__ = ['callback'] - - def __init__(self, callback): - self.callback = callback - - def __call__(self, source): - if source.successful(): - self.callback(source.value) - - def __hash__(self): - return hash(self.callback) - - def __eq__(self, other): - return self.callback == getattr(other, 'callback', other) - - def __str__(self): - return str(self.callback) - - def __repr__(self): - return repr(self.callback) - - def __getattr__(self, item): - assert item != 'callback' - return getattr(self.callback, item) diff --git a/venv/lib/python3.9/site-packages/gevent/pywsgi.py b/venv/lib/python3.9/site-packages/gevent/pywsgi.py deleted file mode 100644 index e3581fa..0000000 --- a/venv/lib/python3.9/site-packages/gevent/pywsgi.py +++ /dev/null @@ -1,1731 +0,0 @@ -# Copyright (c) 2005-2009, eventlet contributors -# Copyright (c) 2009-2018, gevent contributors -""" -A pure-Python, gevent-friendly WSGI server implementing HTTP/1.1. - -The server is provided in :class:`WSGIServer`, but most of the actual -WSGI work is handled by :class:`WSGIHandler` --- a new instance is -created for each request. The server can be customized to use -different subclasses of :class:`WSGIHandler`. - -.. important:: - - This server is intended primarily for development and testing, and - secondarily for other "safe" scenarios where it will not be exposed to - potentially malicious input. The code has not been security audited, - and is not intended for direct exposure to the public Internet. For production - usage on the Internet, either choose a production-strength server such as - gunicorn, or put a reverse proxy between gevent and the Internet. - -.. versionchanged:: 23.9.0 - - Complies more closely with the HTTP specification for chunked transfer encoding. - In particular, we are much stricter about trailers, and trailers that - are invalid (too long or featuring disallowed characters) forcibly close - the connection to the client *after* the results have been sent. - - Trailers otherwise continue to be ignored and are not available to the - WSGI application. - -""" -from __future__ import absolute_import - -# FIXME: Can we refactor to make smallor? -# pylint:disable=too-many-lines - -import errno -from io import BytesIO -import string -import sys -import time -import traceback -from datetime import datetime - -from urllib.parse import unquote - -from gevent import socket -import gevent -from gevent.server import StreamServer -from gevent.hub import GreenletExit -from gevent._compat import reraise - -from functools import partial -unquote_latin1 = partial(unquote, encoding='latin-1') - -_no_undoc_members = True # Don't put undocumented things into sphinx - -__all__ = [ - 'WSGIServer', - 'WSGIHandler', - 'LoggingLogAdapter', - 'Environ', - 'SecureEnviron', - 'WSGISecureEnviron', -] - - -MAX_REQUEST_LINE = 8192 -# Weekday and month names for HTTP date/time formatting; always English! -_WEEKDAYNAME = ("Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun") -_MONTHNAME = (None, # Dummy so we can use 1-based month numbers - "Jan", "Feb", "Mar", "Apr", "May", "Jun", - "Jul", "Aug", "Sep", "Oct", "Nov", "Dec") - -# The contents of the "HEX" grammar rule for HTTP, upper and lowercase A-F plus digits, -# in byte form for comparing to the network. -_HEX = string.hexdigits.encode('ascii') - -# The characters allowed in "token" rules. - -# token = 1*tchar -# tchar = "!" / "#" / "$" / "%" / "&" / "'" / "*" -# / "+" / "-" / "." / "^" / "_" / "`" / "|" / "~" -# / DIGIT / ALPHA -# ; any VCHAR, except delimiters -# ALPHA = %x41-5A / %x61-7A ; A-Z / a-z -_ALLOWED_TOKEN_CHARS = frozenset( - # Remember we have to be careful because bytestrings - # inexplicably iterate as integers, which are not equal to bytes. - - # explicit chars then DIGIT - (c.encode('ascii') for c in "!#$%&'*+-.^_`|~0123456789") - # Then we add ALPHA -) | {c.encode('ascii') for c in string.ascii_letters} -assert b'A' in _ALLOWED_TOKEN_CHARS - - -# Errors -_ERRORS = {} -_INTERNAL_ERROR_STATUS = '500 Internal Server Error' -_INTERNAL_ERROR_BODY = b'Internal Server Error' -_INTERNAL_ERROR_HEADERS = ( - ('Content-Type', 'text/plain'), - ('Connection', 'close'), - ('Content-Length', str(len(_INTERNAL_ERROR_BODY))) -) -_ERRORS[500] = (_INTERNAL_ERROR_STATUS, _INTERNAL_ERROR_HEADERS, _INTERNAL_ERROR_BODY) - -_BAD_REQUEST_STATUS = '400 Bad Request' -_BAD_REQUEST_BODY = '' -_BAD_REQUEST_HEADERS = ( - ('Content-Type', 'text/plain'), - ('Connection', 'close'), - ('Content-Length', str(len(_BAD_REQUEST_BODY))) -) -_ERRORS[400] = (_BAD_REQUEST_STATUS, _BAD_REQUEST_HEADERS, _BAD_REQUEST_BODY) - -_REQUEST_TOO_LONG_RESPONSE = b"HTTP/1.1 414 Request URI Too Long\r\nConnection: close\r\nContent-length: 0\r\n\r\n" -_BAD_REQUEST_RESPONSE = b"HTTP/1.1 400 Bad Request\r\nConnection: close\r\nContent-length: 0\r\n\r\n" -_CONTINUE_RESPONSE = b"HTTP/1.1 100 Continue\r\n\r\n" - - -def format_date_time(timestamp): - # Return a byte-string of the date and time in HTTP format - # .. versionchanged:: 1.1b5 - # Return a byte string, not a native string - year, month, day, hh, mm, ss, wd, _y, _z = time.gmtime(timestamp) - value = "%s, %02d %3s %4d %02d:%02d:%02d GMT" % (_WEEKDAYNAME[wd], day, _MONTHNAME[month], year, hh, mm, ss) - value = value.encode("latin-1") - return value - - -class _InvalidClientInput(IOError): - # Internal exception raised by Input indicating that the client - # sent invalid data at the lowest level of the stream. The result - # *should* be a HTTP 400 error. - pass - - -class _InvalidClientRequest(ValueError): - # Internal exception raised by WSGIHandler.read_request indicating - # that the client sent an HTTP request that cannot be parsed - # (e.g., invalid grammar). The result *should* be an HTTP 400 - # error. It must have exactly one argument, the fully formatted - # error string. - - def __init__(self, message): - ValueError.__init__(self, message) - self.formatted_message = message - - -class Input(object): - - __slots__ = ('rfile', 'content_length', 'socket', 'position', - 'chunked_input', 'chunk_length', '_chunked_input_error', - 'send_100_continue_enabled') - - def __init__(self, rfile, content_length, socket=None, chunked_input=False): - # pylint:disable=redefined-outer-name - self.rfile = rfile - self.content_length = content_length - self.socket = socket - self.position = 0 - self.chunked_input = chunked_input - self.chunk_length = -1 - self._chunked_input_error = False - self.send_100_continue_enabled = True - - def _discard(self): - if self._chunked_input_error: - # We are in an unknown state, so we can't necessarily discard - # the body (e.g., if the client keeps the socket open, we could hang - # here forever). - # In this case, we've raised an exception and the user of this object - # is going to close the socket, so we don't have to discard - return - - if self.position < (self.content_length or 0) or self.chunked_input: - self.send_100_continue_enabled = False - # ## Read and discard body - while 1: - d = self.read(16384) - if not d: - break - self.send_100_continue_enabled = True - - def _send_100_continue(self): - if self.send_100_continue_enabled and self.socket is not None: - self.socket.sendall(_CONTINUE_RESPONSE) - self.socket = None - - def _do_read(self, length=None, use_readline=False): - if use_readline: - reader = self.rfile.readline - else: - reader = self.rfile.read - content_length = self.content_length - if content_length is None: - # Either Content-Length or "Transfer-Encoding: chunked" must be present in a request with a body - # if it was chunked, then this function would have not been called - return b'' - - self._send_100_continue() - left = content_length - self.position - if length is None: - length = left - elif length > left: - length = left - if not length: - return b'' - - # On Python 2, self.rfile is usually socket.makefile(), which - # uses cStringIO.StringIO. If *length* is greater than the C - # sizeof(int) (typically 32 bits signed), parsing the argument to - # readline raises OverflowError. StringIO.read(), OTOH, uses - # PySize_t, typically a long (64 bits). In a bare readline() - # case, because the header lines we're trying to read with - # readline are typically expected to be small, we can correct - # that failure by simply doing a smaller call to readline and - # appending; failures in read we let propagate. - try: - read = reader(length) - except OverflowError: - if not use_readline: - # Expecting to read more than 64 bits of data. Ouch! - raise - # We could loop on calls to smaller readline(), appending them - # until we actually get a newline. For uses in this module, - # we expect the actual length to be small, but WSGI applications - # are allowed to pass in an arbitrary length. (This loop isn't optimal, - # but even client applications *probably* have short lines.) - read = b'' - while len(read) < length and not read.endswith(b'\n'): - read += reader(MAX_REQUEST_LINE) - - self.position += len(read) - if len(read) < length: - if (use_readline and not read.endswith(b"\n")) or not use_readline: - raise IOError("unexpected end of file while reading request at position %s" % (self.position,)) - - return read - - def __read_chunk_length(self, rfile): - # Read and return the next integer chunk length. If no - # chunk length can be read, raises _InvalidClientInput. - - # Here's the production for a chunk (actually the whole body): - # (https://www.rfc-editor.org/rfc/rfc7230#section-4.1) - - # chunked-body = *chunk - # last-chunk - # trailer-part - # CRLF - # - # chunk = chunk-size [ chunk-ext ] CRLF - # chunk-data CRLF - # chunk-size = 1*HEXDIG - # last-chunk = 1*("0") [ chunk-ext ] CRLF - # trailer-part = *( header-field CRLF ) - # chunk-data = 1*OCTET ; a sequence of chunk-size octets - # - # chunk-ext = *( ";" chunk-ext-name [ "=" chunk-ext-val ] ) - # - # chunk-ext-name = token - # chunk-ext-val = token / quoted-string - - # To cope with malicious or broken clients that fail to send - # valid chunk lines, the strategy is to read character by - # character until we either reach a ; or newline. If at any - # time we read a non-HEX digit, we bail. If we hit a ;, - # indicating an chunk-extension, we'll read up to the next - # MAX_REQUEST_LINE characters ("A server ought to limit the - # total length of chunk extensions received") looking for the - # CRLF, and if we don't find it, we bail. If we read more than - # 16 hex characters, (the number needed to represent a 64-bit - # chunk size), we bail (this protects us from a client that - # sends an infinite stream of `F`, for example). - - buf = BytesIO() - while 1: - char = rfile.read(1) - if not char: - self._chunked_input_error = True - raise _InvalidClientInput("EOF before chunk end reached") - - if char in ( - b'\r', # Beginning EOL - b';', # Beginning extension - ): - break - - if char not in _HEX: # Invalid data. - self._chunked_input_error = True - raise _InvalidClientInput("Non-hex data", char) - - buf.write(char) - - if buf.tell() > 16: # Too many hex bytes - self._chunked_input_error = True - raise _InvalidClientInput("Chunk-size too large.") - - if char == b';': - i = 0 - while i < MAX_REQUEST_LINE: - char = rfile.read(1) - if char == b'\r': - break - i += 1 - else: - # we read more than MAX_REQUEST_LINE without - # hitting CR - self._chunked_input_error = True - raise _InvalidClientInput("Too large chunk extension") - - if char == b'\r': - # We either got here from the main loop or from the - # end of an extension - self.__read_chunk_size_crlf(rfile, newline_only=True) - result = int(buf.getvalue(), 16) - if result == 0: - # The only time a chunk size of zero is allowed is the final - # chunk. It is either followed by another \r\n, or some trailers - # which are then followed by \r\n. - while self.__read_chunk_trailer(rfile): - pass - return result - - # Trailers have the following production (they are a header-field followed by CRLF) - # See above for the definition of "token". - # - # header-field = field-name ":" OWS field-value OWS - # field-name = token - # field-value = *( field-content / obs-fold ) - # field-content = field-vchar [ 1*( SP / HTAB ) field-vchar ] - # field-vchar = VCHAR / obs-text - # obs-fold = CRLF 1*( SP / HTAB ) - # ; obsolete line folding - # ; see Section 3.2.4 - - - def __read_chunk_trailer(self, rfile, ): - # With rfile positioned just after a \r\n, read a trailer line. - # Return a true value if a non-empty trailer was read, and - # return false if an empty trailer was read (meaning the trailers are - # done). - # If a single line exceeds the MAX_REQUEST_LINE, raise an exception. - # If the field-name portion contains invalid characters, raise an exception. - - i = 0 - empty = True - seen_field_name = False - while i < MAX_REQUEST_LINE: - char = rfile.read(1) - if char == b'\r': - # Either read the next \n or raise an error. - self.__read_chunk_size_crlf(rfile, newline_only=True) - break - # Not a \r, so we are NOT an empty chunk. - empty = False - if char == b':' and i > 0: - # We're ending the field-name part; stop validating characters. - # Unless : was the first character... - seen_field_name = True - if not seen_field_name and char not in _ALLOWED_TOKEN_CHARS: - raise _InvalidClientInput('Invalid token character: %r' % (char,)) - i += 1 - else: - # We read too much - self._chunked_input_error = True - raise _InvalidClientInput("Too large chunk trailer") - return not empty - - def __read_chunk_size_crlf(self, rfile, newline_only=False): - # Also for safety, correctly verify that we get \r\n when expected. - if not newline_only: - char = rfile.read(1) - if char != b'\r': - self._chunked_input_error = True - raise _InvalidClientInput("Line didn't end in CRLF: %r" % (char,)) - char = rfile.read(1) - if char != b'\n': - self._chunked_input_error = True - raise _InvalidClientInput("Line didn't end in LF: %r" % (char,)) - - def _chunked_read(self, length=None, use_readline=False): - # pylint:disable=too-many-branches - rfile = self.rfile - self._send_100_continue() - - if length == 0: - return b"" - - if use_readline: - reader = self.rfile.readline - else: - reader = self.rfile.read - - response = [] - while self.chunk_length != 0: - maxreadlen = self.chunk_length - self.position - if length is not None and length < maxreadlen: - maxreadlen = length - - if maxreadlen > 0: - data = reader(maxreadlen) - if not data: - self.chunk_length = 0 - self._chunked_input_error = True - raise IOError("unexpected end of file while parsing chunked data") - - datalen = len(data) - response.append(data) - - self.position += datalen - if self.chunk_length == self.position: - self.__read_chunk_size_crlf(rfile) - - if length is not None: - length -= datalen - if length == 0: - break - if use_readline and data[-1] == b"\n"[0]: - break - else: - # We're at the beginning of a chunk, so we need to - # determine the next size to read - self.chunk_length = self.__read_chunk_length(rfile) - self.position = 0 - # If chunk_length was 0, we already read any trailers and - # validated that we have ended with \r\n\r\n. - - return b''.join(response) - - def read(self, length=None): - if length is not None and length < 0: - length = None - if self.chunked_input: - return self._chunked_read(length) - return self._do_read(length) - - def readline(self, size=None): - if size is not None and size < 0: - size = None - if self.chunked_input: - return self._chunked_read(size, True) - return self._do_read(size, use_readline=True) - - def readlines(self, hint=None): - # pylint:disable=unused-argument - return list(self) - - def __iter__(self): - return self - - def next(self): - line = self.readline() - if not line: - raise StopIteration - return line - __next__ = next - - -try: - import mimetools - headers_factory = mimetools.Message -except ImportError: - # adapt Python 3 HTTP headers to old API - from http import client # pylint:disable=import-error - - class OldMessage(client.HTTPMessage): - def __init__(self, **kwargs): - super(client.HTTPMessage, self).__init__(**kwargs) # pylint:disable=bad-super-call - self.status = '' - - def getheader(self, name, default=None): - return self.get(name, default) - - @property - def headers(self): - for key, value in self._headers: - yield '%s: %s\r\n' % (key, value) - - @property - def typeheader(self): - return self.get('content-type') - - def headers_factory(fp, *args): # pylint:disable=unused-argument - try: - ret = client.parse_headers(fp, _class=OldMessage) - except client.LineTooLong: - ret = OldMessage() - ret.status = 'Line too long' - return ret - - -class WSGIHandler(object): - """ - Handles HTTP requests from a socket, creates the WSGI environment, and - interacts with the WSGI application. - - This is the default value of :attr:`WSGIServer.handler_class`. - This class may be subclassed carefully, and that class set on a - :class:`WSGIServer` instance through a keyword argument at - construction time. - - Instances are constructed with the same arguments as passed to the - server's :meth:`WSGIServer.handle` method followed by the server - itself. The application and environment are obtained from the server. - - """ - # pylint:disable=too-many-instance-attributes - - protocol_version = 'HTTP/1.1' - - def MessageClass(self, *args): - return headers_factory(*args) - - # Attributes reset at various times for each request; not public - # documented. Class attributes to keep the constructor fast - # (but not make lint tools complain) - - status = None # byte string: b'200 OK' - _orig_status = None # native string: '200 OK' - response_headers = None # list of tuples (b'name', b'value') - code = None # Integer parsed from status - provided_date = None - provided_content_length = None - close_connection = False - time_start = 0 # time.time() when begin handling request - time_finish = 0 # time.time() when done handling request - headers_sent = False # Have we already sent headers? - response_use_chunked = False # Write with transfer-encoding chunked - # Was the connection upgraded? We shouldn't try to chunk writes in that - # case. - connection_upgraded = False - environ = None # Dict from self.get_environ - application = None # application callable from self.server.application - requestline = None # native str 'GET / HTTP/1.1' - response_length = 0 # How much data we sent - result = None # The return value of the WSGI application - wsgi_input = None # Instance of Input() - content_length = 0 # From application-provided headers Incoming - # request headers, instance of MessageClass (gunicorn uses hasattr - # on this so the default value needs to be compatible with the - # API) - headers = headers_factory(BytesIO()) - request_version = None # str: 'HTTP 1.1' - command = None # str: 'GET' - path = None # str: '/' - - def __init__(self, sock, address, server, rfile=None): - # Deprecation: The rfile kwarg was introduced in 1.0a1 as part - # of a refactoring. It was never documented or used. It is - # considered DEPRECATED and may be removed in the future. Its - # use is not supported. - - self.socket = sock - self.client_address = address - self.server = server - if rfile is None: - self.rfile = sock.makefile('rb', -1) - else: - self.rfile = rfile - - def handle(self): - """ - The main request handling method, called by the server. - - This method runs a request handling loop, calling - :meth:`handle_one_request` until all requests on the - connection have been handled (that is, it implements - keep-alive). - """ - try: - while self.socket is not None: - self.time_start = time.time() - self.time_finish = 0 - - result = self.handle_one_request() - if result is None: - break - if result is True: - continue - - self.status, response_body = result # pylint:disable=unpacking-non-sequence - self.socket.sendall(response_body) - if self.time_finish == 0: - self.time_finish = time.time() - self.log_request() - break - finally: - if self.socket is not None: - _sock = getattr(self.socket, '_sock', None) # Python 3 - try: - # read out request data to prevent error: [Errno 104] Connection reset by peer - if _sock: - try: - # socket.recv would hang - _sock.recv(16384) - finally: - _sock.close() - self.socket.close() - except socket.error: - pass - self.__dict__.pop('socket', None) - self.__dict__.pop('rfile', None) - self.__dict__.pop('wsgi_input', None) - - def _check_http_version(self): - version_str = self.request_version - if not version_str.startswith("HTTP/"): - return False - version = tuple(int(x) for x in version_str[5:].split(".")) # "HTTP/" - if version[1] < 0 or version < (0, 9) or version >= (2, 0): - return False - return True - - def read_request(self, raw_requestline): - """ - Parse the incoming request. - - Parses various headers into ``self.headers`` using - :attr:`MessageClass`. Other attributes that are set upon a successful - return of this method include ``self.content_length`` and ``self.close_connection``. - - :param str raw_requestline: A native :class:`str` representing - the request line. A processed version of this will be stored - into ``self.requestline``. - - :raises ValueError: If the request is invalid. This error will - not be logged as a traceback (because it's a client issue, not a server problem). - :return: A boolean value indicating whether the request was successfully parsed. - This method should either return a true value or have raised a ValueError - with details about the parsing error. - - .. versionchanged:: 1.1b6 - Raise the previously documented :exc:`ValueError` in more cases instead of returning a - false value; this allows subclasses more opportunity to customize behaviour. - """ - # pylint:disable=too-many-branches - self.requestline = raw_requestline.rstrip() - words = self.requestline.split() - if len(words) == 3: - self.command, self.path, self.request_version = words - if not self._check_http_version(): - raise _InvalidClientRequest('Invalid http version: %r' % (raw_requestline,)) - elif len(words) == 2: - self.command, self.path = words - if self.command != "GET": - raise _InvalidClientRequest('Expected GET method; Got command=%r; path=%r; raw=%r' % ( - self.command, self.path, raw_requestline,)) - self.request_version = "HTTP/0.9" - # QQQ I'm pretty sure we can drop support for HTTP/0.9 - else: - raise _InvalidClientRequest('Invalid HTTP method: %r' % (raw_requestline,)) - - self.headers = self.MessageClass(self.rfile, 0) - - if self.headers.status: - raise _InvalidClientRequest('Invalid headers status: %r' % (self.headers.status,)) - - if self.headers.get("transfer-encoding", "").lower() == "chunked": - try: - del self.headers["content-length"] - except KeyError: - pass - - content_length = self.headers.get("content-length") - if content_length is not None: - content_length = int(content_length) - if content_length < 0: - raise _InvalidClientRequest('Invalid Content-Length: %r' % (content_length,)) - - if content_length and self.command in ('HEAD', ): - raise _InvalidClientRequest('Unexpected Content-Length') - - self.content_length = content_length - - if self.request_version == "HTTP/1.1": - conntype = self.headers.get("Connection", "").lower() - self.close_connection = (conntype == 'close') # pylint:disable=superfluous-parens - elif self.request_version == 'HTTP/1.0': - conntype = self.headers.get("Connection", "close").lower() - self.close_connection = (conntype != 'keep-alive') # pylint:disable=superfluous-parens - else: - # XXX: HTTP 0.9. We should drop support - self.close_connection = True - - return True - - _print_unexpected_exc = staticmethod(traceback.print_exc) - - def log_error(self, msg, *args): - if not args: - # Already fully formatted, no need to do it again; msg - # might contain % chars that would lead to a formatting - # error. - message = msg - else: - try: - message = msg % args - except Exception: # pylint:disable=broad-except - self._print_unexpected_exc() - message = '%r %r' % (msg, args) - try: - message = '%s: %s' % (self.socket, message) - except Exception: # pylint:disable=broad-except - pass - - try: - self.server.error_log.write(message + '\n') - except Exception: # pylint:disable=broad-except - self._print_unexpected_exc() - - def read_requestline(self): - """ - Read and return the HTTP request line. - - Under both Python 2 and 3, this should return the native - ``str`` type; under Python 3, this probably means the bytes read - from the network need to be decoded (using the ISO-8859-1 charset, aka - latin-1). - """ - line = self.rfile.readline(MAX_REQUEST_LINE) - line = line.decode('latin-1') - return line - - def handle_one_request(self): - """ - Handles one HTTP request using ``self.socket`` and ``self.rfile``. - - Each invocation of this method will do several things, including (but not limited to): - - - Read the request line using :meth:`read_requestline`; - - Read the rest of the request, including headers, with :meth:`read_request`; - - Construct a new WSGI environment in ``self.environ`` using :meth:`get_environ`; - - Store the application in ``self.application``, retrieving it from the server; - - Handle the remainder of the request, including invoking the application, - with :meth:`handle_one_response` - - There are several possible return values to indicate the state - of the client connection: - - - ``None`` - The client connection is already closed or should - be closed because the WSGI application or client set the - ``Connection: close`` header. The request handling - loop should terminate and perform cleanup steps. - - (status, body) - An HTTP status and body tuple. The request was in error, - as detailed by the status and body. The request handling - loop should terminate, close the connection, and perform - cleanup steps. Note that the ``body`` is the complete contents - to send to the client, including all headers and the initial - status line. - - ``True`` - The literal ``True`` value. The request was successfully handled - and the response sent to the client by :meth:`handle_one_response`. - The connection remains open to process more requests and the connection - handling loop should call this method again. This is the typical return - value. - - .. seealso:: :meth:`handle` - - .. versionchanged:: 1.1b6 - Funnel exceptions having to do with invalid HTTP requests through - :meth:`_handle_client_error` to allow subclasses to customize. Note that - this is experimental and may change in the future. - """ - # pylint:disable=too-many-return-statements - if self.rfile.closed: - return - - try: - self.requestline = self.read_requestline() - # Account for old subclasses that haven't done this - if isinstance(self.requestline, bytes): - self.requestline = self.requestline.decode('latin-1') - except socket.error: - # "Connection reset by peer" or other socket errors aren't interesting here - return - - if not self.requestline: - return - - self.response_length = 0 - - if len(self.requestline) >= MAX_REQUEST_LINE: - return ('414', _REQUEST_TOO_LONG_RESPONSE) - - try: - # for compatibility with older versions of pywsgi, we pass self.requestline as an argument there - # NOTE: read_request is supposed to raise ValueError on invalid input; allow old - # subclasses that return a False value instead. - # NOTE: This can mutate the value of self.headers, so self.get_environ() must not be - # called until AFTER this call is done. - if not self.read_request(self.requestline): - return ('400', _BAD_REQUEST_RESPONSE) - except Exception as ex: # pylint:disable=broad-except - # Notice we don't use self.handle_error because it reports - # a 500 error to the client, and this is almost certainly - # a client error. - # Provide a hook for subclasses. - return self._handle_client_error(ex) - - self.environ = self.get_environ() - self.application = self.server.application - - self.handle_one_response() - - if self.close_connection: - return - - if self.rfile.closed: - return - - return True # read more requests - - def _connection_upgrade_requested(self): - if self.headers.get('Connection', '').lower() == 'upgrade': - return True - if self.headers.get('Upgrade', '').lower() == 'websocket': - return True - return False - - def finalize_headers(self): - if self.provided_date is None: - self.response_headers.append((b'Date', format_date_time(time.time()))) - - self.connection_upgraded = self.code == 101 - - if self.code not in (304, 204): - # the reply will include message-body; make sure we have either Content-Length or chunked - if self.provided_content_length is None: - if hasattr(self.result, '__len__'): - total_len = sum(len(chunk) for chunk in self.result) - total_len_str = str(total_len) - total_len_str = total_len_str.encode("latin-1") - self.response_headers.append((b'Content-Length', total_len_str)) - else: - self.response_use_chunked = ( - not self.connection_upgraded - and self.request_version != 'HTTP/1.0' - ) - if self.response_use_chunked: - self.response_headers.append((b'Transfer-Encoding', b'chunked')) - - def _sendall(self, data): - try: - self.socket.sendall(data) - except socket.error as ex: - self.status = 'socket error: %s' % ex - if self.code > 0: - self.code = -self.code - raise - self.response_length += len(data) - - def _write(self, data, - _bytearray=bytearray): - if not data: - # The application/middleware are allowed to yield - # empty bytestrings. - return - - if self.response_use_chunked: - # Write the chunked encoding header - header_str = b'%x\r\n' % len(data) - towrite = _bytearray(header_str) - - # data - towrite += data - # trailer - towrite += b'\r\n' - self._sendall(towrite) - else: - self._sendall(data) - - ApplicationError = AssertionError - - def write(self, data): - # The write() callable we return from start_response. - # https://www.python.org/dev/peps/pep-3333/#the-write-callable - # Supposed to do pretty much the same thing as yielding values - # from the application's return. - if self.code in (304, 204) and data: - raise self.ApplicationError('The %s response must have no body' % self.code) - - if self.headers_sent: - self._write(data) - else: - if not self.status: - raise self.ApplicationError("The application did not call start_response()") - self._write_with_headers(data) - - def _write_with_headers(self, data): - self.headers_sent = True - self.finalize_headers() - - # self.response_headers and self.status are already in latin-1, as encoded by self.start_response - towrite = bytearray(b'HTTP/1.1 ') - towrite += self.status - towrite += b'\r\n' - for header, value in self.response_headers: - towrite += header - towrite += b': ' - towrite += value - towrite += b"\r\n" - - towrite += b'\r\n' - self._sendall(towrite) - # No need to copy the data into towrite; we may make an extra syscall - # but the copy time could be substantial too, and it reduces the chances - # of sendall being able to send everything in one go - self._write(data) - - def start_response(self, status, headers, exc_info=None): - """ - .. versionchanged:: 1.2a1 - Avoid HTTP header injection by raising a :exc:`ValueError` - if *status* or any *header* name or value contains a carriage - return or newline. - .. versionchanged:: 1.1b5 - Pro-actively handle checking the encoding of the status line - and headers during this method. On Python 2, avoid some - extra encodings. - """ - # pylint:disable=too-many-branches,too-many-statements - if exc_info: - try: - if self.headers_sent: - # Re-raise original exception if headers sent - reraise(*exc_info) - finally: - # Avoid dangling circular ref - exc_info = None - - # Pep 3333, "The start_response callable": - # https://www.python.org/dev/peps/pep-3333/#the-start-response-callable - # "Servers should check for errors in the headers at the time - # start_response is called, so that an error can be raised - # while the application is still running." Here, we check the encoding. - # This aids debugging: headers especially are generated programmatically - # and an encoding error in a loop or list comprehension yields an opaque - # UnicodeError without any clue which header was wrong. - # Note that this results in copying the header list at this point, not modifying it, - # although we are allowed to do so if needed. This slightly increases memory usage. - # We also check for HTTP Response Splitting vulnerabilities - response_headers = [] - header = None - value = None - try: - for header, value in headers: - if not isinstance(header, str): - raise UnicodeError("The header must be a native string", header, value) - if not isinstance(value, str): - raise UnicodeError("The value must be a native string", header, value) - if '\r' in header or '\n' in header: - raise ValueError('carriage return or newline in header name', header) - if '\r' in value or '\n' in value: - raise ValueError('carriage return or newline in header value', value) - # Either we're on Python 2, in which case bytes is correct, or - # we're on Python 3 and the user screwed up (because it should be a native - # string). In either case, make sure that this is latin-1 compatible. Under - # Python 2, bytes.encode() will take a round-trip through the system encoding, - # which may be ascii, which is not really what we want. However, the latin-1 encoding - # can encode everything except control characters and the block from 0x7F to 0x9F, so - # explicitly round-tripping bytes through the encoding is unlikely to be of much - # benefit, so we go for speed (the WSGI spec specifically calls out allowing the range - # from 0x00 to 0xFF, although the HTTP spec forbids the control characters). - # Note: Some Python 2 implementations, like Jython, may allow non-octet (above 255) values - # in their str implementation; this is mentioned in the WSGI spec, but we don't - # run on any platform like that so we can assume that a str value is pure bytes. - response_headers.append((header.encode("latin-1"), - value.encode("latin-1"))) - except UnicodeEncodeError: - # If we get here, we're guaranteed to have a header and value - raise UnicodeError("Non-latin1 header", repr(header), repr(value)) - - # Same as above - if not isinstance(status, str): - raise UnicodeError("The status string must be a native string") - if '\r' in status or '\n' in status: - raise ValueError("carriage return or newline in status", status) - # don't assign to anything until the validation is complete, including parsing the - # code - code = int(status.split(' ', 1)[0]) - - self.status = status.encode("latin-1") - self._orig_status = status # Preserve the native string for logging - self.response_headers = response_headers - self.code = code - - provided_connection = None # Did the wsgi app give us a Connection header? - self.provided_date = None - self.provided_content_length = None - - for header, value in headers: - header = header.lower() - if header == 'connection': - provided_connection = value - elif header == 'date': - self.provided_date = value - elif header == 'content-length': - self.provided_content_length = value - - if self.request_version == 'HTTP/1.0' and provided_connection is None: - conntype = b'close' if self.close_connection else b'keep-alive' - response_headers.append((b'Connection', conntype)) - elif provided_connection == 'close': - self.close_connection = True - - if self.code in (304, 204): - if self.provided_content_length is not None and self.provided_content_length != '0': - msg = 'Invalid Content-Length for %s response: %r (must be absent or zero)' % (self.code, self.provided_content_length) - msg = msg.encode('latin-1') - raise self.ApplicationError(msg) - - return self.write - - def log_request(self): - self.server.log.write(self.format_request() + '\n') - - def format_request(self): - now = datetime.now().replace(microsecond=0) - length = self.response_length or '-' - if self.time_finish: - delta = '%.6f' % (self.time_finish - self.time_start) - else: - delta = '-' - client_address = self.client_address[0] if isinstance(self.client_address, tuple) else self.client_address - return '%s - - [%s] "%s" %s %s %s' % ( - client_address or '-', - now, - self.requestline or '', - # Use the native string version of the status, saved so we don't have to - # decode. But fallback to the encoded 'status' in case of subclasses - # (Is that really necessary? At least there's no overhead.) - (self._orig_status or self.status or '000').split()[0], - length, - delta) - - def process_result(self): - for data in self.result: - if data: - self.write(data) - if self.status and not self.headers_sent: - # In other words, the application returned an empty - # result iterable (and did not use the write callable) - # Trigger the flush of the headers. - self.write(b'') - if self.response_use_chunked: - self._sendall(b'0\r\n\r\n') - - - def run_application(self): - assert self.result is None - try: - self.result = self.application(self.environ, self.start_response) - self.process_result() - finally: - close = getattr(self.result, 'close', None) - try: - if close is not None: - close() - finally: - # Discard the result. If it's a generator this can - # free a lot of hidden resources (if we failed to iterate - # all the way through it---the frames are automatically - # cleaned up when StopIteration is raised); but other cases - # could still free up resources sooner than otherwise. - close = None - self.result = None - - #: These errors are silently ignored by :meth:`handle_one_response` to avoid producing - #: excess log entries on normal operating conditions. They indicate - #: a remote client has disconnected and there is little or nothing - #: this process can be expected to do about it. You may change this - #: value in a subclass. - #: - #: The default value includes :data:`errno.EPIPE` and :data:`errno.ECONNRESET`. - #: On Windows this also includes :data:`errno.WSAECONNABORTED`. - #: - #: This is a provisional API, subject to change. See :pr:`377`, :pr:`999` - #: and :issue:`136`. - #: - #: .. versionadded:: 1.3 - ignored_socket_errors = (errno.EPIPE, errno.ECONNRESET) - try: - ignored_socket_errors += (errno.WSAECONNABORTED,) - except AttributeError: - pass # Not windows - - def handle_one_response(self): - """ - Invoke the application to produce one response. - - This is called by :meth:`handle_one_request` after all the - state for the request has been established. It is responsible - for error handling. - """ - self.time_start = time.time() - self.status = None - self.headers_sent = False - - self.result = None - self.response_use_chunked = False - self.connection_upgraded = False - self.response_length = 0 - - try: - try: - self.run_application() - finally: - try: - self.wsgi_input._discard() - except _InvalidClientInput: - # This one is deliberately raised to the outer - # scope, because, with the incoming stream in some bad state, - # we can't be sure we can synchronize and properly parse the next - # request. - raise - except socket.error: - # Don't let socket exceptions during discarding - # input override any exception that may have been - # raised by the application, such as our own _InvalidClientInput. - # In the general case, these aren't even worth logging (see the comment - # just below) - pass - except _InvalidClientInput as ex: - # DO log this one because: - # - Some of the data may have been read and acted on by the - # application; - # - The response may or may not have been sent; - # - It's likely that the client is bad, or malicious, and - # users might wish to take steps to block the client. - self._handle_client_error(ex) - self.close_connection = True - self._send_error_response_if_possible(400) - except socket.error as ex: - if ex.args[0] in self.ignored_socket_errors: - # See description of self.ignored_socket_errors. - self.close_connection = True - else: - self.handle_error(*sys.exc_info()) - except: # pylint:disable=bare-except - self.handle_error(*sys.exc_info()) - finally: - self.time_finish = time.time() - self.log_request() - - def _send_error_response_if_possible(self, error_code): - if self.response_length: - self.close_connection = True - else: - status, headers, body = _ERRORS[error_code] - try: - self.start_response(status, headers[:]) - self.write(body) - except socket.error: - self.close_connection = True - - def _log_error(self, t, v, tb): - # TODO: Shouldn't we dump this to wsgi.errors? If we did that now, it would - # wind up getting logged twice - if not issubclass(t, GreenletExit): - context = self.environ - if not isinstance(context, self.server.secure_environ_class): - context = self.server.secure_environ_class(context) - self.server.loop.handle_error(context, t, v, tb) - - def handle_error(self, t, v, tb): - # Called for internal, unexpected errors, NOT invalid client input - self._log_error(t, v, tb) - t = v = tb = None - self._send_error_response_if_possible(500) - - def _handle_client_error(self, ex): - # Called for invalid client input - # Returns the appropriate error response. - if not isinstance(ex, (ValueError, _InvalidClientInput)): - # XXX: Why not self._log_error to send it through the loop's - # handle_error method? - # _InvalidClientRequest is a ValueError; _InvalidClientInput is an IOError. - traceback.print_exc() - if isinstance(ex, _InvalidClientRequest): - # No formatting needed, that's already been handled. In fact, because the - # formatted message contains user input, it might have a % in it, and attempting - # to format that with no arguments would be an error. - # However, the error messages do not include the requesting IP - # necessarily, so we do add that. - self.log_error('(from %s) %s', self.client_address, ex.formatted_message) - else: - self.log_error('Invalid request (from %s): %s', - self.client_address, - str(ex) or ex.__class__.__name__) - return ('400', _BAD_REQUEST_RESPONSE) - - def _headers(self): - key = None - value = None - IGNORED_KEYS = (None, 'CONTENT_TYPE', 'CONTENT_LENGTH') - for header in self.headers.headers: - if key is not None and header[:1] in " \t": - value += header - continue - - if key not in IGNORED_KEYS: - yield 'HTTP_' + key, value.strip() - - key, value = header.split(':', 1) - if '_' in key: - # strip incoming bad veaders - key = None - else: - key = key.replace('-', '_').upper() - - if key not in IGNORED_KEYS: - yield 'HTTP_' + key, value.strip() - - def get_environ(self): - """ - Construct and return a new WSGI environment dictionary for a specific request. - - This should begin with asking the server for the base environment - using :meth:`WSGIServer.get_environ`, and then proceed to add the - request specific values. - - By the time this method is invoked the request line and request shall have - been parsed and ``self.headers`` shall be populated. - """ - env = self.server.get_environ() - env['REQUEST_METHOD'] = self.command - # SCRIPT_NAME is explicitly implementation defined. Using an - # empty value for SCRIPT_NAME is both explicitly allowed by - # both the CGI standard and WSGI PEPs, and also the thing that - # makes the most sense from a generic server perspective (we - # have no hierarchy or understanding of URLs or files, just a - # single application to call. The empty string represents the - # application root, which is what we have). Different WSGI - # implementations handle this very differently, so portable - # applications that rely on SCRIPT_NAME will have to use a - # WSGI middleware to set it to a defined value, or otherwise - # rely on server-specific mechanisms (e.g, on waitress, use - # ``--url-prefix``, in gunicorn set the ``SCRIPT_NAME`` header - # or process environment variable, in gevent subclass - # WSGIHandler.) - # - # See https://github.com/gevent/gevent/issues/1667 for discussion. - env['SCRIPT_NAME'] = '' - - path, query = self.path.split('?', 1) if '?' in self.path else (self.path, '') - # Note that self.path contains the original str object; if it contains - # encoded escapes, it will NOT match PATH_INFO. - env['PATH_INFO'] = unquote_latin1(path) - env['QUERY_STRING'] = query - - if self.headers.typeheader is not None: - env['CONTENT_TYPE'] = self.headers.typeheader - - length = self.headers.getheader('content-length') - if length: - env['CONTENT_LENGTH'] = length - env['SERVER_PROTOCOL'] = self.request_version - - client_address = self.client_address - if isinstance(client_address, tuple): - env['REMOTE_ADDR'] = str(client_address[0]) - env['REMOTE_PORT'] = str(client_address[1]) - - for key, value in self._headers(): - if key in env: - if 'COOKIE' in key: - env[key] += '; ' + value - else: - env[key] += ',' + value - else: - env[key] = value - - sock = self.socket if env.get('HTTP_EXPECT') == '100-continue' else None - - chunked = env.get('HTTP_TRANSFER_ENCODING', '').lower() == 'chunked' - # Input refuses to read if the data isn't chunked, and there is no content_length - # provided. For 'Upgrade: Websocket' requests, neither of those things is true. - handling_reads = not self._connection_upgrade_requested() - - self.wsgi_input = Input(self.rfile, self.content_length, socket=sock, chunked_input=chunked) - - env['wsgi.input'] = self.wsgi_input if handling_reads else self.rfile - # This is a non-standard flag indicating that our input stream is - # self-terminated (returns EOF when consumed). - # See https://github.com/gevent/gevent/issues/1308 - env['wsgi.input_terminated'] = handling_reads - return env - - -class _NoopLog(object): - # Does nothing; implements just enough file-like methods - # to pass the WSGI validator - - def write(self, *args, **kwargs): - # pylint:disable=unused-argument - return - - def flush(self): - pass - - def writelines(self, *args, **kwargs): - pass - - -class LoggingLogAdapter(object): - """ - An adapter for :class:`logging.Logger` instances - to let them be used with :class:`WSGIServer`. - - .. warning:: Unless the entire process is monkey-patched at a very - early part of the lifecycle (before logging is configured), - loggers are likely to not be gevent-cooperative. For example, - the socket and syslog handlers use the socket module in a way - that can block, and most handlers acquire threading locks. - - .. warning:: It *may* be possible for the logging functions to be - called in the :class:`gevent.Hub` greenlet. Code running in the - hub greenlet cannot use any gevent blocking functions without triggering - a ``LoopExit``. - - .. versionadded:: 1.1a3 - - .. versionchanged:: 1.1b6 - Attributes not present on this object are proxied to the underlying - logger instance. This permits using custom :class:`~logging.Logger` - subclasses (or indeed, even duck-typed objects). - - .. versionchanged:: 1.1 - Strip trailing newline characters on the message passed to :meth:`write` - because log handlers will usually add one themselves. - """ - - # gevent avoids importing and using logging because importing it and - # creating loggers creates native locks unless monkey-patched. - - __slots__ = ('_logger', '_level') - - def __init__(self, logger, level=20): - """ - Write information to the *logger* at the given *level* (default to INFO). - """ - self._logger = logger - self._level = level - - def write(self, msg): - if msg and msg.endswith('\n'): - msg = msg[:-1] - self._logger.log(self._level, msg) - - def flush(self): - "No-op; required to be a file-like object" - - def writelines(self, lines): - for line in lines: - self.write(line) - - def __getattr__(self, name): - return getattr(self._logger, name) - - def __setattr__(self, name, value): - if name not in LoggingLogAdapter.__slots__: - setattr(self._logger, name, value) - else: - object.__setattr__(self, name, value) - - def __delattr__(self, name): - delattr(self._logger, name) - -#### -## Environ classes. -# These subclass dict. They could subclass collections.UserDict on -# 3.3+ and proxy to the underlying real dict to avoid a copy if we -# have to print them (on 2.7 it's slightly more complicated to be an -# instance of collections.MutableMapping; UserDict.UserDict isn't.) -# Then we could have either the WSGIHandler.get_environ or the -# WSGIServer.get_environ return one of these proxies, and -# WSGIHandler.run_application would know to access the `environ.data` -# attribute to be able to pass the *real* dict to the application -# (because PEP3333 requires no subclasses, only actual dict objects; -# wsgiref.validator and webob.Request both enforce this). This has the -# advantage of not being fragile if anybody else tries to print/log -# self.environ (and not requiring a copy). However, if there are any -# subclasses of Handler or Server, this could break if they don't know -# to return this type. -#### - -class Environ(dict): - """ - A base class that can be used for WSGI environment objects. - - Provisional API. - - .. versionadded:: 1.2a1 - """ - - __slots__ = () # add no ivars or weakref ability - - def copy(self): - return self.__class__(self) - - if not hasattr(dict, 'iteritems'): - # Python 3 - def iteritems(self): - return self.items() - - def __reduce_ex__(self, proto): - return (dict, (), None, None, iter(self.iteritems())) - -class SecureEnviron(Environ): - """ - An environment that does not print its keys and values - by default. - - Provisional API. - - This is intended to keep potentially sensitive information like - HTTP authorization and cookies from being inadvertently printed - or logged. - - For debugging, each instance can have its *secure_repr* attribute - set to ``False``, which will cause it to print like a normal dict. - - When *secure_repr* is ``True`` (the default), then the value of - the *whitelist_keys* attribute is consulted; if this value is - true-ish, it should be a container (something that responds to - ``in``) of key names (typically a list or set). Keys and values in - this dictionary that are in *whitelist_keys* will then be printed, - while all other values will be masked. These values may be - customized on the class by setting the *default_secure_repr* and - *default_whitelist_keys*, respectively:: - - >>> environ = SecureEnviron(key='value') - >>> environ # doctest: +ELLIPSIS - >> environ.whitelist_keys = {'key'} - >>> environ - {'key': 'value'} - - A non-whitelisted key (*only*, to avoid doctest issues) is masked:: - - >>> environ['secure'] = 'secret'; del environ['key'] - >>> environ - {'secure': ''} - - We can turn it off entirely for the instance:: - - >>> environ.secure_repr = False - >>> environ - {'secure': 'secret'} - - We can also customize it at the class level (here we use a new - class to be explicit and to avoid polluting the true default - values; we would set this class to be the ``environ_class`` of the - server):: - - >>> class MyEnviron(SecureEnviron): - ... default_whitelist_keys = ('key',) - ... - >>> environ = MyEnviron({'key': 'value'}) - >>> environ - {'key': 'value'} - - .. versionadded:: 1.2a1 - """ - - default_secure_repr = True - default_whitelist_keys = () - default_print_masked_keys = True - - # Allow instances to override the class values, - # but inherit from the class if not present. Keeps instances - # small since we can't combine __slots__ with class attributes - # of the same name. - __slots__ = ('secure_repr', 'whitelist_keys', 'print_masked_keys') - - def __getattr__(self, name): - if name in SecureEnviron.__slots__: - return getattr(type(self), 'default_' + name) - raise AttributeError(name) - - def __repr__(self): - if self.secure_repr: - whitelist = self.whitelist_keys - print_masked = self.print_masked_keys - if whitelist: - safe = {k: self[k] if k in whitelist else "" - for k in self - if k in whitelist or print_masked} - safe_repr = repr(safe) - if not print_masked and len(safe) != len(self): - safe_repr = safe_repr[:-1] + ", (hidden keys: %d)}" % (len(self) - len(safe)) - return safe_repr - return "" % (len(self), id(self)) - return Environ.__repr__(self) - __str__ = __repr__ - - -class WSGISecureEnviron(SecureEnviron): - """ - Specializes the default list of whitelisted keys to a few - common WSGI variables. - - Example:: - - >>> environ = WSGISecureEnviron(REMOTE_ADDR='::1', HTTP_AUTHORIZATION='secret') - >>> environ - {'REMOTE_ADDR': '::1', (hidden keys: 1)} - >>> import pprint - >>> pprint.pprint(environ) - {'REMOTE_ADDR': '::1', (hidden keys: 1)} - >>> print(pprint.pformat(environ)) - {'REMOTE_ADDR': '::1', (hidden keys: 1)} - """ - default_whitelist_keys = ('REMOTE_ADDR', 'REMOTE_PORT', 'HTTP_HOST') - default_print_masked_keys = False - - -class WSGIServer(StreamServer): - """ - A WSGI server based on :class:`StreamServer` that supports HTTPS. - - - :keyword log: If given, an object with a ``write`` method to which - request (access) logs will be written. If not given, defaults - to :obj:`sys.stderr`. You may pass ``None`` to disable request - logging. You may use a wrapper, around e.g., :mod:`logging`, - to support objects that don't implement a ``write`` method. - (If you pass a :class:`~logging.Logger` instance, or in - general something that provides a ``log`` method but not a - ``write`` method, such a wrapper will automatically be created - and it will be logged to at the :data:`~logging.INFO` level.) - - :keyword error_log: If given, a file-like object with ``write``, - ``writelines`` and ``flush`` methods to which error logs will - be written. If not given, defaults to :obj:`sys.stderr`. You - may pass ``None`` to disable error logging (not recommended). - You may use a wrapper, around e.g., :mod:`logging`, to support - objects that don't implement the proper methods. This - parameter will become the value for ``wsgi.errors`` in the - WSGI environment (if not already set). (As with *log*, - wrappers for :class:`~logging.Logger` instances and the like - will be created automatically and logged to at the :data:`~logging.ERROR` - level.) - - .. seealso:: - - :class:`LoggingLogAdapter` - See important warnings before attempting to use :mod:`logging`. - - .. versionchanged:: 1.1a3 - Added the ``error_log`` parameter, and set ``wsgi.errors`` in the WSGI - environment to this value. - .. versionchanged:: 1.1a3 - Add support for passing :class:`logging.Logger` objects to the ``log`` and - ``error_log`` arguments. - .. versionchanged:: 20.6.0 - Passing a ``handle`` kwarg to the constructor is now officially deprecated. - """ - - #: A callable taking three arguments: (socket, address, server) and returning - #: an object with a ``handle()`` method. The callable is called once for - #: each incoming socket request, as is its handle method. The handle method should not - #: return until all use of the socket is complete. - #: - #: This class uses the :class:`WSGIHandler` object as the default value. You may - #: subclass this class and set a different default value, or you may pass - #: a value to use in the ``handler_class`` keyword constructor argument. - handler_class = WSGIHandler - - #: The object to which request logs will be written. - #: It must never be None. Initialized from the ``log`` constructor - #: parameter. - log = None - - #: The object to which error logs will be written. - #: It must never be None. Initialized from the ``error_log`` constructor - #: parameter. - error_log = None - - #: The class of environ objects passed to the handlers. - #: Must be a dict subclass. For compliance with :pep:`3333` - #: and libraries like WebOb, this is simply :class:`dict` - #: but this can be customized in a subclass or per-instance - #: (probably to :class:`WSGISecureEnviron`). - #: - #: .. versionadded:: 1.2a1 - environ_class = dict - - # Undocumented internal detail: the class that WSGIHandler._log_error - # will cast to before passing to the loop. - secure_environ_class = WSGISecureEnviron - - base_env = {'GATEWAY_INTERFACE': 'CGI/1.1', - 'SERVER_SOFTWARE': 'gevent/%d.%d Python/%d.%d' % (gevent.version_info[:2] + sys.version_info[:2]), - 'SCRIPT_NAME': '', - 'wsgi.version': (1, 0), - 'wsgi.multithread': False, # XXX: Aren't we really, though? - 'wsgi.multiprocess': False, - 'wsgi.run_once': False} - - def __init__(self, listener, application=None, backlog=None, spawn='default', - log='default', error_log='default', - handler_class=None, - environ=None, **ssl_args): - if 'handle' in ssl_args: - # The ultimate base class (BaseServer) uses 'handle' for - # the thing we call 'application'. We never deliberately - # bass a `handle` argument to the base class, but one - # could sneak in through ``**ssl_args``, even though that - # is not the intent, while application is None. That - # causes our own ``def handle`` method to be replaced, - # probably leading to bad results. Passing a 'handle' - # instead of an 'application' can really confuse things. - import warnings - warnings.warn("Passing 'handle' kwarg to WSGIServer is deprecated. " - "Did you mean application?", DeprecationWarning, stacklevel=2) - - StreamServer.__init__(self, listener, backlog=backlog, spawn=spawn, **ssl_args) - - if application is not None: - self.application = application - if handler_class is not None: - self.handler_class = handler_class - - # Note that we can't initialize these as class variables: - # sys.stderr might get monkey patched at runtime. - def _make_log(l, level=20): - if l == 'default': - return sys.stderr - if l is None: - return _NoopLog() - if not hasattr(l, 'write') and hasattr(l, 'log'): - return LoggingLogAdapter(l, level) - return l - self.log = _make_log(log) - self.error_log = _make_log(error_log, 40) # logging.ERROR - - self.set_environ(environ) - self.set_max_accept() - - def set_environ(self, environ=None): - if environ is not None: - self.environ = environ - environ_update = getattr(self, 'environ', None) - - self.environ = self.environ_class(self.base_env) - if self.ssl_enabled: - self.environ['wsgi.url_scheme'] = 'https' - else: - self.environ['wsgi.url_scheme'] = 'http' - if environ_update is not None: - self.environ.update(environ_update) - if self.environ.get('wsgi.errors') is None: - self.environ['wsgi.errors'] = self.error_log - - def set_max_accept(self): - if self.environ.get('wsgi.multiprocess'): - self.max_accept = 1 - - def get_environ(self): - return self.environ_class(self.environ) - - def init_socket(self): - StreamServer.init_socket(self) - self.update_environ() - - def update_environ(self): - """ - Called before the first request is handled to fill in WSGI environment values. - - This includes getting the correct server name and port. - """ - address = self.address - if isinstance(address, tuple): - if 'SERVER_NAME' not in self.environ: - try: - name = socket.getfqdn(address[0]) - except socket.error: - name = str(address[0]) - if not isinstance(name, str): - name = name.decode('ascii') - self.environ['SERVER_NAME'] = name - self.environ.setdefault('SERVER_PORT', str(address[1])) - else: - self.environ.setdefault('SERVER_NAME', '') - self.environ.setdefault('SERVER_PORT', '') - - def handle(self, sock, address): - """ - Create an instance of :attr:`handler_class` to handle the request. - - This method blocks until the handler returns. - """ - # pylint:disable=method-hidden - handler = self.handler_class(sock, address, self) - handler.handle() - -def _main(): - # Provisional main handler, for quick tests, not production - # usage. - from gevent import monkey; monkey.patch_all() - - import argparse - import importlib - - parser = argparse.ArgumentParser() - parser.add_argument("app", help="dotted name of WSGI app callable [module:callable]") - parser.add_argument("-b", "--bind", - help="The socket to bind", - default=":8080") - - args = parser.parse_args() - - module_name, app_name = args.app.split(':') - module = importlib.import_module(module_name) - app = getattr(module, app_name) - bind = args.bind - - server = WSGIServer(bind, app) - server.serve_forever() - -if __name__ == '__main__': - _main() diff --git a/venv/lib/python3.9/site-packages/gevent/queue.py b/venv/lib/python3.9/site-packages/gevent/queue.py deleted file mode 100644 index b9d0629..0000000 --- a/venv/lib/python3.9/site-packages/gevent/queue.py +++ /dev/null @@ -1,826 +0,0 @@ -# Copyright (c) 2009-2012 Denis Bilenko. See LICENSE for details. -# copyright (c) 2018 gevent -# cython: auto_pickle=False,embedsignature=True,always_allow_keywords=False -""" -Synchronized queues. - -The :mod:`gevent.queue` module implements multi-producer, multi-consumer queues -that work across greenlets, with the API similar to the classes found in the -standard :mod:`Queue` and :class:`multiprocessing ` modules. - -The classes in this module implement the iterator protocol. Iterating -over a queue means repeatedly calling :meth:`get ` until -:meth:`get ` returns ``StopIteration`` (specifically that -class, not an instance or subclass). - - >>> import gevent.queue - >>> queue = gevent.queue.Queue() - >>> queue.put(1) - >>> queue.put(2) - >>> queue.put(StopIteration) - >>> for item in queue: - ... print(item) - 1 - 2 - -.. versionchanged:: 1.0 - ``Queue(0)`` now means queue of infinite size, not a channel. A :exc:`DeprecationWarning` - will be issued with this argument. - -.. versionchanged:: 25.4.1 - :class:`Queue` was renamed to :class:`SimpleQueue`, while :class:`JoinableQueue` was - renamed to :class:`Queue` (`JoinableQueue` remains a backwards compatible alias). - This adds the ability to ``join()`` all queues, like the standard library. - - Previously ``SimpleQueue`` was an alias for the undocumented Python - implementation ``queue._PySimpleQueue``; now it is gevent's own implementation. - This ensures that it is cooperative even without monkey-patching. -""" - - -import sys -from heapq import heappush as _heappush -from heapq import heappop as _heappop -from heapq import heapify as _heapify -import collections -import types - -import queue as __queue__ -# We re-export these exceptions to client modules. -# But we also want fast access to them from Cython with a cdef, -# and we do that with the _ definition. -_Full = Full = __queue__.Full -_Empty = Empty = __queue__.Empty - -from gevent.timeout import Timeout -from gevent._hub_local import get_hub_noargs as get_hub -from gevent.exceptions import InvalidSwitchError - -__all__ = [] -__implements__ = ['Queue', 'PriorityQueue', 'LifoQueue', 'SimpleQueue'] -__extensions__ = ['JoinableQueue', 'Channel'] -__imports__ = ['Empty', 'Full'] - -if hasattr(__queue__, 'ShutDown'): # New in 3.13 - ShutDown = __queue__.ShutDown - __imports__.append('ShutDown') -else: - class ShutDown(Exception): - """ - gevent extension for Python versions less than 3.13 - """ - __extensions__.append('ShutDown') - - -__all__ += (__implements__ + __extensions__ + __imports__) - - -# pylint 2.0.dev2 things collections.dequeue.popleft() doesn't return -# pylint:disable=assignment-from-no-return - -def _safe_remove(deq, item): - # For when the item may have been removed by - # Queue._unlock - try: - deq.remove(item) - except ValueError: - pass - -import gevent._waiter -locals()['Waiter'] = gevent._waiter.Waiter -locals()['getcurrent'] = __import__('greenlet').getcurrent -locals()['greenlet_init'] = lambda: None - -class ItemWaiter(Waiter): # pylint:disable=undefined-variable - # pylint:disable=assigning-non-slot - __slots__ = ( - 'item', - 'queue', - ) - - def __init__(self, item, queue): - Waiter.__init__(self) # pylint:disable=undefined-variable - self.item = item - self.queue = queue - - def put_and_switch(self): - self.queue._put(self.item) - self.queue = None - self.item = None - return self.switch(self) - - -class SimpleQueue(object): - """ - Create a queue object with a given maximum size. - - If *maxsize* is less than or equal to zero or ``None``, the queue - size is infinite. - - Queues have a ``len`` equal to the number of items in them (the :meth:`qsize`), - but in a boolean context they are always True. - - .. versionchanged:: 1.1b3 - Queues now support :func:`len`; it behaves the same as :meth:`qsize`. - .. versionchanged:: 1.1b3 - Multiple greenlets that block on a call to :meth:`put` for a full queue - will now be awakened to put their items into the queue in the order in which - they arrived. Likewise, multiple greenlets that block on a call to :meth:`get` for - an empty queue will now receive items in the order in which they blocked. An - implementation quirk under CPython *usually* ensured this was roughly the case - previously anyway, but that wasn't the case for PyPy. - .. versionchanged:: 24.10.1 - Implement the ``shutdown`` methods from Python 3.13. - .. versionchanged:: 25.4.1 - Renamed from ``Queue`` to ``SimpleQueue`` to better match the standard library. - While this class no longer has a ``shutdown`` method, the new ``Queue`` class - (previously ``JoinableQueue``) continues to have it. - .. versionchanged:: 25.4.2 - Make this class subscriptable. - """ - - __slots__ = ( - '_maxsize', - 'getters', - 'putters', - 'hub', - '_event_unlock', - 'queue', - '__weakref__', - 'is_shutdown', # 3.13 - ) - - __class_getitem__ = classmethod(types.GenericAlias) - - def __init__(self, maxsize=None, items=(), _warn_depth=2): - if maxsize is not None and maxsize <= 0: - if maxsize == 0: - import warnings - warnings.warn( - 'Queue(0) now equivalent to Queue(None); if you want a channel, use Channel', - DeprecationWarning, - stacklevel=_warn_depth) - maxsize = None - - self._maxsize = maxsize if maxsize is not None else -1 - # Explicitly maintain order for getters and putters that block - # so that callers can consistently rely on getting things out - # in the apparent order they went in. This was once required by - # imap_unordered. Previously these were set() objects, and the - # items put in the set have default hash() and eq() methods; - # under CPython, since new objects tend to have increasing - # hash values, this tended to roughly maintain order anyway, - # but that's not true under PyPy. An alternative to a deque - # (to avoid the linear scan of remove()) might be an - # OrderedDict, but it's 2.7 only; we don't expect to have so - # many waiters that removing an arbitrary element is a - # bottleneck, though. - self.getters = collections.deque() - self.putters = collections.deque() - self.hub = get_hub() - self._event_unlock = None - self.is_shutdown = False - - self.queue = None - if items: - # The *items* argument is unique to gevent, not in the - # stdlib. So when we monkey-patch ourself in, we won't - # expect to get called with that argument. To be compatible with - # stdlib subclasses that define ``def _init(self, maxsize)`` - # detect this case and call with the same signature. - self._init(maxsize, items) - else: - self._init(maxsize) - - # The stdlib queue class defines four bottleneck methods that - # subclasses override, we want to try to support them as - # best we can: - # - # * _init to initialize the queue attribute - # * _qsize to count the elements - # *_put to add an item - # *_get to remove and return an item. - - def _init(self, maxsize, items=()): # pylint: disable=unused-argument - self.queue = self._create_queue(items) - - def _qsize(self): - return len(self.queue) - - def _get(self): - return self.queue.popleft() - - def _put(self, item): - self.queue.append(item) - - def _create_queue(self, items=()): - return collections.deque(items) - - def _peek(self): - return self.queue[0] - - @property - def maxsize(self): - return self._maxsize if self._maxsize > 0 else None - - @maxsize.setter - def maxsize(self, nv): - # QQQ make maxsize into a property with setter that schedules unlock if necessary - if nv is None or nv <= 0: - self._maxsize = -1 - else: - self._maxsize = nv - - def copy(self): - return type(self)(self.maxsize, self.queue) - - def __repr__(self): - return '<%s at %s%s>' % (type(self).__name__, hex(id(self)), self._format()) - - def __str__(self): - return '<%s%s>' % (type(self).__name__, self._format()) - - def _format(self): - result = [] - if self.maxsize is not None: - result.append('maxsize=%r' % (self.maxsize, )) - if getattr(self, 'queue', None): - result.append('queue=%r' % (self.queue, )) - if self.getters: - result.append('getters[%s]' % len(self.getters)) - if self.putters: - result.append('putters[%s]' % len(self.putters)) - if result: - return ' ' + ' '.join(result) - return '' - - def qsize(self): - """Return the size of the queue.""" - return self._qsize() - - def __len__(self): - """ - Return the size of the queue. This is the same as :meth:`qsize`. - - .. versionadded: 1.1b3 - - Previously, getting len() of a queue would raise a TypeError. - """ - - return self.qsize() - - def __bool__(self): - """ - A queue object is always True. - - .. versionadded: 1.1b3 - - Now that queues support len(), they need to implement ``__bool__`` - to return True for backwards compatibility. - """ - return True - - def empty(self): - """Return ``True`` if the queue is empty, ``False`` otherwise.""" - return not self.qsize() - - def full(self): - """Return ``True`` if the queue is full, ``False`` otherwise. - - ``Queue(None)`` is never full. - """ - return self._maxsize > 0 and self.qsize() >= self._maxsize - - def put(self, item, block=True, timeout=None): - """ - Put an item into the queue. - - If optional arg *block* is true and *timeout* is ``None`` (the default), - block if necessary until a free slot is available. If *timeout* is - a positive number, it blocks at most *timeout* seconds and raises - the :class:`Full` exception if no free slot was available within that time. - Otherwise (*block* is false), put an item on the queue if a free slot - is immediately available, else raise the :class:`Full` exception (*timeout* - is ignored in that case). - - ... versionchanged:: 24.10.1 - Now raises a ``ValueError`` for a negative *timeout* in the cases - that CPython does. - """ - if self.is_shutdown: - raise ShutDown - if self._maxsize == -1 or self.qsize() < self._maxsize: - # there's a free slot, put an item right away. - # For compatibility with CPython, verify that the timeout is non-negative. - if block and timeout is not None and timeout < 0: - raise ValueError("'timeout' must be a non-negative number") - self._put(item) - if self.getters: - self._schedule_unlock() - return - - if self.hub is getcurrent(): # pylint:disable=undefined-variable - # We're in the mainloop, so we cannot wait; we can switch to other greenlets though. - # Check if possible to get a free slot in the queue. - while self.getters and self.qsize() and self.qsize() >= self._maxsize: - getter = self.getters.popleft() - getter.switch(getter) - if self.qsize() < self._maxsize: - self._put(item) - return - raise Full - - if block: - waiter = ItemWaiter(item, self) - self.putters.append(waiter) - timeout = Timeout._start_new_or_dummy(timeout, Full) - try: - if self.getters: - self._schedule_unlock() - result = waiter.get() - if result is not waiter: - raise InvalidSwitchError("Invalid switch into Queue.put: %r" % (result, )) - finally: - timeout.cancel() - _safe_remove(self.putters, waiter) - return - - raise Full - - def put_nowait(self, item): - """Put an item into the queue without blocking. - - Only enqueue the item if a free slot is immediately available. - Otherwise raise the :class:`Full` exception. - """ - self.put(item, False) - - def __get_or_peek(self, method, block, timeout): - # Internal helper method. The `method` should be either - # self._get when called from self.get() or self._peek when - # called from self.peek(). Call this after the initial check - # to see if there are items in the queue. - - if self.is_shutdown: - raise ShutDown - - if block and timeout is not None and timeout < 0: - raise ValueError("'timeout' must be a non-negative number") - if self.hub is getcurrent(): # pylint:disable=undefined-variable - # special case to make get_nowait() or peek_nowait() runnable in the mainloop greenlet - # there are no items in the queue; try to fix the situation by unlocking putters - while self.putters: - # Note: get() used popleft(), peek used pop(); popleft - # is almost certainly correct. - self.putters.popleft().put_and_switch() - if self.qsize(): - return method() - raise Empty - - if not block: - # We can't block, we're not the hub, and we have nothing - # to return. No choice but to raise the Empty exception. - # - # CAUTION: Calling ``q.get(False)`` in a tight loop won't - # work like it does in CPython where it should eventually - # let another thread make progress, because there's never - # a chance to switch greenlets here. We don't sleep() - # to enforce that, as that would be a significant behaviour - # change. - raise Empty - - waiter = Waiter() # pylint:disable=undefined-variable - timeout = Timeout._start_new_or_dummy(timeout, Empty) - try: - self.getters.append(waiter) - if self.putters: - self._schedule_unlock() - result = waiter.get() - if result is not waiter: - raise InvalidSwitchError('Invalid switch into Queue.get: %r' % (result, )) - return method() - finally: - timeout.cancel() - _safe_remove(self.getters, waiter) - - def get(self, block=True, timeout=None): - """ - Remove and return an item from the queue. - - If optional args *block* is true and *timeout* is ``None`` (the default), - block if necessary until an item is available. If *timeout* is a positive number, - it blocks at most *timeout* seconds and raises the :class:`Empty` exception - if no item was available within that time. Otherwise (*block* is false), return - an item if one is immediately available, else raise the :class:`Empty` exception - (*timeout* is ignored in that case). - """ - if self.qsize(): - if self.putters: - self._schedule_unlock() - return self._get() - - return self.__get_or_peek(self._get, block, timeout) - - def get_nowait(self): - """Remove and return an item from the queue without blocking. - - Only get an item if one is immediately available. Otherwise - raise the :class:`Empty` exception. - """ - return self.get(False) - - def peek(self, block=True, timeout=None): - """Return an item from the queue without removing it. - - If optional args *block* is true and *timeout* is ``None`` (the default), - block if necessary until an item is available. If *timeout* is a positive number, - it blocks at most *timeout* seconds and raises the :class:`Empty` exception - if no item was available within that time. Otherwise (*block* is false), return - an item if one is immediately available, else raise the :class:`Empty` exception - (*timeout* is ignored in that case). - """ - if self.qsize(): - # This doesn't schedule an unlock like get() does because we're not - # actually making any space. - return self._peek() - - return self.__get_or_peek(self._peek, block, timeout) - - def peek_nowait(self): - """Return an item from the queue without blocking. - - Only return an item if one is immediately available. Otherwise - raise the :class:`Empty` exception. - """ - return self.peek(False) - - def _unlock(self): - while True: - repeat = False - if self.putters and (self._maxsize == -1 or self.qsize() < self._maxsize): - repeat = True - try: - putter = self.putters.popleft() - self._put(putter.item) - except: # pylint:disable=bare-except - putter.throw(*sys.exc_info()) - else: - putter.switch(putter) - if self.getters and self.qsize(): - repeat = True - getter = self.getters.popleft() - getter.switch(getter) - if not repeat: - return - - def _schedule_unlock(self): - if not self._event_unlock: - self._event_unlock = self.hub.loop.run_callback(self._unlock) - - def __iter__(self): - return self - - def __next__(self): - result = self.get() - if result is StopIteration: - raise result - return result - - -class Queue(SimpleQueue): - """ - A subclass of :class:`SimpleQueue` that additionally has - :meth:`task_done` and :meth:`join` methods. - - .. versionchanged:: 25.4.1 - Renamed from ``JoinablQueue`` to simply ``Queue`` to better - match the capability of the standard library :class:`queue.Queue`. - """ - - __slots__ = ( - '_cond', - 'unfinished_tasks', - ) - - def __init__(self, maxsize=None, items=(), unfinished_tasks=None): - """ - - .. versionchanged:: 1.1a1 - If *unfinished_tasks* is not given, then all the given *items* - (if any) will be considered unfinished. - - """ - SimpleQueue.__init__(self, maxsize, items, _warn_depth=3) - - from gevent.event import Event - self._cond = Event() - self._cond.set() - - if unfinished_tasks: - self.unfinished_tasks = unfinished_tasks - elif items: - self.unfinished_tasks = len(items) - else: - self.unfinished_tasks = 0 - - if self.unfinished_tasks: - self._cond.clear() - - def copy(self): - return type(self)(self.maxsize, self.queue, self.unfinished_tasks) - - def _format(self): - result = SimpleQueue._format(self) - if self.unfinished_tasks: - result += ' tasks=%s _cond=%s' % (self.unfinished_tasks, self._cond) - return result - - def _put(self, item): - SimpleQueue._put(self, item) - self._did_put_task() - - def _did_put_task(self): - self.unfinished_tasks += 1 - self._cond.clear() - - def task_done(self): - '''Indicate that a formerly enqueued task is complete. Used by queue consumer threads. - For each :meth:`get ` used to fetch a task, a subsequent call to - :meth:`task_done` tells the queue that the processing on the task is complete. - - If a :meth:`join` is currently blocking, it will resume when all items have been processed - (meaning that a :meth:`task_done` call was received for every item that had been - :meth:`put ` into the queue). - - Raises a :exc:`ValueError` if called more times than there were items placed in the queue. - ''' - if self.unfinished_tasks <= 0: - raise ValueError('task_done() called too many times') - self.unfinished_tasks -= 1 - if self.unfinished_tasks == 0: - self._cond.set() - - def join(self, timeout=None): - ''' - Block until all items in the queue have been gotten and processed. - - The count of unfinished tasks goes up whenever an item is added to the queue. - The count goes down whenever a consumer thread calls :meth:`task_done` to indicate - that the item was retrieved and all work on it is complete. When the count of - unfinished tasks drops to zero, :meth:`join` unblocks. - - :param float timeout: If not ``None``, then wait no more than this time in seconds - for all tasks to finish. - :return: ``True`` if all tasks have finished; if ``timeout`` was given and expired before - all tasks finished, ``False``. - - .. versionchanged:: 1.1a1 - Add the *timeout* parameter. - ''' - return self._cond.wait(timeout=timeout) - - def shutdown(self, immediate=False): - """ - "Shut-down the queue, making queue gets and puts raise - `ShutDown`. - - By default, gets will only raise once the queue is empty. Set - *immediate* to True to make gets raise immediately instead. - - All blocked callers of `put` and `get` will be unblocked. - - In joinable queues, if *immediate*, a task is marked as done - for each item remaining in the queue, which may unblock - callers of `join`. - """ - self.is_shutdown = True - if immediate: - self._drain_for_immediate_shutdown() - getters = list(self.getters) - putters = list(self.putters) - self.getters.clear() - self.putters.clear() - for waiter in getters + putters: - self.hub.loop.run_callback(waiter.throw, ShutDown) - - def _drain_for_immediate_shutdown(self): - while self.qsize(): - self.get() - self.task_done() - -#: .. versionchanged:: 25.4.1 -#: Now a BWC alias -JoinableQueue = Queue - -class UnboundQueue(Queue): - # A specialization of Queue that knows it can never - # be bound. Changing its maxsize has no effect. - - __slots__ = () - - def __init__(self, maxsize=None, items=()): - if maxsize is not None: - raise ValueError("UnboundQueue has no maxsize") - Queue.__init__(self, maxsize, items) - self.putters = None # Will never be used. - - def put(self, item, block=True, timeout=None): - self._put(item) - if self.getters: - self._schedule_unlock() - - -class PriorityQueue(Queue): - '''A subclass of :class:`Queue` that retrieves entries in priority order (lowest first). - - Entries are typically tuples of the form: ``(priority number, data)``. - - .. versionchanged:: 1.2a1 - Any *items* given to the constructor will now be passed through - :func:`heapq.heapify` to ensure the invariants of this class hold. - Previously it was just assumed that they were already a heap. - ''' - - __slots__ = () - - def _create_queue(self, items=()): - q = list(items) - _heapify(q) - return q - - def _put(self, item): - _heappush(self.queue, item) - self._did_put_task() - - def _get(self): - return _heappop(self.queue) - - -class LifoQueue(Queue): - """ - A subclass of :class:`JoinableQueue` that retrieves most recently added entries first. - - .. versionchanged:: 24.10.1 - Now extends :class:`JoinableQueue` instead of just :class:`Queue`. - - """ - __slots__ = () - - def _create_queue(self, items=()): - return list(items) - - def _put(self, item): - self.queue.append(item) - self._did_put_task() - - def _get(self): - return self.queue.pop() - - def _peek(self): - return self.queue[-1] - - -class Channel: - """ - A queue-like object that can only hold one item at a - time. - - This is commonly used as a synchronization primitive, - and is implemented efficiently for this use-case. - - .. versionchanged:: 25.4.2 - Make this class subscriptable. - """ - - __slots__ = ( - 'getters', - 'putters', - 'hub', - '_event_unlock', - '__weakref__', - ) - - __class_getitem__ = classmethod(types.GenericAlias) - - def __init__(self, maxsize=1): - # We take maxsize to simplify certain kinds of code - if maxsize != 1: - raise ValueError("Channels have a maxsize of 1") - self.getters = collections.deque() - self.putters = collections.deque() - self.hub = get_hub() - self._event_unlock = None - - def __repr__(self): - return '<%s at %s %s>' % (type(self).__name__, hex(id(self)), self._format()) - - def __str__(self): - return '<%s %s>' % (type(self).__name__, self._format()) - - def _format(self): - result = '' - if self.getters: - result += ' getters[%s]' % len(self.getters) - if self.putters: - result += ' putters[%s]' % len(self.putters) - return result - - @property - def balance(self): - return len(self.putters) - len(self.getters) - - def qsize(self): - return 0 - - def empty(self): - return True - - def full(self): - return True - - def put(self, item, block=True, timeout=None): - if self.hub is getcurrent(): # pylint:disable=undefined-variable - if self.getters: - getter = self.getters.popleft() - getter.switch(item) - return - raise Full - - if not block: - timeout = 0 - - waiter = Waiter() # pylint:disable=undefined-variable - item = (item, waiter) - self.putters.append(item) - timeout = Timeout._start_new_or_dummy(timeout, Full) - try: - if self.getters: - self._schedule_unlock() - result = waiter.get() - if result is not waiter: - raise InvalidSwitchError("Invalid switch into Channel.put: %r" % (result, )) - except: - _safe_remove(self.putters, item) - raise - finally: - timeout.cancel() - - def put_nowait(self, item): - self.put(item, False) - - def get(self, block=True, timeout=None): - if self.hub is getcurrent(): # pylint:disable=undefined-variable - if self.putters: - item, putter = self.putters.popleft() - self.hub.loop.run_callback(putter.switch, putter) - return item - - if not block: - timeout = 0 - - waiter = Waiter() # pylint:disable=undefined-variable - timeout = Timeout._start_new_or_dummy(timeout, Empty) - try: - self.getters.append(waiter) - if self.putters: - self._schedule_unlock() - return waiter.get() - except: - self.getters.remove(waiter) - raise - finally: - timeout.close() - - def get_nowait(self): - return self.get(False) - - def _unlock(self): - while self.putters and self.getters: - getter = self.getters.popleft() - item, putter = self.putters.popleft() - getter.switch(item) - putter.switch(putter) - - def _schedule_unlock(self): - if not self._event_unlock: - self._event_unlock = self.hub.loop.run_callback(self._unlock) - - def __iter__(self): - return self - - def __next__(self): - result = self.get() - if result is StopIteration: - raise result - return result - - next = __next__ # Py2 - -def _init(): - greenlet_init() # pylint:disable=undefined-variable - -_init() - - -from gevent._util import import_c_accel -import_c_accel(globals(), 'gevent._queue') diff --git a/venv/lib/python3.9/site-packages/gevent/resolver/__init__.py b/venv/lib/python3.9/site-packages/gevent/resolver/__init__.py deleted file mode 100644 index ac5fc12..0000000 --- a/venv/lib/python3.9/site-packages/gevent/resolver/__init__.py +++ /dev/null @@ -1,285 +0,0 @@ -# Copyright (c) 2018 gevent contributors. See LICENSE for details. - -import _socket -from _socket import AF_INET -from _socket import AF_UNSPEC -from _socket import AI_CANONNAME -from _socket import AI_PASSIVE -from _socket import AI_NUMERICHOST -from _socket import EAI_NONAME -from _socket import EAI_SERVICE -from _socket import SOCK_DGRAM -from _socket import SOCK_STREAM -from _socket import SOL_TCP -from _socket import error -from _socket import gaierror -from _socket import getaddrinfo as native_getaddrinfo -from _socket import getnameinfo as native_getnameinfo -from _socket import gethostbyaddr as native_gethostbyaddr -from _socket import gethostbyname as native_gethostbyname -from _socket import gethostbyname_ex as native_gethostbyname_ex -from _socket import getservbyname as native_getservbyname - - -from gevent._compat import string_types -from gevent._compat import text_type -from gevent._compat import hostname_types -from gevent._compat import integer_types -from gevent._compat import PYPY -from gevent._compat import MAC - -from gevent.resolver._addresses import is_ipv6_addr -# Nothing public here. -__all__ = () - -# trigger import of encodings.idna to avoid https://github.com/gevent/gevent/issues/349 -u'foo'.encode('idna') - - -def _lookup_port(port, socktype): - # pylint:disable=too-many-branches - socktypes = [] - if isinstance(port, string_types): - try: - port = int(port) - except ValueError: - try: - if socktype == 0: - origport = port - try: - port = native_getservbyname(port, 'tcp') - socktypes.append(SOCK_STREAM) - except error: - port = native_getservbyname(port, 'udp') - socktypes.append(SOCK_DGRAM) - else: - try: - if port == native_getservbyname(origport, 'udp'): - socktypes.append(SOCK_DGRAM) - except error: - pass - elif socktype == SOCK_STREAM: - port = native_getservbyname(port, 'tcp') - elif socktype == SOCK_DGRAM: - port = native_getservbyname(port, 'udp') - else: - raise gaierror(EAI_SERVICE, 'Servname not supported for ai_socktype') - except error as ex: - if 'not found' in str(ex): - raise gaierror(EAI_SERVICE, 'Servname not supported for ai_socktype') - raise gaierror(str(ex)) - except UnicodeEncodeError: - raise error('Int or String expected', port) - elif port is None: - port = 0 - elif isinstance(port, integer_types): - pass - else: - raise error('Int or String expected', port, type(port)) - port = int(port % 65536) - if not socktypes and socktype: - socktypes.append(socktype) - return port, socktypes - - - -def _resolve_special(hostname, family): - if not isinstance(hostname, hostname_types): - raise TypeError("argument 1 must be str, bytes or bytearray, not %s" % (type(hostname),)) - - if hostname in (u'', b''): - result = native_getaddrinfo(None, 0, family, SOCK_DGRAM, 0, AI_PASSIVE) - if len(result) != 1: - raise error('wildcard resolved to multiple address') - return result[0][4][0] - return hostname - - -class AbstractResolver(object): - - HOSTNAME_ENCODING = 'idna' - - _LOCAL_HOSTNAMES = ( - b'localhost', - b'ip6-localhost', - b'::1', - b'127.0.0.1', - ) - - _LOCAL_AND_BROADCAST_HOSTNAMES = _LOCAL_HOSTNAMES + ( - b'255.255.255.255', - b'', - ) - - EAI_NONAME_MSG = ( - 'nodename nor servname provided, or not known' - if MAC else - 'Name or service not known' - ) - - EAI_FAMILY_MSG = ( - 'ai_family not supported' - ) - - _KNOWN_ADDR_FAMILIES = { - v - for k, v in vars(_socket).items() - if k.startswith('AF_') - } - - _KNOWN_SOCKTYPES = { - v - for k, v in vars(_socket).items() - if k.startswith('SOCK_') - and k not in ('SOCK_CLOEXEC', 'SOCK_MAX_SIZE') - } - - def close(self): - """ - Release resources held by this object. - - Subclasses that define resources should override. - - .. versionadded:: 22.10.1 - """ - - @staticmethod - def fixup_gaierror(func): - import functools - - @functools.wraps(func) - def resolve(self, *args, **kwargs): - try: - return func(self, *args, **kwargs) - except gaierror as ex: - if ex.args[0] == EAI_NONAME and len(ex.args) == 1: - # dnspython doesn't set an error message - ex.args = (EAI_NONAME, self.EAI_NONAME_MSG) - ex.errno = EAI_NONAME - raise - return resolve - - def _hostname_to_bytes(self, hostname): - if isinstance(hostname, text_type): - hostname = hostname.encode(self.HOSTNAME_ENCODING) - elif not isinstance(hostname, (bytes, bytearray)): - raise TypeError('Expected str, bytes or bytearray, not %s' % type(hostname).__name__) - - return bytes(hostname) - - def gethostbyname(self, hostname, family=AF_INET): - # The native ``gethostbyname`` and ``gethostbyname_ex`` have some different - # behaviour with special names. Notably, ``gethostbyname`` will handle - # both "" and "255.255.255.255", while ``gethostbyname_ex`` refuses to - # handle those; they result in different errors, too. So we can't - # pass those through. - hostname = self._hostname_to_bytes(hostname) - if hostname in self._LOCAL_AND_BROADCAST_HOSTNAMES: - return native_gethostbyname(hostname) - hostname = _resolve_special(hostname, family) - return self.gethostbyname_ex(hostname, family)[-1][0] - - def _gethostbyname_ex(self, hostname_bytes, family): - """Raise an ``herror`` or a ``gaierror``.""" - aliases = self._getaliases(hostname_bytes, family) - addresses = [] - tuples = self.getaddrinfo(hostname_bytes, 0, family, - SOCK_STREAM, - SOL_TCP, AI_CANONNAME) - canonical = tuples[0][3] - for item in tuples: - addresses.append(item[4][0]) - # XXX we just ignore aliases - return (canonical, aliases, addresses) - - def gethostbyname_ex(self, hostname, family=AF_INET): - hostname = self._hostname_to_bytes(hostname) - if hostname in self._LOCAL_AND_BROADCAST_HOSTNAMES: - # The broadcast specials aren't handled here, but they may produce - # special errors that are hard to replicate across all systems. - return native_gethostbyname_ex(hostname) - return self._gethostbyname_ex(hostname, family) - - def _getaddrinfo(self, host_bytes, port, family, socktype, proto, flags): - raise NotImplementedError - - def getaddrinfo(self, host, port, family=0, socktype=0, proto=0, flags=0): - host = self._hostname_to_bytes(host) if host is not None else None - - if ( - not isinstance(host, bytes) # 1, 2 - or (flags & AI_NUMERICHOST) # 3 - or host in self._LOCAL_HOSTNAMES # 4 - or (is_ipv6_addr(host) and host.startswith(b'fe80')) # 5 - ): - # This handles cases which do not require network access - # 1) host is None - # 2) host is of an invalid type - # 3) AI_NUMERICHOST flag is set - # 4) It's a well-known alias. TODO: This is special casing for c-ares that we don't - # really want to do. It's here because it resolves a discrepancy with the system - # resolvers caught by test cases. In gevent 20.4.0, this only worked correctly on - # Python 3 and not Python 2, by accident. - # 5) host is a link-local ipv6; dnspython returns the wrong - # scope-id for those. - return native_getaddrinfo(host, port, family, socktype, proto, flags) - - return self._getaddrinfo(host, port, family, socktype, proto, flags) - - def _getaliases(self, hostname, family): - # pylint:disable=unused-argument - return [] - - def _gethostbyaddr(self, ip_address_bytes): - """Raises herror.""" - raise NotImplementedError - - def gethostbyaddr(self, ip_address): - ip_address = _resolve_special(ip_address, AF_UNSPEC) - ip_address = self._hostname_to_bytes(ip_address) - if ip_address in self._LOCAL_AND_BROADCAST_HOSTNAMES: - return native_gethostbyaddr(ip_address) - - return self._gethostbyaddr(ip_address) - - def _getnameinfo(self, address_bytes, port, sockaddr, flags): - raise NotImplementedError - - def getnameinfo(self, sockaddr, flags): - if not isinstance(flags, integer_types): - raise TypeError('an integer is required') - if not isinstance(sockaddr, tuple): - raise TypeError('getnameinfo() argument 1 must be a tuple') - - address = sockaddr[0] - address = self._hostname_to_bytes(sockaddr[0]) - - if address in self._LOCAL_AND_BROADCAST_HOSTNAMES: - return native_getnameinfo(sockaddr, flags) - - port = sockaddr[1] - if not isinstance(port, integer_types): - raise TypeError('port must be an integer, not %s' % type(port)) - - if not PYPY and port >= 65536: - # System resolvers do different things with an - # out-of-bound port; macOS CPython 3.8 raises ``gaierror: [Errno 8] - # nodename nor servname provided, or not known``, while - # manylinux CPython 2.7 appears to ignore it and raises ``error: - # sockaddr resolved to multiple addresses``. TravisCI, at least ot - # one point, successfully resolved www.gevent.org to ``(readthedocs.org, '0')``. - # But c-ares 1.16 would raise ``gaierror(25, 'ARES_ESERVICE: unknown')``. - # Doing this appears to get the expected results on CPython - port = 0 - if PYPY and (port < 0 or port >= 65536): - # PyPy seems to always be strict about that and produce the same results - # on all platforms. - raise OverflowError("port must be 0-65535.") - - if len(sockaddr) > 2: - # Must be IPv6: (host, port, [flowinfo, [scopeid]]) - flowinfo = sockaddr[2] - if flowinfo > 0xfffff: - raise OverflowError("getnameinfo(): flowinfo must be 0-1048575.") - - return self._getnameinfo(address, port, sockaddr, flags) diff --git a/venv/lib/python3.9/site-packages/gevent/resolver/_addresses.py b/venv/lib/python3.9/site-packages/gevent/resolver/_addresses.py deleted file mode 100644 index f6682a1..0000000 --- a/venv/lib/python3.9/site-packages/gevent/resolver/_addresses.py +++ /dev/null @@ -1,163 +0,0 @@ -# -*- coding: utf-8 -*- -# Copyright (c) 2019 gevent contributors. See LICENSE for details. -# -# Portions of this code taken from dnspython -# https://github.com/rthalley/dnspython -# -# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license - -# Copyright (C) 2003-2017 Nominum, Inc. -# -# Permission to use, copy, modify, and distribute this software and its -# documentation for any purpose with or without fee is hereby granted, -# provided that the above copyright notice and this permission notice -# appear in all copies. -# -# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES -# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR -# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT -# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -""" -Private support for parsing textual addresses. - -""" -from __future__ import absolute_import, division, print_function - -import binascii -import re -import struct - -from gevent.resolver import hostname_types - - -class AddressSyntaxError(ValueError): - pass - - -def _ipv4_inet_aton(text): - """ - Convert an IPv4 address in text form to binary struct. - - *text*, a ``text``, the IPv4 address in textual form. - - Returns a ``binary``. - """ - - if not isinstance(text, bytes): - text = text.encode() - parts = text.split(b'.') - if len(parts) != 4: - raise AddressSyntaxError(text) - for part in parts: - if not part.isdigit(): - raise AddressSyntaxError - if len(part) > 1 and part[0] == '0': - # No leading zeros - raise AddressSyntaxError(text) - try: - ints = [int(part) for part in parts] - return struct.pack('BBBB', *ints) - except: - raise AddressSyntaxError(text) - - -def _ipv6_inet_aton(text, - _v4_ending=re.compile(br'(.*):(\d+\.\d+\.\d+\.\d+)$'), - _colon_colon_start=re.compile(br'::.*'), - _colon_colon_end=re.compile(br'.*::$')): - """ - Convert an IPv6 address in text form to binary form. - - *text*, a ``text``, the IPv6 address in textual form. - - Returns a ``binary``. - """ - # pylint:disable=too-many-branches - - # - # Our aim here is not something fast; we just want something that works. - # - if not isinstance(text, bytes): - text = text.encode() - - if text == b'::': - text = b'0::' - # - # Get rid of the icky dot-quad syntax if we have it. - # - m = _v4_ending.match(text) - if not m is None: - b = bytearray(_ipv4_inet_aton(m.group(2))) - text = (u"{}:{:02x}{:02x}:{:02x}{:02x}".format(m.group(1).decode(), - b[0], b[1], b[2], - b[3])).encode() - # - # Try to turn '::' into ':'; if no match try to - # turn '::' into ':' - # - m = _colon_colon_start.match(text) - if not m is None: - text = text[1:] - else: - m = _colon_colon_end.match(text) - if not m is None: - text = text[:-1] - # - # Now canonicalize into 8 chunks of 4 hex digits each - # - chunks = text.split(b':') - l = len(chunks) - if l > 8: - raise SyntaxError - seen_empty = False - canonical = [] - for c in chunks: - if c == b'': - if seen_empty: - raise AddressSyntaxError(text) - seen_empty = True - for _ in range(0, 8 - l + 1): - canonical.append(b'0000') - else: - lc = len(c) - if lc > 4: - raise AddressSyntaxError(text) - if lc != 4: - c = (b'0' * (4 - lc)) + c - canonical.append(c) - if l < 8 and not seen_empty: - raise AddressSyntaxError(text) - text = b''.join(canonical) - - # - # Finally we can go to binary. - # - try: - return binascii.unhexlify(text) - except (binascii.Error, TypeError): - raise AddressSyntaxError(text) - - -def _is_addr(host, parse=_ipv4_inet_aton): - if not host or not isinstance(host, hostname_types): - return False - - try: - parse(host) - except AddressSyntaxError: - return False - return True - -# Return True if host is a valid IPv4 address -is_ipv4_addr = _is_addr - - -def is_ipv6_addr(host): - # Return True if host is a valid IPv6 address - if host and isinstance(host, hostname_types): - s = '%' if isinstance(host, str) else b'%' - host = host.split(s, 1)[0] - return _is_addr(host, _ipv6_inet_aton) diff --git a/venv/lib/python3.9/site-packages/gevent/resolver/_hostsfile.py b/venv/lib/python3.9/site-packages/gevent/resolver/_hostsfile.py deleted file mode 100644 index 792f849..0000000 --- a/venv/lib/python3.9/site-packages/gevent/resolver/_hostsfile.py +++ /dev/null @@ -1,145 +0,0 @@ -# -*- coding: utf-8 -*- -# Copyright (c) 2019 gevent contributors. See LICENSE for details. -# -# Portions of this code taken from dnspython -# https://github.com/rthalley/dnspython -# -# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license - -# Copyright (C) 2003-2017 Nominum, Inc. -# -# Permission to use, copy, modify, and distribute this software and its -# documentation for any purpose with or without fee is hereby granted, -# provided that the above copyright notice and this permission notice -# appear in all copies. -# -# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES -# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR -# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT -# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -""" -Private support for parsing /etc/hosts. - -""" -from __future__ import absolute_import, division, print_function - -import sys -import os -import re - -from gevent.resolver._addresses import is_ipv4_addr -from gevent.resolver._addresses import is_ipv6_addr - -from gevent._compat import iteritems - - -class HostsFile(object): - """ - A class to read the contents of a hosts file (/etc/hosts). - """ - - LINES_RE = re.compile(r""" - \s* # Leading space - ([^\r\n#]+?) # The actual match, non-greedy so as not to include trailing space - \s* # Trailing space - (?:[#][^\r\n]+)? # Comments - (?:$|[\r\n]+) # EOF or newline - """, re.VERBOSE) - - def __init__(self, fname=None): - self.v4 = {} # name -> ipv4 - self.v6 = {} # name -> ipv6 - self.aliases = {} # name -> canonical_name - self.reverse = {} # ip addr -> some name - if fname is None: - if os.name == 'posix': - fname = '/etc/hosts' - elif os.name == 'nt': # pragma: no cover - fname = os.path.expandvars( - r'%SystemRoot%\system32\drivers\etc\hosts') - self.fname = fname - assert self.fname - self._last_load = 0 - - - def _readlines(self): - # Read the contents of the hosts file. - # - # Return list of lines, comment lines and empty lines are - # excluded. Note that this performs disk I/O so can be - # blocking. - with open(self.fname, 'rb') as fp: - fdata = fp.read() - - - # XXX: Using default decoding. Is that correct? - udata = fdata.decode(errors='ignore') if not isinstance(fdata, str) else fdata - - return self.LINES_RE.findall(udata) - - def load(self): # pylint:disable=too-many-locals - # Load hosts file - - # This will (re)load the data from the hosts - # file if it has changed. - - try: - load_time = os.stat(self.fname).st_mtime - needs_load = load_time > self._last_load - except OSError: - from gevent import get_hub - get_hub().handle_error(self, *sys.exc_info()) - needs_load = False - - if not needs_load: - return - - v4 = {} - v6 = {} - aliases = {} - reverse = {} - - for line in self._readlines(): - parts = line.split() - if len(parts) < 2: - continue - ip = parts.pop(0) - if is_ipv4_addr(ip): - ipmap = v4 - elif is_ipv6_addr(ip): - if ip.startswith('fe80'): - # Do not use link-local addresses, OSX stores these here - continue - ipmap = v6 - else: - continue - cname = parts.pop(0).lower() - ipmap[cname] = ip - for alias in parts: - alias = alias.lower() - ipmap[alias] = ip - aliases[alias] = cname - - # XXX: This is wrong for ipv6 - if ipmap is v4: - ptr = '.'.join(reversed(ip.split('.'))) + '.in-addr.arpa' - else: - ptr = ip + '.ip6.arpa.' - if ptr not in reverse: - reverse[ptr] = cname - - self._last_load = load_time - self.v4 = v4 - self.v6 = v6 - self.aliases = aliases - self.reverse = reverse - - def iter_all_host_addr_pairs(self): - self.load() - for name, addr in iteritems(self.v4): - yield name, addr - for name, addr in iteritems(self.v6): - yield name, addr diff --git a/venv/lib/python3.9/site-packages/gevent/resolver/ares.py b/venv/lib/python3.9/site-packages/gevent/resolver/ares.py deleted file mode 100644 index 8ec2225..0000000 --- a/venv/lib/python3.9/site-packages/gevent/resolver/ares.py +++ /dev/null @@ -1,355 +0,0 @@ -# Copyright (c) 2011-2015 Denis Bilenko. See LICENSE for details. -""" -c-ares based hostname resolver. -""" -from __future__ import absolute_import, print_function, division -import os -import warnings - -from _socket import gaierror -from _socket import herror -from _socket import error -from _socket import EAI_NONAME - -from gevent._compat import text_type -from gevent._compat import integer_types - -from gevent.hub import Waiter -from gevent.hub import get_hub - -from gevent.socket import AF_UNSPEC -from gevent.socket import AF_INET -from gevent.socket import AF_INET6 -from gevent.socket import SOCK_DGRAM -from gevent.socket import SOCK_STREAM -from gevent.socket import SOL_TCP -from gevent.socket import SOL_UDP - - -from gevent._config import config -from gevent._config import AresSettingMixin - -from .cares import channel, InvalidIP # pylint:disable=import-error,no-name-in-module -from . import _lookup_port as lookup_port -from . import AbstractResolver - -__all__ = ['Resolver'] - - -class Resolver(AbstractResolver): - """ - Implementation of the resolver API using the `c-ares`_ library. - - This implementation uses the c-ares library to handle name - resolution. c-ares is natively asynchronous at the socket level - and so integrates well into gevent's event loop. - - In comparison to :class:`gevent.resolver_thread.Resolver` (which - delegates to the native system resolver), the implementation is - much more complex. In addition, there have been reports of it not - properly honoring certain system configurations (for example, the - order in which IPv4 and IPv6 results are returned may not match - the threaded resolver). However, because it does not use threads, - it may scale better for applications that make many lookups. - - There are some known differences from the system resolver. - - - ``gethostbyname_ex`` and ``gethostbyaddr`` may return - different for the ``aliaslist`` tuple member. (Sometimes the - same, sometimes in a different order, sometimes a different - alias altogether.) - - - ``gethostbyname_ex`` may return the ``ipaddrlist`` in a - different order. - - - ``getaddrinfo`` does not return ``SOCK_RAW`` results. - - - ``getaddrinfo`` may return results in a different order. - - - Handling of ``.local`` (mDNS) names may be different, even - if they are listed in the hosts file. - - - c-ares will not resolve ``broadcasthost``, even if listed in - the hosts file prior to 2020-04-30. - - - This implementation may raise ``gaierror(4)`` where the - system implementation would raise ``herror(1)`` or vice versa, - with different error numbers. However, after 2020-04-30, this should be - much reduced. - - - The results for ``localhost`` may be different. In - particular, some system resolvers will return more results - from ``getaddrinfo`` than c-ares does, such as SOCK_DGRAM - results, and c-ares may report more ips on a multi-homed - host. - - - The system implementation may return some names fully qualified, where - this implementation returns only the host name. This appears to be - the case only with entries found in ``/etc/hosts``. - - - c-ares supports a limited set of flags for ``getnameinfo`` and - ``getaddrinfo``; unknown flags are ignored. System-specific flags - such as ``AI_V4MAPPED_CFG`` are not supported. - - - ``getaddrinfo`` may return canonical names even without the ``AI_CANONNAME`` - being set. - - - ``getaddrinfo`` does not appear to support IPv6 symbolic scope IDs. - - .. caution:: - - This module is considered extremely experimental on PyPy, and - due to its implementation in cython, it may be slower. It may also lead to - interpreter crashes. - - .. versionchanged:: 1.5.0 - This version of gevent typically embeds c-ares 1.15.0 or newer. In - that version of c-ares, domains ending in ``.onion`` `are never - resolved `_ or even - sent to the DNS server. - - .. versionchanged:: 20.5.0 - ``getaddrinfo`` is now implemented using the native c-ares function - from c-ares 1.16 or newer. - - .. versionchanged:: 20.5.0 - Now ``herror`` and ``gaierror`` are raised more consistently with - the standard library resolver, and have more consistent errno values. - - Handling of localhost and broadcast names is now more consistent. - - .. versionchanged:: 22.10.1 - Now has a ``__del__`` method that warns if the object is destroyed - without being properly closed. - - .. _c-ares: http://c-ares.haxx.se - """ - - cares_class = channel - - def __init__(self, hub=None, use_environ=True, **kwargs): - AbstractResolver.__init__(self) - if hub is None: - hub = get_hub() - self.hub = hub - if use_environ: - for setting in config.settings.values(): - if isinstance(setting, AresSettingMixin): - value = setting.get() - if value is not None: - kwargs.setdefault(setting.kwarg_name, value) - self.cares = self.cares_class(hub.loop, **kwargs) - self.pid = os.getpid() - self.params = kwargs - self.fork_watcher = hub.loop.fork(ref=False) # We shouldn't keep the loop alive - self.fork_watcher.start(self._on_fork) - - def __repr__(self): - return '' % (id(self), self.cares) - - def _on_fork(self): - # NOTE: See comment in gevent.hub.reinit. - pid = os.getpid() - if pid != self.pid: - self.hub.loop.run_callback(self.cares.destroy) - self.cares = self.cares_class(self.hub.loop, **self.params) - self.pid = pid - - def close(self): - AbstractResolver.close(self) - if self.cares is not None: - self.hub.loop.run_callback(self.cares.destroy) - self.cares = None - self.fork_watcher.stop() - - def __del__(self): - if self.cares is not None: - warnings.warn("cares Resolver destroyed while not closed", - ResourceWarning) - self.close() - - def _gethostbyname_ex(self, hostname_bytes, family): - while True: - ares = self.cares - try: - waiter = Waiter(self.hub) - ares.gethostbyname(waiter, hostname_bytes, family) - result = waiter.get() - if not result[-1]: - raise herror(EAI_NONAME, self.EAI_NONAME_MSG) - return result - except herror as ex: - if ares is self.cares: - if ex.args[0] == 1: - # Somewhere along the line, the internal - # implementation of gethostbyname_ex changed to invoke - # getaddrinfo() as a first pass, much like we do for ``getnameinfo()``; - # this means it raises a different error for not-found hosts. - raise gaierror(EAI_NONAME, self.EAI_NONAME_MSG) - raise - # "self.cares is not ares" means channel was destroyed (because we were forked) - - def _lookup_port(self, port, socktype): - return lookup_port(port, socktype) - - def __getaddrinfo( - self, host, port, - family=0, socktype=0, proto=0, flags=0, - fill_in_type_proto=True - ): - """ - Returns a list ``(family, socktype, proto, canonname, sockaddr)`` - - :raises gaierror: If no results are found. - """ - # pylint:disable=too-many-locals,too-many-branches - if isinstance(host, text_type): - host = host.encode('idna') - - - if isinstance(port, text_type): - port = port.encode('ascii') - elif isinstance(port, integer_types): - if port == 0: - port = None - else: - port = str(port).encode('ascii') - - waiter = Waiter(self.hub) - self.cares.getaddrinfo( - waiter, - host, - port, - family, - socktype, - proto, - flags, - ) - # Result is a list of: - # (family, socktype, proto, canonname, sockaddr) - # Where sockaddr depends on family; for INET it is - # (address, port) - # and INET6 is - # (address, port, flow info, scope id) - result = waiter.get() - - if not result: - raise gaierror(EAI_NONAME, self.EAI_NONAME_MSG) - - if fill_in_type_proto: - # c-ares 1.16 DOES NOT fill in socktype or proto in the results, - # ever. It's at least supposed to do that if they were given as - # hints, but it doesn't (https://github.com/c-ares/c-ares/issues/317) - # Sigh. - # The SOL_* constants are another (older?) name for IPPROTO_* - if socktype: - hard_type_proto = [ - (socktype, SOL_TCP if socktype == SOCK_STREAM else SOL_UDP), - ] - elif proto: - hard_type_proto = [ - (SOCK_STREAM if proto == SOL_TCP else SOCK_DGRAM, proto), - ] - else: - hard_type_proto = [ - (SOCK_STREAM, SOL_TCP), - (SOCK_DGRAM, SOL_UDP), - ] - - # pylint:disable=not-an-iterable,unsubscriptable-object - result = [ - (rfamily, - hard_type if not rtype else rtype, - hard_proto if not rproto else rproto, - rcanon, - raddr) - for rfamily, rtype, rproto, rcanon, raddr - in result - for hard_type, hard_proto - in hard_type_proto - ] - return result - - def _getaddrinfo(self, host_bytes, port, family, socktype, proto, flags): - while True: - ares = self.cares - try: - return self.__getaddrinfo(host_bytes, port, family, socktype, proto, flags) - except gaierror: - if ares is self.cares: - raise - - def __gethostbyaddr(self, ip_address): - waiter = Waiter(self.hub) - try: - self.cares.gethostbyaddr(waiter, ip_address) - return waiter.get() - except InvalidIP: - result = self._getaddrinfo(ip_address, None, - family=AF_UNSPEC, socktype=SOCK_DGRAM, - proto=0, flags=0) - if not result: - raise - # pylint:disable=unsubscriptable-object - _ip_address = result[0][-1][0] - if isinstance(_ip_address, text_type): - _ip_address = _ip_address.encode('ascii') - if _ip_address == ip_address: - raise - waiter.clear() - self.cares.gethostbyaddr(waiter, _ip_address) - return waiter.get() - - def _gethostbyaddr(self, ip_address_bytes): - while True: - ares = self.cares - try: - return self.__gethostbyaddr(ip_address_bytes) - except herror: - if ares is self.cares: - raise - - def __getnameinfo(self, hostname, port, sockaddr, flags): - result = self.__getaddrinfo( - hostname, port, - family=AF_UNSPEC, socktype=SOCK_DGRAM, - proto=0, flags=0, - fill_in_type_proto=False) - if len(result) != 1: - raise error('sockaddr resolved to multiple addresses') - - family, _socktype, _proto, _name, address = result[0] - - if family == AF_INET: - if len(sockaddr) != 2: - raise error("IPv4 sockaddr must be 2 tuple") - elif family == AF_INET6: - address = address[:2] + sockaddr[2:] - - waiter = Waiter(self.hub) - self.cares.getnameinfo(waiter, address, flags) - node, service = waiter.get() - - if service is None: - # ares docs: "If the query did not complete - # successfully, or one of the values was not - # requested, node or service will be NULL ". Python 2 - # allows that for the service, but Python 3 raises - # an error. This is tested by test_socket in py 3.4 - err = gaierror(EAI_NONAME, self.EAI_NONAME_MSG) - err.errno = EAI_NONAME - raise err - - return node, service or '0' - - def _getnameinfo(self, address_bytes, port, sockaddr, flags): - while True: - ares = self.cares - try: - return self.__getnameinfo(address_bytes, port, sockaddr, flags) - except gaierror: - if ares is self.cares: - raise - - # # Things that need proper error handling - # gethostbyaddr = AbstractResolver.convert_gaierror_to_herror(AbstractResolver.gethostbyaddr) diff --git a/venv/lib/python3.9/site-packages/gevent/resolver/blocking.py b/venv/lib/python3.9/site-packages/gevent/resolver/blocking.py deleted file mode 100644 index 4a26a76..0000000 --- a/venv/lib/python3.9/site-packages/gevent/resolver/blocking.py +++ /dev/null @@ -1,45 +0,0 @@ -# Copyright (c) 2018 gevent contributors. See LICENSE for details. - -import _socket - -__all__ = [ - 'Resolver', -] - -class Resolver(object): - """ - A resolver that directly uses the system's resolver functions. - - .. caution:: - - This resolver is *not* cooperative. - - This resolver has the lowest overhead of any resolver and - typically approaches the speed of the unmodified :mod:`socket` - functions. However, it is not cooperative, so if name resolution - blocks, the entire thread and all its greenlets will be blocked. - - This can be useful during debugging, or it may be a good choice if - your operating system provides a good caching resolver (such as - macOS's Directory Services) that is usually very fast and - functionally non-blocking. - - .. versionchanged:: 1.3a2 - This was previously undocumented and existed in :mod:`gevent.socket`. - - """ - - def __init__(self, hub=None): - pass - - def close(self): - pass - - for method in ( - 'gethostbyname', - 'gethostbyname_ex', - 'getaddrinfo', - 'gethostbyaddr', - 'getnameinfo' - ): - locals()[method] = staticmethod(getattr(_socket, method)) diff --git a/venv/lib/python3.9/site-packages/gevent/resolver/cares.cpython-39-x86_64-linux-gnu.so b/venv/lib/python3.9/site-packages/gevent/resolver/cares.cpython-39-x86_64-linux-gnu.so deleted file mode 100755 index 7953fb0..0000000 Binary files a/venv/lib/python3.9/site-packages/gevent/resolver/cares.cpython-39-x86_64-linux-gnu.so and /dev/null differ diff --git a/venv/lib/python3.9/site-packages/gevent/resolver/dnspython.py b/venv/lib/python3.9/site-packages/gevent/resolver/dnspython.py deleted file mode 100644 index df7aded..0000000 --- a/venv/lib/python3.9/site-packages/gevent/resolver/dnspython.py +++ /dev/null @@ -1,511 +0,0 @@ -# Copyright (c) 2018 gevent contributors. See LICENSE for details. - -# Portions of this code taken from the gogreen project: -# http://github.com/slideinc/gogreen -# -# Copyright (c) 2005-2010 Slide, Inc. -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are -# met: -# -# * Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# * Redistributions in binary form must reproduce the above -# copyright notice, this list of conditions and the following -# disclaimer in the documentation and/or other materials provided -# with the distribution. -# * Neither the name of the author nor the names of other -# contributors may be used to endorse or promote products derived -# from this software without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -# Portions of this code taken from the eventlet project: -# https://github.com/eventlet/eventlet/blob/master/eventlet/support/greendns.py - -# Unless otherwise noted, the files in Eventlet are under the following MIT license: - -# Copyright (c) 2005-2006, Bob Ippolito -# Copyright (c) 2007-2010, Linden Research, Inc. -# Copyright (c) 2008-2010, Eventlet Contributors (see AUTHORS) - -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: - -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. - -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. -from __future__ import absolute_import, print_function, division - -import sys -import time - -from _socket import error -from _socket import gaierror -from _socket import herror -from _socket import NI_NUMERICSERV -from _socket import AF_INET -from _socket import AF_INET6 -from _socket import AF_UNSPEC -from _socket import EAI_NONAME -from _socket import EAI_FAMILY - - -import socket - -from gevent.resolver import AbstractResolver -from gevent.resolver._hostsfile import HostsFile - -from gevent.builtins import __import__ as g_import - -from gevent._compat import string_types -from gevent._compat import iteritems -from gevent._config import config - - -__all__ = [ - 'Resolver', -] - -# Import the DNS packages to use the gevent modules, -# even if the system is not monkey-patched. If it *is* already -# patched, this imports a second copy under a different name, -# which is probably not strictly necessary, but matches -# what we've historically done, and allows configuring the resolvers -# differently. - -def _patch_dns(): - from gevent._patcher import import_patched as importer - # The dns package itself is empty but defines __all__ - # we make sure to import all of those things now under the - # patch. Note this triggers two DeprecationWarnings, - # one of which we could avoid. - extras = { - 'dns': ('rdata', 'resolver', 'rdtypes'), - 'dns.rdtypes': ('IN', 'ANY', ), - 'dns.rdtypes.IN': ('A', 'AAAA',), - 'dns.rdtypes.ANY': ('SOA', 'PTR'), - } - def extra_all(mod_name): - return extras.get(mod_name, ()) - - def after_import_hook(dns): # pylint:disable=redefined-outer-name - # Runs while still in the original patching scope. - # The dns.rdata:get_rdata_class() function tries to - # dynamically import modules using __import__ and then walk - # through the attribute tree to find classes in `dns.rdtypes`. - # It is critical that this all matches up, otherwise we can - # get different exception classes that don't get caught. - # We could patch __import__ to do things at runtime, but it's - # easier to enumerate the world and populate the cache now - # before we then switch the names back. - rdata = dns.rdata - get_rdata_class = rdata.get_rdata_class - try: - rdclass_values = list(dns.rdataclass.RdataClass) - except AttributeError: - # dnspython < 2.0 - rdclass_values = dns.rdataclass._by_value - - try: - rdtype_values = list(dns.rdatatype.RdataType) - except AttributeError: - # dnspython < 2.0 - rdtype_values = dns.rdatatype._by_value - - - for rdclass in rdclass_values: - for rdtype in rdtype_values: - get_rdata_class(rdclass, rdtype) - - patcher = importer('dns', extra_all, after_import_hook) - top = patcher.module - - # Now disable the dynamic imports - def _no_dynamic_imports(name): - raise ValueError(name) - - top.rdata.__import__ = _no_dynamic_imports - - return top - -dns = _patch_dns() - -resolver = dns.resolver -dTimeout = dns.resolver.Timeout - -# This is a wrapper for dns.resolver._getaddrinfo with two crucial changes. -# First, it backports https://github.com/rthalley/dnspython/issues/316 -# from version 2.0. This can be dropped when we support only dnspython 2 -# (which means only Python 3.) - -# Second, it adds calls to sys.exc_clear() to avoid failing tests in -# test__refcount.py (timeouts) on Python 2. (Actually, this isn't -# strictly necessary, it was necessary to increase the timeouts in -# that function because dnspython is doing some parsing/regex/host -# lookups that are not super fast. But it does have a habit of leaving -# exceptions around which can complicate our memleak checks.) -def _getaddrinfo(host=None, service=None, family=AF_UNSPEC, socktype=0, - proto=0, flags=0, - _orig_gai=resolver._getaddrinfo, - _exc_clear=getattr(sys, 'exc_clear', lambda: None)): - if flags & (socket.AI_ADDRCONFIG | socket.AI_V4MAPPED) != 0: - # Not implemented. We raise a gaierror as opposed to a - # NotImplementedError as it helps callers handle errors more - # appropriately. [Issue #316] - raise socket.gaierror(socket.EAI_SYSTEM) - res = _orig_gai(host, service, family, socktype, proto, flags) - _exc_clear() - return res - - -resolver._getaddrinfo = _getaddrinfo - -HOSTS_TTL = 300.0 - - -class _HostsAnswer(dns.resolver.Answer): - # Answer class for HostsResolver object - - def __init__(self, qname, rdtype, rdclass, rrset, raise_on_no_answer=True): - self.response = None - self.qname = qname - self.rdtype = rdtype - self.rdclass = rdclass - self.canonical_name = qname - if not rrset and raise_on_no_answer: - raise dns.resolver.NoAnswer() - self.rrset = rrset - self.expiration = (time.time() + - rrset.ttl if hasattr(rrset, 'ttl') else 0) - - -class _HostsResolver(object): - """ - Class to parse the hosts file - """ - - def __init__(self, fname=None, interval=HOSTS_TTL): - self.hosts_file = HostsFile(fname) - self.interval = interval - self._last_load = 0 - - def query(self, qname, rdtype=dns.rdatatype.A, rdclass=dns.rdataclass.IN, - tcp=False, source=None, raise_on_no_answer=True): # pylint:disable=unused-argument - # Query the hosts file - # - # The known rdtypes are dns.rdatatype.A, dns.rdatatype.AAAA and - # dns.rdatatype.CNAME. - # The ``rdclass`` parameter must be dns.rdataclass.IN while the - # ``tcp`` and ``source`` parameters are ignored. - # Return a HostAnswer instance or raise a dns.resolver.NoAnswer - # exception. - - now = time.time() - hosts_file = self.hosts_file - if self._last_load + self.interval < now: - self._last_load = now - hosts_file.load() - - rdclass = dns.rdataclass.IN # Always - if isinstance(qname, string_types): - name = qname - qname = dns.name.from_text(qname) - else: - name = str(qname) - - name = name.lower() - rrset = dns.rrset.RRset(qname, rdclass, rdtype) - rrset.ttl = self._last_load + self.interval - now - - mapping = None - kind = None - if rdtype == dns.rdatatype.A: - mapping = hosts_file.v4 - kind = dns.rdtypes.IN.A.A - elif rdtype == dns.rdatatype.AAAA: - mapping = hosts_file.v6 - kind = dns.rdtypes.IN.AAAA.AAAA - elif rdtype == dns.rdatatype.CNAME: - mapping = hosts_file.aliases - kind = lambda c, t, addr: dns.rdtypes.ANY.CNAME.CNAME(c, t, dns.name.from_text(addr)) - elif rdtype == dns.rdatatype.PTR: - mapping = hosts_file.reverse - kind = lambda c, t, addr: dns.rdtypes.ANY.PTR.PTR(c, t, dns.name.from_text(addr)) - - - addr = mapping.get(name) - if not addr and qname.is_absolute(): - addr = mapping.get(name[:-1]) - if addr: - rrset.add(kind(rdclass, rdtype, addr)) - return _HostsAnswer(qname, rdtype, rdclass, rrset, raise_on_no_answer) - - def getaliases(self, hostname): - # Return a list of all the aliases of a given cname - - # Due to the way store aliases this is a bit inefficient, this - # clearly was an afterthought. But this is only used by - # gethostbyname_ex so it's probably fine. - aliases = self.hosts_file.aliases - result = [] - if hostname in aliases: # pylint:disable=consider-using-get - cannon = aliases[hostname] - else: - cannon = hostname - result.append(cannon) - for alias, cname in iteritems(aliases): - if cannon == cname: - result.append(alias) - result.remove(hostname) - return result - -class _DualResolver(object): - - def __init__(self): - self.hosts_resolver = _HostsResolver() - self.network_resolver = resolver.get_default_resolver() - self.network_resolver.cache = resolver.LRUCache() - - def query(self, qname, rdtype=dns.rdatatype.A, rdclass=dns.rdataclass.IN, - tcp=False, source=None, raise_on_no_answer=True, - _hosts_rdtypes=(dns.rdatatype.A, dns.rdatatype.AAAA, dns.rdatatype.PTR)): - # Query the resolver, using /etc/hosts - - # Behavior: - # 1. if hosts is enabled and contains answer, return it now - # 2. query nameservers for qname - if qname is None: - qname = '0.0.0.0' - - if not isinstance(qname, string_types): - if isinstance(qname, bytes): - qname = qname.decode("idna") - - if isinstance(qname, string_types): - qname = dns.name.from_text(qname, None) - - if isinstance(rdtype, string_types): - rdtype = dns.rdatatype.from_text(rdtype) - - if rdclass == dns.rdataclass.IN and rdtype in _hosts_rdtypes: - try: - answer = self.hosts_resolver.query(qname, rdtype, raise_on_no_answer=False) - except Exception: # pylint: disable=broad-except - from gevent import get_hub - get_hub().handle_error(self, *sys.exc_info()) - else: - if answer.rrset: - return answer - - return self.network_resolver.query(qname, rdtype, rdclass, - tcp, source, raise_on_no_answer=raise_on_no_answer) - -def _family_to_rdtype(family): - if family == socket.AF_INET: - rdtype = dns.rdatatype.A - elif family == socket.AF_INET6: - rdtype = dns.rdatatype.AAAA - else: - raise socket.gaierror(socket.EAI_FAMILY, - 'Address family not supported') - return rdtype - - -class Resolver(AbstractResolver): - """ - An *experimental* resolver that uses `dnspython`_. - - This is typically slower than the default threaded resolver - (unless there's a cache hit, in which case it can be much faster). - It is usually much faster than the c-ares resolver. It tends to - scale well as more concurrent resolutions are attempted. - - Under Python 2, if the ``idna`` package is installed, this - resolver can resolve Unicode host names that the system resolver - cannot. - - .. note:: - - This **does not** use dnspython's default resolver object, or share any - classes with ``import dns``. A separate copy of the objects is imported to - be able to function in a non monkey-patched process. The documentation for the resolver - object still applies. - - The resolver that we use is available as the :attr:`resolver` attribute - of this object (typically ``gevent.get_hub().resolver.resolver``). - - .. caution:: - - Many of the same caveats about DNS results apply here as are documented - for :class:`gevent.resolver.ares.Resolver`. In addition, the handling of - symbolic scope IDs in IPv6 addresses passed to ``getaddrinfo`` exhibits - some differences. - - On PyPy, ``getnameinfo`` can produce results when CPython raises - ``socket.error``, and gevent's DNSPython resolver also - raises ``socket.error``. - - .. caution:: - - This resolver is experimental. It may be removed or modified in - the future. As always, feedback is welcome. - - .. versionadded:: 1.3a2 - - .. versionchanged:: 20.5.0 - The errors raised are now much more consistent with those - raised by the standard library resolvers. - - Handling of localhost and broadcast names is now more consistent. - - .. _dnspython: http://www.dnspython.org - """ - - def __init__(self, hub=None): # pylint: disable=unused-argument - if resolver._resolver is None: - _resolver = resolver._resolver = _DualResolver() - if config.resolver_nameservers: - _resolver.network_resolver.nameservers[:] = config.resolver_nameservers - if config.resolver_timeout: - _resolver.network_resolver.lifetime = config.resolver_timeout - # Different hubs in different threads could be sharing the same - # resolver. - assert isinstance(resolver._resolver, _DualResolver) - self._resolver = resolver._resolver - - @property - def resolver(self): - """ - The dnspython resolver object we use. - - This object has several useful attributes that can be used to - adjust the behaviour of the DNS system: - - * ``cache`` is a :class:`dns.resolver.LRUCache`. Its maximum size - can be configured by calling :meth:`resolver.cache.set_max_size` - * ``nameservers`` controls which nameservers to talk to - * ``lifetime`` configures a timeout for each individual query. - """ - return self._resolver.network_resolver - - def close(self): - pass - - def _getaliases(self, hostname, family): - if not isinstance(hostname, str): - if isinstance(hostname, bytes): - hostname = hostname.decode("idna") - aliases = self._resolver.hosts_resolver.getaliases(hostname) - net_resolver = self._resolver.network_resolver - rdtype = _family_to_rdtype(family) - while 1: - try: - ans = net_resolver.query(hostname, dns.rdatatype.CNAME, rdtype) - except (dns.resolver.NoAnswer, dns.resolver.NXDOMAIN, dns.resolver.NoNameservers): - break - except dTimeout: - break - except AttributeError as ex: - if hostname is None or isinstance(hostname, int): - raise TypeError(ex) - raise - else: - aliases.extend(str(rr.target) for rr in ans.rrset) - hostname = ans[0].target - return aliases - - def _getaddrinfo(self, host_bytes, port, family, socktype, proto, flags): - # dnspython really wants the host to be in native format. - if not isinstance(host_bytes, str): - host_bytes = host_bytes.decode(self.HOSTNAME_ENCODING) - - if host_bytes == 'ff02::1de:c0:face:8D': - # This is essentially a hack to make stdlib - # test_socket:GeneralModuleTests.test_getaddrinfo_ipv6_basic - # pass. They expect to get back a lowercase ``D``, but - # dnspython does not do that. - # ``test_getaddrinfo_ipv6_scopeid_symbolic`` also expect - # the scopeid to be dropped, but again, dnspython does not - # do that; we cant fix that here so we skip that test. - host_bytes = 'ff02::1de:c0:face:8d' - - if family == AF_UNSPEC: - # This tends to raise in the case that a v6 address did not exist - # but a v4 does. So we break it into two parts. - - # Note that if there is no ipv6 in the hosts file, but there *is* - # an ipv4, and there *is* an ipv6 in the nameservers, we will return - # both (from the first call). The system resolver on OS X only returns - # the results from the hosts file. doubleclick.com is one example. - - # See also https://github.com/gevent/gevent/issues/1012 - try: - return _getaddrinfo(host_bytes, port, family, socktype, proto, flags) - except gaierror: - try: - return _getaddrinfo(host_bytes, port, AF_INET6, socktype, proto, flags) - except gaierror: - return _getaddrinfo(host_bytes, port, AF_INET, socktype, proto, flags) - else: - try: - return _getaddrinfo(host_bytes, port, family, socktype, proto, flags) - except gaierror as ex: - if ex.args[0] == EAI_NONAME and family not in self._KNOWN_ADDR_FAMILIES: - # It's possible that we got sent an unsupported family. Check - # that. - ex.args = (EAI_FAMILY, self.EAI_FAMILY_MSG) - ex.errno = EAI_FAMILY - raise - - def _getnameinfo(self, address_bytes, port, sockaddr, flags): - try: - return resolver._getnameinfo(sockaddr, flags) - except error: - if not flags: - # dnspython doesn't like getting ports it can't resolve. - # We have one test, test__socket_dns.py:Test_getnameinfo_geventorg.test_port_zero - # that does this. We conservatively fix it here; this could be expanded later. - return resolver._getnameinfo(sockaddr, NI_NUMERICSERV) - - def _gethostbyaddr(self, ip_address_bytes): - try: - return resolver._gethostbyaddr(ip_address_bytes) - except gaierror as ex: - if ex.args[0] == EAI_NONAME: - # Note: The system doesn't *always* raise herror; - # sometimes the original gaierror propagates through. - # It's impossible to say ahead of time or just based - # on the name which it should be. The herror seems to - # be by far the most common, though. - raise herror(1, "Unknown host") - raise - - # Things that need proper error handling - getnameinfo = AbstractResolver.fixup_gaierror(AbstractResolver.getnameinfo) - gethostbyaddr = AbstractResolver.fixup_gaierror(AbstractResolver.gethostbyaddr) - gethostbyname_ex = AbstractResolver.fixup_gaierror(AbstractResolver.gethostbyname_ex) - getaddrinfo = AbstractResolver.fixup_gaierror(AbstractResolver.getaddrinfo) diff --git a/venv/lib/python3.9/site-packages/gevent/resolver/thread.py b/venv/lib/python3.9/site-packages/gevent/resolver/thread.py deleted file mode 100644 index 6912b78..0000000 --- a/venv/lib/python3.9/site-packages/gevent/resolver/thread.py +++ /dev/null @@ -1,69 +0,0 @@ -# Copyright (c) 2012-2015 Denis Bilenko. See LICENSE for details. -""" -Native thread-based hostname resolver. -""" -import _socket - -from gevent.hub import get_hub - - -__all__ = ['Resolver'] - - -class Resolver(object): - """ - Implementation of the resolver API using native threads and native resolution - functions. - - Using the native resolution mechanisms ensures the highest - compatibility with what a non-gevent program would return - including good support for platform specific configuration - mechanisms. The use of native (non-greenlet) threads ensures that - a caller doesn't block other greenlets. - - This implementation also has the benefit of being very simple in comparison to - :class:`gevent.resolver_ares.Resolver`. - - .. tip:: - - Most users find this resolver to be quite reliable in a - properly monkey-patched environment. However, there have been - some reports of long delays, slow performance or even hangs, - particularly in long-lived programs that make many, many DNS - requests. If you suspect that may be happening to you, try the - dnspython or ares resolver (and submit a bug report). - """ - def __init__(self, hub=None): - if hub is None: - hub = get_hub() - self.pool = hub.threadpool - if _socket.gaierror not in hub.NOT_ERROR: - # Do not cause lookup failures to get printed by the default - # error handler. This can be very noisy. - hub.NOT_ERROR += (_socket.gaierror, _socket.herror) - - def __repr__(self): - return '<%s.%s at 0x%x pool=%r>' % (type(self).__module__, - type(self).__name__, - id(self), self.pool) - - def close(self): - pass - - # from briefly reading socketmodule.c, it seems that all of the functions - # below are thread-safe in Python, even if they are not thread-safe in C. - - def gethostbyname(self, *args): - return self.pool.apply(_socket.gethostbyname, args) - - def gethostbyname_ex(self, *args): - return self.pool.apply(_socket.gethostbyname_ex, args) - - def getaddrinfo(self, *args, **kwargs): - return self.pool.apply(_socket.getaddrinfo, args, kwargs) - - def gethostbyaddr(self, *args, **kwargs): - return self.pool.apply(_socket.gethostbyaddr, args, kwargs) - - def getnameinfo(self, *args, **kwargs): - return self.pool.apply(_socket.getnameinfo, args, kwargs) diff --git a/venv/lib/python3.9/site-packages/gevent/resolver_ares.py b/venv/lib/python3.9/site-packages/gevent/resolver_ares.py deleted file mode 100644 index 9f0c449..0000000 --- a/venv/lib/python3.9/site-packages/gevent/resolver_ares.py +++ /dev/null @@ -1,17 +0,0 @@ -"""Backwards compatibility alias for :mod:`gevent.resolver.ares`. - -.. deprecated:: 1.3 - Use :mod:`gevent.resolver.ares` -""" -import warnings -warnings.warn( - "gevent.resolver_ares is deprecated and will be removed in 1.5. " - "Use gevent.resolver.ares instead.", - DeprecationWarning, - stacklevel=2 -) -del warnings -from gevent.resolver.ares import * # pylint:disable=wildcard-import,unused-wildcard-import -import gevent.resolver.ares as _ares -__all__ = _ares.__all__ -del _ares diff --git a/venv/lib/python3.9/site-packages/gevent/resolver_thread.py b/venv/lib/python3.9/site-packages/gevent/resolver_thread.py deleted file mode 100644 index 1486e42..0000000 --- a/venv/lib/python3.9/site-packages/gevent/resolver_thread.py +++ /dev/null @@ -1,17 +0,0 @@ -"""Backwards compatibility alias for :mod:`gevent.resolver.thread`. - -.. deprecated:: 1.3 - Use :mod:`gevent.resolver.thread` -""" -import warnings -warnings.warn( - "gevent.resolver_thread is deprecated and will be removed in 1.5. " - "Use gevent.resolver.thread instead.", - DeprecationWarning, - stacklevel=2 -) -del warnings -from gevent.resolver.thread import * # pylint:disable=wildcard-import,unused-wildcard-import -import gevent.resolver.thread as _thread -__all__ = _thread.__all__ -del _thread diff --git a/venv/lib/python3.9/site-packages/gevent/select.py b/venv/lib/python3.9/site-packages/gevent/select.py deleted file mode 100644 index eb5413f..0000000 --- a/venv/lib/python3.9/site-packages/gevent/select.py +++ /dev/null @@ -1,381 +0,0 @@ -# Copyright (c) 2009-2011 Denis Bilenko. See LICENSE for details. -""" -Waiting for I/O completion. -""" -from __future__ import absolute_import, division, print_function - -import sys -import select as __select__ - -from gevent.event import Event -from gevent.hub import _get_hub_noargs as get_hub -from gevent.hub import sleep as _g_sleep - -from gevent._util import copy_globals -from gevent._util import _NONE - -from errno import EBADF - -_real_original_select = __select__.select -if sys.platform.startswith('win32'): - def _original_select(r, w, x, t): - # windows can't handle three empty lists, but we've always - # accepted that - if not r and not w and not x: - return ((), (), ()) - return _real_original_select(r, w, x, t) -else: - _original_select = _real_original_select - -# These will be replaced by copy_globals if they are defined by the -# platform. They're not defined on Windows, but we still provide -# poll() there. We only pay attention to POLLIN and POLLOUT. -POLLIN = 1 -POLLPRI = 2 -POLLOUT = 4 -POLLERR = 8 -POLLHUP = 16 -POLLNVAL = 32 - -POLLRDNORM = 64 -POLLRDBAND = 128 -POLLWRNORM = 4 -POLLWRBAND = 256 - -__implements__ = [ - 'select', -] -if hasattr(__select__, 'poll'): - __implements__.append('poll') -else: - __extra__ = [ - 'poll', - ] - -__all__ = ['error'] + __implements__ - -# This is now a plain OSError, we should never try to -# recatch and throw these. But the constant needs to -# remain for BWC. -error = __select__.error - -__imports__ = copy_globals(__select__, globals(), - names_to_ignore=__all__, - dunder_names_to_keep=()) - -_EV_READ = 1 -_EV_WRITE = 2 - -def get_fileno(fileobj): - if isinstance(fileobj, int): - fd = fileobj - else: - try: - fd = int(fileobj.fileno()) - except (AttributeError, TypeError, ValueError): - raise ValueError("Invalid file object: " - "{!r}".format(fileobj)) from None - if fd < 0: - raise ValueError("Invalid file descriptor: {}".format(fd)) - return fd - - -class SelectResult(object): - __slots__ = () - - @staticmethod - def _make_callback(ready_collection, event, mask): - def cb(fd, watcher): - ready_collection.append(fd) - watcher.close() - event.set() - cb.mask = mask - return cb - - @classmethod - def _make_watchers(cls, watchers, *fd_cb): - loop = get_hub().loop - io = loop.io - MAXPRI = loop.MAXPRI - - for fdlist, callback in fd_cb: - for fd in fdlist: - watcher = io(get_fileno(fd), callback.mask) - watcher.priority = MAXPRI - watchers.append(watcher) - watcher.start(callback, fd, watcher) - - @staticmethod - def _closeall(watchers): - for watcher in watchers: - watcher.stop() - watcher.close() - del watchers[:] - - def select(self, rlist, wlist, timeout): - watchers = [] - # read and write are the collected ready objects, accumulated - # by the callback. Note that we could get spurious callbacks - # if the socket is closed while we're blocked. We can't easily - # detect that (libev filters the events passed so we can't - # pass arbitrary events). After an iteration of polling for - # IO, libev will invoke all the pending IO watchers, and then - # any newly added (fed) events, and then we will invoke added - # callbacks. With libev 4.27+ and EV_VERIFY, it's critical to - # close our watcher immediately once we get an event. That - # could be the close event (coming just before the actual - # close happens), and once the FD is closed, libev will abort - # the process if we stop the watcher. - read = [] - write = [] - event = Event() - add_read = self._make_callback(read, event, _EV_READ) - add_write = self._make_callback(write, event, _EV_WRITE) - - try: - self._make_watchers(watchers, - (rlist, add_read), - (wlist, add_write)) - event.wait(timeout=timeout) - return read, write, [] - finally: - self._closeall(watchers) - - -def select(rlist, wlist, xlist, timeout=None): # pylint:disable=unused-argument - """An implementation of :obj:`select.select` that blocks only the current greenlet. - - .. caution:: *xlist* is ignored. - - .. versionchanged:: 1.2a1 - Raise a :exc:`ValueError` if timeout is negative. This matches Python 3's - behaviour (Python 2 would raise a ``select.error``). Previously gevent had - undefined behaviour. - .. versionchanged:: 1.2a1 - Raise an exception if any of the file descriptors are invalid. - """ - if timeout is not None and timeout < 0: - # Raise an error like the real implementation; which error - # depends on the version. Python 3, where select.error is OSError, - # raises a ValueError (which makes sense). Older pythons raise - # the error from the select syscall...but we don't actually get there. - # We choose to just raise the ValueError as it makes more sense and is - # forward compatible - raise ValueError("timeout must be non-negative") - - # since rlist and wlist can be any iterable we will have to first - # copy them into a list, so we can use them in both _original_select - # and in SelectResult.select. We don't need to do it for xlist, since - # that one will only be passed into _original_select - rlist = rlist if isinstance(rlist, (list, tuple)) else list(rlist) - wlist = wlist if isinstance(wlist, (list, tuple)) else list(wlist) - - # First, do a poll with the original select system call. This is - # the most efficient way to check to see if any of the file - # descriptors have previously been closed and raise the correct - # corresponding exception. (Because libev tends to just return - # them as ready, or, if built with EV_VERIFY >= 2 and libev >= - # 4.27, crash the process. And libuv also tends to crash the - # process.) - # - # We accept the *xlist* here even though we can't - # below because this is all about error handling. - # Since Python 3.5, we don't need to worry about EINTR handling. - sel_results = _original_select(rlist, wlist, xlist, 0) - - if sel_results[0] or sel_results[1] or sel_results[2] or (timeout is not None and timeout == 0): - # If we actually had stuff ready, go ahead and return it. No need - # to go through the trouble of doing our own stuff. - - # Likewise, if the timeout is 0, we already did a 0 timeout - # select and we don't need to do it again. Note that in libuv, - # zero duration timers may be called immediately, without - # cycling the event loop at all. 2.7/test_telnetlib.py "hangs" - # calling zero-duration timers if we go to the loop here. - - # However, because this is typically a place where scheduling switches - # can occur, we need to make sure that's still the case; otherwise a single - # consumer could monopolize the thread. (shows up in test_ftplib.) - _g_sleep() - return sel_results - - result = SelectResult() - return result.select(rlist, wlist, timeout) - - - -class PollResult(object): - __slots__ = ('events', 'event') - - def __init__(self): - self.events = set() - self.event = Event() - - def add_event(self, events, fd): - if events < 0: - result_flags = POLLNVAL - else: - result_flags = 0 - if events & _EV_READ: - result_flags = POLLIN - if events & _EV_WRITE: - result_flags |= POLLOUT - - self.events.add((fd, result_flags)) - self.event.set() - - def add_error_before_io(self, fd): - # This is before we do any IO, don't set the event - self.events.add((fd, POLLNVAL)) - -class poll(object): - """ - An implementation of :obj:`select.poll` that blocks only the current greenlet. - - With only one exception, the interface is the same as the standard library interface. - - .. caution:: ``POLLPRI`` data is not supported. - - .. versionadded:: 1.1b1 - .. versionchanged:: 1.5 - This is now always defined, regardless of whether the standard library - defines :func:`select.poll` or not. Note that it may have different performance - characteristics. - """ - def __init__(self): - # {int -> flags} - # We can't keep watcher objects in here because people commonly - # just drop the poll object when they're done, without calling - # unregister(). dnspython does this. - self.fds = {} - self.loop = get_hub().loop - - def register(self, fd, eventmask=_NONE): - """ - Register a file descriptor *fd* with the polling object. - - Future calls to the :meth:`poll`` method will then check - whether the file descriptor has any pending I/O events. *fd* can - be either an integer, or an object with a ``fileno()`` method that - returns an integer. File objects implement ``fileno()``, so they - can also be used as the argument (but remember that regular - files are usually always ready). - - *eventmask* is an optional bitmask describing the type of events - you want to check for, and can be a combination of the - constants ``POLLIN``, and ``POLLOUT`` (``POLLPRI`` is not supported). - """ - if eventmask is _NONE: - flags = _EV_READ | _EV_WRITE - else: - flags = 0 - if eventmask & POLLIN: - flags = _EV_READ - if eventmask & POLLOUT: - flags |= _EV_WRITE - # If they ask for POLLPRI, we can't support - # that. Should we raise an error? - - fileno = get_fileno(fd) - self.fds[fileno] = flags - - def modify(self, fd, eventmask): - """ - Change the set of events being watched on *fd*. - """ - self.register(fd, eventmask) - - def _get_started_watchers(self, poll_result): - watchers = [] - io = self.loop.io - MAXPRI = self.loop.MAXPRI - watcher_cb = poll_result.add_event - try: - for fd, flags in self.fds.items(): - try: - watcher = io(fd, flags) - except OSError as ex: - if ex.errno != EBADF: - raise - poll_result.add_error_before_io(fd) - continue - - watchers.append(watcher) - watcher.priority = MAXPRI - watcher.start(watcher_cb, fd, pass_events=True) - except: - for awatcher in watchers: - awatcher.stop() - awatcher.close() - raise - return watchers - - - def poll(self, timeout=None): - """ - poll the registered fds. - - .. versionchanged:: 1.2a1 - File descriptors that are closed are reported with POLLNVAL. - - .. versionchanged:: 1.3a2 - Under libuv, interpret *timeout* values less than 0 the same as *None*, - i.e., block. This was always the case with libev. - """ - result = PollResult() - watchers = self._get_started_watchers(result) - try: - if timeout is not None: - if timeout < 0: - # The docs for python say that an omitted timeout, - # a negative timeout and a timeout of None are all - # supposed to block forever. Many, but not all - # OS's accept any negative number to mean that. Some - # OS's raise errors for anything negative but not -1. - # Python 3.7 changes to always pass exactly -1 in that - # case from selectors. - - # Our Timeout class currently does not have a defined behaviour - # for negative values. On libuv, it uses a check watcher and effectively - # doesn't block. On libev, it seems to block. In either case, we - # *want* to block, so turn this into the sure fire block request. - timeout = None - elif timeout: - # The docs for poll.poll say timeout is in - # milliseconds. Our result objects work in - # seconds, so this should be *=, shouldn't it? - timeout /= 1000.0 - result.event.wait(timeout=timeout) - return list(result.events) - finally: - for awatcher in watchers: - awatcher.stop() - awatcher.close() - - def unregister(self, fd): - """ - Unregister the *fd*. - - .. versionchanged:: 1.2a1 - Raise a `KeyError` if *fd* was not registered, like the standard - library. Previously gevent did nothing. - """ - fileno = get_fileno(fd) - del self.fds[fileno] - - -def _gevent_do_monkey_patch(patch_request): - aggressive = patch_request.patch_kwargs['aggressive'] - - patch_request.default_patch_items() - - if aggressive: - # since these are blocking we're removing them here. This makes some other - # modules (e.g. asyncore) non-blocking, as they use select that we provide - # when none of these are available. - patch_request.remove_item( - 'epoll', - 'kqueue', - 'kevent', - 'devpoll', - ) diff --git a/venv/lib/python3.9/site-packages/gevent/selectors.py b/venv/lib/python3.9/site-packages/gevent/selectors.py deleted file mode 100644 index cc3dd6d..0000000 --- a/venv/lib/python3.9/site-packages/gevent/selectors.py +++ /dev/null @@ -1,336 +0,0 @@ -# Copyright (c) 2020 gevent contributors. -""" -This module provides :class:`GeventSelector`, a high-level IO -multiplexing mechanism. This is aliased to :class:`DefaultSelector`. - -This module provides the same API as the selectors defined in :mod:`selectors`. - -On Python 2, this module is only available if the `selectors2 -`_ backport is installed. - -.. versionadded:: 20.6.0 -""" -from __future__ import absolute_import -from __future__ import division -from __future__ import print_function - -from collections import defaultdict - -try: - import selectors as __selectors__ -except ImportError: - # Probably on Python 2. Do we have the backport? - import selectors2 as __selectors__ - __target__ = 'selectors2' - -from gevent.hub import _get_hub_noargs as get_hub -from gevent import sleep -from gevent._compat import iteritems -from gevent._compat import itervalues -from gevent._util import copy_globals -from gevent._util import Lazy - -from gevent.event import Event -from gevent.select import _EV_READ -from gevent.select import _EV_WRITE - -__implements__ = [ - 'DefaultSelector', -] -__extra__ = [ - 'GeventSelector', -] -__all__ = __implements__ + __extra__ - -__imports__ = copy_globals( - __selectors__, globals(), - names_to_ignore=__all__, - # Copy __all__; __all__ is defined by selectors2 but not Python 3. - dunder_names_to_keep=('__all__',) -) - -_POLL_ALL = _EV_READ | _EV_WRITE - -EVENT_READ = __selectors__.EVENT_READ -EVENT_WRITE = __selectors__.EVENT_WRITE -_ALL_EVENTS = EVENT_READ | EVENT_WRITE -SelectorKey = __selectors__.SelectorKey - -# In 3.4 and selectors2, BaseSelector is a concrete -# class that can be called. In 3.5 and later, it's an -# ABC, with the real implementation being -# passed to _BaseSelectorImpl. -_BaseSelectorImpl = getattr( - __selectors__, - '_BaseSelectorImpl', - __selectors__.BaseSelector -) - -class GeventSelector(_BaseSelectorImpl): - """ - A selector implementation using gevent primitives. - - This is a type of :class:`selectors.BaseSelector`, so the documentation - for that class applies here. - - .. caution:: - As the base class indicates, it is critically important to - unregister file objects before closing them. (Or close the selector - they are registered with before closing them.) Failure to do so - may crash the process or have other unintended results. - """ - - # Notes on the approach: - # - # It's easy to wrap a selector implementation around - # ``gevent.select.poll``; in fact that's what happens by default - # when monkey-patching in Python 3. But the problem with that is - # each call to ``selector.select()`` will result in creating and - # then destroying new kernel-level polling resources, as nothing - # in ``gevent.select`` can keep watchers around (because the underlying - # file could be closed at any time). This ends up producing a large - # number of syscalls that are unnecessary. - # - # So here, we take advantage of the fact that it is documented and - # required that files not be closed while they are registered. - # This lets us persist watchers. Indeed, it lets us continually - # accrue events in the background before a call to ``select()`` is even - # made. We can take advantage of this to return results immediately, without - # a syscall, if we have them. - # - # We create watchers in ``register()`` and destroy them in - # ``unregister()``. They do not get started until the first call - # to ``select()``, though. Once they are started, they don't get - # stopped until they deliver an event. - # Lifecycle: - # register() -> inactive_watchers - # select() -> inactive_watchers -> active_watchers; - # active_watchers -> inactive_watchers - - def __init__(self, hub=None): - if hub is not None: - self.hub = hub - # {fd: watcher} - self._active_watchers = {} - self._inactive_watchers = {} - # {fd: EVENT_READ|EVENT_WRITE} - self._accumulated_events = defaultdict(int) - self._ready = Event() - super(GeventSelector, self).__init__() - - if not hasattr(_BaseSelectorImpl, '_key_from_fd'): - def _key_from_fd(self, fd): - # Removed in 3.13; this duplicates the old function. - try: - return self._fd_to_key[fd] - except KeyError: - return None - - - def __callback(self, events, fd): - if events > 0: - cur_event_for_fd = self._accumulated_events[fd] - if events & _EV_READ: - cur_event_for_fd |= EVENT_READ - if events & _EV_WRITE: - cur_event_for_fd |= EVENT_WRITE - self._accumulated_events[fd] = cur_event_for_fd - - self._ready.set() - - @Lazy - def hub(self): # pylint:disable=method-hidden - return get_hub() - - def register(self, fileobj, events, data=None): - """ - Register a file object for selection, monitoring it for I/O events. - - *fileobj* is the file object to monitor. It may either be an integer file descriptor - or an object with a ``fileno()`` method. *events* is a bitwise mask of events to - monitor. *data* is an opaque object. - - :return: A new `SelectorKey` instance. - :raises ValueError: In case of invalid - event mask or file descriptor - :raises KeyError: if the file object is already registered. - - .. versionchanged:: 25.8.1 - More reliably raises a ``ValueError`` if the file descriptor - is invalid. - """ - # Handles checking *events* to be valid, and raising the KeyError. - key = _BaseSelectorImpl.register(self, fileobj, events, data) - - if events == _ALL_EVENTS: - flags = _POLL_ALL - elif events == EVENT_READ: - flags = _EV_READ - else: - flags = _EV_WRITE - - - loop = self.hub.loop - io = loop.io - MAXPRI = loop.MAXPRI - - try: - self._inactive_watchers[key.fd] = watcher = io(key.fd, flags) - except OSError as e: - raise ValueError('Invalid file descriptor') from e - watcher.priority = MAXPRI - return key - - def unregister(self, fileobj): - key = _BaseSelectorImpl.unregister(self, fileobj) - if key.fd in self._active_watchers: - watcher = self._active_watchers.pop(key.fd) - else: - watcher = self._inactive_watchers.pop(key.fd) - watcher.stop() - watcher.close() - self._accumulated_events.pop(key.fd, None) - return key - - # XXX: Can we implement ``modify`` more efficiently than - # ``unregister()``+``register()``? We could detect the no-change - # case and do nothing; recent versions of the standard library - # do that. - - def select(self, timeout=None): - """ - Poll for I/O. - - Note that, like the built-in selectors, this will block - indefinitely if no timeout is given and no files have been - registered. - """ - # timeout > 0 : block seconds - # timeout <= 0 : No blocking. - # timeout = None: Block forever - - # Event.wait doesn't deal with negative values - if timeout is not None and timeout < 0: - timeout = 0 - - # Start any watchers that need started. Note that they may - # not actually get a chance to do anything yet if we already had - # events set. - for fd, watcher in iteritems(self._inactive_watchers): - watcher.start(self.__callback, fd, pass_events=True) - self._active_watchers.update(self._inactive_watchers) - self._inactive_watchers.clear() - - # The _ready event is either already set (in which case - # there are some results waiting in _accumulated_events) or - # not set, in which case we have to block. But to make the two cases - # behave the same, we will always yield to the event loop. - if self._ready.is_set(): - sleep() - self._ready.wait(timeout) - self._ready.clear() - # TODO: If we have nothing ready, but they ask us not to block, - # should we make an effort to actually spin the event loop and let - # it check for events? - - result = [] - for fd, event in iteritems(self._accumulated_events): - key = self._key_from_fd(fd) - watcher = self._active_watchers.pop(fd) - - ## The below is taken without comment from - ## https://github.com/gevent/gevent/pull/1523/files and - ## hasn't been checked: - # - # Since we are emulating an epoll object within another epoll object, - # once a watcher has fired, we must deactivate it until poll is called - # next. If we did not, someone else could call, e.g., gevent.time.sleep - # and any unconsumed bytes on our watched fd would prevent the process - # from sleeping correctly. - watcher.stop() - if key: - result.append((key, event & key.events)) - self._inactive_watchers[fd] = watcher - else: # pragma: no cover - # If the key was gone, then somehow we've been unregistered. - # Don't put it back in inactive, close it. - watcher.close() - - self._accumulated_events.clear() - return result - - def close(self): - for d in self._active_watchers, self._inactive_watchers: - if d is None: - continue # already closed - for watcher in itervalues(d): - watcher.stop() - watcher.close() - self._active_watchers = self._inactive_watchers = None - self._accumulated_events = None - self.hub = None - _BaseSelectorImpl.close(self) - - -DefaultSelector = GeventSelector - -def _gevent_do_monkey_patch(patch_request): - aggressive = patch_request.patch_kwargs['aggressive'] - target_mod = patch_request.target_module - - patch_request.default_patch_items() - - import sys - if 'selectors' not in sys.modules: - # Py2: Make 'import selectors' work - sys.modules['selectors'] = sys.modules[__name__] - - # Python 3 wants to use `select.select` as a member function, - # leading to this error in selectors.py (because - # gevent.select.select is not a builtin and doesn't get the - # magic auto-static that they do): - # - # r, w, _ = self._select(self._readers, self._writers, [], timeout) - # TypeError: select() takes from 3 to 4 positional arguments but 5 were given - # - # Note that this obviously only happens if selectors was - # imported after we had patched select; but there is a code - # path that leads to it being imported first (but now we've - # patched select---so we can't compare them identically). It also doesn't - # happen on Windows, because they define a normal method for _select, to work around - # some weirdness in the handling of the third argument. - # - # The backport doesn't have that. - orig_select_select = patch_request.get_original('select', 'select') - assert target_mod.select is not orig_select_select - selectors = __selectors__ - SelectSelector = selectors.SelectSelector - if hasattr(SelectSelector, '_select') and SelectSelector._select in ( - target_mod.select, orig_select_select - ): - from gevent.select import select - def _select(self, *args, **kwargs): # pylint:disable=unused-argument - return select(*args, **kwargs) - selectors.SelectSelector._select = _select - _select._gevent_monkey = True # prove for test cases - - if aggressive: - # If `selectors` had already been imported before we removed - # select.epoll|kqueue|devpoll, these may have been defined in terms - # of those functions. They'll fail at runtime. - patch_request.remove_item( - selectors, - 'EpollSelector', - 'KqueueSelector', - 'DevpollSelector', - ) - selectors.DefaultSelector = DefaultSelector - - # Python 3.7 refactors the poll-like selectors to use a common - # base class and capture a reference to select.poll, etc, at - # import time. selectors tends to get imported early - # (importing 'platform' does it: platform -> subprocess -> selectors), - # so we need to clean that up. - if hasattr(selectors, 'PollSelector') and hasattr(selectors.PollSelector, '_selector_cls'): - from gevent.select import poll - selectors.PollSelector._selector_cls = poll diff --git a/venv/lib/python3.9/site-packages/gevent/server.py b/venv/lib/python3.9/site-packages/gevent/server.py deleted file mode 100644 index 612a49d..0000000 --- a/venv/lib/python3.9/site-packages/gevent/server.py +++ /dev/null @@ -1,290 +0,0 @@ -# Copyright (c) 2009-2012 Denis Bilenko. See LICENSE for details. -"""TCP/SSL server""" -from __future__ import print_function -from __future__ import absolute_import -from __future__ import division - -import sys - -from _socket import error as SocketError -from _socket import SOL_SOCKET -from _socket import SO_REUSEADDR -from _socket import AF_INET -from _socket import SOCK_DGRAM - -from gevent.baseserver import BaseServer -from gevent.socket import EWOULDBLOCK -from gevent.socket import socket as GeventSocket - -__all__ = ['StreamServer', 'DatagramServer'] - - -if sys.platform == 'win32': - # SO_REUSEADDR on Windows does not mean the same thing as on *nix (issue #217) - DEFAULT_REUSE_ADDR = None -else: - DEFAULT_REUSE_ADDR = 1 - - -# sockets and SSL sockets are context managers on Python 3 -def _closing_socket(sock): - return sock - - -class StreamServer(BaseServer): - """ - A generic TCP server. - - Accepts connections on a listening socket and spawns user-provided - *handle* function for each connection with 2 arguments: the client - socket and the client address. - - Note that although the errors in a successfully spawned handler - will not affect the server or other connections, the errors raised - by :func:`accept` and *spawn* cause the server to stop accepting - for a short amount of time. The exact period depends on the values - of :attr:`min_delay` and :attr:`max_delay` attributes. - - The delay starts with :attr:`min_delay` and doubles with each - successive error until it reaches :attr:`max_delay`. A successful - :func:`accept` resets the delay to :attr:`min_delay` again. - - See :class:`~gevent.baseserver.BaseServer` for information on defining the *handle* - function and important restrictions on it. - - **SSL Support** - - The server can optionally work in SSL mode when given the correct - keyword arguments. (That is, the presence of any keyword arguments - will trigger SSL mode.) On Python 2.7.9 and later (any Python - version that supports the :class:`ssl.SSLContext`), this can be - done with a configured ``SSLContext``. On any Python version, it - can be done by passing the appropriate arguments for - :func:`ssl.wrap_socket`. - - The incoming socket will be wrapped into an SSL socket before - being passed to the *handle* function. - - If the *ssl_context* keyword argument is present, it should - contain an :class:`ssl.SSLContext`. The remaining keyword - arguments are passed to the :meth:`ssl.SSLContext.wrap_socket` - method of that object. Depending on the Python version, supported arguments - may include: - - - server_hostname - - suppress_ragged_eofs - - do_handshake_on_connect - - .. caution:: When using an SSLContext, it should either be - imported from :mod:`gevent.ssl`, or the process needs to be monkey-patched. - If the process is not monkey-patched and you pass the standard library - SSLContext, the resulting client sockets will not cooperate with gevent. - - Otherwise, keyword arguments are assumed to apply to :func:`ssl.wrap_socket`. - These keyword arguments may include: - - - keyfile - - certfile - - cert_reqs - - ssl_version - - ca_certs - - suppress_ragged_eofs - - do_handshake_on_connect - - ciphers - - .. versionchanged:: 1.2a2 - Add support for the *ssl_context* keyword argument. - - """ - # the default backlog to use if none was provided in __init__ - # For TCP, 128 is the (default) maximum at the operating system level on Linux and macOS - # larger values are truncated to 128. - # - # Windows defines SOMAXCONN=0x7fffffff to mean "max reasonable value" --- that value - # was undocumented and subject to change, but appears to be 200. - # Beginning in Windows 8 there's SOMAXCONN_HINT(b)=(-(b)) which means "at least - # as many SOMAXCONN but no more than b" which is a portable way to write 200. - backlog = 128 - - reuse_addr = DEFAULT_REUSE_ADDR - - def __init__(self, listener, handle=None, backlog=None, spawn='default', **ssl_args): - BaseServer.__init__(self, listener, handle=handle, spawn=spawn) - try: - if ssl_args: - ssl_args.setdefault('server_side', True) - if 'ssl_context' in ssl_args: - ssl_context = ssl_args.pop('ssl_context') - self.wrap_socket = ssl_context.wrap_socket - self.ssl_args = ssl_args - else: - from gevent.ssl import wrap_socket - self.wrap_socket = wrap_socket - self.ssl_args = ssl_args - else: - self.ssl_args = None - if backlog is not None: - if hasattr(self, 'socket'): - raise TypeError('backlog must be None when a socket instance is passed') - self.backlog = backlog - except: - self.close() - raise - - @property - def ssl_enabled(self): - return self.ssl_args is not None - - def set_listener(self, listener): - BaseServer.set_listener(self, listener) - - def _make_socket_stdlib(self, fresh): - # We want to unwrap the gevent wrapping of the listening socket. - # This lets us be just a hair more efficient: when our 'do_read' is - # called, we've already waited on the socket to be ready to accept(), so - # we don't need to (potentially) do it again. Also we avoid a layer - # of method calls. The cost, though, is that we have to manually wrap - # sockets back up to be non-blocking in do_read(). I'm not sure that's worth - # it. - # - # In the past, we only did this when set_listener() was called with a socket - # object and not an address. It makes sense to do it always though, - # so that we get consistent behaviour. - while hasattr(self.socket, '_sock'): - if fresh: - if hasattr(self.socket, '_drop_events'): - # Discard event listeners. This socket object is not shared, - # so we don't need them anywhere else. - # This matters somewhat for libuv, where we have to multiplex - # listeners, and we're about to create a new listener. - # If we don't do this, on Windows libuv tends to miss incoming - # connects and our _do_read callback doesn't get called. - self.socket._drop_events() - # XXX: Do we need to _drop() for PyPy? - - self.socket = self.socket._sock # pylint:disable=attribute-defined-outside-init - - def init_socket(self): - fresh = False - if not hasattr(self, 'socket'): - fresh = True - # FIXME: clean up the socket lifetime - # pylint:disable=attribute-defined-outside-init - self.socket = self.get_listener(self.address, self.backlog, self.family) - self.address = self.socket.getsockname() - if self.ssl_args: - self._handle = self.wrap_socket_and_handle - else: - self._handle = self.handle - self._make_socket_stdlib(fresh) - - @classmethod - def get_listener(cls, address, backlog=None, family=None): - if backlog is None: - backlog = cls.backlog - return _tcp_listener(address, backlog=backlog, reuse_addr=cls.reuse_addr, family=family) - - def do_read(self): - sock = self.socket - try: - fd, address = sock._accept() - except BlockingIOError: # python 2: pylint: disable=undefined-variable - if not sock.timeout: - return - raise - - sock = GeventSocket(sock.family, sock.type, sock.proto, fileno=fd) - # XXX Python issue #7995? "if no default timeout is set - # and the listening socket had a (non-zero) timeout, force - # the new socket in blocking mode to override - # platform-specific socket flags inheritance." - return sock, address - - def do_close(self, sock, *args): - # pylint:disable=arguments-differ - sock.close() - - def wrap_socket_and_handle(self, client_socket, address): - # used in case of ssl sockets - with _closing_socket(self.wrap_socket(client_socket, **self.ssl_args)) as ssl_socket: - return self.handle(ssl_socket, address) - - -class DatagramServer(BaseServer): - """A UDP server""" - - reuse_addr = DEFAULT_REUSE_ADDR - - def __init__(self, *args, **kwargs): - # The raw (non-gevent) socket, if possible - self._socket = None - BaseServer.__init__(self, *args, **kwargs) - from gevent.lock import Semaphore - self._writelock = Semaphore() - - def init_socket(self): - if not hasattr(self, 'socket'): - # FIXME: clean up the socket lifetime - # pylint:disable=attribute-defined-outside-init - self.socket = self.get_listener(self.address, self.family) - self.address = self.socket.getsockname() - self._socket = self.socket - try: - self._socket = self._socket._sock - except AttributeError: - pass - - @classmethod - def get_listener(cls, address, family=None): - return _udp_socket(address, reuse_addr=cls.reuse_addr, family=family) - - def do_read(self): - try: - data, address = self._socket.recvfrom(8192) - except SocketError as err: - if err.args[0] == EWOULDBLOCK: - return - raise - return data, address - - def sendto(self, *args): - self._writelock.acquire() - try: - self.socket.sendto(*args) - finally: - self._writelock.release() - - -def _tcp_listener(address, backlog=50, reuse_addr=None, family=AF_INET): - """A shortcut to create a TCP socket, bind it and put it into listening state.""" - sock = GeventSocket(family=family) - if reuse_addr is not None: - sock.setsockopt(SOL_SOCKET, SO_REUSEADDR, reuse_addr) - try: - sock.bind(address) - except SocketError as ex: - strerror = getattr(ex, 'strerror', None) - if strerror is not None: - ex.strerror = strerror + ': ' + repr(address) - raise - sock.listen(backlog) - sock.setblocking(0) - return sock - - -def _udp_socket(address, backlog=50, reuse_addr=None, family=AF_INET): - # backlog argument for compat with tcp_listener - # pylint:disable=unused-argument - - # we want gevent.socket.socket here - sock = GeventSocket(family=family, type=SOCK_DGRAM) - if reuse_addr is not None: - sock.setsockopt(SOL_SOCKET, SO_REUSEADDR, reuse_addr) - try: - sock.bind(address) - except SocketError as ex: - strerror = getattr(ex, 'strerror', None) - if strerror is not None: - ex.strerror = strerror + ': ' + repr(address) - raise - return sock diff --git a/venv/lib/python3.9/site-packages/gevent/signal.py b/venv/lib/python3.9/site-packages/gevent/signal.py deleted file mode 100644 index 21e6137..0000000 --- a/venv/lib/python3.9/site-packages/gevent/signal.py +++ /dev/null @@ -1,176 +0,0 @@ -""" -Cooperative implementation of special cases of :func:`signal.signal`. - -This module is designed to work with libev's child watchers, as used -by default in :func:`gevent.os.fork` Note that each ``SIGCHLD`` -handler will be run in a new greenlet when the signal is delivered -(just like :class:`gevent.hub.signal`) - -The implementations in this module are only monkey patched if -:func:`gevent.os.waitpid` is being used (the default) and if -:const:`signal.SIGCHLD` is available; see :func:`gevent.os.fork` for -information on configuring this not to be the case for advanced uses. - -.. versionadded:: 1.1b4 -.. versionchanged:: 1.5a4 - Previously there was a backwards compatibility alias - ``gevent.signal``, introduced in 1.1b4, that partly shadowed this - module, confusing humans and static analysis tools alike. That alias - has been removed. (See `gevent.signal_handler`.) -""" -from gevent._util import _NONE as _INITIAL -from gevent._util import copy_globals - -import signal as _signal - -__implements__ = [] -__extensions__ = [] - -_child_handler = _INITIAL -_child_wakeup_fd = -1 -_child_wakeup_fd_warn_on_full_buffer = None - - -_signal_signal = _signal.signal -_signal_getsignal = _signal.getsignal - - -def getsignal(signalnum): - """ - Exactly the same as :func:`signal.getsignal` except where - :const:`signal.SIGCHLD` is concerned. - - For :const:`signal.SIGCHLD`, this cooperates with :func:`signal` - to provide consistent answers. - """ - if signalnum != _signal.SIGCHLD: - return _signal_getsignal(signalnum) - - global _child_handler - if _child_handler is _INITIAL: - _child_handler = _signal_getsignal(_signal.SIGCHLD) - - return _child_handler - - -def signal(signalnum, handler): - """ - Exactly the same as :func:`signal.signal` except where - :const:`signal.SIGCHLD` is concerned. - - .. note:: - - A :const:`signal.SIGCHLD` handler installed with this function - will only be triggered for children that are forked using - :func:`gevent.os.fork` (:func:`gevent.os.fork_and_watch`); - children forked before monkey patching, or otherwise by the raw - :func:`os.fork`, will not trigger the handler installed by this - function. (It's unlikely that a SIGCHLD handler installed with - the builtin :func:`signal.signal` would be triggered either; - libev typically overwrites such a handler at the C level. At - the very least, it's full of race conditions.) - - .. note:: - - Use of ``SIG_IGN`` and ``SIG_DFL`` may also have race conditions - with libev child watchers and the :mod:`gevent.subprocess` module. - - .. versionchanged:: 1.2a1 - If ``SIG_IGN`` or ``SIG_DFL`` are used to ignore ``SIGCHLD``, a - future use of ``gevent.subprocess`` and libev child watchers - will once again work. However, on Python 2, use of ``os.popen`` - will fail. - - .. versionchanged:: 1.1rc2 - Allow using ``SIG_IGN`` and ``SIG_DFL`` to reset and ignore ``SIGCHLD``. - However, this allows the possibility of a race condition if ``gevent.subprocess`` - had already been used. - """ - if signalnum != _signal.SIGCHLD: - return _signal_signal(signalnum, handler) - - # TODO: raise value error if not called from the main - # greenlet, just like threads - - if handler != _signal.SIG_IGN and handler != _signal.SIG_DFL and not callable(handler): - # exact same error message raised by the stdlib - raise TypeError("signal handler must be signal.SIG_IGN, signal.SIG_DFL, or a callable object") - - old_handler = getsignal(signalnum) - global _child_handler - _child_handler = handler - if handler in (_signal.SIG_IGN, _signal.SIG_DFL): - # Allow resetting/ignoring this signal at the process level. - # Note that this conflicts with gevent.subprocess and other users - # of child watchers, until the next time gevent.subprocess/loop.install_sigchld() - # is called. - from gevent.hub import get_hub # Are we always safe to import here? - _signal_signal(signalnum, handler) - get_hub().loop.reset_sigchld() - return old_handler - - -def _on_child_hook(): - # This is called in the hub greenlet. To let the function - # do more useful work, like use blocking functions, - # we run it in a new greenlet; see gevent.hub.signal - if callable(_child_handler): - # None is a valid value for the frame argument - from gevent import Greenlet - if _child_wakeup_fd >= 0: - greenlet = Greenlet(_write_child_signal_fd, - _child_wakeup_fd, - _child_wakeup_fd_warn_on_full_buffer) - greenlet.switch() - greenlet = Greenlet(_child_handler, _signal.SIGCHLD, None) - greenlet.switch() - - -import gevent.os - - -def _write_child_signal_fd(fd, warn_on_full_buffer): - # Along the lines of - # https://github.com/python/cpython/blob/3663b2ad54c9e15775a605facf69da8f5ee8d335/Modules/signalmodule.c#L274 - # Unclear if it'll work on Windows due to sockets used for pipes - - try: - gevent.os._write(fd, bytes((_signal.SIGCHLD,))) # pylint: disable=no-member - except OSError as e: - if warn_on_full_buffer or e.errno not in gevent.os.ignored_errors: # pylint: disable=no-member - from gevent.hub import get_hub # Are we always safe to import here? - get_hub().handle_error("set_wakeup_fd", None, None, None) - - -def set_wakeup_fd(fd, /, *, warn_on_full_buffer=True): - """ - Set the wakeup file descriptor to *fd*. When a signal is received, the signal number is - written as a single byte into the *fd*. This can be used by a library to wakeup a poll - or select call, allowing the signal to be fully processed. - - .. versionadded:: 25.8.1 - """ - old_fd = _signal.set_wakeup_fd(fd, warn_on_full_buffer=warn_on_full_buffer) - global _child_wakeup_fd, _child_wakeup_fd_warn_on_full_buffer - _child_wakeup_fd = fd - _child_wakeup_fd_warn_on_full_buffer = warn_on_full_buffer - return old_fd - -if 'waitpid' in gevent.os.__implements__ and hasattr(_signal, 'SIGCHLD'): # pylint: disable=no-member - # Tightly coupled here to gevent.os and its waitpid implementation; only use these - # if necessary. - gevent.os._on_child_hook = _on_child_hook # pylint: disable=no-member - __implements__.append("signal") - __implements__.append("getsignal") - __implements__.append("set_wakeup_fd") -else: - # XXX: This breaks test__all__ on windows - __extensions__.append("signal") - __extensions__.append("getsignal") - __extensions__.append("set_wakeup_fd") - -__imports__ = copy_globals(_signal, globals(), - names_to_ignore=__implements__ + __extensions__, - dunder_names_to_keep=()) - -__all__ = __implements__ + __extensions__ diff --git a/venv/lib/python3.9/site-packages/gevent/socket.py b/venv/lib/python3.9/site-packages/gevent/socket.py deleted file mode 100644 index 761b3b5..0000000 --- a/venv/lib/python3.9/site-packages/gevent/socket.py +++ /dev/null @@ -1,166 +0,0 @@ -# Copyright (c) 2009-2014 Denis Bilenko and gevent contributors. See LICENSE for details. - -"""Cooperative low-level networking interface. - -This module provides socket operations and some related functions. -The API of the functions and classes matches the API of the corresponding -items in the standard :mod:`socket` module exactly, but the synchronous functions -in this module only block the current greenlet and let the others run. - -For convenience, exceptions (like :class:`error ` and :class:`timeout `) -as well as the constants from the :mod:`socket` module are imported into this module. -""" -# Our import magic sadly makes this warning useless -# pylint: disable=undefined-variable - - -from gevent._compat import PY311 -from gevent._compat import exc_clear -from gevent._util import copy_globals - - - -from gevent import _socket3 as _source - - -# define some things we're expecting to overwrite; each module -# needs to define these -__implements__ = __dns__ = __all__ = __extensions__ = __imports__ = () - - -class error(Exception): - errno = None - - -def getfqdn(*args): - # pylint:disable=unused-argument - raise NotImplementedError() - -copy_globals(_source, globals(), - dunder_names_to_keep=('__implements__', '__dns__', '__all__', - '__extensions__', '__imports__', '__socket__'), - cleanup_globs=False) - -# The _socket2 and _socket3 don't import things defined in -# __extensions__, to help avoid confusing reference cycles in the -# documentation and to prevent importing from the wrong place, but we -# *do* need to expose them here. (NOTE: This may lead to some sphinx -# warnings like: -# WARNING: missing attribute mentioned in :members: or __all__: -# module gevent._socket2, attribute cancel_wait -# These can be ignored.) -from gevent import _socketcommon -copy_globals(_socketcommon, globals(), - only_names=_socketcommon.__extensions__) - -try: - _GLOBAL_DEFAULT_TIMEOUT = __socket__._GLOBAL_DEFAULT_TIMEOUT -except AttributeError: - _GLOBAL_DEFAULT_TIMEOUT = object() - - -def create_connection(address, timeout=_GLOBAL_DEFAULT_TIMEOUT, source_address=None, *, - all_errors=False): - """ - create_connection(address, timeout=None, source_address=None, *, all_errors=False) -> socket - - Connect to *address* and return the :class:`gevent.socket.socket` - object. - - Convenience function. Connect to *address* (a 2-tuple ``(host, - port)``) and return the socket object. Passing the optional - *timeout* parameter will set the timeout on the socket instance - before attempting to connect. If no *timeout* is supplied, the - global default timeout setting returned by - :func:`getdefaulttimeout` is used. If *source_address* is set it - must be a tuple of (host, port) for the socket to bind as a source - address before making the connection. A host of '' or port 0 tells - the OS to use the default. - - .. versionchanged:: 20.6.0 - If the host part of the address includes an IPv6 scope ID, - it will be used instead of ignored, if the platform supplies - :func:`socket.inet_pton`. - .. versionchanged:: 22.08.0 - Add the *all_errors* argument. This only has meaning on Python 3.11+; - it is a programming error to pass it on earlier versions. - .. versionchanged:: 23.7.0 - You can pass a value for ``all_errors`` on any version of Python. - It is forced to false for any version before 3.11 inside the function. - """ - # Sigh. This function is a near-copy of the CPython implementation. - # Even though we simplified some things, it's still a little complex to - # cope with error handling, which got even more complicated in 3.11. - # pylint:disable=too-many-locals,too-many-branches - if not PY311: - all_errors = False - - host, port = address - exceptions = [] - # getaddrinfo is documented as returning a list, but our interface - # is pluggable, so be sure it does. - addrs = list(getaddrinfo(host, port, 0, SOCK_STREAM)) - if not addrs: - raise error("getaddrinfo returns an empty list") - - for res in addrs: - af, socktype, proto, _canonname, sa = res - sock = None - try: - sock = socket(af, socktype, proto) - if timeout is not _GLOBAL_DEFAULT_TIMEOUT: - sock.settimeout(timeout) - if source_address: - sock.bind(source_address) - sock.connect(sa) - - except error as exc: - if not all_errors: - exceptions = [exc] # raise only the last error - else: - exceptions.append(exc) - del exc # cycle - if sock is not None: - sock.close() - sock = None - if res is addrs[-1]: - if not all_errors: - del exceptions[:] - raise - try: - # pylint isn't smart enough to see that we only use this - # on supported versions. - # pylint:disable=using-exception-groups-in-unsupported-version - raise ExceptionGroup("create_connection failed", exceptions) - finally: - # Break explicitly a reference cycle - del exceptions[:] - # without exc_clear(), if connect() fails once, the socket - # is referenced by the frame in exc_info and the next - # bind() fails (see test__socket.TestCreateConnection) - # that does not happen with regular sockets though, - # because _socket.socket.connect() is a built-in. this is - # similar to "getnameinfo loses a reference" failure in - # test_socket.py - exc_clear() - except BaseException: - # Things like GreenletExit, Timeout and KeyboardInterrupt. - # These get raised immediately, being sure to - # close the socket - if sock is not None: - sock.close() - sock = None - raise - else: - # break reference cycles - del exceptions[:] - try: - return sock - finally: - sock = None - - -# This is promised to be in the __all__ of the _source, but, for circularity reasons, -# we implement it in this module. Mostly for documentation purposes, put it -# in the _source too. -_source.create_connection = create_connection diff --git a/venv/lib/python3.9/site-packages/gevent/ssl.py b/venv/lib/python3.9/site-packages/gevent/ssl.py deleted file mode 100644 index 7543909..0000000 --- a/venv/lib/python3.9/site-packages/gevent/ssl.py +++ /dev/null @@ -1,897 +0,0 @@ -# Wrapper module for _ssl. Written by Bill Janssen. -# Ported to gevent by Denis Bilenko. -"""SSL wrapper for socket objects on Python 3. - -For the documentation, refer to :mod:`ssl` module manual. - -This module implements cooperative SSL socket wrappers. -""" - -from __future__ import absolute_import -import ssl as __ssl__ - -_ssl = __ssl__._ssl - -import errno - - -from gevent.socket import socket, timeout_default -from gevent.socket import timeout as _socket_timeout -from gevent._util import copy_globals -socket_error = OSError - -from weakref import ref as _wref - -__implements__ = [ - 'SSLContext', - 'SSLSocket', - 'get_server_certificate', -] - -if hasattr(__ssl__, 'wrap_socket'): - __implements__.append('wrap_socket') - __extra__ = [] -else: - __extra__ = [ - 'wrap_socket', - ] - -# Manually import things we use so we get better linting. -# Also, in the past (adding 3.9 support) it turned out we were -# relying on certain global variables being defined in the ssl module -# that weren't required to be there, e.g., AF_INET, which should be imported -# from socket -from socket import AF_INET -from socket import SOCK_STREAM -from socket import SO_TYPE -from socket import SOL_SOCKET - -from ssl import SSLWantReadError -from ssl import SSLWantWriteError -from ssl import SSLEOFError -from ssl import SSLZeroReturnError -from ssl import CERT_NONE -from ssl import SSLError -from ssl import SSL_ERROR_EOF -from ssl import SSL_ERROR_WANT_READ -from ssl import SSL_ERROR_WANT_WRITE -from ssl import PROTOCOL_SSLv23 -#from ssl import SSLObject - -from ssl import CHANNEL_BINDING_TYPES -from ssl import CERT_REQUIRED -from ssl import DER_cert_to_PEM_cert -from ssl import create_connection - -# Import all symbols from Python's ssl.py, except those that we are implementing -# and "private" symbols. -__imports__ = copy_globals( - __ssl__, globals(), - # SSLSocket *must* subclass gevent.socket.socket; see issue 597 - names_to_ignore=__implements__ + ['socket'], - dunder_names_to_keep=()) - -__all__ = __implements__ + __imports__ + __extra__ -if 'namedtuple' in __all__: - __all__.remove('namedtuple') - -orig_SSLContext = __ssl__.SSLContext # pylint:disable=no-member - -# We have to pass the raw stdlib socket to SSLContext.wrap_socket. -# That method in turn can pass that object on to things like SNI callbacks. -# It wouldn't have access to any of the attributes on the SSLSocket, like -# context, that it's supposed to (see test_ssl.test_sni_callback). Previously -# we just delegated to the sslsocket with __getattr__, but 3.8 -# added some new callbacks and a test that the object they get is an instance -# of the high-level SSLSocket class, so that doesn't work anymore. Instead, -# we wrap the callback and get the real socket to pass on. -class _contextawaresock(socket._gevent_sock_class): - __slots__ = ('_sslsock',) - - def __init__(self, family, type, proto, fileno, sslsocket_wref): - super().__init__(family, type, proto, fileno) - self._sslsock = sslsocket_wref - - -class _Callback(object): - - __slots__ = ('user_function',) - - def __init__(self, user_function): - self.user_function = user_function - - def __call__(self, conn, *args): - conn = conn._sslsock() - return self.user_function(conn, *args) - -class SSLContext(orig_SSLContext): - - __slots__ = () - - # Added in Python 3.7 - sslsocket_class = None # SSLSocket is assigned later - - def wrap_socket(self, sock, server_side=False, - do_handshake_on_connect=True, - suppress_ragged_eofs=True, - server_hostname=None, - session=None): - # pylint:disable=arguments-differ,not-callable - # (3.6 adds session) - # Sadly, using *args and **kwargs doesn't work - return self.sslsocket_class( - sock=sock, server_side=server_side, - do_handshake_on_connect=do_handshake_on_connect, - suppress_ragged_eofs=suppress_ragged_eofs, - server_hostname=server_hostname, - _context=self, - _session=session) - - if hasattr(orig_SSLContext.options, 'setter'): - # In 3.6, these became properties. They want to access the - # property __set__ method in the superclass, and they do so by using - # super(SSLContext, SSLContext). But we rebind SSLContext when we monkey - # patch, which causes infinite recursion. - # https://github.com/python/cpython/commit/328067c468f82e4ec1b5c510a4e84509e010f296 - # pylint:disable=no-member - @orig_SSLContext.options.setter - def options(self, value): - super(orig_SSLContext, orig_SSLContext).options.__set__(self, value) - - @orig_SSLContext.verify_flags.setter - def verify_flags(self, value): - super(orig_SSLContext, orig_SSLContext).verify_flags.__set__(self, value) - - @orig_SSLContext.verify_mode.setter - def verify_mode(self, value): - super(orig_SSLContext, orig_SSLContext).verify_mode.__set__(self, value) - - if hasattr(orig_SSLContext, 'minimum_version'): - # Like the above, added in 3.7 - # pylint:disable=no-member - @orig_SSLContext.minimum_version.setter - def minimum_version(self, value): - super(orig_SSLContext, orig_SSLContext).minimum_version.__set__(self, value) - - @orig_SSLContext.maximum_version.setter - def maximum_version(self, value): - super(orig_SSLContext, orig_SSLContext).maximum_version.__set__(self, value) - - if hasattr(orig_SSLContext, '_msg_callback'): - # And ditto for 3.8 - # msg_callback is more complex because they want to actually *do* stuff - # in the setter, so we need to call it. For that to work we temporarily rebind - # SSLContext back. This function cannot switch, so it should be safe, - # unless somehow we have multiple threads in a monkey-patched ssl module - # at the same time, which doesn't make much sense. - @property - def _msg_callback(self): - result = super()._msg_callback - if isinstance(result, _Callback): - result = result.user_function - return result - - @_msg_callback.setter - def _msg_callback(self, value): - if value and callable(value): - value = _Callback(value) - - __ssl__.SSLContext = orig_SSLContext - try: - super(SSLContext, SSLContext)._msg_callback.__set__(self, value) # pylint:disable=no-member - finally: - __ssl__.SSLContext = SSLContext - - if hasattr(orig_SSLContext, 'sni_callback'): - # Added in 3.7. - @property - def sni_callback(self): - result = super().sni_callback - if isinstance(result, _Callback): - result = result.user_function # pylint:disable=no-member - return result - @sni_callback.setter - def sni_callback(self, value): - if value and callable(value): - value = _Callback(value) - super(orig_SSLContext, orig_SSLContext).sni_callback.__set__(self, value) # pylint:disable=no-member - else: - # In newer versions, this just sets sni_callback. - def set_servername_callback(self, server_name_callback): - if server_name_callback and callable(server_name_callback): - server_name_callback = _Callback(server_name_callback) - super().set_servername_callback(server_name_callback) - - -class SSLSocket(socket): - """ - gevent `ssl.SSLSocket - `_ for - Python 3. - """ - - # pylint:disable=too-many-instance-attributes,too-many-public-methods - - def __init__(self, sock=None, keyfile=None, certfile=None, - server_side=False, cert_reqs=CERT_NONE, - ssl_version=PROTOCOL_SSLv23, ca_certs=None, - do_handshake_on_connect=True, - family=AF_INET, type=SOCK_STREAM, proto=0, fileno=None, - suppress_ragged_eofs=True, npn_protocols=None, ciphers=None, - server_hostname=None, - _session=None, # 3.6 - _context=None): - # When a *sock* argument is passed, it is used only for its fileno() - # and is immediately detach()'d *unless* we raise an error. - - # pylint:disable=too-many-locals,too-many-statements,too-many-branches - - if _context: - self._context = _context - else: - if server_side and not certfile: - raise ValueError("certfile must be specified for server-side " - "operations") - if keyfile and not certfile: - raise ValueError("certfile must be specified") - if certfile and not keyfile: - keyfile = certfile - self._context = SSLContext(ssl_version) - self._context.verify_mode = cert_reqs - if ca_certs: - self._context.load_verify_locations(ca_certs) - if certfile: - self._context.load_cert_chain(certfile, keyfile) - if npn_protocols: - self._context.set_npn_protocols(npn_protocols) - if ciphers: - self._context.set_ciphers(ciphers) - self.keyfile = keyfile - self.certfile = certfile - self.cert_reqs = cert_reqs - self.ssl_version = ssl_version - self.ca_certs = ca_certs - self.ciphers = ciphers - # Can't use sock.type as other flags (such as SOCK_NONBLOCK) get - # mixed in. - if sock.getsockopt(SOL_SOCKET, SO_TYPE) != SOCK_STREAM: - raise NotImplementedError("only stream sockets are supported") - if server_side: - if server_hostname: - raise ValueError("server_hostname can only be specified " - "in client mode") - if _session is not None: - raise ValueError("session can only be specified " - "in client mode") - if self._context.check_hostname and not server_hostname: - raise ValueError("check_hostname requires server_hostname") - self._session = _session - self.server_side = server_side - self.server_hostname = server_hostname - self.do_handshake_on_connect = do_handshake_on_connect - self.suppress_ragged_eofs = suppress_ragged_eofs - connected = False - sock_timeout = None - if sock is not None: - # We're going non-blocking below, can't set timeout yet. - sock_timeout = sock.gettimeout() - socket.__init__(self, - family=sock.family, - type=sock.type, - proto=sock.proto, - fileno=sock.fileno()) - - # When Python 3 sockets are __del__, they close() themselves, - # including their underlying fd, unless they have been detached. - # Only detach if we succeed in taking ownership; if we raise an exception, - # then the user might have no way to close us and release the resources. - sock.detach() - elif fileno is not None: - socket.__init__(self, fileno=fileno) - else: - socket.__init__(self, family=family, type=type, proto=proto) - - self._closed = False - self._sslobj = None - # see if we're connected - try: - self._sock.getpeername() - except OSError as e: - if e.errno != errno.ENOTCONN: - # This file descriptor is hosed, shared or not. - # Clean up. - self.close() - raise - # Next block is originally from - # https://github.com/python/cpython/commit/75a875e0df0530b75b1470d797942f90f4a718d3, - # intended to fix https://github.com/python/cpython/issues/108310 - blocking = self.getblocking() - self.setblocking(False) - try: - # We are not connected so this is not supposed to block, but - # testing revealed otherwise on macOS and Windows so we do - # the non-blocking dance regardless. Our raise when any data - # is found means consuming the data is harmless. - notconn_pre_handshake_data = self.recv(1) - except OSError as e: # pylint:disable=redefined-outer-name - # EINVAL occurs for recv(1) on non-connected on unix sockets. - if e.errno not in (errno.ENOTCONN, errno.EINVAL): - raise - notconn_pre_handshake_data = b'' - self.setblocking(blocking) - if notconn_pre_handshake_data: - # This prevents pending data sent to the socket before it was - # closed from escaping to the caller who could otherwise - # presume it came through a successful TLS connection. - reason = "Closed before TLS handshake with data in recv buffer." - notconn_pre_handshake_data_error = SSLError(e.errno, reason) - # Add the SSLError attributes that _ssl.c always adds. - notconn_pre_handshake_data_error.reason = reason - notconn_pre_handshake_data_error.library = None - try: - self.close() - except OSError: - pass - raise notconn_pre_handshake_data_error - else: - connected = True - - self.settimeout(sock_timeout) - self._connected = connected - if connected: - # create the SSL object - try: - self._sslobj = self.__create_sslobj(server_side, _session) - - if do_handshake_on_connect: - timeout = self.gettimeout() - if timeout == 0.0: - # non-blocking - raise ValueError("do_handshake_on_connect should not be specified for non-blocking sockets") - self.do_handshake() - except OSError: - self.close() - raise - - def _gevent_sock_class(self, family, type, proto, fileno): - return _contextawaresock(family, type, proto, fileno, _wref(self)) - - def _extra_repr(self): - return ' server=%s, cipher=%r' % ( - self.server_side, - self._sslobj.cipher() if self._sslobj is not None else '' - - ) - - @property - def context(self): - return self._context - - @context.setter - def context(self, ctx): - self._context = ctx - self._sslobj.context = ctx - - @property - def session(self): - """The SSLSession for client socket.""" - if self._sslobj is not None: - return self._sslobj.session - - @session.setter - def session(self, session): - self._session = session - if self._sslobj is not None: - self._sslobj.session = session - - @property - def session_reused(self): - """Was the client session reused during handshake""" - if self._sslobj is not None: - return self._sslobj.session_reused - - def dup(self): - raise NotImplementedError("Can't dup() %s instances" % - self.__class__.__name__) - - def _checkClosed(self, msg=None): - # raise an exception here if you wish to check for spurious closes - pass - - def _check_connected(self): - if not self._connected: - # getpeername() will raise ENOTCONN if the socket is really - # not connected; note that we can be connected even without - # _connected being set, e.g. if connect() first returned - # EAGAIN. - self.getpeername() - - def read(self, nbytes=2014, buffer=None): - """Read up to LEN bytes and return them. - Return zero-length string on EOF. - - .. versionchanged:: 24.2.1 - No longer requires a non-None *buffer* to implement ``len()``. - This is a backport from 3.11.8. - """ - # pylint:disable=too-many-branches - self._checkClosed() - # The stdlib signature is (len=1024, buffer=None) - # but that shadows the len builtin, and its hard/annoying to - # get it back. - # - # Also, the return values are weird. If *buffer* is given, - # we return the count of bytes added to buffer. Otherwise, - # we return the string we read. - bytes_read = 0 - - while True: - if not self._sslobj: - raise ValueError("Read on closed or unwrapped SSL socket.") - if nbytes == 0: - return b'' if buffer is None else 0 - # Negative lengths are handled natively when the buffer is None - # to raise a ValueError - try: - if buffer is not None: - bytes_read += self._sslobj.read(nbytes, buffer) - return bytes_read - return self._sslobj.read(nbytes or 1024) - except SSLWantReadError: - if self.timeout == 0.0: - raise - self._wait(self._read_event, timeout_exc=_SSLErrorReadTimeout()) - except SSLWantWriteError: - if self.timeout == 0.0: - raise - # note: using _SSLErrorReadTimeout rather than _SSLErrorWriteTimeout below is intentional - self._wait(self._write_event, timeout_exc=_SSLErrorReadTimeout()) - except SSLZeroReturnError: - # This one is only seen in PyPy 7.3.17 - if self.suppress_ragged_eofs: - return b'' if buffer is None else bytes_read - raise - except SSLError as ex: - # All the other SSLxxxxxError classes extend SSLError, - # so catch it last. - if ex.args[0] == SSL_ERROR_EOF and self.suppress_ragged_eofs: - return b'' if buffer is None else bytes_read - raise - # Certain versions of Python, built against certain - # versions of OpenSSL operating in certain modes, can - # produce ``ConnectionResetError`` instead of - # ``SSLError``. Notably, it looks like anything built - # against 1.1.1c does that? gevent briefly (from support of TLS 1.3 - # in Sept 2019 to issue #1637 it June 2020) caught that error and treaded - # it just like SSL_ERROR_EOF. But that's not what the standard library does. - # So presumably errors that result from unexpected ``ConnectionResetError`` - # are issues in gevent tests. - - def write(self, data): - """Write DATA to the underlying SSL channel. Returns - number of bytes of DATA actually transmitted.""" - self._checkClosed() - - while True: - if not self._sslobj: - raise ValueError("Write on closed or unwrapped SSL socket.") - - try: - return self._sslobj.write(data) - except SSLError as ex: - if ex.args[0] == SSL_ERROR_WANT_READ: - if self.timeout == 0.0: - raise - self._wait(self._read_event, timeout_exc=_SSLErrorWriteTimeout()) - elif ex.args[0] == SSL_ERROR_WANT_WRITE: - if self.timeout == 0.0: - raise - self._wait(self._write_event, timeout_exc=_SSLErrorWriteTimeout()) - else: - raise - - def getpeercert(self, binary_form=False): - """Returns a formatted version of the data in the - certificate provided by the other end of the SSL channel. - Return None if no certificate was provided, {} if a - certificate was provided, but not validated.""" - - self._checkClosed() - self._check_connected() - try: - c = self._sslobj.peer_certificate - except AttributeError: - # 3.6 - c = self._sslobj.getpeercert - - return c(binary_form) - - def selected_npn_protocol(self): - self._checkClosed() - if not self._sslobj or not _ssl.HAS_NPN: - return None - return self._sslobj.selected_npn_protocol() - - if hasattr(_ssl, 'HAS_ALPN'): - # 3.5+ - def selected_alpn_protocol(self): - self._checkClosed() - if not self._sslobj or not _ssl.HAS_ALPN: # pylint:disable=no-member - return None - return self._sslobj.selected_alpn_protocol() - - def shared_ciphers(self): - """Return a list of ciphers shared by the client during the handshake or - None if this is not a valid server connection. - """ - return self._sslobj.shared_ciphers() - - def version(self): - """Return a string identifying the protocol version used by the - current SSL channel. """ - if not self._sslobj: - return None - return self._sslobj.version() - - # We inherit sendfile from super(); it always uses `send` - - def cipher(self): - self._checkClosed() - if not self._sslobj: - return None - return self._sslobj.cipher() - - def compression(self): - self._checkClosed() - if not self._sslobj: - return None - return self._sslobj.compression() - - def send(self, data, flags=0, timeout=timeout_default): - self._checkClosed() - if timeout is timeout_default: - timeout = self.timeout - if self._sslobj: - if flags != 0: - raise ValueError( - "non-zero flags not allowed in calls to send() on %s" % - self.__class__) - while True: - try: - return self._sslobj.write(data) - except SSLWantReadError: - if self.timeout == 0.0: - return 0 - self._wait(self._read_event) - except SSLWantWriteError: - if self.timeout == 0.0: - return 0 - self._wait(self._write_event) - else: - return socket.send(self, data, flags, timeout) - - def sendto(self, data, flags_or_addr, addr=None): - self._checkClosed() - if self._sslobj: - raise ValueError("sendto not allowed on instances of %s" % - self.__class__) - if addr is None: - return socket.sendto(self, data, flags_or_addr) - return socket.sendto(self, data, flags_or_addr, addr) - - def sendmsg(self, *args, **kwargs): - # Ensure programs don't send data unencrypted if they try to - # use this method. - raise NotImplementedError("sendmsg not allowed on instances of %s" % - self.__class__) - - def sendall(self, data, flags=0): - self._checkClosed() - if self._sslobj: - if flags != 0: - raise ValueError( - "non-zero flags not allowed in calls to sendall() on %s" % - self.__class__) - - try: - return socket.sendall(self, data, flags) - except _socket_timeout: - if self.timeout == 0.0: - # Raised by the stdlib on non-blocking sockets - raise SSLWantWriteError("The operation did not complete (write)") - raise - - def recv(self, buflen=1024, flags=0): - self._checkClosed() - if self._sslobj: - if flags != 0: - raise ValueError( - "non-zero flags not allowed in calls to recv() on %s" % - self.__class__) - if buflen == 0: - # https://github.com/python/cpython/commit/00915577dd84ba75016400793bf547666e6b29b5 - # Python #23804 - return b'' - return self.read(buflen) - return socket.recv(self, buflen, flags) - - def recv_into(self, buffer, nbytes=None, flags=0): - """ - .. versionchanged:: 24.2.1 - No longer requires a non-None *buffer* to implement ``len()``. - This is a backport from 3.11.8. - """ - self._checkClosed() - if nbytes is None: - if buffer is not None: - with memoryview(buffer) as view: - nbytes = view.nbytes - if not nbytes: - nbytes = 1024 - - if self._sslobj: - if flags != 0: - raise ValueError("non-zero flags not allowed in calls to recv_into() on %s" % self.__class__) - return self.read(nbytes, buffer) - return socket.recv_into(self, buffer, nbytes, flags) - - def recvfrom(self, buflen=1024, flags=0): - self._checkClosed() - if self._sslobj: - raise ValueError("recvfrom not allowed on instances of %s" % - self.__class__) - return socket.recvfrom(self, buflen, flags) - - def recvfrom_into(self, buffer, nbytes=None, flags=0): - self._checkClosed() - if self._sslobj: - raise ValueError("recvfrom_into not allowed on instances of %s" % - self.__class__) - return socket.recvfrom_into(self, buffer, nbytes, flags) - - def recvmsg(self, *args, **kwargs): - raise NotImplementedError("recvmsg not allowed on instances of %s" % - self.__class__) - - def recvmsg_into(self, *args, **kwargs): - raise NotImplementedError("recvmsg_into not allowed on instances of " - "%s" % self.__class__) - - def pending(self): - self._checkClosed() - if self._sslobj: - return self._sslobj.pending() - return 0 - - def shutdown(self, how): - self._checkClosed() - self._sslobj = None - socket.shutdown(self, how) - - def unwrap(self): - if not self._sslobj: - raise ValueError("No SSL wrapper around " + str(self)) - - try: - # 3.7 and newer, that use the SSLSocket object - # call its shutdown. - shutdown = self._sslobj.shutdown - except AttributeError: - # Earlier versions use SSLObject, which covers - # that with a layer. - shutdown = self._sslobj.unwrap - - s = self._sock - while True: - try: - s = shutdown() - break - except SSLWantReadError: - # Callers of this method expect to get a socket - # back, so we can't simply return 0, we have - # to let these be raised - if self.timeout == 0.0: - raise - self._wait(self._read_event) - except SSLWantWriteError: - if self.timeout == 0.0: - raise - self._wait(self._write_event) - except SSLEOFError: - break - except SSLZeroReturnError: - # Between PyPy 7.3.12 and PyPy 7.3.17, it started raising - # this. This is equivalent to SSLEOFError for our purposes: - # both indicate the connection has been closed, - # the former uncleanly, the latter cleanly. - break - except OSError as e: - if e.errno == 0: - # The equivalent of SSLEOFError on unpatched versions of Python. - # https://bugs.python.org/issue31122 - break - raise - - self._sslobj = None - - # The return value of shutting down the SSLObject is the - # original wrapped socket passed to _wrap_socket, i.e., - # _contextawaresock. But that object doesn't have the - # gevent wrapper around it so it can't be used. We have to - # wrap it back up with a gevent wrapper. - assert s is self._sock - # In the stdlib, SSLSocket subclasses socket.socket and passes itself - # to _wrap_socket, so it gets itself back. We can't do that, we have to - # pass our subclass of _socket.socket, _contextawaresock. - # So ultimately we should return ourself. - - # See test_ftplib.py:TestTLS_FTPClass.test_ccc - return self - - def _real_close(self): - self._sslobj = None - socket._real_close(self) - - def do_handshake(self): - """Perform a TLS/SSL handshake.""" - self._check_connected() - while True: - try: - self._sslobj.do_handshake() - break - except SSLWantReadError: - if self.timeout == 0.0: - raise - self._wait(self._read_event, timeout_exc=_SSLErrorHandshakeTimeout()) - except SSLWantWriteError: - if self.timeout == 0.0: - raise - self._wait(self._write_event, timeout_exc=_SSLErrorHandshakeTimeout()) - - # 3.7+, making it difficult to create these objects. - # There's a new type, _ssl.SSLSocket, that takes the - # place of SSLObject for self._sslobj. This one does it all. - def __create_sslobj(self, server_side=False, session=None): - return self.context._wrap_socket( - self._sock, server_side, self.server_hostname, - owner=self._sock, session=session - ) - - def _real_connect(self, addr, connect_ex): - if self.server_side: - raise ValueError("can't connect in server-side mode") - # Here we assume that the socket is client-side, and not - # connected at the time of the call. We connect it, then wrap it. - if self._connected: - raise ValueError("attempt to connect already-connected SSLSocket!") - self._sslobj = self.__create_sslobj(False, self._session) - - try: - if connect_ex: - rc = socket.connect_ex(self, addr) - else: - rc = None - socket.connect(self, addr) - if not rc: - if self.do_handshake_on_connect: - self.do_handshake() - self._connected = True - return rc - except socket_error: - self._sslobj = None - raise - - def connect(self, addr): - """Connects to remote ADDR, and then wraps the connection in - an SSL channel.""" - self._real_connect(addr, False) - - def connect_ex(self, addr): - """Connects to remote ADDR, and then wraps the connection in - an SSL channel.""" - return self._real_connect(addr, True) - - def accept(self): - """ - Accepts a new connection from a remote client, and returns a - tuple containing that new connection wrapped with a - server-side SSL channel, and the address of the remote client. - """ - newsock, addr = super().accept() - try: - newsock = self._context.wrap_socket( - newsock, - do_handshake_on_connect=self.do_handshake_on_connect, - suppress_ragged_eofs=self.suppress_ragged_eofs, - server_side=True - ) - return newsock, addr - except: - newsock.close() - raise - - def get_channel_binding(self, cb_type="tls-unique"): - """Get channel binding data for current connection. Raise ValueError - if the requested `cb_type` is not supported. Return bytes of the data - or None if the data is not available (e.g. before the handshake). - """ - if hasattr(self._sslobj, 'get_channel_binding'): - # 3.7+, and sslobj is not None - return self._sslobj.get_channel_binding(cb_type) - if cb_type not in CHANNEL_BINDING_TYPES: - raise ValueError("Unsupported channel binding type") - if cb_type != "tls-unique": - raise NotImplementedError("{0} channel binding type not implemented".format(cb_type)) - if self._sslobj is None: - return None - return self._sslobj.tls_unique_cb() - - def verify_client_post_handshake(self): - # Only present in 3.7.1+; an attributeerror is alright - if self._sslobj: - return self._sslobj.verify_client_post_handshake() - raise ValueError("No SSL wrapper around " + str(self)) - - if hasattr(__ssl__.SSLSocket, 'get_verified_chain'): - # Added in 3.13 - def get_verified_chain(self): - chain = self._sslobj.get_verified_chain() - - if chain is None: - return [] - - return [cert.public_bytes(_ssl.ENCODING_DER) for cert in chain] - - def get_unverified_chain(self): - chain = self._sslobj.get_unverified_chain() - - if chain is None: - return [] - - return [cert.public_bytes(_ssl.ENCODING_DER) for cert in chain] - -# Python does not support forward declaration of types -SSLContext.sslsocket_class = SSLSocket - -# Python 3.2 onwards raise normal timeout errors, not SSLError. -# See https://bugs.python.org/issue10272 -def _SSLErrorReadTimeout(): - return _socket_timeout('The read operation timed out') -def _SSLErrorWriteTimeout(): - return _socket_timeout('The write operation timed out') -def _SSLErrorHandshakeTimeout(): - return _socket_timeout('The handshake operation timed out') - - -def wrap_socket(sock, keyfile=None, certfile=None, - server_side=False, cert_reqs=CERT_NONE, - ssl_version=PROTOCOL_SSLv23, ca_certs=None, - do_handshake_on_connect=True, - suppress_ragged_eofs=True, - ciphers=None): - - return SSLSocket(sock=sock, keyfile=keyfile, certfile=certfile, - server_side=server_side, cert_reqs=cert_reqs, - ssl_version=ssl_version, ca_certs=ca_certs, - do_handshake_on_connect=do_handshake_on_connect, - suppress_ragged_eofs=suppress_ragged_eofs, - ciphers=ciphers) - - -def get_server_certificate(addr, ssl_version=PROTOCOL_SSLv23, ca_certs=None): - """Retrieve the certificate from the server at the specified address, - and return it as a PEM-encoded string. - If 'ca_certs' is specified, validate the server cert against it. - If 'ssl_version' is specified, use it in the connection attempt.""" - - _, _ = addr - if ca_certs is not None: - cert_reqs = CERT_REQUIRED - else: - cert_reqs = CERT_NONE - with create_connection(addr) as sock: - with wrap_socket(sock, ssl_version=ssl_version, - cert_reqs=cert_reqs, ca_certs=ca_certs) as sslsock: - dercert = sslsock.getpeercert(True) - sslsock = sock = None - return DER_cert_to_PEM_cert(dercert) diff --git a/venv/lib/python3.9/site-packages/gevent/subprocess.py b/venv/lib/python3.9/site-packages/gevent/subprocess.py deleted file mode 100644 index 73ce51e..0000000 --- a/venv/lib/python3.9/site-packages/gevent/subprocess.py +++ /dev/null @@ -1,2053 +0,0 @@ -""" -Cooperative ``subprocess`` module. - -.. caution:: On POSIX platforms, this module is not usable from native - threads other than the main thread; attempting to do so will raise - a :exc:`TypeError`. This module depends on libev's fork watchers. - On POSIX systems, fork watchers are implemented using signals, and - the thread to which process-directed signals are delivered `is not - defined`_. Because each native thread has its own gevent/libev - loop, this means that a fork watcher registered with one loop - (thread) may never see the signal about a child it spawned if the - signal is sent to a different thread. - -.. note:: The interface of this module is intended to match that of - the standard library :mod:`subprocess` module (with many backwards - compatible extensions from Python 3 backported to Python 2). There - are some small differences between the Python 2 and Python 3 - versions of that module (the Python 2 ``TimeoutExpired`` exception, - notably, extends ``Timeout`` and there is no ``SubprocessError``) and between the - POSIX and Windows versions. The HTML documentation here can only - describe one version; for definitive documentation, see the - standard library or the source code. - -.. _is not defined: http://www.linuxprogrammingblog.com/all-about-linux-signals?page=11 - -Be sure to see important notes in :func:`gevent.monkey.patch_subprocess`. -""" -from __future__ import absolute_import, print_function -# Can we split this up to make it cleaner? See https://github.com/gevent/gevent/issues/748 -# pylint: disable=too-many-lines -# Most of this we inherit from the standard lib -# pylint: disable=bare-except,too-many-locals,too-many-statements,attribute-defined-outside-init -# pylint: disable=too-many-branches,too-many-instance-attributes -# Most of this is cross-platform -# pylint: disable=no-member,expression-not-assigned,unused-argument,unused-variable -import errno -import gc -import os -import signal -import sys -import traceback -# Python 3.9 -try: - from types import GenericAlias -except ImportError: - GenericAlias = None - -try: - import grp -except ImportError: - grp = None - -try: - import pwd -except ImportError: - pwd = None - -from gevent.event import AsyncResult -from gevent.hub import _get_hub_noargs as get_hub -from gevent.hub import linkproxy -from gevent.hub import sleep -from gevent.hub import getcurrent -from gevent._compat import integer_types, string_types, xrange - -from gevent._compat import PY311 -from gevent._compat import PYPY -from gevent._compat import PY313 -from gevent._compat import PY314 -from gevent._compat import WIN -from gevent._compat import MAC - -from gevent._compat import fsdecode -from gevent._compat import fsencode -from gevent._compat import PathLike -from gevent._util import _NONE -from gevent._util import copy_globals - -from gevent.greenlet import Greenlet, joinall -spawn = Greenlet.spawn -import subprocess as __subprocess__ -# We need our sockets (at least those involved in launching children) -# to REALLY get closed so we can get EPIPE and stop reading. Otherwise -# a few tests hang -from gevent.os import _close as os_close - -# Standard functions and classes that this module re-implements in a gevent-aware way. -__implements__ = [ - 'Popen', - 'call', - 'check_call', - 'check_output', -] -if not sys.platform.startswith('win32'): - __implements__.append("_posixsubprocess") - _posixsubprocess = None - - -# Some symbols we define that we expect to export; -# useful for static analysis -PIPE = "PIPE should be imported" - -# Standard functions and classes that this module re-imports. -__imports__ = [ - 'PIPE', - 'STDOUT', - 'CalledProcessError', - # Windows: - 'CREATE_NEW_CONSOLE', - 'CREATE_NEW_PROCESS_GROUP', - 'STD_INPUT_HANDLE', - 'STD_OUTPUT_HANDLE', - 'STD_ERROR_HANDLE', - 'SW_HIDE', - 'STARTF_USESTDHANDLES', - 'STARTF_USESHOWWINDOW', -] - - -__extra__ = [ - 'MAXFD', - '_eintr_retry_call', - 'STARTUPINFO', - 'pywintypes', - 'list2cmdline', - '_subprocess', - '_winapi', - # Python 2.5 does not have _subprocess, so we don't use it - # XXX We don't run on Py 2.5 anymore; can/could/should we use _subprocess? - # It's only used on mswindows - 'WAIT_OBJECT_0', - 'WaitForSingleObject', - 'GetExitCodeProcess', - 'GetStdHandle', - 'CreatePipe', - 'DuplicateHandle', - 'GetCurrentProcess', - 'DUPLICATE_SAME_ACCESS', - 'GetModuleFileName', - 'GetVersion', - 'CreateProcess', - 'INFINITE', - 'TerminateProcess', - 'STILL_ACTIVE', - - # These were added for 3.5, but we make them available everywhere. - 'run', - 'CompletedProcess', -] - -__imports__ += [ - 'DEVNULL', - 'getstatusoutput', - 'getoutput', - 'SubprocessError', - 'TimeoutExpired', -] - -# Became standard in 3.5 -__extra__.remove('run') -__extra__.remove('CompletedProcess') -__implements__.append('run') -__implements__.append('CompletedProcess') - -# Removed in Python 3.5; this is the exact code that was removed: -# https://hg.python.org/cpython/rev/f98b0a5e5ef5 -__extra__.remove('MAXFD') -try: - MAXFD = os.sysconf("SC_OPEN_MAX") -except: - MAXFD = 256 - - -# This was added to __all__ for windows in 3.6 -__extra__.remove('STARTUPINFO') -__imports__.append('STARTUPINFO') - -__imports__.extend([ - 'ABOVE_NORMAL_PRIORITY_CLASS', 'BELOW_NORMAL_PRIORITY_CLASS', - 'HIGH_PRIORITY_CLASS', 'IDLE_PRIORITY_CLASS', - 'NORMAL_PRIORITY_CLASS', - 'REALTIME_PRIORITY_CLASS', - 'CREATE_NO_WINDOW', 'DETACHED_PROCESS', - 'CREATE_DEFAULT_ERROR_MODE', - 'CREATE_BREAKAWAY_FROM_JOB' -]) - -if PY313 and WIN: - __imports__.extend([ - 'STARTF_FORCEONFEEDBACK', - 'STARTF_FORCEOFFFEEDBACK' - ]) - - -# Using os.posix_spawn() to start subprocesses -# bypasses our child watchers on certain operating systems, -# and with certain library versions. Possibly the right -# fix is to monkey-patch os.posix_spawn like we do os.fork? -# These have no effect, they're just here to match the stdlib. -# TODO: When available, given a monkey patch on them, I think -# we ought to be able to use them if the stdlib has identified them -# as suitable. -__implements__.extend([ - '_use_posix_spawn', -]) - -def _use_posix_spawn(): - return False - -_USE_POSIX_SPAWN = False - -if __subprocess__._USE_POSIX_SPAWN: - __implements__.extend([ - '_USE_POSIX_SPAWN', - ]) -else: - __imports__.extend([ - '_USE_POSIX_SPAWN', - ]) - -if PY311: - # Python 3.11 added some module-level attributes to control the - # use of vfork. The docs specifically say that you should not try to read - # them, only set them, so we don't provide them. - # - # Python 3.11 also added a test, test_surrogates_error_message, that behaves - # differently based on whether or not the pure python implementation of forking - # is in use, or the one written in C from _posixsubprocess. Obviously we don't call - # that, so we need to make us look like a pure python version; it checks that this attribute - # is none for that. - _fork_exec = None - __implements__.extend([ - '_fork_exec', - ] if sys.platform != 'win32' else [ - ]) - -actually_imported = copy_globals(__subprocess__, globals(), - only_names=__imports__, - ignore_missing_names=True) -# anything we couldn't import from here we may need to find -# elsewhere -__extra__.extend(set(__imports__).difference(set(actually_imported))) -__imports__ = actually_imported -del actually_imported - - -# In Python 3 on Windows, a lot of the functions previously -# in _subprocess moved to _winapi -_subprocess = getattr(__subprocess__, '_subprocess', _NONE) -_winapi = getattr(__subprocess__, '_winapi', _NONE) - -_attr_resolution_order = [__subprocess__, _subprocess, _winapi] - -for name in list(__extra__): - if name in globals(): - continue - value = _NONE - for place in _attr_resolution_order: - value = getattr(place, name, _NONE) - if value is not _NONE: - break - - if value is _NONE: - __extra__.remove(name) - else: - globals()[name] = value - -del _attr_resolution_order -__all__ = __implements__ + __imports__ -# Some other things we want to document -for _x in ('run', 'CompletedProcess', 'TimeoutExpired'): - if _x not in __all__: - __all__.append(_x) - - - -mswindows = WIN -if mswindows: - import msvcrt # pylint: disable=import-error - class Handle(int): - closed = False - - def Close(self): - if not self.closed: - self.closed = True - _winapi.CloseHandle(self) - - def Detach(self): - if not self.closed: - self.closed = True - return int(self) - raise ValueError("already closed") - - def __repr__(self): - return "Handle(%d)" % int(self) - - __del__ = Close - __str__ = __repr__ -else: - import fcntl - import pickle - from gevent import monkey - fork = monkey.get_original('os', 'fork') - from gevent.os import fork_and_watch - -# Some explicit imports for static analysis -STDOUT = __subprocess__.STDOUT -TimeoutExpired = __subprocess__.TimeoutExpired - - -def call(*popenargs, **kwargs): - """ - call(args, *, stdin=None, stdout=None, stderr=None, shell=False, timeout=None) -> returncode - - Run command with arguments. Wait for command to complete or - timeout, then return the returncode attribute. - - The arguments are the same as for the Popen constructor. Example:: - - retcode = call(["ls", "-l"]) - - .. versionchanged:: 1.2a1 - The ``timeout`` keyword argument is now accepted on all supported - versions of Python (not just Python 3) and if it expires will raise a - :exc:`TimeoutExpired` exception (under Python 2 this is a subclass of :exc:`~.Timeout`). - """ - timeout = kwargs.pop('timeout', None) - with Popen(*popenargs, **kwargs) as p: - try: - return p.wait(timeout=timeout, _raise_exc=True) - except: - p.kill() - p.wait() - raise - -def check_call(*popenargs, **kwargs): - """ - check_call(args, *, stdin=None, stdout=None, stderr=None, shell=False, timeout=None) -> 0 - - Run command with arguments. Wait for command to complete. If - the exit code was zero then return, otherwise raise - :exc:`CalledProcessError`. The ``CalledProcessError`` object will have the - return code in the returncode attribute. - - The arguments are the same as for the Popen constructor. Example:: - - retcode = check_call(["ls", "-l"]) - """ - retcode = call(*popenargs, **kwargs) - if retcode: - cmd = kwargs.get("args") - if cmd is None: - cmd = popenargs[0] - raise CalledProcessError(retcode, cmd) # pylint:disable=undefined-variable - return 0 - -def check_output(*popenargs, **kwargs): - r""" - check_output(args, *, input=None, stdin=None, stderr=None, shell=False, universal_newlines=False, timeout=None) -> output - - Run command with arguments and return its output. - - If the exit code was non-zero it raises a :exc:`CalledProcessError`. The - ``CalledProcessError`` object will have the return code in the returncode - attribute and output in the output attribute. - - - The arguments are the same as for the Popen constructor. Example:: - - >>> check_output(["ls", "-1", "/dev/null"]) - '/dev/null\n' - - The ``stdout`` argument is not allowed as it is used internally. - - To capture standard error in the result, use ``stderr=STDOUT``:: - - >>> output = check_output(["/bin/sh", "-c", - ... "ls -l non_existent_file ; exit 0"], - ... stderr=STDOUT).decode('ascii').strip() - >>> print(output.rsplit(':', 1)[1].strip()) - No such file or directory - - There is an additional optional argument, "input", allowing you to - pass a string to the subprocess's stdin. If you use this argument - you may not also use the Popen constructor's "stdin" argument, as - it too will be used internally. Example:: - - >>> check_output(["sed", "-e", "s/foo/bar/"], - ... input=b"when in the course of fooman events\n") - 'when in the course of barman events\n' - - If ``universal_newlines=True`` is passed, the return value will be a - string rather than bytes. - - .. versionchanged:: 1.2a1 - The ``timeout`` keyword argument is now accepted on all supported - versions of Python (not just Python 3) and if it expires will raise a - :exc:`TimeoutExpired` exception (under Python 2 this is a subclass of :exc:`~.Timeout`). - .. versionchanged:: 1.2a1 - The ``input`` keyword argument is now accepted on all supported - versions of Python, not just Python 3 - .. versionchanged:: 22.08.0 - Passing the ``check`` keyword argument is forbidden, just as in Python 3.11. - """ - timeout = kwargs.pop('timeout', None) - if 'stdout' in kwargs: - raise ValueError('stdout argument not allowed, it will be overridden.') - if 'check' in kwargs: - raise ValueError('check argument not allowed, it will be overridden.') - if 'input' in kwargs: - if 'stdin' in kwargs: - raise ValueError('stdin and input arguments may not both be used.') - inputdata = kwargs['input'] - del kwargs['input'] - kwargs['stdin'] = PIPE - else: - inputdata = None - - with Popen(*popenargs, stdout=PIPE, **kwargs) as process: - try: - output, unused_err = process.communicate(inputdata, timeout=timeout) - except TimeoutExpired: - process.kill() - output, unused_err = process.communicate() - raise TimeoutExpired(process.args, timeout, output=output) - except: - process.kill() - process.wait() - raise - retcode = process.poll() - if retcode: - # pylint:disable=undefined-variable - raise CalledProcessError(retcode, process.args, output=output) - return output - -_PLATFORM_DEFAULT_CLOSE_FDS = object() - -if hasattr(os, 'set_inheritable'): - _set_inheritable = os.set_inheritable -else: - _set_inheritable = lambda i, v: True - - -def FileObject(*args, **kwargs): - # Defer importing FileObject until we need it - # to allow it to be configured more easily. - from gevent.fileobject import FileObject as _FileObject - globals()['FileObject'] = _FileObject - return _FileObject(*args) - - -class _CommunicatingGreenlets(object): - # At most, exactly one of these objects may be created - # for a given Popen object. This ensures that only one background - # greenlet at a time will be reading from the file object. This matters because - # if a timeout exception is raised, the user may call back into communicate() to - # get the output (usually after killing the process; see run()). We must not - # lose output in that case (Python 3 specifically documents that raising a timeout - # doesn't lose output). Also, attempting to read from a pipe while it's already - # being read from results in `RuntimeError: reentrant call in io.BufferedReader`; - # the same thing happens if you attempt to close() it while that's in progress. - __slots__ = ( - 'stdin', - 'stdout', - 'stderr', - '_all_greenlets', - ) - - def __init__(self, popen, input_data): - self.stdin = self.stdout = self.stderr = None - if popen.stdin: # Even if no data, we need to close - self.stdin = spawn(self._write_and_close, popen.stdin, input_data) - - # If the timeout parameter is used, and the caller calls back after - # getting a TimeoutExpired exception, we can wind up with multiple - # greenlets trying to run and read from and close stdout/stderr. - # That's bad because it can lead to 'RuntimeError: reentrant call in io.BufferedReader'. - # We can't just kill the previous greenlets when a timeout happens, - # though, because we risk losing the output collected by that greenlet - # (and Python 3, where timeout is an official parameter, explicitly says - # that no output should be lost in the event of a timeout.) Instead, we're - # watching for the exception and ignoring it. It's not elegant, - # but it works - if popen.stdout: - self.stdout = spawn(self._read_and_close, popen.stdout) - - if popen.stderr: - self.stderr = spawn(self._read_and_close, popen.stderr) - - all_greenlets = [] - for g in self.stdin, self.stdout, self.stderr: - if g is not None: - all_greenlets.append(g) - self._all_greenlets = tuple(all_greenlets) - - def __iter__(self): - return iter(self._all_greenlets) - - def __bool__(self): - return bool(self._all_greenlets) - - __nonzero__ = __bool__ - - def __len__(self): - return len(self._all_greenlets) - - @staticmethod - def _write_and_close(fobj, data): - try: - if data: - fobj.write(data) - if hasattr(fobj, 'flush'): - # 3.6 started expecting flush to be called. - fobj.flush() - except OSError as ex: - # Test cases from the stdlib can raise BrokenPipeError - # without setting an errno value. This matters because - # Python 2 doesn't have a BrokenPipeError. - if isinstance(ex, BrokenPipeError) and ex.errno is None: - ex.errno = errno.EPIPE - if ex.errno not in (errno.EPIPE, errno.EINVAL): - raise - finally: - try: - fobj.close() - except EnvironmentError: - pass - - @staticmethod - def _read_and_close(fobj): - try: - return fobj.read() - finally: - try: - fobj.close() - except EnvironmentError: - pass - - -class Popen(object): - """ - The underlying process creation and management in this module is - handled by the Popen class. It offers a lot of flexibility so that - developers are able to handle the less common cases not covered by - the convenience functions. - - .. seealso:: :class:`subprocess.Popen` - This class should have the same interface as the standard library class. - - .. caution:: - - The default values of some arguments, notably ``buffering``, differ - between Python 2 and Python 3. For the most consistent behaviour across - versions, it's best to explicitly pass the desired values. - - .. caution:: - - On Python 2, the ``read`` method of the ``stdout`` and ``stderr`` attributes - will not be buffered unless buffering is explicitly requested (e.g., `bufsize=-1`). - This is different than the ``read`` method of the standard library attributes, - which will buffer internally even if no buffering has been requested. This - matches the Python 3 behaviour. For portability, please explicitly request - buffering if you want ``read(n)`` to return all ``n`` bytes, making more than - one system call if needed. See `issue 1701 `_ - for more context. - - .. versionchanged:: 1.2a1 - Instances can now be used as context managers under Python 2.7. Previously - this was restricted to Python 3. - - .. versionchanged:: 1.2a1 - Instances now save the ``args`` attribute under Python 2.7. Previously this was - restricted to Python 3. - - .. versionchanged:: 1.2b1 - Add the ``encoding`` and ``errors`` parameters for Python 3. - - .. versionchanged:: 1.3a1 - Accept "path-like" objects for the *cwd* parameter on all platforms. - This was added to Python 3.6. Previously with gevent, it only worked - on POSIX platforms on 3.6. - - .. versionchanged:: 1.3a1 - Add the ``text`` argument as a synonym for ``universal_newlines``, - as added on Python 3.7. - - .. versionchanged:: 1.3a2 - Allow the same keyword arguments under Python 2 as Python 3: - ``pass_fds``, ``start_new_session``, ``restore_signals``, ``encoding`` - and ``errors``. Under Python 2, ``encoding`` and ``errors`` are ignored - because native handling of universal newlines is used. - - .. versionchanged:: 1.3a2 - Under Python 2, ``restore_signals`` defaults to ``False``. Previously it - defaulted to ``True``, the same as it did in Python 3. - - .. versionchanged:: 20.6.0 - Add the *group*, *extra_groups*, *user*, and *umask* arguments. These - were added to Python 3.9, but are available in any gevent version, provided - the underlying platform support is present. - - .. versionchanged:: 20.12.0 - On Python 2 only, if unbuffered binary communication is requested, - the ``stdin`` attribute of this object will have a ``write`` method that - actually performs internal buffering and looping, similar to the standard library. - It guarantees to write all the data given to it in a single call (but internally - it may make many system calls and/or trips around the event loop to accomplish this). - See :issue:`1711`. - - .. versionchanged:: 21.12.0 - Added the ``pipesize`` argument for compatibility with Python 3.10. - This is ignored on all platforms. - - .. versionchanged:: 22.08.0 - Added the ``process_group`` and ``check`` arguments for compatibility with - Python 3.11. - - .. versionchanged:: 24.10.1 - To match Python 3.13, ``stdout=STDOUT`` now raises a :exc:`ValueError`. - """ - - if GenericAlias is not None: - # 3.9, annoying typing is creeping everywhere. - __class_getitem__ = classmethod(GenericAlias) - - # The value returned from communicate() when there was nothing to read. - # Changes if we're in text mode or universal newlines mode. - _communicate_empty_value = b'' - - # pylint:disable-next=too-many-positional-arguments - def __init__(self, args, - bufsize=-1, - executable=None, - stdin=None, stdout=None, stderr=None, - preexec_fn=None, close_fds=_PLATFORM_DEFAULT_CLOSE_FDS, shell=False, - cwd=None, env=None, universal_newlines=None, - startupinfo=None, creationflags=0, - restore_signals=True, start_new_session=False, - pass_fds=(), - # Added in 3.6. These are kept as ivars - encoding=None, errors=None, - # Added in 3.7. Not an ivar directly. - text=None, - # Added in 3.9 - group=None, extra_groups=None, user=None, - umask=-1, - # Added in 3.10, but ignored. - pipesize=-1, - # Added in 3.11 - process_group=None, - # gevent additions - threadpool=None): - - self.encoding = encoding - self.errors = errors - - hub = get_hub() - - if bufsize is None: - # Python 2 doesn't allow None at all, but Python 3 treats - # it the same as the default. We do as well. - bufsize = -1 - if not isinstance(bufsize, integer_types): - raise TypeError("bufsize must be an integer") - - if stdout is STDOUT: - raise ValueError("STDOUT can only be used for stderr") - - if mswindows: - if preexec_fn is not None: - raise ValueError("preexec_fn is not supported on Windows " - "platforms") - - if close_fds is _PLATFORM_DEFAULT_CLOSE_FDS: - close_fds = True - - if threadpool is None: - threadpool = hub.threadpool - self.threadpool = threadpool - self._waiting = False - else: - # POSIX - if close_fds is _PLATFORM_DEFAULT_CLOSE_FDS: - # close_fds has different defaults on Py3/Py2 - close_fds = True - - if pass_fds and not close_fds: - import warnings - warnings.warn("pass_fds overriding close_fds.", RuntimeWarning) - close_fds = True - if startupinfo is not None: - raise ValueError("startupinfo is only supported on Windows " - "platforms") - if creationflags != 0: - raise ValueError("creationflags is only supported on Windows " - "platforms") - assert threadpool is None - self._loop = hub.loop - - # Validate the combinations of text and universal_newlines - if (text is not None and universal_newlines is not None - and bool(universal_newlines) != bool(text)): - # pylint:disable=undefined-variable - raise SubprocessError('Cannot disambiguate when both text ' - 'and universal_newlines are supplied but ' - 'different. Pass one or the other.') - - self.args = args # Previously this was Py3 only. - self.stdin = None - self.stdout = None - self.stderr = None - self.pid = None - self.returncode = None - self.universal_newlines = universal_newlines - self.result = AsyncResult() - - # Input and output objects. The general principle is like - # this: - # - # Parent Child - # ------ ----- - # p2cwrite ---stdin---> p2cread - # c2pread <--stdout--- c2pwrite - # errread <--stderr--- errwrite - # - # On POSIX, the child objects are file descriptors. On - # Windows, these are Windows file handles. The parent objects - # are file descriptors on both platforms. The parent objects - # are -1 when not using PIPEs. The child objects are -1 - # when not redirecting. - - (p2cread, p2cwrite, - c2pread, c2pwrite, - errread, errwrite) = self._get_handles(stdin, stdout, stderr) - - # We wrap OS handles *before* launching the child, otherwise a - # quickly terminating child could make our fds unwrappable - # (see #8458). - if mswindows: - if p2cwrite != -1: - p2cwrite = msvcrt.open_osfhandle(p2cwrite.Detach(), 0) - if c2pread != -1: - c2pread = msvcrt.open_osfhandle(c2pread.Detach(), 0) - if errread != -1: - errread = msvcrt.open_osfhandle(errread.Detach(), 0) - - text_mode = self.encoding or self.errors or universal_newlines or text - if text_mode or universal_newlines: - # Always a native str in universal_newlines mode, even when that - # str type is bytes. Additionally, text_mode is only true under - # Python 3, so it's actually a unicode str - self._communicate_empty_value = '' - - uid, gid, gids = self.__handle_uids(user, group, extra_groups) - - if p2cwrite != -1: - if text_mode: - # Under Python 3, if we left on the 'b' we'd get different results - # depending on whether we used FileObjectPosix or FileObjectThread - self.stdin = FileObject(p2cwrite, 'w', bufsize, - encoding=self.encoding, errors=self.errors) - else: - self.stdin = FileObject(p2cwrite, 'wb', bufsize) - - if c2pread != -1: - if universal_newlines or text_mode: - self.stdout = FileObject(c2pread, 'r', bufsize, - encoding=self.encoding, errors=self.errors) - # NOTE: Universal Newlines are broken on Windows/Py3, at least - # in some cases. This is true in the stdlib subprocess module - # as well; the following line would fix the test cases in - # test__subprocess.py that depend on python_universal_newlines, - # but would be inconsistent with the stdlib: - - else: - self.stdout = FileObject(c2pread, 'rb', bufsize) - if errread != -1: - if universal_newlines or text_mode: - self.stderr = FileObject(errread, 'r', bufsize, - encoding=encoding, errors=errors) - else: - self.stderr = FileObject(errread, 'rb', bufsize) - - self._closed_child_pipe_fds = False - # Convert here for the sake of all platforms. os.chdir accepts - # path-like objects natively under 3.6, but CreateProcess - # doesn't. - cwd = fsdecode(cwd) if cwd is not None else None - try: - self._execute_child(args, executable, preexec_fn, close_fds, - pass_fds, cwd, env, universal_newlines, - startupinfo, creationflags, shell, - p2cread, p2cwrite, - c2pread, c2pwrite, - errread, errwrite, - restore_signals, - gid, gids, uid, umask, - start_new_session, process_group) - except: - # Cleanup if the child failed starting. - # (gevent: New in python3, but reported as gevent bug in #347. - # Note that under Py2, any error raised below will replace the - # original error so we have to use reraise) - for f in filter(None, (self.stdin, self.stdout, self.stderr)): - try: - f.close() - except OSError: - pass # Ignore EBADF or other errors. - - if not self._closed_child_pipe_fds: - to_close = [] - if stdin == PIPE: - to_close.append(p2cread) - if stdout == PIPE: - to_close.append(c2pwrite) - if stderr == PIPE: - to_close.append(errwrite) - if hasattr(self, '_devnull'): - to_close.append(self._devnull) - for fd in to_close: - try: - os_close(fd) - except OSError: - pass - raise - - def __handle_uids(self, user, group, extra_groups): - gid = None - if group is not None: - if not hasattr(os, 'setregid'): - raise ValueError("The 'group' parameter is not supported on the " - "current platform") - - if isinstance(group, str): - if grp is None: - raise ValueError("The group parameter cannot be a string " - "on systems without the grp module") - - gid = grp.getgrnam(group).gr_gid - elif isinstance(group, int): - gid = group - else: - raise TypeError("Group must be a string or an integer, not {}" - .format(type(group))) - - if gid < 0: - raise ValueError("Group ID cannot be negative, got %s" % gid) - - gids = None - if extra_groups is not None: - if not hasattr(os, 'setgroups'): - raise ValueError("The 'extra_groups' parameter is not " - "supported on the current platform") - - if isinstance(extra_groups, str): - raise ValueError("Groups must be a list, not a string") - - gids = [] - for extra_group in extra_groups: - if isinstance(extra_group, str): - if grp is None: - raise ValueError("Items in extra_groups cannot be " - "strings on systems without the " - "grp module") - - gids.append(grp.getgrnam(extra_group).gr_gid) - elif isinstance(extra_group, int): - if extra_group >= 2**64: - # This check is implicit in the C version of _Py_Gid_Converter. - # - # We actually need access to the C type ``gid_t`` to get - # its actual length. This just makes the test that was added - # for the bug pass. That's OK though, if we guess too big here, - # we should get an OverflowError from the setgroups() - # call we make. The only difference is the type of exception. - # - # See https://bugs.python.org/issue42655 - raise ValueError("Item in extra_groups is too large") - gids.append(extra_group) - else: - raise TypeError("Items in extra_groups must be a string " - "or integer, not {}" - .format(type(extra_group))) - - # make sure that the gids are all positive here so we can do less - # checking in the C code - for gid_check in gids: - if gid_check < 0: - raise ValueError("Group ID cannot be negative, got %s" % (gid_check,)) - - uid = None - if user is not None: - if not hasattr(os, 'setreuid'): - raise ValueError("The 'user' parameter is not supported on " - "the current platform") - - if isinstance(user, str): - if pwd is None: - raise ValueError("The user parameter cannot be a string " - "on systems without the pwd module") - - uid = pwd.getpwnam(user).pw_uid - elif isinstance(user, int): - uid = user - else: - raise TypeError("User must be a string or an integer") - - if uid < 0: - raise ValueError("User ID cannot be negative, got %s" % (uid,)) - - return uid, gid, gids - - def __repr__(self): - return '<%s at 0x%x pid=%r returncode=%r>' % (self.__class__.__name__, id(self), self.pid, self.returncode) - - def _on_child(self, watcher): - watcher.stop() - status = watcher.rstatus - if os.WIFSIGNALED(status): - self.returncode = -os.WTERMSIG(status) - else: - self.returncode = os.WEXITSTATUS(status) - self.result.set(self.returncode) - - def _get_devnull(self): - if not hasattr(self, '_devnull'): - self._devnull = os.open(os.devnull, os.O_RDWR) - return self._devnull - - _communicating_greenlets = None - - def communicate(self, input=None, timeout=None): - """ - Interact with process and return its output and error. - - - Send *input* data to stdin. - - Read data from stdout and stderr, until end-of-file is reached. - - Wait for process to terminate. - - The optional *input* argument should be a - string to be sent to the child process, or None, if no data - should be sent to the child. - - communicate() returns a tuple (stdout, stderr). - - :keyword timeout: Under Python 2, this is a gevent extension; if - given and it expires, we will raise :exc:`TimeoutExpired`, which - extends :exc:`gevent.timeout.Timeout` (note that this only extends :exc:`BaseException`, - *not* :exc:`Exception`) - Under Python 3, this raises the standard :exc:`TimeoutExpired` exception. - - .. versionchanged:: 1.1a2 - Under Python 2, if the *timeout* elapses, raise the :exc:`gevent.timeout.Timeout` - exception. Previously, we silently returned. - .. versionchanged:: 1.1b5 - Honor a *timeout* even if there's no way to communicate with the child - (stdin, stdout, and stderr are not pipes). - """ - if self._communicating_greenlets is None: - self._communicating_greenlets = _CommunicatingGreenlets(self, input) - greenlets = self._communicating_greenlets - - # If we were given stdin=stdout=stderr=None, we have no way to - # communicate with the child, and thus no greenlets to wait - # on. This is a nonsense case, but it comes up in the test - # case for Python 3.5 (test_subprocess.py - # RunFuncTestCase.test_timeout). Instead, we go directly to - # self.wait - if not greenlets and timeout is not None: - self.wait(timeout=timeout, _raise_exc=True) - - done = joinall(greenlets, timeout=timeout) - # Allow finished greenlets, if any, to raise. This takes priority over - # the timeout exception. - for greenlet in done: - greenlet.get() - if timeout is not None and len(done) != len(self._communicating_greenlets): - raise TimeoutExpired(self.args, timeout) - - # Close only after we're sure that everything is done - # (there was no timeout, or there was, but everything finished). - # There should be no greenlets still running, even from a prior - # attempt. If there are, then this can raise RuntimeError: 'reentrant call'. - # So we ensure that previous greenlets are dead. - for pipe in (self.stdout, self.stderr): - if pipe: - try: - pipe.close() - except RuntimeError: - pass - - self.wait() - - return (None if greenlets.stdout is None else greenlets.stdout.get(), - None if greenlets.stderr is None else greenlets.stderr.get()) - - def poll(self): - """Check if child process has terminated. Set and return :attr:`returncode` attribute.""" - return self._internal_poll() - - def __enter__(self): - return self - - def __exit__(self, t, v, tb): - if self.stdout: - self.stdout.close() - if self.stderr: - self.stderr.close() - try: # Flushing a BufferedWriter may raise an error - if self.stdin: - self.stdin.close() - finally: - # Wait for the process to terminate, to avoid zombies. - # JAM: gevent: If the process never terminates, this - # blocks forever. - self.wait() - - def _gevent_result_wait(self, timeout=None, raise_exc=True): - result = self.result.wait(timeout=timeout) - if raise_exc and timeout is not None and not self.result.ready(): - raise TimeoutExpired(self.args, timeout) - return result - - - if mswindows: - # - # Windows methods - # - def _get_handles(self, stdin, stdout, stderr): - """Construct and return tuple with IO objects: - p2cread, p2cwrite, c2pread, c2pwrite, errread, errwrite - """ - # pylint:disable=undefined-variable - if stdin is None and stdout is None and stderr is None: - return (-1, -1, -1, -1, -1, -1) - - p2cread, p2cwrite = -1, -1 - c2pread, c2pwrite = -1, -1 - errread, errwrite = -1, -1 - - try: - DEVNULL - except NameError: - _devnull = object() - else: - _devnull = DEVNULL - - if stdin is None: - p2cread = GetStdHandle(STD_INPUT_HANDLE) - if p2cread is None: - p2cread, _ = CreatePipe(None, 0) - p2cread = Handle(p2cread) - _winapi.CloseHandle(_) - elif stdin == PIPE: - p2cread, p2cwrite = CreatePipe(None, 0) - p2cread, p2cwrite = Handle(p2cread), Handle(p2cwrite) - elif stdin == _devnull: - p2cread = msvcrt.get_osfhandle(self._get_devnull()) - elif isinstance(stdin, int): - p2cread = msvcrt.get_osfhandle(stdin) - else: - # Assuming file-like object - p2cread = msvcrt.get_osfhandle(stdin.fileno()) - p2cread = self._make_inheritable(p2cread) - - if stdout is None: - c2pwrite = GetStdHandle(STD_OUTPUT_HANDLE) - if c2pwrite is None: - _, c2pwrite = CreatePipe(None, 0) - c2pwrite = Handle(c2pwrite) - _winapi.CloseHandle(_) - elif stdout == PIPE: - c2pread, c2pwrite = CreatePipe(None, 0) - c2pread, c2pwrite = Handle(c2pread), Handle(c2pwrite) - elif stdout == _devnull: - c2pwrite = msvcrt.get_osfhandle(self._get_devnull()) - elif isinstance(stdout, int): - c2pwrite = msvcrt.get_osfhandle(stdout) - else: - # Assuming file-like object - c2pwrite = msvcrt.get_osfhandle(stdout.fileno()) - c2pwrite = self._make_inheritable(c2pwrite) - - if stderr is None: - errwrite = GetStdHandle(STD_ERROR_HANDLE) - if errwrite is None: - _, errwrite = CreatePipe(None, 0) - errwrite = Handle(errwrite) - _winapi.CloseHandle(_) - elif stderr == PIPE: - errread, errwrite = CreatePipe(None, 0) - errread, errwrite = Handle(errread), Handle(errwrite) - elif stderr == STDOUT: - errwrite = c2pwrite - elif stderr == _devnull: - errwrite = msvcrt.get_osfhandle(self._get_devnull()) - elif isinstance(stderr, int): - errwrite = msvcrt.get_osfhandle(stderr) - else: - # Assuming file-like object - errwrite = msvcrt.get_osfhandle(stderr.fileno()) - errwrite = self._make_inheritable(errwrite) - - return (p2cread, p2cwrite, - c2pread, c2pwrite, - errread, errwrite) - - def _make_inheritable(self, handle): - """Return a duplicate of handle, which is inheritable""" - # pylint:disable=undefined-variable - return DuplicateHandle(GetCurrentProcess(), - handle, GetCurrentProcess(), 0, 1, - DUPLICATE_SAME_ACCESS) - - def _find_w9xpopen(self): - """Find and return absolute path to w9xpopen.exe""" - # pylint:disable=undefined-variable - w9xpopen = os.path.join(os.path.dirname(GetModuleFileName(0)), - "w9xpopen.exe") - if not os.path.exists(w9xpopen): - # Eeek - file-not-found - possibly an embedding - # situation - see if we can locate it in sys.exec_prefix - w9xpopen = os.path.join(os.path.dirname(sys.exec_prefix), - "w9xpopen.exe") - if not os.path.exists(w9xpopen): - raise RuntimeError("Cannot locate w9xpopen.exe, which is " - "needed for Popen to work with your " - "shell or platform.") - return w9xpopen - - - def _filter_handle_list(self, handle_list): - """Filter out console handles that can't be used - in lpAttributeList["handle_list"] and make sure the list - isn't empty. This also removes duplicate handles.""" - # An handle with it's lowest two bits set might be a special console - # handle that if passed in lpAttributeList["handle_list"], will - # cause it to fail. - # Only works on 3.7+ - return list({handle for handle in handle_list - if handle & 0x3 != 0x3 - or _winapi.GetFileType(handle) != - _winapi.FILE_TYPE_CHAR}) - - - def _execute_child(self, args, executable, preexec_fn, close_fds, - pass_fds, cwd, env, universal_newlines, - startupinfo, creationflags, shell, - p2cread, p2cwrite, - c2pread, c2pwrite, - errread, errwrite, - unused_restore_signals, - unused_gid, unused_gids, unused_uid, unused_umask, - unused_start_new_session, unused_process_group): - """Execute program (MS Windows version)""" - # pylint:disable=undefined-variable - assert not pass_fds, "pass_fds not supported on Windows." - if isinstance(args, str): - pass - elif isinstance(args, bytes): - if shell: - raise TypeError('bytes args is not allowed on Windows') - args = list2cmdline([args]) - elif isinstance(args, PathLike): - if shell: - raise TypeError('path-like args is not allowed when ' - 'shell is true') - args = list2cmdline([args]) - else: - args = list2cmdline(args) - - if executable is not None: - executable = fsdecode(executable) - - if not isinstance(args, string_types): - args = list2cmdline(args) - - # Process startup details - if startupinfo is None: - startupinfo = STARTUPINFO() - elif hasattr(startupinfo, 'copy'): - # bpo-34044: Copy STARTUPINFO since it is modified below, - # so the caller can reuse it multiple times. - startupinfo = startupinfo.copy() - elif hasattr(startupinfo, '_copy'): - # When the fix was backported to Python 3.7, copy() was - # made private as _copy. - startupinfo = startupinfo._copy() - - use_std_handles = -1 not in (p2cread, c2pwrite, errwrite) - if use_std_handles: - startupinfo.dwFlags |= STARTF_USESTDHANDLES - startupinfo.hStdInput = p2cread - startupinfo.hStdOutput = c2pwrite - startupinfo.hStdError = errwrite - - if hasattr(startupinfo, 'lpAttributeList'): - # Support for Python >= 3.7 - - attribute_list = startupinfo.lpAttributeList - have_handle_list = bool(attribute_list and - "handle_list" in attribute_list and - attribute_list["handle_list"]) - - # If we were given an handle_list or need to create one - if have_handle_list or (use_std_handles and close_fds): - if attribute_list is None: - attribute_list = startupinfo.lpAttributeList = {} - handle_list = attribute_list["handle_list"] = \ - list(attribute_list.get("handle_list", [])) - - if use_std_handles: - handle_list += [int(p2cread), int(c2pwrite), int(errwrite)] - - handle_list[:] = self._filter_handle_list(handle_list) - - if handle_list: - if not close_fds: - import warnings - warnings.warn("startupinfo.lpAttributeList['handle_list'] " - "overriding close_fds", RuntimeWarning) - - # When using the handle_list we always request to inherit - # handles but the only handles that will be inherited are - # the ones in the handle_list - close_fds = False - - if shell: - startupinfo.dwFlags |= STARTF_USESHOWWINDOW - startupinfo.wShowWindow = SW_HIDE - comspec = os.environ.get("COMSPEC", "cmd.exe") - args = '{} /c "{}"'.format(comspec, args) - if GetVersion() >= 0x80000000 or os.path.basename(comspec).lower() == "command.com": - # Win9x, or using command.com on NT. We need to - # use the w9xpopen intermediate program. For more - # information, see KB Q150956 - # (http://web.archive.org/web/20011105084002/http://support.microsoft.com/support/kb/articles/Q150/9/56.asp) - w9xpopen = self._find_w9xpopen() - args = '"%s" %s' % (w9xpopen, args) - # Not passing CREATE_NEW_CONSOLE has been known to - # cause random failures on win9x. Specifically a - # dialog: "Your program accessed mem currently in - # use at xxx" and a hopeful warning about the - # stability of your system. Cost is Ctrl+C wont - # kill children. - creationflags |= CREATE_NEW_CONSOLE - - # PyPy 2.7 7.3.6 is now producing these errors. This - # happens automatically on Posix platforms, and is built - # in to the CreateProcess call on CPython 2 & 3. It's not - # clear why we don't pick it up for free from the - # CreateProcess call on PyPy. Currently we don't test PyPy3 on Windows, - # so we don't know for sure if it's built into CreateProcess there. - if PYPY: - def _check_nul(s, err_kind=ValueError): - if not s: - return - nul = b'\0' if isinstance(s, bytes) else '\0' - if nul in s: - # PyPy 2 expects a TypeError; Python 3 raises ValueError always. - raise err_kind("argument must be a string without NUL characters") - def _check_env(): - if not env: - return - for k, v in env.items(): - _check_nul(k) - _check_nul(v) - if '=' in k: - raise ValueError("'=' not allowed in environment keys") - - _check_nul(executable) - _check_nul(args) - _check_env() - - # Start the process - try: - hp, ht, pid, tid = CreateProcess(executable, args, - # no special security - None, None, - int(not close_fds), - creationflags, - env, - cwd, # fsdecode handled earlier - startupinfo) - # except IOError as e: # From 2.6 on, pywintypes.error was defined as IOError - # # Translate pywintypes.error to WindowsError, which is - # # a subclass of OSError. FIXME: We should really - # # translate errno using _sys_errlist (or similar), but - # # how can this be done from Python? - # raise # don't remap here - # raise WindowsError(*e.args) - finally: - # Child is launched. Close the parent's copy of those pipe - # handles that only the child should have open. You need - # to make sure that no handles to the write end of the - # output pipe are maintained in this process or else the - # pipe will not close when the child process exits and the - # ReadFile will hang. - def _close(x): - if x is not None and x != -1: - if hasattr(x, 'Close'): - x.Close() - else: - _winapi.CloseHandle(x) - - _close(p2cread) - _close(c2pwrite) - _close(errwrite) - if hasattr(self, '_devnull'): - os_close(self._devnull) - - # Retain the process handle, but close the thread handle - self._child_created = True - self._handle = Handle(hp) if not hasattr(hp, 'Close') else hp - self.pid = pid - _winapi.CloseHandle(ht) if not hasattr(ht, 'Close') else ht.Close() - - def _internal_poll(self): - """Check if child process has terminated. Returns returncode - attribute. - """ - # pylint:disable=undefined-variable - if self.returncode is None: - if WaitForSingleObject(self._handle, 0) == WAIT_OBJECT_0: - self.returncode = GetExitCodeProcess(self._handle) - self.result.set(self.returncode) - return self.returncode - - def rawlink(self, callback): - if not self.result.ready() and not self._waiting: - self._waiting = True - Greenlet.spawn(self._wait) - self.result.rawlink(linkproxy(callback, self)) - # XXX unlink - - def _blocking_wait(self): - # pylint:disable=undefined-variable - WaitForSingleObject(self._handle, INFINITE) - self.returncode = GetExitCodeProcess(self._handle) - return self.returncode - - def _wait(self): - self.threadpool.spawn(self._blocking_wait).rawlink(self.result) - - def wait(self, timeout=None, _raise_exc=True): - """Wait for child process to terminate. Returns returncode - attribute.""" - if self.returncode is None: - if not self._waiting: - self._waiting = True - self._wait() - return self._gevent_result_wait(timeout, _raise_exc) - - def send_signal(self, sig): - """Send a signal to the process - """ - if sig == signal.SIGTERM: - self.terminate() - elif sig == signal.CTRL_C_EVENT: - os.kill(self.pid, signal.CTRL_C_EVENT) - elif sig == signal.CTRL_BREAK_EVENT: - os.kill(self.pid, signal.CTRL_BREAK_EVENT) - else: - raise ValueError("Unsupported signal: {}".format(sig)) - - def terminate(self): - """Terminates the process - """ - # pylint:disable=undefined-variable - # Don't terminate a process that we know has already died. - if self.returncode is not None: - return - try: - TerminateProcess(self._handle, 1) - except OSError as e: - # ERROR_ACCESS_DENIED (winerror 5) is received when the - # process already died. - if e.winerror != 5: - raise - rc = GetExitCodeProcess(self._handle) - if rc == STILL_ACTIVE: - raise - self.returncode = rc - self.result.set(self.returncode) - - kill = terminate - - else: - # - # POSIX methods - # - - def rawlink(self, callback): - # Not public documented, part of the link protocol - self.result.rawlink(linkproxy(callback, self)) - # XXX unlink - - def _get_handles(self, stdin, stdout, stderr): - """Construct and return tuple with IO objects: - p2cread, p2cwrite, c2pread, c2pwrite, errread, errwrite - """ - p2cread, p2cwrite = -1, -1 - c2pread, c2pwrite = -1, -1 - errread, errwrite = -1, -1 - - try: - DEVNULL - except NameError: - _devnull = object() - else: - _devnull = DEVNULL - - if stdin is None: - pass - elif stdin == PIPE: - p2cread, p2cwrite = self.pipe_cloexec() - elif stdin == _devnull: - p2cread = self._get_devnull() - elif isinstance(stdin, int): - p2cread = stdin - else: - # Assuming file-like object - p2cread = stdin.fileno() - - if stdout is None: - pass - elif stdout == PIPE: - c2pread, c2pwrite = self.pipe_cloexec() - elif stdout == _devnull: - c2pwrite = self._get_devnull() - elif isinstance(stdout, int): - c2pwrite = stdout - else: - # Assuming file-like object - c2pwrite = stdout.fileno() - - if stderr is None: - pass - elif stderr == PIPE: - errread, errwrite = self.pipe_cloexec() - elif stderr == STDOUT: # pylint:disable=undefined-variable - if c2pwrite != -1: - errwrite = c2pwrite - else: # child's stdout is not set, use parent's stdout - errwrite = sys.__stdout__.fileno() - elif stderr == _devnull: - errwrite = self._get_devnull() - elif isinstance(stderr, int): - errwrite = stderr - else: - # Assuming file-like object - errwrite = stderr.fileno() - - return (p2cread, p2cwrite, - c2pread, c2pwrite, - errread, errwrite) - - def _set_cloexec_flag(self, fd, cloexec=True): - try: - cloexec_flag = fcntl.FD_CLOEXEC - except AttributeError: - cloexec_flag = 1 - - old = fcntl.fcntl(fd, fcntl.F_GETFD) - if cloexec: - fcntl.fcntl(fd, fcntl.F_SETFD, old | cloexec_flag) - else: - fcntl.fcntl(fd, fcntl.F_SETFD, old & ~cloexec_flag) - - def _remove_nonblock_flag(self, fd): - flags = fcntl.fcntl(fd, fcntl.F_GETFL) & (~os.O_NONBLOCK) - fcntl.fcntl(fd, fcntl.F_SETFL, flags) - - def pipe_cloexec(self): - """Create a pipe with FDs set CLOEXEC.""" - # Pipes' FDs are set CLOEXEC by default because we don't want them - # to be inherited by other subprocesses: the CLOEXEC flag is removed - # from the child's FDs by _dup2(), between fork() and exec(). - # This is not atomic: we would need the pipe2() syscall for that. - r, w = os.pipe() - self._set_cloexec_flag(r) - self._set_cloexec_flag(w) - return r, w - - _POSSIBLE_FD_DIRS = ( - '/proc/self/fd', # Linux - '/dev/fd', # BSD, including macOS - ) - - @classmethod - def _close_fds(cls, keep, errpipe_write): - # From the C code: - # errpipe_write is part of keep. It must be closed at - # exec(), but kept open in the child process until exec() is - # called. - for path in cls._POSSIBLE_FD_DIRS: - if os.path.isdir(path): - return cls._close_fds_from_path(path, keep, errpipe_write) - return cls._close_fds_brute_force(keep, errpipe_write) - - @classmethod - def _close_fds_from_path(cls, path, keep, errpipe_write): - # path names a directory whose only entries have - # names that are ascii strings of integers in base10, - # corresponding to the fds the current process has open - try: - fds = [int(fname) for fname in os.listdir(path)] - except (ValueError, OSError): - cls._close_fds_brute_force(keep, errpipe_write) - else: - for i in keep: - if i == errpipe_write: - continue - _set_inheritable(i, True) - - for fd in fds: - if fd in keep or fd < 3: - continue - try: - os_close(fd) - except: - pass - - @classmethod - def _close_fds_brute_force(cls, keep, errpipe_write): - # `keep` is a set of fds, so we - # use os.closerange from 3 to min(keep) - # and then from max(keep + 1) to MAXFD and - # loop through filling in the gaps. - - # Under new python versions, we need to explicitly set - # passed fds to be inheritable or they will go away on exec - - # XXX: Bug: We implicitly rely on errpipe_write being the largest open - # FD so that we don't change its cloexec flag. - - assert hasattr(os, 'closerange') # Added in 2.7 - keep = sorted(keep) - min_keep = min(keep) - max_keep = max(keep) - os.closerange(3, min_keep) - os.closerange(max_keep + 1, MAXFD) - - for i in xrange(min_keep, max_keep): - if i in keep: - _set_inheritable(i, True) - continue - - try: - os_close(i) - except: - pass - # pylint:disable-next=too-many-positional-arguments - def _execute_child(self, args, executable, preexec_fn, close_fds, - pass_fds, cwd, env, universal_newlines, - startupinfo, creationflags, shell, - p2cread, p2cwrite, - c2pread, c2pwrite, - errread, errwrite, - restore_signals, - gid, gids, uid, umask, - start_new_session, process_group): - """Execute program (POSIX version)""" - - if isinstance(args, (str, bytes)): - args = [args] - elif isinstance(args, PathLike): - if shell: - raise TypeError('path-like args is not allowed when ' - 'shell is true') - args = [fsencode(args)] # os.PathLike -> [str] - else: - args = list(args) - - if shell: - # On Android the default shell is at '/system/bin/sh'. - unix_shell = ( - '/system/bin/sh' if hasattr(sys, 'getandroidapilevel') else '/bin/sh' - ) - args = [unix_shell, "-c"] + args - if executable: - args[0] = executable - - if executable is None: - executable = args[0] - - self._loop.install_sigchld() - - # For transferring possible exec failure from child to parent - # The first char specifies the exception type: 0 means - # OSError, 1 means some other error. - errpipe_read, errpipe_write = self.pipe_cloexec() - # errpipe_write must not be in the standard io 0, 1, or 2 fd range. - low_fds_to_close = [] - while errpipe_write < 3: - low_fds_to_close.append(errpipe_write) - errpipe_write = os.dup(errpipe_write) - for low_fd in low_fds_to_close: - os_close(low_fd) - try: - try: - gc_was_enabled = gc.isenabled() - # Disable gc to avoid bug where gc -> file_dealloc -> - # write to stderr -> hang. http://bugs.python.org/issue1336 - gc.disable() - try: - self.pid = fork_and_watch(self._on_child, self._loop, True, fork) - except: - if gc_was_enabled: - gc.enable() - raise - if self.pid == 0: - # Child - - # In various places on the child side of things, we catch OSError - # and add attributes to it that detail where in the process we failed; - # like all exceptions until we have exec'd, this exception is pickled - # and sent to the parent to raise in the calling process. - # The parent uses this to decide how to treat that exception, - # adjusting certain information about it as needed. - # - # Python 3.11.8 --- yes, a minor patch release --- stopped - # letting the 'filename' parameter get set in the resulting - # exception for many cases. We're not quite interpreting this - # the same way the stdlib is, I'm sure, but this makes the stdlib - # tests pass. - - # XXX: Technically we're doing a lot of stuff here that - # may not be safe to do before a exec(), depending on the OS. - # CPython 3 goes to great lengths to precompute a lot - # of this info before the fork and pass it all to C functions that - # try hard not to call things like malloc(). (Of course, - # CPython 2 pretty much did what we're doing.) - try: - # Close parent's pipe ends - if p2cwrite != -1: - os_close(p2cwrite) - if c2pread != -1: - os_close(c2pread) - if errread != -1: - os_close(errread) - os_close(errpipe_read) - - # When duping fds, if there arises a situation - # where one of the fds is either 0, 1 or 2, it - # is possible that it is overwritten (#12607). - if c2pwrite == 0: - c2pwrite = os.dup(c2pwrite) - _set_inheritable(c2pwrite, False) - while errwrite in (0, 1): - errwrite = os.dup(errwrite) - _set_inheritable(errwrite, False) - - # Dup fds for child - def _dup2(existing, desired): - # dup2() removes the CLOEXEC flag but - # we must do it ourselves if dup2() - # would be a no-op (issue #10806). - if existing == desired: - self._set_cloexec_flag(existing, False) - elif existing != -1: - os.dup2(existing, desired) - try: - self._remove_nonblock_flag(desired) - except OSError: - # Ignore EBADF, it may not actually be - # open yet. - # Tested beginning in 3.7.0b3 test_subprocess.py - pass - _dup2(p2cread, 0) - _dup2(c2pwrite, 1) - _dup2(errwrite, 2) - - # Close pipe fds. Make sure we don't close the - # same fd more than once, or standard fds. - if not True: - closed = set([None]) - for fd in (p2cread, c2pwrite, errwrite): - if fd not in closed and fd > 2: - os_close(fd) - closed.add(fd) - - # Python 3 (with a working set_inheritable): - # We no longer manually close p2cread, - # c2pwrite, and errwrite here as - # _close_open_fds takes care when it is - # not already non-inheritable. - - if cwd is not None: - try: - os.chdir(cwd) - except OSError as e: - e._failed_chdir = True - raise - - # Python 3.9 - if umask >= 0: - os.umask(umask) - # XXX: CPython does _Py_RestoreSignals here. - # Then setsid() based on ??? - try: - if gids: - os.setgroups(gids) - if gid: - os.setregid(gid, gid) - if uid: - os.setreuid(uid, uid) - if process_group is not None: - os.setpgid(0, process_group) - except OSError as e: - e._failed_chuser = True - raise - - if preexec_fn: - preexec_fn() - - # Close all other fds, if asked for. This must be done - # after preexec_fn runs. - if close_fds: - fds_to_keep = set(pass_fds) - fds_to_keep.add(errpipe_write) - self._close_fds(fds_to_keep, errpipe_write) - - if restore_signals: - # restore the documented signals back to sig_dfl; - # not all will be defined on every platform - for sig in 'SIGPIPE', 'SIGXFZ', 'SIGXFSZ': - sig = getattr(signal, sig, None) - if sig is not None: - signal.signal(sig, signal.SIG_DFL) - - if start_new_session: - os.setsid() - - try: - if env is None: - os.execvp(executable, args) - else: - # Python 3.6 started testing for - # bytes values in the env; it also - # started encoding strs using - # fsencode and using a lower-level - # API that takes a list of keys - # and values. We don't have access - # to that API, so we go the reverse direction. - env = {os.fsdecode(k) if isinstance(k, bytes) else k: - os.fsdecode(v) if isinstance(v, bytes) else v - for k, v in env.items()} - os.execvpe(executable, args, env) - except OSError as e: - e._failed_exec = True - raise - except: - exc_type, exc_value, tb = sys.exc_info() - # Save the traceback and attach it to the exception object - exc_lines = traceback.format_exception(exc_type, - exc_value, - tb) - exc_value.child_traceback = ''.join(exc_lines) - os.write(errpipe_write, pickle.dumps(exc_value)) - - finally: - # Make sure that the process exits no matter what. - # The return code does not matter much as it won't be - # reported to the application - os._exit(1) - - # Parent - self._child_created = True - if gc_was_enabled: - gc.enable() - finally: - # be sure the FD is closed no matter what - os_close(errpipe_write) - - # self._devnull is not always defined. - devnull_fd = getattr(self, '_devnull', None) - if p2cread != -1 and p2cwrite != -1 and p2cread != devnull_fd: - os_close(p2cread) - if c2pwrite != -1 and c2pread != -1 and c2pwrite != devnull_fd: - os_close(c2pwrite) - if errwrite != -1 and errread != -1 and errwrite != devnull_fd: - os_close(errwrite) - if devnull_fd is not None: - os_close(devnull_fd) - # Prevent a double close of these fds from __init__ on error. - self._closed_child_pipe_fds = True - - # Wait for exec to fail or succeed; possibly raising exception - errpipe_read = FileObject(errpipe_read, 'rb') - data = errpipe_read.read() - finally: - try: - if hasattr(errpipe_read, 'close'): - errpipe_read.close() - else: - os_close(errpipe_read) - except OSError: - # Especially on PyPy, we sometimes see the above - # `os_close(errpipe_read)` raise an OSError. - # It's not entirely clear why, but it happens in - # InterprocessSignalTests.test_main sometimes, which must mean - # we have some sort of race condition. - pass - finally: - errpipe_read = -1 - - if data != b"": - self.wait() - child_exception = pickle.loads(data) - for fd in (p2cwrite, c2pread, errread): - if fd is not None and fd != -1: - os_close(fd) - if isinstance(child_exception, OSError): - child_exception.filename = executable - if hasattr(child_exception, '_failed_chdir'): - child_exception.filename = cwd - if getattr(child_exception, '_failed_chuser', False): - child_exception.filename = None - raise child_exception - - def _handle_exitstatus(self, sts, _WIFSIGNALED=os.WIFSIGNALED, - _WTERMSIG=os.WTERMSIG, _WIFEXITED=os.WIFEXITED, - _WEXITSTATUS=os.WEXITSTATUS, _WIFSTOPPED=os.WIFSTOPPED, - _WSTOPSIG=os.WSTOPSIG): - # This method is called (indirectly) by __del__, so it cannot - # refer to anything outside of its local scope. - # (gevent: We don't have a __del__, that's in the CPython implementation.) - if _WIFSIGNALED(sts): - self.returncode = -_WTERMSIG(sts) - elif _WIFEXITED(sts): - self.returncode = _WEXITSTATUS(sts) - elif _WIFSTOPPED(sts): - self.returncode = -_WSTOPSIG(sts) - else: - # Should never happen - raise RuntimeError("Unknown child exit status!") - - def _internal_poll(self): - """Check if child process has terminated. Returns returncode - attribute. - """ - if self.returncode is None: - if get_hub() is not getcurrent(): - sig_pending = getattr(self._loop, 'sig_pending', True) - if sig_pending: - sleep(0.00001) - return self.returncode - - def wait(self, timeout=None, _raise_exc=True): - """ - Wait for child process to terminate. Returns :attr:`returncode` - attribute. - - :keyword timeout: The floating point number of seconds to - wait. Under Python 2, this is a gevent extension, and - we simply return if it expires. Under Python 3, if - this time elapses without finishing the process, - :exc:`TimeoutExpired` is raised. - """ - return self._gevent_result_wait(timeout, _raise_exc) - - def send_signal(self, sig): - """Send a signal to the process - """ - # Skip signalling a process that we know has already died. - if self.returncode is None: - os.kill(self.pid, sig) - - def terminate(self): - """Terminate the process with SIGTERM - """ - self.send_signal(signal.SIGTERM) - - def kill(self): - """Kill the process with SIGKILL - """ - self.send_signal(signal.SIGKILL) - - -def _with_stdout_stderr(exc, stderr): - # Prior to Python 3.5, most exceptions didn't have stdout - # and stderr attributes and can't take the stderr attribute in their - # constructor - exc.stdout = exc.output - exc.stderr = stderr - return exc - -class CompletedProcess(object): - """ - A process that has finished running. - - This is returned by run(). - - Attributes: - - args: The list or str args passed to run(). - - returncode: The exit code of the process, negative for signals. - - stdout: The standard output (None if not captured). - - stderr: The standard error (None if not captured). - - .. versionadded:: 1.2a1 - This first appeared in Python 3.5 and is available to all - Python versions in gevent. - """ - if GenericAlias is not None: - # Sigh, 3.9 spreading typing stuff all over everything - __class_getitem__ = classmethod(GenericAlias) - - def __init__(self, args, returncode, stdout=None, stderr=None): - self.args = args - self.returncode = returncode - self.stdout = stdout - self.stderr = stderr - - def __repr__(self): - args = ['args={!r}'.format(self.args), - 'returncode={!r}'.format(self.returncode)] - if self.stdout is not None: - args.append('stdout={!r}'.format(self.stdout)) - if self.stderr is not None: - args.append('stderr={!r}'.format(self.stderr)) - return "{}({})".format(type(self).__name__, ', '.join(args)) - - def check_returncode(self): - """Raise CalledProcessError if the exit code is non-zero.""" - if self.returncode: - # pylint:disable=undefined-variable - raise _with_stdout_stderr(CalledProcessError(self.returncode, self.args, self.stdout), self.stderr) - - -def run(*popenargs, **kwargs): - """ - run(args, *, stdin=None, input=None, stdout=None, stderr=None, shell=False, timeout=None, check=False) -> CompletedProcess - - Run command with arguments and return a CompletedProcess instance. - - The returned instance will have attributes args, returncode, stdout and - stderr. By default, stdout and stderr are not captured, and those attributes - will be None. Pass stdout=PIPE and/or stderr=PIPE in order to capture them. - If check is True and the exit code was non-zero, it raises a - CalledProcessError. The CalledProcessError object will have the return code - in the returncode attribute, and output & stderr attributes if those streams - were captured. - - If timeout is given, and the process takes too long, a TimeoutExpired - exception will be raised. - - There is an optional argument "input", allowing you to - pass a string to the subprocess's stdin. If you use this argument - you may not also use the Popen constructor's "stdin" argument, as - it will be used internally. - The other arguments are the same as for the Popen constructor. - If universal_newlines=True is passed, the "input" argument must be a - string and stdout/stderr in the returned object will be strings rather than - bytes. - - .. versionadded:: 1.2a1 - This function first appeared in Python 3.5. It is available on all Python - versions gevent supports. - - .. versionchanged:: 1.3a2 - Add the ``capture_output`` argument from Python 3.7. It automatically sets - ``stdout`` and ``stderr`` to ``PIPE``. It is an error to pass either - of those arguments along with ``capture_output``. - """ - input = kwargs.pop('input', None) - timeout = kwargs.pop('timeout', None) - check = kwargs.pop('check', False) - capture_output = kwargs.pop('capture_output', False) - - if input is not None: - if 'stdin' in kwargs: - raise ValueError('stdin and input arguments may not both be used.') - kwargs['stdin'] = PIPE - - if capture_output: - if ('stdout' in kwargs) or ('stderr' in kwargs): - raise ValueError('stdout and stderr arguments may not be used ' - 'with capture_output.') - kwargs['stdout'] = PIPE - kwargs['stderr'] = PIPE - - with Popen(*popenargs, **kwargs) as process: - try: - stdout, stderr = process.communicate(input, timeout=timeout) - except TimeoutExpired: - process.kill() - stdout, stderr = process.communicate() - raise _with_stdout_stderr(TimeoutExpired(process.args, timeout, output=stdout), stderr) - except: - process.kill() - process.wait() - raise - retcode = process.poll() - if check and retcode: - # pylint:disable=undefined-variable - raise _with_stdout_stderr(CalledProcessError(retcode, process.args, stdout), stderr) - - return CompletedProcess(process.args, retcode, stdout, stderr) - -def _gevent_did_monkey_patch(target_module, *_args, **_kwargs): - # This is documented in the docstring for :func:`gevent.monkey.patch_subprocess`. - - if MAC: - # Beginning on 3.8 on Mac, the 'spawn' method became the default - # start method. That doesn't fire fork watchers and we can't - # easily patch to make it do so: multiprocessing uses the private - # c accelerated _subprocess module to implement this. Instead we revert - # back to using fork. - import multiprocessing - if hasattr(multiprocessing, 'set_start_method'): - multiprocessing.set_start_method('fork', force=True) - elif not WIN and PY314: - import multiprocessing - # The default switched to forkserver everywhere except mac and windows. This - # produces stack traces when monkey patched: - # XXX: Why is the socket not blocking correctly? - # File - # "/opt/hostedtoolcache/Python/3.14.0-alpha.7/x64/lib/python3.14/site-packages - # /gevent/tests/test__issue600.py", line 38, in test_process - # p.start() - # ~~~~~~~^^ - # File "///multiprocessing/process.py", line 121, in start - # self._popen = self._Popen(self) - # ~~~~~~~~~~~^^^^^^ - # File "///multiprocessing/context.py", line 224, in _Popen - # return _default_context.get_context().Process._Popen(process_obj) - # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^ - # File "///multiprocessing/context.py", line 300, in _Popen - # return Popen(process_obj) - # File "///multiprocessing/popen_forkserver.py", line 35, in __init__ - # super().__init__(process_obj) - # ~~~~~~~~~~~~~~~~^^^^^^^^^^^^^ - # File "///multiprocessing/popen_fork.py", line 20, in __init__ - # self._launch(process_obj) - # ~~~~~~~~~~~~^^^^^^^^^^^^^ - # File "///multiprocessing/popen_forkserver.py", line 51, in _launch - # self.sentinel, w = forkserver.connect_to_new_process(self._fds) - # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^ - # File "///multiprocessing/forkserver.py", line 106, in connect_to_new_process - # connection.answer_challenge( - # ~~~~~~~~~~~~~~~~~~~~~~~~~~~^ - # wrapped_client, self._forkserver_authkey) - # ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - # File "///multiprocessing/connection.py", line 970, in answer_challenge - # message = connection.recv_bytes(256) # reject large message - # File "///multiprocessing/connection.py", line 222, in recv_bytes - # buf = self._recv_bytes(maxlength) - # File "///multiprocessing/connection.py", line 447, in _recv_bytes - # buf = self._recv(4) - # File "///multiprocessing/connection.py", line 412, in _recv - # chunk = read(handle, to_read) - # BlockingIOError: [Errno 11] Resource temporarily unavailable - multiprocessing.set_start_method('fork', force=True) diff --git a/venv/lib/python3.9/site-packages/gevent/testing/__init__.py b/venv/lib/python3.9/site-packages/gevent/testing/__init__.py deleted file mode 100644 index 6088689..0000000 --- a/venv/lib/python3.9/site-packages/gevent/testing/__init__.py +++ /dev/null @@ -1,182 +0,0 @@ -# Copyright (c) 2008-2009 AG Projects -# Copyright 2018 gevent community -# Author: Denis Bilenko -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. - - -import unittest - -# pylint:disable=unused-import - -# It's important to do this ASAP, because if we're monkey patched, -# then importing things like the standard library test.support can -# need to construct the hub (to check for IPv6 support using a socket). -# We can't do it in the testrunner, as the testrunner spawns new, unrelated -# processes. -from .hub import QuietHub -import gevent.hub -gevent.hub.set_default_hub_class(QuietHub) - -try: - import faulthandler -except ImportError: - # The backport isn't installed. - pass -else: - # Enable faulthandler for stack traces. We have to do this here - # for the same reasons as above. - faulthandler.enable() - -try: - from gevent.libuv import _corecffi -except ImportError: - pass -else: - _corecffi.lib.gevent_test_setup() # pylint:disable=no-member - del _corecffi - -from .sysinfo import VERBOSE -from .sysinfo import WIN -from .sysinfo import LINUX -from .sysinfo import OSX -from .sysinfo import LIBUV -from .sysinfo import CFFI_BACKEND -from .sysinfo import DEBUG -from .sysinfo import RUN_LEAKCHECKS -from .sysinfo import RUN_COVERAGE - -from .sysinfo import PYPY -from .sysinfo import PYPY3 -from .sysinfo import CPYTHON - -from .sysinfo import PLATFORM_SPECIFIC_SUFFIXES -from .sysinfo import NON_APPLICABLE_SUFFIXES -from .sysinfo import SHARED_OBJECT_EXTENSION - -from .sysinfo import RUNNING_ON_TRAVIS -from .sysinfo import RUNNING_ON_APPVEYOR -from .sysinfo import RUNNING_ON_CI -from .sysinfo import RUNNING_ON_MANYLINUX -from .sysinfo import RUNNING_ON_MUSLLINUX -from .sysinfo import RUNNING_ON_GITHUB_ACTIONS - -from .sysinfo import RESOLVER_NOT_SYSTEM -from .sysinfo import RESOLVER_DNSPYTHON -from .sysinfo import RESOLVER_ARES -from .sysinfo import resolver_dnspython_available - -from .sysinfo import EXPECT_POOR_TIMER_RESOLUTION - -from .sysinfo import CONN_ABORTED_ERRORS - -from .skipping import skipOnWindows -from .skipping import skipOnAppVeyor -from .skipping import skipOnCI -from .skipping import skipOnPyPy3OnCI -from .skipping import skipOnPyPy -from .skipping import skipOnPyPyOnCI -from .skipping import skipOnPyPyOnWindows -from .skipping import skipOnPyPy3 -from .skipping import skipIf -from .skipping import skipUnless -from .skipping import skipOnLibev -from .skipping import skipOnLibuv -from .skipping import skipOnLibuvOnWin -from .skipping import skipOnLibuvOnCI -from .skipping import skipOnLibuvOnCIOnPyPy -from .skipping import skipOnLibuvOnPyPyOnWin -from .skipping import skipOnPurePython -from .skipping import skipWithCExtensions -from .skipping import skipOnPy37 -from .skipping import skipOnPy310 -from .skipping import skipOnPy312 -from .skipping import skipOnPy3 -from .skipping import skipWithoutResource -from .skipping import skipWithoutExternalNetwork -from .skipping import skipOnManylinux -from .skipping import skipOnMacOnCI - -from .exception import ExpectedException - - -from .leakcheck import ignores_leakcheck - - -from .params import LARGE_TIMEOUT -from .params import DEFAULT_LOCAL_HOST_ADDR -from .params import DEFAULT_LOCAL_HOST_ADDR6 -from .params import DEFAULT_BIND_ADDR -from .params import DEFAULT_BIND_ADDR_TUPLE -from .params import DEFAULT_CONNECT_HOST - - -from .params import DEFAULT_SOCKET_TIMEOUT -from .params import DEFAULT_XPC_SOCKET_TIMEOUT - -main = unittest.main -SkipTest = unittest.SkipTest - - - - -from .sockets import bind_and_listen -from .sockets import tcp_listener - -from .openfiles import get_number_open_files -from .openfiles import get_open_files - -from .testcase import TestCase - -from .modules import walk_modules - -BaseTestCase = unittest.TestCase - -from .flaky import reraiseFlakyTestTimeout -from .flaky import reraiseFlakyTestRaceCondition -from .flaky import reraises_flaky_timeout -from .flaky import reraises_flaky_race_condition - -def gc_collect_if_needed(): - "Collect garbage if necessary for destructors to run" - import gc - if PYPY: # pragma: no cover - gc.collect() - -# Our usage of mock should be limited to '@mock.patch()' -# and other things that are easily...mocked...here on Python 2 -# when mock is not installed. -try: - from unittest import mock -except ImportError: # Python 2 - try: - import mock - except ImportError: # pragma: no cover - # Backport not installed - class mock(object): - - @staticmethod - def patch(reason): - return unittest.skip(reason) - -mock = mock - - -# zope.interface -from zope.interface import verify diff --git a/venv/lib/python3.9/site-packages/gevent/testing/coveragesite/sitecustomize.py b/venv/lib/python3.9/site-packages/gevent/testing/coveragesite/sitecustomize.py deleted file mode 100644 index edfee10..0000000 --- a/venv/lib/python3.9/site-packages/gevent/testing/coveragesite/sitecustomize.py +++ /dev/null @@ -1,62 +0,0 @@ -# When testrunner.py is invoked with --coverage, it puts this first -# on the path as per https://coverage.readthedocs.io/en/coverage-4.0b3/subprocess.html. -# Note that this disables other sitecustomize.py files. -import os -import coverage -import coverage.exceptions -try: - if not os.environ.get('GEVENT_TEST_SKIP_COVERAGE'): - coverage.process_startup() -except AttributeError as e: - if 'coverage' in str(e) and 'CTracer' in str(e): - # AttributeError: module 'coverage.tracer' has no attribute 'CTracer' - # on github actions. Leads to warnings later: - # "Couldn't import C tracer: module coverage.tracer " - # "does not support loading in subinterpreters (no-ctracer)" - # Seen in test_interpreters.py - # - # HOWEVER: Now coverage also emits a warning (CoverageWarning: Couldn't import C - # tracer: module coverage.tracer does not support loading in subinterpreters - # (no-ctracer)) that gets printed to stderr by default. This is unexpected - # and breaks the test. So we ignore that in testrunner.py - pass - else: - raise -except (coverage.CoverageException, - # As of Coverage 7, the ConfigError seems to be the one raised. - # Not sure when that changed, it used to be CoverageException. Go - # ahead and keep both for safety. - coverage.exceptions.ConfigError, - ) as e: - - if str(e) in ( - "Can't support concurrency=greenlet with PyTracer, only threads are supported", - ): - pass - elif str(e) in ( - # We get this one for the stdlib test_interpreters: greenlet up through at least - # 3.2.0 produces "ImportError: module greenlet._greenlet does not support loading - # in subinterpreters". Now, this is a fairly broad brush with which to try to - # catch that specific case, so we fallback and look for that import error - # as well to make it more specific to exactly this case. - "Couldn't trace with concurrency=greenlet, the module isn't installed.", - ): - ignore = False - try: - __import__('greenlet') - except ImportError as ie: - if str(ie) in ( - "module greenlet._greenlet does not support loading in subinterpreters", - ): - ignore = True - if not ignore: - raise - - else: - import traceback - traceback.print_exc() - raise -except: - import traceback - traceback.print_exc() - raise diff --git a/venv/lib/python3.9/site-packages/gevent/testing/errorhandler.py b/venv/lib/python3.9/site-packages/gevent/testing/errorhandler.py deleted file mode 100644 index 76cbdaa..0000000 --- a/venv/lib/python3.9/site-packages/gevent/testing/errorhandler.py +++ /dev/null @@ -1,57 +0,0 @@ -# Copyright (c) 2018 gevent community -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. -from __future__ import print_function -from functools import wraps - - -def wrap_error_fatal(method): - from gevent._hub_local import get_hub_class - system_error = get_hub_class().SYSTEM_ERROR - - @wraps(method) - def fatal_error_wrapper(self, *args, **kwargs): - # XXX should also be able to do gevent.SYSTEM_ERROR = object - # which is a global default to all hubs - get_hub_class().SYSTEM_ERROR = object - try: - return method(self, *args, **kwargs) - finally: - get_hub_class().SYSTEM_ERROR = system_error - return fatal_error_wrapper - - -def wrap_restore_handle_error(method): - from gevent._hub_local import get_hub_if_exists - from gevent import getcurrent - - @wraps(method) - def restore_fatal_error_wrapper(self, *args, **kwargs): - try: - return method(self, *args, **kwargs) - finally: - # Remove any customized handle_error, if set on the - # instance. - try: - del get_hub_if_exists().handle_error - except AttributeError: - pass - if self.peek_error()[0] is not None: - getcurrent().throw(*self.peek_error()[1:]) - return restore_fatal_error_wrapper diff --git a/venv/lib/python3.9/site-packages/gevent/testing/exception.py b/venv/lib/python3.9/site-packages/gevent/testing/exception.py deleted file mode 100644 index baa9f96..0000000 --- a/venv/lib/python3.9/site-packages/gevent/testing/exception.py +++ /dev/null @@ -1,23 +0,0 @@ -# Copyright (c) 2018 gevent community -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. -from __future__ import absolute_import, print_function, division - -class ExpectedException(Exception): - """An exception whose traceback should be ignored by the hub""" diff --git a/venv/lib/python3.9/site-packages/gevent/testing/flaky.py b/venv/lib/python3.9/site-packages/gevent/testing/flaky.py deleted file mode 100644 index 98f9fe8..0000000 --- a/venv/lib/python3.9/site-packages/gevent/testing/flaky.py +++ /dev/null @@ -1,114 +0,0 @@ -# Copyright (c) 2018 gevent community -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. -from __future__ import absolute_import, print_function, division - -import sys -import functools -import unittest - -from . import sysinfo -from . import six - -class FlakyAssertionError(AssertionError): - "Re-raised so that we know it's a known-flaky test." - -# The next exceptions allow us to raise them in a highly -# greppable way so that we can debug them later. - -class FlakyTest(unittest.SkipTest): - """ - A unittest exception that causes the test to be skipped when raised. - - Use this carefully, it is a code smell and indicates an undebugged problem. - """ - -class FlakyTestRaceCondition(FlakyTest): - """ - Use this when the flaky test is definitely caused by a race condition. - """ - -class FlakyTestTimeout(FlakyTest): - """ - Use this when the flaky test is definitely caused by an - unexpected timeout. - """ - -class FlakyTestCrashes(FlakyTest): - """ - Use this when the test sometimes crashes. - """ - -def reraiseFlakyTestRaceCondition(): - six.reraise(FlakyAssertionError, - FlakyAssertionError(sys.exc_info()[1]), - sys.exc_info()[2]) - -reraiseFlakyTestTimeout = reraiseFlakyTestRaceCondition -reraiseFlakyTestRaceConditionLibuv = reraiseFlakyTestRaceCondition -reraiseFlakyTestTimeoutLibuv = reraiseFlakyTestRaceCondition - -if sysinfo.RUNNING_ON_CI or (sysinfo.PYPY and sysinfo.WIN): - # pylint: disable=function-redefined - def reraiseFlakyTestRaceCondition(): - # Getting stack traces is incredibly expensive - # in pypy on win, at least in test virtual machines. - # It can take minutes. The traceback consistently looks like - # the following when interrupted: - - # dump_stacks -> traceback.format_stack - # -> traceback.extract_stack -> linecache.checkcache - # -> os.stat -> _structseq.structseq_new - - # Moreover, without overriding __repr__ or __str__, - # the msg doesn't get printed like we would want (its basically - # unreadable, all printed on one line). So skip that. - - #msg = '\n'.join(dump_stacks()) - msg = str(sys.exc_info()[1]) - six.reraise(FlakyTestRaceCondition, - FlakyTestRaceCondition(msg), - sys.exc_info()[2]) - - def reraiseFlakyTestTimeout(): - msg = str(sys.exc_info()[1]) - six.reraise(FlakyTestTimeout, - FlakyTestTimeout(msg), - sys.exc_info()[2]) - - if sysinfo.LIBUV: - reraiseFlakyTestRaceConditionLibuv = reraiseFlakyTestRaceCondition - reraiseFlakyTestTimeoutLibuv = reraiseFlakyTestTimeout - - -def reraises_flaky_timeout(exc_kind=AssertionError, _func=reraiseFlakyTestTimeout): - - def wrapper(f): - @functools.wraps(f) - def m(*args): - try: - f(*args) - except exc_kind: - _func() - return m - - return wrapper - -def reraises_flaky_race_condition(exc_kind=AssertionError): - return reraises_flaky_timeout(exc_kind, _func=reraiseFlakyTestRaceCondition) diff --git a/venv/lib/python3.9/site-packages/gevent/testing/hub.py b/venv/lib/python3.9/site-packages/gevent/testing/hub.py deleted file mode 100644 index 09575cb..0000000 --- a/venv/lib/python3.9/site-packages/gevent/testing/hub.py +++ /dev/null @@ -1,70 +0,0 @@ -# Copyright (c) 2018 gevent community -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. -from __future__ import absolute_import, print_function, division - -from contextlib import contextmanager -from gevent.hub import Hub - -from .exception import ExpectedException - -class QuietHub(Hub): - _resolver = None - _threadpool = None - - EXPECTED_TEST_ERROR = (ExpectedException,) - IGNORE_EXPECTED_TEST_ERROR = False - - @contextmanager - def ignoring_expected_test_error(self): - """ - Code in the body of this context manager will ignore - ``EXPECTED_TEST_ERROR`` objects reported to ``handle_error``; - they will not get a chance to go to the hub's parent. - - This completely changes the semantics of normal error handling - by avoiding some switches (to the main greenlet, and eventually - once a callback is processed, back to the hub). This should be used - in narrow ways for test compatibility for tests that assume - ``ExpectedException`` objects behave this way. - """ - old = self.IGNORE_EXPECTED_TEST_ERROR - self.IGNORE_EXPECTED_TEST_ERROR = True - try: - yield - finally: - self.IGNORE_EXPECTED_TEST_ERROR = old - - def handle_error(self, context, type, value, tb): - type, value, tb = self._normalize_exception(type, value, tb) - # If we check that the ``type`` is a subclass of ``EXPECTED_TEST_ERROR``, - # and return, we completely change the semantics: We avoid raising - # this error in the main greenlet, which cuts out several switches. - # Overall, not good. - if self.IGNORE_EXPECTED_TEST_ERROR and issubclass(type, self.EXPECTED_TEST_ERROR): - # Don't pass these up; avoid switches - return - return Hub.handle_error(self, context, type, value, tb) - - def print_exception(self, context, t, v, tb): - t, v, tb = self._normalize_exception(t, v, tb) - if issubclass(t, self.EXPECTED_TEST_ERROR): - # see handle_error - return - return Hub.print_exception(self, context, t, v, tb) diff --git a/venv/lib/python3.9/site-packages/gevent/testing/leakcheck.py b/venv/lib/python3.9/site-packages/gevent/testing/leakcheck.py deleted file mode 100644 index 83ca61a..0000000 --- a/venv/lib/python3.9/site-packages/gevent/testing/leakcheck.py +++ /dev/null @@ -1,238 +0,0 @@ -# Copyright (c) 2018 gevent community -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. - -import sys -import gc -from functools import wraps -import unittest -import warnings - -try: - import objgraph -except ImportError: # pragma: no cover - # Optional test dependency - objgraph = None - -import gevent -import gevent.core - - -def ignores_leakcheck(func): - """ - Ignore the given object during leakchecks. - - Can be applied to a method, in which case the method will run, but - will not be subject to leak checks. - - If applied to a class, the entire class will be skipped during leakchecks. This - is intended to be used for classes that are very slow and cause problems such as - test timeouts; typically it will be used for classes that are subclasses of a base - class and specify variants of behaviour (such as pool sizes). - """ - func.ignore_leakcheck = True - return func - -class _RefCountChecker(object): - - # Some builtin things that we ignore. - # For awhile, we also ignored types.FrameType and types.TracebackType, - # but those are important and often involved in leaks. - IGNORED_TYPES = (tuple, dict,) - try: - CALLBACK_KIND = gevent.core.callback - except AttributeError: - # Must be using FFI. - from gevent._ffi.callback import callback as CALLBACK_KIND - - - def __init__(self, testcase, function): - self.testcase = testcase - self.function = function - self.deltas = [] - self.peak_stats = {} - - # The very first time we are called, we have already been - # self.setUp() by the test runner, so we don't need to do it again. - self.needs_setUp = False - - def _ignore_object_p(self, obj): - if obj is self: - return False - try: - # Certain badly written __eq__ and __contains__ methods - # (I'm looking at you, Python 3.10 importlib.metadata._text! - # ``__eq__(self, other): return self.lower() == other.lower()``) - # raise AttributeError which propagates here, and must be caught. - # Similarly, we can get a TypeError. And abc.SignalDict can raise ValueError. - # - # 3.14 started emitting internal deprecation warnings that we - # can't do anything about: DeprecationWarning: - # '_UnionGenericAlias' is deprecated and slated for removal in - # Python 3.17 - with warnings.catch_warnings(): - warnings.simplefilter('ignore', DeprecationWarning) - if ( - obj in self.__dict__.values() - or obj == self._ignore_object_p # pylint:disable=comparison-with-callable - ): - return False - except (AttributeError, TypeError, ValueError): - # `obj` is things like that _text class. Also have seen - # - psycopg2._psycopg.type - # - relstorage.adapters.drivers._ClassDriverFactory - return True - - - kind = type(obj) - if kind in self.IGNORED_TYPES: - return False - if kind is self.CALLBACK_KIND and obj.callback is None and obj.args is None: - # these represent callbacks that have been stopped, but - # the event loop hasn't cycled around to run them. The only - # known cause of this is killing greenlets before they get a chance - # to run for the first time. - return False - return True - - def _growth(self): - return objgraph.growth(limit=None, peak_stats=self.peak_stats, filter=self._ignore_object_p) - - def _report_diff(self, growth): - if not growth: - return "" - - lines = [] - width = max(len(name) for name, _, _ in growth) - for name, count, delta in growth: - lines.append('%-*s%9d %+9d' % (width, name, count, delta)) - - diff = '\n'.join(lines) - return diff - - - def _run_test(self, args, kwargs): - gc_enabled = gc.isenabled() - gc.disable() - - if self.needs_setUp: - self.testcase.setUp() - self.testcase.skipTearDown = False - try: - self.function(self.testcase, *args, **kwargs) - finally: - self.testcase.tearDown() - self.testcase.doCleanups() - self.testcase.skipTearDown = True - self.needs_setUp = True - if gc_enabled: - gc.enable() - - def _growth_after(self): - # Grab post snapshot - if 'urlparse' in sys.modules: - sys.modules['urlparse'].clear_cache() - if 'urllib.parse' in sys.modules: - sys.modules['urllib.parse'].clear_cache() # pylint:disable=no-member - - return self._growth() - - def _check_deltas(self, growth): - # Return false when we have decided there is no leak, - # true if we should keep looping, raises an assertion - # if we have decided there is a leak. - - deltas = self.deltas - if not deltas: - # We haven't run yet, no data, keep looping - return True - - if gc.garbage: - raise AssertionError("Generated uncollectable garbage %r" % (gc.garbage,)) - - - # the following configurations are classified as "no leak" - # [0, 0] - # [x, 0, 0] - # [... a, b, c, d] where a+b+c+d = 0 - # - # the following configurations are classified as "leak" - # [... z, z, z] where z > 0 - - if deltas[-2:] == [0, 0] and len(deltas) in (2, 3): - return False - - if deltas[-3:] == [0, 0, 0]: - return False - - if len(deltas) >= 4 and sum(deltas[-4:]) == 0: - return False - - if len(deltas) >= 3 and deltas[-1] > 0 and deltas[-1] == deltas[-2] and deltas[-2] == deltas[-3]: - diff = self._report_diff(growth) - raise AssertionError('refcount increased by %r\n%s' % (deltas, diff)) - - # OK, we don't know for sure yet. Let's search for more - if sum(deltas[-3:]) <= 0 or sum(deltas[-4:]) <= 0 or deltas[-4:].count(0) >= 2: - # this is suspicious, so give a few more runs - limit = 11 - else: - limit = 7 - if len(deltas) >= limit: - raise AssertionError('refcount increased by %r\n%s' - % (deltas, - self._report_diff(growth))) - - # We couldn't decide yet, keep going - return True - - def __call__(self, args, kwargs): - for _ in range(3): - gc.collect() - - # Capture state before; the incremental will be - # updated by each call to _growth_after - growth = self._growth() - - while self._check_deltas(growth): - self._run_test(args, kwargs) - - growth = self._growth_after() - - self.deltas.append(sum((stat[2] for stat in growth))) - - -def wrap_refcount(method): - - if objgraph is None or getattr(method, 'ignore_leakcheck', False): - if objgraph is None: - warnings.warn("objgraph not available, leakchecks disabled") - @wraps(method) - def _method_skipped_during_leakcheck(self, *_args, **_kwargs): - self.skipTest("This method ignored during leakchecks") - return _method_skipped_during_leakcheck - - - @wraps(method) - def wrapper(self, *args, **kwargs): # pylint:disable=too-many-branches - if getattr(self, 'ignore_leakcheck', False): - raise unittest.SkipTest("This class ignored during leakchecks") - return _RefCountChecker(self, method)(args, kwargs) - - return wrapper diff --git a/venv/lib/python3.9/site-packages/gevent/testing/modules.py b/venv/lib/python3.9/site-packages/gevent/testing/modules.py deleted file mode 100644 index 7b8549c..0000000 --- a/venv/lib/python3.9/site-packages/gevent/testing/modules.py +++ /dev/null @@ -1,137 +0,0 @@ -# Copyright (c) 2018 gevent community -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. -from __future__ import absolute_import, print_function, division - -import importlib -import os.path -import warnings - -import gevent - -from . import sysinfo -# Avoid importing this at the top level because -# it imports threading and subprocess, and this module -# is always imported in our monkey-patched stdlib unittests, -# and some of them don't like it when those are imported. -# from . import util - - -OPTIONAL_MODULES = frozenset({ - ## Resolvers. - # ares might not be built - 'gevent.resolver_ares', - 'gevent.resolver.ares', - # dnspython might not be installed - 'gevent.resolver.dnspython', - ## Backends - 'gevent.libev', - 'gevent.libev.watcher', - 'gevent.libuv.loop', - 'gevent.libuv.watcher', -}) - -EXCLUDED_MODULES = frozenset({ - '__init__', - 'core', - 'ares', - '_util', - '_semaphore', - 'corecffi', - '_corecffi', - '_corecffi_build', -}) - -def walk_modules( - basedir=None, - modpath=None, - include_so=False, - recursive=False, - check_optional=True, - include_tests=False, - optional_modules=OPTIONAL_MODULES, - excluded_modules=EXCLUDED_MODULES, -): - """ - Find gevent modules, yielding tuples of ``(path, importable_module_name)``. - - :keyword bool check_optional: If true (the default), then if we discover a - module that is known to be optional on this system (such as a backend), - we will attempt to import it; if the import fails, it will not be returned. - If false, then we will not make such an attempt, the caller will need to be prepared - for an `ImportError`; the caller can examine *optional_modules* against - the yielded *importable_module_name*. - """ - # pylint:disable=too-many-branches,too-many-locals - if sysinfo.PYPY: - include_so = False - if basedir is None: - basedir = os.path.dirname(gevent.__file__) - if modpath is None: - modpath = 'gevent.' - else: - if modpath is None: # pylint:disable=else-if-used - modpath = '' - - for fn in sorted(os.listdir(basedir)): - path = os.path.join(basedir, fn) - if os.path.isdir(path): - if not recursive: - continue - if not include_tests and fn in ['testing', 'tests']: - continue - pkg_init = os.path.join(path, '__init__.py') - if os.path.exists(pkg_init): - yield pkg_init, modpath + fn - for p, m in walk_modules( - path, modpath + fn + ".", - include_so=include_so, - recursive=recursive, - check_optional=check_optional, - include_tests=include_tests, - optional_modules=optional_modules, - excluded_modules=excluded_modules, - ): - yield p, m - continue - - if fn.endswith('.py'): - x = fn[:-3] - if x.endswith('_d'): - x = x[:-2] - if x in excluded_modules: - continue - modname = modpath + x - if check_optional and modname in optional_modules: - try: - with warnings.catch_warnings(): - warnings.simplefilter('ignore', DeprecationWarning) - importlib.import_module(modname) - except ImportError: - from . import util - util.debug("Unable to import optional module %s", modname) - continue - yield path, modname - elif include_so and fn.endswith(sysinfo.SHARED_OBJECT_EXTENSION): - if '.pypy-' in fn: - continue - if fn.endswith('_d.so'): - yield path, modpath + fn[:-5] - else: - yield path, modpath + fn[:-3] diff --git a/venv/lib/python3.9/site-packages/gevent/testing/monkey_test.py b/venv/lib/python3.9/site-packages/gevent/testing/monkey_test.py deleted file mode 100644 index 1647204..0000000 --- a/venv/lib/python3.9/site-packages/gevent/testing/monkey_test.py +++ /dev/null @@ -1,178 +0,0 @@ -import sys -import os - - -test_filename = sys.argv[1] -del sys.argv[1] - - - -from gevent import monkey -# Only test the default set of patch arguments. -monkey.patch_all() - -from .patched_tests_setup import disable_tests_in_source -from . import support -from . import resources -from . import SkipTest -from . import util - - - -# This uses the internal built-in function ``_thread._count()``, -# which we don't/can't monkey-patch, so it returns inaccurate information. -def threading_setup(): - return (1, ()) - -# This then tries to wait for that value to return to its original value; -# but if we started worker threads that can never happen. -def threading_cleanup(*_args): - return - -assert support.threading_setup -assert support.threading_cleanup - -support.threading_setup = threading_setup -support.threading_cleanup = threading_cleanup - - -# On all versions of Python 3.6+, this also uses ``_thread._count()``, -# meaning it suffers from inaccuracies, -# and test_socket.py constantly fails with an extra thread -# on some random test. We disable it entirely. -# XXX: Figure out how to make a *definition* in ./support.py actually -# override the original in test.support, without having to -# manually set it -# -import contextlib -@contextlib.contextmanager -def wait_threads_exit(timeout=None): # pylint:disable=unused-argument - # On < 3.10, this is support.wait_threads_exit; - # on >= 3.10, this is threading_helper.wait_threads_exit - yield - -support.wait_threads_exit = wait_threads_exit - -# On Python 3.11, they changed the way that they deal with this, -# meaning that this method no longer works. (Actually, it's not -# clear that any of our patches to `support` are doing anything on -# Python 3 at all? They certainly aren't on 3.11). This was a good -# thing As it led to adding the timeout value for the threadpool -# idle threads. But...the default of 5s meant that many tests in -# test_socket were each taking at least 5s to run, leading to the -# whole thing exceeding the allowed test timeout. We could set the -# GEVENT_THREADPOOL_IDLE_TASK_TIMEOUT env variable to a smaller -# value, and although that might stress the system nicely, it's -# not indicative of what end users see. And it's still hard to get -# a correct value. -# -# So try harder to make sure our patches apply. -# -# If this fails, symptoms are very long running tests that can be resolved -# by setting that TASK_TIMEOUT value small, and/or setting GEVENT_RESOLVER=block. -# Also, some number of warnings about dangling threads, or failures -# from wait_threads_exit -try: - from test import support as ts -except ImportError: - ts = None -else: - ts.threading_setup = threading_setup - ts.threading_cleanup = threading_cleanup - ts.wait_threads_exit = wait_threads_exit - ts.print_warning = lambda msg: msg - -try: - from test.support import threading_helper -except ImportError: - pass -else: - threading_helper.wait_threads_exit = wait_threads_exit - threading_helper.threading_setup = threading_setup - threading_helper.threading_cleanup = threading_cleanup - - -try: - from test.support import import_helper -except ImportError: - pass -else: - # Importing fresh modules breaks our monkey patches. we can't allow that. - def import_fresh_module(name, *_args, **_kwargs): - import importlib - return importlib.import_module(name) - import_helper.import_fresh_module = import_fresh_module - -# So we don't have to patch test_threading to use our -# version of lock_tests, we patch -from gevent.tests import lock_tests -try: - import test.lock_tests -except ImportError: - pass -else: - test.lock_tests = lock_tests - sys.modules['tests.lock_tests'] = lock_tests - -# Configure allowed resources -resources.setup_resources() - -if not os.path.exists(test_filename) and os.sep not in test_filename: - # A simple filename, given without a path, that doesn't exist. - # So we change to the appropriate directory, if we can find it. - # This happens when copy-pasting the output of the testrunner - for d in util.find_stdlib_tests(): - if os.path.exists(os.path.join(d, test_filename)): - os.chdir(d) - break - -__file__ = os.path.abspath(test_filename) #os.path.join(os.getcwd(), test_filename) -test_name = os.path.splitext(os.path.basename(test_filename))[0] - -print('Running with patch_all(): %s' % (__file__,)) - -with open(test_filename, encoding='utf-8') as module_file: - module_source = module_file.read() -module_source = disable_tests_in_source(module_source, test_name) - - -# We write the module source to a file so that tracebacks -# show correctly, since disabling the tests changes line -# numbers. However, note that __file__ must still point to the -# real location so that data files can be found. -# See https://github.com/gevent/gevent/issues/1306 -import tempfile -temp_handle, temp_path = tempfile.mkstemp(prefix=test_name, suffix='.py', text=True) -os.write(temp_handle, module_source.encode('utf-8')) -os.close(temp_handle) -remove_file = not os.environ.get('GEVENT_DEBUG') -if remove_file and ts is not None: - # Some of the stdlib tests spew a lot of data to stdout. This - # makes it hard to read results of a whole run of all the monkey - # stdlib tests. The main CPython regression runner, the equivalent - # of ``gevent.tests`` sets this to false and that stops some of it. - ts.verbose = 0 - print('Disabling verbose stdlib tests') -try: - module_code = compile(module_source, - temp_path, - 'exec', - dont_inherit=True) - exec(module_code, globals()) - remove_file = True -except SkipTest as e: - remove_file = True - # Some tests can raise test.support.ResourceDenied - # in their main method before the testrunner takes over. - # That's a kind of SkipTest. we can't get a true skip count because it - # hasn't run, though. - print(e) - # Match the regular unittest output, including ending with skipped - print("Ran 0 tests in 0.0s") - print('OK (skipped=0)') -finally: - if remove_file: - try: - os.remove(temp_path) - except OSError: - pass diff --git a/venv/lib/python3.9/site-packages/gevent/testing/openfiles.py b/venv/lib/python3.9/site-packages/gevent/testing/openfiles.py deleted file mode 100644 index e498fa5..0000000 --- a/venv/lib/python3.9/site-packages/gevent/testing/openfiles.py +++ /dev/null @@ -1,227 +0,0 @@ -# Copyright (c) 2018 gevent community -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. -from __future__ import absolute_import, print_function, division - -import os -import unittest -import re -import gc -import functools - -from . import sysinfo - -# Linux/OS X/BSD platforms /can/ implement this by calling out to lsof. -# However, if psutil is available (it is cross-platform) use that. -# It is *much* faster than shelling out to lsof each time -# (Running 14 tests takes 3.964s with lsof and 0.046 with psutil) -# However, it still doesn't completely solve the issue on Windows: fds are reported -# as -1 there, so we can't fully check those. - -def _collects(func): - # We've seen OSError: No such file or directory /proc/PID/fd/NUM. - # This occurs in the loop that checks open files. It first does - # listdir() and then tries readlink() on each file. But the file - # went away. This must be because of async GC in PyPy running - # destructors at arbitrary times. This became an issue in PyPy 7.2 - # but could theoretically be an issue with any objects caught in a - # cycle. This is one reason we GC before we begin. (The other is - # to clean up outstanding objects that will close files in - # __del__.) - # - # Note that this can hide errors, though, by causing greenlets to get - # collected and drop references and thus close files. We should be deterministic - # and careful about closing things. - @functools.wraps(func) - def f(**kw): - gc.collect() - gc.collect() - enabled = gc.isenabled() - gc.disable() - - try: - return func(**kw) - finally: - if enabled: - gc.enable() - return f - - -if sysinfo.WIN: - def _run_lsof(): - raise unittest.SkipTest("lsof not expected on Windows") -else: - @_collects - def _run_lsof(): - import tempfile - pid = os.getpid() - fd, tmpname = tempfile.mkstemp('get_open_files') - os.close(fd) - lsof_command = 'lsof -p %s > %s' % (pid, tmpname) - if os.system(lsof_command): - # XXX: This prints to the console an annoying message: 'lsof is not recognized' - raise unittest.SkipTest("lsof failed") - - with open(tmpname) as fobj: # pylint:disable=unspecified-encoding - data = fobj.read().strip() - os.remove(tmpname) - return data - -def default_get_open_files(pipes=False, **_kwargs): - data = _run_lsof() - results = {} - for line in data.split('\n'): - line = line.strip() - if not line or line.startswith("COMMAND"): - # Skip header and blank lines - continue - split = re.split(r'\s+', line) - # Note that this needs the real lsof; it won't work with - # the lsof that comes from BusyBox. You'll get parsing errors - # here. - _command, _pid, _user, fd = split[:4] - # Pipes (on OS X, at least) get an fd like "3" while normal files get an fd like "1u" - if fd[:-1].isdigit() or fd.isdigit(): - if not pipes and fd[-1].isdigit(): - continue - fd = int(fd[:-1]) if not fd[-1].isdigit() else int(fd) - if fd in results: - params = (fd, line, split, results.get(fd), data) - raise AssertionError('error when parsing lsof output: duplicate fd=%r\nline=%r\nsplit=%r\nprevious=%r\ndata:\n%s' % params) - results[fd] = line - if not results: - raise AssertionError('failed to parse lsof:\n%s' % (data, )) - results['data'] = data - return results - -@_collects -def default_get_number_open_files(): - if os.path.exists('/proc/'): - # Linux only - fd_directory = '/proc/%d/fd' % os.getpid() - return len(os.listdir(fd_directory)) - - try: - return len(get_open_files(pipes=True)) - 1 - except (OSError, AssertionError, unittest.SkipTest): - return 0 - -lsof_get_open_files = default_get_open_files - -try: - # psutil import subprocess which on Python 3 imports selectors. - # This can expose issues with monkey-patching. - import psutil -except ImportError: - get_open_files = default_get_open_files - get_number_open_files = default_get_number_open_files -else: - class _TrivialOpenFile(object): - __slots__ = ('fd',) - def __init__(self, fd): - self.fd = fd - - @_collects - def get_open_files(count_closing_as_open=True, **_kw): - """ - Return a list of popenfile and pconn objects. - - Note that other than `fd`, they have different attributes. - - .. important:: If you want to find open sockets, on Windows - and linux, it is important that the socket at least be listening - (socket.listen(1)). Unlike the lsof implementation, this will only - return sockets in a state like that. - """ - - results = {} - - for _ in range(3): - try: - if count_closing_as_open and os.path.exists('/proc/'): - # Linux only. - # psutil doesn't always see all connections, even though - # they exist in the filesystem. It's not entirely clear why. - # It sees them on Travis (prior to Ubuntu Bionic, at least) - # but doesn't in the manylinux image or Fedora 33 Rawhide image. - # This happens in test__makefile_ref TestSSL.*; in particular, if a - # ``sslsock.makefile()`` is opened and used to read all data, and the sending - # side shuts down, psutil no longer finds the open file. So we add them - # back in. - # - # Of course, the flip side of this is that we sometimes find connections - # we're not expecting. - # I *think* this has to do with CLOSE_WAIT handling? - fd_directory = '/proc/%d/fd' % os.getpid() - fd_files = os.listdir(fd_directory) - else: - fd_files = [] - process = psutil.Process() - results['data'] = process.open_files() - results['data'] += process.net_connections('all') - break - except OSError: - pass - else: - # No break executed - raise unittest.SkipTest("Unable to read open files") - - for x in results['data']: - results[x.fd] = x - for fd_str in fd_files: - if fd_str not in results: - fd = int(fd_str) - results[fd] = _TrivialOpenFile(fd) - results['data'] += [('From psutil', process)] - results['data'] += [('fd files', fd_files)] - return results - - @_collects - def get_number_open_files(): - process = psutil.Process() - try: - return process.num_fds() - except AttributeError: - # num_fds is unix only. Is num_handles close enough on Windows? - return 0 - - - -class DoesNotLeakFilesMixin(object): # pragma: no cover - """ - A test case mixin that helps find a method that's leaking an - open file. - - Only mix this in when needed to debug, it slows tests down. - """ - def setUp(self): - self.__open_files_count = get_number_open_files() - super(DoesNotLeakFilesMixin, self).setUp() - - def tearDown(self): - super(DoesNotLeakFilesMixin, self).tearDown() - after = get_number_open_files() - if after > self.__open_files_count: - raise AssertionError( - "Too many open files. Before: %s < After: %s.\n%s" % ( - self.__open_files_count, - after, - get_open_files() - ) - ) diff --git a/venv/lib/python3.9/site-packages/gevent/testing/params.py b/venv/lib/python3.9/site-packages/gevent/testing/params.py deleted file mode 100644 index 00097a7..0000000 --- a/venv/lib/python3.9/site-packages/gevent/testing/params.py +++ /dev/null @@ -1,68 +0,0 @@ -# Copyright (c) 2018 gevent community -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. - -from . import support - -from .sysinfo import PY3 -from .sysinfo import PYPY -from .sysinfo import WIN -from .sysinfo import LIBUV - -from .sysinfo import EXPECT_POOR_TIMER_RESOLUTION - - -# Travis is slow and overloaded; Appveyor used to be faster, but -# as of Dec 2015 it's almost always slower and/or has much worse timer -# resolution -CI_TIMEOUT = 15 -if (PY3 and PYPY) or (PYPY and WIN and LIBUV): - # pypy3 is very slow right now, - # as is PyPy2 on windows (which only has libuv) - CI_TIMEOUT = 20 -if PYPY and LIBUV: - # slow and flaky timeouts - LOCAL_TIMEOUT = CI_TIMEOUT -else: - LOCAL_TIMEOUT = 2 - -LARGE_TIMEOUT = max(LOCAL_TIMEOUT, CI_TIMEOUT) - -# Previously we set this manually to 'localhost' -# and then had some conditions where we changed it to -# 127.0.0.1 (e.g., on Windows or OSX or travis), but Python's test.support says -# # Don't use "localhost", since resolving it uses the DNS under recent -# # Windows versions (see issue #18792). -# and sets it unconditionally to 127.0.0.1. -DEFAULT_LOCAL_HOST_ADDR = support.HOST -DEFAULT_LOCAL_HOST_ADDR6 = support.HOSTv6 -# Not all TCP stacks support dual binding where '' -# binds to both v4 and v6. -# XXX: This is badly named; you often want DEFAULT_BIND_ADDR_TUPLE -DEFAULT_BIND_ADDR = support.HOST - - -DEFAULT_CONNECT_HOST = DEFAULT_CONNECT = DEFAULT_LOCAL_HOST_ADDR -DEFAULT_BIND_ADDR_TUPLE = (DEFAULT_BIND_ADDR, 0) - -# For in-process sockets -DEFAULT_SOCKET_TIMEOUT = 0.1 if not EXPECT_POOR_TIMER_RESOLUTION else 2.0 - -# For cross-process sockets -DEFAULT_XPC_SOCKET_TIMEOUT = 2.0 if not EXPECT_POOR_TIMER_RESOLUTION else 4.0 diff --git a/venv/lib/python3.9/site-packages/gevent/testing/patched_tests_setup.py b/venv/lib/python3.9/site-packages/gevent/testing/patched_tests_setup.py deleted file mode 100644 index 77845af..0000000 --- a/venv/lib/python3.9/site-packages/gevent/testing/patched_tests_setup.py +++ /dev/null @@ -1,1573 +0,0 @@ -# pylint:disable=missing-docstring,invalid-name,too-many-lines -from __future__ import print_function, absolute_import, division - -import collections -import contextlib -import functools -import sys -import os -# At least on 3.6+, importing platform -# imports subprocess, which imports selectors. That -# can expose issues with monkey patching. We don't need it -# though. -# import platform -import re - -from .sysinfo import RUNNING_ON_APPVEYOR as APPVEYOR -from .sysinfo import RUNNING_ON_TRAVIS as TRAVIS -from .sysinfo import RESOLVER_NOT_SYSTEM as ARES -from .sysinfo import RESOLVER_ARES -from .sysinfo import RESOLVER_DNSPYTHON -from .sysinfo import RUNNING_ON_CI -from .sysinfo import RUNNING_ON_MUSLLINUX -from .sysinfo import RUN_COVERAGE - - -from .sysinfo import PYPY -from .sysinfo import PYPY3 - -from .sysinfo import PY310_EXACTLY -from .sysinfo import PY311 -from .sysinfo import PY312 -from .sysinfo import PY313 -from .sysinfo import PY314 - -from .sysinfo import WIN -from .sysinfo import OSX -from .sysinfo import LINUX - -from .sysinfo import LIBUV -from .sysinfo import CFFI_BACKEND - -from . import flaky - -CPYTHON = not PYPY - -# By default, test cases are expected to switch and emit warnings if there was none -# If a test is found in this list, it's expected not to switch. -no_switch_tests = '''test_patched_select.SelectTestCase.test_error_conditions -test_patched_ftplib.*.test_all_errors -test_patched_ftplib.*.test_getwelcome -test_patched_ftplib.*.test_sanitize -test_patched_ftplib.*.test_set_pasv -#test_patched_ftplib.TestIPv6Environment.test_af -test_patched_socket.TestExceptions.testExceptionTree -test_patched_socket.Urllib2FileobjectTest.testClose -test_patched_socket.TestLinuxAbstractNamespace.testLinuxAbstractNamespace -test_patched_socket.TestLinuxAbstractNamespace.testMaxName -test_patched_socket.TestLinuxAbstractNamespace.testNameOverflow -test_patched_socket.FileObjectInterruptedTestCase.* -test_patched_urllib.* -test_patched_asyncore.HelperFunctionTests.* -test_patched_httplib.BasicTest.* -test_patched_httplib.HTTPSTimeoutTest.test_attributes -test_patched_httplib.HeaderTests.* -test_patched_httplib.OfflineTest.* -test_patched_httplib.HTTPSTimeoutTest.test_host_port -test_patched_httplib.SourceAddressTest.testHTTPSConnectionSourceAddress -test_patched_select.SelectTestCase.test_error_conditions -test_patched_smtplib.NonConnectingTests.* -test_patched_urllib2net.OtherNetworkTests.* -test_patched_wsgiref.* -test_patched_subprocess.HelperFunctionTests.* -''' - -ignore_switch_tests = ''' -test_patched_socket.GeneralModuleTests.* -test_patched_httpservers.BaseHTTPRequestHandlerTestCase.* -test_patched_queue.* -test_patched_signal.SiginterruptTest.* -test_patched_urllib2.* -test_patched_ssl.* -test_patched_signal.BasicSignalTests.* -test_patched_threading_local.* -test_patched_threading.* -''' - - -def make_re(tests): - tests = [x.strip().replace(r'\.', r'\\.').replace('*', '.*?') - for x in tests.split('\n') if x.strip()] - return re.compile('^%s$' % '|'.join(tests)) - - -no_switch_tests = make_re(no_switch_tests) -ignore_switch_tests = make_re(ignore_switch_tests) - - -def get_switch_expected(fullname): - """ - >>> get_switch_expected('test_patched_select.SelectTestCase.test_error_conditions') - False - >>> get_switch_expected('test_patched_socket.GeneralModuleTests.testCrucialConstants') - False - >>> get_switch_expected('test_patched_socket.SomeOtherTest.testHello') - True - >>> get_switch_expected("test_patched_httplib.BasicTest.test_bad_status_repr") - False - """ - # certain pylint versions mistype the globals as - # str, not re. - # pylint:disable=no-member - if ignore_switch_tests.match(fullname) is not None: - return None - if no_switch_tests.match(fullname) is not None: - return False - return True - - -disabled_tests = [ - # Want's __module__ to be 'signal', which of course it isn't once - # monkey-patched. - 'test_signal.GenericTests.test_functions_module_attr', - # XXX: While we debug latest updates. This is leaking - 'test_threading.ThreadTests.test_no_refcycle_through_target', - - # These two might have been impacted by the change in greenlet 3.3.2 - 'test_threading.ThreadTests.test_main_thread_during_shutdown', - 'test_threading.ThreadTests.test_locals_at_exit', - # This test only runs if threading has not been imported already - # when the subprocess runs its script. But locally, and on CI, - # threading is already imported. It's not clear how, because getting the backtrace just - # shows all the internal frozen importlib modules, no actual calling code. - # The closest we get is this: - # - # (626)() - # (609)main() - # (541)venv() - # (394)addsitepackages() - # (236)addsitedir() - # (195)addpackage() - # (1)() - # - # which makes it appear like it's one of the .pth files? - # - # The monkey_test.py runner adds some ``gevent.testing`` - # imports to the top of ``test_threading.py``, and those do - # ultimately import threading, but that shouldn't affect the - # Python subprocess that runs the script being tested. - # - # Locally, I had a .pythonrc that was importing threading - # (``rich.traceback`` -> ``pygments.lexers`` -> - # ``pygments.plugin`` -> ``importlib.metadata`` -> ``zipfile`` - # -> ``importlib.util`` -> ``threading``). - # - # That provided the clue we needed. ``importlib._bootstrap`` - # imports ``importlib.util``, which imports threading. No idea - # how this test gets to pass on the CPython test suite. - 'test_threading.ThreadTests.test_import_from_another_thread', - - # The server side takes awhile to shut down - 'test_httplib.HTTPSTest.test_local_bad_hostname', - # These were previously 3.5+ issues (same as above) - # but have been backported. - 'test_httplib.HTTPSTest.test_local_good_hostname', - 'test_httplib.HTTPSTest.test_local_unknown_cert', - - - 'test_threading.ThreadTests.test_PyThreadState_SetAsyncExc', - # uses some internal C API of threads not available when threads are emulated with greenlets - - 'test_threading.ThreadTests.test_join_nondaemon_on_shutdown', - # asserts that repr(sleep) is '' - - 'test_urllib2net.TimeoutTest.test_ftp_no_timeout', - 'test_urllib2net.TimeoutTest.test_ftp_timeout', - 'test_urllib2net.TimeoutTest.test_http_no_timeout', - 'test_urllib2net.TimeoutTest.test_http_timeout', - # accesses _sock.gettimeout() which is always in non-blocking mode - - 'test_urllib2net.OtherNetworkTests.test_ftp', - # too slow - - 'test_urllib2net.OtherNetworkTests.test_urlwithfrag', - # fails dues to some changes on python.org - - 'test_urllib2net.OtherNetworkTests.test_sites_no_connection_close', - # flaky - - 'test_socket.UDPTimeoutTest.testUDPTimeout', - # has a bug which makes it fail with error: (107, 'Transport endpoint is not connected') - # (it creates a TCP socket, not UDP) - - 'test_socket.GeneralModuleTests.testRefCountGetNameInfo', - # fails with "socket.getnameinfo loses a reference" while the reference is only "lost" - # because it is referenced by the traceback - any Python function would lose a reference like that. - # the original getnameinfo does not "lose" it because it's in C. - - 'test_socket.NetworkConnectionNoServer.test_create_connection_timeout', - # replaces socket.socket with MockSocket and then calls create_connection. - # this unfortunately does not work with monkey patching, because gevent.socket.create_connection - # is bound to gevent.socket.socket and updating socket.socket does not affect it. - # this issues also manifests itself when not monkey patching DNS: http://code.google.com/p/gevent/issues/detail?id=54 - # create_connection still uses gevent.socket.getaddrinfo while it should be using socket.getaddrinfo - - 'test_asyncore.BaseTestAPI.test_handle_expt', - # sends some OOB data and expect it to be detected as such; gevent.select.select does not support that - - # This one likes to check its own filename, but we rewrite - # the file to a temp location during patching. - 'test_asyncore.HelperFunctionTests.test_compact_traceback', - - # expects time.sleep() to return prematurely in case of a signal; - # gevent.sleep() is better than that and does not get interrupted - # (unless signal handler raises an error) - 'test_signal.WakeupSignalTests.test_wakeup_fd_early', - - # expects select.select() to raise select.error(EINTR'interrupted - # system call') gevent.select.select() does not get interrupted - # (unless signal handler raises an error) maybe it should? - 'test_signal.WakeupSignalTests.test_wakeup_fd_during', - - # these rely on os.read raising EINTR which never happens with gevent.os.read - 'test_signal.SiginterruptTest.test_without_siginterrupt', - 'test_signal.SiginterruptTest.test_siginterrupt_on', - 'test_signal.SiginterruptTest.test_siginterrupt_off', - # This one takes forever and relies on threading details - 'test_signal.StressTest.test_stress_modifying_handlers', - # This uses an external file, and launches it. This means that it's not - # actually testing gevent because there's no monkey-patch. - 'test_signal.PosixTests.test_interprocess_signal', - - 'test_subprocess.ProcessTestCase.test_leak_fast_process_del_killed', - 'test_subprocess.ProcessTestCase.test_zombie_fast_process_del', - # relies on subprocess._active which we don't use - - # Very slow, tries to open lots and lots of subprocess and files, - # tends to timeout on CI. - 'test_subprocess.ProcessTestCase.test_no_leaking', - - # This test is also very slow, and has been timing out on Travis - # since November of 2016 on Python 3, but now also seen on Python 2/Pypy. - 'test_subprocess.ProcessTestCase.test_leaking_fds_on_error', - - # Added between 3.6.0 and 3.6.3, uses _testcapi and internals - # of the subprocess module. Backported to Python 2.7.16. - 'test_subprocess.POSIXProcessTestCase.test_stopped', - - 'test_ssl.ThreadedTests.test_default_ciphers', - 'test_ssl.ThreadedTests.test_empty_cert', - 'test_ssl.ThreadedTests.test_malformed_cert', - 'test_ssl.ThreadedTests.test_malformed_key', - 'test_ssl.NetworkedTests.test_non_blocking_connect_ex', - # XXX needs investigating - - 'test_ssl.NetworkedTests.test_algorithms', - # The host this wants to use, sha256.tbs-internet.com, is not resolvable - # right now (2015-10-10), and we need to get Windows wheels - - # This started timing out randomly on Travis in oct/nov 2018. It appears - # to be something with random number generation taking too long. - 'test_ssl.BasicSocketTests.test_random_fork', - - # Relies on the repr of objects (Py3) - 'test_ssl.BasicSocketTests.test_dealloc_warn', - - # Takes forever - 'test_ssl.BasicSocketTests.test_connect_ex_error', - - 'test_urllib2.HandlerTests.test_cookie_redirect', - # this uses cookielib which we don't care about - - 'test_thread.ThreadRunningTests.test__count', - 'test_thread.TestForkInThread.test_forkinthread', - # XXX needs investigating - - 'test_subprocess.POSIXProcessTestCase.test_preexec_errpipe_does_not_double_close_pipes', - # Does not exist in the test suite until 2.7.4+. Subclasses Popen, and overrides - # _execute_child. But our version has a different parameter list than the - # version that comes with PyPy/CPython, so fails with a TypeError. - - # This one crashes the interpreter if it has a bug parsing the - # invalid data. - 'test_ssl.BasicSocketTests.test_parse_cert_CVE_2019_5010', - # We had to copy in a newer version of the test file for SSL fixes - # and this doesn't work reliably on all versions. - 'test_httplib.HeaderTests.test_headers_debuglevel', - - # On Appveyor with Python 3.8.0 and 3.7.5, this test - # for __class_getitem__ fails. Presumably this was added - # in a patch release (it's not in the PEP.) Sigh. - # https://bugs.python.org/issue38979 - 'test_context.ContextTest.test_contextvar_getitem', - # The same patch that fixed that removed this test, - # because it would now fail. - 'test_context.ContextTest.test_context_var_new_2', - - - # The C queue objects are immune to monkey patching, disable them - 'test_queue.CLifoQueueTest', - 'test_queue.CPriorityQueueTest', - 'test_queue.CQueueTest', - 'test_queue.CSimpleQueueTest', - 'test_queue.CFailingQueueTest', - - # (These will actually catch tests for many different queue types.) - # They needs to be disabled because it uses tight loops in "threads" - # calling ``q.get(False)`` which doesn't allow any other greenlet to - # make progress, so the shutdown request never gets through. - 'test_queue.PyLifoQueueTest.test_shutdown_all_methods_in_many_threads', - 'test_queue.PyLifoQueueTest.test_shutdown_immediate_all_methods_in_many_threads', - -] - - -if OSX: - disabled_tests += [ - # These are timing dependent, and sometimes run into the OS X - # kernel bug leading to 'Protocol wrong type for socket'. - # See discussion at https://github.com/benoitc/gunicorn/issues/1487 - 'test_ssl.SimpleBackgroundTests.test_connect_capath', - 'test_ssl.SimpleBackgroundTests.test_connect_with_context', - ] - -if PYPY: - disabled_tests += [ - # The exact error message the code code checks for is different - # (possibly just on macOS?). Plain PyPy3 fails as well. - 'test_signal.WakeupSignalTests.test_wakeup_write_error', - ] - -if 'thread' in os.getenv('GEVENT_FILE', ''): - disabled_tests += [ - 'test_subprocess.ProcessTestCase.test_double_close_on_error' - # Fails with "OSError: 9 invalid file descriptor"; expect GC/lifetime issues - ] - - -if LIBUV: - # epoll appears to work with these just fine in some cases; - # kqueue (at least on OS X, the only tested kqueue system) - # never does (failing with abort()) - # (epoll on Raspbian 8.0/Debian Jessie/Linux 4.1.20 works; - # on a VirtualBox image of Ubuntu 15.10/Linux 4.2.0 both tests fail; - # Travis CI Ubuntu 12.04 precise/Linux 3.13 causes one of these tests to hang forever) - # XXX: Retry this with libuv 1.12+ - disabled_tests += [ - # A 2.7 test. Tries to fork, and libuv cannot fork - 'test_signal.InterProcessSignalTests.test_main', - # Likewise, a forking problem - 'test_signal.SiginterruptTest.test_siginterrupt_off', - ] - - disabled_tests += [ - # This test wants to pass an arbitrary fileno - # to a socket and do things with it. libuv doesn't like this, - # it raises EPERM. It is disabled on windows already. - # It depends on whether we had a fd already open and multiplexed with - 'test_socket.GeneralModuleTests.test_unknown_socket_family_repr', - # And yes, there's a typo in some versions. - 'test_socket.GeneralModuleTests.test_uknown_socket_family_repr', - # This test sometimes fails at line 358. It's apparently - # extremely sensitive to timing. - 'test_selectors.PollSelectorTestCase.test_timeout', - ] - - if OSX: - disabled_tests += [ - # XXX: Starting when we upgraded from libuv 1.18.0 - # to 1.19.2, this sometimes (usually) started having - # a series of calls ('select.poll(0)', 'select.poll(-1)') - # take longer than the allowed 0.5 seconds. Debugging showed that - # it was the second call that took longer, for no apparent reason. - # There doesn't seem to be a change in the source code to libuv that - # would affect this. - # XXX-XXX: This actually disables too many tests :( - 'test_selectors.PollSelectorTestCase.test_timeout', - ] - - if RUN_COVERAGE: - - disabled_tests += [ - # Starting with #1145 this test (actually - # TestTLS_FTPClassMixin) becomes sensitive to timings - # under coverage. - 'test_ftplib.TestFTPClass.test_storlines', - ] - - - if sys.platform.startswith('linux'): - disabled_tests += [ - # crashes with EPERM, which aborts the epoll loop, even - # though it was allowed in in the first place. - 'test_asyncore.FileWrapperTest.test_dispatcher', - ] - - - if PYPY: - disabled_tests += [ - # appears to timeout? - 'test_threading.ThreadTests.test_finalize_with_trace', - 'test_asyncore.DispatcherWithSendTests_UsePoll.test_send', - 'test_asyncore.DispatcherWithSendTests.test_send', - - # More unexpected timeouts - 'test_ssl.ContextTests.test__https_verify_envvar', - 'test_subprocess.ProcessTestCase.test_check_output', - 'test_telnetlib.ReadTests.test_read_eager_A', - - # But on Windows, our gc fix for that doesn't work anyway - # so we have to disable it. - 'test_urllib2_localnet.TestUrlopen.test_https_with_cafile', - - # These tests hang. see above. - 'test_threading.ThreadJoinOnShutdown.test_1_join_on_shutdown', - 'test_threading.ThreadingExceptionTests.test_print_exception', - - # Our copy of these in test__subprocess.py also hangs. - # Anything that uses Popen.communicate or directly uses - # Popen.stdXXX.read hangs. It's not clear why. - 'test_subprocess.ProcessTestCase.test_communicate', - 'test_subprocess.ProcessTestCase.test_cwd', - 'test_subprocess.ProcessTestCase.test_env', - 'test_subprocess.ProcessTestCase.test_stderr_pipe', - 'test_subprocess.ProcessTestCase.test_stdout_pipe', - 'test_subprocess.ProcessTestCase.test_stdout_stderr_pipe', - 'test_subprocess.ProcessTestCase.test_stderr_redirect_with_no_stdout_redirect', - 'test_subprocess.ProcessTestCase.test_stdout_filedes_of_stdout', - 'test_subprocess.ProcessTestcase.test_stdout_none', - 'test_subprocess.ProcessTestcase.test_universal_newlines', - 'test_subprocess.ProcessTestcase.test_writes_before_communicate', - 'test_subprocess.Win32ProcessTestCase._kill_process', - 'test_subprocess.Win32ProcessTestCase._kill_dead_process', - 'test_subprocess.Win32ProcessTestCase.test_shell_sequence', - 'test_subprocess.Win32ProcessTestCase.test_shell_string', - 'test_subprocess.CommandsWithSpaces.with_spaces', - ] - - - if WIN: - - disabled_tests += [ - # This test winds up hanging a long time. - # Inserting GCs doesn't fix it. - 'test_ssl.ThreadedTests.test_handshake_timeout', - - # These sometimes raise LoopExit, for no apparent reason, - # mostly but not exclusively on Python 2. Sometimes (often?) - # this happens in the setUp() method when we attempt to get a client - # connection - 'test_socket.BufferIOTest.testRecvFromIntoBytearray', - 'test_socket.BufferIOTest.testRecvFromIntoArray', - 'test_socket.BufferIOTest.testRecvIntoArray', - 'test_socket.BufferIOTest.testRecvIntoMemoryview', - 'test_socket.BufferIOTest.testRecvFromIntoEmptyBuffer', - 'test_socket.BufferIOTest.testRecvFromIntoMemoryview', - 'test_socket.BufferIOTest.testRecvFromIntoSmallBuffer', - 'test_socket.BufferIOTest.testRecvIntoBytearray', - ] - - if PYPY: - - if TRAVIS: - - disabled_tests += [ - # This sometimes causes a segfault for no apparent reason. - # See https://travis-ci.org/gevent/gevent/jobs/327328704 - # Can't reproduce locally. - 'test_subprocess.ProcessTestCase.test_universal_newlines_communicate', - ] - -if RUN_COVERAGE and CFFI_BACKEND: - disabled_tests += [ - # This test hangs in this combo for some reason - 'test_socket.GeneralModuleTests.test_sendall_interrupted', - # This can get a timeout exception instead of the Alarm - 'test_socket.TCPTimeoutTest.testInterruptedTimeout', - - # This test sometimes gets the wrong answer (due to changed timing?) - 'test_socketserver.SocketServerTest.test_ForkingUDPServer', - - # Timing and signals are off, so a handler exception doesn't get raised. - # Seen under libev - 'test_signal.InterProcessSignalTests.test_main', - ] - - -if PYPY and sys.pypy_version_info[:2] == (7, 3): # pylint:disable=no-member - - if OSX: - disabled_tests += [ - # This is expected to produce an SSLError, but instead it appears to - # actually work. See above for when it started failing the same on - # Travis. - 'test_ssl.ThreadedTests.test_alpn_protocols', - # This fails, presumably due to the OpenSSL it's compiled with. - 'test_ssl.ThreadedTests.test_default_ecdh_curve', - ] - -if PYPY3 and TRAVIS: - disabled_tests += [ - # If socket.SOCK_CLOEXEC is defined, this creates a socket - # and tests its type with ``sock.type & socket.SOCK_CLOEXEC`` - # We have a ``@property`` for ``type`` that takes care of - # ``SOCK_NONBLOCK`` on Linux, but otherwise it's just a pass-through. - # This started failing with PyPy 7.3.1 and it's not clear why. - 'test_socket.InheritanceTest.test_SOCK_CLOEXEC', - ] - -if PYPY3 and WIN: - disabled_tests += [ - # test_httpservers.CGIHTTPServerTestCase all seem to hang. - # There seem to be some general subprocess issues. This is - # ignored entirely from known_failures.py - - # This produces: - # - # OSError: [Errno 10014] The system detected an invalid - # pointer address in attempting to use a pointer argument in - # a call - # - # When calling socket.socket(fileno=fd) when we actually - # call ``self._socket =self._gevent_sock_class()``. - 'test_socket.GeneralModuleTests.test_socket_fileno', - - # This doesn't respect the scope properly - # - # self.assertEqual(sockaddr, ('ff02::1de:c0:face:8d', 1234, 0, ifindex)) - # AssertionError: Tuples differ: ('ff02::1de:c0:face:8d%42', 1234, 0, 42) != ('ff02::1de:c0:face:8d', 1234, 0, 42 - # - 'test_socket.GeneralModuleTests.test_getaddrinfo_ipv6_scopeid_numeric', - - # self.assertEqual(newsock.get_inheritable(), False) - # AssertionError: True != False - 'test_socket.InheritanceTest.test_dup', - ] - -def _make_run_with_original(mod_name, func_name): - @contextlib.contextmanager - def with_orig(): - mod = __import__(mod_name) - now = getattr(mod, func_name) - from gevent.monkey import get_original - orig = get_original(mod_name, func_name) - try: - setattr(mod, func_name, orig) - yield - finally: - setattr(mod, func_name, now) - return with_orig - -@contextlib.contextmanager -def _gc_at_end(): - try: - yield - finally: - import gc - gc.collect() - gc.collect() - -@contextlib.contextmanager -def _flaky_socket_timeout(): - import socket - try: - yield - except socket.timeout: - flaky.reraiseFlakyTestTimeout() - -# Map from FQN to a context manager that will be wrapped around -# that test. -wrapped_tests = { -} - - - -class _PatchedTest(object): - def __init__(self, test_fqn): - self._patcher = wrapped_tests[test_fqn] - - def __call__(self, orig_test_fn): - - @functools.wraps(orig_test_fn) - def test(*args, **kwargs): - with self._patcher(): - return orig_test_fn(*args, **kwargs) - return test - - -if OSX: - disabled_tests += [ - 'test_subprocess.POSIXProcessTestCase.test_run_abort', - # causes Mac OS X to show "Python crashes" dialog box which is annoying - ] - -if WIN: - disabled_tests += [ - # Issue with Unix vs DOS newlines in the file vs from the server - 'test_ssl.ThreadedTests.test_socketserver', - # This sometimes hangs (only on appveyor) - 'test_ssl.ThreadedTests.test_asyncore_server', - # On appveyor, this sometimes produces 'A non-blocking socket - # operation could not be completed immediately', followed by - # 'No connection could be made because the target machine - # actively refused it' - 'test_socket.NonBlockingTCPTests.testAccept', - - # On appveyor, this test has been seen to fail on 3.9 and 3.8 - ] - - if sys.version_info[:2] <= (3, 9): - disabled_tests += [ - 'test_context.HamtTest.test_hamt_collision_3', - # Sometimes fails:: - # - # self.assertIn('got more than ', str(cm.exception)) - # AssertionError: 'got more than ' not found in - # 'Remote end closed connection without response' - # - 'test_httplib.BasicTest.test_overflowing_header_limit_after_100', - - ] - - # These are a problem on 3.5; on 3.6+ they wind up getting (accidentally) disabled. - wrapped_tests.update({ - 'test_socket.SendfileUsingSendTest.testWithTimeout': _flaky_socket_timeout, - 'test_socket.SendfileUsingSendTest.testOffset': _flaky_socket_timeout, - 'test_socket.SendfileUsingSendTest.testRegularFile': _flaky_socket_timeout, - 'test_socket.SendfileUsingSendTest.testCount': _flaky_socket_timeout, - }) - -if PYPY: - disabled_tests += [ - # Does not exist in the CPython test suite, tests for a specific bug - # in PyPy's forking. Only runs on linux and is specific to the PyPy - # implementation of subprocess (possibly explains the extra parameter to - # _execut_child) - 'test_subprocess.ProcessTestCase.test_failed_child_execute_fd_leak', - # On some platforms, this returns "zlib_compression", but the test is looking for - # "ZLIB" - 'test_ssl.ThreadedTests.test_compression', - - # These are flaxy, apparently a race condition? Began with PyPy 2.7-7 and 3.6-7 - 'test_asyncore.TestAPI_UsePoll.test_handle_error', - 'test_asyncore.TestAPI_UsePoll.test_handle_read', - ] - - if WIN: - disabled_tests += [ - # Starting in 7.3.1 on Windows, this stopped raising ValueError; it appears to - # be a bug in PyPy. - 'test_signal.WakeupFDTests.test_invalid_fd', - # Likewise for 7.3.1. See the comments for PY35 - 'test_socket.GeneralModuleTests.test_sock_ioctl', - ] - - - disabled_tests += [ - # These are flaky, beginning in 3.6-alpha 7.0, not finding some flag - # set, apparently a race condition - 'test_asyncore.TestAPI_UveIPv6Poll.test_handle_accept', - 'test_asyncore.TestAPI_UveIPv6Poll.test_handle_accepted', - 'test_asyncore.TestAPI_UveIPv6Poll.test_handle_close', - 'test_asyncore.TestAPI_UveIPv6Poll.test_handle_write', - - 'test_asyncore.TestAPI_UseIPV6Select.test_handle_read', - - # These are reporting 'ssl has no attribute ...' - # This could just be an OSX thing - 'test_ssl.ContextTests.test__create_stdlib_context', - 'test_ssl.ContextTests.test_create_default_context', - 'test_ssl.ContextTests.test_get_ciphers', - 'test_ssl.ContextTests.test_options', - 'test_ssl.ContextTests.test_constants', - - # These tend to hang for some reason, probably not properly - # closed sockets. - 'test_socketserver.SocketServerTest.test_write', - - # This uses ctypes to do funky things including using ptrace, - # it hangs - 'test_subprocess.ProcessTestcase.test_child_terminated_in_stopped_state', - - # Certificate errors; need updated test - 'test_urllib2_localnet.TestUrlopen.test_https', - ] - -# Generic Python 3 - - - -disabled_tests += [ - # Triggers the crash reporter - 'test_threading.SubinterpThreadingTests.test_daemon_threads_fatal_error', - - # Relies on an implementation detail, Thread._tstate_lock - 'test_threading.ThreadTests.test_tstate_lock', - # Relies on an implementation detail (reprs); we have our own version - 'test_threading.ThreadTests.test_various_ops', - 'test_threading.ThreadTests.test_various_ops_large_stack', - 'test_threading.ThreadTests.test_various_ops_small_stack', - - # Relies on Event having a _cond and an _reset_internal_locks() - # XXX: These are commented out in the source code of test_threading because - # this doesn't work. - # 'lock_tests.EventTests.test_reset_internal_locks', - - # Python bug 13502. We may or may not suffer from this as its - # basically a timing race condition. - # XXX Same as above - # 'lock_tests.EventTests.test_set_and_clear', - - # These tests want to assert on the type of the class that implements - # `Popen.stdin`; we use a FileObject, but they expect different subclasses - # from the `io` module - 'test_subprocess.ProcessTestCase.test_io_buffered_by_default', - 'test_subprocess.ProcessTestCase.test_io_unbuffered_works', - - # 3.3 exposed the `endtime` argument to wait accidentally. - # It is documented as deprecated and not to be used since 3.4 - # This test in 3.6.3 wants to use it though, and we don't have it. - 'test_subprocess.ProcessTestCase.test_wait_endtime', - - # These all want to inspect the string value of an exception raised - # by the exec() call in the child. The _posixsubprocess module arranges - # for better exception handling and printing than we do. - 'test_subprocess.POSIXProcessTestCase.test_exception_bad_args_0', - 'test_subprocess.POSIXProcessTestCase.test_exception_bad_executable', - 'test_subprocess.POSIXProcessTestCase.test_exception_cwd', - # Relies on a 'fork_exec' attribute that we don't provide - 'test_subprocess.POSIXProcessTestCase.test_exception_errpipe_bad_data', - 'test_subprocess.POSIXProcessTestCase.test_exception_errpipe_normal', - - # Python 3 fixed a bug if the stdio file descriptors were closed; - # we still have that bug - 'test_subprocess.POSIXProcessTestCase.test_small_errpipe_write_fd', - - # Relies on implementation details (some of these tests were added in 3.4, - # but PyPy3 is also shipping them.) - 'test_socket.GeneralModuleTests.test_SocketType_is_socketobject', - 'test_socket.GeneralModuleTests.test_dealloc_warn', - 'test_socket.GeneralModuleTests.test_repr', - 'test_socket.GeneralModuleTests.test_str_for_enums', - 'test_socket.GeneralModuleTests.testGetaddrinfo', - -] -if TRAVIS: - disabled_tests += [ - # test_cwd_with_relative_executable tends to fail - # on Travis...it looks like the test processes are stepping - # on each other and messing up their temp directories. We tend to get things like - # saved_dir = os.getcwd() - # FileNotFoundError: [Errno 2] No such file or directory - 'test_subprocess.ProcessTestCase.test_cwd_with_relative_arg', - 'test_subprocess.ProcessTestCaseNoPoll.test_cwd_with_relative_arg', - 'test_subprocess.ProcessTestCase.test_cwd_with_relative_executable', - - # In 3.7 and 3.8 on Travis CI, this appears to take the full 3 seconds. - # Can't reproduce it locally. We have our own copy of this that takes - # timing on CI into account. - 'test_subprocess.RunFuncTestCase.test_run_with_shell_timeout_and_capture_output', - ] - -disabled_tests += [ - # XXX: BUG: We simply don't handle this correctly. On CPython, - # we wind up raising a BlockingIOError and then - # BrokenPipeError and then some random TypeErrors, all on the - # server. CPython 3.5 goes directly to socket.send() (via - # socket.makefile), whereas CPython 3.6 uses socket.sendall(). - # On PyPy, the behaviour is much worse: we hang indefinitely, perhaps exposing a problem - # with our signal handling. - - # In actuality, though, this test doesn't fully test the EINTR it expects - # to under gevent (because if its EWOULDBLOCK retry behaviour.) - # Instead, the failures were all due to `pthread_kill` trying to send a signal - # to a greenlet instead of a real thread. The solution is to deliver the signal - # to the real thread by letting it get the correct ID, and we previously - # used make_run_with_original to make it do that. - # - # But now that we have disabled our wrappers around Thread.join() in favor - # of the original implementation, that causes problems: - # background.join() thinks that it is the current thread, and won't let it - # be joined. - 'test_wsgiref.IntegrationTests.test_interrupted_write', -] - -# PyPy3 3.5.5 v5.8-beta - -if PYPY3: - - - disabled_tests += [ - # This raises 'RuntimeError: reentrant call' when exiting the - # process tries to close the stdout stream; no other platform does this. - # Seen in both 3.3 and 3.5 (5.7 and 5.8) - 'test_signal.SiginterruptTest.test_siginterrupt_off', - ] - - disabled_tests += [ - # This fails to close all the FDs, at least on CI. On OS X, many of the - # POSIXProcessTestCase fd tests have issues. - 'test_subprocess.POSIXProcessTestCase.test_close_fds_when_max_fd_is_lowered', - - # This has the wrong constants in 5.8 (but worked in 5.7), at least on - # OS X. It finds "zlib compression" but expects "ZLIB". - 'test_ssl.ThreadedTests.test_compression', - - # The below are new with 5.10.1 - # This gets an EOF in violation of protocol; again, even without gevent - # (at least on OS X; it's less consistent about that on travis) - 'test_ssl.NetworkedBIOTests.test_handshake', - - # This passes various "invalid" strings and expects a ValueError. not sure why - # we don't see errors on CPython. - 'test_subprocess.ProcessTestCase.test_invalid_env', - ] - - if OSX: - disabled_tests += [ - # These all fail with "invalid_literal for int() with base 10: b''" - 'test_subprocess.POSIXProcessTestCase.test_close_fds', - 'test_subprocess.POSIXProcessTestCase.test_close_fds_after_preexec', - 'test_subprocess.POSIXProcessTestCase.test_pass_fds', - 'test_subprocess.POSIXProcessTestCase.test_pass_fds_inheritable', - 'test_subprocess.POSIXProcessTestCase.test_pipe_cloexec', - - - # The below are new with 5.10.1 - # These fail with 'OSError: received malformed or improperly truncated ancillary data' - 'test_socket.RecvmsgSCMRightsStreamTest.testCmsgTruncLen0', - 'test_socket.RecvmsgSCMRightsStreamTest.testCmsgTruncLen0Plus1', - 'test_socket.RecvmsgSCMRightsStreamTest.testCmsgTruncLen1', - 'test_socket.RecvmsgSCMRightsStreamTest.testCmsgTruncLen2Minus1', - - # Using the provided High Sierra binary, these fail with - # 'ValueError: invalid protocol version _SSLMethod.PROTOCOL_SSLv3'. - # gevent code isn't involved and running them unpatched has the same issue. - 'test_ssl.ContextTests.test_constructor', - 'test_ssl.ContextTests.test_protocol', - 'test_ssl.ContextTests.test_session_stats', - 'test_ssl.ThreadedTests.test_echo', - 'test_ssl.ThreadedTests.test_protocol_sslv23', - 'test_ssl.ThreadedTests.test_protocol_sslv3', - 'test_ssl.ThreadedTests.test_protocol_tlsv1', - 'test_ssl.ThreadedTests.test_protocol_tlsv1_1', - # Similar, they fail without monkey-patching. - 'test_ssl.TestPostHandshakeAuth.test_pha_no_pha_client', - 'test_ssl.TestPostHandshakeAuth.test_pha_optional', - 'test_ssl.TestPostHandshakeAuth.test_pha_required', - - # This gets None instead of http1.1, even without gevent - 'test_ssl.ThreadedTests.test_npn_protocols', - - # This fails to decode a filename even without gevent, - # at least on High Sierra. Newer versions of the tests actually skip this. - 'test_httpservers.SimpleHTTPServerTestCase.test_undecodable_filename', - ] - - disabled_tests += [ - # This seems to be a buffering issue? Something isn't - # getting flushed. (The output is wrong). Under PyPy3 5.7, - # I couldn't reproduce locally in Ubuntu 16 in a VM - # or a laptop with OS X. Under 5.8.0, I can reproduce it, but only - # when run by the testrunner, not when run manually on the command line, - # so something is changing in stdout buffering in those situations. - 'test_threading.ThreadJoinOnShutdown.test_2_join_in_forked_process', - 'test_threading.ThreadJoinOnShutdown.test_1_join_in_forked_process', - ] - - if TRAVIS: - disabled_tests += [ - # Likewise, but I haven't produced it locally. - 'test_threading.ThreadJoinOnShutdown.test_1_join_on_shutdown', - ] - -if PYPY: - - wrapped_tests.update({ - # XXX: gevent: The error that was raised by that last call - # left a socket open on the server or client. The server gets - # to http/server.py(390)handle_one_request and blocks on - # self.rfile.readline which apparently is where the SSL - # handshake is done. That results in the exception being - # raised on the client above, but apparently *not* on the - # server. Consequently it sits trying to read from that - # socket. On CPython, when the client socket goes out of scope - # it is closed and the server raises an exception, closing the - # socket. On PyPy, we need a GC cycle for that to happen. - # Without the socket being closed and exception being raised, - # the server cannot be stopped (it runs each request in the - # same thread that would notice it had been stopped), and so - # the cleanup method added by start_https_server to stop the - # server blocks "forever". - - # This is an important test, so rather than skip it in patched_tests_setup, - # we do the gc before we return. - 'test_urllib2_localnet.TestUrlopen.test_https_with_cafile': _gc_at_end, - - 'test_httpservers.BaseHTTPServerTestCase.test_command': _gc_at_end, - 'test_httpservers.BaseHTTPServerTestCase.test_handler': _gc_at_end, - 'test_httpservers.BaseHTTPServerTestCase.test_head_keep_alive': _gc_at_end, - 'test_httpservers.BaseHTTPServerTestCase.test_head_via_send_error': _gc_at_end, - 'test_httpservers.BaseHTTPServerTestCase.test_header_close': _gc_at_end, - 'test_httpservers.BaseHTTPServerTestCase.test_internal_key_error': _gc_at_end, - 'test_httpservers.BaseHTTPServerTestCase.test_request_line_trimming': _gc_at_end, - 'test_httpservers.BaseHTTPServerTestCase.test_return_custom_status': _gc_at_end, - 'test_httpservers.BaseHTTPServerTestCase.test_return_header_keep_alive': _gc_at_end, - 'test_httpservers.BaseHTTPServerTestCase.test_send_blank': _gc_at_end, - 'test_httpservers.BaseHTTPServerTestCase.test_send_error': _gc_at_end, - 'test_httpservers.BaseHTTPServerTestCase.test_version_bogus': _gc_at_end, - 'test_httpservers.BaseHTTPServerTestCase.test_version_digits': _gc_at_end, - 'test_httpservers.BaseHTTPServerTestCase.test_version_invalid': _gc_at_end, - 'test_httpservers.BaseHTTPServerTestCase.test_version_none': _gc_at_end, - 'test_httpservers.BaseHTTPServerTestCase.test_version_none_get': _gc_at_end, - 'test_httpservers.BaseHTTPServerTestCase.test_get': _gc_at_end, - 'test_httpservers.SimpleHTTPServerTestCase.test_get': _gc_at_end, - 'test_httpservers.SimpleHTTPServerTestCase.test_head': _gc_at_end, - 'test_httpservers.SimpleHTTPServerTestCase.test_invalid_requests': _gc_at_end, - 'test_httpservers.SimpleHTTPServerTestCase.test_path_without_leading_slash': _gc_at_end, - 'test_httpservers.CGIHTTPServerTestCase.test_invaliduri': _gc_at_end, - 'test_httpservers.CGIHTTPServerTestCase.test_issue19435': _gc_at_end, - - 'test_httplib.TunnelTests.test_connect': _gc_at_end, - 'test_httplib.SourceAddressTest.testHTTPConnectionSourceAddress': _gc_at_end, - - # Unclear - 'test_urllib2_localnet.ProxyAuthTests.test_proxy_with_bad_password_raises_httperror': _gc_at_end, - 'test_urllib2_localnet.ProxyAuthTests.test_proxy_with_no_password_raises_httperror': _gc_at_end, - }) - - - -disabled_tests += [ - 'test_subprocess.ProcessTestCase.test_threadsafe_wait', - # XXX: It seems that threading.Timer is not being greened properly, possibly - # due to a similar issue to what gevent.threading documents for normal threads. - # In any event, this test hangs forever - - - 'test_subprocess.POSIXProcessTestCase.test_preexec_errpipe_does_not_double_close_pipes', - # Subclasses Popen, and overrides _execute_child. Expects things to be done - # in a particular order in an exception case, but we don't follow that - # exact order - - - 'test_selectors.PollSelectorTestCase.test_above_fd_setsize', - # This test attempts to open many many file descriptors and - # poll on them, expecting them all to be ready at once. But - # libev limits the number of events it will return at once. Specifically, - # on linux with epoll, it returns a max of 64 (ev_epoll.c). - - # XXX: Hangs (Linux only) - 'test_socket.NonBlockingTCPTests.testInitNonBlocking', - # We don't handle the Linux-only SOCK_NONBLOCK option - 'test_socket.NonblockConstantTest.test_SOCK_NONBLOCK', - - # Tries to use multiprocessing which doesn't quite work in - # monkey_test module (Windows only) - 'test_socket.TestSocketSharing.testShare', - - # Windows-only: Sockets have a 'ioctl' method in Python 3 - # implemented in the C code. This test tries to check - # for the presence of the method in the class, which we don't - # have because we don't inherit the C implementation. But - # it should be found at runtime. - 'test_socket.GeneralModuleTests.test_sock_ioctl', - - # XXX This fails for an unknown reason - 'test_httplib.HeaderTests.test_parse_all_octets', -] - -if OSX: - disabled_tests += [ - # These raise "OSError: 12 Cannot allocate memory" on both - # patched and unpatched runs - 'test_socket.RecvmsgSCMRightsStreamTest.testFDPassEmpty', - ] - - if TRAVIS: - # This has been seen to produce "Inconsistency detected by - # ld.so: dl-open.c: 231: dl_open_worker: Assertion - # `_dl_debug_initialize (0, args->nsid)->r_state == - # RT_CONSISTENT' failed!" and fail. - disabled_tests += [ - 'test_threading.ThreadTests.test_is_alive_after_fork', - # This has timing constraints that are strict and do not always - # hold. - 'test_selectors.PollSelectorTestCase.test_timeout', - ] - -if TRAVIS: - disabled_tests += [ - 'test_subprocess.ProcessTestCase.test_double_close_on_error', - # This test is racy or OS-dependent. It passes locally (sufficiently fast machine) - # but fails under Travis - ] - - -disabled_tests += [ - # XXX: Hangs - 'test_ssl.ThreadedTests.test_nonblocking_send', - 'test_ssl.ThreadedTests.test_socketserver', - # Uses direct sendfile, doesn't properly check for it being enabled - 'test_socket.GeneralModuleTests.test__sendfile_use_sendfile', - - - # Relies on the regex of the repr having the locked state (TODO: it'd be nice if - # we did that). - # XXX: These are commented out in the source code of test_threading because - # this doesn't work. - # 'lock_tests.LockTests.lest_locked_repr', - # 'lock_tests.LockTests.lest_repr', - - - # This test opens a socket, creates a new socket with the same fileno, - # closes the original socket (and hence fileno) and then - # expects that the calling setblocking() on the duplicate socket - # will raise an error. Our implementation doesn't work that way because - # setblocking() doesn't actually touch the file descriptor. - # That's probably OK because this was a GIL state error in CPython - # see https://github.com/python/cpython/commit/fa22b29960b4e683f4e5d7e308f674df2620473c - 'test_socket.TestExceptions.test_setblocking_invalidfd', -] - - -if ARES: - disabled_tests += [ - # These raise different errors or can't resolve - # the IP address correctly - 'test_socket.GeneralModuleTests.test_host_resolution', - 'test_socket.GeneralModuleTests.test_getnameinfo', - ] - - -disabled_tests += [ - 'test_threading.MiscTestCase.test__all__', -] - -# We don't actually implement socket._sendfile_use_sendfile, -# so these tests, which think they're using that and os.sendfile, -# fail. -disabled_tests += [ - 'test_socket.SendfileUsingSendfileTest.testCount', - 'test_socket.SendfileUsingSendfileTest.testCountSmall', - 'test_socket.SendfileUsingSendfileTest.testCountWithOffset', - 'test_socket.SendfileUsingSendfileTest.testOffset', - 'test_socket.SendfileUsingSendfileTest.testRegularFile', - 'test_socket.SendfileUsingSendfileTest.testWithTimeout', - 'test_socket.SendfileUsingSendfileTest.testEmptyFileSend', - 'test_socket.SendfileUsingSendfileTest.testNonBlocking', - 'test_socket.SendfileUsingSendfileTest.test_errors', -] - -# Ditto -disabled_tests += [ - 'test_socket.GeneralModuleTests.test__sendfile_use_sendfile', -] - -disabled_tests += [ - # This test requires Linux >= 4.3. When we were running 'dist: - # trusty' on the 4.4 kernel, it passed (~July 2017). But when - # trusty became the default dist in September 2017 and updated - # the kernel to 4.11.6, it begain failing. It fails on `res = - # op.recv(assoclen + len(plain) + taglen)` (where 'op' is the - # client socket) with 'OSError: [Errno 22] Invalid argument' - # for unknown reasons. This is *after* having successfully - # called `op.sendmsg_afalg`. Post 3.6.0, what we test with, - # the test was changed to require Linux 4.9 and the data was changed, - # so this is not our fault. We should eventually update this when we - # update our 3.6 version. - # See https://bugs.python.org/issue29324 - 'test_socket.LinuxKernelCryptoAPI.test_aead_aes_gcm', -] - - -disabled_tests += [ - # These want to use the private '_communicate' method, which - # our Popen doesn't have. - 'test_subprocess.MiscTests.test_call_keyboardinterrupt_no_kill', - 'test_subprocess.MiscTests.test_context_manager_keyboardinterrupt_no_kill', - 'test_subprocess.MiscTests.test_run_keyboardinterrupt_no_kill', - - # This wants to check that the underlying fileno is blocking, - # but it isn't. - 'test_socket.NonBlockingTCPTests.testSetBlocking', - - # 3.7b2 made it impossible to instantiate SSLSocket objects - # directly, and this tests for that, but we don't follow that change. - 'test_ssl.BasicSocketTests.test_private_init', - - # 3.7b2 made a change to this test that on the surface looks incorrect, - # but it passes when they run it and fails when we do. It's not - # clear why. - 'test_ssl.ThreadedTests.test_check_hostname_idn', - - # These appear to hang, haven't investigated why - 'test_ssl.SimpleBackgroundTests.test_get_server_certificate', - # Probably the same as NetworkConnectionNoServer.test_create_connection_timeout - 'test_socket.NetworkConnectionNoServer.test_create_connection', - - # Internals of the threading module that change. - 'test_threading.ThreadTests.test_finalization_shutdown', - 'test_threading.ThreadTests.test_shutdown_locks', - # Expects a deprecation warning we don't raise - 'test_threading.ThreadTests.test_old_threading_api', - # This tries to use threading.interrupt_main() from a new Thread; - # but of course that's actually the same thread and things don't - # work as expected. - 'test_threading.InterruptMainTests.test_interrupt_main_subthread', - 'test_threading.InterruptMainTests.test_interrupt_main_noerror', - - # TLS1.3 seems flaky - 'test_ssl.ThreadedTests.test_wrong_cert_tls13', -] - - -if APPVEYOR: - disabled_tests += [ - # This sometimes produces ``self.assertEqual(1, len(s.select(0))): 1 != 0``. - # Probably needs to spin the loop once. - 'test_selectors.BaseSelectorTestCase.test_timeout', - # AssertionError: OSError not raised - 'test_socket.PurePythonSocketPairTest.test_injected_authentication_failure', - # subprocess.TimeoutExpired: Command '('C:\\Program Files\\Git\\usr\\bin\\true.EXE',)' - # timed out after -1 seconds - # Seen on 3.12.5 and 3.13.0rc1 - # Perhaps they changed handling of negative timeouts? Doesn't - # affect any other platforms though. - 'test_subprocess.ProcessTestCase.test_wait_negative_timeout', - ] - - -disabled_tests += [ - # This one seems very strict: doesn't want a pathlike - # first argument when shell is true. - 'test_subprocess.RunFuncTestCase.test_run_with_pathlike_path', - # This tests for a warning we don't raise. - 'test_subprocess.RunFuncTestCase.test_bufsize_equal_one_binary_mode', - - # This compares the output of threading.excepthook with - # data constructed in Python. But excepthook is implemented in C - # and can't see the patched threading.get_ident() we use, so the - # output doesn't match. - 'test_threading.ExceptHookTests.test_excepthook_thread_None', -] - -if sys.version_info[:3] < (3, 8, 1): - disabled_tests += [ - # Earlier versions parse differently so the newer test breaks - 'test_ssl.BasicSocketTests.test_parse_all_sans', - 'test_ssl.BasicSocketTests.test_parse_cert_CVE_2013_4238', - ] - -if sys.version_info[:3] < (3, 8, 10): - disabled_tests += [ - # These were added for fixes sometime between 3.8.1 and 3.8.10 - 'test_ftplib.TestFTPClass.test_makepasv_issue43285_security_disabled', - 'test_ftplib.TestFTPClass.test_makepasv_issue43285_security_enabled_default', - 'test_httplib.BasicTest.test_dir_with_added_behavior_on_status', - 'test_httplib.TunnelTests.test_tunnel_connect_single_send_connection_setup', - 'test_ssl.TestSSLDebug.test_msg_callback_deadlock_bpo43577', - # This one fails with the updated certs - 'test_ssl.ContextTests.test_load_verify_cadata', - # This one times out on 3.7.1 on Appveyor - 'test_ftplib.TestTLS_FTPClassMixin.test_retrbinary_rest', - ] - -if RESOLVER_DNSPYTHON: - disabled_tests += [ - # This does two things DNS python doesn't. First, it sends it - # capital letters and expects them to be returned lowercase. - # Second, it expects the symbolic scopeid to be stripped from the end. - 'test_socket.GeneralModuleTests.test_getaddrinfo_ipv6_scopeid_symbolic', - ] - -# if 'signalfd' in os.environ.get('GEVENT_BACKEND', ''): -# # tests that don't interact well with signalfd -# disabled_tests.extend([ -# 'test_signal.SiginterruptTest.test_siginterrupt_off', -# 'test_socketserver.SocketServerTest.test_ForkingTCPServer', -# 'test_socketserver.SocketServerTest.test_ForkingUDPServer', -# 'test_socketserver.SocketServerTest.test_ForkingUnixStreamServer']) - -# LibreSSL reports OPENSSL_VERSION_INFO (2, 0, 0, 0, 0) regardless of its version, -# so this is known to fail on some distros. We don't want to detect this because we -# don't want to trigger the side-effects of importing ssl prematurely if we will -# be monkey-patching, so we skip this test everywhere. It doesn't do much for us -# anyway. -disabled_tests += [ - 'test_ssl.BasicSocketTests.test_openssl_version' -] - -if OSX: - - disabled_tests += [ - # This sometimes produces OSError: Errno 40: Message too long - 'test_socket.RecvmsgIntoTCPTest.testRecvmsgIntoGenerator', - - # These sometime timeout. Cannot reproduce locally. - 'test_ftp.TestTLS_FTPClassMixin.test_mlsd', - 'test_ftp.TestTLS_FTPClassMixin.test_retrlines_too_long', - 'test_ftp.TestTLS_FTPClassMixin.test_storlines', - 'test_ftp.TestTLS_FTPClassMixin.test_retrbinary_rest', - ] - - if RESOLVER_ARES and not RUNNING_ON_CI: - disabled_tests += [ - # When updating to 1.16.0 this was seen locally, but not on CI. - # Tuples differ: ('ff02::1de:c0:face:8d', 1234, 0, 0) - # != ('ff02::1de:c0:face:8d', 1234, 0, 1) - 'test_socket.GeneralModuleTests.test_getaddrinfo_ipv6_scopeid_symbolic', - ] - - - -disabled_tests += [ - # Depends on exact details of the repr. Eww. - 'test_subprocess.ProcessTestCase.test_repr', - # Tries to wait for the process without using Popen APIs, and expects the - # ``returncode`` attribute to stay None. But we have already hooked SIGCHLD, so - # we see and set the ``returncode``; there is no way to wait that doesn't do that. - 'test_subprocess.POSIXProcessTestTest.test_send_signal_race', -] - - - -disabled_tests += [ - # They arbitrarily made some types so that they can't be created; - # that's an implementation detail we're not going to follow ( - # it would require them to be factory functions). - 'test_select.SelectTestCase.test_disallow_instantiation', - 'test_threading.ThreadTests.test_disallow_instantiation', - # This wants two true threads to work, but a CPU bound loop - # in a greenlet can't be interrupted. - 'test_threading.InterruptMainTests.test_can_interrupt_tight_loops', - # We don't currently implement pipesize. - 'test_subprocess.ProcessTestCase.test_pipesize_default', - 'test_subprocess.ProcessTestCase.test_pipesizes', - # Unknown - 'test_signal.SiginterruptTest.test_siginterrupt_off', -] - -if TRAVIS: - disabled_tests += [ - # The mixing of subinterpreters (with threads) and gevent apparently - # leads to a segfault on Ubuntu/GitHubActions/3.10rc1. Not clear why. - # But that's not a great use case for gevent. - 'test_threading.SubinterpThreadingTests.test_threads_join', - 'test_threading.SubinterpThreadingTests.test_threads_join_2', - ] - -if PY310_EXACTLY and APPVEYOR: - disabled_tests += [ - # On 3.9.13, this has been seen to cause - # - # SystemError: returned - # NULL without setting an error - # - # But this isn't even our code! That's a CPython function. Must be flaky. - # - # Also observed on 3.10.11. - 'test_socket.GeneralModuleTests.testInvalidInterfaceIndexToName', - ] - -if PY311: - disabled_tests += [ - # CPython issue #27718: This wants to require all objects to - # have a __module__ of 'signal' because pydoc. Obviously our patches don't. - 'test_signal.GenericTests.test_functions_module_attr', - # 3.11 added subprocess._USE_VFORK and subprocess._USE_POSIX_SPAWN. - # We don't support either of those (although USE_VFORK might be possible?) - 'test_subprocess.ProcessTestCase.test__use_vfork', - ] - - if sys.version_info[:3] < (3, 11, 8): - # New tests in that version that won't pass on earlier versions. - disabled_tests += [ - 'test_threading.ThreadTests.test_main_thread_after_fork_from_dummy_thread', - 'tets_ssl.TestPreHandshakeClose.test_preauth_data_to_tls_client', - 'test_ssl.TestPreHandshakeClose.test_preauth_data_to_tls_server', - 'test_signal.PosixTests.test_no_repr_is_called_on_signal_handler', - 'test_socket.GeneralModuleTests.testInvalidInterfaceIndexToName', - ] - - if WIN: - disabled_tests += [ - 'test_subprocess.ProcessTestCase.test_win32_duplicate_envs', - 'test_ssl.SimpleBackgroundTests.test_transport_eof', - 'test_ssl.SimpleBackgroundTests.test_bio_read_write_data', - 'test_ssl.SimpleBackgroundTests.test_bio_handshake', - 'test_httplib.ExtendedReadTestContentLengthKnown.test_readline_without_limit', - 'test_httplib.ExtendedReadTestContentLengthKnown.test_readline', - 'test_httplib.ExtendedReadTestContentLengthKnown.test_read1_unbounded', - 'test_httplib.ExtendedReadTestContentLengthKnown.test_read1_bounded', - 'test_httplib.ExtendedReadTestContentLengthKnown.test_read1', - 'test_httplib.HeaderTests.test_ipv6host_header', - ] - -if PY312: - disabled_tests += [ - # This test is new in 3.12.1; it appears to essentially rely - # on blocking sockets to fully read data in one call, and our - # version delivers a short initial read. - 'test_ssl.ThreadedTests.test_recv_into_buffer_protocol_len', - ] - - if sys.version_info[:3] < (3, 12, 1): - # Appveyor still has 3.12.0 when we added the 3.12.1 tests. - # Some of them depend on changes to the stdlib/interpreter. - disabled_tests += [ - 'test_httplib.HeaderTests.test_ipv6host_header', - 'test_interpreters.TestInterpreterClose.test_subthreads_still_running', - 'test_interpreters.TestInterpreterIsRunning.test_main', - 'test_interpreters.TestInterpreterIsRunning.test_with_only_background_threads', - 'test_interpreters.TestInterpreterRun.test_with_background_threads_still_running', - 'test_interpreters.FinalizationTests.test_gh_109793', - 'test_interpreters.StartupTests.test_sys_path_0', - 'test_threading.SubinterpThreadingTests.test_threads_join_with_no_main', - 'test_threading.MiscTestCase.test_gh112826_missing__thread__is_main_interpreter', - ] - - if sys.version_info[:3] < (3, 12, 11): - disabled_tests += [ - # This new tests crashes the interpreter on older versions - 'test_context.ContextTest.test_context_new_unhashable_str_subclass', - - # This is a new test that fails. - 'test_httplib.BasicTest.test_chunked', - ] - - if RUN_COVERAGE: - disabled_tests += [ - # This test wants to look for installed tracing functions, and - # having a coverage tracer function installed breaks it. - 'test_threading.ThreadTests.test_gettrace_all_threads', - ] - - if WIN: - disabled_tests += [ - # These three are looking for an error string that matches, - # and ours differs very slightly - 'test_socket.BasicHyperVTest.testCreateHyperVSocketAddrNotTupleFailure', - 'test_socket.BasicHyperVTest.testCreateHyperVSocketAddrServiceIdNotValidUUIDFailure', - 'test_socket.BasicHyperVTest.testCreateHyperVSocketAddrVmIdNotValidUUIDFailure', - ] - # Like the case for 3.12.1, these need VM or stdlib updates. - if sys.version_info[:3] < (3, 12, 2): - disabled_tests += [ - 'test_socket.GeneralModuleTests.testInvalidInterfaceIndexToName', - 'test_subprocess.ProcessTestCase.test_win32_duplicate_envs', - 'test_httplib.ExtendedReadTestContentLengthKnown.test_readline_without_limit', - 'test_httplib.ExtendedReadTestContentLengthKnown.test_readline', - 'test_httplib.ExtendedReadTestContentLengthKnown.test_read1_unbounded', - 'test_httplib.ExtendedReadTestContentLengthKnown.test_read1_bounded', - 'test_httplib.ExtendedReadTestContentLengthKnown.test_read1', - ] - - if LINUX and RUNNING_ON_CI: - disabled_tests += [ - # These two try to forcibly close a socket, preventing some data - # from reaching its destination. That works OK on some platforms, but - # in this set of circumstances, because of the event loop, gevent is - # able to send that data. - 'test_ssl.TestPreHandshakeClose.test_preauth_data_to_tls_client', - 'test_ssl.TestPreHandshakeClose.test_preauth_data_to_tls_server', - ] - - if ARES: - disabled_tests += [ - # c-ares doesn't like the IPv6 syntax it uses here. - 'test_socket.GeneralModuleTests.test_getaddrinfo_ipv6_scopeid_symbolic', - ] - - -if PY313: - disabled_tests += [ - # Creates a fork bomb because all the threads that have been created in the - # parent process continue running in each child process. - 'test_threading.ThreadJoinOnShutdown.test_reinit_tls_after_fork', - ] - - if OSX and RUNNING_ON_CI: - disabled_tests += [ - # Sometimes times out. Cannot reproduce locally. - 'test_signal.ItimerTest.test_itimer_virtual', - ] - - if APPVEYOR: - disabled_tests += [ - ] - - if sys.version_info[:3] < (3, 13, 3): - disabled_tests += [ - # 3.13.3 changed the way linecache works when non-file strings are being - # evaluated (backport from 3.14), which means this test won't run on anything - # older. It gets 2 lines when it expects 4. - # https://github.com/python/cpython/pull/117500 - 'test_subprocess.RunFuncTestCase.test_encoding_warning', - # This was a fix for a crash in the interpreter. - # https://github.com/python/cpython/issues/132002 - 'test_context.ContextTest.test_context_new_unhashable_str_subclass', - # This was modified in 3.13.3 for apparently a bugfix - # and won't run on older versions. - # https://github.com/python/cpython/commit/bf6c256a643b7066e922fb3a7e44aa3e006a29f3 - 'test_httplib.BasicTest.test_chunked', - ] - - if APPVEYOR: - disabled_tests += [ - - ] - -if PY314: - disabled_tests += [ - # Creates a pipe using ``os.pipe``, spawns a thread to write to it, and expects to - # be able to read from it using a standard file wrapped around the descriptor with - # ``open(fileno)``. The reading code gets run first because Reasons. The thread - # is monkey-patched to be a greenlet, but pipe and open are not patched, so - # we block forever attempting to read. This would be a potential problem for - # anything using the ``_running`` context manager. - 'test__interpreters.DestroyTests.test_still_running', - # Same. - 'test__interpreters.RunStringTests.test_already_running', - # Attempts to use ``signal.pthread_kill`` to send a signal to the - # main thread to interrupt it, but not kill it. Currently there is - # no way to emulate this behaviour with greenlets. - 'test_socketserver.SocketWriterTest.test_write', - # Tries to use ``sys.unraisablehook`` to catch exceptions - # from a background thread. We have no way to intercept that. - 'test_thread.ThreadRunningTests.test_unraisable_exception', - ] - - if ARES: - disabled_tests += [ - # ends up in ``urlib.request._is_local_authority`` for a local - # file URL. That passes it to ``gethostbyname`` and expects it to - # raise a ``socket.gaierror`` on invalid names. But the ares resolver - # raises a ``socket.herror``. I can't fix this without breaking other tests - # (I *think*) - 'test_urllib2.HandlerTests.test_file', - ] - -if TRAVIS: - disabled_tests += [ - # These tests frequently break when we try to use newer Travis CI images, - # due to different versions of OpenSSL being available. See above for some - # specific examples. Usually the tests catch up, eventually (e.g., at this writing, - # the 3.9b1 tests are fine on Ubuntu Bionic, but all other versions fail). - 'test_ssl.ContextTests.test_options', - 'test_ssl.ThreadedTests.test_alpn_protocols', - 'test_ssl.ThreadedTests.test_default_ecdh_curve', - 'test_ssl.ThreadedTests.test_shared_ciphers', - - ] - -if RUNNING_ON_MUSLLINUX: - disabled_tests += [ - # This is supposed to *not* crash, but on the muslilnux image, it - # does crash (exitcode -11, ie, SIGSEGV) - 'test_threading.ThreadingExceptionTests.test_recursion_limit', - ] - - -# Now build up the data structure we'll use to actually find disabled tests -# to avoid a linear scan for every file (it seems the list could get quite large) -# (First, freeze the source list to make sure it isn't modified anywhere) - -def _build_test_structure(sequence_of_tests): - - _disabled_tests = frozenset(sequence_of_tests) - - disabled_tests_by_file = collections.defaultdict(set) - for file_case_meth in _disabled_tests: - file_name, _rest = file_case_meth.split('.', 1) - - by_file = disabled_tests_by_file[file_name] - - by_file.add(file_case_meth) - - return disabled_tests_by_file - -_disabled_tests_by_file = _build_test_structure(disabled_tests) - -_wrapped_tests_by_file = _build_test_structure(wrapped_tests) - - -def disable_tests_in_source(source, filename): - # Source and filename are both native strings. - - if filename.startswith('./'): - # turn "./test_socket.py" (used for auto-complete) into "test_socket.py" - filename = filename[2:] - - if filename.endswith('.py'): - filename = filename[:-3] - - # XXX ignoring TestCase class name (just using function name). - # Maybe we should do this with the AST, or even after the test is - # imported. - my_disabled_tests = _disabled_tests_by_file.get(filename, ()) - my_wrapped_tests = _wrapped_tests_by_file.get(filename, {}) - - - if my_disabled_tests or my_wrapped_tests: - # Insert our imports early in the file. - # If we do it on a def-by-def basis, we can break syntax - # if the function is already decorated - pattern = r'^import .*' - replacement = r'from gevent.testing import patched_tests_setup as _GEVENT_PTS;' - replacement += r'import unittest as _GEVENT_UTS;' - replacement += r'\g<0>' - source, n = re.subn(pattern, replacement, source, - count=1, flags=re.MULTILINE) - - print("Added imports", n) - - # Test cases will always be indented some, - # so use [ \t]+. Without indentation, test_main, commonly used as the - # __main__ function at the top level, could get matched. \s matches - # newlines even in MULTILINE mode so it would still match that. - my_disabled_testcases = set() - for test in my_disabled_tests: - # test will be: - # test_module.TestClass.test_method - # or - # test_module.TestClass - if test.count('.') == 1: - _module, class_name = test.split('.') - # disabling a class. - # - # class CLifoTest(BaseCLass): - # -> - # class _GEVENT_DISABLE_ClifoTest: - # - # Unittest discover finds subclasses of TestCase, - # so make that not be true. This will fail if the definition - # crosses multiple lines... - pattern = r"class " + class_name + r'.*\):' - no_test_class_name = class_name.replace("Test", "") - replacement = 'class _GEVENT_DISABLE_' + no_test_class_name + ":" - source, n = re.subn(pattern, replacement, source, - flags=re.MULTILINE) - else: - testcase = test.split('.')[-1] - my_disabled_testcases.add(testcase) - # def foo_bar(self) - # -> - # @_GEVENT_UTS.skip('Removed by patched_tests_setup') - # def foo_bar(self) - pattern = r"^([ \t]+)def " + testcase - replacement = r"\1@_GEVENT_UTS.skip('Removed by patched_tests_setup: %s')\n" % (test,) - replacement += r"\g<0>" - source, n = re.subn(pattern, replacement, source, - flags=re.MULTILINE) - print('Skipped %s (%d)' % (test, n), file=sys.stderr) - - - for test in my_wrapped_tests: - testcase = test.split('.')[-1] - if testcase in my_disabled_testcases: - print("Not wrapping %s because it is skipped" % (test,)) - continue - - # def foo_bar(self) - # -> - # @_GEVENT_PTS._PatchedTest('file.Case.name') - # def foo_bar(self) - pattern = r"^([ \t]+)def " + testcase - replacement = r"\1@_GEVENT_PTS._PatchedTest('%s')\n" % (test,) - replacement += r"\g<0>" - - source, n = re.subn(pattern, replacement, source, 0, re.MULTILINE) - print('Wrapped %s (%d)' % (testcase, n), file=sys.stderr) - - return source diff --git a/venv/lib/python3.9/site-packages/gevent/testing/resources.py b/venv/lib/python3.9/site-packages/gevent/testing/resources.py deleted file mode 100644 index 547087e..0000000 --- a/venv/lib/python3.9/site-packages/gevent/testing/resources.py +++ /dev/null @@ -1,209 +0,0 @@ -# -*- coding: utf-8 -*- -# Copyright (c) 2018 gevent community -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. - -""" -Test environment setup. - -This establishes the resources that are available for use, -which are tested with `support.is_resource_enabled`. - -""" -from __future__ import absolute_import, division, print_function - -# This file may be imported early, so it should take care not to import -# things it doesn't need, which means deferred imports. - - -def get_ALL_RESOURCES(): - "Return a fresh list of resource names." - # RESOURCE_NAMES is the list of all known resources, including those that - # shouldn't be enabled by default or when asking for "all" resources. - # ALL_RESOURCES is the list of resources enabled by default or with "all" resources. - - try: - # 3.6 and 3.7 - from test.libregrtest import ALL_RESOURCES - except ImportError: - # 2.7 through 3.5 - - # Don't do this: - ## from test.regrtest import ALL_RESOURCES - - # On Python 2.7 to 3.5, importing regrtest iterates - # sys.modules and does modifications. That doesn't work well - # when it's imported from another module at module scope. - # Also, it makes some assumptions about module __file__ that - # may not hold true (at least on 2.7), especially when six or - # other module proxy objects are involved. - # So we hardcode the list. This is from 2.7, which is a superset - # of the defined resources through 3.5. - - ALL_RESOURCES = ( - 'audio', 'curses', 'largefile', 'network', 'bsddb', - 'decimal', 'cpu', 'subprocess', 'urlfetch', 'gui', - 'xpickle' - ) - - return list(ALL_RESOURCES) + [ - # Do we test the stdlib monkey-patched? - 'gevent_monkey', - ] - - -def parse_resources(resource_str=None): - # str -> Sequence[str] - - # Parse it like libregrtest.cmdline documents: - - # -u is used to specify which special resource intensive tests to run, - # such as those requiring large file support or network connectivity. - # The argument is a comma-separated list of words indicating the - # resources to test. Currently only the following are defined: - - # all - Enable all special resources. - # - # none - Disable all special resources (this is the default). - # - # network - It is okay to run tests that use external network - # resource, e.g. testing SSL support for sockets. - # - # - # subprocess Run all tests for the subprocess module. - # - # - # To enable all resources except one, use '-uall,-'. For - # example, to run all the tests except for the gui tests, give the - # option '-uall,-gui'. - - # We make a change though: we default to 'all' resources, instead of - # 'none'. Encountering either of those later in the string resets - # it, for ease of working with appending to environment variables. - - if resource_str is None: - import os - resource_str = os.environ.get('GEVENTTEST_USE_RESOURCES') - - resources = get_ALL_RESOURCES() - - if not resource_str: - return resources - - requested_resources = resource_str.split(',') - - for requested_resource in requested_resources: - # empty strings are ignored; this can happen when working with - # the environment variable if not already set: - # ENV=$ENV,-network - if not requested_resource: - continue - if requested_resource == 'all': - resources = get_ALL_RESOURCES() - elif requested_resource == 'none': - resources = [] - elif requested_resource.startswith('-'): - if requested_resource[1:] in resources: - resources.remove(requested_resource[1:]) - else: - # TODO: Produce a warning if it's an unknown resource? - resources.append(requested_resource) - - return resources - -def unparse_resources(resources): - """ - Given a list of enabled resources, produce the correct environment variable - setting to enable (only) that list. - """ - # By default, we assume all resources are enabled, so explicitly - # listing them here doesn't actually disable anything. To do that, we want to - # list the ones that are disabled. This is usually shorter than starting with - # 'none', and manually adding them back in one by one. - # - # 'none' must be special cased because an empty option string - # means 'all'. Still, we're explicit about that. - # - # TODO: Make this produce the minimal output; sometimes 'none' and - # adding would be shorter. - - all_resources = set(get_ALL_RESOURCES()) - enabled = set(resources) - - if enabled == all_resources: - result = 'all' - elif resources: - explicitly_disabled = all_resources - enabled - result = ''.join(sorted('-' + x for x in explicitly_disabled)) - else: - result = 'none' - return result - - -def setup_resources(resources=None): - """ - Call either with a list of resources or a resource string. - - If ``None`` is given, get the resource string from the environment. - """ - - if isinstance(resources, str) or resources is None: - resources = parse_resources(resources) - - from . import support - support.use_resources = list(resources) - support.gevent_has_setup_resources = True - - return resources - -def ensure_setup_resources(): - # Call when you don't know if resources have been setup and you want to - # get the environment variable if needed. - # Returns an object with `is_resource_enabled`. - from . import support - if not support.gevent_has_setup_resources: - setup_resources() - - return support - -def exit_without_resource(resource): - """ - Call this in standalone test modules that can't use unittest.SkipTest. - - Exits with a status of 0 if the resource isn't enabled. - """ - - if not ensure_setup_resources().is_resource_enabled(resource): - print("Skipped: %r not enabled" % (resource,)) - import sys - sys.exit(0) - -def skip_without_resource(resource, reason=''): - requires = 'Requires resource %r' % (resource,) - if not reason: - reason = requires - else: - reason = reason + ' (' + requires + ')' - - if not ensure_setup_resources().is_resource_enabled(resource): - import unittest - raise unittest.SkipTest(reason) - -if __name__ == '__main__': - print(setup_resources()) diff --git a/venv/lib/python3.9/site-packages/gevent/testing/six.py b/venv/lib/python3.9/site-packages/gevent/testing/six.py deleted file mode 100644 index c47abf4..0000000 --- a/venv/lib/python3.9/site-packages/gevent/testing/six.py +++ /dev/null @@ -1,14 +0,0 @@ -import builtins - -PY3 = True - -exec_ = getattr(builtins, "exec") - -def reraise(tp, value, tb=None): # pylint: disable=unused-argument - if value.__traceback__ is not tb: - raise value.with_traceback(tb) - raise value - -xrange = range -string_types = (str,) -text_type = str diff --git a/venv/lib/python3.9/site-packages/gevent/testing/skipping.py b/venv/lib/python3.9/site-packages/gevent/testing/skipping.py deleted file mode 100644 index 4713282..0000000 --- a/venv/lib/python3.9/site-packages/gevent/testing/skipping.py +++ /dev/null @@ -1,198 +0,0 @@ -# Copyright (c) 2018 gevent community -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. -from __future__ import absolute_import, print_function, division - -import functools -import unittest - -from . import sysinfo - -def _identity(f): - return f - -def _do_not_skip(reason): - assert reason - return _identity - - -skipOnMac = _do_not_skip -skipOnMacOnCI = _do_not_skip -skipOnWindows = _do_not_skip -skipOnAppVeyor = _do_not_skip -skipOnCI = _do_not_skip -skipOnManylinux = _do_not_skip - -skipOnPyPy = _do_not_skip -skipOnPyPyOnCI = _do_not_skip -skipOnPyPy3OnCI = _do_not_skip -skipOnPyPy3 = _do_not_skip -skipOnPyPyOnWindows = _do_not_skip - -skipOnPy3 = unittest.skip if sysinfo.PY3 else _do_not_skip -skipOnPy37 = unittest.skip -skipOnPy310 = unittest.skip -skipOnPy312 = unittest.skip if sysinfo.PY312 else _do_not_skip - -skipOnPurePython = unittest.skip if sysinfo.PURE_PYTHON else _do_not_skip -skipWithCExtensions = unittest.skip if not sysinfo.PURE_PYTHON else _do_not_skip - -skipOnLibuv = _do_not_skip -skipOnLibuvOnWin = _do_not_skip -skipOnLibuvOnCI = _do_not_skip -skipOnLibuvOnCIOnPyPy = _do_not_skip -skipOnLibuvOnPyPyOnWin = _do_not_skip - - -skipOnLibev = _do_not_skip - -if sysinfo.WIN: - skipOnWindows = unittest.skip - -if sysinfo.OSX: - skipOnMac = unittest.skip - -if sysinfo.RUNNING_ON_APPVEYOR: - # See comments scattered around about timeouts and the timer - # resolution available on appveyor (lots of jitter). this - # seems worse with the 62-bit builds. - # Note that we skip/adjust these tests only on AppVeyor, not - # win32---we don't think there's gevent related problems but - # environment related problems. These can be tested and debugged - # separately on windows in a more stable environment. - skipOnAppVeyor = unittest.skip - - -if sysinfo.RUNNING_ON_CI: - skipOnCI = unittest.skip - if sysinfo.OSX: - skipOnMacOnCI = unittest.skip - -if sysinfo.RUNNING_ON_MANYLINUX: - skipOnManylinux = unittest.skip - -if sysinfo.PYPY: - skipOnPyPy = unittest.skip - if sysinfo.RUNNING_ON_CI: - skipOnPyPyOnCI = unittest.skip - - if sysinfo.WIN: - skipOnPyPyOnWindows = unittest.skip - - if sysinfo.PYPY3: - skipOnPyPy3 = unittest.skip - if sysinfo.RUNNING_ON_CI: - # Same as above, for PyPy3.3-5.5-alpha and 3.5-5.7.1-beta and 3.5-5.8 - skipOnPyPy3OnCI = unittest.skip - - -skipUnderCoverage = unittest.skip if sysinfo.RUN_COVERAGE else _do_not_skip - -skipIf = unittest.skipIf -skipUnless = unittest.skipUnless - -_has_psutil_process = None -def _check_psutil(): - global _has_psutil_process - if _has_psutil_process is None: - _has_psutil_process = sysinfo.get_this_psutil_process() is not None - return _has_psutil_process - - -def _make_runtime_skip_decorator(reason, predicate): - def decorator(test_item): - if not isinstance(test_item, type): - f = test_item - @functools.wraps(test_item) - def skip_wrapper(*args, **kwargs): - if not predicate(): - raise unittest.SkipTest(reason) - return f(*args, **kwargs) - test_item = skip_wrapper - else: - # given a class, override setUp() to skip it. - # - # Internally, unittest uses two flags on the class to do this: - # __unittest_skip__ and __unittest_skip_why__. It *appears* - # these are evaluated for each method in the test, so we can safely - # change them at runtime. **This isn't documented.** - # - # If they are set before execution begins, then the class setUpClass - # and tearDownClass are skipped. So changing them at runtime could result - # in something being set up but not torn down. It is substantially - # faster, though, to set them. - base = test_item - base_setUp = base.setUp - @functools.wraps(test_item) - def setUp(self): - if not predicate(): - base.__unittest_skip__ = True - base.__unittest_skip_why__ = reason - raise unittest.SkipTest(reason) - base_setUp(self) - base.setUp = setUp - - return test_item - - return decorator - -def skipWithoutPSUtil(reason): - reason = "psutil not available: " + reason - # Defer the check until runtime to avoid imports - return _make_runtime_skip_decorator(reason, _check_psutil) - -if sysinfo.LIBUV: - skipOnLibuv = unittest.skip - - if sysinfo.RUNNING_ON_CI: - skipOnLibuvOnCI = unittest.skip - if sysinfo.PYPY: - skipOnLibuvOnCIOnPyPy = unittest.skip - - if sysinfo.WIN: - skipOnLibuvOnWin = unittest.skip - if sysinfo.PYPY: - skipOnLibuvOnPyPyOnWin = unittest.skip -else: - skipOnLibev = unittest.skip - - -def skipWithoutResource(resource, reason=''): - requires = 'Requires resource %r' % (resource,) - if not reason: - reason = requires - else: - reason = reason + ' (' + requires + ')' - - # Defer until runtime; resources are established as part - # of test startup. - def predicate(): # This is easily cached if needed - from . import resources - return resources.ensure_setup_resources().is_resource_enabled(resource) - - return _make_runtime_skip_decorator(reason, predicate) - -def skipWithoutExternalNetwork(reason=''): - # Use to decorate test functions or classes that - # need access to external network resources (e.g., DNS, HTTP servers, etc) - # - # Important: If you use this on classes, you must not use the - # two-argument form of super() - - return skipWithoutResource('network', reason) diff --git a/venv/lib/python3.9/site-packages/gevent/testing/sockets.py b/venv/lib/python3.9/site-packages/gevent/testing/sockets.py deleted file mode 100644 index 3604637..0000000 --- a/venv/lib/python3.9/site-packages/gevent/testing/sockets.py +++ /dev/null @@ -1,49 +0,0 @@ -# Copyright (c) 2018 gevent community -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. -from __future__ import absolute_import, print_function, division - -from .params import DEFAULT_BIND_ADDR_TUPLE - -def bind_and_listen(sock, address=DEFAULT_BIND_ADDR_TUPLE, backlog=50, reuse_addr=True): - from socket import SOL_SOCKET, SO_REUSEADDR, error - if reuse_addr: - try: - sock.setsockopt(SOL_SOCKET, SO_REUSEADDR, - sock.getsockopt(SOL_SOCKET, SO_REUSEADDR) | 1) - except error: - pass - sock.bind(address) - if backlog is not None: # udp - sock.listen(backlog) - - -def tcp_listener(address=DEFAULT_BIND_ADDR_TUPLE, backlog=50, reuse_addr=True): - """A shortcut to create a TCP socket, bind it and put it into listening state.""" - from gevent import socket - sock = socket.socket() - bind_and_listen(sock, address, backlog=backlog, reuse_addr=reuse_addr) - return sock - -def udp_listener(address=DEFAULT_BIND_ADDR_TUPLE, reuse_addr=True): - """A shortcut to create a UDF socket, bind it and put it into listening state.""" - from gevent import socket - sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) - bind_and_listen(sock, address, backlog=None, reuse_addr=reuse_addr) - return sock diff --git a/venv/lib/python3.9/site-packages/gevent/testing/support.py b/venv/lib/python3.9/site-packages/gevent/testing/support.py deleted file mode 100644 index f05fbd1..0000000 --- a/venv/lib/python3.9/site-packages/gevent/testing/support.py +++ /dev/null @@ -1,142 +0,0 @@ -# Copyright (c) 2018 gevent community -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. -""" -A re-export of the support module from Python's test package, with some -version compatibility shims and overrides. - -The manylinux docker images do not include test.support at all, for space reasons, -so we need to be vaguely functional to run tests in that environment. -""" - -import sys - -# Proxy through, so that changes to this module reflect in the real -# module too. (In 3.7, this is natively supported with __getattr__ at -# module scope.) This breaks static analysis (pylint), so we configure -# pylint to ignore this module. - -class _Default(object): - # A descriptor-like object that will - # only be used if the actual stdlib module - # doesn't have the value. - - def __init__(self, value): - self.value = value - -class _ModuleProxy(object): - - __slots__ = ('_this_mod', '_stdlib_support') - - def __init__(self): - self._this_mod = sys.modules[__name__] - self._stdlib_support = self - - def __get_stdlib_support(self): - if self._stdlib_support is self: - try: - from test import support as stdlib_support - except ImportError: - stdlib_support = None - self._stdlib_support = stdlib_support - - return self._stdlib_support - - def __getattr__(self, name): - try: - local_val = getattr(self._this_mod, name) - except AttributeError: - return getattr(self.__get_stdlib_support(), name) - - if isinstance(local_val, _Default): - try: - return getattr(self.__get_stdlib_support(), name) - except AttributeError: - return local_val.value - return local_val - - def __setattr__(self, name, value): - if name in _ModuleProxy.__slots__: - super(_ModuleProxy, self).__setattr__(name, value) - return - # Setting it deletes it from this module, so that - # we then continue to fall through to the original module. - try: - setattr(self.__get_stdlib_support(), name, value) - except AttributeError: - setattr(self._this_mod, name, value) - else: - try: - delattr(self._this_mod, name) - except AttributeError: - pass - - def __repr__(self): - return repr(self._this_mod) - -HOSTv6 = _Default('::1') -HOST = _Default("localhost") -HOSTv4 = _Default("127.0.0.1") -verbose = _Default(False) - -@_Default -def is_resource_enabled(_): - return False - -@_Default -def bind_port(sock, host=None): # pragma: no cover - import socket - host = host if host is not None else sys.modules[__name__].HOST - if sock.family == socket.AF_INET and sock.type == socket.SOCK_STREAM: - if hasattr(socket, 'SO_EXCLUSIVEADDRUSE'): - sock.setsockopt(socket.SOL_SOCKET, socket.SO_EXCLUSIVEADDRUSE, 1) # pylint:disable=no-member - - sock.bind((host, 0)) - port = sock.getsockname()[1] - return port - -@_Default -def find_unused_port(family=None, socktype=None): # pragma: no cover - import socket - family = family or socket.AF_INET - socktype = socktype or socket.SOCK_STREAM - tempsock = socket.socket(family, socktype) - try: - port = sys.modules[__name__].bind_port(tempsock) - finally: - tempsock.close() - del tempsock - return port - -@_Default -def threading_setup(): - return [] - -@_Default -def threading_cleanup(*_): - pass - -@_Default -def reap_children(): - pass - -# Set by resources.setup_resources() -gevent_has_setup_resources = False - -sys.modules[__name__] = _ModuleProxy() diff --git a/venv/lib/python3.9/site-packages/gevent/testing/switching.py b/venv/lib/python3.9/site-packages/gevent/testing/switching.py deleted file mode 100644 index d846dc8..0000000 --- a/venv/lib/python3.9/site-packages/gevent/testing/switching.py +++ /dev/null @@ -1,64 +0,0 @@ -# Copyright (c) 2018 gevent community -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. -from __future__ import absolute_import, print_function, division - -from functools import wraps - -from gevent.hub import _get_hub - -from .hub import QuietHub - -from .patched_tests_setup import get_switch_expected - -def wrap_switch_count_check(method): - @wraps(method) - def wrapper(self, *args, **kwargs): - initial_switch_count = getattr(_get_hub(), 'switch_count', None) - self.switch_expected = getattr(self, 'switch_expected', True) - if initial_switch_count is not None: - fullname = getattr(self, 'fullname', None) - if self.switch_expected == 'default' and fullname: - self.switch_expected = get_switch_expected(fullname) - result = method(self, *args, **kwargs) - if initial_switch_count is not None and self.switch_expected is not None: - switch_count = _get_hub().switch_count - initial_switch_count - if self.switch_expected is True: - assert switch_count >= 0 - if not switch_count: - raise AssertionError('%s did not switch' % fullname) - elif self.switch_expected is False: - if switch_count: - raise AssertionError('%s switched but not expected to' % fullname) - else: - raise AssertionError('Invalid value for switch_expected: %r' % (self.switch_expected, )) - return result - return wrapper - - - - -class CountingHub(QuietHub): - - switch_count = 0 - - def switch(self, *args): - # pylint:disable=arguments-differ - self.switch_count += 1 - return QuietHub.switch(self, *args) diff --git a/venv/lib/python3.9/site-packages/gevent/testing/sysinfo.py b/venv/lib/python3.9/site-packages/gevent/testing/sysinfo.py deleted file mode 100644 index ddc178f..0000000 --- a/venv/lib/python3.9/site-packages/gevent/testing/sysinfo.py +++ /dev/null @@ -1,241 +0,0 @@ -# Copyright (c) 2018 gevent community -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. -import errno -import os -import sys - -import gevent.core -from gevent import _compat as gsysinfo - -VERBOSE = sys.argv.count('-v') > 1 - -# Python implementations -PYPY = gsysinfo.PYPY -CPYTHON = not PYPY - -# Platform/operating system -WIN = gsysinfo.WIN -LINUX = gsysinfo.LINUX -OSX = gsysinfo.OSX - -PURE_PYTHON = gsysinfo.PURE_PYTHON - -get_this_psutil_process = gsysinfo.get_this_psutil_process - -# XXX: Formalize this better -LIBUV = 'libuv' in gevent.core.loop.__module__ # pylint:disable=no-member -CFFI_BACKEND = PYPY or LIBUV or 'cffi' in os.getenv('GEVENT_LOOP', '') - -if '--debug-greentest' in sys.argv: - sys.argv.remove('--debug-greentest') - DEBUG = True -else: - DEBUG = False - -RUN_LEAKCHECKS = os.getenv('GEVENTTEST_LEAKCHECK') -RUN_COVERAGE = os.getenv("COVERAGE_PROCESS_START") or os.getenv("GEVENTTEST_COVERAGE") - -# Generally, ignore the portions that are only implemented -# on particular platforms; they generally contain partial -# implementations completed in different modules. -PLATFORM_SPECIFIC_SUFFIXES = ('2', '279', '3') -if WIN: - PLATFORM_SPECIFIC_SUFFIXES += ('posix',) - - -PY310_EXACTLY = None -PY311 = None -PY312 = None -PY313 = None -PY314 = None - -NON_APPLICABLE_SUFFIXES = () -if sys.version_info[0] == 3: - # Python 3 - NON_APPLICABLE_SUFFIXES += ('2', '279') - PY3 = True - if sys.version_info[1] >= 10: - if sys.version_info[:2] == (3, 10): - PY310_EXACTLY = True - if sys.version_info[1] >= 11: - PY311 = True - if sys.version_info[1] >= 12: - PY312 = True - if sys.version_info[1] >= 13: - PY313 = True - if sys.version_info[1] >= 14: - PY314 = True - -else: # pragma: no cover - # Python 4? - raise ImportError('Unsupported major python version') - -PYPY3 = PYPY and PY3 - -if WIN: - NON_APPLICABLE_SUFFIXES += ("posix",) - # This is intimately tied to FileObjectPosix - NON_APPLICABLE_SUFFIXES += ("fileobject2",) - SHARED_OBJECT_EXTENSION = ".pyd" -else: - SHARED_OBJECT_EXTENSION = ".so" - -# We define GitHub actions to be similar to travis -RUNNING_ON_GITHUB_ACTIONS = os.environ.get('GITHUB_ACTIONS') -RUNNING_ON_TRAVIS = os.environ.get('TRAVIS') or RUNNING_ON_GITHUB_ACTIONS -RUNNING_ON_APPVEYOR = os.environ.get('APPVEYOR') -RUNNING_ON_CI = RUNNING_ON_TRAVIS or RUNNING_ON_APPVEYOR -RUNNING_ON_MANYLINUX = os.environ.get('GEVENT_MANYLINUX') -# I'm not sure how to reliably auto-detect this, without -# importing platform, something we don't want to do. -RUNNING_ON_MUSLLINUX = 'musllinux' in os.environ.get('GEVENT_MANYLINUX_NAME', '') - -if RUNNING_ON_APPVEYOR: - # We can't exec corecext on appveyor if we haven't run setup.py in - # 'develop' mode (i.e., we install) - NON_APPLICABLE_SUFFIXES += ('corecext',) - -EXPECT_POOR_TIMER_RESOLUTION = ( - PYPY3 - # Really, this is probably only in VMs. But that's all I test - # Windows with. - or WIN - or (LIBUV and PYPY) - or RUN_COVERAGE - or (OSX and RUNNING_ON_CI) -) - - -CONN_ABORTED_ERRORS = [] -def _make_socket_errnos(*names): - result = [] - for name in names: - try: - x = getattr(errno, name) - except AttributeError: - pass - else: - result.append(x) - return frozenset(result) - -CONN_ABORTED_ERRORS = _make_socket_errnos('WSAECONNABORTED', 'ECONNRESET') -CONN_REFUSED_ERRORS = _make_socket_errnos('WSAECONNREFUSED', 'ECONNREFUSED') - -RESOLVER_ARES = os.getenv('GEVENT_RESOLVER') == 'ares' -RESOLVER_DNSPYTHON = os.getenv('GEVENT_RESOLVER') == 'dnspython' - -RESOLVER_NOT_SYSTEM = RESOLVER_ARES or RESOLVER_DNSPYTHON - -def get_python_version(): - """ - Return a string of the simple python version, - such as '3.8.0b4'. Handles alpha, beta, release candidate, and final releases. - """ - version = '%s.%s.%s' % sys.version_info[:3] - if sys.version_info[3] == 'alpha': - version += 'a%s' % sys.version_info[4] - elif sys.version_info[3] == 'beta': - version += 'b%s' % sys.version_info[4] - elif sys.version_info[3] == 'candidate': - version += 'rc%s' % sys.version_info[4] - - return version - -def _parse_version(ver_str): - try: - from packaging.version import Version - # InvalidVersion is a type of ValueError - except ImportError: - import warnings - warnings.warn('packaging.version not available; assuming no advanced Linux backends') - raise ValueError - - try: - return Version(ver_str) - except ValueError: - import warnings - warnings.warn('Unable to parse version %s' % (ver_str,)) - raise - -def _check_linux_version_at_least(major, minor, error_kind): - # pylint:disable=too-many-return-statements - # ^ Yeah, but this is the most linear and simple way to - # write this. - from platform import system - if system() != 'Linux': - return False - - from platform import release as _release - release = _release() - try: - # Linux versions like '6.8.0-1014-azure' cannot be parsed - # by packaging.version.Version, and distutils.LooseVersion, which - # did handle that, is deprecated. Neither module is guaranteed to be available - # anyway, so do the best we can manually. - ver_strings = (release or '0').split('.', 2) - - if not ver_strings or int(ver_strings[0]) < major: # no way. - return False - - if int(ver_strings[0]) > major: # Way newer! - return True - - assert major == int(ver_strings[0]) # Exactly the major - - if len(ver_strings) < 2: # no minor version, assume no - return False - - if int(ver_strings[1]) < minor: - return False - - assert int(ver_strings[1]) >= minor, (ver_strings[1], minor) - return True - except AssertionError: - raise - except Exception: # pylint:disable=broad-exception-caught - import warnings - warnings.warn('Unable to parse version %r; assuming no %s support' % ( - release, error_kind - )) - return False - -def libev_supports_linux_aio(): - # libev requires kernel 4.19 or above to be able to support - # linux AIO. It can still be compiled in, but will fail to create - # the loop at runtime. - return _check_linux_version_at_least(4, 19, 'aio') - - -def libev_supports_linux_iouring(): - # libev requires kernel XXX to be able to support linux io_uring. - # It fails with the kernel in fedora rawhide (4.19.76) but - # works (doesn't fail catastrophically when asked to create one) - # with kernel 5.3.0 (Ubuntu Bionic) - return _check_linux_version_at_least(5, 3, 'iouring') - - -def resolver_dnspython_available(): - # Try hard not to leave around junk we don't have to. - from importlib import metadata - try: - metadata.distribution('dnspython') - except metadata.PackageNotFoundError: - return False - return True diff --git a/venv/lib/python3.9/site-packages/gevent/testing/testcase.py b/venv/lib/python3.9/site-packages/gevent/testing/testcase.py deleted file mode 100644 index 993306c..0000000 --- a/venv/lib/python3.9/site-packages/gevent/testing/testcase.py +++ /dev/null @@ -1,481 +0,0 @@ -# Copyright (c) 2018 gevent community -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. -from __future__ import absolute_import, print_function, division - -import sys -import os.path -from contextlib import contextmanager -from unittest import TestCase as BaseTestCase -from functools import wraps - -import gevent -from gevent._util import LazyOnClass -from gevent._compat import perf_counter -from gevent._compat import get_clock_info -from gevent._hub_local import get_hub_if_exists - -from . import sysinfo -from . import params -from . import leakcheck -from . import errorhandler -from . import flaky - -from .patched_tests_setup import get_switch_expected - -class TimeAssertMixin(object): - @flaky.reraises_flaky_timeout() - def assertTimeoutAlmostEqual(self, first, second, places=None, msg=None, delta=None): - try: - self.assertAlmostEqual(first, second, places=places, msg=msg, delta=delta) - except AssertionError: - flaky.reraiseFlakyTestTimeout() - - - if sysinfo.EXPECT_POOR_TIMER_RESOLUTION: - # pylint:disable=unused-argument - def assertTimeWithinRange(self, time_taken, min_time, max_time): - return - else: - def assertTimeWithinRange(self, time_taken, min_time, max_time): - self.assertLessEqual(time_taken, max_time) - self.assertGreaterEqual(time_taken, min_time) - - @contextmanager - def runs_in_given_time(self, expected, fuzzy=None, min_time=None): - if fuzzy is None: - if sysinfo.EXPECT_POOR_TIMER_RESOLUTION or sysinfo.LIBUV: - # The noted timer jitter issues on appveyor/pypy3 - fuzzy = expected * 5.0 - else: - fuzzy = expected / 2.0 - min_time = min_time if min_time is not None else expected - fuzzy - max_time = expected + fuzzy - start = perf_counter() - yield (min_time, max_time) - elapsed = perf_counter() - start - try: - self.assertTrue( - min_time <= elapsed <= max_time, - 'Expected: %r; elapsed: %r; min: %r; max: %r; fuzzy %r; clock_info: %s' % ( - expected, elapsed, min_time, max_time, fuzzy, get_clock_info('perf_counter') - )) - except AssertionError: - flaky.reraiseFlakyTestRaceCondition() - - def runs_in_no_time( - self, - fuzzy=(0.01 if not sysinfo.EXPECT_POOR_TIMER_RESOLUTION and not sysinfo.LIBUV else 1.0)): - return self.runs_in_given_time(0.0, fuzzy) - - -class GreenletAssertMixin(object): - """Assertions related to greenlets.""" - - def assert_greenlet_ready(self, g): - self.assertTrue(g.dead, g) - self.assertTrue(g.ready(), g) - self.assertFalse(g, g) - - def assert_greenlet_not_ready(self, g): - self.assertFalse(g.dead, g) - self.assertFalse(g.ready(), g) - - def assert_greenlet_spawned(self, g): - self.assertTrue(g.started, g) - self.assertFalse(g.dead, g) - - # No difference between spawned and switched-to once - assert_greenlet_started = assert_greenlet_spawned - - def assert_greenlet_finished(self, g): - self.assertFalse(g.started, g) - self.assertTrue(g.dead, g) - - -class StringAssertMixin(object): - """ - Assertions dealing with strings. - """ - - @LazyOnClass - def HEX_NUM_RE(self): - import re - return re.compile('-?0x[0123456789abcdef]+L?', re.I) - - def normalize_addr(self, s, replace='X'): - # https://github.com/PyCQA/pylint/issues/1127 - return self.HEX_NUM_RE.sub(replace, s) # pylint:disable=no-member - - def normalize_module(self, s, module=None, replace='module'): - if module is None: - module = type(self).__module__ - - return s.replace(module, replace) - - def normalize(self, s): - return self.normalize_module(self.normalize_addr(s)) - - def assert_nstr_endswith(self, o, val): - s = str(o) - n = self.normalize(s) - self.assertTrue(n.endswith(val), (s, n)) - - def assert_nstr_startswith(self, o, val): - s = str(o) - n = self.normalize(s) - self.assertTrue(n.startswith(val), (s, n)) - - - -class TestTimeout(gevent.Timeout): - _expire_info = '' - - def __init__(self, timeout, method='Not Given'): - gevent.Timeout.__init__( - self, - timeout, - '%r: test timed out (set class __timeout__ to increase)\n' % (method,), - ref=False - ) - - def _on_expiration(self, prev_greenlet, ex): - from gevent.util import format_run_info - loop = gevent.get_hub().loop - debug_info = 'N/A' - if hasattr(loop, 'debug'): - debug_info = [str(s) for s in loop.debug()] - run_info = format_run_info() - self._expire_info = 'Loop Debug:\n%s\nRun Info:\n%s' % ( - '\n'.join(debug_info), '\n'.join(run_info) - ) - gevent.Timeout._on_expiration(self, prev_greenlet, ex) - - def __str__(self): - s = gevent.Timeout.__str__(self) - s += self._expire_info - return s - -def _wrap_timeout(timeout, method): - if timeout is None: - return method - - @wraps(method) - def timeout_wrapper(self, *args, **kwargs): - with TestTimeout(timeout, method): - return method(self, *args, **kwargs) - - return timeout_wrapper - -def _get_class_attr(classDict, bases, attr, default=AttributeError): - NONE = object() - value = classDict.get(attr, NONE) - if value is not NONE: - return value - for base in bases: - value = getattr(base, attr, NONE) - if value is not NONE: - return value - if default is AttributeError: - raise AttributeError('Attribute %r not found\n%s\n%s\n' % (attr, classDict, bases)) - return default - - -class TestCaseMetaClass(type): - # wrap each test method with - # a) timeout check - # b) fatal error check - # c) restore the hub's error handler (see expect_one_error) - # d) totalrefcount check - def __new__(mcs, classname, bases, classDict): - # pylint and pep8 fight over what this should be called (mcs or cls). - # pylint gets it right, but we cant scope disable pep8, so we go with - # its convention. - # pylint: disable=bad-mcs-classmethod-argument - timeout = classDict.get('__timeout__', 'NONE') - if timeout == 'NONE': - timeout = getattr(bases[0], '__timeout__', None) - if sysinfo.RUN_LEAKCHECKS and timeout is not None: - timeout *= 6 - check_totalrefcount = _get_class_attr(classDict, bases, 'check_totalrefcount', True) - - error_fatal = _get_class_attr(classDict, bases, 'error_fatal', True) - uses_handle_error = _get_class_attr(classDict, bases, 'uses_handle_error', True) - # Python 3: must copy, we mutate the classDict. Interestingly enough, - # it doesn't actually error out, but under 3.6 we wind up wrapping - # and re-wrapping the same items over and over and over. - for key, value in list(classDict.items()): - if key.startswith('test') and callable(value): - classDict.pop(key) - # XXX: When did we stop doing this? - #value = wrap_switch_count_check(value) - value = _wrap_timeout(timeout, value) - error_fatal = getattr(value, 'error_fatal', error_fatal) - if error_fatal: - value = errorhandler.wrap_error_fatal(value) - if uses_handle_error: - value = errorhandler.wrap_restore_handle_error(value) - if check_totalrefcount and sysinfo.RUN_LEAKCHECKS: - value = leakcheck.wrap_refcount(value) - classDict[key] = value - return type.__new__(mcs, classname, bases, classDict) - -def _noop(): - return - -class SubscriberCleanupMixin(object): - - def setUp(self): - super(SubscriberCleanupMixin, self).setUp() - from gevent import events - self.__old_subscribers = events.subscribers[:] - - def addSubscriber(self, sub): - from gevent import events - events.subscribers.append(sub) - - def tearDown(self): - from gevent import events - events.subscribers[:] = self.__old_subscribers - super(SubscriberCleanupMixin, self).tearDown() - - -class TestCase( - # TestCaseMetaClass("NewBase", - # (SubscriberCleanupMixin, - # TimeAssertMixin, - # GreenletAssertMixin, - # StringAssertMixin, - # BaseTestCase,), - # {})): - SubscriberCleanupMixin, TimeAssertMixin, GreenletAssertMixin, - StringAssertMixin, BaseTestCase, - metaclass=TestCaseMetaClass -): - __timeout__ = params.LOCAL_TIMEOUT if not sysinfo.RUNNING_ON_CI else params.CI_TIMEOUT - - switch_expected = 'default' - #: Set this to true to cause errors that get reported to the hub to - #: always get propagated to the main greenlet. This can be done at the - #: class or method level. - #: .. caution:: This can hide errors and make it look like exceptions - #: are propagated even if they're not. - error_fatal = True - uses_handle_error = True - close_on_teardown = () - # This is really used by the SubscriberCleanupMixin - __old_subscribers = () # pylint:disable=unused-private-member - - def run(self, *args, **kwargs): # pylint:disable=signature-differs - if self.switch_expected == 'default': - self.switch_expected = get_switch_expected(self.fullname) - return super(TestCase, self).run(*args, **kwargs) - - def setUp(self): - super(TestCase, self).setUp() - # Especially if we're running in leakcheck mode, where - # the same test gets executed repeatedly, we need to update the - # current time. Tests don't always go through the full event loop, - # so that doesn't always happen. test__pool.py:TestPoolYYY.test_async - # tends to show timeouts that are too short if we don't. - # XXX: Should some core part of the loop call this? - hub = get_hub_if_exists() - if hub and hub.loop: - hub.loop.update_now() - self.close_on_teardown = [] - self.addCleanup(self._tearDownCloseOnTearDown) - - def _callTestMethod(self, method): - # 3.12 started raising a stupid warning about returning - # non-None from ``test_...()`` being deprecated. Since the - # test framework never cares about the return value anyway, - # this is an utterly pointless annoyance. Override the method - # that raises that deprecation. (Are the maintainers planning - # to make the return value _mean_ something someday? That's - # the only valid reason for them to do this. Answer: No, no - # they're not. They're just trying to protect people from - # writing broken tests that accidentally turn into generators - # or something. Which...if people don't notice their tests - # aren't working...well. Now, perhaps this got worse in the - # era of asyncio where *everything* is a generator. But that's - # not our problem; we have better ways of dealing with the - # shortcomings of asyncio, namely, don't use it. - # https://bugs.python.org/issue41322) - method() - - def tearDown(self): - if getattr(self, 'skipTearDown', False): - del self.close_on_teardown[:] - return - - cleanup = getattr(self, 'cleanup', _noop) - cleanup() - self._error = self._none - super(TestCase, self).tearDown() - - def _tearDownCloseOnTearDown(self): - while self.close_on_teardown: - x = self.close_on_teardown.pop() - close = getattr(x, 'close', x) - try: - close() - except Exception: # pylint:disable=broad-except - pass - - def _close_on_teardown(self, resource): - """ - *resource* either has a ``close`` method, or is a - callable. - """ - self.close_on_teardown.append(resource) - return resource - - @property - def testname(self): - return getattr(self, '_testMethodName', '') or getattr(self, '_TestCase__testMethodName') - - @property - def testcasename(self): - return self.__class__.__name__ + '.' + self.testname - - @property - def modulename(self): - return os.path.basename(sys.modules[self.__class__.__module__].__file__).rsplit('.', 1)[0] - - @property - def fullname(self): - return os.path.splitext(os.path.basename(self.modulename))[0] + '.' + self.testcasename - - _none = (None, None, None) - # (context, kind, value) - _error = _none - - def expect_one_error(self): - self.assertEqual(self._error, self._none) - gevent.get_hub().handle_error = self._store_error - - def _store_error(self, where, t, value, tb): - del tb - if self._error != self._none: - gevent.get_hub().parent.throw(t, value) - else: - self._error = (where, t, value) - - def peek_error(self): - return self._error - - def get_error(self): - try: - return self._error - finally: - self._error = self._none - - def assert_error(self, kind=None, value=None, error=None, where_type=None): - if error is None: - error = self.get_error() - econtext, ekind, evalue = error - if kind is not None: - self.assertIsInstance(kind, type) - self.assertIsNotNone( - ekind, - "Error must not be none %r" % (error,)) - assert issubclass(ekind, kind), error - if value is not None: - if isinstance(value, str): - self.assertEqual(str(evalue), value) - else: - self.assertIs(evalue, value) - if where_type is not None: - self.assertIsInstance(econtext, where_type) - return error - - def assertMonkeyPatchedFuncSignatures(self, mod_name, func_names=(), exclude=()): - # If inspect.getfullargspec is not available, - # We use inspect.getargspec because it's the only thing available - # in Python 2.7, but it is deprecated - # pylint:disable=deprecated-method,too-many-locals - import inspect - import warnings - from gevent.monkey import get_original - # XXX: Very similar to gevent.monkey.patch_module. Should refactor? - gevent_module = getattr(__import__('gevent.' + mod_name), mod_name) - module_name = getattr(gevent_module, '__target__', mod_name) - - funcs_given = True - if not func_names: - funcs_given = False - func_names = getattr(gevent_module, '__implements__') - - for func_name in func_names: - if func_name in exclude: - continue - gevent_func = getattr(gevent_module, func_name) - if not inspect.isfunction(gevent_func) and not funcs_given: - continue - - func = get_original(module_name, func_name) - - try: - with warnings.catch_warnings(): - getfullargspec = inspect.getfullargspec - gevent_sig = getfullargspec(gevent_func) - sig = getfullargspec(func) - except TypeError: - if funcs_given: - raise - # Can't do this one. If they specifically asked for it, - # it's an error, otherwise it's not. - # Python 3 can check a lot more than Python 2 can. - continue - self.assertEqual(sig.args, gevent_sig.args, func_name) - # The next two might not actually matter? - self.assertEqual(sig.varargs, gevent_sig.varargs, func_name) - self.assertEqual(sig.defaults, gevent_sig.defaults, func_name) - if hasattr(sig, 'keywords'): # the old version - msg = (func_name, sig.keywords, gevent_sig.keywords) - try: - self.assertEqual(sig.keywords, gevent_sig.keywords, msg) - except AssertionError: - # Ok, if we take `kwargs` and the original function doesn't, - # that's OK. We have to do that as a compatibility hack sometimes to - # work across multiple python versions. - self.assertIsNone(sig.keywords, msg) - self.assertEqual('kwargs', gevent_sig.keywords) - else: - # The new hotness. Unfortunately, we can't actually check these things - # until we drop Python 2 support from the shared code. The only known place - # this is a problem is python 3.11 socket.create_connection(), which we manually - # ignore. So the checks all pass as is. - self.assertEqual(sig.kwonlyargs, gevent_sig.kwonlyargs, func_name) - self.assertEqual(sig.kwonlydefaults, gevent_sig.kwonlydefaults, func_name) - # Should deal with others: https://docs.python.org/3/library/inspect.html#inspect.getfullargspec - - def assertEqualFlakyRaceCondition(self, a, b): - try: - self.assertEqual(a, b) - except AssertionError: - flaky.reraiseFlakyTestRaceCondition() - - if not hasattr(BaseTestCase, 'assertStartsWith'): # Added 3.14 - def assertStartsWith(self, s, prefix, msg=None): - self.assertTrue(s.startswith(prefix), msg or (s, prefix)) - - def assertNotMonkeyPatched(self): - from gevent import monkey - self.assertFalse(monkey.is_anything_patched()) diff --git a/venv/lib/python3.9/site-packages/gevent/testing/testrunner.py b/venv/lib/python3.9/site-packages/gevent/testing/testrunner.py deleted file mode 100644 index a1ae08e..0000000 --- a/venv/lib/python3.9/site-packages/gevent/testing/testrunner.py +++ /dev/null @@ -1,991 +0,0 @@ -# -*- coding: utf-8 -*- - -import re -import sys -import os -import glob -import operator -import traceback -import importlib - -from contextlib import contextmanager -from datetime import timedelta -from multiprocessing.pool import ThreadPool -from multiprocessing import cpu_count - -from gevent._util import Lazy - -from . import util -from .resources import parse_resources -from .resources import setup_resources -from .resources import unparse_resources -from .sysinfo import RUNNING_ON_CI -from .sysinfo import PYPY -from .sysinfo import RESOLVER_ARES -from .sysinfo import RUN_LEAKCHECKS -from .sysinfo import OSX -from . import travis - -# Import this while we're probably single-threaded/single-processed -# to try to avoid issues with PyPy 5.10. -# See https://bitbucket.org/pypy/pypy/issues/2769/systemerror-unexpected-internal-exception -try: - __import__('_testcapi') -except (ImportError, OSError): - # This can raise a wide variety of errors - pass - -TIMEOUT = 100 # seconds -AVAIL_NWORKERS = cpu_count() - 1 -DEFAULT_NWORKERS = int(os.environ.get('NWORKERS') or max(AVAIL_NWORKERS, 4)) -if DEFAULT_NWORKERS > 15: - DEFAULT_NWORKERS = 10 - - -if RUN_LEAKCHECKS: - # Capturing the stats takes time, and we run each - # test at least twice - TIMEOUT = 200 - -DEFAULT_RUN_OPTIONS = { - 'timeout': TIMEOUT -} - - -if RUNNING_ON_CI: - # Too many and we get spurious timeouts - DEFAULT_NWORKERS = min(4 if not OSX else 2, DEFAULT_NWORKERS) - - -def _package_relative_filename(filename, package): - if not os.path.isfile(filename) and package: - # Ok, try to locate it as a module in the package - package_dir = _dir_from_package_name(package) - return os.path.join(package_dir, filename) - return filename - -def _dir_from_package_name(package): - package_mod = importlib.import_module(package) - package_dir = os.path.dirname(package_mod.__file__) - return package_dir - - -class ResultCollector(object): - - def __init__(self): - self.total = 0 - self.failed = {} - self.passed = {} - self.total_cases = 0 - self.total_skipped = 0 - # Every RunResult reported: failed, passed, rerun - self._all_results = [] - self.reran = {} - - def __iadd__(self, result): - self._all_results.append(result) - - if not result: - self.failed[result.name] = result #[cmd, kwargs] - else: - self.passed[result.name] = True - self.total_cases += result.run_count - self.total_skipped += result.skipped_count - return self - - def __ilshift__(self, result): - """ - collector <<= result - - Stores the result, but does not count it towards - the number of cases run, skipped, passed or failed. - """ - self._all_results.append(result) - self.reran[result.name] = result - return self - - @property - def longest_running_tests(self): - """ - A new list of RunResult objects, sorted from longest running - to shortest running. - """ - return sorted(self._all_results, - key=operator.attrgetter('run_duration'), - reverse=True) - - -class FailFast(Exception): - pass - -class Runner(object): - - TIME_WAIT_REAP = 0.1 - TIME_WAIT_SPAWN = 0.05 - - def __init__(self, - tests, - *, - allowed_return_codes=(), - configured_failing_tests=(), - failfast=False, - quiet=False, - configured_run_alone_tests=(), - worker_count=DEFAULT_NWORKERS, - second_chance=False): - """ - :keyword allowed_return_codes: Return codes other than - 0 that are counted as a success. Needed because some versions - of Python give ``unittest`` weird return codes. - :keyword quiet: Set to True or False to explicitly choose. Set to - `None` to use the default, which may come from the environment variable - ``GEVENTTEST_QUIET``. - """ - self._tests = tests - self._configured_failing_tests = configured_failing_tests - self._quiet = quiet - self._configured_run_alone_tests = configured_run_alone_tests - - assert not (failfast and second_chance) - self._failfast = failfast - self._second_chance = second_chance - - self.results = ResultCollector() - self.results.total = len(self._tests) - self._running_jobs = [] - - self._worker_count = min(len(tests), worker_count) or 1 - self._allowed_return_codes = allowed_return_codes - - def _run_one(self, cmd, **kwargs): - kwargs['allowed_return_codes'] = self._allowed_return_codes - if self._quiet is not None: - kwargs['quiet'] = self._quiet - result = util.run(cmd, **kwargs) - if not result and self._second_chance: - self.results <<= result - util.log("> %s", result.name, color='warning') - result = util.run(cmd, **kwargs) - if not result and self._failfast: - # Under Python 3.9 (maybe older versions?), raising the - # SystemExit here (a background thread belonging to the - # pool) doesn't seem to work well. It gets stuck waiting - # for a lock? The job never shows up as finished. - raise FailFast(cmd) - self.results += result - - def _reap(self): - "Clean up the list of running jobs, returning how many are still outstanding." - for r in self._running_jobs[:]: - if not r.ready(): - continue - if r.successful(): - self._running_jobs.remove(r) - else: - r.get() - sys.exit('Internal error in testrunner.py: %r' % (r, )) - return len(self._running_jobs) - - def _reap_all(self): - util.log("Reaping %d jobs", len(self._running_jobs), color="debug") - while self._running_jobs: - if not self._reap(): - break - util.sleep(self.TIME_WAIT_REAP) - - def _spawn(self, pool, cmd, options): - while True: - if self._reap() < self._worker_count: - job = pool.apply_async(self._run_one, (cmd, ), options or {}) - self._running_jobs.append(job) - return - - util.sleep(self.TIME_WAIT_SPAWN) - - def __call__(self): - util.log("Running tests in parallel with concurrency %s %s." % ( - self._worker_count, - util._colorize('number', '(concurrency available: %d)' % AVAIL_NWORKERS) - ),) - # Setting global state, in theory we can be used multiple times. - # This is fine as long as we are single threaded and call these - # sequentially. - util.BUFFER_OUTPUT = self._worker_count > 1 or self._quiet - - start = util.perf_counter() - try: - self._run_tests() - except KeyboardInterrupt: - self._report(util.perf_counter() - start, exit=False) - util.log('(partial results)\n') - raise - except: - traceback.print_exc() - raise - - self._reap_all() - self._report(util.perf_counter() - start, exit=True) - - def _run_tests(self): - "Runs the tests, produces no report." - run_alone = [] - - tests = self._tests - pool = ThreadPool(self._worker_count) - try: - for cmd, options in tests: - options = options or {} - if matches(self._configured_run_alone_tests, cmd): - run_alone.append((cmd, options)) - else: - self._spawn(pool, cmd, options) - pool.close() - pool.join() - - if run_alone: - util.log("Running tests marked standalone") - for cmd, options in run_alone: - self._run_one(cmd, **options) - except KeyboardInterrupt: - try: - util.log('Waiting for currently running to finish...') - self._reap_all() - except KeyboardInterrupt: - pool.terminate() - raise - except: - pool.terminate() - raise - - def _report(self, elapsed_time, exit=False): - results = self.results - report( - results, - exit=exit, - took=elapsed_time, - configured_failing_tests=self._configured_failing_tests, - ) - - -class TravisFoldingRunner(object): - - def __init__(self, runner, travis_fold_msg): - self._runner = runner - self._travis_fold_msg = travis_fold_msg - self._travis_fold_name = str(int(util.perf_counter())) - - # A zope-style acquisition proxy would be convenient here. - run_tests = runner._run_tests - - def _run_tests(): - self._begin_fold() - try: - run_tests() - finally: - self._end_fold() - - runner._run_tests = _run_tests - - def _begin_fold(self): - travis.fold_start(self._travis_fold_name, - self._travis_fold_msg) - - def _end_fold(self): - travis.fold_end(self._travis_fold_name) - - def __call__(self): - return self._runner() - - -class Discovery(object): - package_dir = None - package = None - - def __init__( - self, - tests=None, - ignore_files=None, - ignored=(), - coverage=False, - package=None, - config=None, - allow_combine=True, - ): - self.config = config or {} - self.ignore = set(ignored or ()) - self.tests = tests - self.configured_test_options = config.get('TEST_FILE_OPTIONS', set()) - self.allow_combine = allow_combine - if ignore_files: - ignore_files = ignore_files.split(',') - for f in ignore_files: - self.ignore.update(set(load_list_from_file(f, package))) - - if coverage: - self.ignore.update(config.get('IGNORE_COVERAGE', set())) - - if package: - self.package = package - self.package_dir = _dir_from_package_name(package) - - class Discovered(object): - def __init__(self, package, configured_test_options, ignore, config, allow_combine): - self.orig_dir = os.getcwd() - self.configured_run_alone = config['RUN_ALONE'] - self.configured_failing_tests = config['FAILING_TESTS'] - self.package = package - self.configured_test_options = configured_test_options - self.allow_combine = allow_combine - self.ignore = ignore - - self.to_import = [] - self.std_monkey_patch_files = [] - self.no_monkey_patch_files = [] - - self.commands = [] - - @staticmethod - def __makes_simple_monkey_patch( - contents, - _patch_present=re.compile(br'[^#].*patch_all\(\)'), - _patch_indented=re.compile(br' .*patch_all\(\)') - ): - return ( - # A non-commented patch_all() call is present - bool(_patch_present.search(contents)) - # that is not indented (because that implies its not at the top-level, - # so some preconditions are being set) - and not _patch_indented.search(contents) - ) - - @staticmethod - def __file_allows_monkey_combine(contents): - return b'testrunner-no-monkey-combine' not in contents - - @staticmethod - def __file_allows_combine(contents): - return b'testrunner-no-combine' not in contents - - @staticmethod - def __calls_unittest_main_toplevel( - contents, - _greentest_main=re.compile(br' greentest.main\(\)'), - _unittest_main=re.compile(br' unittest.main\(\)'), - _import_main=re.compile(br'from gevent.testing import.*main'), - _main=re.compile(br' main\(\)'), - ): - # TODO: Add a check that this comes in a line directly after - # if __name__ == __main__. - return ( - _greentest_main.search(contents) - or _unittest_main.search(contents) - or (_import_main.search(contents) and _main.search(contents)) - ) - - def __has_config(self, filename): - return ( - RUN_LEAKCHECKS - or filename in self.configured_test_options - or filename in self.configured_run_alone - or matches(self.configured_failing_tests, filename) - ) - - def __can_monkey_combine(self, filename, contents): - return ( - self.allow_combine - and not self.__has_config(filename) - and self.__makes_simple_monkey_patch(contents) - and self.__file_allows_monkey_combine(contents) - and self.__file_allows_combine(contents) - and self.__calls_unittest_main_toplevel(contents) - ) - - @staticmethod - def __makes_no_monkey_patch(contents, _patch_present=re.compile(br'[^#].*patch_\w*\(')): - return not _patch_present.search(contents) - - def __can_nonmonkey_combine(self, filename, contents): - return ( - self.allow_combine - and not self.__has_config(filename) - and self.__makes_no_monkey_patch(contents) - and self.__file_allows_combine(contents) - and self.__calls_unittest_main_toplevel(contents) - ) - - def __begin_command(self): - cmd = [sys.executable, '-u'] - # XXX: -X track-resources is broken. This happened when I updated to - # PyPy 7.3.2. It started failing to even start inside the virtual environment - # with - # - # debug: OperationError: - # debug: operror-type: ImportError - # debug: operror-value: No module named traceback - # - # I don't know if this is PyPy's problem or a problem in virtualenv: - # - # virtualenv==20.0.35 - # virtualenv-clone==0.5.4 - # virtualenvwrapper==4.8.4 - # - # Deferring investigation until I need this... - - # if PYPY and PY2: - # # Doesn't seem to be an env var for this. - # # XXX: track-resources is broken in virtual environments - # # on 7.3.2. - # cmd.extend(('-X', 'track-resources')) - return cmd - - - def __add_test(self, qualified_name, filename, contents): - if b'TESTRUNNER' in contents: # test__monkey_patching.py - # XXX: Rework this to avoid importing. - # XXX: Rework this to allow test combining (it could write the files out and return - # them directly; we would use 'python -m gevent.monkey --module unittest ...) - self.to_import.append(qualified_name) - elif self.__can_monkey_combine(filename, contents): - self.std_monkey_patch_files.append(qualified_name if self.package else filename) - elif self.__can_nonmonkey_combine(filename, contents): - self.no_monkey_patch_files.append(qualified_name if self.package else filename) - else: - # XXX: For simple python module tests, try this with - # `runpy.run_module`, very similar to the way we run - # things for monkey patching. The idea here is that we - # can perform setup ahead of time (e.g., - # setup_resources()) in each test without having to do - # it manually or force calls or modifications to those - # tests. - cmd = self.__begin_command() - if self.package: - # Using a package is the best way to work with coverage 5 - # when we specify 'source = ' - cmd.append('-m' + qualified_name) - else: - cmd.append(filename) - - options = DEFAULT_RUN_OPTIONS.copy() - options.update(self.configured_test_options.get(filename, {})) - self.commands.append((cmd, options)) - - @staticmethod - def __remove_options(lst): - return [x for x in lst if x and not x.startswith('-')] - - def __expand_imports(self): - for qualified_name in self.to_import: - module = importlib.import_module(qualified_name) - for cmd, options in module.TESTRUNNER(): - if self.__remove_options(cmd)[-1] in self.ignore: - continue - self.commands.append((cmd, options)) - del self.to_import[:] - - def __combine_commands(self, files, group_size=5): - if not files: - return - - from itertools import groupby - cnt = [0, 0] - def make_group(_): - if cnt[0] > group_size: - cnt[0] = 0 - cnt[1] += 1 - cnt[0] += 1 - return cnt[1] - - for _, group in groupby(files, make_group): - - cmd = self.__begin_command() - cmd.append('-m') - cmd.append('unittest') - # cmd.append('-v') - for name in group: - cmd.append(name) - self.commands.insert(0, (cmd, DEFAULT_RUN_OPTIONS.copy())) - - del files[:] - - - def visit_file(self, filename): - # Support either 'gevent.tests.foo' or 'gevent/tests/foo.py' - if filename.startswith('gevent.tests'): - # XXX: How does this interact with 'package'? Probably not well - qualified_name = module_name = filename - filename = filename[len('gevent.tests') + 1:] - filename = filename.replace('.', os.sep) + '.py' - else: - module_name = os.path.splitext(filename)[0] - qualified_name = self.package + '.' + module_name if self.package else module_name - - # Also allow just 'foo' as a shortcut for 'gevent.tests.foo' - abs_filename = os.path.abspath(filename) - if ( - not os.path.exists(abs_filename) - and not filename.endswith('.py') - and os.path.exists(abs_filename + '.py') ): - abs_filename += '.py' - - with open(abs_filename, 'rb') as f: - # Some of the test files (e.g., test__socket_dns) are - # UTF8 encoded. Depending on the environment, Python 3 may - # try to decode those as ASCII, which fails with UnicodeDecodeError. - # Thus, be sure to open and compare in binary mode. - # Open the absolute path to make errors more clear, - # but we can't store the absolute path, our configuration is based on - # relative file names. - contents = f.read() - - self.__add_test(qualified_name, filename, contents) - - def visit_files(self, filenames): - for filename in filenames: - self.visit_file(filename) - with Discovery._in_dir(self.orig_dir): - self.__expand_imports() - self.__combine_commands(self.std_monkey_patch_files) - self.__combine_commands(self.no_monkey_patch_files) - - @staticmethod - @contextmanager - def _in_dir(package_dir): - olddir = os.getcwd() - if package_dir: - os.chdir(package_dir) - try: - yield - finally: - os.chdir(olddir) - - @Lazy - def discovered(self): - tests = self.tests - discovered = self.Discovered(self.package, self.configured_test_options, - self.ignore, self.config, self.allow_combine) - - # We need to glob relative names, our config is based on filenames still - with self._in_dir(self.package_dir): - if not tests: - tests = set(glob.glob('test_*.py')) - set(['test_support.py']) - else: - tests = set(tests) - - if self.ignore: - # Always ignore the designated list, even if tests - # were specified on the command line. This fixes a - # nasty interaction with - # test__threading_vs_settrace.py being run under - # coverage when 'grep -l subprocess test*py' is used - # to list the tests to run. - tests -= self.ignore - tests = sorted(tests) - discovered.visit_files(tests) - - return discovered - - def __iter__(self): - return iter(self.discovered.commands) # pylint:disable=no-member - - def __len__(self): - return len(self.discovered.commands) # pylint:disable=no-member - -def load_list_from_file(filename, package): - result = [] - if filename: - # pylint:disable=unspecified-encoding - with open(_package_relative_filename(filename, package)) as f: - for x in f: - x = x.split('#', 1)[0].strip() - if x: - result.append(x) - return result - - -def matches(possibilities, command, include_flaky=True): - if isinstance(command, list): - command = ' '.join(command) - for line in possibilities: - if not include_flaky and line.startswith('FLAKY '): - continue - line = line.replace('FLAKY ', '') - # Our configs are still mostly written in terms of file names, - # but the non-monkey tests are now using package names. - # Strip off '.py' from filenames to see if we match a module. - # XXX: This could be much better. Our command needs better structure. - if command.endswith(' ' + line) or command.endswith(line.replace(".py", '')): - return True - if ' ' not in command and command == line: - return True - return False - - -def format_seconds(seconds): - if seconds < 20: - return '%.1fs' % seconds - seconds = str(timedelta(seconds=round(seconds))) - if seconds.startswith('0:'): - seconds = seconds[2:] - return seconds - - -def _show_longest_running(result_collector, how_many=5): - longest_running_tests = result_collector.longest_running_tests - if not longest_running_tests: - return - # The only tricky part is handling repeats. we want to show them, - # but not count them as a distinct entry. - - util.log('\nLongest-running tests:') - length_of_longest_formatted_decimal = len('%.1f' % longest_running_tests[0].run_duration) - - frmt = '%' + str(length_of_longest_formatted_decimal) + '.1f seconds: %s' - seen_names = set() - for result in longest_running_tests: - util.log(frmt, result.run_duration, result.name) - seen_names.add(result.name) - if len(seen_names) >= how_many: - break - - - -def report(result_collector, # type: ResultCollector - exit=True, took=None, - configured_failing_tests=()): - # pylint:disable=redefined-builtin,too-many-branches,too-many-locals - total = result_collector.total - failed = result_collector.failed - passed = result_collector.passed - total_cases = result_collector.total_cases - total_skipped = result_collector.total_skipped - - _show_longest_running(result_collector) - - if took: - took = ' in %s' % format_seconds(took) - else: - took = '' - - failed_expected = [] - failed_unexpected = [] - passed_unexpected = [] - - for name in passed: - if matches(configured_failing_tests, name, include_flaky=False): - passed_unexpected.append(name) - - if passed_unexpected: - util.log('\n%s/%s unexpected passes', len(passed_unexpected), total, color='error') - print_list(passed_unexpected) - - if result_collector.reran: - util.log('\n%s/%s tests rerun', len(result_collector.reran), total, color='warning') - print_list(result_collector.reran) - - if failed: - util.log('\n%s/%s tests failed%s', len(failed), total, took, color='warning') - - for name in failed: - if matches(configured_failing_tests, name, include_flaky=True): - failed_expected.append(name) - else: - failed_unexpected.append(name) - - if failed_expected: - util.log('\n%s/%s expected failures', len(failed_expected), total, color='warning') - print_list(failed_expected) - - if failed_unexpected: - util.log('\n%s/%s unexpected failures', len(failed_unexpected), total, color='error') - print_list(failed_unexpected) - - util.log( - '\nRan %s tests%s in %s files%s', - total_cases, - util._colorize('skipped', " (skipped=%d)" % total_skipped) if total_skipped else '', - total, - took, - ) - - if exit: - if failed_unexpected: - sys.exit(min(100, len(failed_unexpected))) - if passed_unexpected: - sys.exit(101) - if total <= 0: - sys.exit('No tests found.') - - -def print_list(lst): - for name in lst: - util.log(' - %s', name) - -def _setup_environ(debug=False): - def not_set(key): - return not bool(os.environ.get(key)) - - if (not_set('PYTHONWARNINGS') - and (not sys.warnoptions - # Python 3.7 goes from [] to ['default'] for nothing - or sys.warnoptions == ['default'])): - # action:message:category:module:line - - # - when a warning matches - # more than one option, the action for the last matching - # option is performed. - # - action is one of : ignore, default, all, module, once, error - - # Enable default warnings such as ResourceWarning. - defaults = [ - 'default', - 'default::DeprecationWarning', - 'default::ResourceWarning' - ] - - os.environ['PYTHONWARNINGS'] = ','.join(defaults + [ - # action:message:category:module:line - - # On Python 3[.6], the system site.py module has - # "open(fullname, 'rU')" which produces the warning that - # 'U' is deprecated, so ignore warnings from site.py - 'ignore:::site:', - # pkgutil on Python 2 complains about missing __init__.py - 'ignore:::pkgutil:', - # importlib/_bootstrap.py likes to spit out "ImportWarning: - # can't resolve package from __spec__ or __package__, falling - # back on __name__ and __path__". I have no idea what that means, but it seems harmless - # and is annoying. - 'ignore:::importlib._bootstrap:', - 'ignore:::importlib._bootstrap_external:', - # importing ABCs from collections, not collections.abc - 'ignore:::pkg_resources._vendor.pyparsing:', - 'ignore:::dns.namedict:', - # dns.hash itself is being deprecated, importing it raises the warning; - # we don't import it, but dnspython still does - 'ignore:::dns.hash:', - # dns.zone uses some raw regular expressions - # without the r'' syntax, leading to DeprecationWarning: invalid - # escape sequence. This is fixed in 2.0 (Python 3 only). - 'ignore:::dns.zone:', - # Coverage has started issuing warnings when it can't import - # CTracer in subinterpreters. This breaks those tests. - 'ignore:::coverage.core:', - ]) - - if not_set('PYTHONFAULTHANDLER'): - os.environ['PYTHONFAULTHANDLER'] = 'true' - - if not_set('GEVENT_DEBUG') and debug: - os.environ['GEVENT_DEBUG'] = 'debug' - - if not_set('PYTHONTRACEMALLOC') and debug: - # This slows the tests down quite a bit. Reserve - # for debugging. - os.environ['PYTHONTRACEMALLOC'] = '10' - - if not_set('PYTHONDEVMODE'): - # Python 3.7 and above. - os.environ['PYTHONDEVMODE'] = '1' - - if not_set('PYTHONMALLOC') and debug: - # Python 3.6 and above. - # This slows the tests down some, but - # can detect memory corruption. Unfortunately - # it can also be flaky, especially in pre-release - # versions of Python (e.g., lots of crashes on Python 3.8b4). - os.environ['PYTHONMALLOC'] = 'debug' - - if sys.version_info.releaselevel != 'final' and not debug: - os.environ['PYTHONMALLOC'] = 'default' - os.environ['PYTHONDEVMODE'] = '' - - # PYTHONSAFEPATH breaks the assumptions of some tests, notably test_interpreters.py - os.environ.pop('PYTHONSAFEPATH', None) - - interesting_envs = { - k: os.environ[k] - for k in os.environ - if k.startswith(('PYTHON', 'GEVENT')) - } - widest_k = max(len(k) for k in interesting_envs) - for k, v in sorted(interesting_envs.items()): - util.log('%*s\t=\t%s', widest_k, k, v, color="debug") - - -def main(): - # pylint:disable=too-many-locals,too-many-statements,too-many-branches - import argparse - parser = argparse.ArgumentParser() - parser.add_argument('--ignore') - parser.add_argument( - '--discover', action='store_true', - help="Only print the tests found." - ) - parser.add_argument( - '--config', default='known_failures.py', - help="The path to the config file containing " - "FAILING_TESTS, IGNORED_TESTS and RUN_ALONE. " - "Defaults to %(default)s." - ) - parser.add_argument( - "--coverage", action="store_true", - help="Enable coverage recording with coverage.py." - ) - # TODO: Quiet and verbose should be mutually exclusive - parser.add_argument( - "--quiet", action="store_true", default=True, - help="Be quiet. Defaults to %(default)s. Also the " - "GEVENTTEST_QUIET environment variable." - ) - parser.add_argument("--verbose", action="store_false", dest='quiet') - - parser.add_argument( - "--debug", action="store_true", default=False, - help="Enable debug settings. If the GEVENT_DEBUG environment variable is not set, " - "this sets it to 'debug'. This can also enable PYTHONTRACEMALLOC and the debug PYTHONMALLOC " - "allocators, if not already set. Defaults to %(default)s." - ) - - parser.add_argument( - "--package", default="gevent.tests", - help="Load tests from the given package. Defaults to %(default)s." - ) - parser.add_argument( - "--processes", "-j", default=DEFAULT_NWORKERS, type=int, - help="Use up to the given number of parallel processes to execute tests. " - "Defaults to %(default)s." - ) - parser.add_argument( - '--no-combine', default=True, action='store_false', - help="Do not combine tests into process groups." - ) - parser.add_argument('-u', '--use', metavar='RES1,RES2,...', - action='store', type=parse_resources, - help='specify which special resource intensive tests ' - 'to run. "all" is the default; "none" may also be used. ' - 'Disable individual resources with a leading -.' - 'For example, "-u-network". GEVENTTEST_USE_RESOURCES is used ' - 'if no argument is given. To only use one resources, specify ' - '"-unone,resource".') - parser.add_argument("--travis-fold", metavar="MSG", - help="Emit Travis CI log fold markers around the output.") - - fail_parser = parser.add_mutually_exclusive_group() - fail_parser.add_argument( - "--second-chance", action="store_true", default=False, - help="Give failed tests a second chance.") - fail_parser.add_argument( - '--failfast', '-x', action='store_true', default=False, - help="Stop running after the first failure.") - - parser.add_argument('tests', nargs='*') - options = parser.parse_args() - # options.use will be either None for not given, or a list - # of the last specified -u argument. - # If not given, use the default, which we'll take from the environment, if set. - options.use = list(set(parse_resources() if options.use is None else options.use)) - - # Whether or not it came from the environment, put it in the - # environment now. - os.environ['GEVENTTEST_USE_RESOURCES'] = unparse_resources(options.use) - setup_resources(options.use) - - - # Set this before any test imports in case of 'from .util import QUIET'; - # not that this matters much because we spawn tests in subprocesses, - # it's the environment setting that matters - util.QUIET = options.quiet - if 'GEVENTTEST_QUIET' not in os.environ: - os.environ['GEVENTTEST_QUIET'] = str(options.quiet) - - FAILING_TESTS = [] - IGNORED_TESTS = [] - RUN_ALONE = [] - - coverage = False - if options.coverage or os.environ.get("GEVENTTEST_COVERAGE"): - if PYPY and RUNNING_ON_CI: - print("Ignoring coverage option on PyPy on CI; slow") - else: - coverage = True - cov_config = os.environ['COVERAGE_PROCESS_START'] = os.path.abspath(".coveragerc") - if PYPY: - cov_config = os.environ['COVERAGE_PROCESS_START'] = os.path.abspath(".coveragerc-pypy") - - this_dir = os.path.dirname(__file__) - site_dir = os.path.join(this_dir, 'coveragesite') - site_dir = os.path.abspath(site_dir) - os.environ['PYTHONPATH'] = site_dir + os.pathsep + os.environ.get("PYTHONPATH", "") - # We change directory often, use an absolute path to keep all the - # coverage files (which will have distinct suffixes because of parallel=true in .coveragerc - # in this directory; makes them easier to combine and use with coverage report) - os.environ['COVERAGE_FILE'] = os.path.abspath(".") + os.sep + ".coverage" - # XXX: Log this with color. Right now, it interferes (buffering) with other early - # output. - print("Enabling coverage to", os.environ['COVERAGE_FILE'], - "with site", site_dir, - "and configuration file", cov_config) - assert os.path.exists(cov_config) - assert os.path.exists(os.path.join(site_dir, 'sitecustomize.py')) - - _setup_environ(debug=options.debug) - - if options.config: - config = {} - options.config = _package_relative_filename(options.config, options.package) - with open(options.config) as f: # pylint:disable=unspecified-encoding - config_data = f.read() - exec(config_data, config) - FAILING_TESTS = config['FAILING_TESTS'] - IGNORED_TESTS = config['IGNORED_TESTS'] - RUN_ALONE = config['RUN_ALONE'] - - tests = Discovery( - options.tests, - ignore_files=options.ignore, - ignored=IGNORED_TESTS, - coverage=coverage, - package=options.package, - config=config, - allow_combine=options.no_combine, - ) - if options.discover: - for cmd, options in tests: - print(util.getname(cmd, env=options.get('env'), setenv=options.get('setenv'))) - print('%s tests found.' % len(tests)) - else: - if PYPY and RESOLVER_ARES: - # XXX: Add a way to force these. - print("Not running tests on pypy with c-ares; not a supported configuration") - return - - if options.package: - # Put this directory on the path so relative imports work. - package_dir = _dir_from_package_name(options.package) - os.environ['PYTHONPATH'] = os.environ.get('PYTHONPATH', "") + os.pathsep + package_dir - - allowed_return_codes = () - if sys.version_info[:3] >= (3, 12, 1): - # unittest suddenly started failing with this return code - # if all tests in a module are skipped in 3.12.1. - allowed_return_codes += (5,) - - runner = Runner( - tests, - allowed_return_codes=allowed_return_codes, - configured_failing_tests=FAILING_TESTS, - failfast=options.failfast, - quiet=options.quiet, - configured_run_alone_tests=RUN_ALONE, - worker_count=options.processes, - second_chance=options.second_chance, - ) - - if options.travis_fold: - runner = TravisFoldingRunner(runner, options.travis_fold) - - runner() - - -if __name__ == '__main__': - main() diff --git a/venv/lib/python3.9/site-packages/gevent/testing/timing.py b/venv/lib/python3.9/site-packages/gevent/testing/timing.py deleted file mode 100644 index d960710..0000000 --- a/venv/lib/python3.9/site-packages/gevent/testing/timing.py +++ /dev/null @@ -1,138 +0,0 @@ -# Copyright (c) 2018 gevent community -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. - -import gevent -from gevent._compat import perf_counter - -from . import sysinfo -from . import leakcheck -from .testcase import TestCase - -SMALLEST_RELIABLE_DELAY = 0.001 # 1ms, because of libuv - -SMALL_TICK = 0.01 -SMALL_TICK_MIN_ADJ = SMALLEST_RELIABLE_DELAY -SMALL_TICK_MAX_ADJ = 0.11 -if sysinfo.RUNNING_ON_APPVEYOR: - # Timing resolution is extremely poor on Appveyor - # and subject to jitter. - SMALL_TICK_MAX_ADJ = 1.5 - - -LARGE_TICK = 0.2 -LARGE_TICK_MIN_ADJ = LARGE_TICK / 2.0 -LARGE_TICK_MAX_ADJ = SMALL_TICK_MAX_ADJ - - -class _DelayWaitMixin(object): - - _default_wait_timeout = SMALL_TICK - _default_delay_min_adj = SMALL_TICK_MIN_ADJ - _default_delay_max_adj = SMALL_TICK_MAX_ADJ - - def wait(self, timeout): - raise NotImplementedError('override me in subclass') - - def _check_delay_bounds(self, timeout, delay, - delay_min_adj=None, - delay_max_adj=None): - delay_min_adj = self._default_delay_min_adj if not delay_min_adj else delay_min_adj - delay_max_adj = self._default_delay_max_adj if not delay_max_adj else delay_max_adj - self.assertTimeWithinRange(delay, - timeout - delay_min_adj, - timeout + delay_max_adj) - - def _wait_and_check(self, timeout=None): - if timeout is None: - timeout = self._default_wait_timeout - - # gevent.timer instances have a 'seconds' attribute, - # otherwise it's the raw number - seconds = getattr(timeout, 'seconds', timeout) - - gevent.get_hub().loop.update_now() - start = perf_counter() - try: - result = self.wait(timeout) - finally: - self._check_delay_bounds(seconds, perf_counter() - start, - self._default_delay_min_adj, - self._default_delay_max_adj) - return result - - def test_outer_timeout_is_not_lost(self): - timeout = gevent.Timeout.start_new(SMALLEST_RELIABLE_DELAY, ref=False) - try: - with self.assertRaises(gevent.Timeout) as exc: - self.wait(timeout=1) - self.assertIs(exc.exception, timeout) - finally: - timeout.close() - - -class AbstractGenericWaitTestCase(_DelayWaitMixin, TestCase): - # pylint:disable=abstract-method - - _default_wait_timeout = LARGE_TICK - _default_delay_min_adj = LARGE_TICK_MIN_ADJ - _default_delay_max_adj = LARGE_TICK_MAX_ADJ - - @leakcheck.ignores_leakcheck # waiting checks can be very sensitive to timing - def test_returns_none_after_timeout(self): - result = self._wait_and_check() - # join and wait simply return after timeout expires - self.assertIsNone(result) - - -class AbstractGenericGetTestCase(_DelayWaitMixin, TestCase): - # pylint:disable=abstract-method - - Timeout = gevent.Timeout - - def cleanup(self): - pass - - def test_raises_timeout_number(self): - with self.assertRaises(self.Timeout): - self._wait_and_check(timeout=SMALL_TICK) - # get raises Timeout after timeout expired - self.cleanup() - - def test_raises_timeout_Timeout(self): - timeout = gevent.Timeout(self._default_wait_timeout) - try: - self._wait_and_check(timeout=timeout) - except gevent.Timeout as ex: - self.assertIs(ex, timeout) - finally: - timeout.close() - self.cleanup() - - def test_raises_timeout_Timeout_exc_customized(self): - error = RuntimeError('expected error') - timeout = gevent.Timeout(self._default_wait_timeout, exception=error) - try: - with self.assertRaises(RuntimeError) as exc: - self._wait_and_check(timeout=timeout) - - self.assertIs(exc.exception, error) - self.cleanup() - finally: - timeout.close() diff --git a/venv/lib/python3.9/site-packages/gevent/testing/travis.py b/venv/lib/python3.9/site-packages/gevent/testing/travis.py deleted file mode 100644 index 81f1800..0000000 --- a/venv/lib/python3.9/site-packages/gevent/testing/travis.py +++ /dev/null @@ -1,41 +0,0 @@ -# -*- coding: utf-8 -*- -# Support functions for travis -# See https://github.com/travis-ci/travis-rubies/blob/9f7962a881c55d32da7c76baefc58b89e3941d91/build.sh - -from __future__ import absolute_import -from __future__ import division -from __future__ import print_function - -import sys - - -commands = {} - -def command(func): - commands[func.__name__] = lambda: func(*sys.argv[2:]) - return func - -@command -def fold_start(name, msg): - sys.stdout.write('travis_fold:start:') - sys.stdout.write(name) - sys.stdout.write(chr(0o33)) - sys.stdout.write('[33;1m') - sys.stdout.write(msg) - sys.stdout.write(chr(0o33)) - sys.stdout.write('[33;0m\n') - -@command -def fold_end(name): - sys.stdout.write("\ntravis_fold:end:") - sys.stdout.write(name) - sys.stdout.write("\r\n") - - -def main(): - cmd = sys.argv[1] - commands[cmd]() - - -if __name__ == '__main__': - main() diff --git a/venv/lib/python3.9/site-packages/gevent/testing/util.py b/venv/lib/python3.9/site-packages/gevent/testing/util.py deleted file mode 100644 index 1849183..0000000 --- a/venv/lib/python3.9/site-packages/gevent/testing/util.py +++ /dev/null @@ -1,654 +0,0 @@ -""" -.. caution:: - - This module imports `subprocess` and `threading`; this can - break monkey-patched unittests. Specifically, - ``test_threading.ThreadTests.test_import_from_another_thread``. -""" - -import re -import sys -import os -import traceback -import unittest -import threading -import subprocess -from time import sleep - -from gevent._config import validate_bool -from gevent._compat import perf_counter -from gevent.monkey import get_original - -# pylint: disable=broad-except,attribute-defined-outside-init - -BUFFER_OUTPUT = False -# This is set by the testrunner, defaulting to true (be quiet) -# But if we're run standalone, default to false -QUIET = validate_bool(os.environ.get('GEVENTTEST_QUIET', '0')) - - -class Popen(subprocess.Popen): - """ - Depending on when we're imported and if the process has been monkey-patched, - this could use cooperative or native Popen. - """ - timer = None # a threading.Timer instance - - def __enter__(self): - return self - - def __exit__(self, *args): - kill(self) - - -# Coloring code based on zope.testrunner - -# These colors are carefully chosen to have enough contrast -# on terminals with both black and white background. -_colorscheme = { - 'normal': 'normal', - 'default': 'default', - - 'actual-output': 'red', - 'character-diffs': 'magenta', - 'debug': 'cyan', - 'diff-chunk': 'magenta', - 'error': 'brightred', - 'error-number': 'brightred', - 'exception': 'red', - 'expected-output': 'green', - 'failed-example': 'cyan', - 'filename': 'lightblue', - 'info': 'normal', - 'lineno': 'lightred', - 'number': 'green', - 'ok-number': 'green', - 'skipped': 'brightyellow', - 'slow-test': 'brightmagenta', - 'suboptimal-behaviour': 'magenta', - 'testname': 'lightcyan', - 'warning': 'cyan', -} - -_prefixes = [ - ('dark', '0;'), - ('light', '1;'), - ('bright', '1;'), - ('bold', '1;'), -] - -_colorcodes = { - 'default': 0, - 'normal': 0, - 'black': 30, - 'red': 31, - 'green': 32, - 'brown': 33, 'yellow': 33, - 'blue': 34, - 'magenta': 35, - 'cyan': 36, - 'grey': 37, 'gray': 37, 'white': 37 -} - -def _color_code(color): - prefix_code = '' - for prefix, code in _prefixes: - if color.startswith(prefix): - color = color[len(prefix):] - prefix_code = code - break - color_code = _colorcodes[color] - return '\033[%s%sm' % (prefix_code, color_code) - -def _color(what): - return _color_code(_colorscheme[what]) - -def _colorize(what, message, normal='normal'): - return _color(what) + message + _color(normal) - -def log(message, *args, **kwargs): - """ - Log a *message* - - :keyword str color: One of the values from _colorscheme - """ - color = kwargs.pop('color', 'normal') - - if args: - string = message % args - else: - string = message - string = _colorize(color, string) - - with output_lock: # pylint:disable=not-context-manager - sys.stderr.write(string + '\n') - -def debug(message, *args, **kwargs): - """ - Log the *message* only if we're not in quiet mode. - """ - if not QUIET: - kwargs.setdefault('color', 'debug') - log(message, *args, **kwargs) - -def killpg(pid): - if not hasattr(os, 'killpg'): - return - try: - return os.killpg(pid, 9) - except OSError as ex: - if ex.errno != 3: - log('killpg(%r, 9) failed: %s: %s', pid, type(ex).__name__, ex) - except Exception as ex: - log('killpg(%r, 9) failed: %s: %s', pid, type(ex).__name__, ex) - - -def kill_processtree(pid): - ignore_msg = 'ERROR: The process "%s" not found.' % pid - err = Popen('taskkill /F /PID %s /T' % pid, stderr=subprocess.PIPE).communicate()[1] - if err and err.strip() not in [ignore_msg, '']: - log('%r', err) - - -def _kill(popen): - if hasattr(popen, 'kill'): - try: - popen.kill() - except OSError as ex: - if ex.errno == 3: # No such process - return - if ex.errno == 13: # Permission denied (translated from windows error 5: "Access is denied") - return - raise - else: - try: - os.kill(popen.pid, 9) - except EnvironmentError: - pass - - -def kill(popen): - if popen.timer is not None: - popen.timer.cancel() - popen.timer = None - if popen.poll() is not None: - return - popen.was_killed = True - try: - if getattr(popen, 'setpgrp_enabled', None): - killpg(popen.pid) - elif sys.platform.startswith('win'): - kill_processtree(popen.pid) - except Exception: - traceback.print_exc() - try: - _kill(popen) - except Exception: - traceback.print_exc() - try: - popen.wait() - except Exception: - traceback.print_exc() - -# A set of environment keys we ignore for printing purposes -IGNORED_GEVENT_ENV_KEYS = { - 'GEVENTTEST_QUIET', - 'GEVENT_DEBUG', - 'GEVENTSETUP_EV_VERIFY', - 'GEVENTSETUP_EMBED', -} - -# A set of (name, value) pairs we ignore for printing purposes. -# These should match the defaults. -IGNORED_GEVENT_ENV_ITEMS = { - ('GEVENT_RESOLVER', 'thread'), - ('GEVENT_RESOLVER_NAMESERVERS', '8.8.8.8'), - ('GEVENTTEST_USE_RESOURCES', 'all'), -} - -def getname(command, env=None, setenv=None): - result = [] - - env = (env or os.environ).copy() - env.update(setenv or {}) - - for key, value in sorted(env.items()): - if not key.startswith('GEVENT'): - continue - if key in IGNORED_GEVENT_ENV_KEYS: - continue - if (key, value) in IGNORED_GEVENT_ENV_ITEMS: - continue - result.append('%s=%s' % (key, value)) - - if isinstance(command, str): - result.append(command) - else: - result.extend(command) - - return ' '.join(result) - - -def start(command, quiet=False, **kwargs): - timeout = kwargs.pop('timeout', None) - preexec_fn = None - if not os.environ.get('DO_NOT_SETPGRP'): - preexec_fn = getattr(os, 'setpgrp', None) - env = kwargs.pop('env', None) - setenv = kwargs.pop('setenv', None) or {} - name = getname(command, env=env, setenv=setenv) - if preexec_fn is not None: - setenv['DO_NOT_SETPGRP'] = '1' - if setenv: - env = env.copy() if env else os.environ.copy() - env.update(setenv) - - if not quiet: - log('+ %s', name) - popen = Popen(command, preexec_fn=preexec_fn, env=env, **kwargs) - popen.name = name - popen.setpgrp_enabled = preexec_fn is not None - popen.was_killed = False - if timeout is not None: - t = get_original('threading', 'Timer')(timeout, kill, args=(popen, )) - popen.timer = t - t.daemon = True - t.start() - popen.timer = t - return popen - - -class RunResult(object): - """ - The results of running an external command. - - If the command was successful, this has a boolean - value of True; otherwise, a boolean value of false. - - The integer value of this object is the command's exit code. - """ - - def __init__(self, - command, - run_kwargs, - code, - output=None, # type: str - error=None, # type: str - name=None, - run_count=0, skipped_count=0, - run_duration=0, # type: float - ): - self.command = command - self.run_kwargs = run_kwargs - self.code = code - self.output = output - self.error = error - self.name = name - self.run_count = run_count - self.skipped_count = skipped_count - self.run_duration = run_duration - - @property - def output_lines(self): - return self.output.splitlines() - - def __bool__(self): - return not bool(self.code) - - __nonzero__ = __bool__ - - def __int__(self): - return self.code - - def __repr__(self): - return ( - "RunResult of: %r\n" - "Code: %s\n" - "kwargs: %r\n" - "Output:\n" - "----\n" - "%s" - "----\n" - "Error:\n" - "----\n" - "%s" - "----\n" - ) % ( - self.command, - self.code, - self.run_kwargs, - self.output, - self.error - ) - - -def _should_show_warning_output(out): - if 'Warning' in out: - # Strip out some patterns we specifically do not - # care about. - # from test.support for monkey-patched tests - out = out.replace('Warning -- reap_children', 'NADA') - out = out.replace("Warning -- threading_cleanup", 'NADA') - - # The below *could* be done with sophisticated enough warning - # filters passed to the children - - # collections.abc is the new home; setuptools uses the old one, - # as does dnspython - out = out.replace("DeprecationWarning: Using or importing the ABCs", 'NADA') - # libuv poor timer resolution - out = out.replace('UserWarning: libuv only supports', 'NADA') - # Packages on Python 2 - out = out.replace('ImportWarning: Not importing directory', 'NADA') - # Testing that U mode does the same thing - out = out.replace("DeprecationWarning: 'U' mode is deprecated", 'NADA') - out = out.replace("DeprecationWarning: dns.hash module", 'NADA') - return 'Warning' in out - -output_lock = threading.Lock() - -def _find_test_status(took, out): - status = '[took %.1fs%s]' - skipped = '' - run_count = 0 - skipped_count = 0 - if out: - m = re.search(r"Ran (\d+) tests in", out) - if m: - result = out[m.start():m.end()] - status = status.replace('took', result) - run_count = int(out[m.start(1):m.end(1)]) - - m = re.search(r' \(skipped=(\d+)\)$', out) - if m: - skipped = _colorize('skipped', out[m.start():m.end()]) - skipped_count = int(out[m.start(1):m.end(1)]) - status = status % (took, skipped) # pylint:disable=consider-using-augmented-assign - if took > 10: - status = _colorize('slow-test', status) - return status, run_count, skipped_count - - -def run(command, **kwargs): # pylint:disable=too-many-locals - """ - Execute *command*, returning a `RunResult`. - - This blocks until *command* finishes or until it times out. - """ - buffer_output = kwargs.pop('buffer_output', BUFFER_OUTPUT) - quiet = kwargs.pop('quiet', QUIET) - verbose = not quiet - nested = kwargs.pop('nested', False) - allowed_return_codes = kwargs.pop('allowed_return_codes', ()) - if buffer_output: - assert 'stdout' not in kwargs and 'stderr' not in kwargs, kwargs - kwargs['stderr'] = subprocess.STDOUT - kwargs['stdout'] = subprocess.PIPE - popen = start(command, quiet=quiet, **kwargs) - name = popen.name - - try: - time_start = perf_counter() - out, err = popen.communicate() - duration = perf_counter() - time_start - if popen.was_killed or popen.poll() is None: - result = 'TIMEOUT' - else: - result = popen.poll() - finally: - kill(popen) - assert popen.timer is None - - # We don't want to treat return codes that are allowed as failures, - # but we do want to log those specially. That's why we retain the distinction - # between ``failed`` and ``result`` (failed takes the allowed codes into account). - failed = bool(result) and result not in allowed_return_codes - if out: - out = out.strip() - out = out if isinstance(out, str) else out.decode('utf-8', 'ignore') - if out and (failed or verbose or _should_show_warning_output(out)): - out = ' ' + out.replace('\n', '\n ') - out = out.rstrip() - out += '\n' - log('| %s\n%s', name, out) - status, run_count, skipped_count = _find_test_status(duration, out) - if result: - log('! %s [code %s] %s', name, result, status, - color='error' if failed else 'suboptimal-behaviour') - elif not nested: - log('- %s %s', name, status) - - # For everything outside this function, we need to pretend that - # allowed codes are actually successes. - return RunResult( - command, kwargs, - 0 if result in allowed_return_codes else result, - output=out, error=err, - name=name, - run_count=run_count, - skipped_count=skipped_count, - run_duration=duration, - ) - - -class NoSetupPyFound(Exception): - "Raised by find_setup_py_above" - -def find_setup_py_above(a_file): - "Return the directory containing setup.py somewhere above *a_file*" - root = os.path.dirname(os.path.abspath(a_file)) - while not os.path.exists(os.path.join(root, 'setup.py')): - prev, root = root, os.path.dirname(root) - if root == prev: - # Let's avoid infinite loops at root - raise NoSetupPyFound('could not find my setup.py above %r' % (a_file,)) - return root - -def search_for_setup_py(a_file=None, a_module_name=None, a_class=None, climb_cwd=True): - if a_file is not None: - try: - return find_setup_py_above(a_file) - except NoSetupPyFound: - pass - - if a_class is not None: - try: - return find_setup_py_above(sys.modules[a_class.__module__].__file__) - except NoSetupPyFound: - pass - - if a_module_name is not None: - try: - return find_setup_py_above(sys.modules[a_module_name].__file__) - except NoSetupPyFound: - pass - - if climb_cwd: - return find_setup_py_above("./dne") - - raise NoSetupPyFound("After checking %r" % (locals(),)) - -def _version_dir_components(): - directory = '%s.%s' % sys.version_info[:2] - full_directory = '%s.%s.%s' % sys.version_info[:3] - if hasattr(sys, 'pypy_version_info'): - directory += 'pypy' - full_directory += 'pypy' - - return directory, full_directory - -def find_stdlib_tests(): - """ - Return a sequence of directories that could contain - stdlib tests for the running version of Python. - - The most specific tests are at the end of the sequence. - - No checks are performed on existence of the directories. - """ - setup_py = search_for_setup_py(a_file=__file__) - greentest = os.path.join(setup_py, 'src', 'greentest') - - - directory, full_directory = _version_dir_components() - - directory = '%s.%s' % sys.version_info[:2] - full_directory = '%s.%s.%s' % sys.version_info[:3] - if hasattr(sys, 'pypy_version_info'): - directory += 'pypy' - full_directory += 'pypy' - - directory = os.path.join(greentest, directory) - full_directory = os.path.join(greentest, full_directory) - - return directory, full_directory - -def absolute_pythonpath(): - """ - Return the PYTHONPATH environment variable (if set) with each - entry being an absolute path. If not set, returns None. - """ - if 'PYTHONPATH' not in os.environ: - return None - - path = os.environ['PYTHONPATH'] - path = [os.path.abspath(p) for p in path.split(os.path.pathsep)] - return os.path.pathsep.join(path) - -class ExampleMixin(object): - """ - Something that uses the ``examples/`` directory - from the root of the gevent distribution. - - The `cwd` property is set to the root of the gevent distribution. - """ - #: Arguments to pass to the example file. - example_args = [] - before_delay = 3 - after_delay = 0.5 - #: Path of the example Python file, relative to `cwd` - example = None # subclasses define this to be the path to the server.py - #: Keyword arguments to pass to the start or run method. - start_kwargs = None - - def find_setup_py(self): - "Return the directory containing setup.py" - return search_for_setup_py( - a_file=__file__, - a_class=type(self) - ) - - @property - def cwd(self): - try: - root = self.find_setup_py() - except NoSetupPyFound as e: - raise unittest.SkipTest("Unable to locate file/dir to run: %s" % (e,)) - return os.path.join(root, 'examples') - - @property - def setenv(self): - """ - Returns a dictionary of environment variables to set for the - child in addition to (or replacing) the ones already in the - environment. - - Since the child is run in `cwd`, relative paths in ``PYTHONPATH`` - need to be converted to absolute paths. - """ - abs_pythonpath = absolute_pythonpath() - return {'PYTHONPATH': abs_pythonpath} if abs_pythonpath else None - - def _start(self, meth): - if getattr(self, 'args', None): - raise AssertionError("Invalid test", self, self.args) - if getattr(self, 'server', None): - raise AssertionError("Invalid test", self, self.server) - - try: - # These could be or are properties that can raise - server = self.example - server_dir = self.cwd - except NoSetupPyFound as e: - raise unittest.SkipTest("Unable to locate file/dir to run: %s" % (e,)) - - kwargs = self.start_kwargs or {} - setenv = self.setenv - if setenv: - if 'setenv' in kwargs: - kwargs['setenv'].update(setenv) - else: - kwargs['setenv'] = setenv - return meth( - [sys.executable, '-W', 'ignore', '-u', server] + self.example_args, - cwd=server_dir, - **kwargs - ) - - def start_example(self): - return self._start(meth=start) - - def run_example(self):# run() is a unittest method. - return self._start(meth=run) - - -class TestServer(ExampleMixin, - unittest.TestCase): - popen = None - - def running_server(self): - from contextlib import contextmanager - - @contextmanager - def running_server(): - with self.start_example() as popen: - self.popen = popen - self.before() - yield - self.after() - return running_server() - - def test(self): - with self.running_server(): - self._run_all_tests() - - def before(self): - if self.before_delay is not None: - sleep(self.before_delay) - self.assertIsNone(self.popen.poll(), - '%s died with code %s' % ( - self.example, self.popen.poll(), - )) - - def after(self): - if self.after_delay is not None: - sleep(self.after_delay) - self.assertIsNone(self.popen.poll(), - '%s died with code %s' % ( - self.example, self.popen.poll(), - )) - - def _run_all_tests(self): - ran = False - for method in sorted(dir(self)): - if method.startswith('_test'): - function = getattr(self, method) - if callable(function): - function() - ran = True - assert ran - - -class alarm(threading.Thread): - # can't use signal.alarm because of Windows - - def __init__(self, timeout): - threading.Thread.__init__(self) - self.daemon = True - self.timeout = timeout - self.start() - - def run(self): - sleep(self.timeout) - sys.stderr.write('Timeout.\n') - os._exit(5) diff --git a/venv/lib/python3.9/site-packages/gevent/tests/2_7_keycert.pem b/venv/lib/python3.9/site-packages/gevent/tests/2_7_keycert.pem deleted file mode 100644 index d75a2aa..0000000 --- a/venv/lib/python3.9/site-packages/gevent/tests/2_7_keycert.pem +++ /dev/null @@ -1,81 +0,0 @@ ------BEGIN PRIVATE KEY----- -MIIJQwIBADANBgkqhkiG9w0BAQEFAASCCS0wggkpAgEAAoICAQChqfmG6uOG95Jb -7uRi6yxohJ8GOR3gi39yX6JB+Xdukvqxy2/vsjH1+CF1i8jKZZO0hJLGT+/GmKIc -1c0XUEjVoQvCNQHIaDTXiUXOGXfkQNKR0vtJH5ZOZn/tvYAKPniYPmHuF3TpAB6H -ouLpyIC55SXdK7pTEbmU7J1aBjugn3O56cu6FzjU1j/0QVUVGloxApLvv57bmINa -X9ygKsh/ug0lhV1RwYLJ9UX57m95FIlcofa98tCuoKi++G+sWsjopDXVmsiTbjZf -s72kcDUTRYKNZbRFRRETORdOVRHxlAIPEn4QFYn/3wVSNFvfeY0j8RI5YcPLU66B -atun6HU+YAs6z8Qc8S1EMElJdoyVeLCqLA07btICzKq2I16TZAOWVng2P7NOtibA -eCzDAxAxJ3Oby+BVikKcu8WmJLxGvRvaPljdD76xjPB5NK6O0J62C3uU3EWhPODX -9H5l/WF+aNRqSccgs0Umddj33N+b/mTJnHn1GpanThrv1UfOFGKfxjemwESz66d1 -iqD7iXvTxt7yZeU7LIMRgDqhVe6zoBpJEeWl9YYyfGPwgIOhwzNVZ5WkzQARs7si -3j3Wkmyca7hEN8qq8DkLWNf1PTcIwo/239wKRbyW3Z+U4IGRrVMdeSoC2JpRAx/e -EXTjuUePQlHCvwW9iiY7jTjDfbIvpwIDAQABAoICAC3CJMTRe3FaZezro210T2+O -Ck0CobhLA9nlw9GUwP9lTtxATwCzmXybrSzOUhknwzUXSUwkmCPIVCqBQbnVmagO -G3vu8QA+rqZLTpzVjJ/o0TFBXKsH681pKdCrELDVmeDN135C2W6SABI4Qq4VeIol -mCAQHn8gxzyl9Kvkk8AVIfZ/fJDBve5Qbm2+iEye1uSEa/68aEST2Kod9B7JvVKZ -4Nq78vwPH+v2JsZlfNvyuiakGWkOb47eHqVfQIyybaebwzkgxKEmUvGnuIfw0rUP -ubI4FVx9/iVIxZYAckHEuQh3HYOD9TmdcK4h79dDWnXP6G6hg3/rwbsT+fR+0aBQ -9rkKnA4uToGikYmplixAQ/jDBwMs3VQqenO+YBIsC4HEZ0fJUbs+l4LEnuUJxYcR -UlAvnVQXa1WGne3Yzb2xONWeiocKfhcdJ2JuQo00UR74+2Qonxn/WpimvlLCBDgI -uKxHCSWOgv5yPpU2kwTPIjORXcy/y2G9K2bnsQCzznPRDyNkZmavQxxG6greFcrO -/0yhRPuBgxKBRvXPO+F5fybKFlU9IPLFehV60jLUybBejab/lMJyxdkh9UMu2Xqy -FVsRGazJt6T6AGp6TFEEcFUQw7qXNhVo9S7zGGaJFJdYc+Vx8QJRoCe8EAYVH7Mp -b/eYGhHaKg6iG7QCjPPxAoIBAQDN54wtuDqpAA+4PmqhiEhQKhabNqAoVmAWUxnJ -Db4Zzvkkc3Fo/Yg0HnQVaT0KmkcxY7397lTdtiwNkWPgJ0f6+g7L4K7PA7xh/q84 -IoXFGvYWwVdiVXLR1l06jorpA20clnba6CsbezwcllTq4bWvNnrAcM8l1YrAlRnV -qqqbPL78Rnba4C8q+VFy8r0d9OGnbvFcV7VWJjhr0a3aZbHQ67jPinNiUWvBVFFx -yGrqPMjkeHyiTLMhqQpaSHH67S88rj0g9RKexBaSUrl18QO7xnQHHSCcFWMQOiSN -shNvFri48dnU+Ms6ZLc3MBHbTK6uzP8xJCVnmsz/MWPGkQZFAoIBAQDI/vj/3/y/ -EpIawyHN7PQAMoto4AQF6sVasrgGd1tRsJnGKrCugH9gILvyke3L7qg0JTV3bDJY -e8+vH1vC3NV7PsOlCFjMtRWG0lRbCh/b7Qe3pCvPu4mbFhJgMT/mz+vbl5zvcdgX -kvne+St/267NKnY5gHBDhqitBwkZwNlTWJ0zVmTecKXn/KwjS9lX1qU3HiT3UFkd -5Y5Nt5lj1IOK/6NCXkxVkgOc4Zjcxx138Cg03VJhIiHTusRq6z9iTSTDubhkaSbi -2nadptFBiQtkVhAJ5G53U7pl/pIhhiJy901bu/v/wrIMJ2l6hiZIcLrbg6VGXxjV -5dB7LDEtKoL7AoIBAQC8+ffA+mX0N9c1nSuWh5L+6DIJUHBbtTLJKonu6gsAeuJU -3xNGbfK1CwI1qHnaolAW91knlrcTKaBy726ACu1YXmp4GgW2f9JFCk/csGqfxaf4 -qIg/+va/ugOku7CoPXnGFB6PuSffOBKqlhrn3DI41kKBHsgwDDYlnHKylMmyYmVS -+oUZS0pfIaXsXvbNaLQ2TG9+9gy7Pabo5e+vE0jI25+p84MEyH+iV3XMfUoLI7Cp -aB/TgZuimBelVvotd8Sz56K4/dSSHJwuvXfz1Dk9/Nz+rnAAcOyTtxlXZwnJGkx9 -iZMIkTNMq6UwJJEu+ckVK5ZHjso5tWzSBo1xcCcVAoIBAQCPL0x1A7zK5VDd7cqE -J1w/U8KKiKN1D6VeElkUiiysyjERwdGxzmpvMYKSsDCGCdMbqrInDBXlgPYXnDBD -ZgxSywiW5ZZU5l+advWPEWxWwMmxoitvxfqmV5fpnMwYAmDUQ3KSBTjaumJ03G6H -nBkvoSMtnXjcMe6xrIRoK0Dmpgb+znn3GKqn1BFQ57TCZW+3DytoX33M1X6FkNie -DINVHv3Pxtt8ThNyzCeYh+RPT+9kkZIhDi6o5bENNd8miSw6nnBkX6BLFTRQ5MjH -dfh+luzAD1I+gZAVHsA9T4/09IXQZt+DeNBb5iu3FB/rlRsYS/UOZ6qKnjfhtz6l -HVbHAoIBAFjNY/UPJDxQ/uG+rMU0nrmSBRGdgBvQkcefjWX/LIZV3MjNilUQ+B2a -lXz5AHGmHRnnwQsBVfN8rf4qQLln8l34Kgm7+cIFavgfg2oqVbNyNgezSlUmRq0J -Ttf3xYJtRgRUx8F+BcgJXMqlNGTMQJY8wawM/ATkwkbmSwGOKe04sBeIkwEycMId -BupvfN5lxDrKqJVPSl1t5Rh4us95CNh22/c5Tq5rsynl02ZB4swlcsVTdv8FSGmM -QVf/MkWXGN/x4lHJhKyklHMGv15GGvys1nlPTstMfUYs55ioWRW46TXQ8vOyzzpg -67xzBKYFEde+hgYk7X1Xeqj8A6bsqro= ------END PRIVATE KEY----- ------BEGIN CERTIFICATE----- -MIIFCzCCAvOgAwIBAgIUePnEKFfhxpt3oypt6nTicAGTFJowDQYJKoZIhvcNAQEL -BQAwFDESMBAGA1UEAwwJbG9jYWxob3N0MCAXDTIxMDcwODExMzQzNVoYDzIxMjEw -NjE0MTEzNDM1WjAUMRIwEAYDVQQDDAlsb2NhbGhvc3QwggIiMA0GCSqGSIb3DQEB -AQUAA4ICDwAwggIKAoICAQChqfmG6uOG95Jb7uRi6yxohJ8GOR3gi39yX6JB+Xdu -kvqxy2/vsjH1+CF1i8jKZZO0hJLGT+/GmKIc1c0XUEjVoQvCNQHIaDTXiUXOGXfk -QNKR0vtJH5ZOZn/tvYAKPniYPmHuF3TpAB6HouLpyIC55SXdK7pTEbmU7J1aBjug -n3O56cu6FzjU1j/0QVUVGloxApLvv57bmINaX9ygKsh/ug0lhV1RwYLJ9UX57m95 -FIlcofa98tCuoKi++G+sWsjopDXVmsiTbjZfs72kcDUTRYKNZbRFRRETORdOVRHx -lAIPEn4QFYn/3wVSNFvfeY0j8RI5YcPLU66Batun6HU+YAs6z8Qc8S1EMElJdoyV -eLCqLA07btICzKq2I16TZAOWVng2P7NOtibAeCzDAxAxJ3Oby+BVikKcu8WmJLxG -vRvaPljdD76xjPB5NK6O0J62C3uU3EWhPODX9H5l/WF+aNRqSccgs0Umddj33N+b -/mTJnHn1GpanThrv1UfOFGKfxjemwESz66d1iqD7iXvTxt7yZeU7LIMRgDqhVe6z -oBpJEeWl9YYyfGPwgIOhwzNVZ5WkzQARs7si3j3Wkmyca7hEN8qq8DkLWNf1PTcI -wo/239wKRbyW3Z+U4IGRrVMdeSoC2JpRAx/eEXTjuUePQlHCvwW9iiY7jTjDfbIv -pwIDAQABo1MwUTAdBgNVHQ4EFgQUTUfShFbaXGMwrWEAkm05sXFH/x4wHwYDVR0j -BBgwFoAUTUfShFbaXGMwrWEAkm05sXFH/x4wDwYDVR0TAQH/BAUwAwEB/zANBgkq -hkiG9w0BAQsFAAOCAgEAe65ORDx0NDxTo1q6EY221KS3vEezUNBdZNaeOQsQeUAY -lEO5iZ+2QLIVlWC5UtvISK96FU2CX0ucgAGfHS2ZB7o8i95fbjG2qrWC+VUH4V/6 -jse9jlfGlYGkPuU5onNIDGcZ7gay3n0prCDiguAmCzV419GnGDWgSSgyVNCp/0tx -b7pR5cVr0kZ5bTZjiysEEprkG2ofAlXzj09VGtTfM8gQvCz9Puj7pGzw2iaIEQVk -hSGjoRWlI5x6+o16JOTHXzv9cYRUfDX6tjw3nQJIeMipuUkR8pkHUFjG3EeJEtO3 -X/GO0G8rwUPaZiskGPiMZj7XqoVclnYL7JtntwUHR/dU5A/EhDfhgEfTXTqT78Oe -cKri+VJE+G/hYxbP0FNYaDtqIwJcX1tsy4HOpKVBncc+K/PvXElVsyQET/+uwH7p -Wm5ymndnuLoiQrWIA4nJC6rVwR4GPijuN0NCKcVdE+8jlOCBs3VBJTWKuu0J80RP -71iZy03AoK1YY4+nHglmE9HetAgSsbGh2fWC7DUS/4JzLSzOBeb+nn74zfmIfMU+ -qUArFXvVGAtjmZZ/63cWzXDMZsp1BZ+O5dx6Gi2QtjgGYhh6DhW7ocQYXDkAeN/O -K1Yzwq/G4AEQA0k0/1I+F0Rdlo41+7tOp+LMCOoZXqUzhM0ZQ2sf3QclubxLX9U= ------END CERTIFICATE----- diff --git a/venv/lib/python3.9/site-packages/gevent/tests/__init__.py b/venv/lib/python3.9/site-packages/gevent/tests/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/venv/lib/python3.9/site-packages/gevent/tests/__main__.py b/venv/lib/python3.9/site-packages/gevent/tests/__main__.py deleted file mode 100644 index e43891f..0000000 --- a/venv/lib/python3.9/site-packages/gevent/tests/__main__.py +++ /dev/null @@ -1,6 +0,0 @@ -#!/usr/bin/env python -from __future__ import print_function, absolute_import, division - -if __name__ == '__main__': - from gevent.testing import testrunner - testrunner.main() diff --git a/venv/lib/python3.9/site-packages/gevent/tests/_blocks_at_top_level.py b/venv/lib/python3.9/site-packages/gevent/tests/_blocks_at_top_level.py deleted file mode 100644 index 9f907aa..0000000 --- a/venv/lib/python3.9/site-packages/gevent/tests/_blocks_at_top_level.py +++ /dev/null @@ -1,3 +0,0 @@ -from gevent import sleep -sleep(0.01) -x = "done" diff --git a/venv/lib/python3.9/site-packages/gevent/tests/_import_import_patch.py b/venv/lib/python3.9/site-packages/gevent/tests/_import_import_patch.py deleted file mode 100644 index aa85abd..0000000 --- a/venv/lib/python3.9/site-packages/gevent/tests/_import_import_patch.py +++ /dev/null @@ -1 +0,0 @@ -__import__('_import_patch') diff --git a/venv/lib/python3.9/site-packages/gevent/tests/_import_patch.py b/venv/lib/python3.9/site-packages/gevent/tests/_import_patch.py deleted file mode 100644 index 9d7cc3c..0000000 --- a/venv/lib/python3.9/site-packages/gevent/tests/_import_patch.py +++ /dev/null @@ -1,2 +0,0 @@ -import gevent.monkey -gevent.monkey.patch_all() diff --git a/venv/lib/python3.9/site-packages/gevent/tests/_import_wait.py b/venv/lib/python3.9/site-packages/gevent/tests/_import_wait.py deleted file mode 100644 index 80850a5..0000000 --- a/venv/lib/python3.9/site-packages/gevent/tests/_import_wait.py +++ /dev/null @@ -1,26 +0,0 @@ -# test__import_wait.py calls this via an import statement, -# so all of this is happening with import locks held (especially on py2) -import gevent - - -def fn2(): - return 2 - - -# A blocking function doesn't raise LoopExit -def fn(): - return gevent.wait([gevent.spawn(fn2), gevent.spawn(fn2)]) - -gevent.spawn(fn).get() - - -# Marshalling the traceback across greenlets doesn't -# raise LoopExit -def raise_name_error(): - raise NameError("ThisIsExpected") - -try: - gevent.spawn(raise_name_error).get() - raise AssertionError("Should fail") -except NameError as e: - x = e diff --git a/venv/lib/python3.9/site-packages/gevent/tests/_imports_at_top_level.py b/venv/lib/python3.9/site-packages/gevent/tests/_imports_at_top_level.py deleted file mode 100644 index d11f66b..0000000 --- a/venv/lib/python3.9/site-packages/gevent/tests/_imports_at_top_level.py +++ /dev/null @@ -1,2 +0,0 @@ -# We simply import a stdlib module -__import__('netrc') diff --git a/venv/lib/python3.9/site-packages/gevent/tests/_imports_imports_at_top_level.py b/venv/lib/python3.9/site-packages/gevent/tests/_imports_imports_at_top_level.py deleted file mode 100644 index 00bbf51..0000000 --- a/venv/lib/python3.9/site-packages/gevent/tests/_imports_imports_at_top_level.py +++ /dev/null @@ -1,13 +0,0 @@ -import gevent - -# For reproducing #728: We spawn a greenlet at import time, -# that itself wants to import, and wait on it at import time. -# If we're the only greenlet running, and locks aren't granular -# enough, this results in a LoopExit (and also a lock deadlock) - - -def f(): - __import__('_imports_at_top_level') - -g = gevent.spawn(f) -g.get() diff --git a/venv/lib/python3.9/site-packages/gevent/tests/badcert.pem b/venv/lib/python3.9/site-packages/gevent/tests/badcert.pem deleted file mode 100644 index c419146..0000000 --- a/venv/lib/python3.9/site-packages/gevent/tests/badcert.pem +++ /dev/null @@ -1,36 +0,0 @@ ------BEGIN RSA PRIVATE KEY----- -MIICXwIBAAKBgQC8ddrhm+LutBvjYcQlnH21PPIseJ1JVG2HMmN2CmZk2YukO+9L -opdJhTvbGfEj0DQs1IE8M+kTUyOmuKfVrFMKwtVeCJphrAnhoz7TYOuLBSqt7lVH -fhi/VwovESJlaBOp+WMnfhcduPEYHYx/6cnVapIkZnLt30zu2um+DzA9jQIDAQAB -AoGBAK0FZpaKj6WnJZN0RqhhK+ggtBWwBnc0U/ozgKz2j1s3fsShYeiGtW6CK5nU -D1dZ5wzhbGThI7LiOXDvRucc9n7vUgi0alqPQ/PFodPxAN/eEYkmXQ7W2k7zwsDA -IUK0KUhktQbLu8qF/m8qM86ba9y9/9YkXuQbZ3COl5ahTZrhAkEA301P08RKv3KM -oXnGU2UHTuJ1MAD2hOrPxjD4/wxA/39EWG9bZczbJyggB4RHu0I3NOSFjAm3HQm0 -ANOu5QK9owJBANgOeLfNNcF4pp+UikRFqxk5hULqRAWzVxVrWe85FlPm0VVmHbb/ -loif7mqjU8o1jTd/LM7RD9f2usZyE2psaw8CQQCNLhkpX3KO5kKJmS9N7JMZSc4j -oog58yeYO8BBqKKzpug0LXuQultYv2K4veaIO04iL9VLe5z9S/Q1jaCHBBuXAkEA -z8gjGoi1AOp6PBBLZNsncCvcV/0aC+1se4HxTNo2+duKSDnbq+ljqOM+E7odU+Nq -ewvIWOG//e8fssd0mq3HywJBAJ8l/c8GVmrpFTx8r/nZ2Pyyjt3dH1widooDXYSV -q6Gbf41Llo5sYAtmxdndTLASuHKecacTgZVhy0FryZpLKrU= ------END RSA PRIVATE KEY----- ------BEGIN CERTIFICATE----- -Just bad cert data ------END CERTIFICATE----- ------BEGIN RSA PRIVATE KEY----- -MIICXwIBAAKBgQC8ddrhm+LutBvjYcQlnH21PPIseJ1JVG2HMmN2CmZk2YukO+9L -opdJhTvbGfEj0DQs1IE8M+kTUyOmuKfVrFMKwtVeCJphrAnhoz7TYOuLBSqt7lVH -fhi/VwovESJlaBOp+WMnfhcduPEYHYx/6cnVapIkZnLt30zu2um+DzA9jQIDAQAB -AoGBAK0FZpaKj6WnJZN0RqhhK+ggtBWwBnc0U/ozgKz2j1s3fsShYeiGtW6CK5nU -D1dZ5wzhbGThI7LiOXDvRucc9n7vUgi0alqPQ/PFodPxAN/eEYkmXQ7W2k7zwsDA -IUK0KUhktQbLu8qF/m8qM86ba9y9/9YkXuQbZ3COl5ahTZrhAkEA301P08RKv3KM -oXnGU2UHTuJ1MAD2hOrPxjD4/wxA/39EWG9bZczbJyggB4RHu0I3NOSFjAm3HQm0 -ANOu5QK9owJBANgOeLfNNcF4pp+UikRFqxk5hULqRAWzVxVrWe85FlPm0VVmHbb/ -loif7mqjU8o1jTd/LM7RD9f2usZyE2psaw8CQQCNLhkpX3KO5kKJmS9N7JMZSc4j -oog58yeYO8BBqKKzpug0LXuQultYv2K4veaIO04iL9VLe5z9S/Q1jaCHBBuXAkEA -z8gjGoi1AOp6PBBLZNsncCvcV/0aC+1se4HxTNo2+duKSDnbq+ljqOM+E7odU+Nq -ewvIWOG//e8fssd0mq3HywJBAJ8l/c8GVmrpFTx8r/nZ2Pyyjt3dH1widooDXYSV -q6Gbf41Llo5sYAtmxdndTLASuHKecacTgZVhy0FryZpLKrU= ------END RSA PRIVATE KEY----- ------BEGIN CERTIFICATE----- -Just bad cert data ------END CERTIFICATE----- diff --git a/venv/lib/python3.9/site-packages/gevent/tests/badkey.pem b/venv/lib/python3.9/site-packages/gevent/tests/badkey.pem deleted file mode 100644 index 1c8a955..0000000 --- a/venv/lib/python3.9/site-packages/gevent/tests/badkey.pem +++ /dev/null @@ -1,40 +0,0 @@ ------BEGIN RSA PRIVATE KEY----- -Bad Key, though the cert should be OK ------END RSA PRIVATE KEY----- ------BEGIN CERTIFICATE----- -MIICpzCCAhCgAwIBAgIJAP+qStv1cIGNMA0GCSqGSIb3DQEBBQUAMIGJMQswCQYD -VQQGEwJVUzERMA8GA1UECBMIRGVsYXdhcmUxEzARBgNVBAcTCldpbG1pbmd0b24x -IzAhBgNVBAoTGlB5dGhvbiBTb2Z0d2FyZSBGb3VuZGF0aW9uMQwwCgYDVQQLEwNT -U0wxHzAdBgNVBAMTFnNvbWVtYWNoaW5lLnB5dGhvbi5vcmcwHhcNMDcwODI3MTY1 -NDUwWhcNMTMwMjE2MTY1NDUwWjCBiTELMAkGA1UEBhMCVVMxETAPBgNVBAgTCERl -bGF3YXJlMRMwEQYDVQQHEwpXaWxtaW5ndG9uMSMwIQYDVQQKExpQeXRob24gU29m -dHdhcmUgRm91bmRhdGlvbjEMMAoGA1UECxMDU1NMMR8wHQYDVQQDExZzb21lbWFj -aGluZS5weXRob24ub3JnMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC8ddrh -m+LutBvjYcQlnH21PPIseJ1JVG2HMmN2CmZk2YukO+9LopdJhTvbGfEj0DQs1IE8 -M+kTUyOmuKfVrFMKwtVeCJphrAnhoz7TYOuLBSqt7lVHfhi/VwovESJlaBOp+WMn -fhcduPEYHYx/6cnVapIkZnLt30zu2um+DzA9jQIDAQABoxUwEzARBglghkgBhvhC -AQEEBAMCBkAwDQYJKoZIhvcNAQEFBQADgYEAF4Q5BVqmCOLv1n8je/Jw9K669VXb -08hyGzQhkemEBYQd6fzQ9A/1ZzHkJKb1P6yreOLSEh4KcxYPyrLRC1ll8nr5OlCx -CMhKkTnR6qBsdNV0XtdU2+N25hqW+Ma4ZeqsN/iiJVCGNOZGnvQuvCAGWF8+J/f/ -iHkC6gGdBJhogs4= ------END CERTIFICATE----- ------BEGIN RSA PRIVATE KEY----- -Bad Key, though the cert should be OK ------END RSA PRIVATE KEY----- ------BEGIN CERTIFICATE----- -MIICpzCCAhCgAwIBAgIJAP+qStv1cIGNMA0GCSqGSIb3DQEBBQUAMIGJMQswCQYD -VQQGEwJVUzERMA8GA1UECBMIRGVsYXdhcmUxEzARBgNVBAcTCldpbG1pbmd0b24x -IzAhBgNVBAoTGlB5dGhvbiBTb2Z0d2FyZSBGb3VuZGF0aW9uMQwwCgYDVQQLEwNT -U0wxHzAdBgNVBAMTFnNvbWVtYWNoaW5lLnB5dGhvbi5vcmcwHhcNMDcwODI3MTY1 -NDUwWhcNMTMwMjE2MTY1NDUwWjCBiTELMAkGA1UEBhMCVVMxETAPBgNVBAgTCERl -bGF3YXJlMRMwEQYDVQQHEwpXaWxtaW5ndG9uMSMwIQYDVQQKExpQeXRob24gU29m -dHdhcmUgRm91bmRhdGlvbjEMMAoGA1UECxMDU1NMMR8wHQYDVQQDExZzb21lbWFj -aGluZS5weXRob24ub3JnMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC8ddrh -m+LutBvjYcQlnH21PPIseJ1JVG2HMmN2CmZk2YukO+9LopdJhTvbGfEj0DQs1IE8 -M+kTUyOmuKfVrFMKwtVeCJphrAnhoz7TYOuLBSqt7lVHfhi/VwovESJlaBOp+WMn -fhcduPEYHYx/6cnVapIkZnLt30zu2um+DzA9jQIDAQABoxUwEzARBglghkgBhvhC -AQEEBAMCBkAwDQYJKoZIhvcNAQEFBQADgYEAF4Q5BVqmCOLv1n8je/Jw9K669VXb -08hyGzQhkemEBYQd6fzQ9A/1ZzHkJKb1P6yreOLSEh4KcxYPyrLRC1ll8nr5OlCx -CMhKkTnR6qBsdNV0XtdU2+N25hqW+Ma4ZeqsN/iiJVCGNOZGnvQuvCAGWF8+J/f/ -iHkC6gGdBJhogs4= ------END CERTIFICATE----- diff --git a/venv/lib/python3.9/site-packages/gevent/tests/getaddrinfo_module.py b/venv/lib/python3.9/site-packages/gevent/tests/getaddrinfo_module.py deleted file mode 100644 index 75a25df..0000000 --- a/venv/lib/python3.9/site-packages/gevent/tests/getaddrinfo_module.py +++ /dev/null @@ -1,4 +0,0 @@ -import socket -import gevent.socket as gevent_socket - -gevent_socket.getaddrinfo(u'gevent.org', None, socket.AF_INET) diff --git a/venv/lib/python3.9/site-packages/gevent/tests/hosts_file.txt b/venv/lib/python3.9/site-packages/gevent/tests/hosts_file.txt deleted file mode 100644 index a33da68..0000000 --- a/venv/lib/python3.9/site-packages/gevent/tests/hosts_file.txt +++ /dev/null @@ -1,10351 +0,0 @@ -## -# Host Database -# -# localhost is used to configure the loopback interface -# when the system is booting. Do not change this entry. -## -127.0.0.1 localhost Localhost localhost.localdomain testsite.mc.com mathcounts.mc.com platform.osu.edu - -255.255.255.255 broadcasthost -::1 localhost -fe80::1%lo0 localhost -172.178.0.51 excelsior excelsior.example.com -162.168.8.27 memoryprime.local memoryprime -122.168.9.64 isy.local isy - - -192.168.1.172 drivefoo.local - -172.168.15.95 aragefoo.local -172.168.15.105 livgfoo.local -172.168.16.109 upsirsfoo.local -172.168.15.140 bacorthfoo.local -172.168.15.142 bacouthfoo.local -172.168.16.144 drisfoo.local -172.168.15.152 nghborfoo.local -172.168.15.154 fntfoo.local -172.168.18.151 as.local - -# Internals -146.120.241.22 ds3 -146.120.241.23 ds4 -146.120.241.21 ds2 -146.120.241.20 ds1 - - -# Not blocked by Mar 18 2013 -0.0.0.0 h.ppjol.com -0.0.0.0 s.ppjol.net -0.0.0.0 yayfollowers.com -0.0.0.0 pagead2.googlesyndication.com -0.0.0.0 www.googletagservices.com -0.0.0.0 cdn.teads.tv -0.0.0.0 js.moatads.com -0.0.0.0 cdn2.teads.tv - - -# This hosts file is brought to you by Dan Pollock and can be found at -# http://someonewhocares.org/hosts/zero/ - -# -# For example, to block unpleasant pages, try: -0.0.0.0 goatse.cx # More information on sites such as -0.0.0.0 www.goatse.cx # these can be found in this article -0.0.0.0 oralse.cx # en.wikipedia.org/wiki/List_of_shock_sites -0.0.0.0 www.oralse.cx -0.0.0.0 goatse.ca -0.0.0.0 www.goatse.ca -0.0.0.0 oralse.ca -0.0.0.0 www.oralse.ca -0.0.0.0 goat.cx -0.0.0.0 www.goat.cx -0.0.0.0 goatse.ru -0.0.0.0 www.goatse.ru - -0.0.0.0 1girl1pitcher.com -0.0.0.0 1girl1pitcher.org -0.0.0.0 1guy1cock.com -0.0.0.0 1man1jar.org -0.0.0.0 1man2needles.com -0.0.0.0 1priest1nun.com -0.0.0.0 2girls1cup.com -0.0.0.0 2girls1cup-free.com -0.0.0.0 2girls1cup.nl -0.0.0.0 2girls1cup.ws -0.0.0.0 2girls1finger.com -0.0.0.0 2girls1finger.org -0.0.0.0 2guys1stump.org -0.0.0.0 3guys1hammer.ws -0.0.0.0 4girlsfingerpaint.com -0.0.0.0 4girlsfingerpaint.org -0.0.0.0 bagslap.com -0.0.0.0 ballsack.org -0.0.0.0 bluewaffle.biz -0.0.0.0 bottleguy.com -0.0.0.0 bowlgirl.com -0.0.0.0 cadaver.org -0.0.0.0 clownsong.com -0.0.0.0 copyright-reform.info -0.0.0.0 cshacks.partycat.us -0.0.0.0 cyberscat.com -0.0.0.0 dadparty.com -0.0.0.0 detroithardcore.com -0.0.0.0 donotwatch.org -0.0.0.0 dontwatch.us -0.0.0.0 eelsoup.net -0.0.0.0 fruitlauncher.com -0.0.0.0 fuck.org -0.0.0.0 funnelchair.com -0.0.0.0 goatse.bz -0.0.0.0 goatsegirl.org -0.0.0.0 goatse.ru -0.0.0.0 hai2u.com -0.0.0.0 homewares.org -0.0.0.0 howtotroll.org -0.0.0.0 japscat.org -0.0.0.0 jiztini.com -0.0.0.0 junecleeland.com -0.0.0.0 kids-in-sandbox.com -0.0.0.0 kidsinsandbox.info -0.0.0.0 lemonparty.biz -0.0.0.0 lemonparty.org -0.0.0.0 lolhello.com -0.0.0.0 loltrain.com -0.0.0.0 meatspin.biz -0.0.0.0 meatspin.com -0.0.0.0 merryholidays.org -0.0.0.0 milkfountain.com -0.0.0.0 mudfall.com -0.0.0.0 mudmonster.org -0.0.0.0 nimp.org -0.0.0.0 nobrain.dk -0.0.0.0 nutabuse.com -0.0.0.0 octopusgirl.com -0.0.0.0 on.nimp.org -0.0.0.0 painolympics.info -0.0.0.0 phonejapan.com -0.0.0.0 pressurespot.com -0.0.0.0 prolapseman.com -0.0.0.0 scrollbelow.com -0.0.0.0 selfpwn.org -0.0.0.0 sexitnow.com -0.0.0.0 sourmath.com -0.0.0.0 suckdude.com -0.0.0.0 thatsjustgay.com -0.0.0.0 thatsphucked.com -0.0.0.0 thehomo.org -0.0.0.0 themacuser.org -0.0.0.0 thepounder.com -0.0.0.0 tubgirl.me -0.0.0.0 tubgirl.org -0.0.0.0 turdgasm.com -0.0.0.0 vomitgirl.org -0.0.0.0 walkthedinosaur.com -0.0.0.0 whipcrack.org -0.0.0.0 wormgush.com -0.0.0.0 www.1girl1pitcher.org -0.0.0.0 www.1guy1cock.com -0.0.0.0 www.1man1jar.org -0.0.0.0 www.1man2needles.com -0.0.0.0 www.1priest1nun.com -0.0.0.0 www.2girls1cup-free.com -0.0.0.0 www.2girls1cup.nl -0.0.0.0 www.2girls1cup.ws -0.0.0.0 www.2girls1finger.org -0.0.0.0 www.2guys1stump.org -0.0.0.0 www.3guys1hammer.ws -0.0.0.0 www.4girlsfingerpaint.org -0.0.0.0 www.bagslap.com -0.0.0.0 www.ballsack.org -0.0.0.0 www.bluewaffle.biz -0.0.0.0 www.bottleguy.com -0.0.0.0 www.bowlgirl.com -0.0.0.0 www.cadaver.org -0.0.0.0 www.clownsong.com -0.0.0.0 www.copyright-reform.info -0.0.0.0 www.cshacks.partycat.us -0.0.0.0 www.cyberscat.com -0.0.0.0 www.dadparty.com -0.0.0.0 www.detroithardcore.com -0.0.0.0 www.donotwatch.org -0.0.0.0 www.dontwatch.us -0.0.0.0 www.eelsoup.net -0.0.0.0 www.fruitlauncher.com -0.0.0.0 www.fuck.org -0.0.0.0 www.funnelchair.com -0.0.0.0 www.goatse.bz -0.0.0.0 www.goatsegirl.org -0.0.0.0 www.goatse.ru -0.0.0.0 www.hai2u.com -0.0.0.0 www.homewares.org -0.0.0.0 www.howtotroll.org -0.0.0.0 www.japscat.org -0.0.0.0 www.jiztini.com -0.0.0.0 www.junecleeland.com -0.0.0.0 www.kids-in-sandbox.com -0.0.0.0 www.kidsinsandbox.info -0.0.0.0 www.lemonparty.biz -0.0.0.0 www.lemonparty.org -0.0.0.0 www.lolhello.com -0.0.0.0 www.loltrain.com -0.0.0.0 www.meatspin.biz -0.0.0.0 www.meatspin.com -0.0.0.0 www.merryholidays.org -0.0.0.0 www.milkfountain.com -0.0.0.0 www.mudfall.com -0.0.0.0 www.mudmonster.org -0.0.0.0 www.nimp.org -0.0.0.0 www.nobrain.dk -0.0.0.0 www.nutabuse.com -0.0.0.0 www.octopusgirl.com -0.0.0.0 www.on.nimp.org -0.0.0.0 www.painolympics.info -0.0.0.0 www.phonejapan.com -0.0.0.0 www.pressurespot.com -0.0.0.0 www.prolapseman.com -0.0.0.0 www.punishtube.com -0.0.0.0 www.scrollbelow.com -0.0.0.0 www.selfpwn.org -0.0.0.0 www.sourmath.com -0.0.0.0 www.suckdude.com -0.0.0.0 www.thatsjustgay.com -0.0.0.0 www.thatsphucked.com -0.0.0.0 www.theexgirlfriends.com -0.0.0.0 www.thehomo.org -0.0.0.0 www.themacuser.org -0.0.0.0 www.thepounder.com -0.0.0.0 www.tubgirl.me -0.0.0.0 www.tubgirl.org -0.0.0.0 www.turdgasm.com -0.0.0.0 www.vomitgirl.org -0.0.0.0 www.walkthedinosaur.com -0.0.0.0 www.whipcrack.org -0.0.0.0 www.wormgush.com -0.0.0.0 www.xvideoslive.com -0.0.0.0 www.y8.com -0.0.0.0 www.youaresogay.com -0.0.0.0 www.ypmate.com -0.0.0.0 www.zentastic.com -0.0.0.0 youaresogay.com -0.0.0.0 zentastic.com -# - -0.0.0.0 ads234.com -0.0.0.0 ads345.com -0.0.0.0 www.ads234.com -0.0.0.0 www.ads345.com -# - - -# - -# -0.0.0.0 auto.search.msn.com # Microsoft uses this server to redirect - # mistyped URLs to search engines. They - # log all such errors. -0.0.0.0 sitefinder.verisign.com # Verisign has joined the game -0.0.0.0 sitefinder-idn.verisign.com # of trying to hijack mistyped - # URLs to their site. - # May break iOS Game Center. - -0.0.0.0 s0.2mdn.net # This may interfere with some streaming - # video on sites such as cbc.ca -0.0.0.0 ad.doubleclick.net # This may interefere with www.sears.com - # and potentially other sites. -0.0.0.0 media.fastclick.net # Likewise, this may interfere with some -0.0.0.0 cdn.fastclick.net # sites. -0.0.0.0 ebay.doubleclick.net # may interfere with ebay -#0.0.0.0 google-analytics.com # breaks some sites -#0.0.0.0 ssl.google-analytics.com -#0.0.0.0 www.google-analytics.l.google.com -0.0.0.0 stat.livejournal.com # There are reports that this may mess - # up CSS on livejournal -0.0.0.0 stats.surfaid.ihost.com # This has been known cause - # problems with NPR.org -0.0.0.0 www.google-analytics.com # breaks some sites -0.0.0.0 ads.imeem.com # Seems to interfere with the functioning of imeem.com -# - -0.0.0.0 006.free-counter.co.uk -0.0.0.0 006.freecounters.co.uk -0.0.0.0 06272002-dbase.hitcountz.net # Web bugs in spam -0.0.0.0 123counter.mycomputer.com -0.0.0.0 123counter.superstats.com -0.0.0.0 1ca.cqcounter.com -0.0.0.0 1uk.cqcounter.com -0.0.0.0 1us.cqcounter.com -0.0.0.0 1xxx.cqcounter.com -0.0.0.0 2001-007.com -0.0.0.0 3bc3fd26-91cf-46b2-8ec6-b1559ada0079.statcamp.net -0.0.0.0 3ps.go.com -0.0.0.0 4-counter.com -0.0.0.0 a796faee-7163-4757-a34f-e5b48cada4cb.statcamp.net -0.0.0.0 abscbn.spinbox.net -0.0.0.0 activity.serving-sys.com #eyeblaster.com -0.0.0.0 adadvisor.net -0.0.0.0 adclient.rottentomatoes.com -0.0.0.0 adcodes.aim4media.com -0.0.0.0 adcounter.globeandmail.com -0.0.0.0 adcounter.theglobeandmail.com -0.0.0.0 addfreestats.com -0.0.0.0 ademails.com -0.0.0.0 adlog.com.com # Used by Ziff Davis to serve - # ads and track users across - # the com.com family of sites -0.0.0.0 ad-logics.com -0.0.0.0 admanmail.com -0.0.0.0 adopt.specificclick.net -0.0.0.0 ads.tiscali.com -0.0.0.0 ads.tiscali.it -0.0.0.0 adult.foxcounter.com -0.0.0.0 affiliate.ab1trk.com -0.0.0.0 affiliate.irotracker.com -0.0.0.0 ai062.insightexpress.com -0.0.0.0 ai078.insightexpressai.com -0.0.0.0 ai087.insightexpress.com -0.0.0.0 ai113.insightexpressai.com -0.0.0.0 ai125.insightexpressai.com -0.0.0.0 alpha.easy-hit-counters.com -0.0.0.0 amateur.xxxcounter.com -0.0.0.0 amer.hops.glbdns.microsoft.com -0.0.0.0 amer.rel.msn.com -0.0.0.0 analytics.msnbc.msn.com -0.0.0.0 analytics.prx.org -0.0.0.0 anm.intelli-direct.com -0.0.0.0 ant.conversive.nl -0.0.0.0 apac.rel.msn.com -0.0.0.0 api.bizographics.com -0.0.0.0 apprep.smartscreen.microsoft.com -0.0.0.0 app.yesware.com -0.0.0.0 arbo.hit.gemius.pl -0.0.0.0 au052.insightexpress.com -0.0.0.0 auspice.augur.io -0.0.0.0 au.track.decideinteractive.com -0.0.0.0 a.visualrevenue.com -0.0.0.0 banner.0catch.com -0.0.0.0 banners.webcounter.com -0.0.0.0 beacon-1.newrelic.com -0.0.0.0 beacon.scorecardresearch.com -0.0.0.0 beacons.hottraffic.nl -0.0.0.0 be.sitestat.com -0.0.0.0 best-search.cc #spyware -0.0.0.0 beta.easy-hit-counter.com -0.0.0.0 beta.easy-hit-counters.com -0.0.0.0 beta.easyhitcounters.com -0.0.0.0 bilbo.counted.com -0.0.0.0 bin.clearspring.com -0.0.0.0 birta.stats.is -0.0.0.0 bluekai.com -0.0.0.0 bluestreak.com -0.0.0.0 bookproplus.com -0.0.0.0 broadcastpc.tv -0.0.0.0 report.broadcastpc.tv -0.0.0.0 www.broadcastpc.tv -0.0.0.0 bserver.blick.com -0.0.0.0 bstats.adbrite.com -0.0.0.0 b.stats.paypal.com -0.0.0.0 by.optimost.com -0.0.0.0 c10.statcounter.com -0.0.0.0 c11.statcounter.com -0.0.0.0 c12.statcounter.com -0.0.0.0 c13.statcounter.com -0.0.0.0 c14.statcounter.com -0.0.0.0 c15.statcounter.com -0.0.0.0 c16.statcounter.com -0.0.0.0 c17.statcounter.com -0.0.0.0 c1.statcounter.com -0.0.0.0 c1.thecounter.com -0.0.0.0 c1.thecounter.de -0.0.0.0 c1.xxxcounter.com -0.0.0.0 c2.gostats.com -0.0.0.0 c2.thecounter.com -0.0.0.0 c2.thecounter.de -0.0.0.0 c2.xxxcounter.com -0.0.0.0 c3.gostats.com -0.0.0.0 c3.statcounter.com -0.0.0.0 c3.thecounter.com -0.0.0.0 c3.xxxcounter.com -0.0.0.0 c4.myway.com -0.0.0.0 c4.statcounter.com -0.0.0.0 c5.statcounter.com -0.0.0.0 c6.statcounter.com -0.0.0.0 c7.statcounter.com -0.0.0.0 c8.statcounter.com -0.0.0.0 c9.statcounter.com -0.0.0.0 ca.cqcounter.com -0.0.0.0 cashcounter.com -0.0.0.0 cb1.counterbot.com -0.0.0.0 cdn.krxd.net -0.0.0.0 cdn.oggifinogi.com -0.0.0.0 cdn.taboolasyndication.com -0.0.0.0 cdxbin.vulnerap.com -0.0.0.0 cf.addthis.com -0.0.0.0 cgicounter.onlinehome.de -0.0.0.0 cgicounter.puretec.de -0.0.0.0 cgi.hotstat.nl -0.0.0.0 cgi.sexlist.com -0.0.0.0 ci-mpsnare.iovation.com # See http://www.codingthewheel.com/archives/online-gambling-privacy-iesnare -0.0.0.0 citrix.tradedoubler.com -0.0.0.0 cjt1.net -0.0.0.0 click.atdmt.com -0.0.0.0 clickauditor.net -0.0.0.0 click.fivemtn.com -0.0.0.0 click.investopedia.com -0.0.0.0 click.jve.net -0.0.0.0 clickmeter.com -0.0.0.0 click.payserve.com -0.0.0.0 clicks.emarketmakers.com -0.0.0.0 click.silvercash.com -0.0.0.0 clicks.m4n.nl -0.0.0.0 clicks.natwest.com -0.0.0.0 clickspring.net #used by a spyware product called PurityScan -0.0.0.0 clicks.rbs.co.uk -0.0.0.0 clicktrack.onlineemailmarketing.com -0.0.0.0 clicktracks.webmetro.com -0.0.0.0 clit10.sextracker.com -0.0.0.0 clit13.sextracker.com -0.0.0.0 clit15.sextracker.com -0.0.0.0 clit2.sextracker.com -0.0.0.0 clit4.sextracker.com -0.0.0.0 clit6.sextracker.com -0.0.0.0 clit7.sextracker.com -0.0.0.0 clit8.sextracker.com -0.0.0.0 clit9.sextracker.com -0.0.0.0 clk.aboxdeal.com -0.0.0.0 clk.relestar.com -0.0.0.0 cnn.entertainment.printthis.clickability.com -0.0.0.0 cnt.xcounter.com -0.0.0.0 collector.deepmetrix.com -0.0.0.0 collector.newsx.cc -0.0.0.0 connectionlead.com -0.0.0.0 connexity.net -0.0.0.0 cookies.cmpnet.com -0.0.0.0 count.channeladvisor.com -0.0.0.0 counter10.bravenet.com -0.0.0.0 counter10.sextracker.be -0.0.0.0 counter10.sextracker.com -0.0.0.0 counter11.bravenet.com -0.0.0.0 counter11.sextracker.be -0.0.0.0 counter11.sextracker.com -0.0.0.0 counter.123counts.com -0.0.0.0 counter12.bravenet.com -0.0.0.0 counter12.sextracker.be -0.0.0.0 counter12.sextracker.com -0.0.0.0 counter13.bravenet.com -0.0.0.0 counter13.sextracker.be -0.0.0.0 counter13.sextracker.com -0.0.0.0 counter14.bravenet.com -0.0.0.0 counter14.sextracker.be -0.0.0.0 counter14.sextracker.com -0.0.0.0 counter15.bravenet.com -0.0.0.0 counter15.sextracker.be -0.0.0.0 counter15.sextracker.com -0.0.0.0 counter16.bravenet.com -0.0.0.0 counter16.sextracker.be -0.0.0.0 counter16.sextracker.com -0.0.0.0 counter17.bravenet.com -0.0.0.0 counter18.bravenet.com -0.0.0.0 counter19.bravenet.com -0.0.0.0 counter1.bravenet.com -0.0.0.0 counter1.sextracker.be -0.0.0.0 counter1.sextracker.com -0.0.0.0 counter.1stblaze.com -0.0.0.0 counter20.bravenet.com -0.0.0.0 counter21.bravenet.com -0.0.0.0 counter22.bravenet.com -0.0.0.0 counter23.bravenet.com -0.0.0.0 counter24.bravenet.com -0.0.0.0 counter25.bravenet.com -0.0.0.0 counter26.bravenet.com -0.0.0.0 counter27.bravenet.com -0.0.0.0 counter28.bravenet.com -0.0.0.0 counter29.bravenet.com -0.0.0.0 counter2.bravenet.com -0.0.0.0 counter2.freeware.de -0.0.0.0 counter2.hitslink.com -0.0.0.0 counter2.sextracker.be -0.0.0.0 counter2.sextracker.com -0.0.0.0 counter30.bravenet.com -0.0.0.0 counter31.bravenet.com -0.0.0.0 counter32.bravenet.com -0.0.0.0 counter33.bravenet.com -0.0.0.0 counter34.bravenet.com -0.0.0.0 counter35.bravenet.com -0.0.0.0 counter36.bravenet.com -0.0.0.0 counter37.bravenet.com -0.0.0.0 counter38.bravenet.com -0.0.0.0 counter39.bravenet.com -0.0.0.0 counter3.bravenet.com -0.0.0.0 counter3.sextracker.be -0.0.0.0 counter3.sextracker.com -0.0.0.0 counter40.bravenet.com -0.0.0.0 counter41.bravenet.com -0.0.0.0 counter42.bravenet.com -0.0.0.0 counter43.bravenet.com -0.0.0.0 counter44.bravenet.com -0.0.0.0 counter45.bravenet.com -0.0.0.0 counter46.bravenet.com -0.0.0.0 counter47.bravenet.com -0.0.0.0 counter48.bravenet.com -0.0.0.0 counter49.bravenet.com -0.0.0.0 counter4all.dk -0.0.0.0 counter4.bravenet.com -0.0.0.0 counter4.sextracker.be -0.0.0.0 counter4.sextracker.com -0.0.0.0 counter4u.de -0.0.0.0 counter50.bravenet.com -0.0.0.0 counter5.bravenet.com -0.0.0.0 counter5.sextracker.be -0.0.0.0 counter5.sextracker.com -0.0.0.0 counter6.bravenet.com -0.0.0.0 counter6.sextracker.be -0.0.0.0 counter6.sextracker.com -0.0.0.0 counter7.bravenet.com -0.0.0.0 counter7.sextracker.be -0.0.0.0 counter7.sextracker.com -0.0.0.0 counter8.bravenet.com -0.0.0.0 counter8.sextracker.be -0.0.0.0 counter8.sextracker.com -0.0.0.0 counter9.bravenet.com -0.0.0.0 counter9.sextracker.be -0.0.0.0 counter9.sextracker.com -0.0.0.0 counter.aaddzz.com -0.0.0.0 counterad.de -0.0.0.0 counter.adultcheck.com -0.0.0.0 counter.adultrevenueservice.com -0.0.0.0 counter.advancewebhosting.com -0.0.0.0 counter.aport.ru -0.0.0.0 counteraport.spylog.com -0.0.0.0 counter.asexhound.com -0.0.0.0 counter.avp2000.com -0.0.0.0 counter.bizland.com -0.0.0.0 counter.bloke.com -0.0.0.0 counterbot.com -0.0.0.0 counter.clubnet.ro -0.0.0.0 counter.cnw.cz -0.0.0.0 countercrazy.com -0.0.0.0 counter.credo.ru -0.0.0.0 counter.cz -0.0.0.0 counter.digits.com -0.0.0.0 counter.dreamhost.com -0.0.0.0 counter.e-audit.it -0.0.0.0 counter.execpc.com -0.0.0.0 counter.fateback.com -0.0.0.0 counter.gamespy.com -0.0.0.0 counter.hitslink.com -0.0.0.0 counter.hitslinks.com -0.0.0.0 counter.htmlvalidator.com -0.0.0.0 counter.impressur.com -0.0.0.0 counter.inetusa.com -0.0.0.0 counter.inti.fr -0.0.0.0 counter.kaspersky.com -0.0.0.0 counter.letssingit.com -0.0.0.0 counter.mtree.com -0.0.0.0 counter.mycomputer.com -0.0.0.0 counter.netmore.net -0.0.0.0 counter.nope.dk -0.0.0.0 counter.nowlinux.com -0.0.0.0 counter.pcgames.de -0.0.0.0 counter.rambler.ru -0.0.0.0 counters.auctionhelper.com # comment these -0.0.0.0 counters.auctionwatch.com # out to allow -0.0.0.0 counters.auctiva.com # tracking by -0.0.0.0 counters.honesty.com # ebay users -0.0.0.0 counter.search.bg -0.0.0.0 counter.sexhound.nl -0.0.0.0 counters.gigya.com -0.0.0.0 counter.sparklit.com -0.0.0.0 counter.superstats.com -0.0.0.0 counter.surfcounters.com -0.0.0.0 counters.xaraonline.com -0.0.0.0 counter.times.lv -0.0.0.0 counter.topping.com.ua -0.0.0.0 counter.tripod.com -0.0.0.0 counter.uq.edu.au -0.0.0.0 counter.w3open.com -0.0.0.0 counter.webcom.com -0.0.0.0 counter.webmedia.pl -0.0.0.0 counter.webtrends.com -0.0.0.0 counter.webtrends.net -0.0.0.0 counter.xxxcool.com -0.0.0.0 counter.yadro.ru -0.0.0.0 count.paycounter.com -0.0.0.0 count.xhit.com -0.0.0.0 cs.sexcounter.com -0.0.0.0 c.statcounter.com -0.0.0.0 c.thecounter.de -0.0.0.0 cw.nu -0.0.0.0 cyseal.cyveillance.com -0.0.0.0 cz3.clickzs.com -0.0.0.0 cz6.clickzs.com -0.0.0.0 da.ce.bd.a9.top.list.ru -0.0.0.0 da.newstogram.com -0.0.0.0 data2.perf.overture.com -0.0.0.0 data.coremetrics.com -0.0.0.0 data.webads.co.nz -0.0.0.0 dclk.haaretz.co.il -0.0.0.0 dclk.themarker.com -0.0.0.0 dclk.themarketer.com -0.0.0.0 delivery.loopingclick.com -0.0.0.0 de.sitestat.com -0.0.0.0 didtheyreadit.com # email bugs -0.0.0.0 digistats.westjet.com -0.0.0.0 dimeprice.com # "spam bugs" -0.0.0.0 directads.mcafee.com -0.0.0.0 dotcomsecrets.com -0.0.0.0 dpbolvw.net -0.0.0.0 ds.247realmedia.com -0.0.0.0 ds.amateurmatch.com -0.0.0.0 dwclick.com -0.0.0.0 e-2dj6wfk4ehd5afq.stats.esomniture.com -0.0.0.0 e-2dj6wfk4ggdzkbo.stats.esomniture.com -0.0.0.0 e-2dj6wfk4gkcpiep.stats.esomniture.com -0.0.0.0 e-2dj6wfk4skdpogo.stats.esomniture.com -0.0.0.0 e-2dj6wfkiakdjgcp.stats.esomniture.com -0.0.0.0 e-2dj6wfkiepczoeo.stats.esomniture.com -0.0.0.0 e-2dj6wfkikjd5glq.stats.esomniture.com -0.0.0.0 e-2dj6wfkiokc5odp.stats.esomniture.com -0.0.0.0 e-2dj6wfkiqjcpifp.stats.esomniture.com -0.0.0.0 e-2dj6wfkocjczedo.stats.esomniture.com -0.0.0.0 e-2dj6wfkokjajseq.stats.esomniture.com -0.0.0.0 e-2dj6wfkowkdjokp.stats.esomniture.com -0.0.0.0 e-2dj6wfkykpazskq.stats.esomniture.com -0.0.0.0 e-2dj6wflicocjklo.stats.esomniture.com -0.0.0.0 e-2dj6wfligpd5iap.stats.esomniture.com -0.0.0.0 e-2dj6wflikgdpodo.stats.esomniture.com -0.0.0.0 e-2dj6wflikiajslo.stats.esomniture.com -0.0.0.0 e-2dj6wflioldzoco.stats.esomniture.com -0.0.0.0 e-2dj6wfliwpczolp.stats.esomniture.com -0.0.0.0 e-2dj6wfloenczmkq.stats.esomniture.com -0.0.0.0 e-2dj6wflokmajedo.stats.esomniture.com -0.0.0.0 e-2dj6wfloqgc5mho.stats.esomniture.com -0.0.0.0 e-2dj6wfmysgdzobo.stats.esomniture.com -0.0.0.0 e-2dj6wgkigpcjedo.stats.esomniture.com -0.0.0.0 e-2dj6wgkisnd5abo.stats.esomniture.com -0.0.0.0 e-2dj6wgkoandzieq.stats.esomniture.com -0.0.0.0 e-2dj6wgkycpcpsgq.stats.esomniture.com -0.0.0.0 e-2dj6wgkyepajmeo.stats.esomniture.com -0.0.0.0 e-2dj6wgkyknd5sko.stats.esomniture.com -0.0.0.0 e-2dj6wgkyomdpalp.stats.esomniture.com -0.0.0.0 e-2dj6whkiandzkko.stats.esomniture.com -0.0.0.0 e-2dj6whkiepd5iho.stats.esomniture.com -0.0.0.0 e-2dj6whkiwjdjwhq.stats.esomniture.com -0.0.0.0 e-2dj6wjk4amd5mfp.stats.esomniture.com -0.0.0.0 e-2dj6wjk4kkcjalp.stats.esomniture.com -0.0.0.0 e-2dj6wjk4ukazebo.stats.esomniture.com -0.0.0.0 e-2dj6wjkosodpmaq.stats.esomniture.com -0.0.0.0 e-2dj6wjkouhd5eao.stats.esomniture.com -0.0.0.0 e-2dj6wjkowhd5ggo.stats.esomniture.com -0.0.0.0 e-2dj6wjkowjajcbo.stats.esomniture.com -0.0.0.0 e-2dj6wjkyandpogq.stats.esomniture.com -0.0.0.0 e-2dj6wjkycpdzckp.stats.esomniture.com -0.0.0.0 e-2dj6wjkyqmdzcgo.stats.esomniture.com -0.0.0.0 e-2dj6wjkysndzigp.stats.esomniture.com -0.0.0.0 e-2dj6wjl4qhd5kdo.stats.esomniture.com -0.0.0.0 e-2dj6wjlichdjoep.stats.esomniture.com -0.0.0.0 e-2dj6wjliehcjglp.stats.esomniture.com -0.0.0.0 e-2dj6wjlignajgaq.stats.esomniture.com -0.0.0.0 e-2dj6wjloagc5oco.stats.esomniture.com -0.0.0.0 e-2dj6wjlougazmao.stats.esomniture.com -0.0.0.0 e-2dj6wjlyamdpogo.stats.esomniture.com -0.0.0.0 e-2dj6wjlyckcpelq.stats.esomniture.com -0.0.0.0 e-2dj6wjlyeodjkcq.stats.esomniture.com -0.0.0.0 e-2dj6wjlygkd5ecq.stats.esomniture.com -0.0.0.0 e-2dj6wjmiekc5olo.stats.esomniture.com -0.0.0.0 e-2dj6wjmyehd5mfo.stats.esomniture.com -0.0.0.0 e-2dj6wjmyooczoeo.stats.esomniture.com -0.0.0.0 e-2dj6wjny-1idzkh.stats.esomniture.com -0.0.0.0 e-2dj6wjnyagcpkko.stats.esomniture.com -0.0.0.0 e-2dj6wjnyeocpcdo.stats.esomniture.com -0.0.0.0 e-2dj6wjnygidjskq.stats.esomniture.com -0.0.0.0 e-2dj6wjnyqkajabp.stats.esomniture.com -0.0.0.0 easy-web-stats.com -0.0.0.0 ecestats.theglobeandmail.com -0.0.0.0 economisttestcollect.insightfirst.com -0.0.0.0 ehg.fedex.com -0.0.0.0 eitbglobal.ojdinteractiva.com -0.0.0.0 emea.rel.msn.com -0.0.0.0 engine.cmmeglobal.com -0.0.0.0 enoratraffic.com -0.0.0.0 entry-stats.huffingtonpost.com -0.0.0.0 environmentalgraffiti.uk.intellitxt.com -0.0.0.0 e-n.y-1shz2prbmdj6wvny-1sez2pra2dj6wjmyepdzadpwudj6x9ny-1seq-2-2.stats.esomniture.com -0.0.0.0 e-ny.a-1shz2prbmdj6wvny-1sez2pra2dj6wjny-1jcpgbowsdj6x9ny-1seq-2-2.stats.esomniture.com -0.0.0.0 es.optimost.com -0.0.0.0 fastcounter.bcentral.com -0.0.0.0 fastcounter.com -0.0.0.0 fastcounter.linkexchange.com -0.0.0.0 fastcounter.linkexchange.net -0.0.0.0 fastcounter.linkexchange.nl -0.0.0.0 fastcounter.onlinehoster.net -0.0.0.0 fastwebcounter.com -0.0.0.0 fcstats.bcentral.com -0.0.0.0 fi.sitestat.com -0.0.0.0 fl01.ct2.comclick.com -0.0.0.0 flycast.com -0.0.0.0 forbescollect.247realmedia.com -0.0.0.0 formalyzer.com -0.0.0.0 foxcounter.com -0.0.0.0 free-counter.5u.com -0.0.0.0 freeinvisiblecounters.com -0.0.0.0 freestats.com -0.0.0.0 freewebcounter.com -0.0.0.0 free.xxxcounter.com -0.0.0.0 fs10.fusestats.com -0.0.0.0 ft2.autonomycloud.com -0.0.0.0 gapl.hit.gemius.pl -0.0.0.0 gator.com -0.0.0.0 gcounter.hosting4u.net -0.0.0.0 gd.mlb.com -0.0.0.0 geocounter.net -0.0.0.0 gkkzngresullts.com -0.0.0.0 go-in-search.net -0.0.0.0 goldstats.com -0.0.0.0 googfle.com -0.0.0.0 googletagservices.com -0.0.0.0 gostats.com -0.0.0.0 grafix.xxxcounter.com -0.0.0.0 gtcc1.acecounter.com -0.0.0.0 g-wizzads.net -0.0.0.0 hc2.humanclick.com -0.0.0.0 hit10.hotlog.ru -0.0.0.0 hit2.hotlog.ru -0.0.0.0 hit37.chark.dk -0.0.0.0 hit37.chart.dk -0.0.0.0 hit39.chart.dk -0.0.0.0 hit5.hotlog.ru -0.0.0.0 hit8.hotlog.ru -0.0.0.0 hit.clickaider.com -0.0.0.0 hit-counter.5u.com -0.0.0.0 hit-counter.udub.com -0.0.0.0 hits.guardian.co.uk -0.0.0.0 hits.gureport.co.uk -0.0.0.0 hits.nextstat.com -0.0.0.0 hits.webstat.com -0.0.0.0 hitx.statistics.ro -0.0.0.0 hst.tradedoubler.com -0.0.0.0 htm.freelogs.com -0.0.0.0 http300.edge.ru4.com -0.0.0.0 iccee.com -0.0.0.0 idm.hit.gemius.pl -0.0.0.0 ieplugin.com -0.0.0.0 iesnare.com # See http://www.codingthewheel.com/archives/online-gambling-privacy-iesnare -0.0.0.0 ig.insightgrit.com -0.0.0.0 ih.constantcontacts.com -0.0.0.0 i.kissmetrics.com # http://www.wired.com/epicenter/2011/07/undeletable-cookie/ -0.0.0.0 ilead.itrack.it -0.0.0.0 image.masterstats.com -0.0.0.0 images1.paycounter.com -0.0.0.0 images-aud.freshmeat.net -0.0.0.0 images-aud.slashdot.org -0.0.0.0 images-aud.sourceforge.net -0.0.0.0 images.dailydiscounts.com # "spam bugs" -0.0.0.0 images.itchydawg.com -0.0.0.0 impacts.alliancehub.com # "spam bugs" -0.0.0.0 impch.tradedoubler.com -0.0.0.0 imp.clickability.com -0.0.0.0 impde.tradedoubler.com -0.0.0.0 impdk.tradedoubler.com -0.0.0.0 impes.tradedoubler.com -0.0.0.0 impfr.tradedoubler.com -0.0.0.0 impgb.tradedoubler.com -0.0.0.0 impie.tradedoubler.com -0.0.0.0 impit.tradedouble.com -0.0.0.0 impit.tradedoubler.com -0.0.0.0 impnl.tradedoubler.com -0.0.0.0 impno.tradedoubler.com -0.0.0.0 impse.tradedoubler.com -0.0.0.0 in.paycounter.com -0.0.0.0 insightfirst.com -0.0.0.0 insightxe.looksmart.com -0.0.0.0 int.sitestat.com -0.0.0.0 in.webcounter.cc -0.0.0.0 iprocollect.realmedia.com -0.0.0.0 izitracking.izimailing.com -0.0.0.0 jgoyk.cjt1.net -0.0.0.0 jkearns.freestats.com -0.0.0.0 journalism.uk.smarttargetting.com -0.0.0.0 js.cybermonitor.com -0.0.0.0 jsonlinecollect.247realmedia.com -0.0.0.0 js.revsci.net -0.0.0.0 kissmetrics.com -0.0.0.0 kqzyfj.com -0.0.0.0 kt4.kliptracker.com -0.0.0.0 leadpub.com -0.0.0.0 liapentruromania.ro -0.0.0.0 lin31.metriweb.be -0.0.0.0 linkcounter.com -0.0.0.0 linkcounter.pornosite.com -0.0.0.0 link.masterstats.com -0.0.0.0 linktrack.bravenet.com -0.0.0.0 livestats.atlanta-airport.com -#0.0.0.0 ll.a.hulu.com # Uncomment to block Hulu. -0.0.0.0 loc1.hitsprocessor.com -0.0.0.0 log1.countomat.com -0.0.0.0 log4.quintelligence.com -0.0.0.0 log999.goo.ne.jp -0.0.0.0 loga.xiti.com -0.0.0.0 log.btopenworld.com -0.0.0.0 logc146.xiti.com -0.0.0.0 logc1.xiti.com -0.0.0.0 logc22.xiti.com -0.0.0.0 logc25.xiti.com -0.0.0.0 logc31.xiti.com -0.0.0.0 log.clickstream.co.za -0.0.0.0 log.hankooki.com -0.0.0.0 logi6.xiti.com -0.0.0.0 logi7.xiti.com -0.0.0.0 logi8.xiti.com -0.0.0.0 logp3.xiti.com -0.0.0.0 logs.comics.com -0.0.0.0 logs.eresmas.com -0.0.0.0 logs.eresmas.net -0.0.0.0 log.statistici.ro -0.0.0.0 logv14.xiti.com -0.0.0.0 logv17.xiti.com -0.0.0.0 logv18.xiti.com -0.0.0.0 logv21.xiti.com -0.0.0.0 logv25.xiti.com -0.0.0.0 logv27.xiti.com -0.0.0.0 logv29.xiti.com -0.0.0.0 logv32.xiti.com -0.0.0.0 logv4.xiti.com -0.0.0.0 logv.xiti.com -0.0.0.0 luycos.com -0.0.0.0 lycoscollect.247realmedia.com -0.0.0.0 lycoscollect.realmedia.com -0.0.0.0 m1.nedstatbasic.net -0.0.0.0 m1.webstats4u.com -0.0.0.0 mailcheckisp.biz # "spam bugs" -0.0.0.0 mama128.valuehost.ru -0.0.0.0 marketscore.com -0.0.0.0 mature.xxxcounter.com -0.0.0.0 mbox5.offermatica.com -0.0.0.0 media101.sitebrand.com -0.0.0.0 media.superstats.com -0.0.0.0 mediatrack.revenue.net -0.0.0.0 metric.10best.com -0.0.0.0 metric.infoworld.com -0.0.0.0 metric.nationalgeographic.com -0.0.0.0 metric.nwsource.com -0.0.0.0 metric.olivegarden.com -0.0.0.0 metrics2.pricegrabber.com -0.0.0.0 metrics.accuweather.com -0.0.0.0 metrics.al.com -0.0.0.0 metrics.boston.com -0.0.0.0 metrics.cbc.ca -0.0.0.0 metrics.cleveland.com -0.0.0.0 metrics.cnn.com -0.0.0.0 metrics.csmonitor.com -0.0.0.0 metrics.ctv.ca -0.0.0.0 metrics.dallasnews.com -0.0.0.0 metrics.elle.com -0.0.0.0 metrics.experts-exchange.com -0.0.0.0 metrics.fandome.com -0.0.0.0 metrics.foxnews.com -0.0.0.0 metrics.gap.com -0.0.0.0 metrics.health.com -0.0.0.0 metrics.hrblock.com -0.0.0.0 metrics.ioffer.com -0.0.0.0 metrics.ireport.com -0.0.0.0 metrics.kgw.com -0.0.0.0 metrics.ktvb.com -0.0.0.0 metrics.landolakes.com -0.0.0.0 metrics.lhj.com -0.0.0.0 metrics.maxim.com -0.0.0.0 metrics.mlive.com -0.0.0.0 metrics.mms.mavenapps.net -0.0.0.0 metrics.mpora.com -0.0.0.0 metrics.mysanantonio.com -0.0.0.0 metrics.nba.com -0.0.0.0 metrics.nextgov.com -0.0.0.0 metrics.nfl.com -0.0.0.0 metrics.npr.org -0.0.0.0 metrics.oclc.org -0.0.0.0 metrics.olivegarden.com -0.0.0.0 metrics.oregonlive.com -0.0.0.0 metrics.parallels.com -0.0.0.0 metrics.performancing.com -0.0.0.0 metrics.philly.com -0.0.0.0 metrics.post-gazette.com -0.0.0.0 metrics.premiere.com -0.0.0.0 metrics.rottentomatoes.com -0.0.0.0 metrics.sephora.com -0.0.0.0 metrics.soundandvision.com -0.0.0.0 metrics.soundandvisionmag.com -0.0.0.0 metrics.sun.com -0.0.0.0 metric.starz.com -0.0.0.0 metrics.technologyreview.com -0.0.0.0 metrics.theatlantic.com -0.0.0.0 metrics.thedailybeast.com -0.0.0.0 metrics.thefa.com -0.0.0.0 metrics.thefrisky.com -0.0.0.0 metrics.thenation.com -0.0.0.0 metrics.theweathernetwork.com -#0.0.0.0 metrics.ticketmaster.com # interferes with logging in to ticketmaster.com -0.0.0.0 metrics.tmz.com -0.0.0.0 metrics.toyota.com -0.0.0.0 metrics.tulsaworld.com -0.0.0.0 metrics.washingtonpost.com -0.0.0.0 metrics.whitepages.com -0.0.0.0 metrics.womansday.com -0.0.0.0 metrics.yellowpages.com -0.0.0.0 metrics.yousendit.com -0.0.0.0 metric.thenation.com -0.0.0.0 mng1.clickalyzer.com -0.0.0.0 monster.gostats.com -0.0.0.0 mpsnare.iesnare.com # See http://www.codingthewheel.com/archives/online-gambling-privacy-iesnare -0.0.0.0 msn1.com -0.0.0.0 msnm.com -0.0.0.0 mt122.mtree.com -0.0.0.0 mtcount.channeladvisor.com -0.0.0.0 mtrcs.popcap.com -0.0.0.0 mtv.247realmedia.com -0.0.0.0 multi1.rmuk.co.uk -0.0.0.0 mvs.mediavantage.de -0.0.0.0 mvtracker.com -0.0.0.0 mystats.com -0.0.0.0 nedstat.s0.nl -0.0.0.0 nethit-free.nl -0.0.0.0 net-radar.com -0.0.0.0 network.leadpub.com -0.0.0.0 nextgenstats.com -0.0.0.0 nht-2.extreme-dm.com -0.0.0.0 nl.nedstatbasic.net -0.0.0.0 nl.sitestat.com -0.0.0.0 o.addthis.com -0.0.0.0 objects.tremormedia.com -0.0.0.0 okcounter.com -0.0.0.0 omniture.theglobeandmail.com -0.0.0.0 one.123counters.com -0.0.0.0 oss-crules.marketscore.com -0.0.0.0 oss-survey.marketscore.com -0.0.0.0 ostats.mozilla.com -0.0.0.0 other.xxxcounter.com -0.0.0.0 out.true-counter.com -0.0.0.0 p.addthis.com -0.0.0.0 partner.alerts.aol.com -0.0.0.0 partners.pantheranetwork.com -0.0.0.0 passpport.com -0.0.0.0 paxito.sitetracker.com -0.0.0.0 paycounter.com -0.0.0.0 pei-ads.thesmokingjacket.com -0.0.0.0 perso.estat.com -0.0.0.0 pf.tradedoubler.com -0.0.0.0 pings.blip.tv -0.0.0.0 pix02.revsci.net -0.0.0.0 pix03.revsci.net -0.0.0.0 pix04.revsci.net -0.0.0.0 pixel.invitemedia.com -0.0.0.0 pmg.ad-logics.com -0.0.0.0 pn2.adserver.yahoo.com -0.0.0.0 pointclicktrack.com -0.0.0.0 pong.qubitproducts.com -0.0.0.0 postclick.adcentriconline.com -0.0.0.0 postgazettecollect.247realmedia.com -0.0.0.0 precisioncounter.com -0.0.0.0 p.reuters.com -0.0.0.0 printmail.biz -0.0.0.0 prof.estat.com -0.0.0.0 pro.hit.gemius.pl -0.0.0.0 proxycfg.marketscore.com -0.0.0.0 proxy.ia2.marketscore.com -0.0.0.0 proxy.ia3.marketscore.com -0.0.0.0 proxy.ia4.marketscore.com -0.0.0.0 proxy.or3.marketscore.com -0.0.0.0 proxy.or4.marketscore.com -0.0.0.0 proxy.sj3.marketscore.com -0.0.0.0 proxy.sj4.marketscore.com -0.0.0.0 quantserve.com #: Ad Tracking, JavaScript, etc. -0.0.0.0 quareclk.com -0.0.0.0 raw.oggifinogi.com -0.0.0.0 r.clickdensity.com -0.0.0.0 remotrk.com -0.0.0.0 rightmedia.net -0.0.0.0 rightstats.com -0.0.0.0 roskatrack.roskadirect.com -0.0.0.0 rr1.xxxcounter.com -0.0.0.0 rr2.xxxcounter.com -0.0.0.0 rr3.xxxcounter.com -0.0.0.0 rr4.xxxcounter.com -0.0.0.0 rr5.xxxcounter.com -0.0.0.0 rr7.xxxcounter.com -0.0.0.0 rts.pgmediaserve.com -0.0.0.0 rts.phn.doublepimp.com -0.0.0.0 s10.histats.com -0.0.0.0 s10.sitemeter.com -0.0.0.0 s11.sitemeter.com -0.0.0.0 s12.sitemeter.com -0.0.0.0 s13.sitemeter.com -0.0.0.0 s14.sitemeter.com -0.0.0.0 s15.sitemeter.com -0.0.0.0 s16.sitemeter.com -0.0.0.0 s17.sitemeter.com -0.0.0.0 s18.sitemeter.com -0.0.0.0 s19.sitemeter.com -0.0.0.0 s1.shinystat.it -0.0.0.0 s1.thecounter.com -0.0.0.0 s20.sitemeter.com -0.0.0.0 s21.sitemeter.com -0.0.0.0 s22.sitemeter.com -0.0.0.0 s23.sitemeter.com -0.0.0.0 s24.sitemeter.com -0.0.0.0 s25.sitemeter.com -0.0.0.0 s26.sitemeter.com -0.0.0.0 s27.sitemeter.com -0.0.0.0 s28.sitemeter.com -0.0.0.0 s29.sitemeter.com -0.0.0.0 s2.statcounter.com -0.0.0.0 s2.youtube.com -0.0.0.0 s30.sitemeter.com -0.0.0.0 s31.sitemeter.com -0.0.0.0 s32.sitemeter.com -0.0.0.0 s33.sitemeter.com -0.0.0.0 s34.sitemeter.com -0.0.0.0 s35.sitemeter.com -0.0.0.0 s36.sitemeter.com -0.0.0.0 s37.sitemeter.com -0.0.0.0 s38.sitemeter.com -0.0.0.0 s39.sitemeter.com -0.0.0.0 s3.hit.stat.pl -0.0.0.0 s41.sitemeter.com -0.0.0.0 s42.sitemeter.com -0.0.0.0 s43.sitemeter.com -0.0.0.0 s44.sitemeter.com -0.0.0.0 s45.sitemeter.com -0.0.0.0 s46.sitemeter.com -0.0.0.0 s47.sitemeter.com -0.0.0.0 s48.sitemeter.com -0.0.0.0 s4.histats.com -0.0.0.0 s4.shinystat.com -0.0.0.0 s.clickability.com -0.0.0.0 scorecardresearch.com -0.0.0.0 scribe.twitter.com -0.0.0.0 scrooge.channelcincinnati.com -0.0.0.0 scrooge.channeloklahoma.com -0.0.0.0 scrooge.click10.com -0.0.0.0 scrooge.clickondetroit.com -0.0.0.0 scrooge.nbc11.com -0.0.0.0 scrooge.nbc4columbus.com -0.0.0.0 scrooge.nbc4.com -0.0.0.0 scrooge.nbcsandiego.com -0.0.0.0 scrooge.newsnet5.com -0.0.0.0 scrooge.thebostonchannel.com -0.0.0.0 scrooge.thedenverchannel.com -0.0.0.0 scrooge.theindychannel.com -0.0.0.0 scrooge.thekansascitychannel.com -0.0.0.0 scrooge.themilwaukeechannel.com -0.0.0.0 scrooge.theomahachannel.com -0.0.0.0 scrooge.wesh.com -0.0.0.0 scrooge.wftv.com -0.0.0.0 scrooge.wnbc.com -0.0.0.0 scrooge.wsoctv.com -0.0.0.0 scrooge.wtov9.com -0.0.0.0 sdc.rbistats.com -0.0.0.0 searchadv.com -0.0.0.0 sekel.ch -0.0.0.0 servedby.valuead.com -0.0.0.0 server10.opentracker.net -0.0.0.0 server11.opentracker.net -0.0.0.0 server12.opentracker.net -0.0.0.0 server13.opentracker.net -0.0.0.0 server14.opentracker.net -0.0.0.0 server15.opentracker.net -0.0.0.0 server16.opentracker.net -0.0.0.0 server17.opentracker.net -0.0.0.0 server18.opentracker.net -0.0.0.0 server1.opentracker.net -0.0.0.0 server2.opentracker.net -0.0.0.0 server3.opentracker.net -0.0.0.0 server3.web-stat.com -0.0.0.0 server4.opentracker.net -0.0.0.0 server5.opentracker.net -0.0.0.0 server6.opentracker.net -0.0.0.0 server7.opentracker.net -0.0.0.0 server8.opentracker.net -0.0.0.0 server9.opentracker.net -0.0.0.0 service.bfast.com -0.0.0.0 services.krxd.net -0.0.0.0 se.sitestat.com -0.0.0.0 sexcounter.com -0.0.0.0 seznam.hit.gemius.pl -0.0.0.0 showads.pubmatic.com -0.0.0.0 showcount.honest.com -0.0.0.0 sideshow.directtrack.com -0.0.0.0 sitestat.com -0.0.0.0 sitestats.tiscali.co.uk -0.0.0.0 sm1.sitemeter.com -0.0.0.0 sm2.sitemeter.com -0.0.0.0 sm3.sitemeter.com -0.0.0.0 sm4.sitemeter.com -0.0.0.0 sm5.sitemeter.com -0.0.0.0 sm6.sitemeter.com -0.0.0.0 sm7.sitemeter.com -0.0.0.0 sm8.sitemeter.com -0.0.0.0 sm9.sitemeter.com -0.0.0.0 smartstats.com -0.0.0.0 softcore.xxxcounter.com -0.0.0.0 sostats.mozilla.com -0.0.0.0 sovereign.sitetracker.com -0.0.0.0 spinbox.maccentral.com -0.0.0.0 spinbox.versiontracker.com -0.0.0.0 spklds.com -0.0.0.0 s.statistici.ro -0.0.0.0 s.stats.wordpress.com -0.0.0.0 ss.tiscali.com -0.0.0.0 ss.tiscali.it -0.0.0.0 st1.hit.gemius.pl -0.0.0.0 stags.peer39.net -0.0.0.0 stast2.gq.com -0.0.0.0 stat1.z-stat.com -0.0.0.0 stat3.cybermonitor.com -0.0.0.0 stat.4u.pl -0.0.0.0 stat.alibaba.com -0.0.0.0 statcounter.com -0.0.0.0 stat-counter.tass-online.ru -0.0.0.0 stat.discogs.com -0.0.0.0 static.kibboko.com -0.0.0.0 static.smni.com # Santa Monica - popunders -0.0.0.0 statik.topica.com -0.0.0.0 statistics.dynamicsitestats.com -0.0.0.0 statistics.elsevier.nl -0.0.0.0 statistics.reedbusiness.nl -0.0.0.0 statistics.theonion.com -0.0.0.0 statistik-gallup.net -0.0.0.0 stat.netmonitor.fi -0.0.0.0 stat.onestat.com -0.0.0.0 stats1.clicktracks.com -0.0.0.0 stats1.corusradio.com -0.0.0.0 stats1.in -0.0.0.0 stats.24ways.org -0.0.0.0 stats2.clicktracks.com -0.0.0.0 stats2.gourmet.com -0.0.0.0 stats2.newyorker.com -0.0.0.0 stats2.rte.ie -0.0.0.0 stats2.unrulymedia.com -0.0.0.0 stats2.vanityfair.com -0.0.0.0 stats4all.com -0.0.0.0 stats5.lightningcast.com -0.0.0.0 stats6.lightningcast.net -0.0.0.0 stats.absol.co.za -0.0.0.0 stats.adbrite.com -0.0.0.0 stats.adotube.com -0.0.0.0 stats.adultswim.com -0.0.0.0 stats.airfarewatchdog.com -0.0.0.0 stats.allliquid.com -0.0.0.0 stats.askmen.com -0.0.0.0 stats.bbc.co.uk -0.0.0.0 stats.becu.org -0.0.0.0 stats.big-boards.com -0.0.0.0 stats.blogoscoop.net -0.0.0.0 stats.bonzaii.no -0.0.0.0 stats.break.com -0.0.0.0 stats.brides.com -0.0.0.0 stats.buysellads.com -0.0.0.0 stats.cafepress.com -0.0.0.0 stats.canalblog.com -0.0.0.0 stats.cartoonnetwork.com -0.0.0.0 stats.channel4.com -0.0.0.0 stats.clickability.com -0.0.0.0 stats.concierge.com -0.0.0.0 stats.cts-bv.nl -0.0.0.0 stats.darkbluesea.com -0.0.0.0 stats.datahjaelp.net -0.0.0.0 stats.directnic.com -0.0.0.0 stats.dziennik.pl -0.0.0.0 stats.economist.com -0.0.0.0 stats.epicurious.com -0.0.0.0 statse.webtrendslive.com # Fortune.com among others -0.0.0.0 stats.examiner.com -0.0.0.0 stats.fairmont.com -0.0.0.0 stats.fastcompany.com -0.0.0.0 stats.foxcounter.com -0.0.0.0 stats.free-rein.net -0.0.0.0 stats.f-secure.com -0.0.0.0 stats.ft.com -0.0.0.0 stats.gamestop.com -0.0.0.0 stats.globesports.com -0.0.0.0 stats.groupninetyfour.com -0.0.0.0 stats.idsoft.com -0.0.0.0 stats.ign.com -0.0.0.0 stats.ilsemedia.nl -0.0.0.0 stats.independent.co.uk -0.0.0.0 stats.indexstats.com -0.0.0.0 stats.indextools.com -0.0.0.0 stats.investors.com -0.0.0.0 stats.iwebtrack.com -0.0.0.0 stats.jippii.com -0.0.0.0 stats.klsoft.com -0.0.0.0 stats.ladotstats.nl -0.0.0.0 stats.macworld.com -0.0.0.0 stats.magnify.net -0.0.0.0 stats.manticoretechnology.com -0.0.0.0 stats.mbamupdates.com -0.0.0.0 stats.millanusa.com -0.0.0.0 stats.nowpublic.com -0.0.0.0 stats.paycounter.com -0.0.0.0 stats.platinumbucks.com -0.0.0.0 stats.popscreen.com -0.0.0.0 stats.reinvigorate.net -0.0.0.0 stats.resellerratings.com -0.0.0.0 stats.revenue.net -0.0.0.0 stats.searchles.com -0.0.0.0 stats.ssa.gov -0.0.0.0 stats.superstats.com -0.0.0.0 stats.telegraph.co.uk -0.0.0.0 stats.thoughtcatalog.com -0.0.0.0 stats.townnews.com -0.0.0.0 stats.ultimate-webservices.com -0.0.0.0 stats.unionleader.com -0.0.0.0 stats.video.search.yahoo.com -0.0.0.0 stats.vodpod.com -0.0.0.0 stats.wordpress.com -0.0.0.0 stats.www.ibm.com -0.0.0.0 stats.yourminis.com -0.0.0.0 stat.webmedia.pl -0.0.0.0 stat.www.fi -0.0.0.0 stat.yellowtracker.com -0.0.0.0 stat.youku.com -0.0.0.0 stl.p.a1.traceworks.com -0.0.0.0 straighttangerine.cz.cc -0.0.0.0 st.sageanalyst.net -0.0.0.0 sugoicounter.com -0.0.0.0 superstats.com -0.0.0.0 s.youtube.com -#0.0.0.0 t2.hulu.com # Uncomment to block Hulu. -0.0.0.0 tagging.outrider.com -0.0.0.0 talkcity.realtracker.com -0.0.0.0 targetnet.com -0.0.0.0 tates.freestats.com -0.0.0.0 tcookie.usatoday.com -0.0.0.0 tcr.tynt.com # See http://daringfireball.net/2010/05/tynt_copy_paste_jerks -0.0.0.0 tgpcounter.freethumbnailgalleries.com -0.0.0.0 thecounter.com -0.0.0.0 the-counter.net -0.0.0.0 themecounter.com -0.0.0.0 the.sextracker.com -0.0.0.0 tipsurf.com -0.0.0.0 toolbarpartner.com -0.0.0.0 tools.spylog.ru -0.0.0.0 top.mail.ru -0.0.0.0 topstats.com -0.0.0.0 topstats.net -0.0.0.0 torstarcollect.247realmedia.com -0.0.0.0 track2.mybloglog.com -0.0.0.0 track.adform.com -0.0.0.0 track.adform.net -0.0.0.0 track.did-it.com -0.0.0.0 track.directleads.com -0.0.0.0 track.domainsponsor.com -0.0.0.0 track.effiliation.com -0.0.0.0 tracker.bonnint.net -0.0.0.0 tracker.clicktrade.com -0.0.0.0 tracker.idg.co.uk -0.0.0.0 tracker.mattel.com -0.0.0.0 tracker.netklix.com -0.0.0.0 tracker.tradedoubler.com -0.0.0.0 track.exclusivecpa.com -0.0.0.0 track.ft.com -0.0.0.0 track.gawker.com -0.0.0.0 track.homestead.com -#0.0.0.0 track.hulu.com # Uncomment to block Hulu. -0.0.0.0 tracking.10e20.com -0.0.0.0 tracking.adjug.com -0.0.0.0 tracking.allposters.com -0.0.0.0 tracking.foxnews.com -0.0.0.0 tracking.iol.co.za -0.0.0.0 tracking.msadcenter.msn.com -0.0.0.0 tracking.oggifinogi.com -0.0.0.0 tracking.percentmobile.com -0.0.0.0 tracking.publicidees.com -0.0.0.0 tracking.quisma.com -0.0.0.0 tracking.rangeonlinemedia.com -0.0.0.0 tracking.searchmarketing.com -0.0.0.0 tracking.summitmedia.co.uk -0.0.0.0 tracking.trafficjunky.net -0.0.0.0 tracking.trutv.com -0.0.0.0 tracking.vindicosuite.com -0.0.0.0 track.lfstmedia.com -0.0.0.0 track.mybloglog.com -0.0.0.0 track.omg2.com -0.0.0.0 track.roiservice.com -0.0.0.0 track.searchignite.com -0.0.0.0 tracksurf.daooda.com -0.0.0.0 track.webgains.com -0.0.0.0 tradedoubler.com -0.0.0.0 tradedoubler.sonvideopro.com -0.0.0.0 tr.adinterax.com -0.0.0.0 traffic-stats.streamsolutions.co.uk -0.0.0.0 trax.gamespot.com -0.0.0.0 trc.taboolasyndication.com -0.0.0.0 trk.kissmetrics.com -0.0.0.0 trk.tidaltv.com -0.0.0.0 true-counter.com -0.0.0.0 truehits1.gits.net.th -0.0.0.0 t.senaluno.com -0.0.0.0 tu.connect.wunderloop.net -0.0.0.0 tynt.com -0.0.0.0 u1817.16.spylog.com -0.0.0.0 u3102.47.spylog.com -0.0.0.0 u3305.71.spylog.com -0.0.0.0 u3608.20.spylog.com -0.0.0.0 u4056.56.spylog.com -0.0.0.0 u432.77.spylog.com -0.0.0.0 u4396.79.spylog.com -0.0.0.0 u4443.84.spylog.com -0.0.0.0 u4556.11.spylog.com -0.0.0.0 u5234.87.spylog.com -0.0.0.0 u5234.98.spylog.com -0.0.0.0 u5687.48.spylog.com -0.0.0.0 u574.07.spylog.com -0.0.0.0 u604.41.spylog.com -0.0.0.0 u6762.46.spylog.com -0.0.0.0 u6905.71.spylog.com -0.0.0.0 u7748.16.spylog.com -0.0.0.0 u810.15.spylog.com -0.0.0.0 u920.31.spylog.com -0.0.0.0 u977.40.spylog.com -0.0.0.0 udc.msn.com -0.0.0.0 uk.cqcounter.com -0.0.0.0 uk.sitestat.com -0.0.0.0 ultimatecounter.com -0.0.0.0 us.2.cqcounter.com -0.0.0.0 usa.nedstat.net -0.0.0.0 us.cqcounter.com -0.0.0.0 v1.nedstatbasic.net -0.0.0.0 v7.stats.load.com -0.0.0.0 valueclick.com -0.0.0.0 valueclick.net -0.0.0.0 vertical-stats.huffpost.com -0.0.0.0 video-stats.video.google.com -0.0.0.0 vip.clickzs.com -0.0.0.0 virtualbartendertrack.beer.com -0.0.0.0 visit.theglobeandmail.com # Visits to theglobeandmail.com -0.0.0.0 vis.sexlist.com -0.0.0.0 voken.eyereturn.com -0.0.0.0 vs.dmtracker.com -0.0.0.0 vsii.spinbox.net -0.0.0.0 vsii.spindox.net -0.0.0.0 w1.tcr112.tynt.com -0.0.0.0 warlog.info -0.0.0.0 wau.tynt.com -0.0.0.0 web1.realtracker.com -0.0.0.0 web2.realtracker.com -0.0.0.0 web3.realtracker.com -0.0.0.0 web4.realtracker.com -0.0.0.0 webanalytics.globalthoughtz.com -0.0.0.0 webbug.seatreport.com # web bugs -0.0.0.0 web-counter.5u.com -0.0.0.0 webcounter.com -0.0.0.0 webcounter.goweb.de -0.0.0.0 webcounter.together.net -0.0.0.0 webhit.aftenposten.no -0.0.0.0 webhit.afterposten.no -0.0.0.0 webmasterkai.sitetracker.com -0.0.0.0 webpdp.gator.com -0.0.0.0 webstat.channel4.com -0.0.0.0 webtrends.telenet.be -0.0.0.0 webtrends.thisis.co.uk -0.0.0.0 webtrends.townhall.com -0.0.0.0 wtnj.worldnow.com -0.0.0.0 www.0stats.com -0.0.0.0 www101.coolsavings.com -0.0.0.0 www.123count.com -0.0.0.0 www.123counter.superstats.com -0.0.0.0 www.123stat.com -0.0.0.0 www1.addfreestats.com -0.0.0.0 www1.counter.bloke.com -0.0.0.0 www.1quickclickrx.com -0.0.0.0 www1.tynt.com -0.0.0.0 www.2001-007.com -0.0.0.0 www2.addfreestats.com -0.0.0.0 www2.counter.bloke.com -0.0.0.0 www2.pagecount.com -0.0.0.0 www3.addfreestats.com -0.0.0.0 www3.click-fr.com -0.0.0.0 www3.counter.bloke.com -0.0.0.0 www.3dstats.com -0.0.0.0 www4.addfreestats.com -0.0.0.0 www4.counter.bloke.com -0.0.0.0 www5.addfreestats.com -0.0.0.0 www5.counter.bloke.com -0.0.0.0 www60.valueclick.com -0.0.0.0 www6.addfreestats.com -0.0.0.0 www6.click-fr.com -0.0.0.0 www6.counter.bloke.com -0.0.0.0 www7.addfreestats.com -0.0.0.0 www7.counter.bloke.com -0.0.0.0 www8.addfreestats.com -0.0.0.0 www8.counter.bloke.com -0.0.0.0 www9.counter.bloke.com -0.0.0.0 www.addfreecounter.com -0.0.0.0 www.addfreestats.com -0.0.0.0 www.ademails.com -0.0.0.0 www.affiliatesuccess.net -0.0.0.0 www.bar.ry2002.02-ry014.snpr.hotmx.hair.zaam.net # In spam -0.0.0.0 www.belstat.nl -0.0.0.0 www.betcounter.com -0.0.0.0 www.bigbadted.com -0.0.0.0 www.bluestreak.com -0.0.0.0 www.c1.thecounter.de -0.0.0.0 www.c2.thecounter.de -0.0.0.0 www.clickclick.com -0.0.0.0 www.clickspring.net #used by a spyware product called PurityScan -0.0.0.0 www.clixgalore.com -0.0.0.0 www.connectionlead.com -0.0.0.0 www.counter10.sextracker.be -0.0.0.0 www.counter11.sextracker.be -0.0.0.0 www.counter12.sextracker.be -0.0.0.0 www.counter13.sextracker.be -0.0.0.0 www.counter14.sextracker.be -0.0.0.0 www.counter15.sextracker.be -0.0.0.0 www.counter16.sextracker.be -0.0.0.0 www.counter1.sextracker.be -0.0.0.0 www.counter2.sextracker.be -0.0.0.0 www.counter3.sextracker.be -0.0.0.0 www.counter4all.com -0.0.0.0 www.counter4all.de -0.0.0.0 www.counter4.sextracker.be -0.0.0.0 www.counter5.sextracker.be -0.0.0.0 www.counter6.sextracker.be -0.0.0.0 www.counter7.sextracker.be -0.0.0.0 www.counter8.sextracker.be -0.0.0.0 www.counter9.sextracker.be -0.0.0.0 www.counter.bloke.com -0.0.0.0 www.counterguide.com -0.0.0.0 www.counter.sexhound.nl -0.0.0.0 www.counter.superstats.com -0.0.0.0 www.c.thecounter.de -0.0.0.0 www.cw.nu -0.0.0.0 www.directgrowthhormone.com -0.0.0.0 www.dpbolvw.net -0.0.0.0 www.dwclick.com -0.0.0.0 www.easycounter.com -0.0.0.0 www.emaildeals.biz -0.0.0.0 www.estats4all.com -0.0.0.0 www.fastcounter.linkexchange.nl -0.0.0.0 www.formalyzer.com -0.0.0.0 www.foxcounter.com -0.0.0.0 www.freestats.com -0.0.0.0 www.fxcounters.com -0.0.0.0 www.gator.com -0.0.0.0 www.googkle.com -0.0.0.0 www.googletagservices.com -0.0.0.0 www.hitstats.co.uk -0.0.0.0 www.iccee.com -0.0.0.0 www.iesnare.com # See http://www.codingthewheel.com/archives/online-gambling-privacy-iesnare -0.0.0.0 www.jellycounter.com -0.0.0.0 www.kqzyfj.com -0.0.0.0 www.leadpub.com -0.0.0.0 www.linkcounter.com -0.0.0.0 www.marketscore.com -0.0.0.0 www.megacounter.de -0.0.0.0 www.metareward.com # web bugs in spam -0.0.0.0 www.naturalgrowthstore.biz -0.0.0.0 www.nedstat.com -0.0.0.0 www.nextgenstats.com -0.0.0.0 www.ntsearch.com -0.0.0.0 www.onestat.com -0.0.0.0 www.originalicons.com # installs IE extension -0.0.0.0 www.paycounter.com -0.0.0.0 www.pointclicktrack.com -0.0.0.0 www.popuptrafic.com -0.0.0.0 www.precisioncounter.com -0.0.0.0 www.premiumsmail.net -0.0.0.0 www.printmail.biz -0.0.0.0 www.quantserve.com #: Ad Tracking, JavaScript, etc. -0.0.0.0 www.quareclk.com -0.0.0.0 www.remotrk.com -0.0.0.0 www.rightmedia.net -0.0.0.0 www.rightstats.com -0.0.0.0 www.searchadv.com -0.0.0.0 www.sekel.ch -0.0.0.0 www.shockcounter.com -0.0.0.0 www.simplecounter.net -0.0.0.0 www.specificclick.com -0.0.0.0 www.specificpop.com -0.0.0.0 www.spklds.com -0.0.0.0 www.statcount.com -0.0.0.0 www.statcounter.com -0.0.0.0 www.statsession.com -0.0.0.0 www.stattrax.com -0.0.0.0 www.stiffnetwork.com -0.0.0.0 www.testracking.com -0.0.0.0 www.thecounter.com -0.0.0.0 www.the-counter.net -0.0.0.0 www.toolbarcounter.com -0.0.0.0 www.tradedoubler.com -0.0.0.0 www.tradedoubler.com.ar -0.0.0.0 www.trafficmagnet.net # web bugs in spam -0.0.0.0 www.trafic.ro -0.0.0.0 www.trendcounter.com -0.0.0.0 www.true-counter.com -0.0.0.0 www.tynt.com -0.0.0.0 www.ultimatecounter.com -0.0.0.0 www.v61.com -0.0.0.0 www.webcounter.com -0.0.0.0 www.web-stat.com -0.0.0.0 www.webstat.com -0.0.0.0 www.whereugetxxx.com -0.0.0.0 www.xxxcounter.com -0.0.0.0 x.cb.kount.com -0.0.0.0 xcnn.com -0.0.0.0 xxxcounter.com -0.0.0.0 xyz.freelogs.com -0.0.0.0 zz.cqcounter.com -# -# - -# sites with known trojans, phishing, or other malware -0.0.0.0 05tz2e9.com -0.0.0.0 09killspyware.com -0.0.0.0 11398.onceedge.ru -0.0.0.0 2006mindfreaklike.blogspot.com # Facebook trojan -0.0.0.0 20-yrs-1.info -0.0.0.0 59-106-20-39.r-bl100.sakura.ne.jp -0.0.0.0 662bd114b7c9.onceedge.ru -0.0.0.0 a15172379.alturo-server.de -0.0.0.0 aaukqiooaseseuke.org -0.0.0.0 abetterinternet.com -0.0.0.0 abruzzoinitaly.co.uk -0.0.0.0 acglgoa.com -0.0.0.0 acim.moqhixoz.cn -0.0.0.0 adshufffle.com -0.0.0.0 adwitty.com -0.0.0.0 adwords.google.lloymlincs.com -0.0.0.0 afantispy.com -0.0.0.0 afdbande.cn -0.0.0.0 allhqpics.com # Facebook trojan -0.0.0.0 alphabirdnetwork.com -0.0.0.0 antispywareexpert.com -0.0.0.0 antivirus-online-scan5.com -0.0.0.0 antivirus-scanner8.com -0.0.0.0 antivirus-scanner.com -0.0.0.0 a.oix.com -0.0.0.0 a.oix.net -0.0.0.0 armsart.com -0.0.0.0 articlefuns.cn -0.0.0.0 articleidea.cn -0.0.0.0 asianread.com -0.0.0.0 autohipnose.com -0.0.0.0 a.webwise.com -0.0.0.0 a.webwise.net -0.0.0.0 a.webwise.org -0.0.0.0 beloysoff.ru -0.0.0.0 binsservicesonline.info -0.0.0.0 blackhat.be -0.0.0.0 blenz-me.net -0.0.0.0 bnvxcfhdgf.blogspot.com.es -0.0.0.0 b.oix.com -0.0.0.0 b.oix.net -0.0.0.0 BonusCashh.com -0.0.0.0 brunga.at # Facebook phishing attempt -0.0.0.0 bt.webwise.com -0.0.0.0 bt.webwise.net -0.0.0.0 bt.webwise.org -0.0.0.0 b.webwise.com -0.0.0.0 b.webwise.net -0.0.0.0 b.webwise.org -0.0.0.0 callawaypos.com -0.0.0.0 callbling.com -0.0.0.0 cambonanza.com -0.0.0.0 ccudl.com -0.0.0.0 changduk26.com # Facebook trojan -0.0.0.0 chelick.net # Facebook trojan -0.0.0.0 cioco-froll.com -0.0.0.0 cira.login.cqr.ssl.igotmyloverback.com -0.0.0.0 cleanchain.net -0.0.0.0 click.get-answers-fast.com -0.0.0.0 clien.net -0.0.0.0 cnbc.com-article906773.us -0.0.0.0 co8vd.cn -0.0.0.0 c.oix.com -0.0.0.0 c.oix.net -0.0.0.0 conduit.com -0.0.0.0 cra-arc-gc-ca.noads.biz -0.0.0.0 custom3hurricanedigitalmedia.com -0.0.0.0 c.webwise.com -0.0.0.0 c.webwise.net -0.0.0.0 c.webwise.org -0.0.0.0 dbios.org -0.0.0.0 dhauzja511.co.cc -0.0.0.0 dietpharmacyrx.net -0.0.0.0 download.abetterinternet.com -0.0.0.0 drc-group.net -0.0.0.0 dubstep.onedumb.com -0.0.0.0 east.05tz2e9.com -0.0.0.0 e-kasa.w8w.pl -0.0.0.0 en.likefever.org # Facebook trojan -0.0.0.0 enteryouremail.net -0.0.0.0 eviboli576.o-f.com -0.0.0.0 facebook-repto1040s2.ahlamountada.com -0.0.0.0 faceboook-replyei0ki.montadalitihad.com -0.0.0.0 facemail.com -0.0.0.0 faggotry.com -0.0.0.0 familyupport1.com -0.0.0.0 feaecebook.com -0.0.0.0 fengyixin.com -0.0.0.0 filosvybfimpsv.ru.gg -0.0.0.0 froling.bee.pl -0.0.0.0 fromru.su -0.0.0.0 ftdownload.com -0.0.0.0 fu.golikeus.net # Facebook trojan -0.0.0.0 gamelights.ru -0.0.0.0 gasasthe.freehostia.com -0.0.0.0 get-answers-fast.com -0.0.0.0 gglcash4u.info # twitter worm -0.0.0.0 girlownedbypolicelike.blogspot.com # Facebook trojan -0.0.0.0 goggle.com -0.0.0.0 greatarcadehits.com -0.0.0.0 gyros.es -0.0.0.0 h1317070.stratoserver.net -0.0.0.0 hackerz.ir -0.0.0.0 hakerzy.net -0.0.0.0 hatrecord.ru # Facebook trojan -0.0.0.0 hellwert.biz -0.0.0.0 hotchix.servepics.com -0.0.0.0 hsb-canada.com # phishing site for hsbc.ca -0.0.0.0 hsbconline.ca # phishing site for hsbc.ca -0.0.0.0 icecars.com -0.0.0.0 idea21.org -0.0.0.0 Iframecash.biz -0.0.0.0 infopaypal.com -0.0.0.0 installmac.com -0.0.0.0 ipadzu.net -0.0.0.0 ircleaner.com -0.0.0.0 itwititer.com -0.0.0.0 ity.elusmedic.ru -0.0.0.0 jajajaj-thats-you-really.com -0.0.0.0 janezk.50webs.co -0.0.0.0 jujitsu-ostrava.info -0.0.0.0 jump.ewoss.net -0.0.0.0 juste.ru # Twitter trojan -0.0.0.0 kczambians.com -0.0.0.0 keybinary.com -0.0.0.0 kirgo.at # Facebook phishing attempt -0.0.0.0 klowns4phun.com -0.0.0.0 konflow.com # Facebook trojan -0.0.0.0 kplusd.far.ru -0.0.0.0 kpremium.com -0.0.0.0 lank.ru -0.0.0.0 lighthouse2k.com -0.0.0.0 like.likewut.net -0.0.0.0 likeportal.com # Facebook trojan -0.0.0.0 likespike.com # Facebook trojan -0.0.0.0 likethislist.biz # Facebook trojan -0.0.0.0 likethis.mbosoft.com # Facebook trojan -0.0.0.0 loseweight.asdjiiw.com -0.0.0.0 lucibad.home.ro -0.0.0.0 luxcart.ro -0.0.0.0 m01.oix.com -0.0.0.0 m01.oix.net -0.0.0.0 m01.webwise.com -0.0.0.0 m01.webwise.net -0.0.0.0 m01.webwise.org -0.0.0.0 m02.oix.com -0.0.0.0 m02.oix.net -0.0.0.0 m02.webwise.com -0.0.0.0 m02.webwise.net -0.0.0.0 m02.webwise.org -0.0.0.0 mail.cyberh.fr -0.0.0.0 malware-live-pro-scanv1.com -0.0.0.0 maxi4.firstvds.ru -0.0.0.0 megasurfin.com -0.0.0.0 monkeyball.osa.pl -0.0.0.0 movies.701pages.com -0.0.0.0 mplayerdownloader.com -0.0.0.0 murcia-ban.es -0.0.0.0 mylike.co.uk # Facebook trojan -0.0.0.0 nactx.com -0.0.0.0 natashyabaydesign.com -0.0.0.0 new-dating-2012.info -0.0.0.0 new-vid-zone-1.blogspot.com.au -0.0.0.0 newwayscanner.info -0.0.0.0 novemberrainx.com -0.0.0.0 ns1.oix.com -0.0.0.0 ns1.oix.net -0.0.0.0 ns1.webwise.com -0.0.0.0 ns1.webwise.net -0.0.0.0 ns1.webwise.org -0.0.0.0 ns2.oix.com -0.0.0.0 ns2.oix.net -0.0.0.0 ns2.webwise.com -0.0.0.0 ns2.webwise.net -0.0.0.0 ns2.webwise.org -0.0.0.0 nufindings.info -0.0.0.0 office.officenet.co.kr -0.0.0.0 oix.com -0.0.0.0 oix.net -0.0.0.0 oj.likewut.net -0.0.0.0 online-antispym4.com -0.0.0.0 oo-na-na-pics.com -0.0.0.0 ordersildenafil.com -0.0.0.0 otsserver.com -0.0.0.0 outerinfo.com -0.0.0.0 paincake.yoll.net -0.0.0.0 pc-scanner16.com -0.0.0.0 personalantispy.com -0.0.0.0 phatthalung.go.th -0.0.0.0 picture-uploads.com -0.0.0.0 pilltabletsrxbargain.net -0.0.0.0 powabcyfqe.com -0.0.0.0 premium-live-scan.com -0.0.0.0 products-gold.net -0.0.0.0 proflashdata.com # Facebook trojan -0.0.0.0 protectionupdatecenter.com -0.0.0.0 pv.wantsfly.com -0.0.0.0 qip.ru -0.0.0.0 qy.corrmedic.ru -0.0.0.0 rd.alphabirdnetwork.com -0.0.0.0 rickrolling.com -0.0.0.0 roifmd.info -0.0.0.0 russian-sex.com -0.0.0.0 s4d.in -0.0.0.0 scan.antispyware-free-scanner.com -0.0.0.0 scanner.best-click-av1.info -0.0.0.0 scanner.best-protect.info -0.0.0.0 scottishstuff-online.com # Canadian bank phishing site -0.0.0.0 sc-spyware.com -0.0.0.0 search.conduit.com -0.0.0.0 securedliveuploads.com -0.0.0.0 securityandroidupdate.dinamikaprinting.com -0.0.0.0 securityscan.us -0.0.0.0 sexymarissa.net -0.0.0.0 shell.xhhow4.com -0.0.0.0 shoppstop.comood.opsource.net -0.0.0.0 shop.skin-safety.com -0.0.0.0 signin-ebay-com-ws-ebayisapi-dll-signin-webscr.ocom.pl -0.0.0.0 sinera.org -0.0.0.0 sjguild.com -0.0.0.0 smarturl.it -0.0.0.0 smile-angel.com -0.0.0.0 software-updates.co -0.0.0.0 software-wenc.co.cc -0.0.0.0 someonewhocares.com -0.0.0.0 sousay.info -0.0.0.0 start.qip.ru -0.0.0.0 superegler.net -0.0.0.0 supernaturalart.com -0.0.0.0 superprotection10.com -0.0.0.0 sverd.net -0.0.0.0 tahoesup.com -0.0.0.0 tattooshaha.info # Facebook trojan -0.0.0.0 test.ishvara-yoga.com -0.0.0.0 TheBizMeet.com -0.0.0.0 thedatesafe.com # Facebook trojan -0.0.0.0 themoneyclippodcast.com -0.0.0.0 themusicnetwork.co.uk -0.0.0.0 thinstall.abetterinternet.com -0.0.0.0 tivvitter.com -0.0.0.0 tomorrownewstoday.com # I'm not sure what it does, but it seems to be associated with a phishing attempt on Facebook -0.0.0.0 toolbarbest.biz -0.0.0.0 toolbarbucks.biz -0.0.0.0 toolbarcool.biz -0.0.0.0 toolbardollars.biz -0.0.0.0 toolbarmoney.biz -0.0.0.0 toolbarnew.biz -0.0.0.0 toolbarsale.biz -0.0.0.0 toolbarweb.biz -0.0.0.0 traffic.adwitty.com -0.0.0.0 trialreg.com -0.0.0.0 tvshowslist.com -0.0.0.0 twitter.login.kevanshome.org -0.0.0.0 twitter.secure.bzpharma.net -0.0.0.0 uawj.moqhixoz.cn -0.0.0.0 ughmvqf.spitt.ru -0.0.0.0 uqz.com -0.0.0.0 users16.jabry.com -0.0.0.0 utenti.lycos.it -0.0.0.0 vcipo.info -0.0.0.0 videos.dskjkiuw.com -0.0.0.0 videos.twitter.secure-logins01.com # twitter worm (http://mashable.com/2009/09/23/twitter-worm-dms/) -0.0.0.0 vxiframe.biz -0.0.0.0 waldenfarms.com -0.0.0.0 weblover.info -0.0.0.0 webpaypal.com -0.0.0.0 webwise.com -0.0.0.0 webwise.net -0.0.0.0 webwise.org -0.0.0.0 west.05tz2e9.com -0.0.0.0 wewillrocknow.com -0.0.0.0 willysy.com -0.0.0.0 wm.maxysearch.info -0.0.0.0 womo.corrmedic.ru -0.0.0.0 www1.bmo.com.hotfrio.com.br -0.0.0.0 www1.firesavez5.com -0.0.0.0 www1.firesavez6.com -0.0.0.0 www1.realsoft34.com -0.0.0.0 www4.gy7k.net -0.0.0.0 www.abetterinternet.com -0.0.0.0 www.adshufffle.com -0.0.0.0 www.adwords.google.lloymlincs.com -0.0.0.0 www.afantispy.com -0.0.0.0 www.akoneplatit.sk -0.0.0.0 www.allhqpics.com # Facebook trojan -0.0.0.0 www.alrpost69.com -0.0.0.0 www.anatol.com -0.0.0.0 www.articlefuns.cn -0.0.0.0 www.articleidea.cn -0.0.0.0 www.asianread.com -0.0.0.0 www.backsim.ru -0.0.0.0 www.bankofamerica.com.ok.am -0.0.0.0 www.be4life.ru -0.0.0.0 www.blenz-me.net -0.0.0.0 www.cambonanza.com -0.0.0.0 www.chelick.net # Facebook trojan -0.0.0.0 www.didata.bw -0.0.0.0 www.dietsecret.ru -0.0.0.0 www.eroyear.ru -0.0.0.0 www.exbays.com -0.0.0.0 www.faggotry.com -0.0.0.0 www.feaecebook.com -0.0.0.0 www.fictioncinema.com -0.0.0.0 www.fischereszter.hu -0.0.0.0 www.froling.bee.pl -0.0.0.0 www.gns-consola.com -0.0.0.0 www.goggle.com -0.0.0.0 www.grouphappy.com -0.0.0.0 www.hakerzy.net -0.0.0.0 www.haoyunlaid.com -0.0.0.0 www.icecars.com -0.0.0.0 www.indesignstudioinfo.com -0.0.0.0 www.infopaypal.com -0.0.0.0 www.keybinary.com -0.0.0.0 www.kinomarathon.ru -0.0.0.0 www.kpremium.com -0.0.0.0 www.likeportal.com # Facebook trojan -0.0.0.0 www.likespike.com # Facebook trojan -0.0.0.0 www.likethislist.biz # Facebook trojan -0.0.0.0 www.likethis.mbosoft.com # Facebook trojan -0.0.0.0 www.lomalindasda.org # Facebook trojan -0.0.0.0 www.lovecouple.ru -0.0.0.0 www.lovetrust.ru -0.0.0.0 www.mikras.nl -0.0.0.0 www.monkeyball.osa.pl -0.0.0.0 www.monsonis.net -0.0.0.0 www.movie-port.ru -0.0.0.0 www.mplayerdownloader.com -0.0.0.0 www.mylike.co.uk # Facebook trojan -0.0.0.0 www.mylovecards.com -0.0.0.0 www.nine2rack.in -0.0.0.0 www.novemberrainx.com -0.0.0.0 www.nu26.com -0.0.0.0 www.oix.com -0.0.0.0 www.oix.net -0.0.0.0 www.onlyfreeoffersonline.com -0.0.0.0 www.oreidofitilho.com.br -0.0.0.0 www.otsserver.com -0.0.0.0 www.pay-pal.com-cgibin-canada.4mcmeta4v.cn -0.0.0.0 www.picture-uploads.com -0.0.0.0 www.portaldimensional.com -0.0.0.0 www.poxudeli.ru -0.0.0.0 www.proflashdata.com # Facebook trojan -0.0.0.0 www.rickrolling.com -0.0.0.0 www.russian-sex.com -0.0.0.0 www.scotiaonline.scotiabank.salferreras.com -0.0.0.0 www.sdlpgift.com -0.0.0.0 www.securityscan.us -0.0.0.0 www.servertasarimbu.com -0.0.0.0 www.sexytiger.ru -0.0.0.0 www.shinilchurch.net # domain was hacked and had a trojan installed -0.0.0.0 www.sinera.org -0.0.0.0 www.someonewhocares.com -0.0.0.0 www.tanger.com.br -0.0.0.0 www.tattooshaha.info # Facebook trojan -0.0.0.0 www.te81.net -0.0.0.0 www.thedatesafe.com # Facebook trojan -0.0.0.0 www.trucktirehotline.com -0.0.0.0 www.tvshowslist.com -0.0.0.0 www.upi6.pillsstore-c.com # Facebook trojan -0.0.0.0 www.uqz.com -0.0.0.0 www.via99.org -0.0.0.0 www.videolove.clanteam.com -0.0.0.0 www.videostan.ru -0.0.0.0 www.vippotexa.ru -0.0.0.0 www.wantsfly.com -0.0.0.0 www.webpaypal.com -0.0.0.0 www.webwise.com -0.0.0.0 www.webwise.net -0.0.0.0 www.webwise.org -0.0.0.0 www.wewillrocknow.com -0.0.0.0 www.willysy.com -0.0.0.0 xfotosx01.fromru.su -0.0.0.0 xponlinescanner.com -0.0.0.0 xvrxyzba253.hotmail.ru -0.0.0.0 yrwap.cn -0.0.0.0 zarozinski.info -0.0.0.0 zettapetta.com -0.0.0.0 zfotos.fromru.su -0.0.0.0 zip.er.cz -0.0.0.0 ztrf.net -0.0.0.0 zviframe.biz -# - -# - -0.0.0.0 3ad.doubleclick.net -0.0.0.0 ad2.doubleclick.net -0.0.0.0 ad.3au.doubleclick.net -0.0.0.0 ad.ae.doubleclick.net -0.0.0.0 ad.au.doubleclick.net -0.0.0.0 ad.be.doubleclick.net -0.0.0.0 ad.br.doubleclick.net -0.0.0.0 ad.de.doubleclick.net -0.0.0.0 ad.dk.doubleclick.net -0.0.0.0 ad-emea.doubleclick.net -0.0.0.0 ad.es.doubleclick.net -0.0.0.0 ad.fi.doubleclick.net -0.0.0.0 ad.fr.doubleclick.net -0.0.0.0 ad-g.doubleclick.net -0.0.0.0 ad.it.doubleclick.net -0.0.0.0 ad.jp.doubleclick.net -0.0.0.0 ad.mo.doubleclick.net -0.0.0.0 ad.n2434.doubleclick.net -0.0.0.0 ad.nl.doubleclick.net -0.0.0.0 ad.no.doubleclick.net -0.0.0.0 ad.nz.doubleclick.net -0.0.0.0 ad.pl.doubleclick.net -0.0.0.0 ad.se.doubleclick.net -0.0.0.0 ad.sg.doubleclick.net -0.0.0.0 ad.uk.doubleclick.net -0.0.0.0 ad.ve.doubleclick.net -0.0.0.0 ad-yt-bfp.doubleclick.net -0.0.0.0 ad.za.doubleclick.net -0.0.0.0 amn.doubleclick.net -0.0.0.0 creative.cc-dt.com -0.0.0.0 doubleclick.de -0.0.0.0 doubleclick.net -0.0.0.0 ebaycn.doubleclick.net -0.0.0.0 ebaytw.doubleclick.net -0.0.0.0 exnjadgda1.doubleclick.net -0.0.0.0 exnjadgda2.doubleclick.net -0.0.0.0 exnjadgds1.doubleclick.net -0.0.0.0 exnjmdgda1.doubleclick.net -0.0.0.0 exnjmdgds1.doubleclick.net -0.0.0.0 feedads.g.doubleclick.net -0.0.0.0 fls.doubleclick.net -0.0.0.0 gd10.doubleclick.net -0.0.0.0 gd11.doubleclick.net -0.0.0.0 gd12.doubleclick.net -0.0.0.0 gd13.doubleclick.net -0.0.0.0 gd14.doubleclick.net -0.0.0.0 gd15.doubleclick.net -0.0.0.0 gd16.doubleclick.net -0.0.0.0 gd17.doubleclick.net -0.0.0.0 gd18.doubleclick.net -0.0.0.0 gd19.doubleclick.net -0.0.0.0 gd1.doubleclick.net -0.0.0.0 gd20.doubleclick.net -0.0.0.0 gd21.doubleclick.net -0.0.0.0 gd22.doubleclick.net -0.0.0.0 gd23.doubleclick.net -0.0.0.0 gd24.doubleclick.net -0.0.0.0 gd25.doubleclick.net -0.0.0.0 gd26.doubleclick.net -0.0.0.0 gd27.doubleclick.net -0.0.0.0 gd28.doubleclick.net -0.0.0.0 gd29.doubleclick.net -0.0.0.0 gd2.doubleclick.net -0.0.0.0 gd30.doubleclick.net -0.0.0.0 gd31.doubleclick.net -0.0.0.0 gd3.doubleclick.net -0.0.0.0 gd4.doubleclick.net -0.0.0.0 gd5.doubleclick.net -0.0.0.0 gd7.doubleclick.net -0.0.0.0 gd8.doubleclick.net -0.0.0.0 gd9.doubleclick.net -0.0.0.0 googleads.g.doubleclick.net -0.0.0.0 iv.doubleclick.net -0.0.0.0 ln.doubleclick.net -0.0.0.0 m1.2mdn.net -0.0.0.0 m1.ae.2mdn.net -0.0.0.0 m1.au.2mdn.net -0.0.0.0 m1.be.2mdn.net -0.0.0.0 m1.br.2mdn.net -0.0.0.0 m1.ca.2mdn.net -0.0.0.0 m1.cn.2mdn.net -0.0.0.0 m1.de.2mdn.net -0.0.0.0 m1.dk.2mdn.net -0.0.0.0 m1.doubleclick.net -0.0.0.0 m1.es.2mdn.net -0.0.0.0 m1.fi.2mdn.net -0.0.0.0 m1.fr.2mdn.net -0.0.0.0 m1.it.2mdn.net -0.0.0.0 m1.jp.2mdn.net -0.0.0.0 m1.nl.2mdn.net -0.0.0.0 m1.no.2mdn.net -0.0.0.0 m1.nz.2mdn.net -0.0.0.0 m1.pl.2mdn.net -0.0.0.0 m1.se.2mdn.net -0.0.0.0 m1.sg.2mdn.net -0.0.0.0 m1.uk.2mdn.net -0.0.0.0 m1.ve.2mdn.net -0.0.0.0 m1.za.2mdn.net -0.0.0.0 m2.ae.2mdn.net -0.0.0.0 m2.au.2mdn.net -0.0.0.0 m2.be.2mdn.net -0.0.0.0 m2.br.2mdn.net -0.0.0.0 m2.ca.2mdn.net -0.0.0.0 m2.cn.2mdn.net -0.0.0.0 m2.cn.doubleclick.net -0.0.0.0 m2.de.2mdn.net -0.0.0.0 m2.dk.2mdn.net -0.0.0.0 m2.doubleclick.net -0.0.0.0 m2.es.2mdn.net -0.0.0.0 m2.fi.2mdn.net -0.0.0.0 m2.fr.2mdn.net -0.0.0.0 m2.it.2mdn.net -0.0.0.0 m2.jp.2mdn.net -0.0.0.0 m.2mdn.net -0.0.0.0 m2.nl.2mdn.net -0.0.0.0 m2.no.2mdn.net -0.0.0.0 m2.nz.2mdn.net -0.0.0.0 m2.pl.2mdn.net -0.0.0.0 m2.se.2mdn.net -0.0.0.0 m2.sg.2mdn.net -0.0.0.0 m2.uk.2mdn.net -0.0.0.0 m2.ve.2mdn.net -0.0.0.0 m2.za.2mdn.net -0.0.0.0 m3.ae.2mdn.net -0.0.0.0 m3.au.2mdn.net -0.0.0.0 m3.be.2mdn.net -0.0.0.0 m3.br.2mdn.net -0.0.0.0 m3.ca.2mdn.net -0.0.0.0 m3.cn.2mdn.net -0.0.0.0 m3.de.2mdn.net -0.0.0.0 m3.dk.2mdn.net -0.0.0.0 m3.doubleclick.net -0.0.0.0 m3.es.2mdn.net -0.0.0.0 m3.fi.2mdn.net -0.0.0.0 m3.fr.2mdn.net -0.0.0.0 m3.it.2mdn.net -0.0.0.0 m3.jp.2mdn.net -0.0.0.0 m3.nl.2mdn.net -0.0.0.0 m3.no.2mdn.net -0.0.0.0 m3.nz.2mdn.net -0.0.0.0 m3.pl.2mdn.net -0.0.0.0 m3.se.2mdn.net -0.0.0.0 m3.sg.2mdn.net -0.0.0.0 m3.uk.2mdn.net -0.0.0.0 m3.ve.2mdn.net -0.0.0.0 m3.za.2mdn.net -0.0.0.0 m4.ae.2mdn.net -0.0.0.0 m4.au.2mdn.net -0.0.0.0 m4.be.2mdn.net -0.0.0.0 m4.br.2mdn.net -0.0.0.0 m4.ca.2mdn.net -0.0.0.0 m4.cn.2mdn.net -0.0.0.0 m4.de.2mdn.net -0.0.0.0 m4.dk.2mdn.net -0.0.0.0 m4.doubleclick.net -0.0.0.0 m4.es.2mdn.net -0.0.0.0 m4.fi.2mdn.net -0.0.0.0 m4.fr.2mdn.net -0.0.0.0 m4.it.2mdn.net -0.0.0.0 m4.jp.2mdn.net -0.0.0.0 m4.nl.2mdn.net -0.0.0.0 m4.no.2mdn.net -0.0.0.0 m4.nz.2mdn.net -0.0.0.0 m4.pl.2mdn.net -0.0.0.0 m4.se.2mdn.net -0.0.0.0 m4.sg.2mdn.net -0.0.0.0 m4.uk.2mdn.net -0.0.0.0 m4.ve.2mdn.net -0.0.0.0 m4.za.2mdn.net -0.0.0.0 m5.ae.2mdn.net -0.0.0.0 m5.au.2mdn.net -0.0.0.0 m5.be.2mdn.net -0.0.0.0 m5.br.2mdn.net -0.0.0.0 m5.ca.2mdn.net -0.0.0.0 m5.cn.2mdn.net -0.0.0.0 m5.de.2mdn.net -0.0.0.0 m5.dk.2mdn.net -0.0.0.0 m5.doubleclick.net -0.0.0.0 m5.es.2mdn.net -0.0.0.0 m5.fi.2mdn.net -0.0.0.0 m5.fr.2mdn.net -0.0.0.0 m5.it.2mdn.net -0.0.0.0 m5.jp.2mdn.net -0.0.0.0 m5.nl.2mdn.net -0.0.0.0 m5.no.2mdn.net -0.0.0.0 m5.nz.2mdn.net -0.0.0.0 m5.pl.2mdn.net -0.0.0.0 m5.se.2mdn.net -0.0.0.0 m5.sg.2mdn.net -0.0.0.0 m5.uk.2mdn.net -0.0.0.0 m5.ve.2mdn.net -0.0.0.0 m5.za.2mdn.net -0.0.0.0 m6.ae.2mdn.net -0.0.0.0 m6.au.2mdn.net -0.0.0.0 m6.be.2mdn.net -0.0.0.0 m6.br.2mdn.net -0.0.0.0 m6.ca.2mdn.net -0.0.0.0 m6.cn.2mdn.net -0.0.0.0 m6.de.2mdn.net -0.0.0.0 m6.dk.2mdn.net -0.0.0.0 m6.doubleclick.net -0.0.0.0 m6.es.2mdn.net -0.0.0.0 m6.fi.2mdn.net -0.0.0.0 m6.fr.2mdn.net -0.0.0.0 m6.it.2mdn.net -0.0.0.0 m6.jp.2mdn.net -0.0.0.0 m6.nl.2mdn.net -0.0.0.0 m6.no.2mdn.net -0.0.0.0 m6.nz.2mdn.net -0.0.0.0 m6.pl.2mdn.net -0.0.0.0 m6.se.2mdn.net -0.0.0.0 m6.sg.2mdn.net -0.0.0.0 m6.uk.2mdn.net -0.0.0.0 m6.ve.2mdn.net -0.0.0.0 m6.za.2mdn.net -0.0.0.0 m7.ae.2mdn.net -0.0.0.0 m7.au.2mdn.net -0.0.0.0 m7.be.2mdn.net -0.0.0.0 m7.br.2mdn.net -0.0.0.0 m7.ca.2mdn.net -0.0.0.0 m7.cn.2mdn.net -0.0.0.0 m7.de.2mdn.net -0.0.0.0 m7.dk.2mdn.net -0.0.0.0 m7.doubleclick.net -0.0.0.0 m7.es.2mdn.net -0.0.0.0 m7.fi.2mdn.net -0.0.0.0 m7.fr.2mdn.net -0.0.0.0 m7.it.2mdn.net -0.0.0.0 m7.jp.2mdn.net -0.0.0.0 m7.nl.2mdn.net -0.0.0.0 m7.no.2mdn.net -0.0.0.0 m7.nz.2mdn.net -0.0.0.0 m7.pl.2mdn.net -0.0.0.0 m7.se.2mdn.net -0.0.0.0 m7.sg.2mdn.net -0.0.0.0 m7.uk.2mdn.net -0.0.0.0 m7.ve.2mdn.net -0.0.0.0 m7.za.2mdn.net -0.0.0.0 m8.ae.2mdn.net -0.0.0.0 m8.au.2mdn.net -0.0.0.0 m8.be.2mdn.net -0.0.0.0 m8.br.2mdn.net -0.0.0.0 m8.ca.2mdn.net -0.0.0.0 m8.cn.2mdn.net -0.0.0.0 m8.de.2mdn.net -0.0.0.0 m8.dk.2mdn.net -0.0.0.0 m8.doubleclick.net -0.0.0.0 m8.es.2mdn.net -0.0.0.0 m8.fi.2mdn.net -0.0.0.0 m8.fr.2mdn.net -0.0.0.0 m8.it.2mdn.net -0.0.0.0 m8.jp.2mdn.net -0.0.0.0 m8.nl.2mdn.net -0.0.0.0 m8.no.2mdn.net -0.0.0.0 m8.nz.2mdn.net -0.0.0.0 m8.pl.2mdn.net -0.0.0.0 m8.se.2mdn.net -0.0.0.0 m8.sg.2mdn.net -0.0.0.0 m8.uk.2mdn.net -0.0.0.0 m8.ve.2mdn.net -0.0.0.0 m8.za.2mdn.net -0.0.0.0 m9.ae.2mdn.net -0.0.0.0 m9.au.2mdn.net -0.0.0.0 m9.be.2mdn.net -0.0.0.0 m9.br.2mdn.net -0.0.0.0 m9.ca.2mdn.net -0.0.0.0 m9.cn.2mdn.net -0.0.0.0 m9.de.2mdn.net -0.0.0.0 m9.dk.2mdn.net -0.0.0.0 m9.doubleclick.net -0.0.0.0 m9.es.2mdn.net -0.0.0.0 m9.fi.2mdn.net -0.0.0.0 m9.fr.2mdn.net -0.0.0.0 m9.it.2mdn.net -0.0.0.0 m9.jp.2mdn.net -0.0.0.0 m9.nl.2mdn.net -0.0.0.0 m9.no.2mdn.net -0.0.0.0 m9.nz.2mdn.net -0.0.0.0 m9.pl.2mdn.net -0.0.0.0 m9.se.2mdn.net -0.0.0.0 m9.sg.2mdn.net -0.0.0.0 m9.uk.2mdn.net -0.0.0.0 m9.ve.2mdn.net -0.0.0.0 m9.za.2mdn.net -0.0.0.0 m.de.2mdn.net -0.0.0.0 m.doubleclick.net -0.0.0.0 n3302ad.doubleclick.net -0.0.0.0 n3349ad.doubleclick.net -0.0.0.0 n4061ad.doubleclick.net -0.0.0.0 n4403ad.doubleclick.net -0.0.0.0 n479ad.doubleclick.net -0.0.0.0 optimize.doubleclick.net -0.0.0.0 pubads.g.doubleclick.net -0.0.0.0 rd.intl.doubleclick.net -0.0.0.0 securepubads.g.doubleclick.net -0.0.0.0 stats.g.doubleclick.net -0.0.0.0 twx.2mdn.net -0.0.0.0 twx.doubleclick.net -0.0.0.0 ukrpts.net -0.0.0.0 uunyadgda1.doubleclick.net -0.0.0.0 uunyadgds1.doubleclick.net -0.0.0.0 www.ukrpts.net -# - -# - -0.0.0.0 1up.us.intellitxt.com -0.0.0.0 5starhiphop.us.intellitxt.com -0.0.0.0 askmen2.us.intellitxt.com -0.0.0.0 bargainpda.us.intellitxt.com -0.0.0.0 businesspundit.us.intellitxt.com -0.0.0.0 canadafreepress.us.intellitxt.com -0.0.0.0 contactmusic.uk.intellitxt.com -0.0.0.0 ctv.us.intellitxt.com -0.0.0.0 designtechnica.us.intellitxt.com -0.0.0.0 devshed.us.intellitxt.com -0.0.0.0 digitaltrends.us.intellitxt.com -0.0.0.0 dnps.us.intellitxt.com -0.0.0.0 doubleviking.us.intellitxt.com -0.0.0.0 drizzydrake.us.intellitxt.com -0.0.0.0 ehow.us.intellitxt.com -0.0.0.0 entertainment.msnbc.us.intellitxt.com -0.0.0.0 examnotes.us.intellitxt.com -0.0.0.0 excite.us.intellitxt.com -0.0.0.0 experts.us.intellitxt.com -0.0.0.0 extremetech.us.intellitxt.com -0.0.0.0 ferrago.uk.intellitxt.com -0.0.0.0 filmschoolrejects.us.intellitxt.com -0.0.0.0 filmwad.us.intellitxt.com -0.0.0.0 firstshowing.us.intellitxt.com -0.0.0.0 flashmagazine.us.intellitxt.com -0.0.0.0 foxnews.us.intellitxt.com -0.0.0.0 foxtv.us.intellitxt.com -0.0.0.0 freedownloadcenter.uk.intellitxt.com -0.0.0.0 gadgets.fosfor.se.intellitxt.com -0.0.0.0 gamesradar.us.intellitxt.com -0.0.0.0 gannettbroadcast.us.intellitxt.com -0.0.0.0 gonintendo.us.intellitxt.com -0.0.0.0 gorillanation.us.intellitxt.com -0.0.0.0 hackedgadgets.us.intellitxt.com -0.0.0.0 hardcoreware.us.intellitxt.com -0.0.0.0 hardocp.us.intellitxt.com -0.0.0.0 hothardware.us.intellitxt.com -0.0.0.0 hotonlinenews.us.intellitxt.com -0.0.0.0 ign.us.intellitxt.com -0.0.0.0 images.intellitxt.com -0.0.0.0 itxt2.us.intellitxt.com -0.0.0.0 joblo.us.intellitxt.com -0.0.0.0 johnchow.us.intellitxt.com -0.0.0.0 laptopmag.us.intellitxt.com -0.0.0.0 linuxforums.us.intellitxt.com -0.0.0.0 maccity.it.intellitxt.com -0.0.0.0 macnn.us.intellitxt.com -0.0.0.0 macuser.uk.intellitxt.com -0.0.0.0 macworld.uk.intellitxt.com -0.0.0.0 metro.uk.intellitxt.com -0.0.0.0 mobile9.us.intellitxt.com -0.0.0.0 monstersandcritics.uk.intellitxt.com -0.0.0.0 moviesonline.ca.intellitxt.com -0.0.0.0 mustangevolution.us.intellitxt.com -0.0.0.0 neowin.us.intellitxt.com -0.0.0.0 newcarnet.uk.intellitxt.com -0.0.0.0 newlaunches.uk.intellitxt.com -0.0.0.0 nexys404.us.intellitxt.com -0.0.0.0 ohgizmo.us.intellitxt.com -0.0.0.0 pcadvisor.uk.intellitxt.com -0.0.0.0 pcgameshardware.de.intellitxt.com -0.0.0.0 pcmag.us.intellitxt.com -0.0.0.0 pcper.us.intellitxt.com -0.0.0.0 penton.us.intellitxt.com -0.0.0.0 physorg.uk.intellitxt.com -0.0.0.0 physorg.us.intellitxt.com -0.0.0.0 playfuls.uk.intellitxt.com -0.0.0.0 pocketlint.uk.intellitxt.com -0.0.0.0 popularmechanics.us.intellitxt.com -0.0.0.0 postchronicle.us.intellitxt.com -0.0.0.0 projectorreviews.us.intellitxt.com -0.0.0.0 psp3d.us.intellitxt.com -0.0.0.0 pspcave.uk.intellitxt.com -0.0.0.0 qj.us.intellitxt.com -0.0.0.0 rasmussenreports.us.intellitxt.com -0.0.0.0 rawstory.us.intellitxt.com -0.0.0.0 savemanny.us.intellitxt.com -0.0.0.0 sc.intellitxt.com -0.0.0.0 siliconera.us.intellitxt.com -0.0.0.0 slashphone.us.intellitxt.com -0.0.0.0 soft32.us.intellitxt.com -0.0.0.0 softpedia.uk.intellitxt.com -0.0.0.0 somethingawful.us.intellitxt.com -0.0.0.0 splashnews.uk.intellitxt.com -0.0.0.0 spymac.us.intellitxt.com -0.0.0.0 techeblog.us.intellitxt.com -0.0.0.0 technewsworld.us.intellitxt.com -0.0.0.0 technologyreview.us.intellitxt.com -0.0.0.0 techspot.us.intellitxt.com -0.0.0.0 tgdaily.us.intellitxt.com -0.0.0.0 the-gadgeteer.us.intellitxt.com -0.0.0.0 thelastboss.us.intellitxt.com -0.0.0.0 thetechzone.us.intellitxt.com -0.0.0.0 thoughtsmedia.us.intellitxt.com -0.0.0.0 tmcnet.us.intellitxt.com -0.0.0.0 tomsnetworking.us.intellitxt.com -0.0.0.0 toms.us.intellitxt.com -0.0.0.0 tribal.us.intellitxt.com # vibrantmedia.com -0.0.0.0 universetoday.us.intellitxt.com -0.0.0.0 us.intellitxt.com -0.0.0.0 warp2search.us.intellitxt.com -0.0.0.0 wi-fitechnology.uk.intellitxt.com -0.0.0.0 worldnetdaily.us.intellitxt.com -# - -# - -# Red Sheriff and imrworldwide.com -- server side tracking -0.0.0.0 devfw.imrworldwide.com -0.0.0.0 fe1-au.imrworldwide.com -0.0.0.0 fe1-fi.imrworldwide.com -0.0.0.0 fe1-it.imrworldwide.com -0.0.0.0 fe2-au.imrworldwide.com -0.0.0.0 fe3-au.imrworldwide.com -0.0.0.0 fe3-gc.imrworldwide.com -0.0.0.0 fe3-uk.imrworldwide.com -0.0.0.0 fe4-uk.imrworldwide.com -0.0.0.0 fe-au.imrworldwide.com -0.0.0.0 imrworldwide.com -0.0.0.0 lycos-eu.imrworldwide.com -0.0.0.0 ninemsn.imrworldwide.com -0.0.0.0 rc-au.imrworldwide.com -0.0.0.0 redsheriff.com -#0.0.0.0 secure-au.imrworldwide.com -0.0.0.0 secure-jp.imrworldwide.com -0.0.0.0 secure-nz.imrworldwide.com -0.0.0.0 secure-uk.imrworldwide.com -0.0.0.0 secure-us.imrworldwide.com -0.0.0.0 secure-za.imrworldwide.com -0.0.0.0 server-au.imrworldwide.com -0.0.0.0 server-br.imrworldwide.com -0.0.0.0 server-by.imrworldwide.com -0.0.0.0 server-ca.imrworldwide.com -0.0.0.0 server-de.imrworldwide.com -0.0.0.0 server-dk.imrworldwide.com -0.0.0.0 server-ee.imrworldwide.com -0.0.0.0 server-fi.imrworldwide.com -0.0.0.0 server-fr.imrworldwide.com -0.0.0.0 server-hk.imrworldwide.com -0.0.0.0 server-it.imrworldwide.com -0.0.0.0 server-jp.imrworldwide.com -0.0.0.0 server-lt.imrworldwide.com -0.0.0.0 server-lv.imrworldwide.com -0.0.0.0 server-no.imrworldwide.com -0.0.0.0 server-nz.imrworldwide.com -0.0.0.0 server-oslo.imrworldwide.com -0.0.0.0 server-pl.imrworldwide.com -0.0.0.0 server-ru.imrworldwide.com -0.0.0.0 server-se.imrworldwide.com -0.0.0.0 server-sg.imrworldwide.com -0.0.0.0 server-stockh.imrworldwide.com -0.0.0.0 server-ua.imrworldwide.com -0.0.0.0 server-uk.imrworldwide.com -0.0.0.0 server-us.imrworldwide.com -0.0.0.0 server-za.imrworldwide.com -0.0.0.0 survey1-au.imrworldwide.com -0.0.0.0 telstra.imrworldwide.com -0.0.0.0 www.imrworldwide.com -0.0.0.0 www.imrworldwide.com.au -0.0.0.0 www.redsheriff.com -# - -# - -# cydoor -- server side tracking -0.0.0.0 cydoor.com -0.0.0.0 j.2004cms.com # cydoor -0.0.0.0 jbaventures.cjt1.net -0.0.0.0 jbeet.cjt1.net -0.0.0.0 jbit.cjt1.net -0.0.0.0 jcollegehumor.cjt1.net -0.0.0.0 jcontent.bns1.net -0.0.0.0 jdownloadacc.cjt1.net -0.0.0.0 jgen10.cjt1.net -0.0.0.0 jgen11.cjt1.net -0.0.0.0 jgen12.cjt1.net -0.0.0.0 jgen13.cjt1.net -0.0.0.0 jgen14.cjt1.net -0.0.0.0 jgen15.cjt1.net -0.0.0.0 jgen16.cjt1.net -0.0.0.0 jgen17.cjt1.net -0.0.0.0 jgen18.cjt1.net -0.0.0.0 jgen19.cjt1.net -0.0.0.0 jgen1.cjt1.net -0.0.0.0 jgen20.cjt1.net -0.0.0.0 jgen21.cjt1.net -0.0.0.0 jgen22.cjt1.net -0.0.0.0 jgen23.cjt1.net -0.0.0.0 jgen24.cjt1.net -0.0.0.0 jgen25.cjt1.net -0.0.0.0 jgen26.cjt1.net -0.0.0.0 jgen27.cjt1.net -0.0.0.0 jgen28.cjt1.net -0.0.0.0 jgen29.cjt1.net -0.0.0.0 jgen2.cjt1.net -0.0.0.0 jgen30.cjt1.net -0.0.0.0 jgen31.cjt1.net -0.0.0.0 jgen32.cjt1.net -0.0.0.0 jgen33.cjt1.net -0.0.0.0 jgen34.cjt1.net -0.0.0.0 jgen35.cjt1.net -0.0.0.0 jgen36.cjt1.net -0.0.0.0 jgen37.cjt1.net -0.0.0.0 jgen38.cjt1.net -0.0.0.0 jgen39.cjt1.net -0.0.0.0 jgen3.cjt1.net -0.0.0.0 jgen40.cjt1.net -0.0.0.0 jgen41.cjt1.net -0.0.0.0 jgen42.cjt1.net -0.0.0.0 jgen43.cjt1.net -0.0.0.0 jgen44.cjt1.net -0.0.0.0 jgen45.cjt1.net -0.0.0.0 jgen46.cjt1.net -0.0.0.0 jgen47.cjt1.net -0.0.0.0 jgen48.cjt1.net -0.0.0.0 jgen49.cjt1.net -0.0.0.0 jgen4.cjt1.net -0.0.0.0 jgen5.cjt1.net -0.0.0.0 jgen6.cjt1.net -0.0.0.0 jgen7.cjt1.net -0.0.0.0 jgen8.cjt1.net -0.0.0.0 jgen9.cjt1.net -0.0.0.0 jhumour.cjt1.net -0.0.0.0 jmbi58.cjt1.net -0.0.0.0 jnova.cjt1.net -0.0.0.0 jpirate.cjt1.net -0.0.0.0 jsandboxer.cjt1.net -0.0.0.0 jumcna.cjt1.net -0.0.0.0 jwebbsense.cjt1.net -0.0.0.0 www.cydoor.com -# - -#<2o7-sites> - -# 2o7.net -- server side tracking -0.0.0.0 102.112.2o7.net -0.0.0.0 102.122.2o7.net -0.0.0.0 112.2o7.net -0.0.0.0 122.2o7.net -0.0.0.0 192.168.112.2o7.net -0.0.0.0 2o7.net -0.0.0.0 actforvictory.112.2o7.net -0.0.0.0 adbrite.112.2o7.net -0.0.0.0 adbrite.122.2o7.net -0.0.0.0 aehistory.112.2o7.net -0.0.0.0 aetv.112.2o7.net -0.0.0.0 agamgreetingscom.112.2o7.net -0.0.0.0 allbritton.122.2o7.net -0.0.0.0 americanbaby.112.2o7.net -0.0.0.0 ancestrymsn.112.2o7.net -0.0.0.0 ancestryuki.112.2o7.net -0.0.0.0 angiba.112.2o7.net -0.0.0.0 angmar.112.2o7.net -0.0.0.0 angtr.112.2o7.net -0.0.0.0 angts.112.2o7.net -0.0.0.0 angvac.112.2o7.net -0.0.0.0 anm.112.2o7.net -0.0.0.0 aolcareers.122.2o7.net -0.0.0.0 aoldlama.122.2o7.net -0.0.0.0 aoljournals.122.2o7.net -0.0.0.0 aolnsnews.122.2o7.net -0.0.0.0 aolpf.122.2o7.net -0.0.0.0 aolpolls.112.2o7.net -0.0.0.0 aolpolls.122.2o7.net -0.0.0.0 aolsearch.122.2o7.net -0.0.0.0 aolsvc.122.2o7.net -0.0.0.0 aoltmz.122.2o7.net -0.0.0.0 aolturnercnnmoney.112.2o7.net -0.0.0.0 aolturnercnnmoney.122.2o7.net -0.0.0.0 aolturnersi.122.2o7.net -0.0.0.0 aolukglobal.122.2o7.net -0.0.0.0 aolwinamp.122.2o7.net -0.0.0.0 aolwpaim.112.2o7.net -0.0.0.0 aolwpicq.122.2o7.net -0.0.0.0 aolwpmq.112.2o7.net -0.0.0.0 aolwpmqnoban.112.2o7.net -0.0.0.0 apdigitalorg.112.2o7.net -0.0.0.0 apdigitalorgovn.112.2o7.net -0.0.0.0 apnonline.112.2o7.net -#0.0.0.0 appleglobal.112.2o7.net #breaks apple.com -#0.0.0.0 applestoreus.112.2o7.net #breaks apple.com -0.0.0.0 atlassian.122.2o7.net -0.0.0.0 autobytel.112.2o7.net -0.0.0.0 autoweb.112.2o7.net -0.0.0.0 bbcnewscouk.112.2o7.net -0.0.0.0 bellca.112.2o7.net -0.0.0.0 bellglobemediapublishing.122.2o7.net -0.0.0.0 bellglovemediapublishing.122.2o7.net -0.0.0.0 bellserviceeng.112.2o7.net -0.0.0.0 betterhg.112.2o7.net -0.0.0.0 bhgmarketing.112.2o7.net -0.0.0.0 bidentonrccom.122.2o7.net -0.0.0.0 biwwltvcom.112.2o7.net -0.0.0.0 biwwltvcom.122.2o7.net -0.0.0.0 blackpress.122.2o7.net -0.0.0.0 bnkr8dev.112.2o7.net -0.0.0.0 bntbcstglobal.112.2o7.net -0.0.0.0 bosecom.112.2o7.net -0.0.0.0 brightcove.112.2o7.net -0.0.0.0 bulldog.122.2o7.net -0.0.0.0 businessweekpoc.112.2o7.net -0.0.0.0 bzresults.122.2o7.net -0.0.0.0 cablevision.112.2o7.net -0.0.0.0 canwest.112.2o7.net -0.0.0.0 canwestcom.112.2o7.net -0.0.0.0 canwestglobal.112.2o7.net -0.0.0.0 capcityadvcom.112.2o7.net -0.0.0.0 capcityadvcom.122.2o7.net -0.0.0.0 careers.112.2o7.net -0.0.0.0 cartoonnetwork.122.2o7.net -0.0.0.0 cbaol.112.2o7.net -0.0.0.0 cbc.122.2o7.net -0.0.0.0 cbcca.112.2o7.net -0.0.0.0 cbcca.122.2o7.net -0.0.0.0 cbcincinnatienquirer.112.2o7.net -0.0.0.0 cbmsn.112.2o7.net -0.0.0.0 cbs.112.2o7.net -0.0.0.0 cbsncaasports.112.2o7.net -0.0.0.0 cbsnfl.112.2o7.net -0.0.0.0 cbspgatour.112.2o7.net -0.0.0.0 cbsspln.112.2o7.net -0.0.0.0 ccrbudgetca.112.2o7.net -0.0.0.0 ccrgaviscom.112.2o7.net -0.0.0.0 cfrfa.112.2o7.net -0.0.0.0 chicagosuntimes.122.2o7.net -0.0.0.0 chumtv.122.2o7.net -0.0.0.0 classifiedscanada.112.2o7.net -0.0.0.0 classmatescom.112.2o7.net -0.0.0.0 cmpglobalvista.112.2o7.net -0.0.0.0 cnetasiapacific.122.2o7.net -0.0.0.0 cnetaustralia.122.2o7.net -0.0.0.0 cneteurope.122.2o7.net -0.0.0.0 cnetnews.112.2o7.net -0.0.0.0 cnetzdnet.112.2o7.net -0.0.0.0 cnhienid.122.2o7.net -0.0.0.0 cnhimcalesternews.122.2o7.net -0.0.0.0 cnhipicayuneitemv.112.2o7.net -0.0.0.0 cnhitribunestar.122.2o7.net -0.0.0.0 cnhitribunestara.122.2o7.net -0.0.0.0 cnhregisterherald.122.2o7.net -0.0.0.0 cnn.122.2o7.net -0.0.0.0 computerworldcom.112.2o7.net -0.0.0.0 condenast.112.2o7.net -0.0.0.0 coxnetmasterglobal.112.2o7.net -0.0.0.0 coxpalmbeachpost.112.2o7.net -0.0.0.0 csoonlinecom.112.2o7.net -0.0.0.0 ctvcrimelibrary.112.2o7.net -0.0.0.0 ctvsmokinggun.112.2o7.net -0.0.0.0 cxociocom.112.2o7.net -0.0.0.0 denverpost.112.2o7.net -0.0.0.0 diginet.112.2o7.net -0.0.0.0 digitalhomediscountptyltd.122.2o7.net -0.0.0.0 disccglobal.112.2o7.net -0.0.0.0 disccstats.112.2o7.net -0.0.0.0 dischannel.112.2o7.net -0.0.0.0 divx.112.2o7.net -0.0.0.0 dixonslnkcouk.112.2o7.net -0.0.0.0 dogpile.112.2o7.net -0.0.0.0 donval.112.2o7.net -0.0.0.0 dowjones.122.2o7.net -0.0.0.0 dreammates.112.2o7.net -0.0.0.0 eaeacom.112.2o7.net -0.0.0.0 eagamesuk.112.2o7.net -0.0.0.0 earthlnkpsplive.122.2o7.net -0.0.0.0 ebay1.112.2o7.net -0.0.0.0 ebaynonreg.112.2o7.net -0.0.0.0 ebayreg.112.2o7.net -0.0.0.0 ebayus.112.2o7.net -0.0.0.0 ebcom.112.2o7.net -0.0.0.0 ectestlampsplus1.112.2o7.net -0.0.0.0 edietsmain.112.2o7.net -0.0.0.0 edmundsinsideline.112.2o7.net -0.0.0.0 edsa.112.2o7.net -0.0.0.0 ehg-moma.hitbox.com.112.2o7.net -0.0.0.0 emc.122.2o7.net -0.0.0.0 employ22.112.2o7.net -0.0.0.0 employ26.112.2o7.net -0.0.0.0 employment.112.2o7.net -0.0.0.0 enterprisenewsmedia.122.2o7.net -0.0.0.0 epost.122.2o7.net -0.0.0.0 ewsnaples.112.2o7.net -0.0.0.0 ewstcpalm.112.2o7.net -0.0.0.0 examinercom.122.2o7.net -0.0.0.0 execulink.112.2o7.net -0.0.0.0 expedia4.112.2o7.net -0.0.0.0 expedia.ca.112.2o7.net -0.0.0.0 f2ncracker.112.2o7.net -0.0.0.0 f2nsmh.112.2o7.net -0.0.0.0 f2ntheage.112.2o7.net -0.0.0.0 faceoff.112.2o7.net -0.0.0.0 fbkmnr.112.2o7.net -0.0.0.0 forbesattache.112.2o7.net -0.0.0.0 forbesauto.112.2o7.net -0.0.0.0 forbesautos.112.2o7.net -0.0.0.0 forbescom.112.2o7.net -0.0.0.0 ford.112.2o7.net -0.0.0.0 foxcom.112.2o7.net -0.0.0.0 foxsimpsons.112.2o7.net -0.0.0.0 georgewbush.112.2o7.net -0.0.0.0 georgewbushcom.112.2o7.net -0.0.0.0 gettyimages.122.2o7.net -0.0.0.0 gjfastcompanycom.112.2o7.net -0.0.0.0 gmchevyapprentice.112.2o7.net -0.0.0.0 gmhummer.112.2o7.net -0.0.0.0 gntbcstglobal.112.2o7.net -0.0.0.0 gntbcstkxtv.112.2o7.net -0.0.0.0 gntbcstwtsp.112.2o7.net -0.0.0.0 gpaper104.112.2o7.net -0.0.0.0 gpaper105.112.2o7.net -0.0.0.0 gpaper107.112.2o7.net -0.0.0.0 gpaper108.112.2o7.net -0.0.0.0 gpaper109.112.2o7.net -0.0.0.0 gpaper110.112.2o7.net -0.0.0.0 gpaper111.112.2o7.net -0.0.0.0 gpaper112.112.2o7.net -0.0.0.0 gpaper113.112.2o7.net -0.0.0.0 gpaper114.112.2o7.net -0.0.0.0 gpaper115.112.2o7.net -0.0.0.0 gpaper116.112.2o7.net -0.0.0.0 gpaper117.112.2o7.net -0.0.0.0 gpaper118.112.2o7.net -0.0.0.0 gpaper119.112.2o7.net -0.0.0.0 gpaper120.112.2o7.net -0.0.0.0 gpaper121.112.2o7.net -0.0.0.0 gpaper122.112.2o7.net -0.0.0.0 gpaper123.112.2o7.net -0.0.0.0 gpaper124.112.2o7.net -0.0.0.0 gpaper125.112.2o7.net -0.0.0.0 gpaper126.112.2o7.net -0.0.0.0 gpaper127.112.2o7.net -0.0.0.0 gpaper128.112.2o7.net -0.0.0.0 gpaper129.112.2o7.net -0.0.0.0 gpaper131.112.2o7.net -0.0.0.0 gpaper132.112.2o7.net -0.0.0.0 gpaper133.112.2o7.net -0.0.0.0 gpaper138.112.2o7.net -0.0.0.0 gpaper139.112.2o7.net -0.0.0.0 gpaper140.112.2o7.net -0.0.0.0 gpaper141.112.2o7.net -0.0.0.0 gpaper142.112.2o7.net -0.0.0.0 gpaper144.112.2o7.net -0.0.0.0 gpaper145.112.2o7.net -0.0.0.0 gpaper147.112.2o7.net -0.0.0.0 gpaper149.112.2o7.net -0.0.0.0 gpaper151.112.2o7.net -0.0.0.0 gpaper154.112.2o7.net -0.0.0.0 gpaper156.112.2o7.net -0.0.0.0 gpaper157.112.2o7.net -0.0.0.0 gpaper158.112.2o7.net -0.0.0.0 gpaper162.112.2o7.net -0.0.0.0 gpaper164.112.2o7.net -0.0.0.0 gpaper166.112.2o7.net -0.0.0.0 gpaper167.112.2o7.net -0.0.0.0 gpaper169.112.2o7.net -0.0.0.0 gpaper170.112.2o7.net -0.0.0.0 gpaper171.112.2o7.net -0.0.0.0 gpaper172.112.2o7.net -0.0.0.0 gpaper173.112.2o7.net -0.0.0.0 gpaper174.112.2o7.net -0.0.0.0 gpaper176.112.2o7.net -0.0.0.0 gpaper177.112.2o7.net -0.0.0.0 gpaper180.112.2o7.net -0.0.0.0 gpaper183.112.2o7.net -0.0.0.0 gpaper184.112.2o7.net -0.0.0.0 gpaper191.112.2o7.net -0.0.0.0 gpaper192.112.2o7.net -0.0.0.0 gpaper193.112.2o7.net -0.0.0.0 gpaper194.112.2o7.net -0.0.0.0 gpaper195.112.2o7.net -0.0.0.0 gpaper196.112.2o7.net -0.0.0.0 gpaper197.112.2o7.net -0.0.0.0 gpaper198.112.2o7.net -0.0.0.0 gpaper202.112.2o7.net -0.0.0.0 gpaper204.112.2o7.net -0.0.0.0 gpaper205.112.2o7.net -0.0.0.0 gpaper212.112.2o7.net -0.0.0.0 gpaper214.112.2o7.net -0.0.0.0 gpaper219.112.2o7.net -0.0.0.0 gpaper223.112.2o7.net -0.0.0.0 harpo.122.2o7.net -0.0.0.0 hchrmain.112.2o7.net -0.0.0.0 heavycom.112.2o7.net -0.0.0.0 heavycom.122.2o7.net -0.0.0.0 homesclick.112.2o7.net -0.0.0.0 hostdomainpeople.112.2o7.net -0.0.0.0 hostdomainpeopleca.112.2o7.net -0.0.0.0 hostpowermedium.112.2o7.net -0.0.0.0 hpglobal.112.2o7.net -0.0.0.0 hphqglobal.112.2o7.net -0.0.0.0 hphqsearch.112.2o7.net -0.0.0.0 infomart.ca.112.2o7.net -0.0.0.0 infospace.com.112.2o7.net -0.0.0.0 intelcorpcim.112.2o7.net -0.0.0.0 intelglobal.112.2o7.net -0.0.0.0 ivillageglobal.112.2o7.net -0.0.0.0 jijsonline.122.2o7.net -0.0.0.0 jitmj4.122.2o7.net -0.0.0.0 johnlewis.112.2o7.net -0.0.0.0 journalregistercompany.122.2o7.net -0.0.0.0 kddi.122.2o7.net -0.0.0.0 krafteurope.112.2o7.net -0.0.0.0 ktva.112.2o7.net -0.0.0.0 ladieshj.112.2o7.net -0.0.0.0 laptopmag.122.2o7.net -0.0.0.0 laxnws.112.2o7.net -0.0.0.0 laxprs.112.2o7.net -0.0.0.0 laxpsd.112.2o7.net -0.0.0.0 ldsfch.112.2o7.net -0.0.0.0 leeenterprises.112.2o7.net -0.0.0.0 lenovo.112.2o7.net -0.0.0.0 logoworksdev.112.2o7.net -0.0.0.0 losu.112.2o7.net -0.0.0.0 mailtribune.112.2o7.net -0.0.0.0 maxim.122.2o7.net -0.0.0.0 maxvr.112.2o7.net -0.0.0.0 mdamarillo.112.2o7.net -0.0.0.0 mdjacksonville.112.2o7.net -0.0.0.0 mdtopeka.112.2o7.net -0.0.0.0 mdwardmore.112.2o7.net -0.0.0.0 mdwsavannah.112.2o7.net -0.0.0.0 medbroadcast.112.2o7.net -0.0.0.0 mediabistrocom.112.2o7.net -0.0.0.0 mediamatters.112.2o7.net -0.0.0.0 meetupcom.112.2o7.net -0.0.0.0 metacafe.122.2o7.net -0.0.0.0 mgjournalnow.112.2o7.net -0.0.0.0 mgtbo.112.2o7.net -0.0.0.0 mgtimesdispatch.112.2o7.net -0.0.0.0 mgwsls.112.2o7.net -0.0.0.0 mgwspa.112.2o7.net -0.0.0.0 microsoftconsumermarketing.112.2o7.net -0.0.0.0 microsofteup.112.2o7.net -0.0.0.0 microsoftwindows.112.2o7.net -0.0.0.0 midala.112.2o7.net -0.0.0.0 midar.112.2o7.net -0.0.0.0 midsen.112.2o7.net -0.0.0.0 mlbastros.112.2o7.net -0.0.0.0 mlbcolorado.112.2o7.net -0.0.0.0 mlbcom.112.2o7.net -0.0.0.0 mlbglobal08.112.2o7.net -0.0.0.0 mlbglobal.112.2o7.net -0.0.0.0 mlbhouston.112.2o7.net -0.0.0.0 mlbstlouis.112.2o7.net -0.0.0.0 mlbtoronto.112.2o7.net -0.0.0.0 mmsshopcom.112.2o7.net -0.0.0.0 mnfidnahub.112.2o7.net -0.0.0.0 mngidmn.112.2o7.net -0.0.0.0 mngirockymtnnews.112.2o7.net -0.0.0.0 mngislctrib.112.2o7.net -0.0.0.0 mngiyrkdr.112.2o7.net -0.0.0.0 mseuppremain.112.2o7.net -0.0.0.0 msnmercom.112.2o7.net -0.0.0.0 msnportal.112.2o7.net -0.0.0.0 mtvn.112.2o7.net -0.0.0.0 mtvu.112.2o7.net -0.0.0.0 mxmacromedia.112.2o7.net -0.0.0.0 myfamilyancestry.112.2o7.net -0.0.0.0 nasdaq.122.2o7.net -0.0.0.0 natgeoeditco.112.2o7.net -0.0.0.0 natgeoeditcom.112.2o7.net -0.0.0.0 natgeonews.112.2o7.net -0.0.0.0 natgeongmcom.112.2o7.net -0.0.0.0 nationalpost.112.2o7.net -0.0.0.0 nba.112.2o7.net -0.0.0.0 neber.112.2o7.net -0.0.0.0 netrp.112.2o7.net -0.0.0.0 netsdartboards.122.2o7.net -0.0.0.0 newsinteractive.112.2o7.net -0.0.0.0 newstimeslivecom.112.2o7.net -0.0.0.0 nike.112.2o7.net -0.0.0.0 nikeplus.112.2o7.net -0.0.0.0 nmanchorage.112.2o7.net -0.0.0.0 nmbrampton.112.2o7.net -0.0.0.0 nmcommancomedia.112.2o7.net -0.0.0.0 nmfresno.112.2o7.net -0.0.0.0 nmhiltonhead.112.2o7.net -0.0.0.0 nmkawartha.112.2o7.net -0.0.0.0 nmminneapolis.112.2o7.net -0.0.0.0 nmmississauga.112.2o7.net -0.0.0.0 nmnandomedia.112.2o7.net -0.0.0.0 nmraleigh.112.2o7.net -0.0.0.0 nmrockhill.112.2o7.net -0.0.0.0 nmsacramento.112.2o7.net -0.0.0.0 nmtoronto.112.2o7.net -0.0.0.0 nmtricity.112.2o7.net -0.0.0.0 nmyork.112.2o7.net -0.0.0.0 novellcom.112.2o7.net -0.0.0.0 nytbglobe.112.2o7.net -0.0.0.0 nytglobe.112.2o7.net -0.0.0.0 nythglobe.112.2o7.net -0.0.0.0 nytimesglobal.112.2o7.net -0.0.0.0 nytimesnonsampled.112.2o7.net -0.0.0.0 nytimesnoonsampled.112.2o7.net -0.0.0.0 nytmembercenter.112.2o7.net -0.0.0.0 nytrflorence.112.2o7.net -0.0.0.0 nytrgadsden.112.2o7.net -0.0.0.0 nytrgainseville.112.2o7.net -0.0.0.0 nytrhendersonville.112.2o7.net -0.0.0.0 nytrhouma.112.2o7.net -0.0.0.0 nytrlakeland.112.2o7.net -0.0.0.0 nytrsantarosa.112.2o7.net -0.0.0.0 nytrsarasota.112.2o7.net -0.0.0.0 nytrwilmington.112.2o7.net -0.0.0.0 nyttechnology.112.2o7.net -0.0.0.0 omniture.112.2o7.net -0.0.0.0 omnitureglobal.112.2o7.net -0.0.0.0 onlineindigoca.112.2o7.net -0.0.0.0 oracle.112.2o7.net -0.0.0.0 oraclecom.112.2o7.net -0.0.0.0 overstock.com.112.2o7.net -0.0.0.0 overturecomvista.112.2o7.net -0.0.0.0 paypal.112.2o7.net -0.0.0.0 poacprod.122.2o7.net -0.0.0.0 poconorecordcom.112.2o7.net -0.0.0.0 projectorpeople.112.2o7.net -0.0.0.0 publicationsunbound.112.2o7.net -0.0.0.0 pulharktheherald.112.2o7.net -0.0.0.0 pulpantagraph.112.2o7.net -0.0.0.0 rckymtnnws.112.2o7.net -0.0.0.0 recordnetcom.112.2o7.net -0.0.0.0 recordonlinecom.112.2o7.net -0.0.0.0 rey3935.112.2o7.net -0.0.0.0 rezrezwhistler.112.2o7.net -0.0.0.0 riptownmedia.122.2o7.net -0.0.0.0 rncgopcom.122.2o7.net -0.0.0.0 roxio.112.2o7.net -0.0.0.0 salesforce.122.2o7.net -0.0.0.0 santacruzsentinel.112.2o7.net -0.0.0.0 sciamglobal.112.2o7.net -0.0.0.0 scrippsbathvert.112.2o7.net -0.0.0.0 scrippsfoodnet.112.2o7.net -0.0.0.0 scrippswfts.112.2o7.net -0.0.0.0 scrippswxyz.112.2o7.net -0.0.0.0 seacoastonlinecom.112.2o7.net -0.0.0.0 searscom.112.2o7.net -0.0.0.0 smibs.112.2o7.net -0.0.0.0 smwww.112.2o7.net -0.0.0.0 sonycorporate.122.2o7.net -0.0.0.0 sonyglobal.112.2o7.net -0.0.0.0 southcoasttoday.112.2o7.net -0.0.0.0 spiketv.112.2o7.net -0.0.0.0 stpetersburgtimes.122.2o7.net -0.0.0.0 suncom.112.2o7.net -0.0.0.0 sunglobal.112.2o7.net -0.0.0.0 sunonesearch.112.2o7.net -0.0.0.0 survey.112.2o7.net -0.0.0.0 sympmsnsports.112.2o7.net -0.0.0.0 techreview.112.2o7.net -0.0.0.0 thestar.122.2o7.net -0.0.0.0 thestardev.122.2o7.net -0.0.0.0 thinkgeek.112.2o7.net -0.0.0.0 timebus2.112.2o7.net -0.0.0.0 timecom.112.2o7.net -0.0.0.0 timeew.122.2o7.net -0.0.0.0 timefortune.112.2o7.net -0.0.0.0 timehealth.112.2o7.net -0.0.0.0 timeofficepirates.122.2o7.net -0.0.0.0 timepeople.122.2o7.net -0.0.0.0 timepopsci.122.2o7.net -0.0.0.0 timerealsimple.112.2o7.net -0.0.0.0 timewarner.122.2o7.net -0.0.0.0 tmsscion.112.2o7.net -0.0.0.0 tmstoyota.112.2o7.net -0.0.0.0 tnttv.112.2o7.net -0.0.0.0 torstardigital.122.2o7.net -0.0.0.0 travidiathebrick.112.2o7.net -0.0.0.0 tribuneinteractive.122.2o7.net -0.0.0.0 usatoday1.112.2o7.net -0.0.0.0 usnews.122.2o7.net -0.0.0.0 usun.112.2o7.net -0.0.0.0 vanns.112.2o7.net -0.0.0.0 verisignwildcard.112.2o7.net -0.0.0.0 verisonwildcard.112.2o7.net -0.0.0.0 vh1com.112.2o7.net -0.0.0.0 viaatomvideo.112.2o7.net -0.0.0.0 viacomedycentralrl.112.2o7.net -0.0.0.0 viagametrailers.112.2o7.net -0.0.0.0 viamtvcom.112.2o7.net -0.0.0.0 viasyndimedia.112.2o7.net -0.0.0.0 viavh1com.112.2o7.net -0.0.0.0 viay2m.112.2o7.net -0.0.0.0 vintacom.112.2o7.net -0.0.0.0 viralvideo.112.2o7.net -0.0.0.0 walmartcom.112.2o7.net -0.0.0.0 westjet.112.2o7.net -0.0.0.0 wileydumcom.112.2o7.net -0.0.0.0 wmg.112.2o7.net -0.0.0.0 wmgmulti.112.2o7.net -0.0.0.0 workopolis.122.2o7.net -0.0.0.0 wpni.112.2o7.net -0.0.0.0 xhealthmobiletools.112.2o7.net -0.0.0.0 youtube.112.2o7.net -0.0.0.0 yrkeve.112.2o7.net -0.0.0.0 ziffdavisglobal.112.2o7.net -0.0.0.0 ziffdavispennyarcade.112.2o7.net -# - - -# ads -0.0.0.0 0101011.com -0.0.0.0 0427d7.se -0.0.0.0 0d79ed.r.axf8.net -0.0.0.0 104231.dtiblog.com -0.0.0.0 10.im.cz -0.0.0.0 123.fluxads.com -0.0.0.0 123specialgifts.com -#0.0.0.0 140cc.v.fwmrm.net #interferes with Comedy Central videos -0.0.0.0 1.adbrite.com -0.0.0.0 1.forgetstore.com -0.0.0.0 1.httpads.com -0.0.0.0 1.primaryads.com -0.0.0.0 207-87-18-203.wsmg.digex.net -0.0.0.0 247support.adtech.fr -0.0.0.0 247support.adtech.us -0.0.0.0 24ratownik.hit.gemius.pl -0.0.0.0 24trk.com -0.0.0.0 25184.hittail.com -0.0.0.0 2754.btrll.com -0.0.0.0 2912a.v.fwmrm.net -0.0.0.0 2.adbrite.com -0.0.0.0 2-art-coliseum.com -0.0.0.0 312.1d27c9b8fb.com -0.0.0.0 321cba.com -0.0.0.0 32red.it -0.0.0.0 360ads.com -0.0.0.0 3.adbrite.com -0.0.0.0 3.cennter.com -0.0.0.0 3fns.com -0.0.0.0 4.adbrite.com -0.0.0.0 4c28d6.r.axf8.net -0.0.0.0 4qinvite.4q.iperceptions.com -0.0.0.0 7500.com -0.0.0.0 76.a.boom.ro -0.0.0.0 7adpower.com -0.0.0.0 7bpeople.com -0.0.0.0 7bpeople.data.7bpeople.com -0.0.0.0 7cnbcnews.com -0.0.0.0 85103.hittail.com -0.0.0.0 8574dnj3yzjace8c8io6zr9u3n.hop.clickbank.net -0.0.0.0 888casino.com -0.0.0.0 961.com -0.0.0.0 9cf9.v.fwmrm.net -0.0.0.0 a01.gestionpub.com -0.0.0.0 a.0day.kiev.ua -0.0.0.0 a1.greenadworks.net -0.0.0.0 a1.interclick.com -0.0.0.0 a200.yieldoptimizer.com -0.0.0.0 a2.mediagra.com -0.0.0.0 a2.websponsors.com -0.0.0.0 a3.suntimes.com -0.0.0.0 a3.websponsors.com -0.0.0.0 a4.websponsors.com -0.0.0.0 a5.websponsors.com -0.0.0.0 a.admaxserver.com -0.0.0.0 a.adorika.net -0.0.0.0 a.ad.playstation.net -0.0.0.0 a.adready.com -0.0.0.0 a.ads1.msn.com -0.0.0.0 a.ads2.msn.com -0.0.0.0 a.adstome.com -0.0.0.0 aads.treehugger.com -0.0.0.0 aams1.aim4media.com -0.0.0.0 aan.amazon.com -0.0.0.0 aa-nb.marketgid.com -0.0.0.0 aa.newsblock.dt00.net -0.0.0.0 aa.newsblock.marketgid.com -0.0.0.0 a.as-eu.falkag.net -0.0.0.0 a.as-us.falkag.net -0.0.0.0 aax-us-east.amazon-adsystem.com -0.0.0.0 abcnews.footprint.net -0.0.0.0 a.boom.ro -0.0.0.0 abrogatesdv.info -0.0.0.0 abseckw.adtlgc.com -0.0.0.0 a.collective-media.net -0.0.0.0 ac.rnm.ca -0.0.0.0 actiondesk.com -0.0.0.0 actionflash.com -0.0.0.0 action.ientry.net -0.0.0.0 action.mathtag.com -0.0.0.0 action.media6degrees.com -0.0.0.0 actionsplash.com -0.0.0.0 ac.tynt.com -0.0.0.0 acvs.mediaonenetwork.net -0.0.0.0 acvsrv.mediaonenetwork.net -0.0.0.0 ad01.adonspot.com -0.0.0.0 ad01.focalink.com -0.0.0.0 ad01.mediacorpsingapore.com -0.0.0.0 ad02.focalink.com -0.0.0.0 ad03.focalink.com -0.0.0.0 ad04.focalink.com -0.0.0.0 ad05.focalink.com -0.0.0.0 ad06.focalink.com -0.0.0.0 ad07.focalink.com -0.0.0.0 ad08.focalink.com -0.0.0.0 ad09.focalink.com -0.0.0.0 ad0.haynet.com -0.0.0.0 ad101com.adbureau.net -0.0.0.0 ad10.bannerbank.ru -0.0.0.0 ad10.focalink.com -0.0.0.0 ad11.bannerbank.ru -0.0.0.0 ad11.focalink.com -0.0.0.0 ad12.bannerbank.ru -0.0.0.0 ad12.focalink.com -0.0.0.0 ad13.focalink.com -0.0.0.0 ad14.focalink.com -0.0.0.0 ad15.focalink.com -0.0.0.0 ad16.focalink.com -0.0.0.0 ad17.focalink.com -0.0.0.0 ad18.focalink.com -0.0.0.0 ad19.focalink.com -0.0.0.0 ad1.adtitan.net -0.0.0.0 ad1.bannerbank.ru -0.0.0.0 ad1.clickhype.com -0.0.0.0 ad1.emediate.dk -0.0.0.0 ad1.emediate.se -0.0.0.0 ad1.gamezone.com -0.0.0.0 ad1.hotel.com -0.0.0.0 ad1.lbn.ru -0.0.0.0 ad1.peel.com -0.0.0.0 ad1.popcap.com -0.0.0.0 ad1.yomiuri.co.jp -0.0.0.0 ad1.yourmedia.com -0.0.0.0 ad234.prbn.ru -0.0.0.0 ad2.adecn.com -0.0.0.0 ad2.bal.dotandad.com -0.0.0.0 ad2.bannerbank.ru -0.0.0.0 ad2.bannerhost.ru -0.0.0.0 ad2.bbmedia.cz -0.0.0.0 ad2.cooks.com -0.0.0.0 ad2.firehousezone.com -0.0.0.0 ad2games.com -0.0.0.0 ad2.gammae.com -0.0.0.0 ad2.hotel.com -0.0.0.0 ad2.ip.ro -0.0.0.0 ad2.lbn.ru -0.0.0.0 ad2.nationalreview.com -0.0.0.0 ad2.pamedia.com -0.0.0.0 ad2.parom.hu -0.0.0.0 ad2.peel.com -0.0.0.0 ad2.pl -0.0.0.0 ad2.pl.mediainter.net -0.0.0.0 ad2.sbisec.co.jp -0.0.0.0 ad2.smni.com -0.0.0.0 ad.360yield.com -0.0.0.0 ad3.adfarm1.adition.com -0.0.0.0 ad3.bannerbank.ru -0.0.0.0 ad3.bb.ru -0.0.0.0 ad.3dnews.ru -0.0.0.0 ad3.lbn.ru -0.0.0.0 ad3.nationalreview.com -0.0.0.0 ad3.rambler.ru -0.0.0.0 ad41.atlas.cz -0.0.0.0 ad4.adfarm1.adition.com -0.0.0.0 ad4.bannerbank.ru -0.0.0.0 ad4.lbn.ru -0.0.0.0 ad4.liverail.com -0.0.0.0 ad4.speedbit.com -0.0.0.0 ad5.bannerbank.ru -0.0.0.0 ad5.lbn.ru -0.0.0.0 ad6.bannerbank.ru -0.0.0.0 ad6.horvitznewspapers.net -0.0.0.0 ad.71i.de -0.0.0.0 ad7.bannerbank.ru -0.0.0.0 ad8.bannerbank.ru -0.0.0.0 ad9.bannerbank.ru -0.0.0.0 ad.abcnews.com -0.0.0.0 ad.aboutwebservices.com -0.0.0.0 ad.adfunky.com -0.0.0.0 ad.adition.de -0.0.0.0 ad.adition.net -0.0.0.0 ad.adlegend.com -0.0.0.0 ad.admarketplace.net -0.0.0.0 ad.adnet.biz -0.0.0.0 ad.adnet.de -0.0.0.0 ad.adnetwork.com.br -0.0.0.0 ad.adnetwork.net -0.0.0.0 ad.adorika.com -0.0.0.0 ad.adperium.com -0.0.0.0 ad.adriver.ru -0.0.0.0 ad.adserve.com -0.0.0.0 ad.adserverplus.com -0.0.0.0 ad.adsmart.net -0.0.0.0 ad.adtegrity.net -0.0.0.0 ad.adtoma.com -0.0.0.0 ad.adverticum.net -0.0.0.0 ad.advertstream.com -0.0.0.0 ad.adview.pl -0.0.0.0 ad.afilo.pl -0.0.0.0 ad.aftenposten.no -0.0.0.0 ad.aftonbladet.se -0.0.0.0 ad.afy11.net -0.0.0.0 ad.agava.tbn.ru -0.0.0.0 adagiobanner.s3.amazonaws.com -0.0.0.0 ad.agkn.com -0.0.0.0 ad.amgdgt.com -0.0.0.0 adap.tv -0.0.0.0 ad.aquamediadirect.com -0.0.0.0 ad.asv.de -0.0.0.0 ad-audit.tubemogul.com -0.0.0.0 ad.auditude.com -0.0.0.0 ad.bannerbank.ru -0.0.0.0 ad.bannerconnect.net -0.0.0.0 adblade.com -0.0.0.0 ad.bnmla.com -0.0.0.0 adbnr.ru -0.0.0.0 adbot.theonion.com -0.0.0.0 adbrite.com -0.0.0.0 adbucks.brandreachsys.com -0.0.0.0 adc2.adcentriconline.com -0.0.0.0 adcache.aftenposten.no -0.0.0.0 adcanadian.com -0.0.0.0 adcash.com -0.0.0.0 adcast.deviantart.com -0.0.0.0 adcentriconline.com -0.0.0.0 adcentric.randomseed.com -0.0.0.0 ad.cibleclick.com -0.0.0.0 ad.clickdistrict.com -0.0.0.0 adclick.hit.gemius.pl -0.0.0.0 ad.clickotmedia.com -0.0.0.0 adclient-af.lp.uol.com.br -0.0.0.0 adclient.uimserv.net -0.0.0.0 adcode.adengage.com -0.0.0.0 adcontent.gamespy.com -0.0.0.0 adcontent.reedbusiness.com -0.0.0.0 adcontent.videoegg.com -0.0.0.0 adcontroller.unicast.com -0.0.0.0 adcount.ohmynews.com -0.0.0.0 adcreative.tribuneinteractive.com -0.0.0.0 adcycle.footymad.net -0.0.0.0 adcycle.icpeurope.net -0.0.0.0 ad.dc2.adtech.de -0.0.0.0 addelivery.thestreet.com -0.0.0.0 ad.designtaxi.com -0.0.0.0 ad.deviantart.com -0.0.0.0 ad.directrev.com -0.0.0.0 addthiscdn.com -0.0.0.0 addthis.com -0.0.0.0 adecn.com -0.0.0.0 ad.egloos.com -0.0.0.0 adengine.rt.ru -0.0.0.0 ad.espn.starwave.com -0.0.0.0 ad.eurosport.com -0.0.0.0 adexpansion.com -0.0.0.0 adexprt.com -0.0.0.0 adexprt.me -0.0.0.0 adexprts.com -0.0.0.0 adext.inkclub.com -0.0.0.0 adfarm1.adition.com -0.0.0.0 adfarm.mserve.ca -0.0.0.0 adfiles.pitchforkmedia.com -0.0.0.0 ad.filmweb.pl -0.0.0.0 ad.firstadsolution.com -0.0.0.0 ad.flux.com -#0.0.0.0 adf.ly -0.0.0.0 adforce.ads.imgis.com -0.0.0.0 adforce.adtech.de -0.0.0.0 adforce.adtech.fr -0.0.0.0 adforce.adtech.us -0.0.0.0 adforce.imgis.com -0.0.0.0 adform.com -0.0.0.0 adfu.blockstackers.com -0.0.0.0 ad.funpic.de -0.0.0.0 adfusion.com -0.0.0.0 ad.garantiarkadas.com -0.0.0.0 adgardener.com -0.0.0.0 ad.gazeta.pl -0.0.0.0 ad.goo.ne.jp -0.0.0.0 adgraphics.theonion.com -0.0.0.0 ad.gra.pl -0.0.0.0 ad.gr.doubleclick.net -0.0.0.0 ad.greenmarquee.com -0.0.0.0 adgroup.naver.com -0.0.0.0 ad.hankooki.com -0.0.0.0 ad.harrenmedianetwork.com -0.0.0.0 adhearus.com -0.0.0.0 adhese.be -0.0.0.0 adhese.com -0.0.0.0 adhitzads.com -0.0.0.0 ad.horvitznewspapers.net -0.0.0.0 ad.host.bannerflow.com -0.0.0.0 ad.howstuffworks.com -0.0.0.0 adhref.pl -#0.0.0.0 ad.hulu.com # Uncomment to block Hulu. -0.0.0.0 ad.iconadserver.com -0.0.0.0 adidm.idmnet.pl -0.0.0.0 adidm.supermedia.pl -0.0.0.0 adimage.asia1.com.sg -0.0.0.0 adimage.asiaone.com -0.0.0.0 adimage.asiaone.com.sg -0.0.0.0 adimage.blm.net -0.0.0.0 adimages.earthweb.com -0.0.0.0 adimages.go.com -0.0.0.0 adimages.mp3.com -0.0.0.0 adimages.watchmygf.net -0.0.0.0 adi.mainichi.co.jp -0.0.0.0 adimg.activeadv.net -0.0.0.0 adimg.com.com -0.0.0.0 adincl.gopher.com -0.0.0.0 ad.insightexpressai.com -0.0.0.0 ad.investopedia.com -0.0.0.0 adipics.com -0.0.0.0 adireland.com -0.0.0.0 ad.ir.ru -0.0.0.0 ad.isohunt.com -0.0.0.0 adition.com -0.0.0.0 ad.iwin.com -0.0.0.0 adj10.thruport.com -0.0.0.0 adj11.thruport.com -0.0.0.0 adj12.thruport.com -0.0.0.0 adj13.thruport.com -0.0.0.0 adj14.thruport.com -0.0.0.0 adj15.thruport.com -0.0.0.0 adj16r1.thruport.com -0.0.0.0 adj16.thruport.com -0.0.0.0 adj17.thruport.com -0.0.0.0 adj18.thruport.com -0.0.0.0 adj19.thruport.com -0.0.0.0 adj1.thruport.com -0.0.0.0 adj22.thruport.com -0.0.0.0 adj23.thruport.com -0.0.0.0 adj24.thruport.com -0.0.0.0 adj25.thruport.com -0.0.0.0 adj26.thruport.com -0.0.0.0 adj27.thruport.com -0.0.0.0 adj28.thruport.com -0.0.0.0 adj29.thruport.com -0.0.0.0 adj2.thruport.com -0.0.0.0 adj30.thruport.com -0.0.0.0 adj31.thruport.com -0.0.0.0 adj32.thruport.com -0.0.0.0 adj33.thruport.com -0.0.0.0 adj34.thruport.com -0.0.0.0 adj35.thruport.com -0.0.0.0 adj36.thruport.com -0.0.0.0 adj37.thruport.com -0.0.0.0 adj38.thruport.com -0.0.0.0 adj39.thruport.com -0.0.0.0 adj3.thruport.com -0.0.0.0 adj40.thruport.com -0.0.0.0 adj41.thruport.com -0.0.0.0 adj43.thruport.com -0.0.0.0 adj44.thruport.com -0.0.0.0 adj45.thruport.com -0.0.0.0 adj46.thruport.com -0.0.0.0 adj47.thruport.com -0.0.0.0 adj48.thruport.com -0.0.0.0 adj49.thruport.com -0.0.0.0 adj4.thruport.com -0.0.0.0 adj50.thruport.com -0.0.0.0 adj51.thruport.com -0.0.0.0 adj52.thruport.com -0.0.0.0 adj53.thruport.com -0.0.0.0 adj54.thruport.com -0.0.0.0 adj55.thruport.com -0.0.0.0 adj56.thruport.com -0.0.0.0 adj5.thruport.com -0.0.0.0 adj6.thruport.com -0.0.0.0 adj7.thruport.com -0.0.0.0 adj8.thruport.com -0.0.0.0 adj9.thruport.com -0.0.0.0 ad.jamba.net -0.0.0.0 ad.jamster.ca -0.0.0.0 adjmps.com -0.0.0.0 adjuggler.net -0.0.0.0 adjuggler.yourdictionary.com -0.0.0.0 ad.kataweb.it -0.0.0.0 ad.kat.ph -0.0.0.0 adkontekst.pl -0.0.0.0 ad.krutilka.ru -0.0.0.0 ad.leadcrunch.com -0.0.0.0 ad.lgappstv.com -0.0.0.0 ad.linkexchange.com -0.0.0.0 ad.linksynergy.com -0.0.0.0 admanager1.collegepublisher.com -0.0.0.0 admanager2.broadbandpublisher.com -0.0.0.0 admanager3.collegepublisher.com -0.0.0.0 admanager.adam4adam.com -0.0.0.0 admanager.beweb.com -0.0.0.0 admanager.btopenworld.com -0.0.0.0 admanager.collegepublisher.com -0.0.0.0 adman.freeze.com -0.0.0.0 adman.in.gr -0.0.0.0 ad.mastermedia.ru -0.0.0.0 admatcher.videostrip.com #http://admatcher.videostrip.com/?puid=23940627&host=www.dumpert.nl&categories=default -0.0.0.0 admatch-syndication.mochila.com -0.0.0.0 admax.quisma.com -0.0.0.0 ad.media-servers.net -0.0.0.0 admedia.xoom.com -0.0.0.0 admeld.com -0.0.0.0 admeta.vo.llnwd.net -#0.0.0.0 adm.fwmrm.net #may interfere with nhl.com -0.0.0.0 admin.digitalacre.com -0.0.0.0 admin.hotkeys.com -0.0.0.0 admin.inq.com -0.0.0.0 admonkey.dapper.net -0.0.0.0 ad.moscowtimes.ru -0.0.0.0 adm.shacknews.com -0.0.0.0 adms.physorg.com -0.0.0.0 ad.my.doubleclick.net -0.0.0.0 ad.nate.com -0.0.0.0 adn.ebay.com -0.0.0.0 adnet.asahi.com -0.0.0.0 adnet.biz -0.0.0.0 adnet.chicago.tribune.com -0.0.0.0 adnet.com -0.0.0.0 adnet.de -0.0.0.0 ad.network60.com -0.0.0.0 adnetwork.nextgen.net -0.0.0.0 adnetwork.rovicorp.com -0.0.0.0 adnetxchange.com -0.0.0.0 adng.ascii24.com -0.0.0.0 adn.kinkydollars.com -0.0.0.0 ad.nozonedata.com -0.0.0.0 adnxs.com -0.0.0.0 adnxs.revsci.net -0.0.0.0 adobee.com -0.0.0.0 adobe.tt.omtrdc.net -0.0.0.0 adocean.pl -0.0.0.0 ad.ohmynews.com -0.0.0.0 adopt.euroclick.com -0.0.0.0 adopt.precisead.com -0.0.0.0 adotube.com -0.0.0.0 ad.parom.hu -0.0.0.0 ad.partis.si -0.0.0.0 adpepper.dk -0.0.0.0 adp.gazeta.pl -0.0.0.0 ad.ph-prt.tbn.ru -0.0.0.0 adpick.switchboard.com -0.0.0.0 ad.pravda.ru -0.0.0.0 ad.preferences.com -0.0.0.0 ad.pro-advertising.com -0.0.0.0 ad.propellerads.com -0.0.0.0 ad.prv.pl -0.0.0.0 adpulse.ads.targetnet.com -0.0.0.0 adpush.dreamscape.com -0.0.0.0 adq.nextag.com -0.0.0.0 adremote.pathfinder.com -0.0.0.0 adremote.timeinc.aol.com -0.0.0.0 adremote.timeinc.net -0.0.0.0 ad.repubblica.it -0.0.0.0 adriver.ru -0.0.0.0 adroll.com -0.0.0.0 adrotate.se -0.0.0.0 adrotator.se -0.0.0.0 ad.ru.doubleclick.net -0.0.0.0 ads01.focalink.com -0.0.0.0 ads01.hyperbanner.net -0.0.0.0 ads02.focalink.com -0.0.0.0 ads02.hyperbanner.net -0.0.0.0 ads03.focalink.com -0.0.0.0 ads03.hyperbanner.net -0.0.0.0 ads04.focalink.com -0.0.0.0 ads04.hyperbanner.net -0.0.0.0 ads05.focalink.com -0.0.0.0 ads05.hyperbanner.net -0.0.0.0 ads06.focalink.com -0.0.0.0 ads06.hyperbanner.net -0.0.0.0 ads07.focalink.com -0.0.0.0 ads07.hyperbanner.net -0.0.0.0 ads08.focalink.com -0.0.0.0 ads08.hyperbanner.net -0.0.0.0 ads09.focalink.com -0.0.0.0 ads09.hyperbanner.net -0.0.0.0 ads0.okcupid.com -0.0.0.0 ads10.focalink.com -0.0.0.0 ads10.hyperbanner.net -0.0.0.0 ads10.speedbit.com -0.0.0.0 ads10.udc.advance.net -0.0.0.0 ads11.focalink.com -0.0.0.0 ads11.hyperbanner.net -0.0.0.0 ads11.udc.advance.net -0.0.0.0 ads12.focalink.com -0.0.0.0 ads12.hyperbanner.net -0.0.0.0 ads12.udc.advance.net -0.0.0.0 ads13.focalink.com -0.0.0.0 ads13.hyperbanner.net -0.0.0.0 ads13.udc.advance.net -0.0.0.0 ads14.bpath.com -0.0.0.0 ads14.focalink.com -0.0.0.0 ads14.hyperbanner.net -0.0.0.0 ads14.udc.advance.net -0.0.0.0 ads15.bpath.com -0.0.0.0 ads15.focalink.com -0.0.0.0 ads15.hyperbanner.net -0.0.0.0 ads15.udc.advance.net -0.0.0.0 ads16.advance.net -0.0.0.0 ads16.focalink.com -0.0.0.0 ads16.hyperbanner.net -0.0.0.0 ads16.udc.advance.net -0.0.0.0 ads17.focalink.com -0.0.0.0 ads17.hyperbanner.net -0.0.0.0 ads18.focalink.com -0.0.0.0 ads18.hyperbanner.net -0.0.0.0 ads19.focalink.com -0.0.0.0 ads1.activeagent.at -0.0.0.0 ads1.ad-flow.com -0.0.0.0 ads1.admedia.ro -0.0.0.0 ads1.advance.net -0.0.0.0 ads1.advertwizard.com -0.0.0.0 ads1.ami-admin.com -0.0.0.0 ads1.canoe.ca -0.0.0.0 ads1.destructoid.com -0.0.0.0 ads1.empiretheatres.com -0.0.0.0 ads1.erotism.com -0.0.0.0 ads1.eudora.com -0.0.0.0 ads1.globeandmail.com -0.0.0.0 ads1.itadnetwork.co.uk -0.0.0.0 ads1.jev.co.za -0.0.0.0 ads1.msads.net -0.0.0.0 ads1.msn.com -0.0.0.0 ads1.perfadbrite.com.akadns.net -0.0.0.0 ads1.performancingads.com -0.0.0.0 ads1.realcities.com -0.0.0.0 ads1.revenue.net -0.0.0.0 ads1.sptimes.com -0.0.0.0 ads1.theglobeandmail.com -0.0.0.0 ads1.ucomics.com -0.0.0.0 ads1.udc.advance.net -0.0.0.0 ads1.updated.com -0.0.0.0 ads1.virtumundo.com -0.0.0.0 ads1.zdnet.com -0.0.0.0 ads20.focalink.com -0.0.0.0 ads21.focalink.com -0.0.0.0 ads22.focalink.com -0.0.0.0 ads23.focalink.com -0.0.0.0 ads24.focalink.com -0.0.0.0 ads25.focalink.com -0.0.0.0 ads2.adbrite.com -0.0.0.0 ads2.ad-flow.com -0.0.0.0 ads2.advance.net -0.0.0.0 ads2.advertwizard.com -0.0.0.0 ads2.canoe.ca -0.0.0.0 ads2.clearchannel.com -0.0.0.0 ads2.clickad.com -0.0.0.0 ads2.collegclub.com -0.0.0.0 ads2.collegeclub.com -0.0.0.0 ads2.contentabc.com -0.0.0.0 ads2.drivelinemedia.com -0.0.0.0 ads2.emeraldcoast.com -0.0.0.0 ads2.exhedra.com -0.0.0.0 ads2.firingsquad.com -0.0.0.0 ads2.gamecity.net -0.0.0.0 ads2.jubii.dk -0.0.0.0 ads2.ljworld.com -0.0.0.0 ads2.msn.com -0.0.0.0 ads2.newtimes.com -0.0.0.0 ads2.osdn.com -0.0.0.0 ads2.pittsburghlive.com -0.0.0.0 ads2.realcities.com -0.0.0.0 ads2.revenue.net -0.0.0.0 ads2.rp.pl -0.0.0.0 ads2srv.com -0.0.0.0 ads2.theglobeandmail.com -0.0.0.0 ads2.udc.advance.net -0.0.0.0 ads2.virtumundo.com -0.0.0.0 ads2.weblogssl.com -0.0.0.0 ads2.zdnet.com -0.0.0.0 ads2.zeusclicks.com -0.0.0.0 ads360.com -0.0.0.0 ads36.hyperbanner.net -0.0.0.0 ads3.ad-flow.com -0.0.0.0 ads3.adman.gr -0.0.0.0 ads3.advance.net -0.0.0.0 ads3.advertwizard.com -0.0.0.0 ads3.canoe.ca -0.0.0.0 ads3.freebannertrade.com -0.0.0.0 ads3.gamecity.net -0.0.0.0 ads3.jubii.dk -0.0.0.0 ads3.realcities.com -0.0.0.0 ads3.udc.advance.net -0.0.0.0 ads3.virtumundo.com -0.0.0.0 ads3.zdnet.com -0.0.0.0 ads4.ad-flow.com -0.0.0.0 ads4.advance.net -0.0.0.0 ads4.advertwizard.com -0.0.0.0 ads4.canoe.ca -0.0.0.0 ads4.clearchannel.com -0.0.0.0 ads4.gamecity.net -0.0.0.0 ads4homes.com -0.0.0.0 ads4.realcities.com -0.0.0.0 ads4.udc.advance.net -0.0.0.0 ads4.virtumundo.com -0.0.0.0 ads5.ad-flow.com -0.0.0.0 ads5.advance.net -0.0.0.0 ads5.advertwizard.com -0.0.0.0 ads5.canoe.ca -0.0.0.0 ads.5ci.lt -0.0.0.0 ads5.fxdepo.com -0.0.0.0 ads5.mconetwork.com -0.0.0.0 ads5.udc.advance.net -0.0.0.0 ads5.virtumundo.com -0.0.0.0 ads6.ad-flow.com -0.0.0.0 ads6.advance.net -0.0.0.0 ads6.advertwizard.com -0.0.0.0 ads6.gamecity.net -0.0.0.0 ads6.udc.advance.net -0.0.0.0 ads7.ad-flow.com -0.0.0.0 ads7.advance.net -0.0.0.0 ads7.advertwizard.com -0.0.0.0 ads.7days.ae -0.0.0.0 ads7.gamecity.net -0.0.0.0 ads7.speedbit.com -0.0.0.0 ads7.udc.advance.net -0.0.0.0 ads.8833.com -0.0.0.0 ads8.ad-flow.com -0.0.0.0 ads8.advertwizard.com -0.0.0.0 ads8.com -0.0.0.0 ads8.udc.advance.net -0.0.0.0 ads9.ad-flow.com -0.0.0.0 ads9.advertwizard.com -0.0.0.0 ads9.udc.advance.net -0.0.0.0 ads.abs-cbn.com -0.0.0.0 ads.accelerator-media.com -0.0.0.0 ads.aceweb.net -0.0.0.0 ads.activeagent.at -0.0.0.0 ads.active.com -0.0.0.0 ads.ad4game.com -0.0.0.0 ads.adap.tv -0.0.0.0 ads.adbrite.com -0.0.0.0 ads.adbroker.de -0.0.0.0 ads.adcorps.com -0.0.0.0 ads.addesktop.com -0.0.0.0 ads.addynamix.com -0.0.0.0 ads.adengage.com -0.0.0.0 ads.ad-flow.com -0.0.0.0 ads.adfox.ru -0.0.0.0 ads.adgoto.com -0.0.0.0 ads.adhall.com -0.0.0.0 ads.adhearus.com -0.0.0.0 ads.adhostingsolutions.com -0.0.0.0 ads.admarvel.com -0.0.0.0 ads.admaximize.com -0.0.0.0 adsadmin.aspentimes.com -0.0.0.0 adsadmin.corusradionetwork.com -0.0.0.0 adsadmin.vaildaily.com -0.0.0.0 ads.admonitor.net -0.0.0.0 ads.adn.com -0.0.0.0 ads.adroar.com -0.0.0.0 ads.adsag.com -0.0.0.0 ads.adsbookie.com -0.0.0.0 ads.adshareware.net -0.0.0.0 ads.adsinimages.com -0.0.0.0 ads.adsonar.com -0.0.0.0 ads.adsrvmedia.com -0.0.0.0 ads.adtegrity.net -0.0.0.0 ads.adtiger.de -0.0.0.0 ads.adultfriendfinder.com -0.0.0.0 ads.adultswim.com -0.0.0.0 ads.advance.net -0.0.0.0 ads.adverline.com -0.0.0.0 ads.adviva.net -0.0.0.0 ads.advolume.com -0.0.0.0 ads.adworldnetwork.com -0.0.0.0 ads.adx.nu -0.0.0.0 ads.adxpansion.com -0.0.0.0 ads.adxpose.com -0.0.0.0 ads.adxpose.mpire.akadns.net -0.0.0.0 ads.affiliates.match.com -0.0.0.0 ads.aftonbladet.se -0.0.0.0 ads.ah-ha.com -0.0.0.0 ads.aintitcool.com -0.0.0.0 ads.airamericaradio.com -0.0.0.0 ads.ak.facebook.com -0.0.0.0 ads.albawaba.com -0.0.0.0 ads.al.com -0.0.0.0 ads.allsites.com -0.0.0.0 ads.allvertical.com -0.0.0.0 ads.amarillo.com -0.0.0.0 ads.amateurmatch.com -0.0.0.0 ads.amazingmedia.com -0.0.0.0 ads.amgdgt.com -0.0.0.0 ads.ami-admin.com -0.0.0.0 ads.anm.co.uk -0.0.0.0 ads.anvato.com -0.0.0.0 ads.aol.com -0.0.0.0 ads.apartmenttherapy.com -0.0.0.0 ads.apn.co.nz -0.0.0.0 ads.apn.co.za -0.0.0.0 ads.appleinsider.com -0.0.0.0 ads.arcadechain.com -0.0.0.0 ads.aroundtherings.com -0.0.0.0 ads.as4x.tmcs.net -0.0.0.0 ads.as4x.tmcs.ticketmaster.ca -0.0.0.0 ads.as4x.tmcs.ticketmaster.com -0.0.0.0 ads.asia1.com -0.0.0.0 ads.asia1.com.sg -0.0.0.0 ads.aspalliance.com -0.0.0.0 ads.aspentimes.com -0.0.0.0 ads.asp.net -0.0.0.0 ads.associatedcontent.com -0.0.0.0 ads.astalavista.us -0.0.0.0 ads.atlantamotorspeedway.com -0.0.0.0 adsatt.abcnews.starwave.com -0.0.0.0 adsatt.espn.go.com -0.0.0.0 adsatt.espn.starwave.com -0.0.0.0 ads.auctionads.com -0.0.0.0 ads.auctioncity.co.nz -0.0.0.0 ads.auctions.yahoo.com -0.0.0.0 ads.augusta.com -0.0.0.0 ads.aversion2.com -0.0.0.0 ads.aws.sitepoint.com -0.0.0.0 ads.azjmp.com -0.0.0.0 ads.baazee.com -0.0.0.0 ads.bangkokpost.co.th -0.0.0.0 ads.banner.t-online.de -0.0.0.0 ads.barnonedrinks.com -0.0.0.0 ads.battle.net -0.0.0.0 ads.bauerpublishing.com -0.0.0.0 ads.baventures.com -0.0.0.0 ads.bbcworld.com -0.0.0.0 ads.bcnewsgroup.com -0.0.0.0 ads.beeb.com -0.0.0.0 ads.beliefnet.com -0.0.0.0 ads.belointeractive.com -0.0.0.0 ads.beta.itravel2000.com -0.0.0.0 ads.betanews.com -0.0.0.0 ads.bfast.com -0.0.0.0 ads.bfm.valueclick.net -0.0.0.0 ads.bianca.com -0.0.0.0 ads.bidclix.com -0.0.0.0 ads.bidvertiser.com -0.0.0.0 ads.bigcitytools.com -0.0.0.0 ads.biggerboat.com -0.0.0.0 ads.bitsonthewire.com -0.0.0.0 ads.bizhut.com -0.0.0.0 ads.blixem.nl -0.0.0.0 ads.blog.com -0.0.0.0 ads.blogherads.com -0.0.0.0 ads.bloomberg.com -0.0.0.0 ads.blp.calueclick.net -0.0.0.0 ads.blp.valueclick.net -0.0.0.0 ads.bluelithium.com -0.0.0.0 ads.bluemountain.com -0.0.0.0 ads.bonnint.net -0.0.0.0 ads.box.sk -0.0.0.0 ads.brabys.com -0.0.0.0 ads.brand.net -0.0.0.0 ads.bridgetrack.com -0.0.0.0 ads.britishexpats.com -0.0.0.0 ads.buscape.com.br -0.0.0.0 ads.businessclick.com -0.0.0.0 ads.businessweek.com -0.0.0.0 ads.calgarysun.com -0.0.0.0 ads.callofdutyblackopsforum.net -0.0.0.0 ads.camrecord.com -0.0.0.0 ads.canoe.ca -0.0.0.0 ads.cardea.se -0.0.0.0 ads.cardplayer.com -0.0.0.0 ads.carltononline.com -0.0.0.0 ads.carocean.co.uk -0.0.0.0 ads.casinocity.com -0.0.0.0 ads.catholic.org -0.0.0.0 ads.cavello.com -0.0.0.0 ads.cbc.ca -0.0.0.0 ads.cdfreaks.com -0.0.0.0 ads.cdnow.com -0.0.0.0 adscendmedia.com -0.0.0.0 ads.centraliprom.com -0.0.0.0 ads.cgchannel.com -0.0.0.0 ads.chalomumbai.com -0.0.0.0 ads.champs-elysees.com -0.0.0.0 ads.channel4.com -0.0.0.0 ads.checkm8.co.za -0.0.0.0 ads.chipcenter.com -0.0.0.0 adscholar.com -0.0.0.0 ads.chumcity.com -0.0.0.0 ads.cjonline.com -0.0.0.0 ads.clamav.net -0.0.0.0 ads.clara.net -0.0.0.0 ads.clearchannel.com -0.0.0.0 ads.cleveland.com -0.0.0.0 ads.clickability.com -0.0.0.0 ads.clickad.com.pl -0.0.0.0 ads.clickagents.com -0.0.0.0 ads.clickhouse.com -0.0.0.0 ads.clicksor.com -0.0.0.0 ads.clickthru.net -0.0.0.0 ads.clicmanager.fr -0.0.0.0 ads.clubzone.com -0.0.0.0 ads.cluster01.oasis.zmh.zope.net -0.0.0.0 ads.cmediaworld.com -0.0.0.0 ads.cmg.valueclick.net -0.0.0.0 ads.cnn.com -0.0.0.0 ads.cnngo.com -0.0.0.0 ads.cobrad.com -0.0.0.0 ads.collegclub.com -0.0.0.0 ads.collegehumor.com -0.0.0.0 ads.collegemix.com -0.0.0.0 ads.com.com -0.0.0.0 ads.comediagroup.hu -0.0.0.0 ads.comicbookresources.com -0.0.0.0 ads.contactmusic.com -0.0.0.0 ads.contentabc.com -0.0.0.0 ads.coopson.com -0.0.0.0 ads.corusradionetwork.com -0.0.0.0 ads.courierpostonline.com -0.0.0.0 ads.cpsgsoftware.com -0.0.0.0 ads.crakmedia.com -0.0.0.0 ads.crapville.com -0.0.0.0 ads.creative-serving.com -0.0.0.0 ads.crosscut.com -0.0.0.0 ads.ctvdigital.net -0.0.0.0 ads.currantbun.com -0.0.0.0 ads.cyberfight.ru -0.0.0.0 ads.cybersales.cz -0.0.0.0 ads.cybertrader.com -0.0.0.0 ads.dada.it -0.0.0.0 ads.danworld.net -0.0.0.0 adsdaq.com -0.0.0.0 ads.dbforums.com -0.0.0.0 ads.ddj.com -0.0.0.0 ads.dealnews.com -0.0.0.0 ads.democratandchronicle.com -0.0.0.0 ads.dennisnet.co.uk -0.0.0.0 ads.designboom.com -0.0.0.0 ads.designtaxi.com -0.0.0.0 ads.desmoinesregister.com -0.0.0.0 ads-de.spray.net -0.0.0.0 ads.detelefoongids.nl -0.0.0.0 ads.developershed.com -0.0.0.0 ads.deviantart.com -0.0.0.0 ads-dev.youporn.com -0.0.0.0 ads.digitalacre.com -0.0.0.0 ads.digital-digest.com -0.0.0.0 ads.digitalhealthcare.com -0.0.0.0 ads.digitalmedianet.com -0.0.0.0 ads.digitalpoint.com -0.0.0.0 ads.dimcab.com -0.0.0.0 ads.directionsmag.com -0.0.0.0 ads-direct.prodigy.net -0.0.0.0 ads.discovery.com -0.0.0.0 ads.dk -0.0.0.0 ads.doclix.com -0.0.0.0 ads.domeus.com -0.0.0.0 ads.dontpanicmedia.com -0.0.0.0 ads.dothads.com -0.0.0.0 ads.doubleviking.com -0.0.0.0 ads.drf.com -0.0.0.0 ads.drivelinemedia.com -0.0.0.0 ads.drugs.com -0.0.0.0 ads.dumpalink.com -0.0.0.0 adsearch.adkontekst.pl -0.0.0.0 adsearch.pl -0.0.0.0 adsearch.wp.pl -0.0.0.0 ads.ecircles.com -0.0.0.0 ads.economist.com -0.0.0.0 ads.ecosalon.com -0.0.0.0 ads.edirectme.com -0.0.0.0 ads.einmedia.com -0.0.0.0 ads.eircom.net -0.0.0.0 ads.emeraldcoast.com -0.0.0.0 ads.enliven.com -0.0.0.0 ad.sensismediasmart.com.au -0.0.0.0 adsentnetwork.com -0.0.0.0 adserer.ihigh.com -0.0.0.0 ads.erotism.com -0.0.0.0 adserv001.adtech.de -0.0.0.0 adserv001.adtech.fr -0.0.0.0 adserv001.adtech.us -0.0.0.0 adserv002.adtech.de -0.0.0.0 adserv002.adtech.fr -0.0.0.0 adserv002.adtech.us -0.0.0.0 adserv003.adtech.de -0.0.0.0 adserv003.adtech.fr -0.0.0.0 adserv003.adtech.us -0.0.0.0 adserv004.adtech.de -0.0.0.0 adserv004.adtech.fr -0.0.0.0 adserv004.adtech.us -0.0.0.0 adserv005.adtech.de -0.0.0.0 adserv005.adtech.fr -0.0.0.0 adserv005.adtech.us -0.0.0.0 adserv006.adtech.de -0.0.0.0 adserv006.adtech.fr -0.0.0.0 adserv006.adtech.us -0.0.0.0 adserv007.adtech.de -0.0.0.0 adserv007.adtech.fr -0.0.0.0 adserv007.adtech.us -0.0.0.0 adserv008.adtech.de -0.0.0.0 adserv008.adtech.fr -0.0.0.0 adserv008.adtech.us -0.0.0.0 adserv2.bravenet.com -0.0.0.0 adserv.aip.org -0.0.0.0 adservant.guj.de -0.0.0.0 adserv.bravenet.com -0.0.0.0 adserve5.nikkeibp.co.jp -0.0.0.0 adserve.adtoll.com -0.0.0.0 adserve.canadawidemagazines.com -0.0.0.0 adserve.city-ad.com -0.0.0.0 adserve.ehpub.com -0.0.0.0 adserve.gossipgirls.com -0.0.0.0 adserve.mizzenmedia.com -0.0.0.0 adserv.entriq.net -0.0.0.0 adserve.podaddies.com -0.0.0.0 adserve.profit-smart.com -0.0.0.0 adserver01.ancestry.com -0.0.0.0 adserver.100free.com -0.0.0.0 adserver.163.com -0.0.0.0 adserver1.adserver.com.pl -0.0.0.0 adserver1.adtech.com.tr -0.0.0.0 adserver1.backbeatmedia.com -0.0.0.0 adserver1.economist.com -0.0.0.0 adserver1.eudora.com -0.0.0.0 adserver1.harvestadsdepot.com -0.0.0.0 adserver1.hookyouup.com -0.0.0.0 adserver1-images.backbeatmedia.com -0.0.0.0 adserver1.isohunt.com -0.0.0.0 adserver1.lokitorrent.com -0.0.0.0 adserver1.mediainsight.de -0.0.0.0 adserver1.ogilvy-interactive.de -0.0.0.0 adserver1.realtracker.com -0.0.0.0 adserver1.sonymusiceurope.com -0.0.0.0 adserver1.teracent.net -0.0.0.0 adserver1.wmads.com -0.0.0.0 adserver.2618.com -0.0.0.0 adserver2.adserver.com.pl -0.0.0.0 adserver2.atman.pl -0.0.0.0 adserver2.christianitytoday.com -0.0.0.0 adserver2.condenast.co.uk -0.0.0.0 adserver2.creative.com -0.0.0.0 adserver2.eudora.com -0.0.0.0 adserver-2.ig.com.br -0.0.0.0 adserver2.mediainsight.de -0.0.0.0 adserver2.news-journalonline.com -0.0.0.0 adserver2.popdata.de -0.0.0.0 adserver2.realtracker.com -0.0.0.0 adserver2.teracent.net -0.0.0.0 adserver.3digit.de -0.0.0.0 adserver3.eudora.com -0.0.0.0 adserver-3.ig.com.br -0.0.0.0 adserver4.eudora.com -0.0.0.0 adserver-4.ig.com.br -0.0.0.0 adserver-5.ig.com.br -0.0.0.0 adserver.71i.de -0.0.0.0 adserver9.contextad.com -0.0.0.0 adserver.ad-it.dk -0.0.0.0 adserver.adreactor.com -0.0.0.0 adserver.adremedy.com -0.0.0.0 adserver.ads360.com -0.0.0.0 adserver.adserver.com.pl -0.0.0.0 adserver.adsincontext.com -0.0.0.0 adserver.adtech.de -0.0.0.0 adserver.adtech.fr -0.0.0.0 adserver.adtech.us -0.0.0.0 adserver.adtechus.com -0.0.0.0 adserver.adultfriendfinder.com -0.0.0.0 adserver.advertist.com -0.0.0.0 adserver.affiliatemg.com -0.0.0.0 adserver.affiliation.com -0.0.0.0 adserver.aim4media.com -0.0.0.0 adserver.a.in.monster.com -0.0.0.0 adserver.airmiles.ca -0.0.0.0 adserver.akqa.net -0.0.0.0 adserver.allheadlinenews.com -0.0.0.0 adserver.amnews.com -0.0.0.0 adserver.ancestry.com -0.0.0.0 adserver.anemo.com -0.0.0.0 adserver.anm.co.uk -0.0.0.0 adserver.aol.fr -0.0.0.0 adserver.archant.co.uk -0.0.0.0 adserver.artempireindustries.com -0.0.0.0 adserver.arttoday.com -0.0.0.0 adserver.atari.net -0.0.0.0 adserverb.conjelco.com -0.0.0.0 adserver.betandwin.de -0.0.0.0 adserver.billiger-surfen.de -0.0.0.0 adserver.billiger-telefonieren.de -0.0.0.0 adserver.bizland-inc.net -0.0.0.0 adserver.bluereactor.com -0.0.0.0 adserver.bluereactor.net -0.0.0.0 adserver.bluewin.ch -0.0.0.0 adserver.buttonware.com -0.0.0.0 adserver.buttonware.net -0.0.0.0 adserver.cams.com -0.0.0.0 adserver.cantv.net -0.0.0.0 adserver.cebu-online.com -0.0.0.0 adserver.cheatplanet.com -0.0.0.0 adserver.chickclick.com -0.0.0.0 adserver.click4cash.de -0.0.0.0 adserver.clubic.com -0.0.0.0 adserver.clundressed.com -0.0.0.0 adserver.co.il -0.0.0.0 adserver.colleges.com -0.0.0.0 adserver.com -0.0.0.0 adserver.comparatel.fr -0.0.0.0 adserver.com-solutions.com -0.0.0.0 adserver.conjelco.com -0.0.0.0 adserver.corusradionetwork.com -0.0.0.0 adserver.creative-asia.com -0.0.0.0 adserver.creativeinspire.com -0.0.0.0 adserver.dayrates.com -0.0.0.0 adserver.dbusiness.com -0.0.0.0 adserver.developersnetwork.com -0.0.0.0 adserver.devx.com -0.0.0.0 adserver.digitalpartners.com -0.0.0.0 adserver.digitoday.com -0.0.0.0 adserver.directforce.com -0.0.0.0 adserver.directforce.net -0.0.0.0 adserver.dnps.com -0.0.0.0 adserver.dotcommedia.de -0.0.0.0 adserver.dotmusic.com -0.0.0.0 adserver.eham.net -0.0.0.0 adserver.emapadserver.com -0.0.0.0 adserver.emporis.com -0.0.0.0 adserver.emulation64.com -0.0.0.0 adserver-espnet.sportszone.net -0.0.0.0 adserver.eudora.com -0.0.0.0 adserver.eva2000.com -0.0.0.0 adserver.expatica.nxs.nl -0.0.0.0 adserver.ezzhosting.com -0.0.0.0 adserver.filefront.com -0.0.0.0 adserver.fmpub.net -0.0.0.0 adserver.fr.adtech.de -0.0.0.0 adserver.freecity.de -0.0.0.0 adserver.freenet.de -0.0.0.0 adserver.friendfinder.com -0.0.0.0 adserver.gameparty.net -0.0.0.0 adserver.gamesquad.net -0.0.0.0 adserver.garden.com -0.0.0.0 adserver.gorillanation.com -0.0.0.0 adserver.gr -0.0.0.0 adserver.gunaxin.com -0.0.0.0 adserver.hardsextube.com -0.0.0.0 adserver.hardwareanalysis.com -0.0.0.0 adserver.harktheherald.com -0.0.0.0 adserver.harvestadsdepot.com -0.0.0.0 adserver.hellasnet.gr -0.0.0.0 adserver.hg-computer.de -0.0.0.0 adserver.hi-m.de -0.0.0.0 adserver.hispavista.com -0.0.0.0 adserver.hk.outblaze.com -0.0.0.0 adserver.home.pl -0.0.0.0 adserver.hostinteractive.com -0.0.0.0 adserver.humanux.com -0.0.0.0 adserver.hwupgrade.it -0.0.0.0 adserver.ifmagazine.com -0.0.0.0 adserver.ig.com.br -0.0.0.0 adserver.ign.com -0.0.0.0 adserver.ilounge.com -0.0.0.0 adserver.infinit.net -0.0.0.0 adserver.infotiger.com -0.0.0.0 adserver.interfree.it -0.0.0.0 adserver.inwind.it -0.0.0.0 adserver.ision.de -0.0.0.0 adserver.isonews.com -0.0.0.0 adserver.ixm.co.uk -0.0.0.0 adserver.jacotei.com.br -0.0.0.0 adserver.janes.com -0.0.0.0 adserver.janes.net -0.0.0.0 adserver.janes.org -0.0.0.0 adserver.jolt.co.uk -0.0.0.0 adserver.journalinteractive.com -0.0.0.0 adserver.juicyads.com -0.0.0.0 adserver.kcilink.com -0.0.0.0 adserver.killeraces.com -0.0.0.0 adserver.kylemedia.com -0.0.0.0 adserver.lanacion.com.ar -0.0.0.0 adserver.lanepress.com -0.0.0.0 adserver.latimes.com -0.0.0.0 adserver.legacy-network.com -0.0.0.0 adserver.libero.it -0.0.0.0 adserver.linktrader.co.uk -0.0.0.0 adserver.livejournal.com -0.0.0.0 adserver.lostreality.com -0.0.0.0 adserver.lunarpages.com -0.0.0.0 adserver.lycos.co.jp -0.0.0.0 adserver.m2kcore.com -0.0.0.0 adserver.magazyn.pl -0.0.0.0 adserver.matchcraft.com -0.0.0.0 adserver.merc.com -0.0.0.0 adserver.mindshare.de -0.0.0.0 adserver.mobsmith.com -0.0.0.0 adserver.monster.com -0.0.0.0 adserver.monstersandcritics.com -0.0.0.0 adserver.motonews.pl -0.0.0.0 adserver.myownemail.com -0.0.0.0 adserver.netcreators.nl -0.0.0.0 adserver.netshelter.net -0.0.0.0 adserver.newdigitalgroup.com -0.0.0.0 adserver.newmassmedia.net -0.0.0.0 adserver.news.com -0.0.0.0 adserver.news.com.au -0.0.0.0 adserver.news-journalonline.com -0.0.0.0 adserver.newtimes.com -0.0.0.0 adserver.ngz-network.de -0.0.0.0 adserver.nydailynews.com -0.0.0.0 adserver.nzoom.com -0.0.0.0 adserver.o2.pl -0.0.0.0 adserver.onwisconsin.com -0.0.0.0 adserver.passion.com -0.0.0.0 adserver.phatmax.net -0.0.0.0 adserver.phillyburbs.com -0.0.0.0 adserver.pl -0.0.0.0 adserver.planet-multiplayer.de -0.0.0.0 adserver.plhb.com -0.0.0.0 adserver.pollstar.com -0.0.0.0 adserver.portalofevil.com -0.0.0.0 adserver.portal.pl -0.0.0.0 adserver.portugalmail.pt -0.0.0.0 adserver.prodigy.net -0.0.0.0 adserver.proteinos.com -0.0.0.0 adserver.radio-canada.ca -0.0.0.0 adserver.ratestar.net -0.0.0.0 adserver.revver.com -0.0.0.0 adserver.ro -0.0.0.0 adserver.sabc.co.za -0.0.0.0 adserver.sabcnews.co.za -0.0.0.0 adserver.sanomawsoy.fi -0.0.0.0 adserver.scmp.com -0.0.0.0 adserver.securityfocus.com -0.0.0.0 adserver.sextracker.com -0.0.0.0 adserver.sharewareonline.com -0.0.0.0 adserver.singnet.com -0.0.0.0 adserver.sl.kharkov.ua -0.0.0.0 adserver.smashtv.com -0.0.0.0 adserver.snowball.com -0.0.0.0 adserver.softonic.com -0.0.0.0 adserver.soloserver.com -0.0.0.0 adserversolutions.com -0.0.0.0 adserver.swiatobrazu.pl -0.0.0.0 adserver.synergetic.de -0.0.0.0 adserver.telalink.net -0.0.0.0 adserver.te.pt -0.0.0.0 adserver.teracent.net -0.0.0.0 adserver.terra.com.br -0.0.0.0 adserver.terra.es -0.0.0.0 adserver.theknot.com -0.0.0.0 adserver.theonering.net -0.0.0.0 adserver.thirty4.com -0.0.0.0 adserver.thisislondon.co.uk -0.0.0.0 adserver.tilted.net -0.0.0.0 adserver.tqs.ca -0.0.0.0 adserver.track-star.com -0.0.0.0 adserver.trader.ca -0.0.0.0 adserver.trafficsyndicate.com -0.0.0.0 adserver.trb.com -0.0.0.0 adserver.tribuneinteractive.com -0.0.0.0 adserver.tsgadv.com -0.0.0.0 adserver.tulsaworld.com -0.0.0.0 adserver.tweakers.net -0.0.0.0 adserver.twitpic.com -0.0.0.0 adserver.ugo.com -0.0.0.0 adserver.ugo.nl -0.0.0.0 adserver.ukplus.co.uk -0.0.0.0 adserver.uproxx.com -0.0.0.0 adserver.usermagnet.com -0.0.0.0 adserver.van.net -0.0.0.0 adserver.virginmedia.com -0.0.0.0 adserver.virgin.net -0.0.0.0 adserver.virtualminds.nl -0.0.0.0 adserver.virtuous.co.uk -0.0.0.0 adserver.voir.ca -0.0.0.0 adserver.webads.co.uk -0.0.0.0 adserver.webads.nl -0.0.0.0 adserver.wemnet.nl -0.0.0.0 adserver.x3.hu -0.0.0.0 adserver.ya.com -0.0.0.0 adserver.yahoo.com -0.0.0.0 adserver.zaz.com.br -0.0.0.0 adserver.zeads.com -0.0.0.0 adserve.shopzilla.com -0.0.0.0 adserve.splicetoday.com -0.0.0.0 adserve.viaarena.com -0.0.0.0 adserv.free6.com -0.0.0.0 adserv.geocomm.com -0.0.0.0 adserv.iafrica.com -0.0.0.0 adservices.google.com -0.0.0.0 adservices.picadmedia.com -0.0.0.0 adservingcentral.com -0.0.0.0 adserving.cpxinteractive.com -0.0.0.0 adserv.internetfuel.com -0.0.0.0 adserv.jupiter.com -0.0.0.0 adserv.lwmn.net -0.0.0.0 adserv.maineguide.com -0.0.0.0 adserv.muchosucko.com -0.0.0.0 adserv.mywebtimes.com -0.0.0.0 adserv.pitchforkmedia.com -0.0.0.0 adserv.postbulletin.com -0.0.0.0 adserv.qconline.com -0.0.0.0 adserv.quality-channel.de -0.0.0.0 adserv.usps.com -0.0.0.0 adserwer.o2.pl -0.0.0.0 ads.espn.adsonar.com -0.0.0.0 ads.eudora.com -0.0.0.0 ads.eu.msn.com -0.0.0.0 ads.euniverseads.com -0.0.0.0 adseu.novem.pl -0.0.0.0 ads.examiner.net -0.0.0.0 ads.exhedra.com -0.0.0.0 ads.expedia.com -0.0.0.0 ads.expekt.com -0.0.0.0 ads.ezboard.com -0.0.0.0 adsfac.eu -0.0.0.0 adsfac.net -0.0.0.0 adsfac.us -0.0.0.0 ads.fairfax.com.au -0.0.0.0 ads.fark.com -0.0.0.0 ads.fayettevillenc.com -0.0.0.0 ads.filecloud.com -0.0.0.0 ads.fileindexer.com -0.0.0.0 ads.filmup.com -0.0.0.0 ads.first-response.be -0.0.0.0 ads.flabber.nl -0.0.0.0 ads.flashgames247.com -0.0.0.0 ads.fling.com -0.0.0.0 ads.floridatoday.com -0.0.0.0 ads.fool.com -0.0.0.0 ads.forbes.com -0.0.0.0 ads.forbes.net -0.0.0.0 ads.fortunecity.com -0.0.0.0 ads.fredericksburg.com -0.0.0.0 ads.freebannertrade.com -0.0.0.0 ads.freshmeat.net -0.0.0.0 ads.fresnobee.com -0.0.0.0 ads.friendfinder.com -0.0.0.0 ads.ft.com -0.0.0.0 ads.gamblinghit.com -0.0.0.0 ads.gamecity.net -0.0.0.0 ads.gamecopyworld.no -0.0.0.0 ads.gameinformer.com -0.0.0.0 ads.game.net -0.0.0.0 ads.gamershell.com -0.0.0.0 ads.gamespy.com -0.0.0.0 ads.gamespyid.com -0.0.0.0 ads.gateway.com -0.0.0.0 ads.gawker.com -0.0.0.0 ads.gettools.com -0.0.0.0 ads.gigaom.com.php5-12.websitetestlink.com -0.0.0.0 ads.globeandmail.com -0.0.0.0 ads.gmg.valueclick.net -0.0.0.0 ads.gmodules.com -0.0.0.0 ads.god.co.uk -0.0.0.0 ads.gorillanation.com -0.0.0.0 ads.gplusmedia.com -0.0.0.0 ads.granadamedia.com -0.0.0.0 ads.greenbaypressgazette.com -0.0.0.0 ads.greenvilleonline.com -0.0.0.0 ads.guardian.co.uk -0.0.0.0 ads.guardianunlimited.co.uk -0.0.0.0 ads.gunaxin.com -0.0.0.0 ads.halogennetwork.com -0.0.0.0 ads.hamptonroads.com -0.0.0.0 ads.hamtonroads.com -0.0.0.0 ads.hardwarezone.com -0.0.0.0 ads.harpers.org -0.0.0.0 ads.hbv.de -0.0.0.0 ads.hearstmags.com -0.0.0.0 ads.heartlight.org -0.0.0.0 ads.herald-mail.com -0.0.0.0 ads.heraldnet.com -0.0.0.0 ads.heraldonline.com -0.0.0.0 ads.heraldsun.com -0.0.0.0 ads.heroldonline.com -0.0.0.0 ads.he.valueclick.net -0.0.0.0 ads.hitcents.com -0.0.0.0 ads.hlwd.valueclick.net -0.0.0.0 ads.hollandsentinel.com -0.0.0.0 ads.hollywood.com -0.0.0.0 ads.hooqy.com -0.0.0.0 ads.hothardware.com -0.0.0.0 ad.showbizz.net -0.0.0.0 ads.hulu.com.edgesuite.net -#0.0.0.0 ads.hulu.com # Uncomment to block Hulu. -0.0.0.0 ads.humorbua.no -0.0.0.0 ads.i12.de -0.0.0.0 ads.i33.com -0.0.0.0 ads.iafrica.com -0.0.0.0 ads.i-am-bored.com -0.0.0.0 ads.iboost.com -0.0.0.0 ads.icq.com -0.0.0.0 ads.iforex.com -0.0.0.0 ads.ign.com -0.0.0.0 ads.illuminatednation.com -0.0.0.0 ads.imdb.com -0.0.0.0 ads.imgur.com -0.0.0.0 ads.imposibil.ro -0.0.0.0 ads.indiatimes.com -0.0.0.0 ads.indya.com -0.0.0.0 ads.indystar.com -0.0.0.0 ads.inedomedia.com -0.0.0.0 ads.inetdirectories.com -0.0.0.0 ads.inetinteractive.com -0.0.0.0 ads.infi.net -0.0.0.0 ads.infospace.com -0.0.0.0 adsinimages.com -0.0.0.0 ads.injersey.com -0.0.0.0 ads.insidehighered.com -0.0.0.0 ads.intellicast.com -0.0.0.0 ads.internic.co.il -0.0.0.0 ads.inthesidebar.com -0.0.0.0 adsintl.starwave.com -0.0.0.0 ads.iol.co.il -0.0.0.0 ads.ipowerweb.com -0.0.0.0 ads.ireport.com -0.0.0.0 ads.isat-tech.com -0.0.0.0 ads.isoftmarketing.com -0.0.0.0 ads.isum.de -0.0.0.0 ads.itv.com -0.0.0.0 ads.iwon.com -0.0.0.0 ads.jacksonville.com -0.0.0.0 ads.jeneauempire.com -0.0.0.0 ads.jetpackdigital.com -0.0.0.0 ads.jetphotos.net -0.0.0.0 ads.jewcy.com -0.0.0.0 ads.jimworld.com -0.0.0.0 ads.joetec.net -0.0.0.0 ads.jokaroo.com -0.0.0.0 ads.jornadavirtual.com.mx -0.0.0.0 ads.jossip.com -0.0.0.0 ads.jpost.com -0.0.0.0 ads.jubii.dk -0.0.0.0 ads.juicyads.com -0.0.0.0 ads.juneauempire.com -0.0.0.0 ads.jwtt3.com -0.0.0.0 ads.kazaa.com -0.0.0.0 ads.keywordblocks.com -0.0.0.0 ads.kixer.com -0.0.0.0 ads.kleinman.com -0.0.0.0 ads.kmpads.com -0.0.0.0 ads.koreanfriendfinder.com -0.0.0.0 ads.ksl.com -0.0.0.0 ad.slashgear.com -0.0.0.0 ads.leo.org -0.0.0.0 ads.lfstmedia.com -0.0.0.0 ads.lilengine.com -0.0.0.0 ads.link4ads.com -0.0.0.0 ads.linksponsor.com -0.0.0.0 ads.linktracking.net -0.0.0.0 ads.linuxjournal.com -0.0.0.0 ads.linuxsecurity.com -0.0.0.0 ads.list-universe.com -0.0.0.0 ads.live365.com -0.0.0.0 ads.ljworld.com -0.0.0.0 ads.lnkworld.com -0.0.0.0 ads.localnow.com -0.0.0.0 ads-local.sixapart.com -0.0.0.0 ads.lubbockonline.com -0.0.0.0 ads.lucidmedia.com -0.0.0.0 ads.lucidmedia.com.gslb.com -0.0.0.0 ads.lycos.com -0.0.0.0 ads.lycos-europe.com -0.0.0.0 ads.lzjl.com -0.0.0.0 ads.macnews.de -0.0.0.0 ads.macupdate.com -0.0.0.0 ads.madisonavenue.com -0.0.0.0 ads.madison.com -0.0.0.0 ads.magnetic.is -0.0.0.0 ads.mail.com -0.0.0.0 ads.mambocommunities.com -0.0.0.0 ad.sma.punto.net -0.0.0.0 ads.mariuana.it -0.0.0.0 adsmart.com -0.0.0.0 adsmart.co.uk -0.0.0.0 adsmart.net -0.0.0.0 ads.mcafee.com -0.0.0.0 ads.mdchoice.com -0.0.0.0 ads.mediamayhemcorp.com -0.0.0.0 ads.mediaodyssey.com -0.0.0.0 ads.mediaturf.net -0.0.0.0 ads.mefeedia.com -0.0.0.0 ads.megaproxy.com -0.0.0.0 ads.metblogs.com -0.0.0.0 ads.mgnetwork.com -0.0.0.0 ads.mindsetnetwork.com -0.0.0.0 ads.miniclip.com -0.0.0.0 ads.mininova.org -0.0.0.0 ads.mircx.com -0.0.0.0 ads.mixtraffic.com -0.0.0.0 ads.mlive.com -0.0.0.0 ads.mm.ap.org -0.0.0.0 ads.mndaily.com -0.0.0.0 ad.smni.com -0.0.0.0 ads.mobiledia.com -0.0.0.0 ads.mobygames.com -0.0.0.0 ads.modbee.com -0.0.0.0 ads.mofos.com -0.0.0.0 ads.money.pl -0.0.0.0 ads.monster.com -0.0.0.0 ads.mouseplanet.com -0.0.0.0 ads.movieweb.com -0.0.0.0 ads.mp3searchy.com -0.0.0.0 adsm.soush.com -0.0.0.0 ads.mt.valueclick.net -0.0.0.0 ads.mtv.uol.com.br -0.0.0.0 ads.multimania.lycos.fr -0.0.0.0 ads.musiccity.com -0.0.0.0 ads.mustangworks.com -0.0.0.0 ads.mysimon.com -0.0.0.0 ads.mytelus.com -0.0.0.0 ads.nandomedia.com -0.0.0.0 ads.nationalreview.com -0.0.0.0 ads.nativeinstruments.de -0.0.0.0 ads.neoseeker.com -0.0.0.0 ads.neowin.net -0.0.0.0 ads.nerve.com -0.0.0.0 ads.netmechanic.com -0.0.0.0 ads.networkwcs.net -0.0.0.0 ads.networldmedia.net -0.0.0.0 ads.neudesicmediagroup.com -0.0.0.0 ads.newcity.com -0.0.0.0 ads.newcitynet.com -0.0.0.0 ads.newdream.net -0.0.0.0 ads.newgrounds.com -0.0.0.0 ads.newsint.co.uk -0.0.0.0 ads.newsminerextra.com -0.0.0.0 ads.newsobserver.com -0.0.0.0 ads.newsquest.co.uk -0.0.0.0 ads.newtention.net -0.0.0.0 ads.newtimes.com -0.0.0.0 adsnew.userfriendly.org -0.0.0.0 ads.ngenuity.com -0.0.0.0 ads.ninemsn.com.au -0.0.0.0 adsniper.ru -0.0.0.0 ads.nola.com -0.0.0.0 ads.northjersey.com -0.0.0.0 ads.novem.pl -0.0.0.0 ads.nowrunning.com -0.0.0.0 ads.npr.valueclick.net -0.0.0.0 ads.ntadvice.com -0.0.0.0 ads.nudecards.com -0.0.0.0 ads.nwsource.com -0.0.0.0 ads.nwsource.com.edgesuite.net -0.0.0.0 ads.nyi.net -0.0.0.0 ads.nyjournalnews.com -0.0.0.0 ads.nypost.com -0.0.0.0 ads.nytimes.com -0.0.0.0 ads.o2.pl -0.0.0.0 adsoftware.com -0.0.0.0 adsoldier.com -0.0.0.0 ads.ole.com -0.0.0.0 ads.omaha.com -0.0.0.0 adsonar.com -0.0.0.0 adson.awempire.com -0.0.0.0 ads.onlineathens.com -0.0.0.0 ads.online.ie -0.0.0.0 ads.onvertise.com -0.0.0.0 ads.ookla.com -0.0.0.0 ads.open.pl -0.0.0.0 ads.opensubtitles.org -0.0.0.0 ads.oregonlive.com -0.0.0.0 ads.orsm.net -0.0.0.0 ads.osdn.com -0.0.0.0 ad-souk.com -0.0.0.0 adspaces.ero-advertising.com -0.0.0.0 ads.parrysound.com -0.0.0.0 ads.partner2profit.com -0.0.0.0 ads.pastemagazine.com -0.0.0.0 ads.paxnet.co.kr -0.0.0.0 ads.pcper.com -0.0.0.0 ads.pdxguide.com -0.0.0.0 ads.peel.com -0.0.0.0 ads.peninsulaclarion.com -0.0.0.0 ads.penny-arcade.com -0.0.0.0 ads.pennyweb.com -0.0.0.0 ads.people.com.cn -0.0.0.0 ads.pg.valueclick.net -0.0.0.0 ads.pheedo.com -0.0.0.0 ads.phillyburbs.com -0.0.0.0 ads.phpclasses.org -0.0.0.0 ads.pilotonline.com -0.0.0.0 adspirit.net -0.0.0.0 adspiro.pl -0.0.0.0 ads.pitchforkmedia.com -0.0.0.0 ads.pittsburghlive.com -0.0.0.0 ads.pixiq.com -0.0.0.0 ads.place1.com -0.0.0.0 ads.planet-f1.com -0.0.0.0 ads.plantyours.com -0.0.0.0 ads.pni.com -0.0.0.0 ads.pno.net -0.0.0.0 ads.poconorecord.com -0.0.0.0 ads.pointroll.com -0.0.0.0 ads.portlandmercury.com -0.0.0.0 ads.premiumnetwork.com -0.0.0.0 ads.premiumnetwork.net -0.0.0.0 ads.pressdemo.com -0.0.0.0 ads.pricescan.com -0.0.0.0 ads.primaryclick.com -0.0.0.0 ads.primeinteractive.net -0.0.0.0 ads.prisacom.com -0.0.0.0 ads.profitsdeluxe.com -0.0.0.0 ads.profootballtalk.com -0.0.0.0 ads.program3.com -0.0.0.0 ads.pro-market.net -0.0.0.0 ads.pro-market.net.edgesuite.net -0.0.0.0 ads.prospect.org -0.0.0.0 ads.pubmatic.com -0.0.0.0 ads.queendom.com -0.0.0.0 ads.quicken.com -0.0.0.0 adsr3pg.com.br -0.0.0.0 ads.rackshack.net -0.0.0.0 ads.rasmussenreports.com -0.0.0.0 ads.ratemyprofessors.com -0.0.0.0 adsrc.bankrate.com -0.0.0.0 ads.rcgroups.com -0.0.0.0 ads.rdstore.com -0.0.0.0 ads.realcastmedia.com -0.0.0.0 ads.realcities.com -0.0.0.0 ads.realmedia.de -0.0.0.0 ads.realtechnetwork.net -0.0.0.0 ads.reason.com -0.0.0.0 ads.rediff.com -0.0.0.0 ads.redorbit.com -0.0.0.0 ads.register.com -0.0.0.0 adsremote.scripps.com -0.0.0.0 adsremote.scrippsnetwork.com -0.0.0.0 ads.revenews.com -0.0.0.0 ads.revenue.net -0.0.0.0 adsrevenue.net -0.0.0.0 ads.revsci.net -0.0.0.0 ads.rim.co.uk -0.0.0.0 ads-rm.looksmart.com -0.0.0.0 ads.roanoke.com -0.0.0.0 ads.rockstargames.com -0.0.0.0 ads.rodale.com -0.0.0.0 ads.roiserver.com -0.0.0.0 ads.rondomondo.com -0.0.0.0 ads.rootzoo.com -0.0.0.0 ads.rottentomatoes.com -0.0.0.0 ads.rp-online.de -0.0.0.0 ads.ruralpress.com -0.0.0.0 adsrv2.wilmingtonstar.com -0.0.0.0 adsrv.bankrate.com -0.0.0.0 adsrv.dispatch.com -0.0.0.0 adsrv.emporis.com -0.0.0.0 adsrv.heraldtribune.com -0.0.0.0 adsrv.hpg.com.br -0.0.0.0 adsrv.iol.co.za -0.0.0.0 adsrv.lua.pl -0.0.0.0 adsrv.news.com.au -0.0.0.0 adsrvr.com -0.0.0.0 adsrv.tuscaloosanews.com -0.0.0.0 adsrv.wilmingtonstar.com -0.0.0.0 ads.sacbee.com -0.0.0.0 ads.satyamonline.com -0.0.0.0 ads.savannahnow.com -0.0.0.0 ads.scabee.com -0.0.0.0 ads.schwabtrader.com -0.0.0.0 ads.scifi.com -0.0.0.0 ads.seattletimes.com -0.0.0.0 ads.sfusion.com -0.0.0.0 ads.shizmoo.com -0.0.0.0 ads.shoppingads.com -0.0.0.0 ads.shoutfile.com -0.0.0.0 ads.sify.com -0.0.0.0 ads.simtel.com -0.0.0.0 ads.simtel.net -0.0.0.0 ads.sitemeter.com -0.0.0.0 ads.sixapart.com -0.0.0.0 adssl01.adtech.de -0.0.0.0 adssl01.adtech.fr -0.0.0.0 adssl01.adtech.us -0.0.0.0 adssl02.adtech.de -0.0.0.0 adssl02.adtech.fr -0.0.0.0 adssl02.adtech.us -0.0.0.0 ads.sl.interpals.net -0.0.0.0 ads.smartclick.com -0.0.0.0 ads.smartclicks.com -0.0.0.0 ads.smartclicks.net -0.0.0.0 ads.snowball.com -0.0.0.0 ads.socialmedia.com -0.0.0.0 ads.sohh.com -0.0.0.0 ads.somethingawful.com -0.0.0.0 ads.space.com -0.0.0.0 adsspace.net -0.0.0.0 ads.specificclick.com -0.0.0.0 ads.specificmedia.com -0.0.0.0 ads.specificpop.com -0.0.0.0 ads.sptimes.com -0.0.0.0 ads.spymac.net -0.0.0.0 ads.stackoverflow.com -0.0.0.0 ads.starbanner.com -0.0.0.0 ads.stephensmedia.com -0.0.0.0 ads.stileproject.com -0.0.0.0 ads.stupid.com -0.0.0.0 ads.sunjournal.com -0.0.0.0 ads.sup.com -0.0.0.0 ads.swiftnews.com -0.0.0.0 ads.switchboard.com -0.0.0.0 ads.teamyehey.com -0.0.0.0 ads.technoratimedia.com -0.0.0.0 ads.techtv.com -0.0.0.0 ads.techvibes.com -0.0.0.0 ads.techweb.com -0.0.0.0 ads.telegraaf.nl -0.0.0.0 ads.telegraph.co.uk -0.0.0.0 ads.the15thinternet.com -0.0.0.0 ads.theawl.com -0.0.0.0 ads.thebugs.ws -0.0.0.0 ads.thecoolhunter.net -0.0.0.0 ads.thecrimson.com -0.0.0.0 ads.thefrisky.com -0.0.0.0 ads.thegauntlet.com -0.0.0.0 ads.theglobeandmail.com -0.0.0.0 ads.theindependent.com -0.0.0.0 ads.theolympian.com -0.0.0.0 ads.thesmokinggun.com -0.0.0.0 ads.thestar.com #Toronto Star -0.0.0.0 ads.thestranger.com -0.0.0.0 ads.thewebfreaks.com -0.0.0.0 adstil.indiatimes.com -0.0.0.0 ads.timesunion.com -0.0.0.0 ads.tiscali.fr -0.0.0.0 ads.tmcs.net -0.0.0.0 ads.tnt.tv -0.0.0.0 adstogo.com -0.0.0.0 adstome.com -0.0.0.0 ads.top500.org #TOP500 SuperComputer Site -0.0.0.0 ads.top-banners.com -0.0.0.0 ads.toronto.com -0.0.0.0 ads.townhall.com -0.0.0.0 ads.track.net -0.0.0.0 ads.traderonline.com -0.0.0.0 ads.traffichaus.com -0.0.0.0 ads.trafficjunky.net -0.0.0.0 ads.traffikings.com -0.0.0.0 adstream.cardboardfish.com -0.0.0.0 adstreams.org -0.0.0.0 ads.treehugger.com -0.0.0.0 ads.tricityherald.com -0.0.0.0 ads.trinitymirror.co.uk -0.0.0.0 ads.tripod.com -0.0.0.0 ads.tripod.lycos.co.uk -0.0.0.0 ads.tripod.lycos.de -0.0.0.0 ads.tripod.lycos.es -0.0.0.0 ads.tromaville.com -0.0.0.0 ads-t.ru -0.0.0.0 ads.trutv.com -0.0.0.0 ads.tucows.com -0.0.0.0 ads.tw.adsonar.com -0.0.0.0 ads.ucomics.com -0.0.0.0 ads.uigc.net -0.0.0.0 ads.undertone.com -0.0.0.0 ads.unixathome.org -0.0.0.0 ads.update.com -0.0.0.0 ad.suprnova.org -0.0.0.0 ads.uproar.com -0.0.0.0 ads.urbandictionary.com -0.0.0.0 ads.usatoday.com -0.0.0.0 ads.us.e-planning.ne -0.0.0.0 ads.us.e-planning.net -0.0.0.0 ads.userfriendly.org -0.0.0.0 ads.v3.com -0.0.0.0 ads.v3exchange.com -0.0.0.0 ads.vaildaily.com -0.0.0.0 ads.valuead.com -0.0.0.0 ads.vegas.com -0.0.0.0 ads.veloxia.com -0.0.0.0 ads.ventivmedia.com -0.0.0.0 ads.veoh.com -0.0.0.0 ads.verkata.com -0.0.0.0 ads.vesperexchange.com -0.0.0.0 ads.vg.basefarm.net -0.0.0.0 ads.viddler.com -0.0.0.0 ads.videoadvertising.com -0.0.0.0 ads.viewlondon.co.uk -0.0.0.0 ads.virginislandsdailynews.com -0.0.0.0 ads.virtualcountries.com -0.0.0.0 ads.vnuemedia.com -0.0.0.0 adsvr.adknowledge.com -0.0.0.0 ads.vs.co -0.0.0.0 ads.vs.com -0.0.0.0 ads.wanadooregie.com -0.0.0.0 ads.warcry.com -0.0.0.0 ads.watershed-publishing.com -0.0.0.0 ads.wave.si -0.0.0.0 ads.weather.ca -0.0.0.0 ads.weather.com -0.0.0.0 ads.web21.com -0.0.0.0 ads.web.alwayson-network.com -0.0.0.0 ads.web.aol.com -0.0.0.0 ads.webattack.com -0.0.0.0 ads.web.compuserve.com -0.0.0.0 ads.webcoretech.com -0.0.0.0 ads.web.cs.com -0.0.0.0 ads.web.de -0.0.0.0 ads.webfeat.com -0.0.0.0 ads.webheat.com -0.0.0.0 ads.webhosting.info -0.0.0.0 ads.webindia123.com -0.0.0.0 ads-web.mail.com -0.0.0.0 ads.webmd.com -0.0.0.0 ads.webnet.advance.net -0.0.0.0 ads.websponsors.com -0.0.0.0 adsweb.tiscali.cz -0.0.0.0 ads.weissinc.com -0.0.0.0 ads.whaleads.com -0.0.0.0 ads.whi.co.nz -0.0.0.0 ads.winsite.com -0.0.0.0 ads.wnd.com -0.0.0.0 ads.wunderground.com -0.0.0.0 ads.x10.com -0.0.0.0 ads.x10.net -0.0.0.0 ads.x17online.com -0.0.0.0 ads.xboxic.com -0.0.0.0 ads.xbox-scene.com -0.0.0.0 ads.xposed.com -0.0.0.0 ads.xtra.ca -0.0.0.0 ads.xtra.co.nz -0.0.0.0 ads.xtramsn.co.nz -0.0.0.0 ads.yahoo.com -0.0.0.0 ads.yimg.com -0.0.0.0 ads.yimg.com.edgesuite.net -0.0.0.0 ads.yldmgrimg.net -0.0.0.0 adsyndication.msn.com -0.0.0.0 adsyndication.yelldirect.com -0.0.0.0 adsynergy.com -0.0.0.0 ads.youporn.com -0.0.0.0 ads.youtube.com -0.0.0.0 adsys.townnews.com -0.0.0.0 ads.zap2it.com -0.0.0.0 ads.zdnet.com -0.0.0.0 adtag.msn.ca -0.0.0.0 adtag.sympatico.ca -0.0.0.0 adtaily.com -0.0.0.0 adtaily.pl -0.0.0.0 ad.tbn.ru -0.0.0.0 adtcp.ru -0.0.0.0 adtech.de -0.0.0.0 ad.technoramedia.com -0.0.0.0 adtech.panthercustomer.com -0.0.0.0 adtechus.com -0.0.0.0 adtegrity.spinbox.net -0.0.0.0 adtext.pl -0.0.0.0 ad.text.tbn.ru -0.0.0.0 ad.tgdaily.com -0.0.0.0 ad.thehill.com -0.0.0.0 ad.thetyee.ca -0.0.0.0 ad.thewheelof.com -0.0.0.0 adthru.com -0.0.0.0 adtigerpl.adspirit.net -0.0.0.0 ad.tiscali.com -0.0.0.0 adtlgc.com -0.0.0.0 adtology3.com -0.0.0.0 ad.tomshardware.com -0.0.0.0 adtotal.pl -0.0.0.0 adtracking.vinden.nl -0.0.0.0 adtrader.com -0.0.0.0 ad.trafficmp.com -0.0.0.0 adtrak.net -0.0.0.0 ad.turn.com -0.0.0.0 ad.tv2.no -0.0.0.0 ad.twitchguru.com -0.0.0.0 ad.ubnm.co.kr -0.0.0.0 ad.uk.tangozebra.com -0.0.0.0 ad-uk.tiscali.com -0.0.0.0 adultadworld.com -0.0.0.0 ad.usatoday.com -0.0.0.0 adv0005.247realmedia.com -0.0.0.0 adv0035.247realmedia.com -0.0.0.0 adv.440net.com -0.0.0.0 adv.adgates.com -0.0.0.0 adv.adtotal.pl -0.0.0.0 adv.adview.pl -0.0.0.0 adv.bannercity.ru -0.0.0.0 adv.bbanner.it -0.0.0.0 adv.bookclubservices.ca -0.0.0.0 adveng.hiasys.com -0.0.0.0 adveraction.pl -0.0.0.0 advert.bayarea.com -0.0.0.0 advertise.com -0.0.0.0 advertisers.federatedmedia.net -0.0.0.0 advertising.aol.com -0.0.0.0 advertisingbay.com -0.0.0.0 advertising.bbcworldwide.com -0.0.0.0 advertising.com -0.0.0.0 advertising.gfxartist.com -0.0.0.0 advertising.hiasys.com -0.0.0.0 advertising.illinimedia.com -0.0.0.0 advertising.online-media24.de -0.0.0.0 advertising.paltalk.com -0.0.0.0 advertising.wellpack.fr -0.0.0.0 advertising.zenit.org -0.0.0.0 advertlets.com -0.0.0.0 advertpro.investorvillage.com -0.0.0.0 advertpro.sitepoint.com -0.0.0.0 adverts.digitalspy.co.uk -0.0.0.0 adverts.ecn.co.uk -0.0.0.0 adverts.freeloader.com -0.0.0.0 adverts.im4ges.com -0.0.0.0 advertstream.com -0.0.0.0 advert.uloz.to -0.0.0.0 adv.federalpost.ru -0.0.0.0 adv.gazeta.pl -0.0.0.0 advicepl.adocean.pl -0.0.0.0 adview.pl -0.0.0.0 adviva.net -0.0.0.0 adv.lampsplus.com -0.0.0.0 advmaker.ru -0.0.0.0 adv.merlin.co.il -0.0.0.0 adv.netshelter.net -0.0.0.0 adv.publy.net -0.0.0.0 adv.surinter.net -0.0.0.0 advt.webindia123.com -0.0.0.0 ad.vurts.com -0.0.0.0 adv.virgilio.it -0.0.0.0 adv.webmd.com -0.0.0.0 adv.wp.pl -0.0.0.0 adv.zapal.ru -0.0.0.0 advzilla.com -0.0.0.0 adware.kogaryu.com -0.0.0.0 adweb2.hornymatches.com -0.0.0.0 ad.webprovider.com -0.0.0.0 adw.sapo.pt -0.0.0.0 ad.wsod.com -0.0.0.0 adx.adrenalinesk.sk -0.0.0.0 adx.gainesvillesun.com -0.0.0.0 adx.gainesvillsun.com -0.0.0.0 adx.groupstate.com -0.0.0.0 adx.hendersonvillenews.com -0.0.0.0 adx.heraldtribune.com -0.0.0.0 adxpose.com -0.0.0.0 adx.starnewsonline.com -0.0.0.0 ad.xtendmedia.com -0.0.0.0 adx.theledger.com -0.0.0.0 ad.yadro.ru -0.0.0.0 ad.yieldmanager.com -0.0.0.0 adz.afterdawn.net -0.0.0.0 ad.zanox.com -0.0.0.0 adzerk.net -0.0.0.0 ad.zodera.hu -0.0.0.0 adzone.ro -0.0.0.0 adzone.stltoday.com -0.0.0.0 adzservice.theday.com -0.0.0.0 ae.goodsblock.marketgid.com -0.0.0.0 afe2.specificclick.net -0.0.0.0 afe.specificclick.net -0.0.0.0 aff.foxtab.com -0.0.0.0 affiliate.a4dtracker.com -0.0.0.0 affiliate.aol.com -0.0.0.0 affiliate.baazee.com -0.0.0.0 affiliate.cfdebt.com -0.0.0.0 affiliate.exabytes.com.my -0.0.0.0 affiliate-fr.com -0.0.0.0 affiliate.fr.espotting.com -0.0.0.0 affiliate.googleusercontent.com -0.0.0.0 affiliate.hbytracker.com -0.0.0.0 affiliate.mlntracker.com -0.0.0.0 affiliates.arvixe.com -0.0.0.0 affiliates.eblastengine.com -0.0.0.0 affiliates.genealogybank.com -0.0.0.0 affiliates.globat.com -0.0.0.0 affiliation-france.com -0.0.0.0 affimg.pop6.com -0.0.0.0 afform.co.uk -0.0.0.0 affpartners.com -0.0.0.0 aff.ringtonepartner.com -0.0.0.0 afi.adocean.pl -0.0.0.0 afilo.pl -0.0.0.0 agkn.com -0.0.0.0 aj.600z.com -0.0.0.0 ajcclassifieds.com -0.0.0.0 akaads-espn.starwave.com -0.0.0.0 aka-cdn.adtechus.com -0.0.0.0 aka-cdn-ns.adtech.de -0.0.0.0 aka-cdn-ns.adtechus.com -0.0.0.0 akamai.invitemedia.com -0.0.0.0 ak.buyservices.com -0.0.0.0 a.kerg.net -0.0.0.0 ak.maxserving.com -0.0.0.0 ako.cc -0.0.0.0 ak.p.openx.net -0.0.0.0 al1.sharethis.com -0.0.0.0 alert.police-patrol-agent.com -0.0.0.0 a.ligatus.com -0.0.0.0 a.ligatus.de -0.0.0.0 alliance.adbureau.net -0.0.0.0 all.orfr.adgtw.orangeads.fr -0.0.0.0 altfarm.mediaplex.com -0.0.0.0 amch.questionmarket.com -0.0.0.0 americansingles.click-url.com -0.0.0.0 a.mktw.net -0.0.0.0 amscdn.btrll.com -0.0.0.0 analysis.fc2.com -0.0.0.0 analytics.kwebsoft.com -0.0.0.0 analytics.percentmobile.com -0.0.0.0 analyzer51.fc2.com -0.0.0.0 ankieta-online.pl -0.0.0.0 annuaire-autosurf.com -0.0.0.0 anrtx.tacoda.net -0.0.0.0 answers.us.intellitxt.com -0.0.0.0 an.tacoda.net -0.0.0.0 an.yandex.ru -0.0.0.0 apex-ad.com -0.0.0.0 api.addthis.com -0.0.0.0 api.affinesystems.com -0.0.0.0 api-public.addthis.com -0.0.0.0 apopt.hbmediapro.com -0.0.0.0 apparelncs.com -0.0.0.0 apparel-offer.com -0.0.0.0 appdev.addthis.com -0.0.0.0 appnexus.com -0.0.0.0 apps5.oingo.com -0.0.0.0 app.scanscout.com -0.0.0.0 ap.read.mediation.pns.ap.orangeads.fr -0.0.0.0 a.prisacom.com -0.0.0.0 apx.moatads.com -0.0.0.0 a.rad.live.com -0.0.0.0 a.rad.msn.com -0.0.0.0 arbomedia.pl -0.0.0.0 arbopl.bbelements.com -0.0.0.0 arsconsole.global-intermedia.com -0.0.0.0 art-music-rewardpath.com -0.0.0.0 art-offer.com -0.0.0.0 art-offer.net -0.0.0.0 art-photo-music-premiumblvd.com -0.0.0.0 art-photo-music-rewardempire.com -0.0.0.0 art-photo-music-savingblvd.com -0.0.0.0 as1.falkag.de -0.0.0.0 as1image1.adshuffle.com -0.0.0.0 as1image2.adshuffle.com -0.0.0.0 as1.inoventiv.com -0.0.0.0 as2.falkag.de -0.0.0.0 as3.falkag.de -0.0.0.0 as4.falkag.de -0.0.0.0 as.5to1.com -0.0.0.0 asa.tynt.com -0.0.0.0 asb.tynt.com -0.0.0.0 as.casalemedia.com -0.0.0.0 as.ebz.io -0.0.0.0 asg01.casalemedia.com -0.0.0.0 asg02.casalemedia.com -0.0.0.0 asg03.casalemedia.com -0.0.0.0 asg04.casalemedia.com -0.0.0.0 asg05.casalemedia.com -0.0.0.0 asg06.casalemedia.com -0.0.0.0 asg07.casalemedia.com -0.0.0.0 asg08.casalemedia.com -0.0.0.0 asg09.casalemedia.com -0.0.0.0 asg10.casalemedia.com -0.0.0.0 asg11.casalemedia.com -0.0.0.0 asg12.casalemedia.com -0.0.0.0 asg13.casalemedia.com -0.0.0.0 ask-gps.ru -0.0.0.0 asklots.com -0.0.0.0 askmen.thruport.com -0.0.0.0 asm2.z1.adserver.com -0.0.0.0 asm3.z1.adserver.com -0.0.0.0 asn.advolution.de -0.0.0.0 asn.cunda.advolution.biz -0.0.0.0 a.ss34.on9mail.com -0.0.0.0 assets.igapi.com -0.0.0.0 assets.kixer.com -0.0.0.0 assets.percentmobile.com -0.0.0.0 as.sexad.net -0.0.0.0 asv.nuggad.net -0.0.0.0 as.vs4entertainment.com -0.0.0.0 as.webmd.com -0.0.0.0 a.tadd.react2media.com -0.0.0.0 at-adserver.alltop.com -0.0.0.0 at.campaigns.f2.com.au -0.0.0.0 at.ceofreehost.com -0.0.0.0 atdmt.com -0.0.0.0 atemda.com -0.0.0.0 athena-ads.wikia.com -0.0.0.0 at.m1.nedstatbasic.net -0.0.0.0 a.total-media.net -0.0.0.0 a.tribalfusion.com -0.0.0.0 a.triggit.com -0.0.0.0 au.adserver.yahoo.com -0.0.0.0 au.ads.link4ads.com -0.0.0.0 aud.pubmatic.com -0.0.0.0 aureate.com -0.0.0.0 auslieferung.commindo-media-ressourcen.de -0.0.0.0 austria1.adverserve.net -0.0.0.0 autocontext.begun.ru -0.0.0.0 automotive-offer.com -0.0.0.0 automotive-rewardpath.com -0.0.0.0 avcounter10.com -0.0.0.0 avpa.dzone.com -0.0.0.0 avpa.javalobby.org -0.0.0.0 a.websponsors.com -0.0.0.0 awesomevipoffers.com -0.0.0.0 awrz.net -0.0.0.0 axp.zedo.com -0.0.0.0 azcentra.app.ur.gcion.com -0.0.0.0 azoogleads.com -0.0.0.0 b1.adbrite.com -0.0.0.0 b1.azjmp.com -0.0.0.0 b2b.filecloud.me -0.0.0.0 babycenter.tt.omtrdc.net -0.0.0.0 b.ads2.msn.com -0.0.0.0 badservant.guj.de -0.0.0.0 b.am15.net -0.0.0.0 bananacashback.com -0.0.0.0 banery.acr.pl -0.0.0.0 banery.netart.pl -0.0.0.0 banery.onet.pl -0.0.0.0 banki.onet.pl -0.0.0.0 bankofamerica.tt.omtrdc.net -0.0.0.0 banman.nepsecure.co.uk -0.0.0.0 banner.1and1.co.uk -0.0.0.0 banner1.pornhost.com -0.0.0.0 banner2.inet-traffic.com -0.0.0.0 bannerads.anytimenews.com -0.0.0.0 bannerads.de -0.0.0.0 bannerads.zwire.com -0.0.0.0 banner.affactive.com -0.0.0.0 banner.betroyalaffiliates.com -0.0.0.0 banner.betwwts.com -0.0.0.0 banner.cdpoker.com -0.0.0.0 banner.clubdicecasino.com -0.0.0.0 bannerconnect.net -0.0.0.0 banner.coza.com -0.0.0.0 banner.diamondclubcasino.com -0.0.0.0 bannerdriven.ru -0.0.0.0 banner.easyspace.com -0.0.0.0 bannerfarm.ace.advertising.com -0.0.0.0 banner.free6.com # www.free6.com -0.0.0.0 bannerhost.egamingonline.com -0.0.0.0 bannerimages.0catch.com -0.0.0.0 banner.joylandcasino.com -0.0.0.0 banner.media-system.de -0.0.0.0 banner.monacogoldcasino.com -0.0.0.0 banner.newyorkcasino.com -0.0.0.0 banner.northsky.com -0.0.0.0 banner.oddcast.com -0.0.0.0 banner.orb.net -0.0.0.0 banner.piratos.de -0.0.0.0 banner.playgatecasino.com -0.0.0.0 bannerpower.com -0.0.0.0 banner.prestigecasino.com -0.0.0.0 banner.publisher.to -0.0.0.0 banner.rbc.ru -0.0.0.0 banner.relcom.ru -0.0.0.0 banners1.linkbuddies.com -0.0.0.0 banners2.castles.org -0.0.0.0 banners3.spacash.com -0.0.0.0 banners.adgoto.com -0.0.0.0 banners.adultfriendfinder.com -0.0.0.0 banners.affiliatefuel.com -0.0.0.0 banners.affiliatefuture.com -0.0.0.0 banners.aftrk.com -0.0.0.0 banners.audioholics.com -0.0.0.0 banners.blogads.com -0.0.0.0 banners.bol.se -0.0.0.0 banners.broadwayworld.com -0.0.0.0 banners.celebritybling.com -0.0.0.0 banners.crisscross.com -0.0.0.0 banners.directnic.com -0.0.0.0 banners.dnastudio.com -0.0.0.0 banners.easydns.com -0.0.0.0 banners.easysolutions.be -0.0.0.0 banners.ebay.com -0.0.0.0 banners.expressindia.com -0.0.0.0 banners.flair.be -0.0.0.0 banners.free6.com # www.free6.com -0.0.0.0 banners.fuifbeest.be -0.0.0.0 banners.globovision.com -0.0.0.0 banners.img.uol.com.br -0.0.0.0 banners.ims.nl -0.0.0.0 banners.iop.org -0.0.0.0 banners.ipotd.com -0.0.0.0 banners.japantoday.com -0.0.0.0 banners.kfmb.com -0.0.0.0 banners.ksl.com -0.0.0.0 banners.linkbuddies.com -0.0.0.0 banners.looksmart.com -0.0.0.0 banners.nbcupromotes.com -0.0.0.0 banners.netcraft.com -0.0.0.0 banners.newsru.com -0.0.0.0 banners.nextcard.com -0.0.0.0 banners.passion.com -0.0.0.0 banners.pennyweb.com -0.0.0.0 banners.primaryclick.com -0.0.0.0 banners.resultonline.com -0.0.0.0 banners.rspworldwide.com -0.0.0.0 banners.sextracker.com -0.0.0.0 banners.spiceworks.com -0.0.0.0 banners.thegridwebmaster.com -0.0.0.0 banners.thestranger.com -0.0.0.0 banners.thgimages.co.uk -0.0.0.0 banners.tribute.ca -0.0.0.0 banners.tucson.com -0.0.0.0 banners.unibet.com -0.0.0.0 bannersurvey.biz -0.0.0.0 banners.valuead.com -0.0.0.0 banners.videosecrets.com -0.0.0.0 banners.webmasterplan.com -0.0.0.0 banners.wunderground.com -0.0.0.0 banners.zbs.ru -0.0.0.0 banner.tattomedia.com -0.0.0.0 banner.techarp.com -0.0.0.0 bannert.ru -0.0.0.0 bannerus1.axelsfun.com -0.0.0.0 bannerus3.axelsfun.com -0.0.0.0 banner.usacasino.com -0.0.0.0 banniere.reussissonsensemble.fr -0.0.0.0 bans.bride.ru -0.0.0.0 banstex.com -0.0.0.0 bansys.onzin.com -0.0.0.0 bargainbeautybuys.com -0.0.0.0 barnesandnoble.bfast.com -0.0.0.0 b.as-us.falkag.net -0.0.0.0 bayoubuzz.advertserve.com -0.0.0.0 bbcdn.go.adlt.bbelements.com -0.0.0.0 bbcdn.go.adnet.bbelements.com -0.0.0.0 bbcdn.go.arbo.bbelements.com -0.0.0.0 bbcdn.go.eu.bbelements.com -0.0.0.0 bbcdn.go.ihned.bbelements.com -0.0.0.0 bbcdn.go.pl.bbelements.com -0.0.0.0 bb.crwdcntrl.net -0.0.0.0 bbnaut.bbelements.com -0.0.0.0 bc685d37-266c-488e-824e-dd95d1c0e98b.statcamp.net -0.0.0.0 bcp.crwdcntrl.net -0.0.0.0 bdnad1.bangornews.com -0.0.0.0 bdv.bidvertiser.com -0.0.0.0 beacon-3.newrelic.com -0.0.0.0 beacons.helium.com -0.0.0.0 bell.adcentriconline.com -0.0.0.0 beseenad.looksmart.com -0.0.0.0 bestgift4you.cn -0.0.0.0 bestshopperrewards.com -0.0.0.0 beta.hotkeys.com -0.0.0.0 bet-at-home.com -0.0.0.0 betterperformance.goldenopps.info -0.0.0.0 bfast.com -0.0.0.0 bidclix.net -0.0.0.0 bid.openx.net -0.0.0.0 bidsystem.com -0.0.0.0 bidtraffic.com -0.0.0.0 bidvertiser.com -0.0.0.0 bigads.guj.de -0.0.0.0 bigbrandpromotions.com -0.0.0.0 bigbrandrewards.com -0.0.0.0 biggestgiftrewards.com -0.0.0.0 billing.speedboink.com -0.0.0.0 bitburg.adtech.de -0.0.0.0 bitburg.adtech.fr -0.0.0.0 bitburg.adtech.us -0.0.0.0 bitcast-d.bitgravity.com -0.0.0.0 bizad.nikkeibp.co.jp -0.0.0.0 biz-offer.com -0.0.0.0 bizopprewards.com -0.0.0.0 blabla4u.adserver.co.il -0.0.0.0 blasphemysfhs.info -0.0.0.0 blatant8jh.info -0.0.0.0 b.liquidustv.com -0.0.0.0 blog.addthis.com -0.0.0.0 blogads.com -0.0.0.0 blogads.ebanner.nl -0.0.0.0 blogvertising.pl -0.0.0.0 bluediamondoffers.com -0.0.0.0 blu.mobileads.msn.com -0.0.0.0 bl.wavecdn.de -0.0.0.0 b.myspace.com -0.0.0.0 bn.bfast.com -0.0.0.0 bnmgr.adinjector.net -0.0.0.0 bnrs.ilm.ee -0.0.0.0 boksy.dir.onet.pl -0.0.0.0 boksy.onet.pl -0.0.0.0 bookclub-offer.com -0.0.0.0 books-media-edu-premiumblvd.com -0.0.0.0 books-media-edu-rewardempire.com -0.0.0.0 books-media-rewardpath.com -0.0.0.0 bostonsubwayoffer.com -0.0.0.0 bp.specificclick.net -0.0.0.0 b.rad.live.com -0.0.0.0 b.rad.msn.com -0.0.0.0 br.adserver.yahoo.com -0.0.0.0 brandrewardcentral.com -0.0.0.0 brandsurveypanel.com -0.0.0.0 bravo.israelinfo.ru -0.0.0.0 bravospots.com -0.0.0.0 br.naked.com -0.0.0.0 broadcast.piximedia.fr -0.0.0.0 broadent.vo.llnwd.net -0.0.0.0 brokertraffic.com -0.0.0.0 bsads.looksmart.com -#0.0.0.0 b.scorecardresearch.com # interferes with Huffington Post slideshows -0.0.0.0 bs.israelinfo.ru -0.0.0.0 bs.serving-sys.com #eyeblaster.com -0.0.0.0 bt.linkpulse.com -0.0.0.0 burns.adtech.de -0.0.0.0 burns.adtech.fr -0.0.0.0 burns.adtech.us -0.0.0.0 business-rewardpath.com -0.0.0.0 bus-offer.com -0.0.0.0 buttcandy.com -0.0.0.0 buttons.googlesyndication.com -0.0.0.0 buzzbox.buzzfeed.com -0.0.0.0 bwp.lastfm.com.com -0.0.0.0 bwp.news.com -0.0.0.0 c1.popads.net -0.0.0.0 c1.teaser-goods.ru -0.0.0.0 c1.zedo.com -0.0.0.0 c2.zedo.com -0.0.0.0 c3.zedo.com -0.0.0.0 c4.maxserving.com -0.0.0.0 c4.zedo.com -0.0.0.0 c5.zedo.com -0.0.0.0 c6.zedo.com -0.0.0.0 c7.zedo.com -0.0.0.0 c8.zedo.com -0.0.0.0 ca.adserver.yahoo.com -0.0.0.0 cache.addthiscdn.com -0.0.0.0 cache.addthis.com -0.0.0.0 cache.blogads.com -0.0.0.0 cache-dev.addthis.com -0.0.0.0 cacheserve.eurogrand.com -0.0.0.0 cacheserve.prestigecasino.com -0.0.0.0 cache.unicast.com -0.0.0.0 c.actiondesk.com -0.0.0.0 c.adroll.com -0.0.0.0 califia.imaginemedia.com -0.0.0.0 c.am10.ru -0.0.0.0 camgeil.com -0.0.0.0 campaign.iitech.dk -0.0.0.0 campaign.indieclick.com -0.0.0.0 campaigns.f2.com.au -0.0.0.0 campaigns.interclick.com -0.0.0.0 capath.com -0.0.0.0 cardgamespidersolitaire.com -0.0.0.0 cards.virtuagirlhd.com -0.0.0.0 careers.canwestad.net -0.0.0.0 careers-rewardpath.com -0.0.0.0 c.ar.msn.com -0.0.0.0 carrier.bz -0.0.0.0 car-truck-boat-bonuspath.com -0.0.0.0 car-truck-boat-premiumblvd.com -0.0.0.0 casalemedia.com -0.0.0.0 cas.clickability.com -0.0.0.0 cashback.co.uk -0.0.0.0 cashbackwow.co.uk -0.0.0.0 cashflowmarketing.com -0.0.0.0 casino770.com -0.0.0.0 c.as-us.falkag.net -0.0.0.0 catalinkcashback.com -0.0.0.0 catchvid.info -0.0.0.0 c.at.msn.com -0.0.0.0 cbanners.virtuagirlhd.com -0.0.0.0 c.be.msn.com -0.0.0.0 c.blogads.com -0.0.0.0 c.br.msn.com -0.0.0.0 c.ca.msn.com -0.0.0.0 c.casalemedia.com -0.0.0.0 ccas.clearchannel.com -0.0.0.0 c.cl.msn.com -0.0.0.0 c.de.msn.com -0.0.0.0 c.dk.msn.com -0.0.0.0 cdn1.adexprt.com -0.0.0.0 cdn1.ads.mofos.com -0.0.0.0 cdn1.eyewonder.com -0.0.0.0 cdn1.rmgserving.com -0.0.0.0 cdn1.traffichaus.com -0.0.0.0 cdn1.xlightmedia.com -0.0.0.0 cdn2.adsdk.com -0.0.0.0 cdn2.amateurmatch.com -0.0.0.0 cdn2.emediate.eu -0.0.0.0 cdn3.adexprts.com -0.0.0.0 cdn3.telemetryverification.net -0.0.0.0 cdn454.telemetryverification.net -0.0.0.0 cdn5.tribalfusion.com -0.0.0.0 cdn6.emediate.eu -0.0.0.0 cdn.adigniter.org -0.0.0.0 cdn.adnxs.com -0.0.0.0 cdnads.cam4.com -0.0.0.0 cdn.ads.ookla.com -0.0.0.0 cdn.amateurmatch.com -0.0.0.0 cdn.amgdgt.com -0.0.0.0 cdn.assets.craveonline.com -0.0.0.0 cdn.banners.scubl.com -0.0.0.0 cdn.cpmstar.com -0.0.0.0 cdn.crowdignite.com -0.0.0.0 cdn.directrev.com -0.0.0.0 cdn.eyewonder.com -0.0.0.0 cdn.go.arbo.bbelements.com -0.0.0.0 cdn.go.arbopl.bbelements.com -0.0.0.0 cdn.go.cz.bbelements.com -0.0.0.0 cdn.go.idmnet.bbelements.com -0.0.0.0 cdn.go.pol.bbelements.com -0.0.0.0 cdn.hadj7.adjuggler.net -0.0.0.0 cdn.innovid.com -0.0.0.0 cdn.krxd.net -0.0.0.0 cdn.mediative.ca -0.0.0.0 cdn.merchenta.com -0.0.0.0 cdn.mobicow.com -0.0.0.0 cdn.nearbyad.com -0.0.0.0 cdn.nsimg.net -0.0.0.0 cdn.onescreen.net -#0.0.0.0 cdns.gigya.com -0.0.0.0 cdns.mydirtyhobby.com -0.0.0.0 cdns.privatamateure.com -0.0.0.0 cdn.stat.easydate.biz -0.0.0.0 cdn.syn.verticalacuity.com -0.0.0.0 cdn.tabnak.ir -0.0.0.0 cdnt.yottos.com -0.0.0.0 cdn.udmserve.net -0.0.0.0 cdn.undertone.com -0.0.0.0 cdn.wg.uproxx.com -0.0.0.0 cdnw.ringtonepartner.com -0.0.0.0 cdn.yottos.com -0.0.0.0 cdn.zeusclicks.com -0.0.0.0 cds.adecn.com -0.0.0.0 cecash.com -0.0.0.0 ced.sascdn.com -0.0.0.0 cell-phone-giveaways.com -0.0.0.0 cellphoneincentives.com -0.0.0.0 cent.adbureau.net -0.0.0.0 c.es.msn.com -0.0.0.0 c.fi.msn.com -0.0.0.0 cf.kampyle.com -0.0.0.0 c.fr.msn.com -0.0.0.0 cgirm.greatfallstribune.com -0.0.0.0 cgm.adbureau.ne -0.0.0.0 cgm.adbureau.net -0.0.0.0 c.gr.msn.com -0.0.0.0 chainsawoffer.com -0.0.0.0 chartbeat.com -0.0.0.0 checkintocash.data.7bpeople.com -0.0.0.0 cherryhi.app.ur.gcion.com -0.0.0.0 c.hk.msn.com -0.0.0.0 chkpt.zdnet.com -0.0.0.0 choicedealz.com -0.0.0.0 choicesurveypanel.com -0.0.0.0 christianbusinessadvertising.com -0.0.0.0 c.id.msn.com -0.0.0.0 c.ie.msn.com -0.0.0.0 c.il.msn.com -0.0.0.0 c.imedia.cz -0.0.0.0 c.in.msn.com -0.0.0.0 cithingy.info -0.0.0.0 citi.bridgetrack.com -0.0.0.0 c.it.msn.com -0.0.0.0 citrix.market2lead.com -0.0.0.0 cityads.telus.net -0.0.0.0 citycash2.blogspot.com -0.0.0.0 c.jp.msn.com -0.0.0.0 cl21.v4.adaction.se -0.0.0.0 cl320.v4.adaction.se -0.0.0.0 claimfreerewards.com -0.0.0.0 clashmediausa.com -0.0.0.0 classicjack.com -0.0.0.0 c.latam.msn.com -0.0.0.0 click1.mainadv.com -0.0.0.0 click1.rbc.magna.ru -0.0.0.0 click2.rbc.magna.ru -0.0.0.0 click3.rbc.magna.ru -0.0.0.0 click4.rbc.magna.ru -0.0.0.0 clickad.eo.pl -0.0.0.0 clickarrows.com -0.0.0.0 click.avenuea.com -0.0.0.0 clickbangpop.com -0.0.0.0 clickcash.webpower.com -0.0.0.0 click.go2net.com -0.0.0.0 click.israelinfo.ru -0.0.0.0 clickit.go2net.com -0.0.0.0 clickmedia.ro -0.0.0.0 click.pulse360.com -0.0.0.0 clicks2.virtuagirl.com -0.0.0.0 clicks.adultplex.com -0.0.0.0 clicks.deskbabes.com -0.0.0.0 click-see-save.com -0.0.0.0 clicksor.com -0.0.0.0 clicksotrk.com -0.0.0.0 clicks.totemcash.com -0.0.0.0 clicks.toteme.com -0.0.0.0 clicks.virtuagirl.com -0.0.0.0 clicks.virtuagirlhd.com -0.0.0.0 clicks.virtuaguyhd.com -0.0.0.0 clicks.walla.co.il -0.0.0.0 clickthru.net -0.0.0.0 clickthrunet.net -0.0.0.0 clickthruserver.com -0.0.0.0 clickthrutraffic.com -0.0.0.0 clicktorrent.info -0.0.0.0 clipserv.adclip.com -0.0.0.0 clkads.com -0.0.0.0 clk.cloudyisland.com -0.0.0.0 clk.tradedoubler.com -0.0.0.0 clkuk.tradedoubler.com -0.0.0.0 c.lomadee.com -0.0.0.0 closeoutproductsreview.com -0.0.0.0 cluster3.adultadworld.com -0.0.0.0 cluster.adultadworld.com -0.0.0.0 cm1359.com -0.0.0.0 cmads.sv.publicus.com -0.0.0.0 cmads.us.publicus.com -0.0.0.0 cmap.am.ace.advertising.com -0.0.0.0 cmap.an.ace.advertising.com -0.0.0.0 cmap.at.ace.advertising.com -0.0.0.0 cmap.dc.ace.advertising.com -0.0.0.0 cmap.ox.ace.advertising.com -0.0.0.0 cmap.pub.ace.advertising.com -0.0.0.0 cmap.rm.ace.advertising.com -0.0.0.0 cmap.rub.ace.advertising.com -0.0.0.0 cmhtml.overture.com -0.0.0.0 cmn1lsm2.beliefnet.com -0.0.0.0 cm.npc-hearst.overture.com -0.0.0.0 cmps.mt50ad.com -0.0.0.0 cm.the-n.overture.com -0.0.0.0 c.my.msn.com -0.0.0.0 cnad1.economicoutlook.net -0.0.0.0 cnad2.economicoutlook.net -0.0.0.0 cnad3.economicoutlook.net -0.0.0.0 cnad4.economicoutlook.net -0.0.0.0 cnad5.economicoutlook.net -0.0.0.0 cnad6.economicoutlook.net -0.0.0.0 cnad7.economicoutlook.net -0.0.0.0 cnad8.economicoutlook.net -0.0.0.0 cnad9.economicoutlook.net -0.0.0.0 cnad.economicoutlook.net -0.0.0.0 cn.adserver.yahoo.com -0.0.0.0 cnf.adshuffle.com -0.0.0.0 c.ninemsn.com.au -0.0.0.0 c.nl.msn.com -0.0.0.0 c.no.msn.com -0.0.0.0 c.novostimira.biz -0.0.0.0 cnt1.xhamster.com -0.0.0.0 code2.adtlgc.com -0.0.0.0 code.adtlgc.com -0.0.0.0 collectiveads.net -0.0.0.0 col.mobileads.msn.com -0.0.0.0 comadverts.bcmpweb.co.nz -0.0.0.0 comcastresidentialservices.tt.omtrdc.net -0.0.0.0 com.cool-premiums-now.com -0.0.0.0 come-see-it-all.com -0.0.0.0 com.htmlwww.youfck.com -0.0.0.0 commerce-offer.com -0.0.0.0 commerce-rewardpath.com -0.0.0.0 commerce.www.ibm.com -0.0.0.0 common.ziffdavisinternet.com -0.0.0.0 companion.adap.tv -0.0.0.0 computer-offer.com -0.0.0.0 computer-offer.net -0.0.0.0 computers-electronics-rewardpath.com -0.0.0.0 computersncs.com -0.0.0.0 com.shc-rebates.com -0.0.0.0 connect.247media.ads.link4ads.com -0.0.0.0 consumergiftcenter.com -0.0.0.0 consumerincentivenetwork.com -0.0.0.0 consumerinfo.tt.omtrdc.net -0.0.0.0 consumer-org.com -0.0.0.0 contaxe.com -0.0.0.0 content.ad-flow.com -0.0.0.0 content.clipster.ws -0.0.0.0 content.codelnet.com -0.0.0.0 content.promoisland.net -0.0.0.0 contentsearch.de.espotting.com -0.0.0.0 content.yieldmanager.edgesuite.net -0.0.0.0 context3.kanoodle.com -0.0.0.0 context5.kanoodle.com -0.0.0.0 context.adshadow.net -0.0.0.0 contextweb.com -0.0.0.0 conv.adengage.com -0.0.0.0 conversion-pixel.invitemedia.com -0.0.0.0 cookiecontainer.blox.pl -0.0.0.0 cookie.pebblemedia.be -0.0.0.0 cookingtiprewards.com -0.0.0.0 cookonsea.com -0.0.0.0 cool-premiums.com -0.0.0.0 cool-premiums-now.com -0.0.0.0 coolpremiumsnow.com -0.0.0.0 coolsavings.com -0.0.0.0 corba.adtech.de -0.0.0.0 corba.adtech.fr -0.0.0.0 corba.adtech.us -0.0.0.0 core0.node12.top.mail.ru -0.0.0.0 core2.adtlgc.com -0.0.0.0 coreg.flashtrack.net -0.0.0.0 coreglead.co.uk -0.0.0.0 core.insightexpressai.com -0.0.0.0 core.videoegg.com -0.0.0.0 cornflakes.pathfinder.com -0.0.0.0 corusads.dserv.ca -0.0.0.0 cosmeticscentre.uk.com -0.0.0.0 count6.51yes.com -0.0.0.0 count.casino-trade.com -0.0.0.0 cover.m2y.siemens.ch -0.0.0.0 c.ph.msn.com -0.0.0.0 cpmadvisors.com -0.0.0.0 cp.promoisland.net -0.0.0.0 c.prodigy.msn.com -0.0.0.0 c.pt.msn.com -0.0.0.0 cpu.firingsquad.com -0.0.0.0 creatiby1.unicast.com -0.0.0.0 creative.adshuffle.com -0.0.0.0 creative.ak.facebook.com -0.0.0.0 creatives.livejasmin.com -0.0.0.0 creatives.rgadvert.com -0.0.0.0 creatrixads.com -0.0.0.0 crediblegfj.info -0.0.0.0 creditburner.blueadvertise.com -0.0.0.0 creditsoffer.blogspot.com -0.0.0.0 creview.adbureau.net -0.0.0.0 crosspixel.demdex.net -0.0.0.0 crowdgravity.com -0.0.0.0 crowdignite.com -0.0.0.0 c.ru.msn.com -0.0.0.0 crux.songline.com -0.0.0.0 crwdcntrl.net -0.0.0.0 c.se.msn.com -0.0.0.0 cserver.mii.instacontent.net -0.0.0.0 c.sg.msn.com -0.0.0.0 csh.actiondesk.com -0.0.0.0 csm.rotator.hadj7.adjuggler.net -0.0.0.0 cspix.media6degrees.com -0.0.0.0 cs.prd.msys.playstation.net -0.0.0.0 csr.onet.pl -0.0.0.0 ctbdev.net -0.0.0.0 c.th.msn.com -0.0.0.0 c.tr.msn.com -0.0.0.0 cts.channelintelligence.com -0.0.0.0 c.tw.msn.com -0.0.0.0 ctxtad.tribalfusion.com -0.0.0.0 c.uk.msn.com -0.0.0.0 cxoadfarm.dyndns.info -0.0.0.0 cxtad.specificmedia.com -0.0.0.0 cyber-incentives.com -0.0.0.0 cz8.clickzs.com -0.0.0.0 c.za.msn.com -0.0.0.0 cz.bbelements.com -0.0.0.0 d.101m3.com -0.0.0.0 d10.zedo.com -0.0.0.0 d11.zedo.com -0.0.0.0 d12.zedo.com -0.0.0.0 d14.zedo.com -0.0.0.0 d1.openx.org -0.0.0.0 d1ros97qkrwjf5.cloudfront.net -0.0.0.0 d1.zedo.com -0.0.0.0 d2.zedo.com -0.0.0.0 d3.zedo.com -0.0.0.0 d4.zedo.com -0.0.0.0 d5phz18u4wuww.cloudfront.net -0.0.0.0 d5.zedo.com -0.0.0.0 d6.c5.b0.a2.top.mail.ru -0.0.0.0 d6.zedo.com -0.0.0.0 d7.zedo.com -0.0.0.0 d8.zedo.com -0.0.0.0 d9.zedo.com -0.0.0.0 da.2000888.com -0.0.0.0 d.adnetxchange.com -0.0.0.0 d.adserve.com -0.0.0.0 dads.new.digg.com -0.0.0.0 d.ads.readwriteweb.com -0.0.0.0 d.agkn.com -0.0.0.0 daily-saver.com -0.0.0.0 darmowe-liczniki.info -0.0.0.0 dart.chron.com -0.0.0.0 data.flurry.com -0.0.0.0 date.ventivmedia.com -0.0.0.0 datingadvertising.com -0.0.0.0 db4.net-filter.com -0.0.0.0 dbbsrv.com -0.0.0.0 dc.sabela.com.pl -0.0.0.0 dctracking.com -0.0.0.0 de.adserver.yahoo.com -0.0.0.0 del1.phillyburbs.com -0.0.0.0 delb.mspaceads.com -0.0.0.0 delivery.adyea.com -0.0.0.0 delivery.trafficjunky.net -0.0.0.0 delivery.w00tads.com -0.0.0.0 delivery.way2traffic.com -0.0.0.0 demr.mspaceads.com -0.0.0.0 demr.opt.fimserve.com -0.0.0.0 derkeiler.com -0.0.0.0 desb.mspaceads.com -0.0.0.0 descargas2.tuvideogratis.com -0.0.0.0 designbloxlive.com -0.0.0.0 desk.mspaceads.com -0.0.0.0 desk.opt.fimserve.com -0.0.0.0 dev.adforum.com -0.0.0.0 devart.adbureau.net -0.0.0.0 devlp1.linkpulse.com -0.0.0.0 dev.sfbg.com -0.0.0.0 dgm2.com -0.0.0.0 dgmaustralia.com -0.0.0.0 dg.specificclick.net -0.0.0.0 dietoftoday.ca.pn #security risk/fake news# -0.0.0.0 diff3.smartadserver.com -0.0.0.0 dinoadserver1.roka.net -0.0.0.0 dinoadserver2.roka.net -0.0.0.0 directleads.com -0.0.0.0 directpowerrewards.com -0.0.0.0 directrev.cloudapp.net -0.0.0.0 dirtyrhino.com -0.0.0.0 discount-savings-more.com -0.0.0.0 discoverecommerce.tt.omtrdc.net -0.0.0.0 display.gestionpub.com -0.0.0.0 dist.belnk.com -0.0.0.0 divx.adbureau.net -0.0.0.0 djbanners.deadjournal.com -0.0.0.0 djugoogs.com -0.0.0.0 dk.adserver.yahoo.com -0.0.0.0 dl.ncbuy.com -0.0.0.0 dl-plugin.com -0.0.0.0 dlvr.readserver.net -0.0.0.0 dnads.directnic.com -0.0.0.0 dnps.com -0.0.0.0 dnse.linkpulse.com -0.0.0.0 dosugcz.biz -0.0.0.0 dot.wp.pl -0.0.0.0 downloadcdn.com -0.0.0.0 do-wn-lo-ad.com -0.0.0.0 downloads.larivieracasino.com -0.0.0.0 downloads.mytvandmovies.com -0.0.0.0 dqs001.adtech.de -0.0.0.0 dqs001.adtech.fr -0.0.0.0 dqs001.adtech.us -0.0.0.0 dra.amazon-adsystem.com -0.0.0.0 drowle.com -0.0.0.0 ds.contextweb.com -0.0.0.0 ds.onet.pl -0.0.0.0 ds.serving-sys.com -0.0.0.0 dt.linkpulse.com -0.0.0.0 dub.mobileads.msn.com -0.0.0.0 e0.extreme-dm.com -0.0.0.0 e1.addthis.com -0.0.0.0 e2.cdn.qnsr.com -0.0.0.0 e2.emediate.se -0.0.0.0 eads-adserving.com -0.0.0.0 ead.sharethis.com -0.0.0.0 earnmygift.com -0.0.0.0 earnpointsandgifts.com -0.0.0.0 e.as-eu.falkag.net -0.0.0.0 easyadservice.com -0.0.0.0 easyweb.tdcanadatrust.secureserver.host1.customer-identification-process.b88600d8.com -0.0.0.0 eatps.web.aol.com -0.0.0.0 eb.adbureau.net -0.0.0.0 eblastengine.upickem.net -0.0.0.0 ecomadserver.com -0.0.0.0 eddamedia.linkpulse.com -0.0.0.0 edge.bnmla.com -0.0.0.0 edge.quantserve.com -0.0.0.0 edirect.hotkeys.com -0.0.0.0 education-rewardpath.com -0.0.0.0 edu-offer.com -0.0.0.0 electronics-bonuspath.com -0.0.0.0 electronics-offer.net -0.0.0.0 electronicspresent.com -0.0.0.0 electronics-rewardpath.com -0.0.0.0 emailadvantagegroup.com -0.0.0.0 emailproductreview.com -0.0.0.0 emapadserver.com -0.0.0.0 emea-bidder.mathtag.com -0.0.0.0 engage.everyone.net -0.0.0.0 engage.speedera.net -0.0.0.0 engine2.adzerk.net -0.0.0.0 engine.4chan-ads.org -0.0.0.0 engine.adland.ru -0.0.0.0 engine.adzerk.net -0.0.0.0 engine.carbonads.com -0.0.0.0 engine.espace.netavenir.com -0.0.0.0 engine.influads.com -0.0.0.0 engine.rorer.ru -0.0.0.0 enirocode.adtlgc.com -0.0.0.0 enirodk.adtlgc.com -0.0.0.0 enn.advertserve.com -0.0.0.0 entertainment-rewardpath.com -0.0.0.0 entertainment-specials.com -0.0.0.0 es.adserver.yahoo.com -0.0.0.0 escape.insites.eu -0.0.0.0 espn.footprint.net -0.0.0.0 etad.telegraph.co.uk -0.0.0.0 etrk.asus.com -0.0.0.0 etype.adbureau.net -0.0.0.0 eu2.madsone.com -0.0.0.0 euniverseads.com -0.0.0.0 eu-pn4.adserver.yahoo.com -0.0.0.0 europe.adserver.yahoo.com -0.0.0.0 eu.xtms.net -0.0.0.0 eventtracker.videostrip.com -0.0.0.0 exclusivegiftcards.com -0.0.0.0 exits1.webquest.net -0.0.0.0 exits2.webquest.net -0.0.0.0 exponential.com -0.0.0.0 eyewonder.com -0.0.0.0 ezboard.bigbangmedia.com -0.0.0.0 falkag.net -0.0.0.0 family-offer.com -0.0.0.0 farm.plista.com -0.0.0.0 f.as-eu.falkag.net -0.0.0.0 fatcatrewards.com -0.0.0.0 fbcdn-creative-a.akamaihd.net -0.0.0.0 fbfreegifts.com -0.0.0.0 fbi.gov.id402037057-8235504608.d9680.com -0.0.0.0 fcg.casino770.com -0.0.0.0 fc.webmasterpro.de -0.0.0.0 fdimages.fairfax.com.au -0.0.0.0 feedads.googleadservices.com -0.0.0.0 feeds.videosz.com -0.0.0.0 feeds.weselltraffic.com -0.0.0.0 fei.pro-market.net -0.0.0.0 fe.lea.lycos.es -0.0.0.0 fhm.valueclick.net -0.0.0.0 fif49.info -0.0.0.0 files.adbrite.com -0.0.0.0 fin.adbureau.net -0.0.0.0 finance-offer.com -0.0.0.0 finanzmeldungen.com -0.0.0.0 finder.cox.net -0.0.0.0 fixbonus.com -0.0.0.0 floatingads.madisonavenue.com -0.0.0.0 floridat.app.ur.gcion.com -0.0.0.0 flowers-offer.com -0.0.0.0 fls-na.amazon.com -0.0.0.0 flu23.com -0.0.0.0 fmads.osdn.com -0.0.0.0 focusin.ads.targetnet.com -0.0.0.0 folloyu.com -0.0.0.0 food-drink-bonuspath.com -0.0.0.0 food-drink-rewardpath.com -0.0.0.0 foodmixeroffer.com -0.0.0.0 food-offer.com -0.0.0.0 foreignpolicy.advertserve.com -0.0.0.0 fp.uclo.net -0.0.0.0 fp.valueclick.com -0.0.0.0 fr.a2dfp.net -0.0.0.0 fr.adserver.yahoo.com -0.0.0.0 fr.classic.clickintext.net -0.0.0.0 freebiegb.co.uk -0.0.0.0 freecameraonus.com -0.0.0.0 freecameraprovider.com -0.0.0.0 freecamerasource.com -0.0.0.0 freecamerauk.co.uk -0.0.0.0 freecoolgift.com -0.0.0.0 freedesignerhandbagreviews.com -0.0.0.0 freedinnersource.com -0.0.0.0 freedvddept.com -0.0.0.0 freeelectronicscenter.com -0.0.0.0 freeelectronicsdepot.com -0.0.0.0 freeelectronicsonus.com -0.0.0.0 freeelectronicssource.com -0.0.0.0 freeentertainmentsource.com -0.0.0.0 freefoodprovider.com -0.0.0.0 freefoodsource.com -0.0.0.0 freefuelcard.com -0.0.0.0 freefuelcoupon.com -0.0.0.0 freegasonus.com -0.0.0.0 freegasprovider.com -0.0.0.0 free-gift-cards-now.com -0.0.0.0 freegiftcardsource.com -0.0.0.0 freegiftreward.com -0.0.0.0 free-gifts-comp.com -0.0.0.0 free.hotsocialz.com -0.0.0.0 freeipodnanouk.co.uk -0.0.0.0 freeipoduk.com -0.0.0.0 freeipoduk.co.uk -0.0.0.0 freelaptopgift.com -0.0.0.0 freelaptopnation.com -0.0.0.0 free-laptop-reward.com -0.0.0.0 freelaptopreward.com -0.0.0.0 freelaptopwebsites.com -0.0.0.0 freenation.com -0.0.0.0 freeoffers-toys.com -0.0.0.0 freepayasyougotopupuk.co.uk -0.0.0.0 freeplasmanation.com -0.0.0.0 freerestaurantprovider.com -0.0.0.0 freerestaurantsource.com -0.0.0.0 free-rewards.com-s.tv -0.0.0.0 freeshoppingprovider.com -0.0.0.0 freeshoppingsource.com -0.0.0.0 free.thesocialsexnetwork.com -0.0.0.0 freevideodownloadforpc.com -0.0.0.0 frontend-loadbalancer.meteorsolutions.com -0.0.0.0 fwdservice.com -0.0.0.0 fwmrm.net -0.0.0.0 g1.idg.pl -0.0.0.0 g2.gumgum.com -0.0.0.0 g3t4d5.madison.com -0.0.0.0 g4p.grt02.com -0.0.0.0 gadgeteer.pdamart.com -0.0.0.0 gam.adnxs.com -0.0.0.0 gameconsolerewards.com -0.0.0.0 games-toys-bonuspath.com -0.0.0.0 games-toys-free.com -0.0.0.0 games-toys-rewardpath.com -0.0.0.0 gate.hyperpaysys.com -0.0.0.0 gavzad.keenspot.com -0.0.0.0 gazeta.hit.gemius.pl -0.0.0.0 gazetteextra.advertserve.com -0.0.0.0 gbanners.hornymatches.com -0.0.0.0 gcads.osdn.com -0.0.0.0 gcdn.2mdn.net -0.0.0.0 gc.gcl.ru -0.0.0.0 gcir.gannett-tv.com -0.0.0.0 gcirm2.indystar.com -0.0.0.0 gcirm.argusleader.com -0.0.0.0 gcirm.argusleader.gcion.com -0.0.0.0 gcirm.battlecreekenquirer.com -0.0.0.0 gcirm.burlingtonfreepress.com -0.0.0.0 gcirm.centralohio.com -0.0.0.0 gcirm.centralohio.gcion.com -0.0.0.0 gcirm.cincinnati.com -0.0.0.0 gcirm.citizen-times.com -0.0.0.0 gcirm.clarionledger.com -0.0.0.0 gcirm.coloradoan.com -0.0.0.0 gcirm.courier-journal.com -0.0.0.0 gcirm.courierpostonline.com -0.0.0.0 gcirm.customcoupon.com -0.0.0.0 gcirm.dailyrecord.com -0.0.0.0 gcirm.delawareonline.com -0.0.0.0 gcirm.democratandchronicle.com -0.0.0.0 gcirm.desmoinesregister.com -0.0.0.0 gcirm.detnews.com -0.0.0.0 gcirm.dmp.gcion.com -0.0.0.0 gcirm.dmregister.com -0.0.0.0 gcirm.dnj.com -0.0.0.0 gcirm.flatoday.com -0.0.0.0 gcirm.gannettnetwork.com -0.0.0.0 gcirm.gannett-tv.com -0.0.0.0 gcirm.greatfallstribune.com -0.0.0.0 gcirm.greenvilleonline.com -0.0.0.0 gcirm.greenvilleonline.gcion.com -0.0.0.0 gcirm.honoluluadvertiser.gcion.com -0.0.0.0 gcirm.idahostatesman.com -0.0.0.0 gcirm.idehostatesman.com -0.0.0.0 gcirm.indystar.com -0.0.0.0 gcirm.injersey.com -0.0.0.0 gcirm.jacksonsun.com -0.0.0.0 gcirm.laregionalonline.com -0.0.0.0 gcirm.lsj.com -0.0.0.0 gcirm.montgomeryadvertiser.com -0.0.0.0 gcirm.muskogeephoenix.com -0.0.0.0 gcirm.newsleader.com -0.0.0.0 gcirm.news-press.com -0.0.0.0 gcirm.ozarksnow.com -0.0.0.0 gcirm.pensacolanewsjournal.com -0.0.0.0 gcirm.press-citizen.com -0.0.0.0 gcirm.pressconnects.com -0.0.0.0 gcirm.rgj.com -0.0.0.0 gcirm.sctimes.com -0.0.0.0 gcirm.stargazette.com -0.0.0.0 gcirm.statesmanjournal.com -0.0.0.0 gcirm.tallahassee.com -0.0.0.0 gcirm.tennessean.com -0.0.0.0 gcirm.thedailyjournal.com -0.0.0.0 gcirm.thedesertsun.com -0.0.0.0 gcirm.theithacajournal.com -0.0.0.0 gcirm.thejournalnews.com -0.0.0.0 gcirm.theolympian.com -0.0.0.0 gcirm.thespectrum.com -0.0.0.0 gcirm.tucson.com -0.0.0.0 gcirm.wisinfo.com -0.0.0.0 gde.adocean.pl -0.0.0.0 gdeee.hit.gemius.pl -0.0.0.0 gdelt.hit.gemius.pl -0.0.0.0 gdelv.hit.gemius.pl -0.0.0.0 gdyn.cnngo.com -0.0.0.0 gdyn.trutv.com -0.0.0.0 gemius.pl -0.0.0.0 geoads.osdn.com -0.0.0.0 geoloc11.geovisite.com -0.0.0.0 geo.precisionclick.com -0.0.0.0 getacool100.com -0.0.0.0 getacool500.com -0.0.0.0 getacoollaptop.com -0.0.0.0 getacooltv.com -0.0.0.0 getafreeiphone.org -0.0.0.0 getagiftonline.com -0.0.0.0 getmyfreebabystuff.com -0.0.0.0 getmyfreegear.com -0.0.0.0 getmyfreegiftcard.com -0.0.0.0 getmyfreelaptop.com -0.0.0.0 getmyfreelaptophere.com -0.0.0.0 getmyfreeplasma.com -0.0.0.0 getmylaptopfree.com -0.0.0.0 getmyplasmatv.com -0.0.0.0 getspecialgifts.com -0.0.0.0 getyour5kcredits0.blogspot.com -0.0.0.0 getyourfreecomputer.com -0.0.0.0 getyourfreetv.com -0.0.0.0 getyourgiftnow2.blogspot.com -0.0.0.0 getyourgiftnow3.blogspot.com -0.0.0.0 gg.adocean.pl -0.0.0.0 giftcardchallenge.com -0.0.0.0 giftcardsurveys.us.com -0.0.0.0 giftrewardzone.com -0.0.0.0 gifts-flowers-rewardpath.com -0.0.0.0 gimmethatreward.com -0.0.0.0 gingert.net -0.0.0.0 globalwebads.com -0.0.0.0 gmads.net -0.0.0.0 gm.preferences.com -0.0.0.0 go2.hit.gemius.pl -0.0.0.0 go.adee.bbelements.com -0.0.0.0 go.adlt.bbelements.com -0.0.0.0 go.adlv.bbelements.com -0.0.0.0 go.admulti.com -0.0.0.0 go.adnet.bbelements.com -0.0.0.0 go.arbo.bbelements.com -0.0.0.0 go.arbopl.bbelements.com -0.0.0.0 go.arboru.bbelements.com -0.0.0.0 go.bb007.bbelements.com -0.0.0.0 go.evolutionmedia.bbelements.com -0.0.0.0 go-free-gifts.com -0.0.0.0 gofreegifts.com -0.0.0.0 go.ihned.bbelements.com -0.0.0.0 go.intact.bbelements.com -0.0.0.0 go.lfstmedia.com -0.0.0.0 go.lotech.bbelements.com -0.0.0.0 goodsblock.marketgid.com -0.0.0.0 goody-garage.com -0.0.0.0 go.pl.bbelements.com -0.0.0.0 got2goshop.com -0.0.0.0 goto.trafficmultiplier.com -0.0.0.0 gozing.directtrack.com -0.0.0.0 grabbit-rabbit.com -0.0.0.0 graphics.adultfriendfinder.com -0.0.0.0 graphics.pop6.com -0.0.0.0 gratkapl.adocean.pl -0.0.0.0 gravitron.chron.com -0.0.0.0 greasypalm.com -0.0.0.0 grfx.mp3.com -0.0.0.0 groupon.pl -0.0.0.0 grz67.com -0.0.0.0 gs1.idsales.co.uk -0.0.0.0 gserv.cneteu.net -0.0.0.0 gspro.hit.gemius.pl -0.0.0.0 g.thinktarget.com -0.0.0.0 guiaconsumidor.com -0.0.0.0 guide2poker.com -0.0.0.0 guptamedianetwork.com -0.0.0.0 guru.sitescout.netdna-cdn.com -0.0.0.0 gwallet.com -0.0.0.0 gx-in-f109.1e100.net -0.0.0.0 h-afnetwww.adshuffle.com -0.0.0.0 halfords.ukrpts.net -0.0.0.0 happydiscountspecials.com -0.0.0.0 harvest176.adgardener.com -0.0.0.0 harvest284.adgardener.com -0.0.0.0 harvest285.adgardener.com -0.0.0.0 harvest.adgardener.com -0.0.0.0 hathor.eztonez.com -0.0.0.0 haynet.adbureau.net -0.0.0.0 hbads.eboz.com -0.0.0.0 hbadz.eboz.com -0.0.0.0 healthbeautyncs.com -0.0.0.0 health-beauty-rewardpath.com -0.0.0.0 health-beauty-savingblvd.com -0.0.0.0 healthclicks.co.uk -0.0.0.0 hebdotop.com -0.0.0.0 help.adtech.de -0.0.0.0 help.adtech.fr -0.0.0.0 help.adtech.us -0.0.0.0 helpint.mywebsearch.com -0.0.0.0 hightrafficads.com -0.0.0.0 himediads.com -0.0.0.0 hit4.hotlog.ru -0.0.0.0 hk.adserver.yahoo.com -0.0.0.0 hlcc.ca -0.0.0.0 holiday-gift-offers.com -0.0.0.0 holidayproductpromo.com -0.0.0.0 holidayshoppingrewards.com -0.0.0.0 home4bizstart.ru -0.0.0.0 homeelectronicproducts.com -0.0.0.0 home-garden-premiumblvd.com -0.0.0.0 home-garden-rewardempire.com -0.0.0.0 home-garden-rewardpath.com -0.0.0.0 homeimprovementonus.com -0.0.0.0 honolulu.app.ur.gcion.com -0.0.0.0 hooqy.com -0.0.0.0 host207.ewtn.com -0.0.0.0 hostedaje14.thruport.com -0.0.0.0 hosting.adjug.com -0.0.0.0 hot-daily-deal.com -0.0.0.0 hotgiftzone.com -0.0.0.0 hot-product-hangout.com -0.0.0.0 hpad.www.infoseek.co.jp -0.0.0.0 h.ppjol.com -0.0.0.0 htmlads.ru -0.0.0.0 html.centralmediaserver.com -0.0.0.0 htmlwww.youfck.com -0.0.0.0 http300.content.ru4.com -0.0.0.0 httpads.com -0.0.0.0 httpwwwadserver.com -0.0.0.0 hub.com.pl -0.0.0.0 huiwiw.hit.gemius.pl -0.0.0.0 huntingtonbank.tt.omtrdc.net -0.0.0.0 huomdgde.adocean.pl -0.0.0.0 hyperion.adtech.de -0.0.0.0 hyperion.adtech.fr -0.0.0.0 hyperion.adtech.us -0.0.0.0 i1.teaser-goods.ru -0.0.0.0 iacas.adbureau.net -0.0.0.0 iad.anm.co.uk -0.0.0.0 iadc.qwapi.com -#0.0.0.0 iadsdk.apple.com #may interfere with iTunes radio -0.0.0.0 ib.adnxs.com -0.0.0.0 ibis.lgappstv.com -0.0.0.0 i.blogads.com -0.0.0.0 i.casalemedia.com -0.0.0.0 icon.clickthru.net -0.0.0.0 id11938.luxup.ru -0.0.0.0 id5576.al21.luxup.ru -0.0.0.0 idearc.tt.omtrdc.net -0.0.0.0 idpix.media6degrees.com -0.0.0.0 ieee.adbureau.net -0.0.0.0 if.bbanner.it -0.0.0.0 iftarvakitleri.net -0.0.0.0 ih2.gamecopyworld.com -0.0.0.0 i.hotkeys.com -0.0.0.0 i.interia.pl -0.0.0.0 i.laih.com -0.0.0.0 ilinks.industrybrains.com -0.0.0.0 im.adtech.de -0.0.0.0 image2.pubmatic.com -0.0.0.0 imageads.canoe.ca -0.0.0.0 imagec08.247realmedia.com -0.0.0.0 imagec12.247realmedia.com -0.0.0.0 imagec14.247realmedia.com -0.0.0.0 imagecache2.allposters.com -0.0.0.0 imageceu1.247realmedia.com -0.0.0.0 image.click.livedoor.com -0.0.0.0 image.i1img.com -0.0.0.0 image.linkexchange.com -0.0.0.0 images2.laih.com -0.0.0.0 images3.linkwithin.com -0.0.0.0 images.ads.fairfax.com.au -0.0.0.0 images.blogads.com -0.0.0.0 images.bluetime.com -0.0.0.0 images-cdn.azoogleads.com -0.0.0.0 images.clickfinders.com -0.0.0.0 images.conduit-banners.com -0.0.0.0 images.cybereps.com -0.0.0.0 images.directtrack.com -0.0.0.0 images.emapadserver.com -0.0.0.0 imageserv.adtech.de -0.0.0.0 imageserv.adtech.fr -0.0.0.0 imageserv.adtech.us -0.0.0.0 imageserver1.thruport.com -0.0.0.0 images.jambocast.com -0.0.0.0 images.linkwithin.com -0.0.0.0 images.mbuyu.nl -0.0.0.0 images.netcomvad.com -0.0.0.0 images.newsx.cc -0.0.0.0 images.people2people.com -0.0.0.0 images.primaryads.com -0.0.0.0 images.sexlist.com -0.0.0.0 images.steamray.com -0.0.0.0 images.trafficmp.com -0.0.0.0 im.banner.t-online.de -0.0.0.0 i.media.cz -0.0.0.0 img0.ru.redtram.com -0.0.0.0 img1.ru.redtram.com -0.0.0.0 img2.ru.redtram.com -0.0.0.0 img4.cdn.adjuggler.com -0.0.0.0 img-a2.ak.imagevz.net -0.0.0.0 img.blogads.com -0.0.0.0 img-cdn.mediaplex.com -0.0.0.0 img.directtrack.com -0.0.0.0 imgg.dt00.net -0.0.0.0 imgg.marketgid.com -0.0.0.0 img.layer-ads.de -0.0.0.0 img.marketgid.com -0.0.0.0 imgn.dt00.net -0.0.0.0 imgn.dt07.com -0.0.0.0 imgn.marketgid.com -0.0.0.0 imgserv.adbutler.com -0.0.0.0 img.sn00.net -0.0.0.0 img.soulmate.com -0.0.0.0 img.xnxx.com -0.0.0.0 im.of.pl -0.0.0.0 impact.cossette-webpact.com -0.0.0.0 impbe.tradedoubler.com -0.0.0.0 imp.partner2profit.com -0.0.0.0 imppl.tradedoubler.com -0.0.0.0 impressionaffiliate.com -0.0.0.0 impressionaffiliate.mobi -0.0.0.0 impressionlead.com -0.0.0.0 impressionperformance.biz -0.0.0.0 imserv001.adtech.de -0.0.0.0 imserv001.adtech.fr -0.0.0.0 imserv001.adtech.us -0.0.0.0 imserv002.adtech.de -0.0.0.0 imserv002.adtech.fr -0.0.0.0 imserv002.adtech.us -0.0.0.0 imserv003.adtech.de -0.0.0.0 imserv003.adtech.fr -0.0.0.0 imserv003.adtech.us -0.0.0.0 imserv004.adtech.de -0.0.0.0 imserv004.adtech.fr -0.0.0.0 imserv004.adtech.us -0.0.0.0 imserv005.adtech.de -0.0.0.0 imserv005.adtech.fr -0.0.0.0 imserv005.adtech.us -0.0.0.0 imserv006.adtech.de -0.0.0.0 imserv006.adtech.fr -0.0.0.0 imserv006.adtech.us -0.0.0.0 imserv00x.adtech.de -0.0.0.0 imserv00x.adtech.fr -0.0.0.0 imserv00x.adtech.us -0.0.0.0 imssl01.adtech.de -0.0.0.0 imssl01.adtech.fr -0.0.0.0 imssl01.adtech.us -0.0.0.0 im.xo.pl -0.0.0.0 in.adserver.yahoo.com -0.0.0.0 incentivegateway.com -0.0.0.0 incentiverewardcenter.com -0.0.0.0 incentive-scene.com -0.0.0.0 indexhu.adocean.pl -0.0.0.0 infinite-ads.com -0.0.0.0 inklineglobal.com -0.0.0.0 inl.adbureau.net -0.0.0.0 input.insights.gravity.com -0.0.0.0 insightxe.pittsburghlive.com -0.0.0.0 insightxe.vtsgonline.com -0.0.0.0 ins-offer.com -0.0.0.0 installer.zutrack.com -0.0.0.0 insurance-rewardpath.com -0.0.0.0 intela.com -0.0.0.0 intelliads.com -0.0.0.0 internet.billboard.cz -0.0.0.0 intnet-offer.com -0.0.0.0 intrack.pl -0.0.0.0 invitefashion.com -0.0.0.0 ipacc1.adtech.de -0.0.0.0 ipacc1.adtech.fr -0.0.0.0 ipacc1.adtech.us -0.0.0.0 ipad2free4u.com -0.0.0.0 i.pcp001.com -0.0.0.0 ipdata.adtech.de -0.0.0.0 ipdata.adtech.fr -0.0.0.0 ipdata.adtech.us -0.0.0.0 iq001.adtech.de -0.0.0.0 iq001.adtech.fr -0.0.0.0 iq001.adtech.us -0.0.0.0 i.qitrck.com -0.0.0.0 is.casalemedia.com -0.0.0.0 i.securecontactinfo.com -0.0.0.0 isg01.casalemedia.com -0.0.0.0 isg02.casalemedia.com -0.0.0.0 isg03.casalemedia.com -0.0.0.0 isg04.casalemedia.com -0.0.0.0 isg05.casalemedia.com -0.0.0.0 isg06.casalemedia.com -0.0.0.0 isg07.casalemedia.com -0.0.0.0 isg08.casalemedia.com -0.0.0.0 isg09.casalemedia.com -0.0.0.0 i.simpli.fi -0.0.0.0 it.adserver.yahoo.com -0.0.0.0 i.total-media.net -0.0.0.0 itrackerpro.com -0.0.0.0 i.trkjmp.com -0.0.0.0 itsfree123.com -0.0.0.0 itxt.vibrantmedia.com -0.0.0.0 iwantmyfreecash.com -0.0.0.0 iwantmy-freelaptop.com -0.0.0.0 iwantmyfree-laptop.com -0.0.0.0 iwantmyfreelaptop.com -0.0.0.0 iwantmygiftcard.com -0.0.0.0 jambocast.com -0.0.0.0 jb9clfifs6.s.ad6media.fr -0.0.0.0 jcarter.spinbox.net -0.0.0.0 j.clickdensity.com -0.0.0.0 jcrew.tt.omtrdc.net -0.0.0.0 jersey-offer.com -0.0.0.0 jgedads.cjt.net -0.0.0.0 jh.revolvermaps.com -0.0.0.0 jivox.com -0.0.0.0 jl29jd25sm24mc29.com -0.0.0.0 jlinks.industrybrains.com -0.0.0.0 jmn.jangonetwork.com -0.0.0.0 join1.winhundred.com -0.0.0.0 js1.bloggerads.net -0.0.0.0 js77.neodatagroup.com -0.0.0.0 js.adlink.net -0.0.0.0 js.admngr.com -0.0.0.0 js.adscale.de -0.0.0.0 js.adserverpub.com -0.0.0.0 js.adsonar.com -0.0.0.0 jsc.dt07.net -0.0.0.0 js.goods.redtram.com -0.0.0.0 js.himediads.com -0.0.0.0 js.hotkeys.com -0.0.0.0 jsn.dt07.net -0.0.0.0 js.ru.redtram.com -0.0.0.0 js.selectornews.com -0.0.0.0 js.smi2.ru -0.0.0.0 js.tongji.linezing.com -0.0.0.0 js.zevents.com -0.0.0.0 judo.salon.com -0.0.0.0 juggler.inetinteractive.com -0.0.0.0 justwebads.com -0.0.0.0 jxliu.com -0.0.0.0 k5ads.osdn.com -0.0.0.0 kaartenhuis.nl.site-id.nl -0.0.0.0 kansas.valueclick.com -0.0.0.0 katu.adbureau.net -0.0.0.0 kazaa.adserver.co.il -0.0.0.0 kermit.macnn.com -0.0.0.0 kestrel.ospreymedialp.com -0.0.0.0 keys.dmtracker.com -0.0.0.0 keywordblocks.com -0.0.0.0 keywords.adtlgc.com -0.0.0.0 kitaramarketplace.com -0.0.0.0 kitaramedia.com -0.0.0.0 kitaratrk.com -0.0.0.0 kithrup.matchlogic.com -0.0.0.0 kixer.com -0.0.0.0 klikk.linkpulse.com -0.0.0.0 klikmoney.net -0.0.0.0 kliksaya.com -0.0.0.0 klipads.dvlabs.com -0.0.0.0 klipmart.dvlabs.com -0.0.0.0 klipmart.forbes.com -0.0.0.0 kmdl101.com -0.0.0.0 knc.lv -0.0.0.0 knight.economist.com -0.0.0.0 kona2.kontera.com -0.0.0.0 kona3.kontera.com -0.0.0.0 kona4.kontera.com -0.0.0.0 kona5.kontera.com -0.0.0.0 kona6.kontera.com -0.0.0.0 kona7.kontera.com -0.0.0.0 kona8.kontera.com -0.0.0.0 kona.kontera.com -0.0.0.0 kontera.com -0.0.0.0 kreaffiliation.com -0.0.0.0 kropka.onet.pl -0.0.0.0 kuhdi.com -0.0.0.0 l.5min.com -0.0.0.0 ladyclicks.ru -0.0.0.0 lanzar.publicidadweb.com -0.0.0.0 laptopreportcard.com -0.0.0.0 laptoprewards.com -0.0.0.0 laptoprewardsgroup.com -0.0.0.0 laptoprewardszone.com -0.0.0.0 larivieracasino.com -0.0.0.0 lasthr.info -0.0.0.0 lastmeasure.zoy.org -0.0.0.0 launch.adserver.yahoo.com -0.0.0.0 layer-ads.de -0.0.0.0 lb-adserver.ig.com.br -0.0.0.0 ld1.criteo.com -0.0.0.0 ld2.criteo.com -0.0.0.0 ldglob01.adtech.de -0.0.0.0 ldglob01.adtech.fr -0.0.0.0 ldglob01.adtech.us -0.0.0.0 ldglob02.adtech.de -0.0.0.0 ldglob02.adtech.fr -0.0.0.0 ldglob02.adtech.us -0.0.0.0 ldimage01.adtech.de -0.0.0.0 ldimage01.adtech.fr -0.0.0.0 ldimage01.adtech.us -0.0.0.0 ldimage02.adtech.de -0.0.0.0 ldimage02.adtech.fr -0.0.0.0 ldimage02.adtech.us -0.0.0.0 ldserv01.adtech.de -0.0.0.0 ldserv01.adtech.fr -0.0.0.0 ldserv01.adtech.us -0.0.0.0 ldserv02.adtech.de -0.0.0.0 ldserv02.adtech.fr -0.0.0.0 ldserv02.adtech.us -0.0.0.0 le1er.net -0.0.0.0 leadback.advertising.com -0.0.0.0 leader.linkexchange.com -0.0.0.0 lead.program3.com -0.0.0.0 leadsynaptic.go2jump.org -0.0.0.0 learning-offer.com -0.0.0.0 legal-rewardpath.com -0.0.0.0 leisure-offer.com -0.0.0.0 lg.brandreachsys.com -0.0.0.0 liberty.gedads.com -0.0.0.0 link2me.ru -0.0.0.0 link4ads.com -0.0.0.0 linktracker.angelfire.com -0.0.0.0 linuxpark.adtech.de -0.0.0.0 linuxpark.adtech.fr -0.0.0.0 linuxpark.adtech.us -0.0.0.0 liquidad.narrowcastmedia.com -0.0.0.0 live-cams-1.livejasmin.com -0.0.0.0 livingnet.adtech.de -0.0.0.0 ll.atdmt.com -0.0.0.0 l.linkpulse.com -0.0.0.0 lnads.osdn.com -0.0.0.0 load.exelator.com -0.0.0.0 load.focalex.com -0.0.0.0 loading321.com -0.0.0.0 loadm.exelator.com -0.0.0.0 local.promoisland.net -0.0.0.0 logc252.xiti.com -0.0.0.0 log.feedjit.com -0.0.0.0 login.linkpulse.com -0.0.0.0 log.olark.com -0.0.0.0 looksmartcollect.247realmedia.com -0.0.0.0 louisvil.app.ur.gcion.com -0.0.0.0 louisvil.ur.gcion.com -0.0.0.0 lp1.linkpulse.com -0.0.0.0 lp4.linkpulse.com -0.0.0.0 lpcloudsvr405.com -0.0.0.0 lstats.qip.ru -0.0.0.0 lt.andomedia.com -0.0.0.0 lt.angelfire.com -0.0.0.0 lucky-day-uk.com -0.0.0.0 luxup.ru -0.0.0.0 lw1.gamecopyworld.com -0.0.0.0 lw2.gamecopyworld.com -0.0.0.0 lycos.247realmedia.com -0.0.0.0 l.yieldmanager.net -0.0.0.0 m1.emea.2mdn.net.edgesuite.net -0.0.0.0 m2.sexgarantie.nl -0.0.0.0 m3.2mdn.net -0.0.0.0 macaddictads.snv.futurenet.com -0.0.0.0 macads.net -0.0.0.0 mackeeperapp1.zeobit.com -0.0.0.0 mad2.brandreachsys.com -0.0.0.0 m.adbridge.de -0.0.0.0 mads.aol.com -0.0.0.0 mads.cnet.com -0.0.0.0 mail.radar.imgsmail.ru -0.0.0.0 manage001.adtech.de -0.0.0.0 manage001.adtech.fr -0.0.0.0 manage001.adtech.us -0.0.0.0 manager.rovion.com -0.0.0.0 manuel.theonion.com -0.0.0.0 marketgid.com -0.0.0.0 marketing.888.com -0.0.0.0 marketing-rewardpath.com -0.0.0.0 marriottinternationa.tt.omtrdc.net -0.0.0.0 mastertracks.be -0.0.0.0 matomy.adk2.co -0.0.0.0 matrix.mediavantage.de -0.0.0.0 maxadserver.corusradionetwork.com -0.0.0.0 maxads.ruralpress.com -0.0.0.0 maxbounty.com -0.0.0.0 maximumpcads.imaginemedia.com -0.0.0.0 maxmedia.sgaonline.com -0.0.0.0 maxserving.com -0.0.0.0 mb01.com -0.0.0.0 mbox2.offermatica.com -0.0.0.0 mbox9.offermatica.com -0.0.0.0 mds.centrport.net -0.0.0.0 media2021.videostrip.com -0.0.0.0 media2.adshuffle.com -0.0.0.0 media2.legacy.com -0.0.0.0 media2.travelzoo.com -0.0.0.0 media4021.videostrip.com #http://media4021.videostrip.com/dev8/0/000/449/0000449408.mp4 -0.0.0.0 media5021.videostrip.com #http://media5021.videostrip.com/dev14/0/000/363/0000363146.mp4 -0.0.0.0 media6021.videostrip.com -0.0.0.0 media6.sitebrand.com -0.0.0.0 media.888.com -0.0.0.0 media.adcentriconline.com -0.0.0.0 media.adrcdn.com -0.0.0.0 media.adrevolver.com -0.0.0.0 media.adrime.com -0.0.0.0 media.adshadow.net -0.0.0.0 media.b.lead.program3.com -0.0.0.0 media.bonnint.net -0.0.0.0 mediacharger.com -0.0.0.0 media.contextweb.com -0.0.0.0 media.elb-kind.de -0.0.0.0 media.espace-plus.net -0.0.0.0 media.fairlink.ru -0.0.0.0 mediafr.247realmedia.com -0.0.0.0 media.funpic.de -0.0.0.0 medialand.relax.ru -0.0.0.0 media.markethealth.com -0.0.0.0 media.naked.com -0.0.0.0 media.nk-net.pl -0.0.0.0 media.ontarionorth.com -0.0.0.0 media.popuptraffic.com -0.0.0.0 mediapst.adbureau.net -0.0.0.0 mediapst-images.adbureau.net -0.0.0.0 mediative.ca -0.0.0.0 mediative.com -0.0.0.0 media.trafficfactory.biz -0.0.0.0 media.trafficjunky.net -0.0.0.0 mediauk.247realmedia.com -0.0.0.0 media.ventivmedia.com -0.0.0.0 media.viwii.net -0.0.0.0 medical-offer.com -0.0.0.0 medical-rewardpath.com -0.0.0.0 medleyads.com -0.0.0.0 medrx.sensis.com.au -0.0.0.0 megapanel.gem.pl -0.0.0.0 mercury.bravenet.com -0.0.0.0 messagent.duvalguillaume.com -0.0.0.0 messagia.adcentric.proximi-t.com -0.0.0.0 meter-svc.nytimes.com -0.0.0.0 metrics.natmags.co.uk -0.0.0.0 metrics.sfr.fr -0.0.0.0 metrics.target.com -0.0.0.0 m.fr.a2dfp.net -0.0.0.0 m.friendlyduck.com -0.0.0.0 mf.sitescout.com -0.0.0.0 mg.dt00.net -0.0.0.0 mgid.com -0.0.0.0 mhlnk.com -0.0.0.0 mi.adinterax.com -0.0.0.0 microsof.wemfbox.ch -0.0.0.0 mightymagoo.com -0.0.0.0 mii-image.adjuggler.com -0.0.0.0 mini.videostrip.com -0.0.0.0 mirror.pointroll.com -0.0.0.0 mjxads.internet.com -0.0.0.0 mjx.ads.nwsource.com -0.0.0.0 mklik.gazeta.pl -0.0.0.0 mktg-offer.com -0.0.0.0 mlntracker.com -0.0.0.0 mm.admob.com -0.0.0.0 mm.chitika.net -0.0.0.0 mob.adwhirl.com -0.0.0.0 mobileads.msn.com -0.0.0.0 mobile.juicyads.com -0.0.0.0 mobularity.com -0.0.0.0 mochibot.com -0.0.0.0 mojofarm.mediaplex.com -0.0.0.0 moneyraid.com -0.0.0.0 monstersandcritics.advertserve.com -0.0.0.0 morefreecamsecrets.com -0.0.0.0 morevisits.info -0.0.0.0 motd.pinion.gg -0.0.0.0 movieads.imgs.sapo.pt -0.0.0.0 mp3playersource.com -0.0.0.0 mp.tscapeplay.com -0.0.0.0 msn.allyes.com -0.0.0.0 msnbe-hp.metriweb.be -0.0.0.0 msn-cdn.effectivemeasure.net -0.0.0.0 msn.oewabox.at -0.0.0.0 msn.tns-cs.net -0.0.0.0 msn.uvwbox.de -0.0.0.0 msn.wrating.com -0.0.0.0 mt58.mtree.com -0.0.0.0 m.tribalfusion.com -0.0.0.0 mu-in-f167.1e100.net -0.0.0.0 multi.xnxx.com -0.0.0.0 mvonline.com -0.0.0.0 mx.adserver.yahoo.com -0.0.0.0 myao.adocean.pl -0.0.0.0 my.blueadvertise.com -0.0.0.0 mycashback.co.uk -0.0.0.0 mycelloffer.com -0.0.0.0 mychoicerewards.com -0.0.0.0 myexclusiverewards.com -0.0.0.0 myfreedinner.com -0.0.0.0 myfreegifts.co.uk -0.0.0.0 myfreemp3player.com -0.0.0.0 mygiftcardcenter.com -0.0.0.0 mygiftresource.com -0.0.0.0 mygreatrewards.com -0.0.0.0 myoffertracking.com -0.0.0.0 my-reward-channel.com -0.0.0.0 my-rewardsvault.com -0.0.0.0 myseostats.com -0.0.0.0 myusersonline.com -0.0.0.0 myyearbookdigital.checkm8.com -0.0.0.0 n4g.us.intellitxt.com -0.0.0.0 n4p.ru.redtram.com -0.0.0.0 nationalissuepanel.com -0.0.0.0 nationalpost.adperfect.com -0.0.0.0 nationalsurveypanel.com -0.0.0.0 nbads.com -0.0.0.0 nbc.adbureau.net -0.0.0.0 nbimg.dt00.net -0.0.0.0 nb.netbreak.com.au -0.0.0.0 nc.ru.redtram.com -0.0.0.0 nctracking.com -0.0.0.0 nd1.gamecopyworld.com -0.0.0.0 nearbyad.com -0.0.0.0 needadvertising.com -0.0.0.0 netads.hotwired.com -0.0.0.0 netadsrv.iworld.com -0.0.0.0 netads.sohu.com -0.0.0.0 netcomm.spinbox.net -0.0.0.0 netpalnow.com -0.0.0.0 netshelter.adtrix.com -0.0.0.0 netspiderads2.indiatimes.com -0.0.0.0 netsponsors.com -0.0.0.0 networkads.net -0.0.0.0 network-ca.247realmedia.com -0.0.0.0 network.realmedia.com -0.0.0.0 network.realtechnetwork.net -0.0.0.0 newads.cmpnet.com -0.0.0.0 newadserver.interfree.it -0.0.0.0 new-ads.eurogamer.net -0.0.0.0 newbs.hutz.co.il -0.0.0.0 news6health.com -0.0.0.0 newsblock.marketgid.com -0.0.0.0 new.smartcontext.pl -0.0.0.0 newssourceoftoday.com #security risk/fake news# -0.0.0.0 newt1.adultadworld.com -0.0.0.0 newt1.adultworld.com -0.0.0.0 ng3.ads.warnerbros.com -0.0.0.0 ngads.smartage.com -0.0.0.0 nitrous.exitfuel.com -0.0.0.0 nitrous.internetfuel.com -0.0.0.0 nivendas.net -0.0.0.0 nkcache.brandreachsys.com -0.0.0.0 nl.adserver.yahoo.com -0.0.0.0 no.adserver.yahoo.com -0.0.0.0 nospartenaires.com -0.0.0.0 nothing-but-value.com -0.0.0.0 novafinanza.com -0.0.0.0 novem.onet.pl -0.0.0.0 nrads.1host.co.il -0.0.0.0 nrkno.linkpulse.com -0.0.0.0 ns1.lalibco.com -0.0.0.0 ns1.primeinteractive.net -0.0.0.0 ns2.hitbox.com -0.0.0.0 ns2.lalibco.com -0.0.0.0 ns2.primeinteractive.net -0.0.0.0 nsads4.us.publicus.com -0.0.0.0 nsads.hotwired.com -0.0.0.0 nsads.us.publicus.com -0.0.0.0 nspmotion.com -0.0.0.0 ns-vip1.hitbox.com -0.0.0.0 ns-vip2.hitbox.com -0.0.0.0 ns-vip3.hitbox.com -0.0.0.0 ntbanner.digitalriver.com -0.0.0.0 nx-adv0005.247realmedia.com -0.0.0.0 nxs.kidcolez.cn -0.0.0.0 nxtscrn.adbureau.net -0.0.0.0 nysubwayoffer.com -0.0.0.0 nytadvertising.nytimes.com -0.0.0.0 o0.winfuture.de -0.0.0.0 o1.qnsr.com -0.0.0.0 o2.eyereturn.com -0.0.0.0 oads.cracked.com -0.0.0.0 oamsrhads.us.publicus.com -0.0.0.0 oas-1.rmuk.co.uk -0.0.0.0 oasads.whitepages.com -0.0.0.0 oasc02023.247realmedia.com -0.0.0.0 oasc02.247realmedia.com -0.0.0.0 oasc03.247realmedia.com -0.0.0.0 oasc04.247.realmedia.com -0.0.0.0 oasc05050.247realmedia.com -0.0.0.0 oasc05.247realmedia.com -0.0.0.0 oasc16.247realmedia.com -0.0.0.0 oascenral.phoenixnewtimes.com -0.0.0.0 oascentral.videodome.com -0.0.0.0 oas.dn.se -0.0.0.0 oas-eu.247realmedia.com -0.0.0.0 oas.heise.de -0.0.0.0 oasis2.advfn.com -0.0.0.0 oasis.411affiliates.ca -0.0.0.0 oasis.nysun.com -0.0.0.0 oasis.promon.cz -0.0.0.0 oasis.realbeer.com -0.0.0.0 oasis.zmh.zope.com -0.0.0.0 oasis.zmh.zope.net -0.0.0.0 oasn03.247realmedia.com -0.0.0.0 oassis.zmh.zope.com -0.0.0.0 objects.abcvisiteurs.com -0.0.0.0 objects.designbloxlive.com -0.0.0.0 obozua.adocean.pl -0.0.0.0 observer.advertserve.com -0.0.0.0 obs.nnm2.ru -0.0.0.0 offers.impower.com -0.0.0.0 offerx.co.uk -0.0.0.0 oinadserve.com -0.0.0.0 old-darkroast.adknowledge.com -0.0.0.0 ometrics.warnerbros.com -0.0.0.0 onclickads.net -0.0.0.0 online1.webcams.com -0.0.0.0 onlineads.magicvalley.com -0.0.0.0 onlinebestoffers.net -0.0.0.0 onocollect.247realmedia.com -0.0.0.0 open.4info.net -0.0.0.0 openadext.tf1.fr -0.0.0.0 openad.infobel.com -0.0.0.0 openads.dimcab.com -0.0.0.0 openads.friendfinder.com -0.0.0.0 openads.nightlifemagazine.ca -0.0.0.0 openads.smithmag.net -0.0.0.0 openads.zeads.com -0.0.0.0 openad.travelnow.com -0.0.0.0 opentable.tt.omtrdc.net -0.0.0.0 openx2.fotoflexer.com -0.0.0.0 openx.adfactor.nl -0.0.0.0 openx.coolconcepts.nl -0.0.0.0 openx.shinyads.com -0.0.0.0 openxxx.viragemedia.com -0.0.0.0 optimized-by.rubiconproject.com -0.0.0.0 optimized.by.vitalads.net -0.0.0.0 optimize.indieclick.com -0.0.0.0 optimzedby.rmxads.com -0.0.0.0 orange.weborama.fr -0.0.0.0 ordie.adbureau.net -0.0.0.0 origin.chron.com -0.0.0.0 out.popads.net -0.0.0.0 overflow.adsoftware.com -0.0.0.0 overlay.ringtonematcher.com -0.0.0.0 overstock.tt.omtrdc.net -0.0.0.0 ox-d.hbr.org -0.0.0.0 ox-d.hulkshare.com -0.0.0.0 ox-d.hypeads.org -0.0.0.0 ox-d.zenoviagroup.com -0.0.0.0 ox.eurogamer.net -0.0.0.0 ox-i.zenoviagroup.com -0.0.0.0 ozonemedia.adbureau.net -0.0.0.0 oz.valueclick.com -0.0.0.0 oz.valueclick.ne.jp -0.0.0.0 p0rnuha.com -0.0.0.0 p1.adhitzads.com -0.0.0.0 pagead1.googlesyndication.com -0.0.0.0 pagead2.googlesyndication.com -0.0.0.0 pagead3.googlesyndication.com -0.0.0.0 pagead.googlesyndication.com -0.0.0.0 pages.etology.com -0.0.0.0 paime.com -0.0.0.0 panel.adtify.pl -0.0.0.0 paperg.com -0.0.0.0 partner01.oingo.com -0.0.0.0 partner02.oingo.com -0.0.0.0 partner03.oingo.com -0.0.0.0 partner.ah-ha.com -0.0.0.0 partner.ceneo.pl -0.0.0.0 partner.join.com.ua -0.0.0.0 partner.magna.ru -0.0.0.0 partner.pobieraczek.pl -0.0.0.0 partners.sprintrade.com -0.0.0.0 partners.webmasterplan.com -0.0.0.0 partner.wapacz.pl -0.0.0.0 partner.wapster.pl -0.0.0.0 pathforpoints.com -0.0.0.0 paulsnetwork.com -0.0.0.0 pbid.pro-market.net -0.0.0.0 pb.tynt.com -0.0.0.0 pcads.ru -0.0.0.0 pei-ads.playboy.com -0.0.0.0 people-choice-sites.com -0.0.0.0 personalcare-offer.com -0.0.0.0 personalcashbailout.com -0.0.0.0 pg2.solution.weborama.fr -0.0.0.0 ph-ad01.focalink.com -0.0.0.0 ph-ad02.focalink.com -0.0.0.0 ph-ad03.focalink.com -0.0.0.0 ph-ad04.focalink.com -0.0.0.0 ph-ad05.focalink.com -0.0.0.0 ph-ad06.focalink.com -0.0.0.0 ph-ad07.focalink.com -0.0.0.0 ph-ad08.focalink.com -0.0.0.0 ph-ad09.focalink.com -0.0.0.0 ph-ad10.focalink.com -0.0.0.0 ph-ad11.focalink.com -0.0.0.0 ph-ad12.focalink.com -0.0.0.0 ph-ad13.focalink.com -0.0.0.0 ph-ad14.focalink.com -0.0.0.0 ph-ad15.focalink.com -0.0.0.0 ph-ad16.focalink.com -0.0.0.0 ph-ad17.focalink.com -0.0.0.0 ph-ad18.focalink.com -0.0.0.0 ph-ad19.focalink.com -0.0.0.0 ph-ad20.focalink.com -0.0.0.0 ph-ad21.focalink.com -0.0.0.0 ph-cdn.effectivemeasure.net -0.0.0.0 phoenixads.co.in -0.0.0.0 photobucket.adnxs.com -0.0.0.0 photos0.pop6.com -0.0.0.0 photos1.pop6.com -0.0.0.0 photos2.pop6.com -0.0.0.0 photos3.pop6.com -0.0.0.0 photos4.pop6.com -0.0.0.0 photos5.pop6.com -0.0.0.0 photos6.pop6.com -0.0.0.0 photos7.pop6.com -0.0.0.0 photos8.pop6.com -0.0.0.0 photos.daily-deals.analoganalytics.com -0.0.0.0 photos.pop6.com -0.0.0.0 phpads.astalavista.us -0.0.0.0 phpads.cnpapers.com -0.0.0.0 phpads.flipcorp.com -0.0.0.0 phpads.foundrymusic.com -0.0.0.0 phpads.i-merge.net -0.0.0.0 phpads.macbidouille.com -0.0.0.0 phpadsnew.gamefolk.de -0.0.0.0 phpadsnew.wn.com -0.0.0.0 php.fark.com -0.0.0.0 pick-savings.com -0.0.0.0 p.ic.tynt.com -0.0.0.0 pink.habralab.ru -0.0.0.0 pix01.revsci.net -0.0.0.0 pix521.adtech.de -0.0.0.0 pix521.adtech.fr -0.0.0.0 pix521.adtech.us -0.0.0.0 pix522.adtech.de -0.0.0.0 pix522.adtech.fr -0.0.0.0 pix522.adtech.us -0.0.0.0 pixel.everesttech.net -0.0.0.0 pixel.mathtag.com -0.0.0.0 pixel.quantserve.com -0.0.0.0 pixel.sitescout.com -0.0.0.0 plasmatv4free.com -0.0.0.0 plasmatvreward.com -0.0.0.0 playlink.pl -0.0.0.0 playtime.tubemogul.com -0.0.0.0 pl.bbelements.com -0.0.0.0 pmstrk.mercadolivre.com.br -0.0.0.0 pntm.adbureau.net -0.0.0.0 pntm-images.adbureau.net -0.0.0.0 pol.bbelements.com -0.0.0.0 politicalopinionsurvey.com -0.0.0.0 pool.pebblemedia.adhese.com -0.0.0.0 popadscdn.net -0.0.0.0 popclick.net -0.0.0.0 poponclick.com -0.0.0.0 popunder.adsrevenue.net -0.0.0.0 popunder.paypopup.com -0.0.0.0 popupclick.ru -0.0.0.0 popupdomination.com -0.0.0.0 popup.matchmaker.com -0.0.0.0 popups.ad-logics.com -0.0.0.0 popups.infostart.com -0.0.0.0 postmasterdirect.com -0.0.0.0 post.rmbn.ru -0.0.0.0 pp.free.fr -0.0.0.0 p.profistats.net -0.0.0.0 p.publico.es -0.0.0.0 premium.ascensionweb.com -0.0.0.0 premiumholidayoffers.com -0.0.0.0 premiumproductsonline.com -0.0.0.0 premium-reward-club.com -0.0.0.0 prexyone.appspot.com -0.0.0.0 primetime.ad.primetime.net -0.0.0.0 privitize.com -0.0.0.0 prizes.co.uk -0.0.0.0 productopinionpanel.com -0.0.0.0 productresearchpanel.com -0.0.0.0 producttestpanel.com -0.0.0.0 profile.uproxx.com -0.0.0.0 promo.awempire.com -0.0.0.0 promo.easy-dating.org -0.0.0.0 promos.fling.com -0.0.0.0 promote-bz.net -0.0.0.0 promotion.partnercash.com -0.0.0.0 proximityads.flipcorp.com -0.0.0.0 proxy.blogads.com -0.0.0.0 ptrads.mp3.com -0.0.0.0 pubdirecte.com -0.0.0.0 pubimgs.sapo.pt -0.0.0.0 publiads.com -0.0.0.0 publicidades.redtotalonline.com -0.0.0.0 publicis.adcentriconline.com -0.0.0.0 publish.bonzaii.no -0.0.0.0 publishers.adscholar.com -0.0.0.0 publishers.bidtraffic.com -0.0.0.0 publishers.brokertraffic.com -0.0.0.0 publishing.kalooga.com -0.0.0.0 pub.sapo.pt -0.0.0.0 pubshop.img.uol.com.br -0.0.0.0 purgecolon.net -0.0.0.0 px10.net -0.0.0.0 q.azcentral.com -0.0.0.0 q.b.h.cltomedia.info -0.0.0.0 qip.magna.ru -0.0.0.0 qitrck.com -0.0.0.0 quickbrowsersearch.com -0.0.0.0 r1-ads.ace.advertising.com -0.0.0.0 r.ace.advertising.com -0.0.0.0 radaronline.advertserve.com -0.0.0.0 r.admob.com -0.0.0.0 rad.msn.com -0.0.0.0 rads.stackoverflow.com -0.0.0.0 ravel-rewardpath.com -0.0.0.0 rb.burstway.com -0.0.0.0 rb.newsru.com -0.0.0.0 rbqip.pochta.ru -0.0.0.0 rc.asci.freenet.de -0.0.0.0 rc.bt.ilsemedia.nl -0.0.0.0 rccl.bridgetrack.com -0.0.0.0 rcdna.gwallet.com -0.0.0.0 r.chitika.net -0.0.0.0 rc.hotkeys.com -0.0.0.0 rcm-images.amazon.com -0.0.0.0 rcm-it.amazon.it -0.0.0.0 rc.rlcdn.com -0.0.0.0 rc.wl.webads.nl -0.0.0.0 realads.realmedia.com -0.0.0.0 realgfsbucks.com -0.0.0.0 realmedia-a800.d4p.net # Scientific American -0.0.0.0 realmedia.advance.net -0.0.0.0 recreation-leisure-rewardpath.com -0.0.0.0 red01.as-eu.falkag.net -0.0.0.0 red01.as-us.falkag.net -0.0.0.0 red02.as-eu.falkag.net -0.0.0.0 red02.as-us.falkag.net -0.0.0.0 red03.as-eu.falkag.net -0.0.0.0 red03.as-us.falkag.net -0.0.0.0 red04.as-eu.falkag.net -0.0.0.0 red04.as-us.falkag.net -0.0.0.0 red.as-eu.falkag.net -0.0.0.0 red.as-us.falkag.net -0.0.0.0 redherring.ngadcenter.net -0.0.0.0 redirect.click2net.com -0.0.0.0 redirect.hotkeys.com -0.0.0.0 reduxads.valuead.com -0.0.0.0 reg.coolsavings.com -0.0.0.0 regflow.com -0.0.0.0 regie.espace-plus.net -0.0.0.0 regio.adlink.de -0.0.0.0 reklama.onet.pl -0.0.0.0 reklamy.sfd.pl -0.0.0.0 re.kontera.com -0.0.0.0 rek.www.wp.pl -0.0.0.0 relestar.com -0.0.0.0 remotead.cnet.com -0.0.0.0 report02.adtech.de -0.0.0.0 report02.adtech.fr -0.0.0.0 report02.adtech.us -0.0.0.0 reporter001.adtech.de -0.0.0.0 reporter001.adtech.fr -0.0.0.0 reporter001.adtech.us -0.0.0.0 reporter.adtech.de -0.0.0.0 reporter.adtech.fr -0.0.0.0 reporter.adtech.us -0.0.0.0 reportimage.adtech.de -0.0.0.0 reportimage.adtech.fr -0.0.0.0 reportimage.adtech.us -0.0.0.0 resolvingserver.com -0.0.0.0 resources.infolinks.com -0.0.0.0 restaurantcom.tt.omtrdc.net -0.0.0.0 reverso.refr.adgtw.orangeads.fr -0.0.0.0 revsci.net -0.0.0.0 rewardblvd.com -0.0.0.0 rewardhotspot.com -0.0.0.0 rewardsflow.com -0.0.0.0 rhads.sv.publicus.com -0.0.0.0 rh.revolvermaps.com -0.0.0.0 richmedia.yimg.com -0.0.0.0 ridepush.com -0.0.0.0 ringtonepartner.com -0.0.0.0 rmbn.ru -0.0.0.0 rmedia.boston.com -0.0.0.0 rmm1u.checkm8.com -0.0.0.0 rms.admeta.com -0.0.0.0 ro.bbelements.com -0.0.0.0 romepartners.com -0.0.0.0 roosevelt.gjbig.com -0.0.0.0 rosettastone.tt.omtrdc.net -0.0.0.0 rotabanner100.utro.ru -0.0.0.0 rotabanner468.utro.ru -0.0.0.0 rotate.infowars.com -0.0.0.0 rotator.adjuggler.com -0.0.0.0 rotator.juggler.inetinteractive.com -0.0.0.0 rotobanner468.utro.ru -0.0.0.0 rovion.com -0.0.0.0 rpc.trafficfactory.biz -0.0.0.0 rp.hit.gemius.pl -0.0.0.0 r.reklama.biz -0.0.0.0 rscounter10.com -0.0.0.0 rsense-ad.realclick.co.kr -0.0.0.0 rss.buysellads.com -0.0.0.0 rt2.infolinks.com -0.0.0.0 rt3.infolinks.com -0.0.0.0 rtb.pclick.yahoo.com -0.0.0.0 rtb.tubemogul.com -0.0.0.0 rtr.innovid.com -0.0.0.0 rts.sparkstudios.com -0.0.0.0 r.turn.com -0.0.0.0 ru.bbelements.com -0.0.0.0 ru.redtram.com -0.0.0.0 russ-shalavy.ru -0.0.0.0 rv.adcpx.v1.de.eusem.adaos-ads.net -0.0.0.0 rya.rockyou.com -0.0.0.0 s0b.bluestreak.com -0.0.0.0 s1.buysellads.com -0.0.0.0 s1.cz.adocean.pl -0.0.0.0 s1.gratkapl.adocean.pl -0.0.0.0 s2.buysellads.com -0.0.0.0 s3.buysellads.com -0.0.0.0 s5.addthis.com -0.0.0.0 s7.addthis.com -0.0.0.0 s.admulti.com -0.0.0.0 sad.sharethis.com -0.0.0.0 safe.hyperpaysys.com -0.0.0.0 safenyplanet.in -0.0.0.0 salesforcecom.tt.omtrdc.net -0.0.0.0 s.amazon-adsystem.com -0.0.0.0 samsung3.solution.weborama.fr -0.0.0.0 s.as-us.falkag.net -0.0.0.0 sat-city-ads.com -0.0.0.0 s.atemda.com -0.0.0.0 saturn.tiser.com.au -0.0.0.0 save-plan.com -0.0.0.0 savings-specials.com -0.0.0.0 savings-time.com -0.0.0.0 s.boom.ro -0.0.0.0 schoorsteen.geenstijl.nl -0.0.0.0 schumacher.adtech.de -0.0.0.0 schumacher.adtech.fr -0.0.0.0 schumacher.adtech.us -0.0.0.0 schwab.tt.omtrdc.net -0.0.0.0 s.clicktale.net -0.0.0.0 scoremygift.com -0.0.0.0 screen-mates.com -0.0.0.0 script.banstex.com -0.0.0.0 script.crsspxl.com -0.0.0.0 scripts.verticalacuity.com -0.0.0.0 scr.kliksaya.com -0.0.0.0 s.di.com.pl -0.0.0.0 se.adserver.yahoo.com -0.0.0.0 search.addthis.com -0.0.0.0 search.freeonline.com -0.0.0.0 search.keywordblocks.com -0.0.0.0 search.netseer.com -0.0.0.0 searchportal.information.com -0.0.0.0 searchwe.com -0.0.0.0 seasonalsamplerspecials.com -0.0.0.0 sec.hit.gemius.pl -0.0.0.0 secimage.adtech.de -0.0.0.0 secimage.adtech.fr -0.0.0.0 secimage.adtech.us -0.0.0.0 secserv.adtech.de -0.0.0.0 secserv.adtech.fr -0.0.0.0 secserv.adtech.us -0.0.0.0 secure.ace-tag.advertising.com -0.0.0.0 secure.addthis.com -0.0.0.0 secureads.ft.com -0.0.0.0 secure.bidvertiserr.com -0.0.0.0 securecontactinfo.com -0.0.0.0 secure.gaug.es -0.0.0.0 secure.img-cdn.mediaplex.com -0.0.0.0 securerunner.com -0.0.0.0 secure.webconnect.net -0.0.0.0 seduction-zone.com -0.0.0.0 sel.as-eu.falkag.net -0.0.0.0 sel.as-us.falkag.net -0.0.0.0 select001.adtech.de -0.0.0.0 select001.adtech.fr -0.0.0.0 select001.adtech.us -0.0.0.0 select002.adtech.de -0.0.0.0 select002.adtech.fr -0.0.0.0 select002.adtech.us -0.0.0.0 select003.adtech.de -0.0.0.0 select003.adtech.fr -0.0.0.0 select003.adtech.us -0.0.0.0 select004.adtech.de -0.0.0.0 select004.adtech.fr -0.0.0.0 select004.adtech.us -0.0.0.0 sergarius.popunder.ru -0.0.0.0 serv2.ad-rotator.com -0.0.0.0 serv.ad-rotator.com -0.0.0.0 servads.aip.org -0.0.0.0 serv.adspeed.com -0.0.0.0 servedbyadbutler.com -0.0.0.0 servedby.adcombination.com -0.0.0.0 servedby.advertising.com -0.0.0.0 servedby.flashtalking.com -0.0.0.0 servedby.netshelter.net -0.0.0.0 servedby.precisionclick.com -0.0.0.0 serve.freegaypix.com -0.0.0.0 serve.popads.net -0.0.0.0 serve.prestigecasino.com -0.0.0.0 server01.popupmoney.com -0.0.0.0 server2.as5000.com -0.0.0.0 server2.mediajmp.com -0.0.0.0 server3.yieldmanaged.com -0.0.0.0 server.as5000.com -0.0.0.0 server.bittads.com -0.0.0.0 server.cpmstar.com -0.0.0.0 server.popads.net -0.0.0.0 server-ssl.yieldmanaged.com -0.0.0.0 service001.adtech.de -0.0.0.0 service001.adtech.fr -0.0.0.0 service001.adtech.us -0.0.0.0 service002.adtech.de -0.0.0.0 service002.adtech.fr -0.0.0.0 service002.adtech.us -0.0.0.0 service003.adtech.de -0.0.0.0 service003.adtech.fr -0.0.0.0 service003.adtech.us -0.0.0.0 service004.adtech.fr -0.0.0.0 service004.adtech.us -0.0.0.0 service00x.adtech.de -0.0.0.0 service00x.adtech.fr -0.0.0.0 service00x.adtech.us -0.0.0.0 service.adtech.de -0.0.0.0 service.adtech.fr -0.0.0.0 service.adtech.us -0.0.0.0 services1.adtech.de -0.0.0.0 services1.adtech.fr -0.0.0.0 services1.adtech.us -0.0.0.0 services.adtech.de -0.0.0.0 services.adtech.fr -0.0.0.0 services.adtech.us -0.0.0.0 serving.plexop.net -0.0.0.0 sexpartnerx.com -0.0.0.0 sexsponsors.com -0.0.0.0 sexzavod.com -0.0.0.0 sfads.osdn.com -0.0.0.0 s.flite.com -0.0.0.0 sg.adserver.yahoo.com -0.0.0.0 sgs001.adtech.de -0.0.0.0 sgs001.adtech.fr -0.0.0.0 sgs001.adtech.us -0.0.0.0 sh4sure-images.adbureau.net -0.0.0.0 shareasale.com -0.0.0.0 sharebar.addthiscdn.com -0.0.0.0 share-server.com -0.0.0.0 shc-rebates.com -0.0.0.0 shinystat.shiny.it -0.0.0.0 shopperpromotions.com -0.0.0.0 shopping-offer.com -0.0.0.0 shoppingsiterewards.com -0.0.0.0 shops-malls-rewardpath.com -0.0.0.0 shoptosaveenergy.com -0.0.0.0 showads1000.pubmatic.com -0.0.0.0 showadsak.pubmatic.com -0.0.0.0 sifomedia.citypaketet.se -0.0.0.0 signup.advance.net -0.0.0.0 si.hit.gemius.pl -0.0.0.0 simg.zedo.com -0.0.0.0 simpleads.net -0.0.0.0 simpli.fi -0.0.0.0 s.innovid.com -0.0.0.0 sixapart.adbureau.net -0.0.0.0 sizzle-savings.com -0.0.0.0 skgde.adocean.pl -0.0.0.0 skill.skilljam.com -0.0.0.0 slider.plugrush.com -0.0.0.0 smartadserver -0.0.0.0 smartadserver.com -0.0.0.0 smart.besonders.ru -0.0.0.0 smartclip.com -0.0.0.0 smartclip.net -0.0.0.0 smartcontext.pl -0.0.0.0 smartinit.webads.nl -0.0.0.0 smart-scripts.com -0.0.0.0 smartshare.lgtvsdp.com -0.0.0.0 s.media-imdb.com -0.0.0.0 s.megaclick.com -0.0.0.0 smile.modchipstore.com -0.0.0.0 smm.sitescout.com -0.0.0.0 s.moatads.com -0.0.0.0 smokersopinionpoll.com -0.0.0.0 smsmovies.net -0.0.0.0 snaps.vidiemi.com -0.0.0.0 sn.baventures.com -0.0.0.0 snip.answers.com -0.0.0.0 snipjs.answcdn.com -0.0.0.0 sochr.com -0.0.0.0 social.bidsystem.com -0.0.0.0 softlinkers.popunder.ru -0.0.0.0 sokrates.adtech.de -0.0.0.0 sokrates.adtech.fr -0.0.0.0 sokrates.adtech.us -0.0.0.0 sol.adbureau.net -0.0.0.0 sol-images.adbureau.net -0.0.0.0 solitairetime.com -0.0.0.0 solution.weborama.fr -0.0.0.0 somethingawful.crwdcntrl.net -0.0.0.0 sonycomputerentertai.tt.omtrdc.net -0.0.0.0 soongu.info -0.0.0.0 spanids.dictionary.com -0.0.0.0 spanids.thesaurus.com -0.0.0.0 spc.cekfmeoejdbfcfichgbfcgjf.vast2as3.glammedia-pubnet.northamerica.telemetryverification.net -0.0.0.0 spe.atdmt.com -0.0.0.0 specialgiftrewards.com -0.0.0.0 specialoffers.aol.com -0.0.0.0 specialonlinegifts.com -0.0.0.0 specials-rewardpath.com -0.0.0.0 speedboink.com -0.0.0.0 speedclicks.ero-advertising.com -0.0.0.0 speed.pointroll.com # Microsoft -0.0.0.0 spinbox.com -0.0.0.0 spinbox.consumerreview.com -0.0.0.0 spinbox.freedom.com -0.0.0.0 spinbox.macworld.com -0.0.0.0 spinbox.techtracker.com -0.0.0.0 spin.spinbox.net -0.0.0.0 sponsor1.com -0.0.0.0 sponsors.behance.com -0.0.0.0 sponsors.ezgreen.com -0.0.0.0 sponsorships.net -0.0.0.0 sports-bonuspath.com -0.0.0.0 sports-fitness-rewardpath.com -0.0.0.0 sports-offer.com -0.0.0.0 sports-offer.net -0.0.0.0 sports-premiumblvd.com -0.0.0.0 spotxchange.com -0.0.0.0 s.ppjol.net -0.0.0.0 sq2trk2.com -0.0.0.0 srs.targetpoint.com -0.0.0.0 srv.juiceadv.com -0.0.0.0 ssads.osdn.com -0.0.0.0 s.skimresources.com -0.0.0.0 sso.canada.com -0.0.0.0 staging.snip.answers.com -0.0.0.0 stampen.adtlgc.com -0.0.0.0 stampen.linkpulse.com -0.0.0.0 stampscom.tt.omtrdc.net -0.0.0.0 stanzapub.advertserve.com -0.0.0.0 star-advertising.com -0.0.0.0 stat.blogads.com -0.0.0.0 stat.dealtime.com -0.0.0.0 stat.ebuzzing.com -0.0.0.0 static1.influads.com -0.0.0.0 static.2mdn.net -0.0.0.0 static.admaximize.com -0.0.0.0 staticads.btopenworld.com -0.0.0.0 static.adsonar.com -0.0.0.0 static.adtaily.pl -0.0.0.0 static.adzerk.net -0.0.0.0 static.aff-landing-tmp.foxtab.com -0.0.0.0 staticb.mydirtyhobby.com -0.0.0.0 static.carbonads.com -0.0.0.0 static.clicktorrent.info -0.0.0.0 static.creatives.livejasmin.com -0.0.0.0 static.doubleclick.net -0.0.0.0 static.everyone.net -0.0.0.0 static.exoclick.com -0.0.0.0 static.fastpic.ru -0.0.0.0 static.firehunt.com -0.0.0.0 static.fmpub.net -0.0.0.0 static.freenet.de -0.0.0.0 static.groupy.co.nz -0.0.0.0 static.hitfarm.com -0.0.0.0 static.ifa.camads.net -0.0.0.0 static.l3.cdn.adbucks.com -0.0.0.0 static.l3.cdn.adsucks.com -0.0.0.0 static.plista.com -0.0.0.0 static.plugrush.com -0.0.0.0 static.pulse360.com -0.0.0.0 static.scanscout.com -0.0.0.0 static.vpptechnologies.com -0.0.0.0 static.way2traffic.com -0.0.0.0 statistik-gallup.dk -0.0.0.0 stats2.dooyoo.com -0.0.0.0 stats.askmoses.com -0.0.0.0 stats.buzzparadise.com -0.0.0.0 stats.jtvnw.net -0.0.0.0 stats.shopify.com -0.0.0.0 status.addthis.com -0.0.0.0 st.blogads.com -0.0.0.0 s.tcimg.com -0.0.0.0 st.marketgid.com -0.0.0.0 stocker.bonnint.net -0.0.0.0 storage.softure.com -0.0.0.0 storage.trafic.ro -0.0.0.0 streamate.com -0.0.0.0 stts.rbc.ru -0.0.0.0 st.valueclick.com -0.0.0.0 su.addthis.com -0.0.0.0 subtracts.userplane.com -0.0.0.0 sudokuwhiz.com -0.0.0.0 sunmaker.com -0.0.0.0 superbrewards.com -0.0.0.0 support.sweepstakes.com -0.0.0.0 supremeadsonline.com -0.0.0.0 suresafe1.adsovo.com -0.0.0.0 surplus-suppliers.com -0.0.0.0 surveycentral.directinsure.info -0.0.0.0 surveymonkeycom.tt.omtrdc.net -0.0.0.0 surveypass.com -0.0.0.0 susi.adtech.fr -0.0.0.0 susi.adtech.us -0.0.0.0 svd2.adtlgc.com -0.0.0.0 svd.adtlgc.com -0.0.0.0 sview.avenuea.com -0.0.0.0 sweetsforfree.com -0.0.0.0 symbiosting.com -0.0.0.0 synad2.nuffnang.com.cn -0.0.0.0 synad.nuffnang.com.sg -0.0.0.0 syncaccess.net -0.0.0.0 sync.mathtag.com -0.0.0.0 syndicated.mondominishows.com -0.0.0.0 syndication.exoclick.com -0.0.0.0 syndication.traffichaus.com -0.0.0.0 syn.verticalacuity.com -0.0.0.0 sysadmin.map24.com -0.0.0.0 t1.adserver.com -0.0.0.0 t4.liverail.com -0.0.0.0 t-ads.adap.tv -0.0.0.0 tag1.webabacus.com -0.0.0.0 tag.admeld.com -0.0.0.0 tag.contextweb.com -0.0.0.0 tag.regieci.com -0.0.0.0 tags.bluekai.com -0.0.0.0 tags.hypeads.org -0.0.0.0 tag.webcompteur.com -0.0.0.0 tag.yieldoptimizer.com -0.0.0.0 taloussanomat.linkpulse.com -0.0.0.0 tap2-cdn.rubiconproject.com -0.0.0.0 tbtrack.zutrack.com -0.0.0.0 tcadops.ca -0.0.0.0 tcimg.com -0.0.0.0 t.cpmadvisors.com -0.0.0.0 tdameritrade.tt.omtrdc.net -0.0.0.0 tdc.advertorials.dk -0.0.0.0 tdkads.ads.dk -0.0.0.0 techreview.adbureau.net -0.0.0.0 techreview-images.adbureau.net -0.0.0.0 teeser.ru -0.0.0.0 te.kontera.com -0.0.0.0 tel.geenstijl.nl -0.0.0.0 textads.madisonavenue.com -0.0.0.0 textad.traficdublu.ro -0.0.0.0 text-link-ads.com -0.0.0.0 text-link-ads.ientry.com -0.0.0.0 text-link-ads-inventory.com -0.0.0.0 textsrv.com -0.0.0.0 tf.nexac.com -0.0.0.0 tgpmanager.com -0.0.0.0 the-binary-trader.biz -0.0.0.0 the-path-gateway.com -0.0.0.0 thepiratetrader.com -0.0.0.0 the-smart-stop.com -0.0.0.0 theuploadbusiness.com -0.0.0.0 theuseful.com -0.0.0.0 theuseful.net -0.0.0.0 thinknyc.eu-adcenter.net -0.0.0.0 thinktarget.com -0.0.0.0 thinlaptoprewards.com -0.0.0.0 this.content.served.by.adshuffle.com -0.0.0.0 thoughtfully-free.com -0.0.0.0 thruport.com -0.0.0.0 tmp3.nexac.com -0.0.0.0 tmsads.tribune.com -0.0.0.0 tmx.technoratimedia.com -0.0.0.0 tn.adserve.com -0.0.0.0 toads.osdn.com -0.0.0.0 tons-to-see.com -0.0.0.0 toolbar.adperium.com -0.0.0.0 top100-images.rambler.ru -0.0.0.0 top1site.3host.com -0.0.0.0 top5.mail.ru -0.0.0.0 topbrandrewards.com -0.0.0.0 topconsumergifts.com -0.0.0.0 topdemaroc.com -0.0.0.0 topica.advertserve.com -0.0.0.0 top.list.ru -0.0.0.0 toplist.throughput.de -0.0.0.0 topmarketcenter.com -0.0.0.0 touche.adcentric.proximi-t.com -0.0.0.0 tower.adexpedia.com -0.0.0.0 toy-offer.com -0.0.0.0 toy-offer.net -0.0.0.0 tpads.ovguide.com -0.0.0.0 tpc.googlesyndication.com -0.0.0.0 tps30.doubleverify.com -0.0.0.0 tps31.doubleverify.com -0.0.0.0 track.adbooth.net -0.0.0.0 trackadvertising.net -0.0.0.0 track-apmebf.cj.akadns.net -0.0.0.0 track.bigbrandpromotions.com -0.0.0.0 track.e7r.com.br -0.0.0.0 trackers.1st-affiliation.fr -0.0.0.0 tracking.craktraffic.com -0.0.0.0 tracking.edvisors.com -0.0.0.0 tracking.eurowebaffiliates.com -0.0.0.0 tracking.joker.com -0.0.0.0 tracking.keywordmax.com -0.0.0.0 tracking.veoxa.com -0.0.0.0 track.omgpl.com -0.0.0.0 track.the-members-section.com -0.0.0.0 track.vscash.com -0.0.0.0 tradearabia.advertserve.com -0.0.0.0 tradefx.advertserve.com -0.0.0.0 trafficbee.com -0.0.0.0 trafficrevenue.net -0.0.0.0 traffictraders.com -0.0.0.0 traffprofit.com -0.0.0.0 trafmag.com -0.0.0.0 trafsearchonline.com -0.0.0.0 traktum.com -0.0.0.0 travel-leisure-bonuspath.com -0.0.0.0 travel-leisure-premiumblvd.com -0.0.0.0 traveller-offer.com -0.0.0.0 traveller-offer.net -0.0.0.0 travelncs.com -0.0.0.0 trekmedia.net -0.0.0.0 trendnews.com -0.0.0.0 trk.alskeip.com -0.0.0.0 trk.etrigue.com -0.0.0.0 trk.yadomedia.com -0.0.0.0 trustsitesite.com -0.0.0.0 trvlnet.adbureau.net -0.0.0.0 trvlnet-images.adbureau.net -0.0.0.0 tr.wl.webads.nl -0.0.0.0 tsms-ad.tsms.com -0.0.0.0 tste.ivillage.com -0.0.0.0 tste.mcclatchyinteractive.com -0.0.0.0 tste.startribune.com -0.0.0.0 ttarget.adbureau.net -0.0.0.0 ttuk.offers4u.mobi -0.0.0.0 turnerapac.d1.sc.omtrdc.net -0.0.0.0 tv2no.linkpulse.com -0.0.0.0 tvshowsnow.tvmax.hop.clickbank.net -0.0.0.0 tw.adserver.yahoo.com -0.0.0.0 twnads.weather.ca # Canadian Weather Network -0.0.0.0 uac.advertising.com -0.0.0.0 u-ads.adap.tv -0.0.0.0 uav.tidaltv.com -0.0.0.0 uc.csc.adserver.yahoo.com -0.0.0.0 uedata.amazon.com -0.0.0.0 uelbdc74fn.s.ad6media.fr -0.0.0.0 uf2.svrni.ca -0.0.0.0 ugo.eu-adcenter.net -0.0.0.0 ui.ppjol.com -0.0.0.0 uk.adserver.yahoo.com -0.0.0.0 uleadstrk.com -0.0.0.0 ultimatefashiongifts.com -0.0.0.0 ultrabestportal.com -0.0.0.0 um.simpli.fi -0.0.0.0 undertonenetworks.com -0.0.0.0 uole.ad.uol.com.br -0.0.0.0 u.openx.net -0.0.0.0 upload.adtech.de -0.0.0.0 upload.adtech.fr -0.0.0.0 upload.adtech.us -0.0.0.0 uproar.com -0.0.0.0 uproar.fortunecity.com -0.0.0.0 upsellit.com -0.0.0.0 us.adserver.yahoo.com -0.0.0.0 usads.vibrantmedia.com -0.0.0.0 usatoday.app.ur.gcion.com -0.0.0.0 usatravel-specials.com -0.0.0.0 usatravel-specials.net -0.0.0.0 us-choicevalue.com -0.0.0.0 usemax.de -0.0.0.0 usr.marketgid.com -0.0.0.0 us-topsites.com -0.0.0.0 ut.addthis.com -0.0.0.0 utarget.ru -0.0.0.0 utils.media-general.com -0.0.0.0 utils.mediageneral.com -0.0.0.0 vad.adbasket.net -0.0.0.0 vads.adbrite.com -0.0.0.0 van.ads.link4ads.com -0.0.0.0 vast.bp3845260.btrll.com -0.0.0.0 vast.bp3846806.btrll.com -0.0.0.0 vast.bp3846885.btrll.com -0.0.0.0 vast.tubemogul.com -0.0.0.0 vclick.adbrite.com -0.0.0.0 venus.goclick.com -0.0.0.0 ve.tscapeplay.com -0.0.0.0 v.fwmrm.net -0.0.0.0 vibrantmedia.com -0.0.0.0 videocop.com -0.0.0.0 videoegg.adbureau.net -0.0.0.0 video-game-rewards-central.com -0.0.0.0 videogamerewardscentral.com -0.0.0.0 videos.fleshlight.com -0.0.0.0 videoslots.888.com -0.0.0.0 videos.video-loader.com -0.0.0.0 view.atdmt.com #This may interfere with downloading from Microsoft, MSDN and TechNet websites. -0.0.0.0 view.avenuea.com -0.0.0.0 view.binlayer.com -0.0.0.0 view.iballs.a1.avenuea.com -0.0.0.0 view.jamba.de -0.0.0.0 view.netrams.com -0.0.0.0 views.m4n.nl -0.0.0.0 viglink.com -0.0.0.0 viglink.pgpartner.com -0.0.0.0 villagevoicecollect.247realmedia.com -0.0.0.0 vip1.tw.adserver.yahoo.com -0.0.0.0 vipfastmoney.com -0.0.0.0 vk.18sexporn.ru -0.0.0.0 vmcsatellite.com -0.0.0.0 vmix.adbureau.net -0.0.0.0 vms.boldchat.com -0.0.0.0 vnu.eu-adcenter.net -0.0.0.0 vodafoneit.solution.weborama.fr -0.0.0.0 vp.tscapeplay.com -0.0.0.0 vu.veoxa.com -0.0.0.0 vzarabotke.ru -0.0.0.0 w100.am15.net -0.0.0.0 w10.am15.net -0.0.0.0 w10.centralmediaserver.com -0.0.0.0 w11.am15.net -0.0.0.0 w11.centralmediaserver.com -0.0.0.0 w12.am15.net -0.0.0.0 w13.am15.net -0.0.0.0 w14.am15.net -0.0.0.0 w15.am15.net -0.0.0.0 w16.am15.net -0.0.0.0 w17.am15.net -0.0.0.0 w18.am15.net -0.0.0.0 w19.am15.net -0.0.0.0 w1.am15.net -0.0.0.0 w1.webcompteur.com -0.0.0.0 w20.am15.net -0.0.0.0 w21.am15.net -0.0.0.0 w22.am15.net -0.0.0.0 w23.am15.net -0.0.0.0 w24.am15.net -0.0.0.0 w25.am15.net -0.0.0.0 w26.am15.net -0.0.0.0 w27.am15.net -0.0.0.0 w28.am15.net -0.0.0.0 w29.am15.net -0.0.0.0 w2.am15.net -0.0.0.0 w30.am15.net -0.0.0.0 w31.am15.net -0.0.0.0 w32.am15.net -0.0.0.0 w33.am15.net -0.0.0.0 w34.am15.net -0.0.0.0 w35.am15.net -0.0.0.0 w36.am15.net -0.0.0.0 w37.am15.net -0.0.0.0 w38.am15.net -0.0.0.0 w39.am15.net -0.0.0.0 w3.am15.net -0.0.0.0 w40.am15.net -0.0.0.0 w41.am15.net -0.0.0.0 w42.am15.net -0.0.0.0 w43.am15.net -0.0.0.0 w44.am15.net -0.0.0.0 w45.am15.net -0.0.0.0 w46.am15.net -0.0.0.0 w47.am15.net -0.0.0.0 w48.am15.net -0.0.0.0 w49.am15.net -0.0.0.0 w4.am15.net -0.0.0.0 w50.am15.net -0.0.0.0 w51.am15.net -0.0.0.0 w52.am15.net -0.0.0.0 w53.am15.net -0.0.0.0 w54.am15.net -0.0.0.0 w55.am15.net -0.0.0.0 w56.am15.net -0.0.0.0 w57.am15.net -0.0.0.0 w58.am15.net -0.0.0.0 w59.am15.net -0.0.0.0 w5.am15.net -0.0.0.0 w60.am15.net -0.0.0.0 w61.am15.net -0.0.0.0 w62.am15.net -0.0.0.0 w63.am15.net -0.0.0.0 w64.am15.net -0.0.0.0 w65.am15.net -0.0.0.0 w66.am15.net -0.0.0.0 w67.am15.net -0.0.0.0 w68.am15.net -0.0.0.0 w69.am15.net -0.0.0.0 w6.am15.net -0.0.0.0 w70.am15.net -0.0.0.0 w71.am15.net -0.0.0.0 w72.am15.net -0.0.0.0 w73.am15.net -0.0.0.0 w74.am15.net -0.0.0.0 w75.am15.net -0.0.0.0 w76.am15.net -0.0.0.0 w77.am15.net -0.0.0.0 w78.am15.net -0.0.0.0 w79.am15.net -0.0.0.0 w7.am15.net -0.0.0.0 w80.am15.net -0.0.0.0 w81.am15.net -0.0.0.0 w82.am15.net -0.0.0.0 w83.am15.net -0.0.0.0 w84.am15.net -0.0.0.0 w85.am15.net -0.0.0.0 w86.am15.net -0.0.0.0 w87.am15.net -0.0.0.0 w88.am15.net -0.0.0.0 w89.am15.net -0.0.0.0 w8.am15.net -0.0.0.0 w90.am15.net -0.0.0.0 w91.am15.net -0.0.0.0 w92.am15.net -0.0.0.0 w93.am15.net -0.0.0.0 w94.am15.net -0.0.0.0 w95.am15.net -0.0.0.0 w96.am15.net -0.0.0.0 w97.am15.net -0.0.0.0 w98.am15.net -0.0.0.0 w99.am15.net -0.0.0.0 w9.am15.net -0.0.0.0 wahoha.com -0.0.0.0 warp.crystalad.com -0.0.0.0 wdm29.com -0.0.0.0 web1b.netreflector.com -0.0.0.0 web.adblade.com -0.0.0.0 webads.bizservers.com -0.0.0.0 webads.nl -0.0.0.0 webcompteur.com -0.0.0.0 webhosting-ads.home.pl -0.0.0.0 webmdcom.tt.omtrdc.net -0.0.0.0 web.nyc.ads.juno.co -0.0.0.0 webservices-rewardpath.com -0.0.0.0 websurvey.spa-mr.com -0.0.0.0 wegetpaid.net -0.0.0.0 w.ic.tynt.com -0.0.0.0 widget3.linkwithin.com -0.0.0.0 widget5.linkwithin.com -0.0.0.0 widget.crowdignite.com -0.0.0.0 widget.plugrush.com -0.0.0.0 widgets.outbrain.com -0.0.0.0 widgets.tcimg.com -0.0.0.0 wigetmedia.com -0.0.0.0 wikiforosh.ir -0.0.0.0 williamhill.es -0.0.0.0 wmedia.rotator.hadj7.adjuggler.net -0.0.0.0 wordplaywhiz.com -0.0.0.0 work-offer.com -0.0.0.0 worry-free-savings.com -0.0.0.0 wppluginspro.com -0.0.0.0 ws.addthis.com -0.0.0.0 wtp101.com -0.0.0.0 ww251.smartadserver.com -0.0.0.0 wwbtads.com -0.0.0.0 www10.ad.tomshardware.com -0.0.0.0 www10.glam.com -0.0.0.0 www10.indiads.com -0.0.0.0 www10.paypopup.com -0.0.0.0 www11.ad.tomshardware.com -0.0.0.0 www123.glam.com -0.0.0.0 www.123specialgifts.com -0.0.0.0 www12.ad.tomshardware.com -0.0.0.0 www12.glam.com -0.0.0.0 www13.ad.tomshardware.com -0.0.0.0 www13.glam.com -0.0.0.0 www14.ad.tomshardware.com -0.0.0.0 www15.ad.tomshardware.com -0.0.0.0 www17.glam.com -0.0.0.0 www18.glam.com -0.0.0.0 www1.adireland.com -0.0.0.0 www1.ad.tomshardware.com -0.0.0.0 www1.bannerspace.com -0.0.0.0 www1.belboon.de -0.0.0.0 www1.clicktorrent.info -0.0.0.0 www1.mpnrs.com -0.0.0.0 www1.popinads.com -0.0.0.0 www1.safenyplanet.in -0.0.0.0 www210.paypopup.com -0.0.0.0 www211.paypopup.com -0.0.0.0 www212.paypopup.com -0.0.0.0 www213.paypopup.com -0.0.0.0 www.247realmedia.com -0.0.0.0 www24a.glam.com -0.0.0.0 www24.glam.com -0.0.0.0 www25a.glam.com -0.0.0.0 www25.glam.com -0.0.0.0 www2.adireland.com -0.0.0.0 www2.adserverpub.com -0.0.0.0 www2.ad.tomshardware.com -0.0.0.0 www.2-art-coliseum.com -0.0.0.0 www2.bannerspace.com -0.0.0.0 www2.glam.com -0.0.0.0 www30a1.glam.com -0.0.0.0 www30a1-orig.glam.com -0.0.0.0 www30a2-orig.glam.com -0.0.0.0 www30a3.glam.com -0.0.0.0 www30a3-orig.glam.com -0.0.0.0 www30a7.glam.com -0.0.0.0 www30.glam.com -0.0.0.0 www30l2.glam.com -0.0.0.0 www30t1-orig.glam.com -0.0.0.0 www.321cba.com -0.0.0.0 www35f.glam.com -0.0.0.0 www35jm.glam.com -0.0.0.0 www35t.glam.com -0.0.0.0 www.360ads.com -0.0.0.0 www3.addthis.com -0.0.0.0 www3.adireland.com -0.0.0.0 www3.ad.tomshardware.com -0.0.0.0 www3.bannerspace.com -0.0.0.0 www3.game-advertising-online.com -0.0.0.0 www.3qqq.net -0.0.0.0 www.3turtles.com -0.0.0.0 www.404errorpage.com -0.0.0.0 www4.ad.tomshardware.com -0.0.0.0 www4.bannerspace.com -0.0.0.0 www4.glam.com -0.0.0.0 www4.smartadserver.com -0.0.0.0 www5.ad.tomshardware.com -0.0.0.0 www5.bannerspace.com -0.0.0.0 www.5thavenue.com -0.0.0.0 www6.ad.tomshardware.com -0.0.0.0 www6.bannerspace.com -0.0.0.0 www74.valueclick.com -0.0.0.0 www.7500.com -0.0.0.0 www7.ad.tomshardware.com -0.0.0.0 www7.bannerspace.com -0.0.0.0 www.7bpeople.com -0.0.0.0 www.7cnbcnews.com -0.0.0.0 www.805m.com -0.0.0.0 www81.valueclick.com -0.0.0.0 www.888casino.com -0.0.0.0 www.888.com -0.0.0.0 www.888poker.com -0.0.0.0 www8.ad.tomshardware.com -0.0.0.0 www8.bannerspace.com -0.0.0.0 www.961.com -0.0.0.0 www9.ad.tomshardware.com -0.0.0.0 www9.paypopup.com -0.0.0.0 www.abrogatesdv.info -0.0.0.0 www.actiondesk.com -0.0.0.0 www.action.ientry.net -0.0.0.0 www.adbanner.gr -0.0.0.0 www.adbrite.com -0.0.0.0 www.adcanadian.com -0.0.0.0 www.adcash.com -0.0.0.0 www.addthiscdn.com -0.0.0.0 www.adengage.com -0.0.0.0 www.adfunkyserver.com -0.0.0.0 www.adfusion.com -0.0.0.0 www.adimages.beeb.com -0.0.0.0 www.adipics.com -0.0.0.0 www.adireland.com -0.0.0.0 www.adjmps.com -0.0.0.0 www.adjug.com -0.0.0.0 www.adloader.com -0.0.0.0 www.adlogix.com -0.0.0.0 www.admex.com -0.0.0.0 www.adnet.biz -0.0.0.0 www.adnet.com -0.0.0.0 www.adnet.de -0.0.0.0 www.adobee.com -0.0.0.0 www.adocean.pl -0.0.0.0 www.adotube.com -0.0.0.0 www.adpepper.dk -0.0.0.0 www.adpowerzone.com -0.0.0.0 www.adquest3d.com -0.0.0.0 www.adreporting.com -0.0.0.0 www.ads2srv.com -0.0.0.0 www.adsentnetwork.com -0.0.0.0 www.adserver.co.il -0.0.0.0 www.adserver.com -0.0.0.0 www.adserver.com.my -0.0.0.0 www.adserver.com.pl -0.0.0.0 www.adserver-espnet.sportszone.net -0.0.0.0 www.adserver.janes.net -0.0.0.0 www.adserver.janes.org -0.0.0.0 www.adserver.jolt.co.uk -0.0.0.0 www.adserver.net -0.0.0.0 www.adserver.ugo.nl -0.0.0.0 www.adservtech.com -0.0.0.0 www.adsinimages.com -0.0.0.0 www.ads.joetec.net -0.0.0.0 www.adsoftware.com -0.0.0.0 www.ad-souk.com -0.0.0.0 www.adspics.com -0.0.0.0 www.ads.revenue.net -0.0.0.0 www.adstogo.com -0.0.0.0 www.adstreams.org -0.0.0.0 www.adtaily.pl -0.0.0.0 www.adtechus.com -0.0.0.0 www.ad.tgdaily.com -0.0.0.0 www.adtlgc.com -0.0.0.0 www.ad.tomshardware.com -0.0.0.0 www.adtrader.com -0.0.0.0 www.adtrix.com -0.0.0.0 www.ad.twitchguru.com -0.0.0.0 www.ad-up.com -0.0.0.0 www.advaliant.com -0.0.0.0 www.advertising-department.com -0.0.0.0 www.advertlets.com -0.0.0.0 www.advertpro.com -0.0.0.0 www.adverts.dcthomson.co.uk -0.0.0.0 www.advertyz.com -0.0.0.0 www.ad-words.ru -0.0.0.0 www.afcyhf.com -0.0.0.0 www.affiliateclick.com -0.0.0.0 www.affiliate-fr.com -0.0.0.0 www.affiliation-france.com -0.0.0.0 www.afform.co.uk -0.0.0.0 www.affpartners.com -0.0.0.0 www.afterdownload.com -0.0.0.0 www.agkn.com -0.0.0.0 www.alexxe.com -0.0.0.0 www.allosponsor.com -0.0.0.0 www.annuaire-autosurf.com -0.0.0.0 www.apparelncs.com -0.0.0.0 www.apparel-offer.com -0.0.0.0 www.applelounge.com -0.0.0.0 www.appnexus.com -0.0.0.0 www.art-music-rewardpath.com -0.0.0.0 www.art-offer.com -0.0.0.0 www.art-offer.net -0.0.0.0 www.art-photo-music-premiumblvd.com -0.0.0.0 www.art-photo-music-rewardempire.com -0.0.0.0 www.art-photo-music-savingblvd.com -0.0.0.0 www.auctionshare.net -0.0.0.0 www.aureate.com -0.0.0.0 www.autohipnose.com -0.0.0.0 www.automotive-offer.com -0.0.0.0 www.automotive-rewardpath.com -0.0.0.0 www.avcounter10.com -0.0.0.0 www.avsads.com -0.0.0.0 www.a.websponsors.com -0.0.0.0 www.awesomevipoffers.com -0.0.0.0 www.awin1.com -0.0.0.0 www.awltovhc.com #qksrv -0.0.0.0 www.bananacashback.com -0.0.0.0 www.banner4all.dk -0.0.0.0 www.bannerads.de -0.0.0.0 www.bannerbackup.com -0.0.0.0 www.bannerconnect.net -0.0.0.0 www.banners.paramountzone.com -0.0.0.0 www.bannersurvey.biz -0.0.0.0 www.banstex.com -0.0.0.0 www.bargainbeautybuys.com -0.0.0.0 www.bbelements.com -0.0.0.0 www.bestshopperrewards.com -0.0.0.0 www.bet365.com -0.0.0.0 www.bidtraffic.com -0.0.0.0 www.bidvertiser.com -0.0.0.0 www.bigbrandpromotions.com -0.0.0.0 www.bigbrandrewards.com -0.0.0.0 www.biggestgiftrewards.com -0.0.0.0 www.binarysystem4u.com -0.0.0.0 www.biz-offer.com -0.0.0.0 www.bizopprewards.com -0.0.0.0 www.blasphemysfhs.info -0.0.0.0 www.blatant8jh.info -0.0.0.0 www.bluediamondoffers.com -0.0.0.0 www.bnnr.nl -0.0.0.0 www.bonzi.com -0.0.0.0 www.bookclub-offer.com -0.0.0.0 www.books-media-edu-premiumblvd.com -0.0.0.0 www.books-media-edu-rewardempire.com -0.0.0.0 www.books-media-rewardpath.com -0.0.0.0 www.boonsolutions.com -0.0.0.0 www.bostonsubwayoffer.com -0.0.0.0 www.brandrewardcentral.com -0.0.0.0 www.brandsurveypanel.com -0.0.0.0 www.brokertraffic.com -0.0.0.0 www.budsinc.com -0.0.0.0 www.bugsbanner.it -0.0.0.0 www.bulkclicks.com -0.0.0.0 www.bulletads.com -0.0.0.0 www.burstnet.com -0.0.0.0 www.business-rewardpath.com -0.0.0.0 www.bus-offer.com -0.0.0.0 www.buttcandy.com -0.0.0.0 www.buwobarun.cn -0.0.0.0 www.buycheapadvertising.com -0.0.0.0 www.buyhitscheap.com -0.0.0.0 www.capath.com -0.0.0.0 www.careers-rewardpath.com -0.0.0.0 www.car-truck-boat-bonuspath.com -0.0.0.0 www.car-truck-boat-premiumblvd.com -0.0.0.0 www.cashback.co.uk -0.0.0.0 www.cashbackwow.co.uk -0.0.0.0 www.cashcount.com -0.0.0.0 www.casino770.com -0.0.0.0 www.catalinkcashback.com -0.0.0.0 www.cell-phone-giveaways.com -0.0.0.0 www.cellphoneincentives.com -0.0.0.0 www.chainsawoffer.com -0.0.0.0 www.chartbeat.com -0.0.0.0 www.choicedealz.com -0.0.0.0 www.choicesurveypanel.com -0.0.0.0 www.christianbusinessadvertising.com -0.0.0.0 www.ciqugasox.cn -0.0.0.0 www.claimfreerewards.com -0.0.0.0 www.clashmediausa.com -0.0.0.0 www.click10.com -0.0.0.0 www.click4click.com -0.0.0.0 www.clickbank.com -0.0.0.0 www.clickdensity.com -0.0.0.0 www.click-find-save.com -0.0.0.0 www.click-see-save.com -0.0.0.0 www.clicksor.com -0.0.0.0 www.clicksotrk.com -0.0.0.0 www.clicktale.com -0.0.0.0 www.clicktale.net -0.0.0.0 www.clickthruserver.com -0.0.0.0 www.clickthrutraffic.com -0.0.0.0 www.clicktilluwin.com -0.0.0.0 www.clicktorrent.info -0.0.0.0 www.clickxchange.com -0.0.0.0 www.closeoutproductsreview.com -0.0.0.0 www.cm1359.com -0.0.0.0 www.come-see-it-all.com -0.0.0.0 www.commerce-offer.com -0.0.0.0 www.commerce-rewardpath.com -0.0.0.0 www.computer-offer.com -0.0.0.0 www.computer-offer.net -0.0.0.0 www.computers-electronics-rewardpath.com -0.0.0.0 www.computersncs.com -0.0.0.0 www.consumergiftcenter.com -0.0.0.0 www.consumerincentivenetwork.com -0.0.0.0 www.consumer-org.com -0.0.0.0 www.contaxe.com -0.0.0.0 www.contextuads.com -0.0.0.0 www.contextweb.com -0.0.0.0 www.cookingtiprewards.com -0.0.0.0 www.coolconcepts.nl -0.0.0.0 www.cool-premiums.com -0.0.0.0 www.cool-premiums-now.com -0.0.0.0 www.coolpremiumsnow.com -0.0.0.0 www.coolsavings.com -0.0.0.0 www.coreglead.co.uk -0.0.0.0 www.cosmeticscentre.uk.com -0.0.0.0 www.cpabank.com -0.0.0.0 www.cpmadvisors.com -0.0.0.0 www.crazypopups.com -0.0.0.0 www.crazywinnings.com -0.0.0.0 www.crediblegfj.info -0.0.0.0 www.crispads.com -0.0.0.0 www.crowdgravity.com -0.0.0.0 www.crowdignite.com -0.0.0.0 www.ctbdev.net -0.0.0.0 www.cyber-incentives.com -0.0.0.0 www.d03x2011.com -0.0.0.0 www.da-ads.com -0.0.0.0 www.daily-saver.com -0.0.0.0 www.datatech.es -0.0.0.0 www.datingadvertising.com -0.0.0.0 www.dctracking.com -0.0.0.0 www.depravedwhores.com -0.0.0.0 www.designbloxlive.com -0.0.0.0 www.dgmaustralia.com -0.0.0.0 www.dietoftoday.ca.pn -0.0.0.0 www.digimedia.com -0.0.0.0 www.directnetadvertising.net -0.0.0.0 www.directpowerrewards.com -0.0.0.0 www.dirtyrhino.com -0.0.0.0 www.discount-savings-more.com -0.0.0.0 www.djugoogs.com -0.0.0.0 www.dl-plugin.com -0.0.0.0 www.drowle.com -0.0.0.0 www.dutchsales.org -0.0.0.0 www.earnmygift.com -0.0.0.0 www.earnpointsandgifts.com -0.0.0.0 www.easyadservice.com -0.0.0.0 www.e-bannerx.com -0.0.0.0 www.ebaybanner.com -0.0.0.0 www.education-rewardpath.com -0.0.0.0 www.edu-offer.com -0.0.0.0 www.electronics-bonuspath.com -0.0.0.0 www.electronics-offer.net -0.0.0.0 www.electronicspresent.com -0.0.0.0 www.electronics-rewardpath.com -0.0.0.0 www.emailadvantagegroup.com -0.0.0.0 www.emailproductreview.com -0.0.0.0 www.emarketmakers.com -0.0.0.0 www.entertainment-rewardpath.com -0.0.0.0 www.entertainment-specials.com -0.0.0.0 www.eshopads2.com -0.0.0.0 www.euros4click.de -0.0.0.0 www.exclusivegiftcards.com -0.0.0.0 www.eyeblaster-bs.com -0.0.0.0 www.eyewonder.com #: Interactive Digital Advertising, Rich Media Ads, Flash Ads, Online Advertising -0.0.0.0 www.falkag.de -0.0.0.0 www.family-offer.com -0.0.0.0 www.fast-adv.it -0.0.0.0 www.fatcatrewards.com -0.0.0.0 www.feedjit.com -0.0.0.0 www.feedstermedia.com -0.0.0.0 www.fif49.info -0.0.0.0 www.finance-offer.com -0.0.0.0 www.finder.cox.net -0.0.0.0 www.fineclicks.com -0.0.0.0 www.flagcounter.com -0.0.0.0 www.flowers-offer.com -0.0.0.0 www.flu23.com -0.0.0.0 www.focalex.com -0.0.0.0 www.folloyu.com -0.0.0.0 www.food-drink-bonuspath.com -0.0.0.0 www.food-drink-rewardpath.com -0.0.0.0 www.foodmixeroffer.com -0.0.0.0 www.food-offer.com -0.0.0.0 www.fpctraffic2.com -0.0.0.0 www.freeadguru.com -0.0.0.0 www.freebiegb.co.uk -0.0.0.0 www.freecameraonus.com -0.0.0.0 www.freecameraprovider.com -0.0.0.0 www.freecamerasource.com -0.0.0.0 www.freecamerauk.co.uk -0.0.0.0 www.freecamsecrets.com -0.0.0.0 www.freecoolgift.com -0.0.0.0 www.freedesignerhandbagreviews.com -0.0.0.0 www.freedinnersource.com -0.0.0.0 www.freedvddept.com -0.0.0.0 www.freeelectronicscenter.com -0.0.0.0 www.freeelectronicsdepot.com -0.0.0.0 www.freeelectronicsonus.com -0.0.0.0 www.freeelectronicssource.com -0.0.0.0 www.freeentertainmentsource.com -0.0.0.0 www.freefoodprovider.com -0.0.0.0 www.freefoodsource.com -0.0.0.0 www.freefuelcard.com -0.0.0.0 www.freefuelcoupon.com -0.0.0.0 www.freegasonus.com -0.0.0.0 www.freegasprovider.com -0.0.0.0 www.free-gift-cards-now.com -0.0.0.0 www.freegiftcardsource.com -0.0.0.0 www.freegiftreward.com -0.0.0.0 www.free-gifts-comp.com -0.0.0.0 www.freeipodnanouk.co.uk -0.0.0.0 www.freeipoduk.com -0.0.0.0 www.freeipoduk.co.uk -0.0.0.0 www.freelaptopgift.com -0.0.0.0 www.freelaptopnation.com -0.0.0.0 www.free-laptop-reward.com -0.0.0.0 www.freelaptopreward.com -0.0.0.0 www.freelaptopwebsites.com -0.0.0.0 www.freenation.com -0.0.0.0 www.freeoffers-toys.com -0.0.0.0 www.freepayasyougotopupuk.co.uk -0.0.0.0 www.freeplasmanation.com -0.0.0.0 www.freerestaurantprovider.com -0.0.0.0 www.freerestaurantsource.com -0.0.0.0 www.freeshoppingprovider.com -0.0.0.0 www.freeshoppingsource.com -0.0.0.0 www.friendlyduck.com -0.0.0.0 www.frontpagecash.com -0.0.0.0 www.ftjcfx.com #commission junction -0.0.0.0 www.fusionbanners.com -0.0.0.0 www.gameconsolerewards.com -0.0.0.0 www.games-toys-bonuspath.com -0.0.0.0 www.games-toys-free.com -0.0.0.0 www.games-toys-rewardpath.com -0.0.0.0 www.gatoradvertisinginformationnetwork.com -0.0.0.0 www.getacool100.com -0.0.0.0 www.getacool500.com -0.0.0.0 www.getacoollaptop.com -0.0.0.0 www.getacooltv.com -0.0.0.0 www.getagiftonline.com -0.0.0.0 www.getloan.com -0.0.0.0 www.getmyfreebabystuff.com -0.0.0.0 www.getmyfreegear.com -0.0.0.0 www.getmyfreegiftcard.com -0.0.0.0 www.getmyfreelaptop.com -0.0.0.0 www.getmyfreelaptophere.com -0.0.0.0 www.getmyfreeplasma.com -0.0.0.0 www.getmylaptopfree.com -0.0.0.0 www.getmyplasmatv.com -0.0.0.0 www.getspecialgifts.com -0.0.0.0 www.getyourfreecomputer.com -0.0.0.0 www.getyourfreetv.com -0.0.0.0 www.giftcardchallenge.com -0.0.0.0 www.giftcardsurveys.us.com -0.0.0.0 www.giftrewardzone.com -0.0.0.0 www.gifts-flowers-rewardpath.com -0.0.0.0 www.gimmethatreward.com -0.0.0.0 www.gmads.net -0.0.0.0 www.go-free-gifts.com -0.0.0.0 www.gofreegifts.com -0.0.0.0 www.goody-garage.com -0.0.0.0 www.gopopup.com -0.0.0.0 www.grabbit-rabbit.com -0.0.0.0 www.greasypalm.com -0.0.0.0 www.grz67.com -0.0.0.0 www.guesstheview.com -0.0.0.0 www.guptamedianetwork.com -0.0.0.0 www.happydiscountspecials.com -0.0.0.0 www.healthbeautyncs.com -0.0.0.0 www.health-beauty-rewardpath.com -0.0.0.0 www.health-beauty-savingblvd.com -0.0.0.0 www.healthclicks.co.uk -0.0.0.0 www.hebdotop.com -0.0.0.0 www.hightrafficads.com -0.0.0.0 www.holiday-gift-offers.com -0.0.0.0 www.holidayproductpromo.com -0.0.0.0 www.holidayshoppingrewards.com -0.0.0.0 www.home4bizstart.ru -0.0.0.0 www.homeelectronicproducts.com -0.0.0.0 www.home-garden-premiumblvd.com -0.0.0.0 www.home-garden-rewardempire.com -0.0.0.0 www.home-garden-rewardpath.com -0.0.0.0 www.hooqy.com -0.0.0.0 www.hot-daily-deal.com -0.0.0.0 www.hotgiftzone.com -0.0.0.0 www.hotkeys.com -0.0.0.0 www.hot-product-hangout.com -0.0.0.0 www.idealcasino.net -0.0.0.0 www.idirect.com -0.0.0.0 www.iicdn.com -0.0.0.0 www.ijacko.net -0.0.0.0 www.ilovecheating.com -0.0.0.0 www.impressionaffiliate.com -0.0.0.0 www.impressionaffiliate.mobi -0.0.0.0 www.impressionlead.com -0.0.0.0 www.impressionperformance.biz -0.0.0.0 www.incentivegateway.com -0.0.0.0 www.incentiverewardcenter.com -0.0.0.0 www.incentive-scene.com -0.0.0.0 www.inckamedia.com -0.0.0.0 www.indiads.com -0.0.0.0 www.infinite-ads.com # www.shareactor.com -0.0.0.0 www.ins-offer.com -0.0.0.0 www.insurance-rewardpath.com -0.0.0.0 www.intela.com -0.0.0.0 www.interstitialzone.com -0.0.0.0 www.intnet-offer.com -0.0.0.0 www.invitefashion.com -0.0.0.0 www.is1.clixgalore.com -0.0.0.0 www.itrackerpro.com -0.0.0.0 www.itsfree123.com -0.0.0.0 www.iwantmyfreecash.com -0.0.0.0 www.iwantmy-freelaptop.com -0.0.0.0 www.iwantmyfree-laptop.com -0.0.0.0 www.iwantmyfreelaptop.com -0.0.0.0 www.iwantmygiftcard.com -0.0.0.0 www.jersey-offer.com -0.0.0.0 www.jetseeker.com -0.0.0.0 www.jivox.com -0.0.0.0 www.jl29jd25sm24mc29.com -0.0.0.0 www.joinfree.ro -0.0.0.0 www.jxliu.com -0.0.0.0 www.keybinary.com -0.0.0.0 www.keywordblocks.com -0.0.0.0 www.kitaramarketplace.com -0.0.0.0 www.kitaramedia.com -0.0.0.0 www.kitaratrk.com -0.0.0.0 www.kixer.com -0.0.0.0 www.kliksaya.com -0.0.0.0 www.kmdl101.com -0.0.0.0 www.kontera.com -0.0.0.0 www.konversation.com -0.0.0.0 www.kreaffiliation.com -0.0.0.0 www.kuhdi.com -0.0.0.0 www.ladyclicks.ru -0.0.0.0 www.laptopreportcard.com -0.0.0.0 www.laptoprewards.com -0.0.0.0 www.laptoprewardsgroup.com -0.0.0.0 www.laptoprewardszone.com -0.0.0.0 www.larivieracasino.com -0.0.0.0 www.lasthr.info -0.0.0.0 www.lduhtrp.net #commission junction -0.0.0.0 www.le1er.net -0.0.0.0 www.leadgreed.com -0.0.0.0 www.learning-offer.com -0.0.0.0 www.legal-rewardpath.com -0.0.0.0 www.leisure-offer.com -0.0.0.0 www.linkhut.com -0.0.0.0 www.linkpulse.com -0.0.0.0 www.linkwithin.com -0.0.0.0 www.liveinternet.ru -0.0.0.0 www.lottoforever.com -0.0.0.0 www.lpcloudsvr302.com -0.0.0.0 www.lucky-day-uk.com -0.0.0.0 www.macombdisplayads.com -0.0.0.0 www.marketing-rewardpath.com -0.0.0.0 www.mastertracks.be -0.0.0.0 www.maxbounty.com -0.0.0.0 www.mb01.com -0.0.0.0 www.media2.travelzoo.com -0.0.0.0 www.media-motor.com -0.0.0.0 www.medical-offer.com -0.0.0.0 www.medical-rewardpath.com -0.0.0.0 www.merchantapp.com -0.0.0.0 www.merlin.co.il -0.0.0.0 www.mgid.com -0.0.0.0 www.mightymagoo.com -0.0.0.0 www.mktg-offer.com -0.0.0.0 www.mlntracker.com -0.0.0.0 www.mochibot.com -0.0.0.0 www.morefreecamsecrets.com -0.0.0.0 www.morevisits.info -0.0.0.0 www.mp3playersource.com -0.0.0.0 www.mpression.net -0.0.0.0 www.myadsl.co.za -0.0.0.0 www.myaffiliateprogram.com -0.0.0.0 www.myairbridge.com -0.0.0.0 www.mycashback.co.uk -0.0.0.0 www.mycelloffer.com -0.0.0.0 www.mychoicerewards.com -0.0.0.0 www.myexclusiverewards.com -0.0.0.0 www.myfreedinner.com -0.0.0.0 www.myfreegifts.co.uk -0.0.0.0 www.myfreemp3player.com -0.0.0.0 www.mygiftcardcenter.com -0.0.0.0 www.mygreatrewards.com -0.0.0.0 www.myoffertracking.com -0.0.0.0 www.my-reward-channel.com -0.0.0.0 www.my-rewardsvault.com -0.0.0.0 www.myseostats.com -0.0.0.0 www.my-stats.com -0.0.0.0 www.myuitm.com -0.0.0.0 www.myusersonline.com -0.0.0.0 www.na47.com -0.0.0.0 www.nationalissuepanel.com -0.0.0.0 www.nationalsurveypanel.com -0.0.0.0 www.nctracking.com -0.0.0.0 www.nearbyad.com -0.0.0.0 www.needadvertising.com -0.0.0.0 www.neptuneads.com -0.0.0.0 www.netpalnow.com -0.0.0.0 www.netpaloffers.net -0.0.0.0 www.news6health.com -0.0.0.0 www.newssourceoftoday.com -0.0.0.0 www.nospartenaires.com -0.0.0.0 www.nothing-but-value.com -0.0.0.0 www.nysubwayoffer.com -0.0.0.0 www.offerx.co.uk -0.0.0.0 www.oinadserve.com -0.0.0.0 www.onlinebestoffers.net -0.0.0.0 www.ontheweb.com -0.0.0.0 www.opendownload.de -0.0.0.0 www.openload.de -0.0.0.0 www.optiad.net -0.0.0.0 www.paperg.com -0.0.0.0 www.parsads.com -0.0.0.0 www.pathforpoints.com -0.0.0.0 www.paypopup.com -0.0.0.0 www.people-choice-sites.com -0.0.0.0 www.personalcare-offer.com -0.0.0.0 www.personalcashbailout.com -0.0.0.0 www.phoenixads.co.in -0.0.0.0 www.pick-savings.com -0.0.0.0 www.plasmatv4free.com -0.0.0.0 www.plasmatvreward.com -0.0.0.0 www.politicalopinionsurvey.com -0.0.0.0 www.poponclick.com -0.0.0.0 www.popupad.net -0.0.0.0 www.popupdomination.com -0.0.0.0 www.popuptraffic.com -0.0.0.0 www.postmasterbannernet.com -0.0.0.0 www.postmasterdirect.com -0.0.0.0 www.postnewsads.com -0.0.0.0 www.premiumholidayoffers.com -0.0.0.0 www.premiumproductsonline.com -0.0.0.0 www.premium-reward-club.com -0.0.0.0 www.prizes.co.uk -0.0.0.0 www.probabilidades.net -0.0.0.0 www.productopinionpanel.com -0.0.0.0 www.productresearchpanel.com -0.0.0.0 www.producttestpanel.com -0.0.0.0 www.psclicks.com -0.0.0.0 www.pubdirecte.com -0.0.0.0 www.qitrck.com -0.0.0.0 www.quickbrowsersearch.com -0.0.0.0 www.radiate.com -0.0.0.0 www.rankyou.com -0.0.0.0 www.ravel-rewardpath.com -0.0.0.0 www.recreation-leisure-rewardpath.com -0.0.0.0 www.regflow.com -0.0.0.0 www.registrarads.com -0.0.0.0 www.resolvingserver.com -0.0.0.0 www.rewardblvd.com -0.0.0.0 www.rewardhotspot.com -0.0.0.0 www.rewardsflow.com -0.0.0.0 www.ringtonepartner.com -0.0.0.0 www.romepartners.com -0.0.0.0 www.roulettebotplus.com -0.0.0.0 www.rovion.com -0.0.0.0 www.rscounter10.com -0.0.0.0 www.rtcode.com -0.0.0.0 www.rwpads.net -0.0.0.0 www.sa44.net -0.0.0.0 www.salesonline.ie -0.0.0.0 www.save-plan.com -0.0.0.0 www.savings-specials.com -0.0.0.0 www.savings-time.com -0.0.0.0 www.scoremygift.com -0.0.0.0 www.screen-mates.com -0.0.0.0 www.searchwe.com -0.0.0.0 www.seasonalsamplerspecials.com -0.0.0.0 www.securecontactinfo.com -0.0.0.0 www.securerunner.com -0.0.0.0 www.servedby.advertising.com -0.0.0.0 www.sexpartnerx.com -0.0.0.0 www.sexsponsors.com -0.0.0.0 www.shareasale.com -0.0.0.0 www.share-server.com -0.0.0.0 www.shc-rebates.com -0.0.0.0 www.shopperpromotions.com -0.0.0.0 www.shoppingjobshere.com -0.0.0.0 www.shopping-offer.com -0.0.0.0 www.shoppingsiterewards.com -0.0.0.0 www.shops-malls-rewardpath.com -0.0.0.0 www.shoptosaveenergy.com -0.0.0.0 www.simpli.fi -0.0.0.0 www.sizzle-savings.com -0.0.0.0 www.smartadserver.com -0.0.0.0 www.smart-scripts.com -0.0.0.0 www.smarttargetting.com -0.0.0.0 www.smokersopinionpoll.com -0.0.0.0 www.smspop.com -0.0.0.0 www.sochr.com -0.0.0.0 www.sociallypublish.com -0.0.0.0 www.soongu.info -0.0.0.0 www.specialgiftrewards.com -0.0.0.0 www.specialonlinegifts.com -0.0.0.0 www.specials-rewardpath.com -0.0.0.0 www.speedboink.com -0.0.0.0 www.speedyclick.com -0.0.0.0 www.spinbox.com -0.0.0.0 www.sponsorads.de -0.0.0.0 www.sponsoradulto.com -0.0.0.0 www.sports-bonuspath.com -0.0.0.0 www.sports-fitness-rewardpath.com -0.0.0.0 www.sports-offer.com -0.0.0.0 www.sports-offer.net -0.0.0.0 www.sports-premiumblvd.com -0.0.0.0 www.sq2trk2.com -0.0.0.0 www.star-advertising.com -0.0.0.0 www.subsitesadserver.co.uk -0.0.0.0 www.sudokuwhiz.com -0.0.0.0 www.superbrewards.com -0.0.0.0 www.supremeadsonline.com -0.0.0.0 www.surplus-suppliers.com -0.0.0.0 www.sweetsforfree.com -0.0.0.0 www.symbiosting.com -0.0.0.0 www.syncaccess.net -0.0.0.0 www.system-live-media.cz -0.0.0.0 www.tcimg.com -0.0.0.0 www.textbanners.net -0.0.0.0 www.text-link-ads.com -0.0.0.0 www.textsrv.com -0.0.0.0 www.tgpmanager.com -0.0.0.0 www.thatrendsystem.com -0.0.0.0 www.the-binary-options-guide.com -0.0.0.0 www.the-binary-theorem.com -0.0.0.0 www.the-path-gateway.com -0.0.0.0 www.the-smart-stop.com -0.0.0.0 www.thetraderinpajamas.com -0.0.0.0 www.theuseful.com -0.0.0.0 www.theuseful.net -0.0.0.0 www.thinktarget.com -0.0.0.0 www.thinlaptoprewards.com -0.0.0.0 www.thoughtfully-free.com -0.0.0.0 www.thruport.com -0.0.0.0 www.tons-to-see.com -0.0.0.0 www.top20free.com -0.0.0.0 www.topbrandrewards.com -0.0.0.0 www.topconsumergifts.com -0.0.0.0 www.topdemaroc.com -0.0.0.0 www.toy-offer.com -0.0.0.0 www.toy-offer.net -0.0.0.0 www.tqlkg.com #commission junction -0.0.0.0 www.trackadvertising.net -0.0.0.0 www.tracklead.net -0.0.0.0 www.trafficrevenue.net -0.0.0.0 www.traffictrader.net -0.0.0.0 www.traffictraders.com -0.0.0.0 www.trafsearchonline.com -0.0.0.0 www.traktum.com -0.0.0.0 www.traveladvertising.com -0.0.0.0 www.travel-leisure-bonuspath.com -0.0.0.0 www.travel-leisure-premiumblvd.com -0.0.0.0 www.traveller-offer.com -0.0.0.0 www.traveller-offer.net -0.0.0.0 www.travelncs.com -0.0.0.0 www.treeloot.com -0.0.0.0 www.trendnews.com -0.0.0.0 www.trendsonline.biz -0.0.0.0 www.trendsonline.me -0.0.0.0 www.trendsonline.mobi -0.0.0.0 www.trndsys.mobi -0.0.0.0 www.tutop.com -0.0.0.0 www.tuttosessogratis.org -0.0.0.0 www.ukbanners.com -0.0.0.0 www.uleadstrk.com -0.0.0.0 www.ultimatefashiongifts.com -0.0.0.0 www.uproar.com -0.0.0.0 www.upsellit.com -0.0.0.0 www.usatravel-specials.com -0.0.0.0 www.usatravel-specials.net -0.0.0.0 www.us-choicevalue.com -0.0.0.0 www.usemax.de -0.0.0.0 www.us-topsites.com -0.0.0.0 www.utarget.co.uk -0.0.0.0 www.valueclick.com -0.0.0.0 www.via22.net -0.0.0.0 www.vibrantmedia.com -0.0.0.0 www.video-game-rewards-central.com -0.0.0.0 www.videogamerewardscentral.com -0.0.0.0 www.view4cash.de -0.0.0.0 www.virtumundo.com -0.0.0.0 www.vmcsatellite.com -0.0.0.0 www.wdm29.com -0.0.0.0 www.webcashvideos.com -0.0.0.0 www.webcompteur.com -0.0.0.0 www.webservices-rewardpath.com -0.0.0.0 www.websponsors.com -0.0.0.0 www.wegetpaid.net -0.0.0.0 www.whatuwhatuwhatuwant.com -0.0.0.0 www.widgetbucks.com -0.0.0.0 www.wigetmedia.com -0.0.0.0 www.williamhill.es -0.0.0.0 www.windaily.com -0.0.0.0 www.winnerschoiceservices.com -0.0.0.0 www.wordplaywhiz.com -0.0.0.0 www.work-offer.com -0.0.0.0 www.worry-free-savings.com -0.0.0.0 www.wppluginspro.com -0.0.0.0 www.wtp101.com -0.0.0.0 www.xbn.ru # exclusive banner network (Russian) -0.0.0.0 www.yceml.net -0.0.0.0 www.yibaruxet.cn -0.0.0.0 www.yieldmanager.net -0.0.0.0 www.youfck.com -0.0.0.0 www.yourdvdplayer.com -0.0.0.0 www.yourfreegascard.com -0.0.0.0 www.yourgascards.com -0.0.0.0 www.yourgiftrewards.com -0.0.0.0 www.your-gift-zone.com -0.0.0.0 www.yourgiftzone.com -0.0.0.0 www.yourhandytips.com -0.0.0.0 www.yourhotgiftzone.com -0.0.0.0 www.youripad4free.com -0.0.0.0 www.yourrewardzone.com -0.0.0.0 www.yoursmartrewards.com -0.0.0.0 www.zemgo.com -0.0.0.0 www.zevents.com -0.0.0.0 x86adserve006.adtech.de -0.0.0.0 xads.zedo.com -0.0.0.0 x.azjmp.com -0.0.0.0 x.iasrv.com -0.0.0.0 x.interia.pl -0.0.0.0 xlonhcld.xlontech.net -0.0.0.0 xml.adtech.de -0.0.0.0 xml.adtech.fr -0.0.0.0 xml.adtech.us -0.0.0.0 xml.click9.com -0.0.0.0 x.mochiads.com -0.0.0.0 xpantivirus.com -0.0.0.0 xpcs.ads.yahoo.com -0.0.0.0 xstatic.nk-net.pl -0.0.0.0 yadro.ru -0.0.0.0 y.cdn.adblade.com -0.0.0.0 yieldmanagement.adbooth.net -0.0.0.0 yieldmanager.net -0.0.0.0 ym.adnxs.com -0.0.0.0 yodleeinc.tt.omtrdc.net -0.0.0.0 youfck.com -0.0.0.0 yourdvdplayer.com -0.0.0.0 yourfreegascard.com -0.0.0.0 your-free-iphone.com -0.0.0.0 yourgascards.com -0.0.0.0 yourgiftrewards.com -0.0.0.0 your-gift-zone.com -0.0.0.0 yourgiftzone.com -0.0.0.0 yourhandytips.com -0.0.0.0 yourhotgiftzone.com -0.0.0.0 youripad4free.com -0.0.0.0 yourrewardzone.com -0.0.0.0 yoursmartrewards.com -0.0.0.0 ypn-js.overture.com -0.0.0.0 ysiu.freenation.com -0.0.0.0 ytaahg.vo.llnwd.net -0.0.0.0 yumenetworks.com -0.0.0.0 yx-in-f108.1e100.net -0.0.0.0 z1.adserver.com -0.0.0.0 zads.zedo.com -0.0.0.0 z.blogads.com -0.0.0.0 z.ceotrk.com -0.0.0.0 zdads.e-media.com -0.0.0.0 zeevex-online.com -0.0.0.0 zemgo.com -0.0.0.0 zevents.com -0.0.0.0 zuzzer5.com -# - -# - -# yahoo banner ads -0.0.0.0 eur.a1.yimg.com -0.0.0.0 in.yimg.com -0.0.0.0 sg.yimg.com -0.0.0.0 uk.i1.yimg.com -0.0.0.0 us.a1.yimg.com -0.0.0.0 us.b1.yimg.com -0.0.0.0 us.c1.yimg.com -0.0.0.0 us.d1.yimg.com -0.0.0.0 us.e1.yimg.com -0.0.0.0 us.f1.yimg.com -0.0.0.0 us.g1.yimg.com -0.0.0.0 us.h1.yimg.com -#0.0.0.0 us.i1.yimg.com #Uncomment this to block yahoo images -0.0.0.0 us.j1.yimg.com -0.0.0.0 us.k1.yimg.com -0.0.0.0 us.l1.yimg.com -0.0.0.0 us.m1.yimg.com -0.0.0.0 us.n1.yimg.com -0.0.0.0 us.o1.yimg.com -0.0.0.0 us.p1.yimg.com -0.0.0.0 us.q1.yimg.com -0.0.0.0 us.r1.yimg.com -0.0.0.0 us.s1.yimg.com -0.0.0.0 us.t1.yimg.com -0.0.0.0 us.u1.yimg.com -0.0.0.0 us.v1.yimg.com -0.0.0.0 us.w1.yimg.com -0.0.0.0 us.x1.yimg.com -0.0.0.0 us.y1.yimg.com -0.0.0.0 us.z1.yimg.com -# - -# - -# hitbox.com web bugs -0.0.0.0 1cgi.hitbox.com -0.0.0.0 2cgi.hitbox.com -0.0.0.0 adminec1.hitbox.com -0.0.0.0 ads.hitbox.com -0.0.0.0 ag1.hitbox.com -0.0.0.0 ahbn1.hitbox.com -0.0.0.0 ahbn2.hitbox.com -0.0.0.0 ahbn3.hitbox.com -0.0.0.0 ahbn4.hitbox.com -0.0.0.0 aibg.hitbox.com -0.0.0.0 aibl.hitbox.com -0.0.0.0 aics.hitbox.com -0.0.0.0 ai.hitbox.com -0.0.0.0 aiui.hitbox.com -0.0.0.0 bigip1.hitbox.com -0.0.0.0 bigip2.hitbox.com -0.0.0.0 blowfish.hitbox.com -0.0.0.0 cdb.hitbox.com -0.0.0.0 cgi.hitbox.com -0.0.0.0 counter2.hitbox.com -0.0.0.0 counter.hitbox.com -0.0.0.0 dev101.hitbox.com -0.0.0.0 dev102.hitbox.com -0.0.0.0 dev103.hitbox.com -0.0.0.0 dev.hitbox.com -0.0.0.0 download.hitbox.com -0.0.0.0 ec1.hitbox.com -0.0.0.0 ehg-247internet.hitbox.com -0.0.0.0 ehg-accuweather.hitbox.com -0.0.0.0 ehg-acdsystems.hitbox.com -0.0.0.0 ehg-adeptscience.hitbox.com -0.0.0.0 ehg-affinitynet.hitbox.com -0.0.0.0 ehg-aha.hitbox.com -0.0.0.0 ehg-amerix.hitbox.com -0.0.0.0 ehg-apcc.hitbox.com -0.0.0.0 ehg-associatenewmedia.hitbox.com -0.0.0.0 ehg-ati.hitbox.com -0.0.0.0 ehg-attenza.hitbox.com -0.0.0.0 ehg-autodesk.hitbox.com -0.0.0.0 ehg-baa.hitbox.com -0.0.0.0 ehg-backweb.hitbox.com -0.0.0.0 ehg-bestbuy.hitbox.com -0.0.0.0 ehg-bizjournals.hitbox.com -0.0.0.0 ehg-bmwna.hitbox.com -0.0.0.0 ehg-boschsiemens.hitbox.com -0.0.0.0 ehg-bskyb.hitbox.com -0.0.0.0 ehg-cafepress.hitbox.com -0.0.0.0 ehg-careerbuilder.hitbox.com -0.0.0.0 ehg-cbc.hitbox.com -0.0.0.0 ehg-cbs.hitbox.com -0.0.0.0 ehg-cbsradio.hitbox.com -0.0.0.0 ehg-cedarpoint.hitbox.com -0.0.0.0 ehg-clearchannel.hitbox.com -0.0.0.0 ehg-closetmaid.hitbox.com -0.0.0.0 ehg-commjun.hitbox.com -0.0.0.0 ehg.commjun.hitbox.com -0.0.0.0 ehg-communityconnect.hitbox.com -0.0.0.0 ehg-communityconnet.hitbox.com -0.0.0.0 ehg-comscore.hitbox.com -0.0.0.0 ehg-corusentertainment.hitbox.com -0.0.0.0 ehg-coverityinc.hitbox.com -0.0.0.0 ehg-crain.hitbox.com -0.0.0.0 ehg-ctv.hitbox.com -0.0.0.0 ehg-cygnusbm.hitbox.com -0.0.0.0 ehg-datamonitor.hitbox.com -0.0.0.0 ehg-digg.hitbox.com -0.0.0.0 ehg-dig.hitbox.com -0.0.0.0 ehg-eckounlimited.hitbox.com -0.0.0.0 ehg-esa.hitbox.com -0.0.0.0 ehg-espn.hitbox.com -0.0.0.0 ehg-fifa.hitbox.com -0.0.0.0 ehg-findlaw.hitbox.com -0.0.0.0 ehg-foundation.hitbox.com -0.0.0.0 ehg-foxsports.hitbox.com -0.0.0.0 ehg-futurepub.hitbox.com -0.0.0.0 ehg-gamedaily.hitbox.com -0.0.0.0 ehg-gamespot.hitbox.com -0.0.0.0 ehg-gatehousemedia.hitbox.com -0.0.0.0 ehg-gatehoussmedia.hitbox.com -0.0.0.0 ehg-glam.hitbox.com -0.0.0.0 ehg-groceryworks.hitbox.com -0.0.0.0 ehg-groupernetworks.hitbox.com -0.0.0.0 ehg-guardian.hitbox.com -0.0.0.0 ehg-hasbro.hitbox.com -0.0.0.0 ehg-hellodirect.hitbox.com -0.0.0.0 ehg-himedia.hitbox.com -0.0.0.0 ehg.hitbox.com -0.0.0.0 ehg-hitent.hitbox.com -0.0.0.0 ehg-hollywood.hitbox.com -0.0.0.0 ehg-idgentertainment.hitbox.com -0.0.0.0 ehg-idg.hitbox.com -0.0.0.0 ehg-ifilm.hitbox.com -0.0.0.0 ehg-ignitemedia.hitbox.com -0.0.0.0 ehg-intel.hitbox.com -0.0.0.0 ehg-ittoolbox.hitbox.com -0.0.0.0 ehg-itworldcanada.hitbox.com -0.0.0.0 ehg-kingstontechnology.hitbox.com -0.0.0.0 ehg-knightridder.hitbox.com -0.0.0.0 ehg-learningco.hitbox.com -0.0.0.0 ehg-legonewyorkinc.hitbox.com -0.0.0.0 ehg-liveperson.hitbox.com -0.0.0.0 ehg-macpublishingllc.hitbox.com -0.0.0.0 ehg-macromedia.hitbox.com -0.0.0.0 ehg-magicalia.hitbox.com -0.0.0.0 ehg-maplesoft.hitbox.com -0.0.0.0 ehg-mgnlimited.hitbox.com -0.0.0.0 ehg-mindshare.hitbox.com -0.0.0.0 ehg.mindshare.hitbox.com -0.0.0.0 ehg-mtv.hitbox.com -0.0.0.0 ehg-mybc.hitbox.com -0.0.0.0 ehg-newarkinone.hitbox.com.hitbox.com -0.0.0.0 ehg-newegg.hitbox.com -0.0.0.0 ehg-newscientist.hitbox.com -0.0.0.0 ehg-newsinternational.hitbox.com -0.0.0.0 ehg-nokiafin.hitbox.com -0.0.0.0 ehg-novell.hitbox.com -0.0.0.0 ehg-nvidia.hitbox.com -0.0.0.0 ehg-oreilley.hitbox.com -0.0.0.0 ehg-oreilly.hitbox.com -0.0.0.0 ehg-pacifictheatres.hitbox.com -0.0.0.0 ehg-pennwell.hitbox.com -0.0.0.0 ehg-peoplesoft.hitbox.com -0.0.0.0 ehg-philipsvheusen.hitbox.com -0.0.0.0 ehg-pizzahut.hitbox.com -0.0.0.0 ehg-playboy.hitbox.com -0.0.0.0 ehg-presentigsolutions.hitbox.com -0.0.0.0 ehg-qualcomm.hitbox.com -0.0.0.0 ehg-quantumcorp.hitbox.com -0.0.0.0 ehg-randomhouse.hitbox.com -0.0.0.0 ehg-redherring.hitbox.com -0.0.0.0 ehg-register.hitbox.com -0.0.0.0 ehg-researchinmotion.hitbox.com -0.0.0.0 ehg-rfa.hitbox.com -0.0.0.0 ehg-rodale.hitbox.com -0.0.0.0 ehg-salesforce.hitbox.com -0.0.0.0 ehg-salonmedia.hitbox.com -0.0.0.0 ehg-samsungusa.hitbox.com -0.0.0.0 ehg-seca.hitbox.com -0.0.0.0 ehg-shoppersdrugmart.hitbox.com -0.0.0.0 ehg-sonybssc.hitbox.com -0.0.0.0 ehg-sonycomputer.hitbox.com -0.0.0.0 ehg-sonyelec.hitbox.com -0.0.0.0 ehg-sonymusic.hitbox.com -0.0.0.0 ehg-sonyny.hitbox.com -0.0.0.0 ehg-space.hitbox.com -0.0.0.0 ehg-sportsline.hitbox.com -0.0.0.0 ehg-streamload.hitbox.com -0.0.0.0 ehg-superpages.hitbox.com -0.0.0.0 ehg-techtarget.hitbox.com -0.0.0.0 ehg-tfl.hitbox.com -0.0.0.0 ehg-thefirstchurchchrist.hitbox.com -0.0.0.0 ehg-tigerdirect2.hitbox.com -0.0.0.0 ehg-tigerdirect.hitbox.com -0.0.0.0 ehg-topps.hitbox.com -0.0.0.0 ehg-tribute.hitbox.com -0.0.0.0 ehg-tumbleweed.hitbox.com -0.0.0.0 ehg-ubisoft.hitbox.com -0.0.0.0 ehg-uniontrib.hitbox.com -0.0.0.0 ehg-usnewsworldreport.hitbox.com -0.0.0.0 ehg-verizoncommunications.hitbox.com -0.0.0.0 ehg-viacom.hitbox.com -0.0.0.0 ehg-vmware.hitbox.com -0.0.0.0 ehg-vonage.hitbox.com -0.0.0.0 ehg-wachovia.hitbox.com -0.0.0.0 ehg-wacomtechnology.hitbox.com -0.0.0.0 ehg-warner-brothers.hitbox.com -0.0.0.0 ehg-wizardsofthecoast.hitbox.com.hitbox.com -0.0.0.0 ehg-womanswallstreet.hitbox.com -0.0.0.0 ehg-wss.hitbox.com -0.0.0.0 ehg-xxolympicwintergames.hitbox.com -0.0.0.0 ehg-yellowpages.hitbox.com -0.0.0.0 ehg-youtube.hitbox.com -0.0.0.0 ejs.hitbox.com -0.0.0.0 enterprise-admin.hitbox.com -0.0.0.0 enterprise.hitbox.com -0.0.0.0 esg.hitbox.com -0.0.0.0 evwr.hitbox.com -0.0.0.0 get.hitbox.com -0.0.0.0 hg10.hitbox.com -0.0.0.0 hg11.hitbox.com -0.0.0.0 hg12.hitbox.com -0.0.0.0 hg13.hitbox.com -0.0.0.0 hg14.hitbox.com -0.0.0.0 hg15.hitbox.com -0.0.0.0 hg16.hitbox.com -0.0.0.0 hg17.hitbox.com -0.0.0.0 hg1.hitbox.com -0.0.0.0 hg2.hitbox.com -0.0.0.0 hg3.hitbox.com -0.0.0.0 hg4.hitbox.com -0.0.0.0 hg5.hitbox.com -0.0.0.0 hg6a.hitbox.com -0.0.0.0 hg6.hitbox.com -0.0.0.0 hg7.hitbox.com -0.0.0.0 hg8.hitbox.com -0.0.0.0 hg9.hitbox.com -0.0.0.0 hitboxbenchmarker.com -0.0.0.0 hitboxcentral.com -0.0.0.0 hitbox.com -0.0.0.0 hitboxenterprise.com -0.0.0.0 hitboxwireless.com -0.0.0.0 host6.hitbox.com -0.0.0.0 ias2.hitbox.com -0.0.0.0 ias.hitbox.com -0.0.0.0 ibg.hitbox.com -0.0.0.0 ics.hitbox.com -0.0.0.0 idb.hitbox.com -0.0.0.0 js1.hitbox.com -0.0.0.0 lb.hitbox.com -0.0.0.0 lesbian-erotica.hitbox.com -0.0.0.0 lookup2.hitbox.com -0.0.0.0 lookup.hitbox.com -0.0.0.0 mrtg.hitbox.com -0.0.0.0 myhitbox.com -0.0.0.0 na.hitbox.com -0.0.0.0 narwhal.hitbox.com -0.0.0.0 nei.hitbox.com -0.0.0.0 nocboard.hitbox.com -0.0.0.0 noc.hitbox.com -0.0.0.0 noc-request.hitbox.com -0.0.0.0 ns1.hitbox.com -0.0.0.0 oas.hitbox.com -0.0.0.0 phg.hitbox.com -0.0.0.0 pure.hitbox.com -0.0.0.0 rainbowclub.hitbox.com -0.0.0.0 rd1.hitbox.com -0.0.0.0 reseller.hitbox.com -0.0.0.0 resources.hitbox.com -0.0.0.0 sitesearch.hitbox.com -0.0.0.0 specialtyclub.hitbox.com -0.0.0.0 ss.hitbox.com -0.0.0.0 stage101.hitbox.com -0.0.0.0 stage102.hitbox.com -0.0.0.0 stage103.hitbox.com -0.0.0.0 stage104.hitbox.com -0.0.0.0 stage105.hitbox.com -0.0.0.0 stage.hitbox.com -0.0.0.0 stats2.hitbox.com -0.0.0.0 stats3.hitbox.com -0.0.0.0 stats.hitbox.com -0.0.0.0 switch10.hitbox.com -0.0.0.0 switch11.hitbox.com -0.0.0.0 switch1.hitbox.com -0.0.0.0 switch5.hitbox.com -0.0.0.0 switch6.hitbox.com -0.0.0.0 switch8.hitbox.com -0.0.0.0 switch9.hitbox.com -0.0.0.0 switch.hitbox.com -0.0.0.0 tetra.hitbox.com -0.0.0.0 tools2.hitbox.com -0.0.0.0 toolsa.hitbox.com -0.0.0.0 tools.hitbox.com -0.0.0.0 ts1.hitbox.com -0.0.0.0 ts2.hitbox.com -0.0.0.0 vwr1.hitbox.com -0.0.0.0 vwr2.hitbox.com -0.0.0.0 vwr3.hitbox.com -0.0.0.0 w100.hitbox.com -0.0.0.0 w101.hitbox.com -0.0.0.0 w102.hitbox.com -0.0.0.0 w103.hitbox.com -0.0.0.0 w104.hitbox.com -0.0.0.0 w105.hitbox.com -0.0.0.0 w106.hitbox.com -0.0.0.0 w107.hitbox.com -0.0.0.0 w108.hitbox.com -0.0.0.0 w109.hitbox.com -0.0.0.0 w10.hitbox.com -0.0.0.0 w110.hitbox.com -0.0.0.0 w111.hitbox.com -0.0.0.0 w112.hitbox.com -0.0.0.0 w113.hitbox.com -0.0.0.0 w114.hitbox.com -0.0.0.0 w115.hitbox.com -0.0.0.0 w116.hitbox.com -0.0.0.0 w117.hitbox.com -0.0.0.0 w118.hitbox.com -0.0.0.0 w119.hitbox.com -0.0.0.0 w11.hitbox.com -0.0.0.0 w120.hitbox.com -0.0.0.0 w121.hitbox.com -0.0.0.0 w122.hitbox.com -0.0.0.0 w123.hitbox.com -0.0.0.0 w124.hitbox.com -0.0.0.0 w126.hitbox.com -0.0.0.0 w128.hitbox.com -0.0.0.0 w129.hitbox.com -0.0.0.0 w12.hitbox.com -0.0.0.0 w130.hitbox.com -0.0.0.0 w131.hitbox.com -0.0.0.0 w132.hitbox.com -0.0.0.0 w133.hitbox.com -0.0.0.0 w135.hitbox.com -0.0.0.0 w136.hitbox.com -0.0.0.0 w137.hitbox.com -0.0.0.0 w138.hitbox.com -0.0.0.0 w139.hitbox.com -0.0.0.0 w13.hitbox.com -0.0.0.0 w140.hitbox.com -0.0.0.0 w141.hitbox.com -0.0.0.0 w144.hitbox.com -0.0.0.0 w147.hitbox.com -0.0.0.0 w14.hitbox.com -0.0.0.0 w153.hitbox.com -0.0.0.0 w154.hitbox.com -0.0.0.0 w155.hitbox.com -0.0.0.0 w157.hitbox.com -0.0.0.0 w159.hitbox.com -0.0.0.0 w15.hitbox.com -0.0.0.0 w161.hitbox.com -0.0.0.0 w162.hitbox.com -0.0.0.0 w167.hitbox.com -0.0.0.0 w168.hitbox.com -0.0.0.0 w16.hitbox.com -0.0.0.0 w170.hitbox.com -0.0.0.0 w175.hitbox.com -0.0.0.0 w177.hitbox.com -0.0.0.0 w179.hitbox.com -0.0.0.0 w17.hitbox.com -0.0.0.0 w18.hitbox.com -0.0.0.0 w19.hitbox.com -0.0.0.0 w1.hitbox.com -0.0.0.0 w20.hitbox.com -0.0.0.0 w21.hitbox.com -0.0.0.0 w22.hitbox.com -0.0.0.0 w23.hitbox.com -0.0.0.0 w24.hitbox.com -0.0.0.0 w25.hitbox.com -0.0.0.0 w26.hitbox.com -0.0.0.0 w27.hitbox.com -0.0.0.0 w28.hitbox.com -0.0.0.0 w29.hitbox.com -0.0.0.0 w2.hitbox.com -0.0.0.0 w30.hitbox.com -0.0.0.0 w31.hitbox.com -0.0.0.0 w32.hitbox.com -0.0.0.0 w33.hitbox.com -0.0.0.0 w34.hitbox.com -0.0.0.0 w35.hitbox.com -0.0.0.0 w36.hitbox.com -0.0.0.0 w3.hitbox.com -0.0.0.0 w4.hitbox.com -0.0.0.0 w5.hitbox.com -0.0.0.0 w6.hitbox.com -0.0.0.0 w7.hitbox.com -0.0.0.0 w8.hitbox.com -0.0.0.0 w9.hitbox.com -0.0.0.0 webload101.hitbox.com -0.0.0.0 wss-gw-1.hitbox.com -0.0.0.0 wss-gw-3.hitbox.com -0.0.0.0 wvwr1.hitbox.com -0.0.0.0 ww1.hitbox.com -0.0.0.0 ww2.hitbox.com -0.0.0.0 ww3.hitbox.com -0.0.0.0 wwa.hitbox.com -0.0.0.0 wwb.hitbox.com -0.0.0.0 wwc.hitbox.com -0.0.0.0 wwd.hitbox.com -0.0.0.0 www.ehg-rr.hitbox.com -0.0.0.0 www.hitbox.com -0.0.0.0 www.hitboxwireless.com -0.0.0.0 y2k.hitbox.com -0.0.0.0 yang.hitbox.com -0.0.0.0 ying.hitbox.com -# - -# - -# www.extreme-dm.com tracking -0.0.0.0 extreme-dm.com -0.0.0.0 reports.extreme-dm.com -0.0.0.0 t0.extreme-dm.com -0.0.0.0 t1.extreme-dm.com -0.0.0.0 t.extreme-dm.com -0.0.0.0 u0.extreme-dm.com -0.0.0.0 u1.extreme-dm.com -0.0.0.0 u.extreme-dm.com -0.0.0.0 v0.extreme-dm.com -0.0.0.0 v1.extreme-dm.com -0.0.0.0 v.extreme-dm.com -0.0.0.0 w0.extreme-dm.com -0.0.0.0 w1.extreme-dm.com -0.0.0.0 w2.extreme-dm.com -0.0.0.0 w3.extreme-dm.com -0.0.0.0 w4.extreme-dm.com -0.0.0.0 w5.extreme-dm.com -0.0.0.0 w6.extreme-dm.com -0.0.0.0 w7.extreme-dm.com -0.0.0.0 w8.extreme-dm.com -0.0.0.0 w9.extreme-dm.com -0.0.0.0 w.extreme-dm.com -0.0.0.0 www.extreme-dm.com -0.0.0.0 x3.extreme-dm.com -0.0.0.0 y0.extreme-dm.com -0.0.0.0 y1.extreme-dm.com -0.0.0.0 y.extreme-dm.com -0.0.0.0 z0.extreme-dm.com -0.0.0.0 z1.extreme-dm.com -0.0.0.0 z.extreme-dm.com -# - -# - -# realmedia.com's Open Ad Stream -0.0.0.0 ap.oasfile.aftenposten.no -0.0.0.0 imagenen1.247realmedia.com -0.0.0.0 oacentral.cepro.com -0.0.0.0 oas.adx.nu -0.0.0.0 oas.aurasports.com -0.0.0.0 oas.benchmark.fr -0.0.0.0 oasc03012.247realmedia.com -0.0.0.0 oasc03049.247realmedia.com -0.0.0.0 oasc06006.247realmedia.com -0.0.0.0 oasc08008.247realmedia.com -0.0.0.0 oasc09.247realmedia.com -0.0.0.0 oascentral.123greetings.com -0.0.0.0 oascentral.abclocal.go.com -0.0.0.0 oascentral.adage.com -0.0.0.0 oascentral.adageglobal.com -0.0.0.0 oascentral.aircanada.com -0.0.0.0 oascentral.alanicnewsnet.ca -0.0.0.0 oascentral.alanticnewsnet.ca -0.0.0.0 oascentral.americanheritage.com -0.0.0.0 oascentral.artistdirect.com -0.0.0.0 oascentral.artistirect.com -0.0.0.0 oascentral.askmen.com -0.0.0.0 oascentral.aviationnow.com -0.0.0.0 oascentral.blackenterprises.com -0.0.0.0 oascentral.blogher.org -0.0.0.0 oascentral.bostonherald.com -0.0.0.0 oascentral.bostonphoenix.com -0.0.0.0 oascentral.businessinsider.com -0.0.0.0 oascentral.businessweek.com -0.0.0.0 oascentral.businessweeks.com -0.0.0.0 oascentral.buy.com -0.0.0.0 oascentral.canadaeast.com -0.0.0.0 oascentral.canadianliving.com -0.0.0.0 oascentral.charleston.net -0.0.0.0 oascentral.chicagobusiness.com -0.0.0.0 oascentral.chron.com -0.0.0.0 oascentral.citypages.com -0.0.0.0 oascentral.clearchannel.com -0.0.0.0 oascentral.comcast.net -0.0.0.0 oascentral.comics.com -0.0.0.0 oascentral.construction.com -0.0.0.0 oascentral.consumerreports.org -0.0.0.0 oascentral.covers.com -0.0.0.0 oascentral.crainsdetroit.com -0.0.0.0 oascentral.crimelibrary.com -0.0.0.0 oascentral.cybereps.com -0.0.0.0 oascentral.dailybreeze.com -0.0.0.0 oascentral.dailyherald.com -0.0.0.0 oascentral.dilbert.com -0.0.0.0 oascentral.discovery.com -0.0.0.0 oascentral.drphil.com -0.0.0.0 oascentral.eastbayexpress.com -0.0.0.0 oas-central.east.realmedia.com -0.0.0.0 oascentral.encyclopedia.com -0.0.0.0 oascentral.fashionmagazine.com -0.0.0.0 oascentral.fayettevillenc.com -0.0.0.0 oascentral.feedroom.com -0.0.0.0 oascentral.forsythnews.com -0.0.0.0 oascentral.fortunecity.com -0.0.0.0 oascentral.foxnews.com -0.0.0.0 oascentral.freedom.com -0.0.0.0 oascentral.g4techtv.com -0.0.0.0 oascentral.ggl.com -0.0.0.0 oascentral.gigex.com -0.0.0.0 oascentral.globalpost.com -0.0.0.0 oascentral.hamptonroads.com -0.0.0.0 oascentral.hamptoroads.com -0.0.0.0 oascentral.hamtoroads.com -0.0.0.0 oascentral.herenb.com -0.0.0.0 oascentral.hollywood.com -0.0.0.0 oascentral.houstonpress.com -0.0.0.0 oascentral.inq7.net -0.0.0.0 oascentral.investors.com -0.0.0.0 oascentral.investorwords.com -0.0.0.0 oascentral.itbusiness.ca -0.0.0.0 oascentral.killsometime.com -0.0.0.0 oascentral.laptopmag.com -0.0.0.0 oascentral.law.com -0.0.0.0 oascentral.laweekly.com -0.0.0.0 oascentral.looksmart.com -0.0.0.0 oascentral.lycos.com -0.0.0.0 oascentral.mailtribune.com -0.0.0.0 oascentral.mayoclinic.com -0.0.0.0 oascentral.medbroadcast.com -0.0.0.0 oascentral.metro.us -0.0.0.0 oascentral.minnpost.com -0.0.0.0 oascentral.mochila.com -0.0.0.0 oascentral.motherjones.com -0.0.0.0 oascentral.nerve.com -0.0.0.0 oascentral.newsmax.com -0.0.0.0 oascentral.nowtoronto.com -0.0.0.0 oascentralnx.comcast.net -0.0.0.0 oascentral.onwisconsin.com -0.0.0.0 oascentral.phoenixnewtimes.com -0.0.0.0 oascentral.phoenixvillenews.com -0.0.0.0 oascentral.pitch.com -0.0.0.0 oascentral.poconorecord.com -0.0.0.0 oascentral.politico.com -0.0.0.0 oascentral.post-gazette.com -0.0.0.0 oascentral.pottsmerc.com -0.0.0.0 oascentral.princetonreview.com -0.0.0.0 oascentral.publicradio.org -0.0.0.0 oascentral.radaronline.com -0.0.0.0 oascentral.rcrnews.com -0.0.0.0 oas-central.realmedia.com -0.0.0.0 oascentral.redherring.com -0.0.0.0 oascentral.redorbit.com -0.0.0.0 oascentral.redstate.com -0.0.0.0 oascentral.reference.com -0.0.0.0 oascentral.regalinterative.com -0.0.0.0 oascentral.register.com -0.0.0.0 oascentral.registerguard.com -0.0.0.0 oascentral.registguard.com -0.0.0.0 oascentral.riverfronttimes.com -0.0.0.0 oascentral.salon.com -0.0.0.0 oascentral.santacruzsentinel.com -0.0.0.0 oascentral.sciam.com -0.0.0.0 oascentral.scientificamerican.com -0.0.0.0 oascentral.seacoastonline.com -0.0.0.0 oascentral.seattleweekly.com -0.0.0.0 oascentral.sfgate.com -0.0.0.0 oascentral.sfweekly.com -0.0.0.0 oascentral.sina.com -0.0.0.0 oascentral.sina.com.hk -0.0.0.0 oascentral.sparknotes.com -0.0.0.0 oascentral.sptimes.com -0.0.0.0 oascentral.starbulletin.com -0.0.0.0 oascentral.suntimes.com -0.0.0.0 oascentral.surfline.com -0.0.0.0 oascentral.thechronicleherald.ca -0.0.0.0 oascentral.thehockeynews.com -0.0.0.0 oascentral.thenation.com -0.0.0.0 oascentral.theonionavclub.com -0.0.0.0 oascentral.theonion.com -0.0.0.0 oascentral.thephoenix.com -0.0.0.0 oascentral.thesmokinggun.com -0.0.0.0 oascentral.thespark.com -0.0.0.0 oascentral.tmcnet.com -0.0.0.0 oascentral.tnr.com -0.0.0.0 oascentral.tourismvancouver.com -0.0.0.0 oascentral.townhall.com -0.0.0.0 oascentral.tribe.net -0.0.0.0 oascentral.trutv.com -0.0.0.0 oascentral.upi.com -0.0.0.0 oascentral.urbanspoon.com -0.0.0.0 oascentral.villagevoice.com -0.0.0.0 oascentral.virtualtourist.com -0.0.0.0 oascentral.warcry.com -0.0.0.0 oascentral.washtimes.com -0.0.0.0 oascentral.wciv.com -0.0.0.0 oascentral.westword.com -0.0.0.0 oascentral.where.ca -0.0.0.0 oascentral.wjla.com -0.0.0.0 oascentral.wkrn.com -0.0.0.0 oascentral.wwe.com -0.0.0.0 oascentral.yellowpages.com -0.0.0.0 oascentral.ywlloewpages.ca -0.0.0.0 oascentral.zwire.com -0.0.0.0 oascentreal.adcritic.com -0.0.0.0 oascetral.laweekly.com -0.0.0.0 oas.dispatch.com -0.0.0.0 oas.foxnews.com -0.0.0.0 oas.greensboro.com -0.0.0.0 oas.guardian.co.uk -0.0.0.0 oas.ibnlive.com -0.0.0.0 oas.lee.net -0.0.0.0 oas.nrjlink.fr -0.0.0.0 oas.nzz.ch -0.0.0.0 oas.portland.com -0.0.0.0 oas.publicitas.ch -0.0.0.0 oasroanoke.com -0.0.0.0 oas.salon.com -0.0.0.0 oas.sciencemag.org -0.0.0.0 oas.signonsandiego.com -0.0.0.0 oas.startribune.com -0.0.0.0 oas.toronto.com -0.0.0.0 oas.uniontrib.com -0.0.0.0 oas.villagevoice.com -0.0.0.0 oas.vtsgonline.com -# - -# - -# fastclick banner ads -0.0.0.0 media1.fastclick.net -0.0.0.0 media2.fastclick.net -0.0.0.0 media3.fastclick.net -0.0.0.0 media4.fastclick.net -0.0.0.0 media5.fastclick.net -0.0.0.0 media6.fastclick.net -0.0.0.0 media7.fastclick.net -0.0.0.0 media8.fastclick.net -0.0.0.0 media9.fastclick.net -0.0.0.0 media10.fastclick.net -0.0.0.0 media11.fastclick.net -0.0.0.0 media12.fastclick.net -0.0.0.0 media13.fastclick.net -0.0.0.0 media14.fastclick.net -0.0.0.0 media15.fastclick.net -0.0.0.0 media16.fastclick.net -0.0.0.0 media17.fastclick.net -0.0.0.0 media18.fastclick.net -0.0.0.0 media19.fastclick.net -0.0.0.0 media20.fastclick.net -0.0.0.0 media21.fastclick.net -0.0.0.0 media22.fastclick.net -0.0.0.0 media23.fastclick.net -0.0.0.0 media24.fastclick.net -0.0.0.0 media25.fastclick.net -0.0.0.0 media26.fastclick.net -0.0.0.0 media27.fastclick.net -0.0.0.0 media28.fastclick.net -0.0.0.0 media29.fastclick.net -0.0.0.0 media30.fastclick.net -0.0.0.0 media31.fastclick.net -0.0.0.0 media32.fastclick.net -0.0.0.0 media33.fastclick.net -0.0.0.0 media34.fastclick.net -0.0.0.0 media35.fastclick.net -0.0.0.0 media36.fastclick.net -0.0.0.0 media37.fastclick.net -0.0.0.0 media38.fastclick.net -0.0.0.0 media39.fastclick.net -0.0.0.0 media40.fastclick.net -0.0.0.0 media41.fastclick.net -0.0.0.0 media42.fastclick.net -0.0.0.0 media43.fastclick.net -0.0.0.0 media44.fastclick.net -0.0.0.0 media45.fastclick.net -0.0.0.0 media46.fastclick.net -0.0.0.0 media47.fastclick.net -0.0.0.0 media48.fastclick.net -0.0.0.0 media49.fastclick.net -0.0.0.0 media50.fastclick.net -0.0.0.0 media51.fastclick.net -0.0.0.0 media52.fastclick.net -0.0.0.0 media53.fastclick.net -0.0.0.0 media54.fastclick.net -0.0.0.0 media55.fastclick.net -0.0.0.0 media56.fastclick.net -0.0.0.0 media57.fastclick.net -0.0.0.0 media58.fastclick.net -0.0.0.0 media59.fastclick.net -0.0.0.0 media60.fastclick.net -0.0.0.0 media61.fastclick.net -0.0.0.0 media62.fastclick.net -0.0.0.0 media63.fastclick.net -0.0.0.0 media64.fastclick.net -0.0.0.0 media65.fastclick.net -0.0.0.0 media66.fastclick.net -0.0.0.0 media67.fastclick.net -0.0.0.0 media68.fastclick.net -0.0.0.0 media69.fastclick.net -0.0.0.0 media70.fastclick.net -0.0.0.0 media71.fastclick.net -0.0.0.0 media72.fastclick.net -0.0.0.0 media73.fastclick.net -0.0.0.0 media74.fastclick.net -0.0.0.0 media75.fastclick.net -0.0.0.0 media76.fastclick.net -0.0.0.0 media77.fastclick.net -0.0.0.0 media78.fastclick.net -0.0.0.0 media79.fastclick.net -0.0.0.0 media80.fastclick.net -0.0.0.0 media81.fastclick.net -0.0.0.0 media82.fastclick.net -0.0.0.0 media83.fastclick.net -0.0.0.0 media84.fastclick.net -0.0.0.0 media85.fastclick.net -0.0.0.0 media86.fastclick.net -0.0.0.0 media87.fastclick.net -0.0.0.0 media88.fastclick.net -0.0.0.0 media89.fastclick.net -0.0.0.0 media90.fastclick.net -0.0.0.0 media91.fastclick.net -0.0.0.0 media92.fastclick.net -0.0.0.0 media93.fastclick.net -0.0.0.0 media94.fastclick.net -0.0.0.0 media95.fastclick.net -0.0.0.0 media96.fastclick.net -0.0.0.0 media97.fastclick.net -0.0.0.0 media98.fastclick.net -0.0.0.0 media99.fastclick.net -0.0.0.0 fastclick.net -# - -# - -# belo interactive ads -0.0.0.0 te.about.com -0.0.0.0 te.adlandpro.com -0.0.0.0 te.advance.net -0.0.0.0 te.ap.org -0.0.0.0 te.astrology.com -0.0.0.0 te.audiencematch.net -0.0.0.0 te.belointeractive.com -0.0.0.0 te.boston.com -0.0.0.0 te.businessweek.com -0.0.0.0 te.chicagotribune.com -0.0.0.0 te.chron.com -0.0.0.0 te.cleveland.net -0.0.0.0 te.ctnow.com -0.0.0.0 te.dailycamera.com -0.0.0.0 te.dailypress.com -0.0.0.0 te.dentonrc.com -0.0.0.0 te.greenwichtime.com -0.0.0.0 te.idg.com -0.0.0.0 te.infoworld.com -0.0.0.0 te.ivillage.com -0.0.0.0 te.journalnow.com -0.0.0.0 te.latimes.com -0.0.0.0 te.mcall.com -0.0.0.0 te.mgnetwork.com -0.0.0.0 te.mysanantonio.com -0.0.0.0 te.newsday.com -0.0.0.0 te.nytdigital.com -0.0.0.0 te.orlandosentinel.com -0.0.0.0 te.scripps.com -0.0.0.0 te.scrippsnetworksprivacy.com -0.0.0.0 te.scrippsnewspapersprivacy.com -0.0.0.0 te.sfgate.com -0.0.0.0 te.signonsandiego.com -0.0.0.0 te.stamfordadvocate.com -0.0.0.0 te.sun-sentinel.com -0.0.0.0 te.sunspot.net -0.0.0.0 te.suntimes.com -0.0.0.0 te.tbo.com -0.0.0.0 te.thestar.ca -0.0.0.0 te.thestar.com -0.0.0.0 te.trb.com -0.0.0.0 te.versiontracker.com -0.0.0.0 te.wsls.com -# - -# - -# popup traps -- sites that bounce you around or won't let you leave -0.0.0.0 24hwebsex.com -0.0.0.0 adultfriendfinder.com -0.0.0.0 all-tgp.org -0.0.0.0 fioe.info -0.0.0.0 incestland.com -0.0.0.0 lesview.com -0.0.0.0 searchforit.com -0.0.0.0 www.asiansforu.com -0.0.0.0 www.bangbuddy.com -0.0.0.0 www.datanotary.com -0.0.0.0 www.entercasino.com -0.0.0.0 www.incestdot.com -0.0.0.0 www.incestgold.com -0.0.0.0 www.justhookup.com -0.0.0.0 www.mangayhentai.com -0.0.0.0 www.myluvcrush.ca -0.0.0.0 www.ourfuckbook.com -0.0.0.0 www.realincestvideos.com -0.0.0.0 www.searchforit.com -0.0.0.0 www.searchv.com -0.0.0.0 www.secretosx.com -0.0.0.0 www.seductiveamateurs.com -0.0.0.0 www.smsmovies.net -0.0.0.0 www.wowjs.1www.cn -0.0.0.0 www.xxxnations.com -0.0.0.0 www.xxxnightly.com -0.0.0.0 www.xxxtoolbar.com -0.0.0.0 www.yourfuckbook.com -# - -# - -# malicious e-card -- these sites send out mass quantities of spam - # and some distribute adware and spyware -0.0.0.0 123greetings.com # contains one link to distributor of adware or spyware -0.0.0.0 2000greetings.com -0.0.0.0 celebwelove.com -0.0.0.0 ecard4all.com -0.0.0.0 eforu.com -0.0.0.0 freewebcards.com -0.0.0.0 fukkad.com -0.0.0.0 fun-e-cards.com -0.0.0.0 funnyreign.com # heavy spam (Site Advisor received 1075 e-mails/week) -0.0.0.0 funsilly.com -0.0.0.0 myfuncards.com -0.0.0.0 www.cool-downloads.com -0.0.0.0 www.cool-downloads.net -0.0.0.0 www.friend-card.com -0.0.0.0 www.friend-cards.com -0.0.0.0 www.friend-cards.net -0.0.0.0 www.friend-greeting.com -0.0.0.0 www.friend-greetings.com -0.0.0.0 www.friendgreetings.com -0.0.0.0 www.friend-greetings.net -0.0.0.0 www.friendgreetings.net -0.0.0.0 www.laugh-mail.com -0.0.0.0 www.laugh-mail.net -# - -# - -# European network of tracking sites -0.0.0.0 0ivwbox.de -0.0.0.0 1ivwbox.de -0.0.0.0 1und1.ivwbox.de -0.0.0.0 2ivwbox.de -0.0.0.0 3ivwbox.de -0.0.0.0 4ivwbox.de -0.0.0.0 5ivwbox.de -0.0.0.0 6ivwbox.de -0.0.0.0 7ivwbox.de -0.0.0.0 8ivwbox.de -0.0.0.0 8vwbox.de -0.0.0.0 9ivwbox.de -0.0.0.0 9vwbox.de -0.0.0.0 aivwbox.de -0.0.0.0 avwbox.de -0.0.0.0 bild.ivwbox.de -0.0.0.0 bivwbox.de -0.0.0.0 civwbox.de -0.0.0.0 divwbox.de -0.0.0.0 eevwbox.de -0.0.0.0 eivwbox.de -0.0.0.0 evwbox.de -0.0.0.0 faz.ivwbox.de -0.0.0.0 fivwbox.de -0.0.0.0 givwbox.de -0.0.0.0 hivwbox.de -0.0.0.0 i8vwbox.de -0.0.0.0 i9vwbox.de -0.0.0.0 iavwbox.de -0.0.0.0 ibvwbox.de -0.0.0.0 ibwbox.de -0.0.0.0 icvwbox.de -0.0.0.0 icwbox.de -0.0.0.0 ievwbox.de -0.0.0.0 ifvwbox.de -0.0.0.0 ifwbox.de -0.0.0.0 igvwbox.de -0.0.0.0 igwbox.de -0.0.0.0 iivwbox.de -0.0.0.0 ijvwbox.de -0.0.0.0 ikvwbox.de -0.0.0.0 iovwbox.de -0.0.0.0 iuvwbox.de -0.0.0.0 iv2box.de -0.0.0.0 iv2wbox.de -0.0.0.0 iv3box.de -0.0.0.0 iv3wbox.de -0.0.0.0 ivabox.de -0.0.0.0 ivawbox.de -0.0.0.0 ivbox.de -0.0.0.0 ivbwbox.de -0.0.0.0 ivbwox.de -0.0.0.0 ivcwbox.de -0.0.0.0 ivebox.de -0.0.0.0 ivewbox.de -0.0.0.0 ivfwbox.de -0.0.0.0 ivgwbox.de -0.0.0.0 ivqbox.de -0.0.0.0 ivqwbox.de -0.0.0.0 ivsbox.de -0.0.0.0 ivswbox.de -0.0.0.0 ivvbox.de -0.0.0.0 ivvwbox.de -0.0.0.0 ivw2box.de -0.0.0.0 ivw3box.de -0.0.0.0 ivwabox.de -0.0.0.0 ivwb0ox.de -0.0.0.0 ivwb0x.de -0.0.0.0 ivwb9ox.de -0.0.0.0 ivwb9x.de -0.0.0.0 ivwbaox.de -0.0.0.0 ivwbax.de -0.0.0.0 ivwbbox.de -0.0.0.0 ivwbeox.de -0.0.0.0 ivwbex.de -0.0.0.0 ivwbgox.de -0.0.0.0 ivwbhox.de -0.0.0.0 ivwbiox.de -0.0.0.0 ivwbix.de -0.0.0.0 ivwbkox.de -0.0.0.0 ivwbkx.de -0.0.0.0 ivwblox.de -0.0.0.0 ivwblx.de -0.0.0.0 ivwbnox.de -0.0.0.0 ivwbo0x.de -0.0.0.0 ivwbo9x.de -0.0.0.0 ivwboax.de -0.0.0.0 ivwboc.de -0.0.0.0 ivwbock.de -0.0.0.0 ivwbocx.de -0.0.0.0 ivwbod.de -0.0.0.0 ivwbo.de -0.0.0.0 ivwbodx.de -0.0.0.0 ivwboex.de -0.0.0.0 ivwboix.de -0.0.0.0 ivwboks.de -0.0.0.0 ivwbokx.de -0.0.0.0 ivwbolx.de -0.0.0.0 ivwboox.de -0.0.0.0 ivwbopx.de -0.0.0.0 ivwbos.de -0.0.0.0 ivwbosx.de -0.0.0.0 ivwboux.de -0.0.0.0 ivwbox0.de -0.0.0.0 ivwbox1.de -0.0.0.0 ivwbox2.de -0.0.0.0 ivwbox3.de -0.0.0.0 ivwbox4.de -0.0.0.0 ivwbox5.de -0.0.0.0 ivwbox6.de -0.0.0.0 ivwbox7.de -0.0.0.0 ivwbox8.de -0.0.0.0 ivwbox9.de -0.0.0.0 ivwboxa.de -0.0.0.0 ivwboxb.de -0.0.0.0 ivwboxc.de -0.0.0.0 ivwboxd.de -0.0.0.0 ivwbox.de -0.0.0.0 ivwboxe.de -0.0.0.0 ivwboxes.de -0.0.0.0 ivwboxf.de -0.0.0.0 ivwboxg.de -0.0.0.0 ivwboxh.de -0.0.0.0 ivwboxi.de -0.0.0.0 ivwboxj.de -0.0.0.0 ivwboxk.de -0.0.0.0 ivwboxl.de -0.0.0.0 ivwboxm.de -0.0.0.0 ivwboxn.de -0.0.0.0 ivwboxo.de -0.0.0.0 ivwboxp.de -0.0.0.0 ivwboxq.de -0.0.0.0 ivwboxr.de -0.0.0.0 ivwboxs.de -0.0.0.0 ivwboxt.de -0.0.0.0 ivwboxu.de -0.0.0.0 ivwboxv.de -0.0.0.0 ivwboxw.de -0.0.0.0 ivwboxx.de -0.0.0.0 ivwboxy.de -0.0.0.0 ivwboxz.de -0.0.0.0 ivwboyx.de -0.0.0.0 ivwboz.de -0.0.0.0 ivwbozx.de -0.0.0.0 ivwbpox.de -0.0.0.0 ivwbpx.de -0.0.0.0 ivwbuox.de -0.0.0.0 ivwbux.de -0.0.0.0 ivwbvox.de -0.0.0.0 ivwbx.de -0.0.0.0 ivwbxo.de -0.0.0.0 ivwbyox.de -0.0.0.0 ivwbyx.de -0.0.0.0 ivwebox.de -0.0.0.0 ivwgbox.de -0.0.0.0 ivwgox.de -0.0.0.0 ivwhbox.de -0.0.0.0 ivwhox.de -0.0.0.0 ivwnbox.de -0.0.0.0 ivwnox.de -0.0.0.0 ivwobx.de -0.0.0.0 ivwox.de -0.0.0.0 ivwpbox.de -0.0.0.0 ivwpox.de -0.0.0.0 ivwqbox.de -0.0.0.0 ivwsbox.de -0.0.0.0 ivwvbox.de -0.0.0.0 ivwvox.de -0.0.0.0 ivwwbox.de -0.0.0.0 iwbox.de -0.0.0.0 iwvbox.de -0.0.0.0 iwvwbox.de -0.0.0.0 iwwbox.de -0.0.0.0 iyvwbox.de -0.0.0.0 jivwbox.de -0.0.0.0 jvwbox.de -0.0.0.0 kicker.ivwbox.de -0.0.0.0 kivwbox.de -0.0.0.0 kvwbox.de -0.0.0.0 livwbox.de -0.0.0.0 mivwbox.de -0.0.0.0 netzmarkt.ivwbox.de -0.0.0.0 nivwbox.de -0.0.0.0 ntv.ivwbox.de -0.0.0.0 oivwbox.de -0.0.0.0 onvis.ivwbox.de -0.0.0.0 ovwbox.de -0.0.0.0 pivwbox.de -0.0.0.0 qivwbox.de -0.0.0.0 rivwbox.de -0.0.0.0 sivwbox.de -0.0.0.0 spiegel.ivwbox.de -0.0.0.0 tivwbox.de -0.0.0.0 uivwbox.de -0.0.0.0 uvwbox.de -0.0.0.0 vivwbox.de -0.0.0.0 viwbox.de -0.0.0.0 vwbox.de -0.0.0.0 wivwbox.de -0.0.0.0 wwivwbox.de -0.0.0.0 www.0ivwbox.de -0.0.0.0 www.1ivwbox.de -0.0.0.0 www.2ivwbox.de -0.0.0.0 www.3ivwbox.de -0.0.0.0 www.4ivwbox.de -0.0.0.0 www.5ivwbox.de -0.0.0.0 www.6ivwbox.de -0.0.0.0 www.7ivwbox.de -0.0.0.0 www.8ivwbox.de -0.0.0.0 www.8vwbox.de -0.0.0.0 www.9ivwbox.de -0.0.0.0 www.9vwbox.de -0.0.0.0 www.aivwbox.de -0.0.0.0 www.avwbox.de -0.0.0.0 www.bivwbox.de -0.0.0.0 www.civwbox.de -0.0.0.0 www.divwbox.de -0.0.0.0 www.eevwbox.de -0.0.0.0 www.eivwbox.de -0.0.0.0 www.evwbox.de -0.0.0.0 www.fivwbox.de -0.0.0.0 www.givwbox.de -0.0.0.0 www.hivwbox.de -0.0.0.0 www.i8vwbox.de -0.0.0.0 www.i9vwbox.de -0.0.0.0 www.iavwbox.de -0.0.0.0 www.ibvwbox.de -0.0.0.0 www.ibwbox.de -0.0.0.0 www.icvwbox.de -0.0.0.0 www.icwbox.de -0.0.0.0 www.ievwbox.de -0.0.0.0 www.ifvwbox.de -0.0.0.0 www.ifwbox.de -0.0.0.0 www.igvwbox.de -0.0.0.0 www.igwbox.de -0.0.0.0 www.iivwbox.de -0.0.0.0 www.ijvwbox.de -0.0.0.0 www.ikvwbox.de -0.0.0.0 www.iovwbox.de -0.0.0.0 www.iuvwbox.de -0.0.0.0 www.iv2box.de -0.0.0.0 www.iv2wbox.de -0.0.0.0 www.iv3box.de -0.0.0.0 www.iv3wbox.de -0.0.0.0 www.ivabox.de -0.0.0.0 www.ivawbox.de -0.0.0.0 www.ivbox.de -0.0.0.0 www.ivbwbox.de -0.0.0.0 www.ivbwox.de -0.0.0.0 www.ivcwbox.de -0.0.0.0 www.ivebox.de -0.0.0.0 www.ivewbox.de -0.0.0.0 www.ivfwbox.de -0.0.0.0 www.ivgwbox.de -0.0.0.0 www.ivqbox.de -0.0.0.0 www.ivqwbox.de -0.0.0.0 www.ivsbox.de -0.0.0.0 www.ivswbox.de -0.0.0.0 www.ivvbox.de -0.0.0.0 www.ivvwbox.de -0.0.0.0 www.ivw2box.de -0.0.0.0 www.ivw3box.de -0.0.0.0 www.ivwabox.de -0.0.0.0 www.ivwb0ox.de -0.0.0.0 www.ivwb0x.de -0.0.0.0 www.ivwb9ox.de -0.0.0.0 www.ivwb9x.de -0.0.0.0 www.ivwbaox.de -0.0.0.0 www.ivwbax.de -0.0.0.0 www.ivwbbox.de -0.0.0.0 www.ivwbeox.de -0.0.0.0 www.ivwbex.de -0.0.0.0 www.ivwbgox.de -0.0.0.0 www.ivwbhox.de -0.0.0.0 www.ivwbiox.de -0.0.0.0 www.ivwbix.de -0.0.0.0 www.ivwbkox.de -0.0.0.0 www.ivwbkx.de -0.0.0.0 www.ivwblox.de -0.0.0.0 www.ivwblx.de -0.0.0.0 www.ivwbnox.de -0.0.0.0 www.ivwbo0x.de -0.0.0.0 www.ivwbo9x.de -0.0.0.0 www.ivwboax.de -0.0.0.0 www.ivwboc.de -0.0.0.0 www.ivwbock.de -0.0.0.0 www.ivwbocx.de -0.0.0.0 www.ivwbod.de -0.0.0.0 www.ivwbo.de -0.0.0.0 www.ivwbodx.de -0.0.0.0 www.ivwboex.de -0.0.0.0 www.ivwboix.de -0.0.0.0 www.ivwboks.de -0.0.0.0 www.ivwbokx.de -0.0.0.0 www.ivwbolx.de -0.0.0.0 www.ivwboox.de -0.0.0.0 www.ivwbopx.de -0.0.0.0 www.ivwbos.de -0.0.0.0 www.ivwbosx.de -0.0.0.0 www.ivwboux.de -0.0.0.0 www.ivwbox0.de -0.0.0.0 www.ivwbox1.de -0.0.0.0 www.ivwbox2.de -0.0.0.0 www.ivwbox3.de -0.0.0.0 www.ivwbox4.de -0.0.0.0 www.ivwbox5.de -0.0.0.0 www.ivwbox6.de -0.0.0.0 www.ivwbox7.de -0.0.0.0 www.ivwbox8.de -0.0.0.0 www.ivwbox9.de -0.0.0.0 www.ivwboxa.de -0.0.0.0 www.ivwboxb.de -0.0.0.0 www.ivwboxc.de -0.0.0.0 www.ivwboxd.de -0.0.0.0 www.ivwbox.de -0.0.0.0 wwwivwbox.de -0.0.0.0 www.ivwboxe.de -0.0.0.0 www.ivwboxes.de -0.0.0.0 www.ivwboxf.de -0.0.0.0 www.ivwboxg.de -0.0.0.0 www.ivwboxh.de -0.0.0.0 www.ivwboxi.de -0.0.0.0 www.ivwboxj.de -0.0.0.0 www.ivwboxk.de -0.0.0.0 www.ivwboxl.de -0.0.0.0 www.ivwboxm.de -0.0.0.0 www.ivwboxn.de -0.0.0.0 www.ivwboxo.de -0.0.0.0 www.ivwboxp.de -0.0.0.0 www.ivwboxq.de -0.0.0.0 www.ivwboxr.de -0.0.0.0 www.ivwboxs.de -0.0.0.0 www.ivwboxt.de -0.0.0.0 www.ivwboxu.de -0.0.0.0 www.ivwboxv.de -0.0.0.0 www.ivwboxw.de -0.0.0.0 www.ivwboxx.de -0.0.0.0 www.ivwboxy.de -0.0.0.0 www.ivwboxz.de -0.0.0.0 www.ivwboyx.de -0.0.0.0 www.ivwboz.de -0.0.0.0 www.ivwbozx.de -0.0.0.0 www.ivwbpox.de -0.0.0.0 www.ivwbpx.de -0.0.0.0 www.ivwbuox.de -0.0.0.0 www.ivwbux.de -0.0.0.0 www.ivwbvox.de -0.0.0.0 www.ivwbx.de -0.0.0.0 www.ivwbxo.de -0.0.0.0 www.ivwbyox.de -0.0.0.0 www.ivwbyx.de -0.0.0.0 www.ivwebox.de -0.0.0.0 www.ivwgbox.de -0.0.0.0 www.ivwgox.de -0.0.0.0 www.ivwhbox.de -0.0.0.0 www.ivwhox.de -0.0.0.0 www.ivwnbox.de -0.0.0.0 www.ivwnox.de -0.0.0.0 www.ivwobx.de -0.0.0.0 www.ivwox.de -0.0.0.0 www.ivwpbox.de -0.0.0.0 www.ivwpox.de -0.0.0.0 www.ivwqbox.de -0.0.0.0 www.ivwsbox.de -0.0.0.0 www.ivwvbox.de -0.0.0.0 www.ivwvox.de -0.0.0.0 www.ivwwbox.de -0.0.0.0 www.iwbox.de -0.0.0.0 www.iwvbox.de -0.0.0.0 www.iwvwbox.de -0.0.0.0 www.iwwbox.de -0.0.0.0 www.iyvwbox.de -0.0.0.0 www.jivwbox.de -0.0.0.0 www.jvwbox.de -0.0.0.0 www.kivwbox.de -0.0.0.0 www.kvwbox.de -0.0.0.0 www.livwbox.de -0.0.0.0 www.mivwbox.de -0.0.0.0 www.nivwbox.de -0.0.0.0 www.oivwbox.de -0.0.0.0 www.ovwbox.de -0.0.0.0 www.pivwbox.de -0.0.0.0 www.qivwbox.de -0.0.0.0 www.rivwbox.de -0.0.0.0 www.sivwbox.de -0.0.0.0 www.tivwbox.de -0.0.0.0 www.uivwbox.de -0.0.0.0 www.uvwbox.de -0.0.0.0 www.vivwbox.de -0.0.0.0 www.viwbox.de -0.0.0.0 www.vwbox.de -0.0.0.0 www.wivwbox.de -0.0.0.0 www.wwivwbox.de -0.0.0.0 www.wwwivwbox.de -0.0.0.0 www.xivwbox.de -0.0.0.0 www.yevwbox.de -0.0.0.0 www.yivwbox.de -0.0.0.0 www.yvwbox.de -0.0.0.0 www.zivwbox.de -0.0.0.0 xivwbox.de -0.0.0.0 yevwbox.de -0.0.0.0 yivwbox.de -0.0.0.0 yvwbox.de -0.0.0.0 zivwbox.de -# - -# - -# message board and wiki spam -- these sites are linked in - # message board spam and are unlikely to be real sites -0.0.0.0 10pg.scl5fyd.info -0.0.0.0 21jewelry.com -0.0.0.0 24x7.soliday.org -0.0.0.0 2site.com -0.0.0.0 33b.b33r.net -0.0.0.0 48.2mydns.net -0.0.0.0 4allfree.com -0.0.0.0 55.2myip.com -0.0.0.0 6165.rapidforum.com -0.0.0.0 6pg.ryf3hgf.info -0.0.0.0 7x7.ruwe.net -0.0.0.0 7x.cc -0.0.0.0 911.x24hr.com -0.0.0.0 ab.5.p2l.info -0.0.0.0 aboutharrypotter.fasthost.tv -0.0.0.0 aciphex.about-tabs.com -0.0.0.0 actonel.about-tabs.com -0.0.0.0 actos.about-tabs.com -0.0.0.0 acyclovir.1.p2l.info -0.0.0.0 adderall.ourtablets.com -0.0.0.0 adderallxr.freespaces.com -0.0.0.0 adipex.1.p2l.info -0.0.0.0 adipex.24sws.ws -0.0.0.0 adipex.3.p2l.info -0.0.0.0 adipex.4.p2l.info -0.0.0.0 adipex.hut1.ru -0.0.0.0 adipex.ourtablets.com -0.0.0.0 adipexp.3xforum.ro -0.0.0.0 adipex.shengen.ru -0.0.0.0 adipex.t-amo.net -0.0.0.0 adsearch.www1.biz -0.0.0.0 adult.shengen.ru -0.0.0.0 aguileranude.1stOK.com -0.0.0.0 ahh-teens.com -0.0.0.0 aid-golf-golfdust-training.tabrays.com -0.0.0.0 airline-ticket.gloses.net -0.0.0.0 air-plane-ticket.beesearch.info -0.0.0.0 ak.5.p2l.info -0.0.0.0 al.5.p2l.info -0.0.0.0 alcohol-treatment.gloses.net -0.0.0.0 allegra.1.p2l.info -0.0.0.0 allergy.1.p2l.info -0.0.0.0 all-sex.shengen.ru -0.0.0.0 alprazolamonline.findmenow.info -0.0.0.0 alprazolam.ourtablets.com -0.0.0.0 alyssamilano.1stOK.com -0.0.0.0 alyssamilano.ca.tt -0.0.0.0 alyssamilano.home.sapo.pt -0.0.0.0 amateur-mature-sex.adaltabaza.net -0.0.0.0 ambien.1.p2l.info -0.0.0.0 ambien.3.p2l.info -0.0.0.0 ambien.4.p2l.info -0.0.0.0 ambien.ourtablets.com -0.0.0.0 amoxicillin.ourtablets.com -0.0.0.0 angelinajolie.1stOK.com -0.0.0.0 angelinajolie.ca.tt -0.0.0.0 anklets.shengen.ru -0.0.0.0 annanicolesannanicolesmith.ca.tt -0.0.0.0 annanicolesmith.1stOK.com -0.0.0.0 antidepressants.1.p2l.info -0.0.0.0 anxiety.1.p2l.info -0.0.0.0 aol.spb.su -0.0.0.0 ar.5.p2l.info -0.0.0.0 arcade.ya.com -0.0.0.0 armanix.white.prohosting.com -0.0.0.0 arthritis.atspace.com -0.0.0.0 as.5.p2l.info -0.0.0.0 aspirin.about-tabs.com -0.0.0.0 ativan.ourtablets.com -0.0.0.0 austria-car-rental.findworm.net -0.0.0.0 auto.allewagen.de -0.0.0.0 az.5.p2l.info -0.0.0.0 azz.badazz.org -0.0.0.0 balabass.peerserver.com -0.0.0.0 balab.portx.net -0.0.0.0 bbs.ws -0.0.0.0 bc.5.p2l.info -0.0.0.0 beauty.finaltips.com -0.0.0.0 berkleynude.ca.tt -0.0.0.0 bestlolaray.com -0.0.0.0 bet-online.petrovka.info -0.0.0.0 betting-online.petrovka.info -0.0.0.0 bextra.ourtablets.com -0.0.0.0 bextra-store.shengen.ru -0.0.0.0 bingo-online.petrovka.info -0.0.0.0 birth-control.1.p2l.info -0.0.0.0 bontril.1.p2l.info -0.0.0.0 bontril.ourtablets.com -0.0.0.0 britneyspears.1stOK.com -0.0.0.0 britneyspears.ca.tt -0.0.0.0 br.rawcomm.net -0.0.0.0 bupropion-hcl.1.p2l.info -0.0.0.0 buspar.1.p2l.info -0.0.0.0 buspirone.1.p2l.info -0.0.0.0 butalbital-apap.1.p2l.info -0.0.0.0 buy-adipex.aca.ru -0.0.0.0 buy-adipex-cheap-adipex-online.com -0.0.0.0 buy-adipex.hut1.ru -0.0.0.0 buy-adipex.i-jogo.net -0.0.0.0 buy-adipex-online.md-online24.de -0.0.0.0 buy-adipex.petrovka.info -0.0.0.0 buy-carisoprodol.polybuild.ru -0.0.0.0 buy-cheap-phentermine.blogspot.com -0.0.0.0 buy-cheap-xanax.all.at -0.0.0.0 buy-cialis-cheap-cialis-online.info -0.0.0.0 buy-cialis.freewebtools.com -0.0.0.0 buycialisonline.7h.com -0.0.0.0 buycialisonline.bigsitecity.com -0.0.0.0 buy-cialis-online.iscool.nl -0.0.0.0 buy-cialis-online.meperdoe.net -0.0.0.0 buy-cialis.splinder.com -0.0.0.0 buy-diazepam.connect.to -0.0.0.0 buyfioricet.findmenow.info -0.0.0.0 buy-fioricet.hut1.ru -0.0.0.0 buyfioricetonline.7h.com -0.0.0.0 buyfioricetonline.bigsitecity.com -0.0.0.0 buyfioricetonline.freeservers.com -0.0.0.0 buy-flower.petrovka.info -0.0.0.0 buy-hydrocodone.aca.ru -0.0.0.0 buyhydrocodone.all.at -0.0.0.0 buy-hydrocodone-cheap-hydrocodone-online.com -0.0.0.0 buy-hydrocodone.este.ru -0.0.0.0 buyhydrocodoneonline.findmenow.info -0.0.0.0 buy-hydrocodone-online.tche.com -0.0.0.0 buy-hydrocodone.petrovka.info -0.0.0.0 buy-hydrocodone.polybuild.ru -0.0.0.0 buy-hydrocodone.quesaudade.net -0.0.0.0 buy-hydrocodone.scromble.com -0.0.0.0 buylevitra.3xforum.ro -0.0.0.0 buy-levitra-cheap-levitra-online.info -0.0.0.0 buylevitraonline.7h.com -0.0.0.0 buylevitraonline.bigsitecity.com -0.0.0.0 buy-lortab-cheap-lortab-online.com -0.0.0.0 buy-lortab.hut1.ru -0.0.0.0 buylortabonline.7h.com -0.0.0.0 buylortabonline.bigsitecity.com -0.0.0.0 buy-lortab-online.iscool.nl -0.0.0.0 buypaxilonline.7h.com -0.0.0.0 buypaxilonline.bigsitecity.com -0.0.0.0 buy-phentermine-cheap-phentermine-online.com -0.0.0.0 buy-phentermine.hautlynx.com -0.0.0.0 buy-phentermine-online.135.it -0.0.0.0 buyphentermineonline.7h.com -0.0.0.0 buyphentermineonline.bigsitecity.com -0.0.0.0 buy-phentermine-online.i-jogo.net -0.0.0.0 buy-phentermine-online.i-ltda.net -0.0.0.0 buy-phentermine.polybuild.ru -0.0.0.0 buy-phentermine.thepizza.net -0.0.0.0 buy-tamiflu.asian-flu-vaccine.com -0.0.0.0 buy-ultram-online.iscool.nl -0.0.0.0 buy-valium-cheap-valium-online.com -0.0.0.0 buy-valium.este.ru -0.0.0.0 buy-valium.hut1.ru -0.0.0.0 buy-valium.polybuild.ru -0.0.0.0 buyvalium.polybuild.ru -0.0.0.0 buy-viagra.aca.ru -0.0.0.0 buy-viagra.go.to -0.0.0.0 buy-viagra.polybuild.ru -0.0.0.0 buyviagra.polybuild.ru -0.0.0.0 buy-vicodin-cheap-vicodin-online.com -0.0.0.0 buy-vicodin.dd.vu -0.0.0.0 buy-vicodin.hut1.ru -0.0.0.0 buy-vicodin.iscool.nl -0.0.0.0 buy-vicodin-online.i-blog.net -0.0.0.0 buy-vicodin-online.seumala.net -0.0.0.0 buy-vicodin-online.supersite.fr -0.0.0.0 buyvicodinonline.veryweird.com -0.0.0.0 buy-xanax.aztecaonline.net -0.0.0.0 buy-xanax-cheap-xanax-online.com -0.0.0.0 buy-xanax.hut1.ru -0.0.0.0 buy-xanax-online.amovoce.net -0.0.0.0 buy-zyban.all.at -0.0.0.0 bx6.blrf.net -0.0.0.0 ca.5.p2l.info -0.0.0.0 camerondiaznude.1stOK.com -0.0.0.0 camerondiaznude.ca.tt -0.0.0.0 car-donation.shengen.ru -0.0.0.0 car-insurance.inshurance-from.com -0.0.0.0 carisoprodol.1.p2l.info -0.0.0.0 carisoprodol.hut1.ru -0.0.0.0 carisoprodol.ourtablets.com -0.0.0.0 carisoprodol.polybuild.ru -0.0.0.0 carisoprodol.shengen.ru -0.0.0.0 car-loan.shengen.ru -0.0.0.0 carmenelectra.1stOK.com -0.0.0.0 cash-advance.now-cash.com -0.0.0.0 casino-gambling-online.searchservice.info -0.0.0.0 casino-online.100gal.net -0.0.0.0 cat.onlinepeople.net -0.0.0.0 cc5f.dnyp.com -0.0.0.0 celebrex.1.p2l.info -0.0.0.0 celexa.1.p2l.info -0.0.0.0 celexa.3.p2l.info -0.0.0.0 celexa.4.p2l.info -0.0.0.0 cephalexin.ourtablets.com -0.0.0.0 charlizetheron.1stOK.com -0.0.0.0 cheap-adipex.hut1.ru -0.0.0.0 cheap-carisoprodol.polybuild.ru -0.0.0.0 cheap-hydrocodone.go.to -0.0.0.0 cheap-hydrocodone.polybuild.ru -0.0.0.0 cheap-phentermine.polybuild.ru -0.0.0.0 cheap-valium.polybuild.ru -0.0.0.0 cheap-viagra.polybuild.ru -0.0.0.0 cheap-web-hosting-here.blogspot.com -0.0.0.0 cheap-xanax-here.blogspot.com -0.0.0.0 cheapxanax.hut1.ru -0.0.0.0 cialis.1.p2l.info -0.0.0.0 cialis.3.p2l.info -0.0.0.0 cialis.4.p2l.info -0.0.0.0 cialis-finder.com -0.0.0.0 cialis-levitra-viagra.com.cn -0.0.0.0 cialis.ourtablets.com -0.0.0.0 cialis-store.shengen.ru -0.0.0.0 co.5.p2l.info -0.0.0.0 co.dcclan.co.uk -0.0.0.0 codeine.ourtablets.com -0.0.0.0 creampie.afdss.info -0.0.0.0 credit-card-application.now-cash.com -0.0.0.0 credit-cards.shengen.ru -0.0.0.0 ct.5.p2l.info -0.0.0.0 cuiland.info -0.0.0.0 cyclobenzaprine.1.p2l.info -0.0.0.0 cyclobenzaprine.ourtablets.com -0.0.0.0 dal.d.la -0.0.0.0 danger-phentermine.allforyourlife.com -0.0.0.0 darvocet.ourtablets.com -0.0.0.0 dc.5.p2l.info -0.0.0.0 de.5.p2l.info -0.0.0.0 debt.shengen.ru -0.0.0.0 def.5.p2l.info -0.0.0.0 demimoorenude.1stOK.com -0.0.0.0 deniserichards.1stOK.com -0.0.0.0 detox-kit.com -0.0.0.0 detox.shengen.ru -0.0.0.0 diazepam.ourtablets.com -0.0.0.0 diazepam.razma.net -0.0.0.0 diazepam.shengen.ru -0.0.0.0 didrex.1.p2l.info -0.0.0.0 diet-pills.hut1.ru -0.0.0.0 digital-cable-descrambler.planet-high-heels.com -0.0.0.0 dir.opank.com -0.0.0.0 dos.velek.com -0.0.0.0 drewbarrymore.ca.tt -0.0.0.0 drugdetox.shengen.ru -0.0.0.0 drug-online.petrovka.info -0.0.0.0 drug-testing.shengen.ru -0.0.0.0 eb.dd.bluelinecomputers.be -0.0.0.0 eb.prout.be -0.0.0.0 ed.at.is13.de -0.0.0.0 ed.at.thamaster.de -0.0.0.0 e-dot.hut1.ru -0.0.0.0 efam4.info -0.0.0.0 effexor-xr.1.p2l.info -0.0.0.0 e-hosting.hut1.ru -0.0.0.0 ei.imbucurator-de-prost.com -0.0.0.0 eminemticket.freespaces.com -0.0.0.0 en.dd.blueline.be -0.0.0.0 enpresse.1.p2l.info -0.0.0.0 en.ultrex.ru -0.0.0.0 epson-printer-ink.beesearch.info -0.0.0.0 erectile.byethost33.com -0.0.0.0 esgic.1.p2l.info -0.0.0.0 fahrrad.bikesshop.de -0.0.0.0 famous-pics.com -0.0.0.0 famvir.1.p2l.info -0.0.0.0 farmius.org -0.0.0.0 fee-hydrocodone.bebto.com -0.0.0.0 female-v.1.p2l.info -0.0.0.0 femaleviagra.findmenow.info -0.0.0.0 fg.softguy.com -0.0.0.0 findmenow.info -0.0.0.0 fioricet.1.p2l.info -0.0.0.0 fioricet.3.p2l.info -0.0.0.0 fioricet.4.p2l.info -0.0.0.0 fioricet-online.blogspot.com -0.0.0.0 firstfinda.info -0.0.0.0 fl.5.p2l.info -0.0.0.0 flexeril.1.p2l.info -0.0.0.0 flextra.1.p2l.info -0.0.0.0 flonase.1.p2l.info -0.0.0.0 flonase.3.p2l.info -0.0.0.0 flonase.4.p2l.info -0.0.0.0 florineff.ql.st -0.0.0.0 flower-online.petrovka.info -0.0.0.0 fluoxetine.1.p2l.info -0.0.0.0 fo4n.com -0.0.0.0 forex-broker.hut1.ru -0.0.0.0 forex-chart.hut1.ru -0.0.0.0 forex-market.hut1.ru -0.0.0.0 forex-news.hut1.ru -0.0.0.0 forex-online.hut1.ru -0.0.0.0 forex-signal.hut1.ru -0.0.0.0 forex-trade.hut1.ru -0.0.0.0 forex-trading-benefits.blogspot.com -0.0.0.0 forextrading.hut1.ru -0.0.0.0 freechat.llil.de -0.0.0.0 free.hostdepartment.com -0.0.0.0 free-money.host.sk -0.0.0.0 free-viagra.polybuild.ru -0.0.0.0 free-virus-scan.100gal.net -0.0.0.0 ga.5.p2l.info -0.0.0.0 game-online-video.petrovka.info -0.0.0.0 gaming-online.petrovka.info -0.0.0.0 gastrointestinal.1.p2l.info -0.0.0.0 gen-hydrocodone.polybuild.ru -0.0.0.0 getcarisoprodol.polybuild.ru -0.0.0.0 gocarisoprodol.polybuild.ru -0.0.0.0 gsm-mobile-phone.beesearch.info -0.0.0.0 gu.5.p2l.info -0.0.0.0 guerria-skateboard-tommy.tabrays.com -0.0.0.0 gwynethpaltrow.ca.tt -0.0.0.0 h1.ripway.com -0.0.0.0 hair-dos.resourcesarchive.com -0.0.0.0 halleberrynude.ca.tt -0.0.0.0 heathergraham.ca.tt -0.0.0.0 herpes.1.p2l.info -0.0.0.0 herpes.3.p2l.info -0.0.0.0 herpes.4.p2l.info -0.0.0.0 hf.themafia.info -0.0.0.0 hi.5.p2l.info -0.0.0.0 hi.pacehillel.org -0.0.0.0 holobumo.info -0.0.0.0 homehre.bravehost.com -0.0.0.0 homehre.ifrance.com -0.0.0.0 homehre.tripod.com -0.0.0.0 hoodia.kogaryu.com -0.0.0.0 hotel-las-vegas.gloses.net -0.0.0.0 hydrocodone-buy-online.blogspot.com -0.0.0.0 hydrocodone.irondel.swisshost.by -0.0.0.0 hydrocodone.on.to -0.0.0.0 hydrocodone.shengen.ru -0.0.0.0 hydrocodone.t-amo.net -0.0.0.0 hydrocodone.visa-usa.ru -0.0.0.0 hydro.polybuild.ru -0.0.0.0 ia.5.p2l.info -0.0.0.0 ia.warnet-thunder.net -0.0.0.0 ibm-notebook-battery.wp-club.net -0.0.0.0 id.5.p2l.info -0.0.0.0 il.5.p2l.info -0.0.0.0 imitrex.1.p2l.info -0.0.0.0 imitrex.3.p2l.info -0.0.0.0 imitrex.4.p2l.info -0.0.0.0 in.5.p2l.info -0.0.0.0 ionamin.1.p2l.info -0.0.0.0 ionamin.t35.com -0.0.0.0 irondel.swisshost.by -0.0.0.0 japanese-girl-xxx.com -0.0.0.0 java-games.bestxs.de -0.0.0.0 jg.hack-inter.net -0.0.0.0 job-online.petrovka.info -0.0.0.0 jobs-online.petrovka.info -0.0.0.0 kitchen-island.mensk.us -0.0.0.0 konstantin.freespaces.com -0.0.0.0 ks.5.p2l.info -0.0.0.0 ky.5.p2l.info -0.0.0.0 la.5.p2l.info -0.0.0.0 lamictal.about-tabs.com -0.0.0.0 lamisil.about-tabs.com -0.0.0.0 levitra.1.p2l.info -0.0.0.0 levitra.3.p2l.info -0.0.0.0 levitra.4.p2l.info -0.0.0.0 lexapro.1.p2l.info -0.0.0.0 lexapro.3.p2l.info -0.0.0.0 lexapro.4.p2l.info -0.0.0.0 loan.aol.msk.su -0.0.0.0 loan.maybachexelero.org -0.0.0.0 loestrin.1.p2l.info -0.0.0.0 lo.ljkeefeco.com -0.0.0.0 lol.to -0.0.0.0 lortab-cod.hut1.ru -0.0.0.0 lortab.hut1.ru -0.0.0.0 ma.5.p2l.info -0.0.0.0 mailforfreedom.com -0.0.0.0 make-money.shengen.ru -0.0.0.0 maps-antivert58.eksuziv.net -0.0.0.0 maps-spyware251-300.eksuziv.net -0.0.0.0 marketing.beesearch.info -0.0.0.0 mb.5.p2l.info -0.0.0.0 mba-online.petrovka.info -0.0.0.0 md.5.p2l.info -0.0.0.0 me.5.p2l.info -0.0.0.0 medical.carway.net -0.0.0.0 mens.1.p2l.info -0.0.0.0 meridia.1.p2l.info -0.0.0.0 meridia.3.p2l.info -0.0.0.0 meridia.4.p2l.info -0.0.0.0 meridiameridia.3xforum.ro -0.0.0.0 mesotherapy.jino-net.ru -0.0.0.0 mi.5.p2l.info -0.0.0.0 micardiss.ql.st -0.0.0.0 microsoft-sql-server.wp-club.net -0.0.0.0 mn.5.p2l.info -0.0.0.0 mo.5.p2l.info -0.0.0.0 moc.silk.com -0.0.0.0 mortgage-memphis.hotmail.ru -0.0.0.0 mortgage-rates.now-cash.com -0.0.0.0 mp.5.p2l.info -0.0.0.0 mrjeweller.us -0.0.0.0 ms.5.p2l.info -0.0.0.0 mt.5.p2l.info -0.0.0.0 multimedia-projector.katrina.ru -0.0.0.0 muscle-relaxers.1.p2l.info -0.0.0.0 music102.awardspace.com -0.0.0.0 mydaddy.b0x.com -0.0.0.0 myphentermine.polybuild.ru -0.0.0.0 nasacort.1.p2l.info -0.0.0.0 nasonex.1.p2l.info -0.0.0.0 nb.5.p2l.info -0.0.0.0 nc.5.p2l.info -0.0.0.0 nd.5.p2l.info -0.0.0.0 ne.5.p2l.info -0.0.0.0 nellyticket.beast-space.com -0.0.0.0 nelsongod.ca -0.0.0.0 nexium.1.p2l.info -0.0.0.0 nextel-ringtone.komi.su -0.0.0.0 nextel-ringtone.spb.su -0.0.0.0 nf.5.p2l.info -0.0.0.0 nh.5.p2l.info -0.0.0.0 nj.5.p2l.info -0.0.0.0 nm.5.p2l.info -0.0.0.0 nordette.1.p2l.info -0.0.0.0 nordette.3.p2l.info -0.0.0.0 nordette.4.p2l.info -0.0.0.0 norton-antivirus-trial.searchservice.info -0.0.0.0 notebook-memory.searchservice.info -0.0.0.0 ns.5.p2l.info -0.0.0.0 nv.5.p2l.info -0.0.0.0 ny.5.p2l.info -0.0.0.0 o8.aus.cc -0.0.0.0 ofni.al0ne.info -0.0.0.0 oh.5.p2l.info -0.0.0.0 ok.5.p2l.info -0.0.0.0 on.5.p2l.info -0.0.0.0 online-auto-insurance.petrovka.info -0.0.0.0 online-bingo.petrovka.info -0.0.0.0 online-broker.petrovka.info -0.0.0.0 online-cash.petrovka.info -0.0.0.0 online-casino.shengen.ru -0.0.0.0 online-casino.webpark.pl -0.0.0.0 online-cigarettes.hitslog.net -0.0.0.0 online-college.petrovka.info -0.0.0.0 online-degree.petrovka.info -0.0.0.0 online-florist.petrovka.info -0.0.0.0 online-forex.hut1.ru -0.0.0.0 online-forex-trading-systems.blogspot.com -0.0.0.0 online-gaming.petrovka.info -0.0.0.0 online-job.petrovka.info -0.0.0.0 online-loan.petrovka.info -0.0.0.0 online-mortgage.petrovka.info -0.0.0.0 online-personal.petrovka.info -0.0.0.0 online-personals.petrovka.info -0.0.0.0 online-pharmacy-online.blogspot.com -0.0.0.0 online-pharmacy.petrovka.info -0.0.0.0 online-phentermine.petrovka.info -0.0.0.0 online-poker-gambling.petrovka.info -0.0.0.0 online-poker-game.petrovka.info -0.0.0.0 online-poker.shengen.ru -0.0.0.0 online-prescription.petrovka.info -0.0.0.0 online-school.petrovka.info -0.0.0.0 online-schools.petrovka.info -0.0.0.0 online-single.petrovka.info -0.0.0.0 online-tarot-reading.beesearch.info -0.0.0.0 online-travel.petrovka.info -0.0.0.0 online-university.petrovka.info -0.0.0.0 online-viagra.petrovka.info -0.0.0.0 online-xanax.petrovka.info -0.0.0.0 onlypreteens.com -0.0.0.0 only-valium.go.to -0.0.0.0 only-valium.shengen.ru -0.0.0.0 or.5.p2l.info -0.0.0.0 oranla.info -0.0.0.0 orderadipex.findmenow.info -0.0.0.0 order-hydrocodone.polybuild.ru -0.0.0.0 order-phentermine.polybuild.ru -0.0.0.0 order-valium.polybuild.ru -0.0.0.0 ortho-tri-cyclen.1.p2l.info -0.0.0.0 pa.5.p2l.info -0.0.0.0 pacific-poker.e-online-poker-4u.net -0.0.0.0 pain-relief.1.p2l.info -0.0.0.0 paintball-gun.tripod.com -0.0.0.0 patio-furniture.dreamhoster.com -0.0.0.0 paxil.1.p2l.info -0.0.0.0 pay-day-loans.beesearch.info -0.0.0.0 payday-loans.now-cash.com -0.0.0.0 pctuzing.php5.cz -0.0.0.0 pd1.funnyhost.com -0.0.0.0 pe.5.p2l.info -0.0.0.0 peter-north-cum-shot.blogspot.com -0.0.0.0 pets.finaltips.com -0.0.0.0 pharmacy-canada.forsearch.net -0.0.0.0 pharmacy.hut1.ru -0.0.0.0 pharmacy-news.blogspot.com -0.0.0.0 pharmacy-online.petrovka.info -0.0.0.0 phendimetrazine.1.p2l.info -0.0.0.0 phentermine.1.p2l.info -0.0.0.0 phentermine.3.p2l.info -0.0.0.0 phentermine.4.p2l.info -0.0.0.0 phentermine.aussie7.com -0.0.0.0 phentermine-buy-online.hitslog.net -0.0.0.0 phentermine-buy.petrovka.info -0.0.0.0 phentermine-online.iscool.nl -0.0.0.0 phentermine-online.petrovka.info -0.0.0.0 phentermine.petrovka.info -0.0.0.0 phentermine.polybuild.ru -0.0.0.0 phentermine.shengen.ru -0.0.0.0 phentermine.t-amo.net -0.0.0.0 phentermine.webpark.pl -0.0.0.0 phone-calling-card.exnet.su -0.0.0.0 plavix.shengen.ru -0.0.0.0 play-poker-free.forsearch.net -0.0.0.0 poker-games.e-online-poker-4u.net -0.0.0.0 pop.egi.biz -0.0.0.0 pr.5.p2l.info -0.0.0.0 prescription-drugs.easy-find.net -0.0.0.0 prescription-drugs.shengen.ru -0.0.0.0 preteenland.com -0.0.0.0 preteensite.com -0.0.0.0 prevacid.1.p2l.info -0.0.0.0 prevent-asian-flu.com -0.0.0.0 prilosec.1.p2l.info -0.0.0.0 propecia.1.p2l.info -0.0.0.0 protonix.shengen.ru -0.0.0.0 psorias.atspace.com -0.0.0.0 purchase.hut1.ru -0.0.0.0 qc.5.p2l.info -0.0.0.0 qz.informs.com -0.0.0.0 refinance.shengen.ru -0.0.0.0 relenza.asian-flu-vaccine.com -0.0.0.0 renova.1.p2l.info -0.0.0.0 replacement-windows.gloses.net -0.0.0.0 re.rutan.org -0.0.0.0 resanium.com -0.0.0.0 retin-a.1.p2l.info -0.0.0.0 ri.5.p2l.info -0.0.0.0 rise-media.ru -0.0.0.0 root.dns.bz -0.0.0.0 roulette-online.petrovka.info -0.0.0.0 router.googlecom.biz -0.0.0.0 s32.bilsay.com -0.0.0.0 samsclub33.pochta.ru -0.0.0.0 sc10.net -0.0.0.0 sc.5.p2l.info -0.0.0.0 sd.5.p2l.info -0.0.0.0 search4you.50webs.com -0.0.0.0 search-phentermine.hpage.net -0.0.0.0 searchpill.boom.ru -0.0.0.0 seasonale.1.p2l.info -0.0.0.0 shop.kauffes.de -0.0.0.0 single-online.petrovka.info -0.0.0.0 sk.5.p2l.info -0.0.0.0 skelaxin.1.p2l.info -0.0.0.0 skelaxin.3.p2l.info -0.0.0.0 skelaxin.4.p2l.info -0.0.0.0 skin-care.1.p2l.info -0.0.0.0 skocz.pl -0.0.0.0 sleep-aids.1.p2l.info -0.0.0.0 sleeper-sofa.dreamhoster.com -0.0.0.0 slf5cyd.info -0.0.0.0 sobolev.net.ru -0.0.0.0 soma.1.p2l.info -0.0.0.0 soma.3xforum.ro -0.0.0.0 soma-store.visa-usa.ru -0.0.0.0 sonata.1.p2l.info -0.0.0.0 sport-betting-online.hitslog.net -0.0.0.0 spyware-removers.shengen.ru -0.0.0.0 spyware-scan.100gal.net -0.0.0.0 spyware.usafreespace.com -0.0.0.0 sq7.co.uk -0.0.0.0 sql-server-driver.beesearch.info -0.0.0.0 starlix.ql.st -0.0.0.0 stop-smoking.1.p2l.info -0.0.0.0 supplements.1.p2l.info -0.0.0.0 sx.nazari.org -0.0.0.0 sx.z0rz.com -0.0.0.0 ta.at.ic5mp.net -0.0.0.0 ta.at.user-mode-linux.net -0.0.0.0 tamiflu-in-canada.asian-flu-vaccine.com -0.0.0.0 tamiflu-no-prescription.asian-flu-vaccine.com -0.0.0.0 tamiflu-purchase.asian-flu-vaccine.com -0.0.0.0 tamiflu-without-prescription.asian-flu-vaccine.com -0.0.0.0 tenuate.1.p2l.info -0.0.0.0 texas-hold-em.e-online-poker-4u.net -0.0.0.0 texas-holdem.shengen.ru -0.0.0.0 ticket20.tripod.com -0.0.0.0 tizanidine.1.p2l.info -0.0.0.0 tn.5.p2l.info -0.0.0.0 topmeds10.com -0.0.0.0 top.pcanywhere.net -0.0.0.0 toyota.cyberealhosting.com -0.0.0.0 tramadol.1.p2l.info -0.0.0.0 tramadol2006.3xforum.ro -0.0.0.0 tramadol.3.p2l.info -0.0.0.0 tramadol.4.p2l.info -0.0.0.0 travel-insurance-quotes.beesearch.info -0.0.0.0 triphasil.1.p2l.info -0.0.0.0 triphasil.3.p2l.info -0.0.0.0 triphasil.4.p2l.info -0.0.0.0 tx.5.p2l.info -0.0.0.0 uf2aasn.111adfueo.us -0.0.0.0 ultracet.1.p2l.info -0.0.0.0 ultram.1.p2l.info -0.0.0.0 united-airline-fare.100pantyhose.com -0.0.0.0 university-online.petrovka.info -0.0.0.0 urlcut.net -0.0.0.0 urshort.net -0.0.0.0 us.kopuz.com -0.0.0.0 ut.5.p2l.info -0.0.0.0 utairway.com -0.0.0.0 va.5.p2l.info -0.0.0.0 vacation.toppick.info -0.0.0.0 valium.este.ru -0.0.0.0 valium.hut1.ru -0.0.0.0 valium.ourtablets.com -0.0.0.0 valium.polybuild.ru -0.0.0.0 valiumvalium.3xforum.ro -0.0.0.0 valtrex.1.p2l.info -0.0.0.0 valtrex.3.p2l.info -0.0.0.0 valtrex.4.p2l.info -0.0.0.0 valtrex.7h.com -0.0.0.0 vaniqa.1.p2l.info -0.0.0.0 vi.5.p2l.info -0.0.0.0 viagra.1.p2l.info -0.0.0.0 viagra.3.p2l.info -0.0.0.0 viagra.4.p2l.info -0.0.0.0 viagra-online.petrovka.info -0.0.0.0 viagra-pill.blogspot.com -0.0.0.0 viagra.polybuild.ru -0.0.0.0 viagra-soft-tabs.1.p2l.info -0.0.0.0 viagra-store.shengen.ru -0.0.0.0 viagraviagra.3xforum.ro -0.0.0.0 vicodin-online.petrovka.info -0.0.0.0 vicodin-store.shengen.ru -0.0.0.0 vicodin.t-amo.net -0.0.0.0 viewtools.com -0.0.0.0 vioxx.1.p2l.info -0.0.0.0 vitalitymax.1.p2l.info -0.0.0.0 vt.5.p2l.info -0.0.0.0 vxv.phre.net -0.0.0.0 w0.drag0n.org -0.0.0.0 wa.5.p2l.info -0.0.0.0 water-bed.8p.org.uk -0.0.0.0 web-hosting.hitslog.net -0.0.0.0 webhosting.hut1.ru -0.0.0.0 weborg.hut1.ru -0.0.0.0 weight-loss.1.p2l.info -0.0.0.0 weight-loss.3.p2l.info -0.0.0.0 weight-loss.4.p2l.info -0.0.0.0 weight-loss.hut1.ru -0.0.0.0 wellbutrin.1.p2l.info -0.0.0.0 wellbutrin.3.p2l.info -0.0.0.0 wellbutrin.4.p2l.info -0.0.0.0 wellnessmonitor.bravehost.com -0.0.0.0 wi.5.p2l.info -0.0.0.0 world-trade-center.hawaiicity.com -0.0.0.0 wp-club.net -0.0.0.0 ws01.do.nu -0.0.0.0 ws02.do.nu -0.0.0.0 ws03.do.nu -0.0.0.0 ws03.home.sapo.pt -0.0.0.0 ws04.do.nu -0.0.0.0 ws04.home.sapo.pt -0.0.0.0 ws05.home.sapo.pt -0.0.0.0 ws06.home.sapo.pt -0.0.0.0 wv.5.p2l.info -0.0.0.0 www.31d.net -0.0.0.0 www3.ddns.ms -0.0.0.0 www4.at.debianbase.de -0.0.0.0 www4.epac.to -0.0.0.0 www5.3-a.net -0.0.0.0 www69.bestdeals.at -0.0.0.0 www69.byinter.net -0.0.0.0 www69.dynu.com -0.0.0.0 www69.findhere.org -0.0.0.0 www69.fw.nu -0.0.0.0 www69.ugly.as -0.0.0.0 www6.ezua.com -0.0.0.0 www6.ns1.name -0.0.0.0 www7.ygto.com -0.0.0.0 www8.ns01.us -0.0.0.0 www99.bounceme.net -0.0.0.0 www99.fdns.net -0.0.0.0 www99.zapto.org -0.0.0.0 www9.compblue.com -0.0.0.0 www9.servequake.com -0.0.0.0 www9.trickip.org -0.0.0.0 www.adspoll.com -0.0.0.0 www.adult-top-list.com -0.0.0.0 www.aektschen.de -0.0.0.0 www.aeqs.com -0.0.0.0 www.alladultdirectories.com -0.0.0.0 www.alladultdirectory.net -0.0.0.0 www.arbeitssuche-web.de -0.0.0.0 www.bestrxpills.com -0.0.0.0 www.bigsister.cxa.de -0.0.0.0 www.bigsister-puff.cxa.de -0.0.0.0 www.bitlocker.net -0.0.0.0 www.cheap-laptops-notebook-computers.info -0.0.0.0 www.cheap-online-stamp.cast.cc -0.0.0.0 www.codez-knacken.de -0.0.0.0 www.computerxchange.com -0.0.0.0 www.credit-dreams.com -0.0.0.0 www.edle-stuecke.de -0.0.0.0 www.exe-file.de -0.0.0.0 www.exttrem.de -0.0.0.0 www.fetisch-pornos.cxa.de -0.0.0.0 www.ficken-ficken-ficken.cxa.de -0.0.0.0 www.ficken-xxx.cxa.de -0.0.0.0 www.financial-advice-books.com -0.0.0.0 www.finanzmarkt2004.de -0.0.0.0 www.furnitureulimited.com -0.0.0.0 www.gewinnspiele-slotmachine.de -0.0.0.0 www.hardware4freaks.de -0.0.0.0 www.healthyaltprods.com -0.0.0.0 www.heimlich-gefilmt.cxa.de -0.0.0.0 www.huberts-kochseite.de -0.0.0.0 www.huren-verzeichnis.is4all.de -0.0.0.0 www.kaaza-legal.de -0.0.0.0 www.kajahdfssa.net -0.0.0.0 www.keyofhealth.com -0.0.0.0 www.kitchentablegang.org -0.0.0.0 www.km69.de -0.0.0.0 www.koch-backrezepte.de -0.0.0.0 www.kvr-systems.de -0.0.0.0 www.lesben-pornos.cxa.de -0.0.0.0 www.links-private-krankenversicherung.de -0.0.0.0 www.littledevildoubt.com -0.0.0.0 www.mailforfreedom.com -0.0.0.0 www.masterspace.biz -0.0.0.0 www.medical-research-books.com -0.0.0.0 www.microsoft2010.com -0.0.0.0 www.nelsongod.ca -0.0.0.0 www.nextstudent.com -0.0.0.0 www.ntdesk.de -0.0.0.0 www.nutten-verzeichnis.cxa.de -0.0.0.0 www.obesitycheck.com -0.0.0.0 www.pawnauctions.net -0.0.0.0 www.pills-home.com -0.0.0.0 www.poker4spain.com -0.0.0.0 www.poker-new.com -0.0.0.0 www.poker-unique.com -0.0.0.0 www.porno-lesben.cxa.de -0.0.0.0 www.prevent-asian-flu.com -0.0.0.0 www.randppro-cuts.com -0.0.0.0 www.romanticmaui.net -0.0.0.0 www.salldo.de -0.0.0.0 www.samsclub33.pochta.ru -0.0.0.0 www.schwarz-weisses.de -0.0.0.0 www.schwule-boys-nackt.cxa.de -0.0.0.0 www.shopping-artikel.de -0.0.0.0 www.showcaserealestate.net -0.0.0.0 www.skattabrain.com -0.0.0.0 www.softcha.com -0.0.0.0 www.striemline.de -0.0.0.0 www.talentbroker.net -0.0.0.0 www.the-discount-store.com -0.0.0.0 www.topmeds10.com -0.0.0.0 www.uniqueinternettexasholdempoker.com -0.0.0.0 www.viagra-home.com -0.0.0.0 www.vthought.com -0.0.0.0 www.vtoyshop.com -0.0.0.0 www.vulcannonibird.de -0.0.0.0 www.webabrufe.de -0.0.0.0 www.wilddreams.info -0.0.0.0 www.willcommen.de -0.0.0.0 www.xcr-286.com -0.0.0.0 wy.5.p2l.info -0.0.0.0 x25.2mydns.com -0.0.0.0 x25.plorp.com -0.0.0.0 x4.lov3.net -0.0.0.0 x6x.a.la -0.0.0.0 x888x.myserver.org -0.0.0.0 x8x.dyndns.dk -0.0.0.0 x8x.trickip.net -0.0.0.0 xanax-online.dot.de -0.0.0.0 xanax-online.run.to -0.0.0.0 xanax-online.sms2.us -0.0.0.0 xanax.ourtablets.com -0.0.0.0 xanax-store.shengen.ru -0.0.0.0 xanax.t-amo.net -0.0.0.0 xanaxxanax.3xforum.ro -0.0.0.0 x-box.t35.com -0.0.0.0 xcr-286.com -0.0.0.0 xenical.1.p2l.info -0.0.0.0 xenical.3.p2l.info -0.0.0.0 xenical.4.p2l.info -0.0.0.0 x-hydrocodone.info -0.0.0.0 xoomer.alice.it -0.0.0.0 x-phentermine.info -0.0.0.0 xr.h4ck.la -0.0.0.0 yasmin.1.p2l.info -0.0.0.0 yasmin.3.p2l.info -0.0.0.0 yasmin.4.p2l.info -0.0.0.0 yt.5.p2l.info -0.0.0.0 zanaflex.1.p2l.info -0.0.0.0 zebutal.1.p2l.info -0.0.0.0 zocor.about-tabs.com -0.0.0.0 zoloft.1.p2l.info -0.0.0.0 zoloft.3.p2l.info -0.0.0.0 zoloft.4.p2l.info -0.0.0.0 zoloft.about-tabs.com -0.0.0.0 zyban.1.p2l.info -0.0.0.0 zyban.about-tabs.com -0.0.0.0 zyban-store.shengen.ru -0.0.0.0 zyprexa.about-tabs.com -0.0.0.0 zyrtec.1.p2l.info -0.0.0.0 zyrtec.3.p2l.info -0.0.0.0 zyrtec.4.p2l.info -# - -# - -# Phorm contextual advertising sites -0.0.0.0 a.oix.com -0.0.0.0 a.oix.net -0.0.0.0 a.openinternetexchange.com -0.0.0.0 a.phormlabs.com -0.0.0.0 a.webwise.com -0.0.0.0 a.webwise.net -0.0.0.0 b.oix.net -0.0.0.0 br.phorm.com -0.0.0.0 bt.phorm.com -0.0.0.0 bt.webwise.com -0.0.0.0 b.webwise.net -0.0.0.0 c.webwise.com -0.0.0.0 c.webwise.net -0.0.0.0 d.oix.com -0.0.0.0 d.phormlabs.com -0.0.0.0 ig.fp.oix.net -0.0.0.0 invite.gezinti.com -0.0.0.0 kentsucks.youcanoptout.com -0.0.0.0 kr.phorm.com -0.0.0.0 mail.youcanoptout.com -0.0.0.0 mail.youcanoptout.net -0.0.0.0 mail.youcanoptout.org -0.0.0.0 monitor.phorm.com -0.0.0.0 mx01.openinternetexchange.com -0.0.0.0 mx01.openinternetexchange.net -0.0.0.0 mx01.webwise.com -0.0.0.0 mx03.phorm.com -0.0.0.0 navegador.oi.com.br -0.0.0.0 navegador.telefonica.com.br -0.0.0.0 ns1.oix.com -0.0.0.0 ns1.openinternetexchange.com -0.0.0.0 ns1.phorm.com -0.0.0.0 ns2.oix.com -0.0.0.0 ns2.openinternetexchange.com -0.0.0.0 ns2.phorm.com -0.0.0.0 ns2.youcanoptout.com -0.0.0.0 ns3.openinternetexchange.com -0.0.0.0 oi.webnavegador.com.br -0.0.0.0 oixcrv-lab.net -0.0.0.0 oixcrv.net -0.0.0.0 oixcrv-stage.net -0.0.0.0 oix.phorm.com -0.0.0.0 oixpre.net -0.0.0.0 oixpre-stage.net -0.0.0.0 oixssp-lab.net -0.0.0.0 oixssp.net -0.0.0.0 oix-stage.net -0.0.0.0 openinternetexchange.com -0.0.0.0 openinternetexchange.net -0.0.0.0 phorm.kr -0.0.0.0 phormlabs.com -0.0.0.0 prm-ext.phorm.com -0.0.0.0 romdiscover.com -0.0.0.0 rtc.romdiscover.com -0.0.0.0 stats.oix.com -0.0.0.0 stopphoulplay.com -0.0.0.0 stopphoulplay.net -0.0.0.0 telefonica.webnavegador.com.br -0.0.0.0 webnavegador.com.br -0.0.0.0 webwise.com -0.0.0.0 webwise.net -0.0.0.0 w.oix.net -0.0.0.0 www.gezinti.com -0.0.0.0 www.gozatar.com -0.0.0.0 www.oix.com -0.0.0.0 www.openinternetexchange.com -0.0.0.0 www.phormlabs.com -0.0.0.0 www.stopphoulplay.com -0.0.0.0 www.youcanoptout.com -0.0.0.0 www.youcanoptout.net -0.0.0.0 www.youcanoptout.org -0.0.0.0 xxyyzz.youcanoptout.com -0.0.0.0 youcanoptout.com -0.0.0.0 youcanoptout.net -0.0.0.0 youcanoptout.org -# diff --git a/venv/lib/python3.9/site-packages/gevent/tests/https_svn_python_org_root.pem b/venv/lib/python3.9/site-packages/gevent/tests/https_svn_python_org_root.pem deleted file mode 100644 index e7dfc82..0000000 --- a/venv/lib/python3.9/site-packages/gevent/tests/https_svn_python_org_root.pem +++ /dev/null @@ -1,41 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIHPTCCBSWgAwIBAgIBADANBgkqhkiG9w0BAQQFADB5MRAwDgYDVQQKEwdSb290 -IENBMR4wHAYDVQQLExVodHRwOi8vd3d3LmNhY2VydC5vcmcxIjAgBgNVBAMTGUNB -IENlcnQgU2lnbmluZyBBdXRob3JpdHkxITAfBgkqhkiG9w0BCQEWEnN1cHBvcnRA -Y2FjZXJ0Lm9yZzAeFw0wMzAzMzAxMjI5NDlaFw0zMzAzMjkxMjI5NDlaMHkxEDAO -BgNVBAoTB1Jvb3QgQ0ExHjAcBgNVBAsTFWh0dHA6Ly93d3cuY2FjZXJ0Lm9yZzEi -MCAGA1UEAxMZQ0EgQ2VydCBTaWduaW5nIEF1dGhvcml0eTEhMB8GCSqGSIb3DQEJ -ARYSc3VwcG9ydEBjYWNlcnQub3JnMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIIC -CgKCAgEAziLA4kZ97DYoB1CW8qAzQIxL8TtmPzHlawI229Z89vGIj053NgVBlfkJ -8BLPRoZzYLdufujAWGSuzbCtRRcMY/pnCujW0r8+55jE8Ez64AO7NV1sId6eINm6 -zWYyN3L69wj1x81YyY7nDl7qPv4coRQKFWyGhFtkZip6qUtTefWIonvuLwphK42y -fk1WpRPs6tqSnqxEQR5YYGUFZvjARL3LlPdCfgv3ZWiYUQXw8wWRBB0bF4LsyFe7 -w2t6iPGwcswlWyCR7BYCEo8y6RcYSNDHBS4CMEK4JZwFaz+qOqfrU0j36NK2B5jc -G8Y0f3/JHIJ6BVgrCFvzOKKrF11myZjXnhCLotLddJr3cQxyYN/Nb5gznZY0dj4k -epKwDpUeb+agRThHqtdB7Uq3EvbXG4OKDy7YCbZZ16oE/9KTfWgu3YtLq1i6L43q -laegw1SJpfvbi1EinbLDvhG+LJGGi5Z4rSDTii8aP8bQUWWHIbEZAWV/RRyH9XzQ -QUxPKZgh/TMfdQwEUfoZd9vUFBzugcMd9Zi3aQaRIt0AUMyBMawSB3s42mhb5ivU -fslfrejrckzzAeVLIL+aplfKkQABi6F1ITe1Yw1nPkZPcCBnzsXWWdsC4PDSy826 -YreQQejdIOQpvGQpQsgi3Hia/0PsmBsJUUtaWsJx8cTLc6nloQsCAwEAAaOCAc4w -ggHKMB0GA1UdDgQWBBQWtTIb1Mfz4OaO873SsDrusjkY0TCBowYDVR0jBIGbMIGY -gBQWtTIb1Mfz4OaO873SsDrusjkY0aF9pHsweTEQMA4GA1UEChMHUm9vdCBDQTEe -MBwGA1UECxMVaHR0cDovL3d3dy5jYWNlcnQub3JnMSIwIAYDVQQDExlDQSBDZXJ0 -IFNpZ25pbmcgQXV0aG9yaXR5MSEwHwYJKoZIhvcNAQkBFhJzdXBwb3J0QGNhY2Vy -dC5vcmeCAQAwDwYDVR0TAQH/BAUwAwEB/zAyBgNVHR8EKzApMCegJaAjhiFodHRw -czovL3d3dy5jYWNlcnQub3JnL3Jldm9rZS5jcmwwMAYJYIZIAYb4QgEEBCMWIWh0 -dHBzOi8vd3d3LmNhY2VydC5vcmcvcmV2b2tlLmNybDA0BglghkgBhvhCAQgEJxYl -aHR0cDovL3d3dy5jYWNlcnQub3JnL2luZGV4LnBocD9pZD0xMDBWBglghkgBhvhC -AQ0ESRZHVG8gZ2V0IHlvdXIgb3duIGNlcnRpZmljYXRlIGZvciBGUkVFIGhlYWQg -b3ZlciB0byBodHRwOi8vd3d3LmNhY2VydC5vcmcwDQYJKoZIhvcNAQEEBQADggIB -ACjH7pyCArpcgBLKNQodgW+JapnM8mgPf6fhjViVPr3yBsOQWqy1YPaZQwGjiHCc -nWKdpIevZ1gNMDY75q1I08t0AoZxPuIrA2jxNGJARjtT6ij0rPtmlVOKTV39O9lg -18p5aTuxZZKmxoGCXJzN600BiqXfEVWqFcofN8CCmHBh22p8lqOOLlQ+TyGpkO/c -gr/c6EWtTZBzCDyUZbAEmXZ/4rzCahWqlwQ3JNgelE5tDlG+1sSPypZt90Pf6DBl -Jzt7u0NDY8RD97LsaMzhGY4i+5jhe1o+ATc7iwiwovOVThrLm82asduycPAtStvY -sONvRUgzEv/+PDIqVPfE94rwiCPCR/5kenHA0R6mY7AHfqQv0wGP3J8rtsYIqQ+T -SCX8Ev2fQtzzxD72V7DX3WnRBnc0CkvSyqD/HMaMyRa+xMwyN2hzXwj7UfdJUzYF -CpUCTPJ5GhD22Dp1nPMd8aINcGeGG7MW9S/lpOt5hvk9C8JzC6WZrG/8Z7jlLwum -GCSNe9FINSkYQKyTYOGWhlC0elnYjyELn8+CkcY7v2vcB5G5l1YjqrZslMZIBjzk -zk6q5PYvCdxTby78dOs6Y5nCpqyJvKeyRKANihDjbPIky/qbn3BHLt4Ui9SyIAmW -omTxJBzcoTWcFbLUvFUufQb1nA5V9FrWk9p2rSVzTMVD ------END CERTIFICATE----- diff --git a/venv/lib/python3.9/site-packages/gevent/tests/keycert.pem b/venv/lib/python3.9/site-packages/gevent/tests/keycert.pem deleted file mode 100644 index 2f46fcf..0000000 --- a/venv/lib/python3.9/site-packages/gevent/tests/keycert.pem +++ /dev/null @@ -1,32 +0,0 @@ ------BEGIN RSA PRIVATE KEY----- -MIICXwIBAAKBgQC8ddrhm+LutBvjYcQlnH21PPIseJ1JVG2HMmN2CmZk2YukO+9L -opdJhTvbGfEj0DQs1IE8M+kTUyOmuKfVrFMKwtVeCJphrAnhoz7TYOuLBSqt7lVH -fhi/VwovESJlaBOp+WMnfhcduPEYHYx/6cnVapIkZnLt30zu2um+DzA9jQIDAQAB -AoGBAK0FZpaKj6WnJZN0RqhhK+ggtBWwBnc0U/ozgKz2j1s3fsShYeiGtW6CK5nU -D1dZ5wzhbGThI7LiOXDvRucc9n7vUgi0alqPQ/PFodPxAN/eEYkmXQ7W2k7zwsDA -IUK0KUhktQbLu8qF/m8qM86ba9y9/9YkXuQbZ3COl5ahTZrhAkEA301P08RKv3KM -oXnGU2UHTuJ1MAD2hOrPxjD4/wxA/39EWG9bZczbJyggB4RHu0I3NOSFjAm3HQm0 -ANOu5QK9owJBANgOeLfNNcF4pp+UikRFqxk5hULqRAWzVxVrWe85FlPm0VVmHbb/ -loif7mqjU8o1jTd/LM7RD9f2usZyE2psaw8CQQCNLhkpX3KO5kKJmS9N7JMZSc4j -oog58yeYO8BBqKKzpug0LXuQultYv2K4veaIO04iL9VLe5z9S/Q1jaCHBBuXAkEA -z8gjGoi1AOp6PBBLZNsncCvcV/0aC+1se4HxTNo2+duKSDnbq+ljqOM+E7odU+Nq -ewvIWOG//e8fssd0mq3HywJBAJ8l/c8GVmrpFTx8r/nZ2Pyyjt3dH1widooDXYSV -q6Gbf41Llo5sYAtmxdndTLASuHKecacTgZVhy0FryZpLKrU= ------END RSA PRIVATE KEY----- ------BEGIN CERTIFICATE----- -MIICpzCCAhCgAwIBAgIJAP+qStv1cIGNMA0GCSqGSIb3DQEBBQUAMIGJMQswCQYD -VQQGEwJVUzERMA8GA1UECBMIRGVsYXdhcmUxEzARBgNVBAcTCldpbG1pbmd0b24x -IzAhBgNVBAoTGlB5dGhvbiBTb2Z0d2FyZSBGb3VuZGF0aW9uMQwwCgYDVQQLEwNT -U0wxHzAdBgNVBAMTFnNvbWVtYWNoaW5lLnB5dGhvbi5vcmcwHhcNMDcwODI3MTY1 -NDUwWhcNMTMwMjE2MTY1NDUwWjCBiTELMAkGA1UEBhMCVVMxETAPBgNVBAgTCERl -bGF3YXJlMRMwEQYDVQQHEwpXaWxtaW5ndG9uMSMwIQYDVQQKExpQeXRob24gU29m -dHdhcmUgRm91bmRhdGlvbjEMMAoGA1UECxMDU1NMMR8wHQYDVQQDExZzb21lbWFj -aGluZS5weXRob24ub3JnMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC8ddrh -m+LutBvjYcQlnH21PPIseJ1JVG2HMmN2CmZk2YukO+9LopdJhTvbGfEj0DQs1IE8 -M+kTUyOmuKfVrFMKwtVeCJphrAnhoz7TYOuLBSqt7lVHfhi/VwovESJlaBOp+WMn -fhcduPEYHYx/6cnVapIkZnLt30zu2um+DzA9jQIDAQABoxUwEzARBglghkgBhvhC -AQEEBAMCBkAwDQYJKoZIhvcNAQEFBQADgYEAF4Q5BVqmCOLv1n8je/Jw9K669VXb -08hyGzQhkemEBYQd6fzQ9A/1ZzHkJKb1P6yreOLSEh4KcxYPyrLRC1ll8nr5OlCx -CMhKkTnR6qBsdNV0XtdU2+N25hqW+Ma4ZeqsN/iiJVCGNOZGnvQuvCAGWF8+J/f/ -iHkC6gGdBJhogs4= ------END CERTIFICATE----- diff --git a/venv/lib/python3.9/site-packages/gevent/tests/known_failures.py b/venv/lib/python3.9/site-packages/gevent/tests/known_failures.py deleted file mode 100644 index 27fbddb..0000000 --- a/venv/lib/python3.9/site-packages/gevent/tests/known_failures.py +++ /dev/null @@ -1,560 +0,0 @@ -# This is a list of known failures (=bugs). -# The tests listed there must fail (or testrunner.py will report error) unless they are prefixed with FLAKY -# in which cases the result of them is simply ignored -from __future__ import print_function - -import sys -import struct - -from gevent.testing import sysinfo - -class Condition(object): - __slots__ = () - - def __and__(self, other): - return AndCondition(self, other) - - def __or__(self, other): - return OrCondition(self, other) - - def __bool__(self): - raise NotImplementedError - - -class AbstractBinaryCondition(Condition): # pylint:disable=abstract-method - __slots__ = ( - 'lhs', - 'rhs', - ) - OP = None - def __init__(self, lhs, rhs): - self.lhs = lhs - self.rhs = rhs - - def __repr__(self): - return "(%r %s %r)" % ( - self.lhs, - self.OP, - self.rhs - ) - -class OrCondition(AbstractBinaryCondition): - __slots__ = () - OP = '|' - def __bool__(self): - return bool(self.lhs) or bool(self.rhs) - -class AndCondition(AbstractBinaryCondition): - __slots__ = () - OP = '&' - def __bool__(self): - return bool(self.lhs) and bool(self.rhs) - -class ConstantCondition(Condition): - __slots__ = ( - 'value', - '__name__', - ) - - def __init__(self, value, name=None): - self.value = bool(value) - self.__name__ = name or str(value) - - def __bool__(self): - return self.value - - def __repr__(self): - return self.__name__ - -ALWAYS = ConstantCondition(True) -NEVER = ConstantCondition(False) - -class _AttrCondition(ConstantCondition): - __slots__ = ( - ) - - def __init__(self, name): - ConstantCondition.__init__(self, getattr(sysinfo, name), name) - -PYPY = _AttrCondition('PYPY') -PYPY3 = _AttrCondition('PYPY3') -PY3 = _AttrCondition('PY3') - -OSX = _AttrCondition('OSX') -LIBUV = _AttrCondition('LIBUV') -WIN = _AttrCondition('WIN') -APPVEYOR = _AttrCondition('RUNNING_ON_APPVEYOR') -TRAVIS = _AttrCondition('RUNNING_ON_TRAVIS') -CI = _AttrCondition('RUNNING_ON_CI') -LEAKTEST = _AttrCondition('RUN_LEAKCHECKS') -COVERAGE = _AttrCondition('RUN_COVERAGE') -RESOLVER_NOT_SYSTEM = _AttrCondition('RESOLVER_NOT_SYSTEM') -BIT_64 = ConstantCondition(struct.calcsize('P') * 8 == 64, 'BIT_64') -PY380_EXACTLY = ConstantCondition(sys.version_info[:3] == (3, 8, 0), 'PY380_EXACTLY') -PY312B3_EXACTLY = ConstantCondition(sys.version_info == (3, 12, 0, 'beta', 3)) -PY312B4_EXACTLY = ConstantCondition(sys.version_info == (3, 12, 0, 'beta', 4)) -PY313LT5 = ConstantCondition( - sys.version_info[:2] == (3, 13) - and sys.version_info[2] < 5 -) - -class _Definition(object): - __slots__ = ( - '__name__', - # When does the class of this condition apply? - 'when', - # When should this test be run alone, if it's run? - 'run_alone', - # Should this test be ignored during coverage measurement? - 'ignore_coverage', - # {name: (Condition, value)} - 'options', - ) - - def __init__(self, when, run_alone, ignore_coverage, options): - assert isinstance(when, Condition) - assert isinstance(run_alone, Condition) - assert isinstance(ignore_coverage, Condition) - self.when = when - self.__name__ = None # pylint:disable=non-str-assignment-to-dunder-name - self.run_alone = run_alone - self.ignore_coverage = ignore_coverage - if options: - for v in options.values(): - assert isinstance(v, tuple) and len(v) == 2 - assert isinstance(v[0], Condition) - self.options = options - - def __set_name__(self, owner, name): - self.__name__ = name - - def __repr__(self): - return '<%s for %s when=%r=%s run_alone=%r=%s>' % ( - type(self).__name__, - self.__name__, - self.when, bool(self.when), - self.run_alone, bool(self.run_alone) - ) - -class _Action(_Definition): - __slots__ = ( - 'reason', - ) - def __init__(self, reason='', when=ALWAYS, run_alone=NEVER, ignore_coverage=NEVER, - options=None): - _Definition.__init__(self, when, run_alone, ignore_coverage, options) - self.reason = reason - -class RunAlone(_Action): - __slots__ = () - - def __init__(self, reason='', when=ALWAYS, ignore_coverage=NEVER): - _Action.__init__(self, reason, run_alone=when, ignore_coverage=ignore_coverage) - -class Failing(_Action): - __slots__ = () - -class Flaky(Failing): - __slots__ = () - -class Ignored(_Action): - __slots__ = () - -class Multi(object): - def __init__(self): - self._conds = [] - - def flaky(self, reason='', when=True, ignore_coverage=NEVER, run_alone=NEVER): - self._conds.append( - Flaky( - reason, when=when, - ignore_coverage=ignore_coverage, - run_alone=run_alone, - ) - ) - return self - - def ignored(self, reason='', when=True): - self._conds.append(Ignored(reason, when=when)) - return self - - def __set_name__(self, owner, name): - for c in self._conds: - c.__set_name__(owner, name) - - -class DefinitionsMeta(type): - # a metaclass on Python 3 that makes sure we only set attributes once. pylint doesn't - # warn about that. - @classmethod - def __prepare__(mcs, name, bases): # pylint:disable=unused-argument,bad-dunder-name - return SetOnceMapping() - - -class SetOnceMapping(dict): - - def __setitem__(self, name, value): - if name in self: - raise AttributeError(name) - dict.__setitem__(self, name, value) - -som = SetOnceMapping() -som[1] = 1 -try: - som[1] = 2 -except AttributeError: - del som -else: - raise AssertionError("SetOnceMapping is broken") - - - -class Definitions(metaclass=DefinitionsMeta): - - test__util = RunAlone( - """ - If we have extra greenlets hanging around due to changes in GC, we won't - match the expected output. - - This arises on CI 3.14.3 when combined with test__threadpool; - it was previously seen with some specific 3.12 releases. - For safety, always run alone. - """, - when=(CI) - ) - - test__issue6 = Flaky( - """test__issue6 (see comments in test file) is really flaky on both Travis and Appveyor; - on Travis we could just run the test again (but that gets old fast), but on appveyor - we don't have that option without a new commit---and sometimes we really need a build - to succeed in order to get a release wheel""" - ) - - test__core_fork = Ignored( - """fork watchers don't get called on windows - because fork is not a concept windows has. - See this file for a detailed explanation.""", - when=WIN - ) - - test__greenletset = Flaky( - when=WIN, - ignore_coverage=PYPY - ) - - test__example_udp_client = test__example_udp_server = Flaky( - """ - These both run on port 9000 and can step on each other...seems - like the appveyor containers aren't fully port safe? Or it - takes longer for the processes to shut down? Or we run them in - a different order in the process pool than we do other places? - - On PyPy on Travis, this fails to get the correct results, - sometimes. I can't reproduce locally - """, - when=APPVEYOR | (PYPY & TRAVIS) - ) - - # This one sometimes randomly closes connections, but no indication - # of a server crash, only a client side close. - test__server_pywsgi = Flaky(when=APPVEYOR) - - test_threading = Multi().ignored( - """ - This one seems to just stop right after patching is done. It - passes on a local win 10 vm, and the main test_threading_2.py - does as well. Based on the printouts we added, it appears to - not even finish importing: - https://ci.appveyor.com/project/denik/gevent/build/1.0.1277/job/tpvhesij5gldjxqw#L1190 - Ignored because it takes two minutes to time out. - """, - when=APPVEYOR & LIBUV & PYPY - ).flaky( - """ - test_set_and_clear in Py3 relies on 5 threads all starting and - coming to an Event wait point while a sixth thread sleeps for a half - second. The sixth thread then does something and checks that - the 5 threads were all at the wait point. But the timing is sometimes - too tight for appveyor. This happens even if Event isn't - monkey-patched - """, - when=APPVEYOR & PY3 - ) - - test_ftplib = Flaky( - r""" - could be a problem of appveyor - not sure - ====================================================================== - ERROR: test_af (__main__.TestIPv6Environment) - ---------------------------------------------------------------------- - File "C:\Python27-x64\lib\ftplib.py", line 135, in connect - self.sock = socket.create_connection((self.host, self.port), self.timeout) - File "c:\projects\gevent\gevent\socket.py", line 73, in create_connection - raise err - error: [Errno 10049] [Error 10049] The requested address is not valid in its context. - XXX: On Jan 3 2016 this suddenly started passing on Py27/64; no idea why, the python version - was 2.7.11 before and after. - """, - when=APPVEYOR & BIT_64 - ) - - - test__backdoor = Flaky(when=LEAKTEST | PYPY) - test__socket_errors = Flaky(when=LEAKTEST) - test_signal = Multi().flaky( - "On Travis, this very frequently fails due to timing", - when=TRAVIS & LEAKTEST, - # Partial workaround for the _testcapi issue on PyPy, - # but also because signal delivery can sometimes be slow, and this - # spawn processes of its own - run_alone=APPVEYOR, - ).ignored( - """ - This fails to run a single test. It looks like just importing the module - can hang. All I see is the output from patch_all() - """, - when=APPVEYOR & PYPY3 - ) - - test__monkey_sigchld_2 = Ignored( - """ - This hangs for no apparent reason when run by the testrunner, - even wher maked standalone when run standalone from the - command line, it's fine. Issue in pypy2 6.0? - """, - when=PYPY & LIBUV - ) - - test_ssl = Ignored( - """ - PyPy 7.0 and 7.1 on Travis with Ubunto Xenial 16.04 can't - allocate SSL Context objects, either in Python 2.7 or 3.6. - There must be some library incompatibility. No point even - running them. XXX: Remember to turn this back on. - - On Windows, with PyPy3.7 7.3.7, there seem to be all kind of certificate - errors. - """, - when=(PYPY & TRAVIS) | (PYPY3 & WIN) - ) - - test_httpservers = Ignored( - """ - All the CGI tests hang. There appear to be subprocess problems. - """, - when=PYPY3 & WIN - ) - - - - test__pywsgi = Ignored( - """ - XXX: Re-enable this when we can investigate more. This has - started crashing with a SystemError. I cannot reproduce with - the same version on macOS and I cannot reproduce with the same - version in a Linux vm. Commenting out individual tests just - moves the crash around. - https://bitbucket.org/pypy/pypy/issues/2769/systemerror-unexpected-internal-exception - - On Appveyor 3.8.0, for some reason this takes *way* too long, about 100s, which - often goes just over the default timeout of 100s. This makes no sense. - But it also takes nearly that long in 3.7. 3.6 and earlier are much faster. - - It also takes just over 100s on PyPy 3.7. - """, - when=(PYPY & TRAVIS & LIBUV) | PY380_EXACTLY, - # https://bitbucket.org/pypy/pypy/issues/2769/systemerror-unexpected-internal-exception - run_alone=(CI & LEAKTEST & PY3) | (PYPY & LIBUV), - # This often takes much longer on PyPy on CI. - options={'timeout': (CI & PYPY, 180)}, - ) - - test_subprocess = Multi().flaky( - "Unknown, can't reproduce locally; times out one test", - when=PYPY & PY3 & TRAVIS, - ignore_coverage=ALWAYS, - ).ignored( - "Tests don't even start before the process times out.", - when=PYPY3 & WIN - ) - - test__threadpool = Ignored( - """ - XXX: Re-enable these when we have more time to investigate. - - This test, which normally takes ~60s, sometimes - hangs forever after running several tests. I cannot reproduce, - it seems highly load dependent. Observed with both libev and libuv. - """, - when=TRAVIS & (PYPY | OSX), - # This often takes much longer on PyPy on CI. - options={'timeout': (CI & PYPY, 180)}, - ) - - test__threading_2 = Ignored( - """ - This test, which normally takes 4-5s, sometimes - hangs forever after running two tests. I cannot reproduce, - it seems highly load dependent. Observed with both libev and libuv. - """, - when=TRAVIS & (PYPY | OSX), - # This often takes much longer on PyPy on CI. - options={'timeout': (CI & PYPY, 180)}, - ) - - test__issue230 = Ignored( - """ - This rarely hangs for unknown reasons. I cannot reproduce - locally. - """, - when=TRAVIS & OSX - ) - - test_selectors = Flaky( - """ - Timing issues on appveyor. - """, - when=PY3 & APPVEYOR, - ignore_coverage=ALWAYS, - ) - - test__example_portforwarder = Flaky( - """ - This one sometimes times out, often after output "The process - with PID XXX could not be terminated. Reason: There is no - running instance of the task.", - """, - when=APPVEYOR | COVERAGE - ) - - test__issue302monkey = test__threading_vs_settrace = Flaky( - """ - The gevent concurrency plugin tends to slow things - down and get us past our default timeout value. These - tests in particular are sensitive to it. So in fact we just turn them - off. - """, - when=COVERAGE, - ignore_coverage=ALWAYS, - ) - - test__hub_join_timeout = Ignored( - r""" - This sometimes times out. It appears to happen when the - times take too long and a test raises a FlakyTestTimeout error, - aka a unittest.SkipTest error. This probably indicates that we're - not cleaning something up correctly: - - .....ss - GEVENTTEST_USE_RESOURCES=-network C:\Python38-x64\python.exe -u \ - -mgevent.tests.test__hub_join_timeout [code TIMEOUT] [took 100.4s] - """, - when=APPVEYOR - ) - - test__example_wsgiserver = test__example_webproxy = RunAlone( - """ - These share the same port, which means they can conflict - between concurrent test runs too - XXX: Fix this by dynamically picking a port. - """, - ) - - test__pool = RunAlone( - """ - On a heavily loaded box, these can all take upwards of 200s. - """, - when=(CI & LEAKTEST) | (PYPY3 & APPVEYOR) - ) - - test_socket = RunAlone( - "Sometimes has unexpected timeouts", - when=CI & PYPY & PY3, - ignore_coverage=ALWAYS, # times out - ) - - test__refcount = Ignored( - "Sometimes fails to connect for no reason", - when=(CI & OSX) | (CI & PYPY) | APPVEYOR, - ignore_coverage=PYPY - ) - - test__doctests = Ignored( - "Sometimes times out during/after gevent._config.Config", - when=CI & OSX - ) - - test_httplib = Ignored( - """ - Imports ``test.support.testcase.ExtraAssertions`` - which doesn't exist yet. - """, - when=PY313LT5, - ) - - - -# tests that can't be run when coverage is enabled -# TODO: Now that we have this declarative, we could eliminate this list, -# just add them to the main IGNORED_TESTS list. -IGNORE_COVERAGE = [ -] - -# A mapping from test file basename to a dictionary of -# options that will be applied on top of the DEFAULT_RUN_OPTIONS. -TEST_FILE_OPTIONS = { - -} - -FAILING_TESTS = [] -IGNORED_TESTS = [] -# tests that don't do well when run on busy box -# or that are mutually exclusive -RUN_ALONE = [ - -] - -def populate(): # pylint:disable=too-many-branches - # TODO: Maybe move to the metaclass. - # TODO: This could be better. - for k, v in Definitions.__dict__.items(): - if isinstance(v, Multi): - actions = v._conds - else: - actions = (v,) - test_name = k + '.py' - del k, v - - for action in actions: - if not isinstance(action, _Action): - continue - - if action.run_alone: - RUN_ALONE.append(test_name) - if action.ignore_coverage: - IGNORE_COVERAGE.append(test_name) - if action.options: - for opt_name, (condition, value) in action.options.items(): - # TODO: Verify that this doesn't match more than once. - if condition: - TEST_FILE_OPTIONS.setdefault(test_name, {})[opt_name] = value - if action.when: - if isinstance(action, Ignored): - IGNORED_TESTS.append(test_name) - elif isinstance(action, Flaky): - FAILING_TESTS.append('FLAKY ' + test_name) - elif isinstance(action, Failing): - FAILING_TESTS.append(test_name) - - FAILING_TESTS.sort() - IGNORED_TESTS.sort() - RUN_ALONE.sort() - -populate() - -if __name__ == '__main__': - print('known_failures:\n', FAILING_TESTS) - print('ignored tests:\n', IGNORED_TESTS) - print('run alone:\n', RUN_ALONE) - print('options:\n', TEST_FILE_OPTIONS) - print("ignore during coverage:\n", IGNORE_COVERAGE) diff --git a/venv/lib/python3.9/site-packages/gevent/tests/lock_tests.py b/venv/lib/python3.9/site-packages/gevent/tests/lock_tests.py deleted file mode 100644 index 1033df7..0000000 --- a/venv/lib/python3.9/site-packages/gevent/tests/lock_tests.py +++ /dev/null @@ -1,764 +0,0 @@ -""" -Various tests for synchronization primitives. -""" -# pylint:disable=no-member,abstract-method -import sys -import time -try: - from thread import start_new_thread, get_ident -except ImportError: - from _thread import start_new_thread, get_ident -import threading -import unittest - -from gevent.testing import support -from gevent.testing.testcase import TimeAssertMixin - -def _wait(): - # A crude wait/yield function not relying on synchronization primitives. - time.sleep(0.01) - -class Bunch(object): - """ - A bunch of threads. - """ - def __init__(self, f, n, wait_before_exit=False): - """ - Construct a bunch of `n` threads running the same function `f`. - If `wait_before_exit` is True, the threads won't terminate until - do_finish() is called. - """ - self.f = f - self.n = n - self.started = [] - self.finished = [] - self._can_exit = not wait_before_exit - def task(): - tid = get_ident() - self.started.append(tid) - try: - f() - finally: - self.finished.append(tid) - while not self._can_exit: - _wait() - for _ in range(n): - start_new_thread(task, ()) - - def wait_for_started(self): - while len(self.started) < self.n: - _wait() - - def wait_for_finished(self): - while len(self.finished) < self.n: - _wait() - - def do_finish(self): - self._can_exit = True - - -class BaseTestCase(TimeAssertMixin, unittest.TestCase): - def setUp(self): - self._threads = support.threading_setup() - - def tearDown(self): - support.threading_cleanup(*self._threads) - support.reap_children() - - -class BaseLockTests(BaseTestCase): - """ - Tests for both recursive and non-recursive locks. - """ - - def locktype(self): - raise NotImplementedError() - - def test_constructor(self): - lock = self.locktype() - del lock - - def test_acquire_destroy(self): - lock = self.locktype() - lock.acquire() - del lock - - def test_acquire_release(self): - lock = self.locktype() - lock.acquire() - lock.release() - del lock - - def test_try_acquire(self): - lock = self.locktype() - self.assertTrue(lock.acquire(False)) - lock.release() - - def test_try_acquire_contended(self): - lock = self.locktype() - lock.acquire() - result = [] - def f(): - result.append(lock.acquire(False)) - Bunch(f, 1).wait_for_finished() - self.assertFalse(result[0]) - lock.release() - - def test_acquire_contended(self): - lock = self.locktype() - lock.acquire() - N = 5 - def f(): - lock.acquire() - lock.release() - - b = Bunch(f, N) - b.wait_for_started() - _wait() - self.assertEqual(len(b.finished), 0) - lock.release() - b.wait_for_finished() - self.assertEqual(len(b.finished), N) - - def test_with(self): - lock = self.locktype() - def f(): - lock.acquire() - lock.release() - def _with(err=None): - with lock: - if err is not None: - raise err # pylint:disable=raising-bad-type - _with() - # Check the lock is unacquired - Bunch(f, 1).wait_for_finished() - self.assertRaises(TypeError, _with, TypeError) - # Check the lock is unacquired - Bunch(f, 1).wait_for_finished() - - def test_thread_leak(self): - # The lock shouldn't leak a Thread instance when used from a foreign - # (non-threading) thread. - lock = self.locktype() - def f(): - lock.acquire() - lock.release() - n = len(threading.enumerate()) - # We run many threads in the hope that existing threads ids won't - # be recycled. - Bunch(f, 15).wait_for_finished() - self.assertEqual(n, len(threading.enumerate())) - - -class LockTests(BaseLockTests): # pylint:disable=abstract-method - """ - Tests for non-recursive, weak locks - (which can be acquired and released from different threads). - """ - def test_reacquire(self): - # Lock needs to be released before re-acquiring. - lock = self.locktype() - phase = [] - def f(): - lock.acquire() - phase.append(None) - lock.acquire() - phase.append(None) - start_new_thread(f, ()) - while not phase: - _wait() - _wait() - self.assertEqual(len(phase), 1) - lock.release() - while len(phase) == 1: - _wait() - self.assertEqual(len(phase), 2) - - def test_different_thread(self): - # Lock can be released from a different thread. - lock = self.locktype() - lock.acquire() - def f(): - lock.release() - b = Bunch(f, 1) - b.wait_for_finished() - lock.acquire() - lock.release() - - -class RLockTests(BaseLockTests): - """ - Tests for recursive locks. - """ - def test_reacquire(self): - lock = self.locktype() - lock.acquire() - lock.acquire() - lock.release() - lock.acquire() - lock.release() - lock.release() - - def test_release_unacquired(self): - # Cannot release an unacquired lock - lock = self.locktype() - self.assertRaises(RuntimeError, lock.release) - lock.acquire() - lock.acquire() - lock.release() - lock.acquire() - lock.release() - lock.release() - self.assertRaises(RuntimeError, lock.release) - - def test_different_thread(self): - # Cannot release from a different thread - lock = self.locktype() - def f(): - lock.acquire() - b = Bunch(f, 1, True) - try: - self.assertRaises(RuntimeError, lock.release) - finally: - b.do_finish() - - def test__is_owned(self): - lock = self.locktype() - self.assertFalse(lock._is_owned()) - lock.acquire() - self.assertTrue(lock._is_owned()) - lock.acquire() - self.assertTrue(lock._is_owned()) - result = [] - def f(): - result.append(lock._is_owned()) - Bunch(f, 1).wait_for_finished() - self.assertFalse(result[0]) - lock.release() - self.assertTrue(lock._is_owned()) - lock.release() - self.assertFalse(lock._is_owned()) - - -class EventTests(BaseTestCase): - """ - Tests for Event objects. - """ - - def eventtype(self): - raise NotImplementedError() - - def test_is_set(self): - evt = self.eventtype() - self.assertFalse(evt.is_set()) - evt.set() - self.assertTrue(evt.is_set()) - evt.set() - self.assertTrue(evt.is_set()) - evt.clear() - self.assertFalse(evt.is_set()) - evt.clear() - self.assertFalse(evt.is_set()) - - def _check_notify(self, evt): - # All threads get notified - N = 5 - results1 = [] - results2 = [] - def f(): - evt.wait() - results1.append(evt.is_set()) - evt.wait() - results2.append(evt.is_set()) - b = Bunch(f, N) - b.wait_for_started() - _wait() - self.assertEqual(len(results1), 0) - evt.set() - b.wait_for_finished() - self.assertEqual(results1, [True] * N) - self.assertEqual(results2, [True] * N) - - def test_notify(self): - evt = self.eventtype() - self._check_notify(evt) - # Another time, after an explicit clear() - evt.set() - evt.clear() - self._check_notify(evt) - - def test_timeout(self): - evt = self.eventtype() - results1 = [] - results2 = [] - N = 5 - def f(): - evt.wait(0.0) - results1.append(evt.is_set()) - t1 = time.time() - evt.wait(0.2) - r = evt.is_set() - t2 = time.time() - results2.append((r, t2 - t1)) - Bunch(f, N).wait_for_finished() - self.assertEqual(results1, [False] * N) - for r, dt in results2: - self.assertFalse(r) - self.assertTimeWithinRange(dt, 0.18, 10) - # The event is set - results1 = [] - results2 = [] - evt.set() - Bunch(f, N).wait_for_finished() - self.assertEqual(results1, [True] * N) - for r, dt in results2: - self.assertTrue(r) - - -class ConditionTests(BaseTestCase): - """ - Tests for condition variables. - """ - - def condtype(self, *args): - raise NotImplementedError() - - def test_acquire(self): - cond = self.condtype() - # Be default we have an RLock: the condition can be acquired multiple - # times. - # pylint:disable=consider-using-with - cond.acquire() - cond.acquire() - cond.release() - cond.release() - lock = threading.Lock() - cond = self.condtype(lock) - cond.acquire() - self.assertFalse(lock.acquire(False)) - cond.release() - self.assertTrue(lock.acquire(False)) - self.assertFalse(cond.acquire(False)) - lock.release() - with cond: - self.assertFalse(lock.acquire(False)) - - def test_unacquired_wait(self): - cond = self.condtype() - self.assertRaises(RuntimeError, cond.wait) - - def test_unacquired_notify(self): - cond = self.condtype() - self.assertRaises(RuntimeError, cond.notify) - - def _check_notify(self, cond): - N = 5 - results1 = [] - results2 = [] - phase_num = 0 - def f(): - cond.acquire() - cond.wait() - cond.release() - results1.append(phase_num) - cond.acquire() - cond.wait() - cond.release() - results2.append(phase_num) - b = Bunch(f, N) - b.wait_for_started() - _wait() - self.assertEqual(results1, []) - # Notify 3 threads at first - cond.acquire() - cond.notify(3) - _wait() - phase_num = 1 - cond.release() - while len(results1) < 3: - _wait() - self.assertEqual(results1, [1] * 3) - self.assertEqual(results2, []) - # Notify 5 threads: they might be in their first or second wait - cond.acquire() - cond.notify(5) - _wait() - phase_num = 2 - cond.release() - while len(results1) + len(results2) < 8: - _wait() - self.assertEqual(results1, [1] * 3 + [2] * 2) - self.assertEqual(results2, [2] * 3) - # Notify all threads: they are all in their second wait - cond.acquire() - cond.notify_all() - _wait() - phase_num = 3 - cond.release() - while len(results2) < 5: - _wait() - self.assertEqual(results1, [1] * 3 + [2] * 2) - self.assertEqual(results2, [2] * 3 + [3] * 2) - b.wait_for_finished() - - def test_notify(self): - cond = self.condtype() - self._check_notify(cond) - # A second time, to check internal state is still ok. - self._check_notify(cond) - - def test_timeout(self): - cond = self.condtype() - results = [] - N = 5 - def f(): - cond.acquire() - t1 = time.time() - cond.wait(0.2) - t2 = time.time() - cond.release() - results.append(t2 - t1) - Bunch(f, N).wait_for_finished() - self.assertEqual(len(results), 5) - for dt in results: - # XXX: libuv sometimes produces 0.19958 - self.assertTimeWithinRange(dt, 0.19, 2.0) - - -class BaseSemaphoreTests(BaseTestCase): - """ - Common tests for {bounded, unbounded} semaphore objects. - """ - - def semtype(self, *args): - raise NotImplementedError() - - def test_constructor(self): - self.assertRaises(ValueError, self.semtype, value=-1) - # Py3 doesn't have sys.maxint - self.assertRaises((ValueError, OverflowError), self.semtype, - value=-getattr(sys, 'maxint', getattr(sys, 'maxsize', None))) - - def test_acquire(self): - sem = self.semtype(1) - sem.acquire() - sem.release() - sem = self.semtype(2) - sem.acquire() - sem.acquire() - sem.release() - sem.release() - - def test_acquire_destroy(self): - sem = self.semtype() - sem.acquire() - del sem - - def test_acquire_contended(self): - sem = self.semtype(7) - sem.acquire() - #N = 10 - results1 = [] - results2 = [] - phase_num = 0 - def f(): - sem.acquire() - results1.append(phase_num) - sem.acquire() - results2.append(phase_num) - b = Bunch(f, 10) - b.wait_for_started() - while len(results1) + len(results2) < 6: - _wait() - self.assertEqual(results1 + results2, [0] * 6) - phase_num = 1 - for _ in range(7): - sem.release() - while len(results1) + len(results2) < 13: - _wait() - self.assertEqual(sorted(results1 + results2), [0] * 6 + [1] * 7) - phase_num = 2 - for _ in range(6): - sem.release() - while len(results1) + len(results2) < 19: - _wait() - self.assertEqual(sorted(results1 + results2), [0] * 6 + [1] * 7 + [2] * 6) - # The semaphore is still locked - self.assertFalse(sem.acquire(False)) - # Final release, to let the last thread finish - sem.release() - b.wait_for_finished() - - def test_try_acquire(self): - sem = self.semtype(2) - self.assertTrue(sem.acquire(False)) - self.assertTrue(sem.acquire(False)) - self.assertFalse(sem.acquire(False)) - sem.release() - self.assertTrue(sem.acquire(False)) - - def test_try_acquire_contended(self): - sem = self.semtype(4) - sem.acquire() - results = [] - def f(): - results.append(sem.acquire(False)) - results.append(sem.acquire(False)) - Bunch(f, 5).wait_for_finished() - # There can be a thread switch between acquiring the semaphore and - # appending the result, therefore results will not necessarily be - # ordered. - self.assertEqual(sorted(results), [False] * 7 + [True] * 3) - - def test_default_value(self): - # The default initial value is 1. - sem = self.semtype() - sem.acquire() - def f(): - sem.acquire() - sem.release() - b = Bunch(f, 1) - b.wait_for_started() - _wait() - self.assertFalse(b.finished) - sem.release() - b.wait_for_finished() - - def test_with(self): - sem = self.semtype(2) - def _with(err=None): - with sem: - self.assertTrue(sem.acquire(False)) - sem.release() - with sem: - self.assertFalse(sem.acquire(False)) - if err: - raise err # pylint:disable=raising-bad-type - _with() - self.assertTrue(sem.acquire(False)) - sem.release() - self.assertRaises(TypeError, _with, TypeError) - self.assertTrue(sem.acquire(False)) - sem.release() - -class SemaphoreTests(BaseSemaphoreTests): - """ - Tests for unbounded semaphores. - """ - - def test_release_unacquired(self): - # Unbounded releases are allowed and increment the semaphore's value - sem = self.semtype(1) - sem.release() - sem.acquire() - sem.acquire() - sem.release() - - -class BoundedSemaphoreTests(BaseSemaphoreTests): - """ - Tests for bounded semaphores. - """ - - def test_release_unacquired(self): - # Cannot go past the initial value - sem = self.semtype() - self.assertRaises(ValueError, sem.release) - sem.acquire() - sem.release() - self.assertRaises(ValueError, sem.release) - -class BarrierTests(BaseTestCase): - """ - Tests for Barrier objects. - """ - N = 5 - defaultTimeout = 2.0 - - def setUp(self): - self.barrier = self.barriertype(self.N, timeout=self.defaultTimeout) - def tearDown(self): - self.barrier.abort() - - def run_threads(self, f): - b = Bunch(f, self.N-1) - f() - b.wait_for_finished() - - def multipass(self, results, n): - m = self.barrier.parties - self.assertEqual(m, self.N) - for i in range(n): - results[0].append(True) - self.assertEqual(len(results[1]), i * m) - self.barrier.wait() - results[1].append(True) - self.assertEqual(len(results[0]), (i + 1) * m) - self.barrier.wait() - self.assertEqual(self.barrier.n_waiting, 0) - self.assertFalse(self.barrier.broken) - - def test_barrier(self, passes=1): - """ - Test that a barrier is passed in lockstep - """ - results = [[], []] - def f(): - self.multipass(results, passes) - self.run_threads(f) - - def test_barrier_10(self): - """ - Test that a barrier works for 10 consecutive runs - """ - return self.test_barrier(10) - - def test_wait_return(self): - """ - test the return value from barrier.wait - """ - results = [] - def f(): - r = self.barrier.wait() - results.append(r) - - self.run_threads(f) - self.assertEqual(sum(results), sum(range(self.N))) - - def test_action(self): - """ - Test the 'action' callback - """ - results = [] - def action(): - results.append(True) - barrier = self.barriertype(self.N, action) - def f(): - barrier.wait() - self.assertEqual(len(results), 1) - - self.run_threads(f) - - def test_abort(self): - """ - Test that an abort will put the barrier in a broken state - """ - results1 = [] - results2 = [] - def f(): - try: - i = self.barrier.wait() - if i == self.N//2: - raise RuntimeError - self.barrier.wait() - results1.append(True) - except threading.BrokenBarrierError: - results2.append(True) - except RuntimeError: - self.barrier.abort() - - self.run_threads(f) - self.assertEqual(len(results1), 0) - self.assertEqual(len(results2), self.N-1) - self.assertTrue(self.barrier.broken) - - def test_reset(self): - """ - Test that a 'reset' on a barrier frees the waiting threads - """ - results1 = [] - results2 = [] - results3 = [] - def f(): - i = self.barrier.wait() - if i == self.N//2: - # Wait until the other threads are all in the barrier. - while self.barrier.n_waiting < self.N-1: - time.sleep(0.001) - self.barrier.reset() - else: - try: - self.barrier.wait() - results1.append(True) - except threading.BrokenBarrierError: - results2.append(True) - # Now, pass the barrier again - self.barrier.wait() - results3.append(True) - - self.run_threads(f) - self.assertEqual(len(results1), 0) - self.assertEqual(len(results2), self.N-1) - self.assertEqual(len(results3), self.N) - - - def test_abort_and_reset(self): - """ - Test that a barrier can be reset after being broken. - """ - results1 = [] - results2 = [] - results3 = [] - barrier2 = self.barriertype(self.N) - def f(): - try: - i = self.barrier.wait() - if i == self.N//2: - raise RuntimeError - self.barrier.wait() - results1.append(True) - except threading.BrokenBarrierError: - results2.append(True) - except RuntimeError: - self.barrier.abort() - - # Synchronize and reset the barrier. Must synchronize first so - # that everyone has left it when we reset, and after so that no - # one enters it before the reset. - if barrier2.wait() == self.N//2: - self.barrier.reset() - barrier2.wait() - self.barrier.wait() - results3.append(True) - - self.run_threads(f) - self.assertEqual(len(results1), 0) - self.assertEqual(len(results2), self.N-1) - self.assertEqual(len(results3), self.N) - - def test_timeout(self): - """ - Test wait(timeout) - """ - def f(): - i = self.barrier.wait() - if i == self.N // 2: - # One thread is late! - time.sleep(1.0) - # Default timeout is 2.0, so this is shorter. - self.assertRaises(threading.BrokenBarrierError, - self.barrier.wait, 0.5) - self.run_threads(f) - - def test_default_timeout(self): - """ - Test the barrier's default timeout - """ - # create a barrier with a low default timeout - barrier = self.barriertype(self.N, timeout=0.3) - def f(): - i = barrier.wait() - if i == self.N // 2: - # One thread is later than the default timeout of 0.3s. - time.sleep(1.0) - self.assertRaises(threading.BrokenBarrierError, barrier.wait) - self.run_threads(f) - - def test_single_thread(self): - b = self.barriertype(1) - b.wait() - b.wait() - - -if __name__ == '__main__': - print("This module contains no tests; it is used by other test cases like test_threading_2") diff --git a/venv/lib/python3.9/site-packages/gevent/tests/monkey_package/__init__.py b/venv/lib/python3.9/site-packages/gevent/tests/monkey_package/__init__.py deleted file mode 100644 index 34431cf..0000000 --- a/venv/lib/python3.9/site-packages/gevent/tests/monkey_package/__init__.py +++ /dev/null @@ -1,12 +0,0 @@ -# -*- coding: utf-8 -*- -""" -Make a package. - -This file has no other functionality. Individual modules in this package -are used for testing, often being run with 'python -m ...' in individual -test cases (functions). - -""" -from __future__ import absolute_import -from __future__ import division -from __future__ import print_function diff --git a/venv/lib/python3.9/site-packages/gevent/tests/monkey_package/__main__.py b/venv/lib/python3.9/site-packages/gevent/tests/monkey_package/__main__.py deleted file mode 100644 index edfd6f0..0000000 --- a/venv/lib/python3.9/site-packages/gevent/tests/monkey_package/__main__.py +++ /dev/null @@ -1,9 +0,0 @@ -from __future__ import print_function -# This file makes this directory into a runnable package. -# it exists to test 'python -m gevent.monkey monkey_package' -# Note that the __file__ may differ slightly; starting with -# Python 3.9, directly running it gets an abspath, but -# using ``runpy`` doesn't. -import os.path -print(os.path.abspath(__file__)) -print(__name__) diff --git a/venv/lib/python3.9/site-packages/gevent/tests/monkey_package/issue1526_no_monkey.py b/venv/lib/python3.9/site-packages/gevent/tests/monkey_package/issue1526_no_monkey.py deleted file mode 100644 index 38bb195..0000000 --- a/venv/lib/python3.9/site-packages/gevent/tests/monkey_package/issue1526_no_monkey.py +++ /dev/null @@ -1,21 +0,0 @@ -# -*- coding: utf-8 -*- -""" -Test for issue #1526: -- dnspython is imported first; -- no monkey-patching is done. -""" -from __future__ import print_function -from __future__ import absolute_import - -import dns # pylint:disable=import-error -assert dns -import gevent.socket as socket # pylint:disable=consider-using-from-import -socket.getfqdn() # create the resolver - -from gevent.resolver.dnspython import dns as gdns -import dns.rdtypes # pylint:disable=import-error - -assert dns is not gdns, (dns, gdns) -assert dns.rdtypes is not gdns.rdtypes -import sys -print(sorted(sys.modules)) diff --git a/venv/lib/python3.9/site-packages/gevent/tests/monkey_package/issue1526_with_monkey.py b/venv/lib/python3.9/site-packages/gevent/tests/monkey_package/issue1526_with_monkey.py deleted file mode 100644 index e3fbfe3..0000000 --- a/venv/lib/python3.9/site-packages/gevent/tests/monkey_package/issue1526_with_monkey.py +++ /dev/null @@ -1,28 +0,0 @@ -# -*- coding: utf-8 -*- -""" -Test for issue #1526: -- dnspython is imported first; -- monkey-patching happens early -""" -from __future__ import print_function, absolute_import - -from gevent import monkey -monkey.patch_all() -# pylint:disable=import-error -import dns -assert dns - -import socket -import sys - -socket.getfqdn() - -import gevent.resolver.dnspython -from gevent.resolver.dnspython import dns as gdns -from dns import rdtypes # NOT import dns.rdtypes - -assert gevent.resolver.dnspython.dns is gdns -assert gdns is not dns, (gdns, dns, "id dns", id(dns)) -assert gdns.rdtypes is not rdtypes, (gdns.rdtypes, rdtypes) -assert hasattr(dns, 'rdtypes') -print(sorted(sys.modules)) diff --git a/venv/lib/python3.9/site-packages/gevent/tests/monkey_package/issue302monkey.py b/venv/lib/python3.9/site-packages/gevent/tests/monkey_package/issue302monkey.py deleted file mode 100644 index 104e943..0000000 --- a/venv/lib/python3.9/site-packages/gevent/tests/monkey_package/issue302monkey.py +++ /dev/null @@ -1,26 +0,0 @@ -from __future__ import print_function -import socket -import sys -import os.path -if sys.argv[1] == 'patched': - print('gevent' in repr(socket.socket)) -else: - assert sys.argv[1] == 'stdlib' - print('gevent' not in repr(socket.socket)) -print(os.path.abspath(__file__)) - - - -if sys.argv[1] == 'patched': - # __package__ is handled differently, for some reason, and - # runpy doesn't let us override it. When we call it, it - # becomes ''. This appears to be against the documentation for - # runpy, which says specifically "If the supplied path - # directly references a script file (whether as source or as - # precompiled byte code), then __file__ will be set to the - # supplied path, and __spec__, __cached__, __loader__ and - # __package__ will all be set to None." - print(__package__ == '') # pylint:disable=compare-to-empty-string -else: - # but the interpreter sets it to None - print(__package__ is None) diff --git a/venv/lib/python3.9/site-packages/gevent/tests/monkey_package/script.py b/venv/lib/python3.9/site-packages/gevent/tests/monkey_package/script.py deleted file mode 100644 index 4f3f616..0000000 --- a/venv/lib/python3.9/site-packages/gevent/tests/monkey_package/script.py +++ /dev/null @@ -1,20 +0,0 @@ -# -*- coding: utf-8 -*- -""" -Test script file, to be used directly as a file. -""" -from __future__ import absolute_import -from __future__ import division -from __future__ import print_function - - -# We need some global imports -from textwrap import dedent - -def use_import(): - return dedent(" text") - -if __name__ == '__main__': - import os.path - print(os.path.abspath(__file__)) - print(__name__) - print(use_import()) diff --git a/venv/lib/python3.9/site-packages/gevent/tests/monkey_package/threadpool_monkey_patches.py b/venv/lib/python3.9/site-packages/gevent/tests/monkey_package/threadpool_monkey_patches.py deleted file mode 100644 index 7ee922b..0000000 --- a/venv/lib/python3.9/site-packages/gevent/tests/monkey_package/threadpool_monkey_patches.py +++ /dev/null @@ -1,30 +0,0 @@ -# -*- coding: utf-8 -*- -""" -This file runs ``gevent.monkey.patch_all()``. - -It is intended to be used by ``python -m gevent.monkey `` -to prove that monkey-patching twice doesn't have unfortunate sife effects (such as -breaking the threadpool). -""" -from __future__ import absolute_import -from __future__ import division -from __future__ import print_function - -import sys -from gevent import monkey -from gevent import get_hub - -monkey.patch_all(thread=False, sys=True) - -def thread_is_greenlet(): - from gevent.thread import get_ident as gr_ident - std_thread_mod = 'thread' if bytes is str else '_thread' - thr_ident = monkey.get_original(std_thread_mod, 'get_ident') - return thr_ident() == gr_ident() - - -is_greenlet = get_hub().threadpool.apply(thread_is_greenlet) -print(is_greenlet) -print(len(sys._current_frames())) -sys.stdout.flush() -sys.stderr.flush() diff --git a/venv/lib/python3.9/site-packages/gevent/tests/monkey_package/threadpool_no_monkey.py b/venv/lib/python3.9/site-packages/gevent/tests/monkey_package/threadpool_no_monkey.py deleted file mode 100644 index bcbccbb..0000000 --- a/venv/lib/python3.9/site-packages/gevent/tests/monkey_package/threadpool_no_monkey.py +++ /dev/null @@ -1,30 +0,0 @@ -# -*- coding: utf-8 -*- -""" -This file *does not* run ``gevent.monkey.patch_all()``. - -It is intended to be used by ``python -m gevent.monkey `` -to prove that the threadpool and getting the original value of things -works. -""" -from __future__ import absolute_import -from __future__ import division -from __future__ import print_function - -import sys -from gevent import monkey -from gevent import get_hub - -from gevent.thread import get_ident as gr_ident - -std_thread_mod = 'thread' if bytes is str else '_thread' -thr_ident = monkey.get_original(std_thread_mod, 'get_ident') - -print(thr_ident is gr_ident) - -def thread_is_greenlet(): - return thr_ident() == gr_ident() - - -is_greenlet = get_hub().threadpool.apply(thread_is_greenlet) -print(is_greenlet) -print(len(sys._current_frames())) diff --git a/venv/lib/python3.9/site-packages/gevent/tests/nullcert.pem b/venv/lib/python3.9/site-packages/gevent/tests/nullcert.pem deleted file mode 100644 index e69de29..0000000 diff --git a/venv/lib/python3.9/site-packages/gevent/tests/server.crt b/venv/lib/python3.9/site-packages/gevent/tests/server.crt deleted file mode 100644 index 78f036f..0000000 --- a/venv/lib/python3.9/site-packages/gevent/tests/server.crt +++ /dev/null @@ -1,29 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIFCzCCAvOgAwIBAgIUePnEKFfhxpt3oypt6nTicAGTFJowDQYJKoZIhvcNAQEL -BQAwFDESMBAGA1UEAwwJbG9jYWxob3N0MCAXDTIxMDcwODExMzQzNVoYDzIxMjEw -NjE0MTEzNDM1WjAUMRIwEAYDVQQDDAlsb2NhbGhvc3QwggIiMA0GCSqGSIb3DQEB -AQUAA4ICDwAwggIKAoICAQChqfmG6uOG95Jb7uRi6yxohJ8GOR3gi39yX6JB+Xdu -kvqxy2/vsjH1+CF1i8jKZZO0hJLGT+/GmKIc1c0XUEjVoQvCNQHIaDTXiUXOGXfk -QNKR0vtJH5ZOZn/tvYAKPniYPmHuF3TpAB6HouLpyIC55SXdK7pTEbmU7J1aBjug -n3O56cu6FzjU1j/0QVUVGloxApLvv57bmINaX9ygKsh/ug0lhV1RwYLJ9UX57m95 -FIlcofa98tCuoKi++G+sWsjopDXVmsiTbjZfs72kcDUTRYKNZbRFRRETORdOVRHx -lAIPEn4QFYn/3wVSNFvfeY0j8RI5YcPLU66Batun6HU+YAs6z8Qc8S1EMElJdoyV -eLCqLA07btICzKq2I16TZAOWVng2P7NOtibAeCzDAxAxJ3Oby+BVikKcu8WmJLxG -vRvaPljdD76xjPB5NK6O0J62C3uU3EWhPODX9H5l/WF+aNRqSccgs0Umddj33N+b -/mTJnHn1GpanThrv1UfOFGKfxjemwESz66d1iqD7iXvTxt7yZeU7LIMRgDqhVe6z -oBpJEeWl9YYyfGPwgIOhwzNVZ5WkzQARs7si3j3Wkmyca7hEN8qq8DkLWNf1PTcI -wo/239wKRbyW3Z+U4IGRrVMdeSoC2JpRAx/eEXTjuUePQlHCvwW9iiY7jTjDfbIv -pwIDAQABo1MwUTAdBgNVHQ4EFgQUTUfShFbaXGMwrWEAkm05sXFH/x4wHwYDVR0j -BBgwFoAUTUfShFbaXGMwrWEAkm05sXFH/x4wDwYDVR0TAQH/BAUwAwEB/zANBgkq -hkiG9w0BAQsFAAOCAgEAe65ORDx0NDxTo1q6EY221KS3vEezUNBdZNaeOQsQeUAY -lEO5iZ+2QLIVlWC5UtvISK96FU2CX0ucgAGfHS2ZB7o8i95fbjG2qrWC+VUH4V/6 -jse9jlfGlYGkPuU5onNIDGcZ7gay3n0prCDiguAmCzV419GnGDWgSSgyVNCp/0tx -b7pR5cVr0kZ5bTZjiysEEprkG2ofAlXzj09VGtTfM8gQvCz9Puj7pGzw2iaIEQVk -hSGjoRWlI5x6+o16JOTHXzv9cYRUfDX6tjw3nQJIeMipuUkR8pkHUFjG3EeJEtO3 -X/GO0G8rwUPaZiskGPiMZj7XqoVclnYL7JtntwUHR/dU5A/EhDfhgEfTXTqT78Oe -cKri+VJE+G/hYxbP0FNYaDtqIwJcX1tsy4HOpKVBncc+K/PvXElVsyQET/+uwH7p -Wm5ymndnuLoiQrWIA4nJC6rVwR4GPijuN0NCKcVdE+8jlOCBs3VBJTWKuu0J80RP -71iZy03AoK1YY4+nHglmE9HetAgSsbGh2fWC7DUS/4JzLSzOBeb+nn74zfmIfMU+ -qUArFXvVGAtjmZZ/63cWzXDMZsp1BZ+O5dx6Gi2QtjgGYhh6DhW7ocQYXDkAeN/O -K1Yzwq/G4AEQA0k0/1I+F0Rdlo41+7tOp+LMCOoZXqUzhM0ZQ2sf3QclubxLX9U= ------END CERTIFICATE----- diff --git a/venv/lib/python3.9/site-packages/gevent/tests/server.key b/venv/lib/python3.9/site-packages/gevent/tests/server.key deleted file mode 100644 index 754ad8d..0000000 --- a/venv/lib/python3.9/site-packages/gevent/tests/server.key +++ /dev/null @@ -1,52 +0,0 @@ ------BEGIN PRIVATE KEY----- -MIIJQwIBADANBgkqhkiG9w0BAQEFAASCCS0wggkpAgEAAoICAQChqfmG6uOG95Jb -7uRi6yxohJ8GOR3gi39yX6JB+Xdukvqxy2/vsjH1+CF1i8jKZZO0hJLGT+/GmKIc -1c0XUEjVoQvCNQHIaDTXiUXOGXfkQNKR0vtJH5ZOZn/tvYAKPniYPmHuF3TpAB6H -ouLpyIC55SXdK7pTEbmU7J1aBjugn3O56cu6FzjU1j/0QVUVGloxApLvv57bmINa -X9ygKsh/ug0lhV1RwYLJ9UX57m95FIlcofa98tCuoKi++G+sWsjopDXVmsiTbjZf -s72kcDUTRYKNZbRFRRETORdOVRHxlAIPEn4QFYn/3wVSNFvfeY0j8RI5YcPLU66B -atun6HU+YAs6z8Qc8S1EMElJdoyVeLCqLA07btICzKq2I16TZAOWVng2P7NOtibA -eCzDAxAxJ3Oby+BVikKcu8WmJLxGvRvaPljdD76xjPB5NK6O0J62C3uU3EWhPODX -9H5l/WF+aNRqSccgs0Umddj33N+b/mTJnHn1GpanThrv1UfOFGKfxjemwESz66d1 -iqD7iXvTxt7yZeU7LIMRgDqhVe6zoBpJEeWl9YYyfGPwgIOhwzNVZ5WkzQARs7si -3j3Wkmyca7hEN8qq8DkLWNf1PTcIwo/239wKRbyW3Z+U4IGRrVMdeSoC2JpRAx/e -EXTjuUePQlHCvwW9iiY7jTjDfbIvpwIDAQABAoICAC3CJMTRe3FaZezro210T2+O -Ck0CobhLA9nlw9GUwP9lTtxATwCzmXybrSzOUhknwzUXSUwkmCPIVCqBQbnVmagO -G3vu8QA+rqZLTpzVjJ/o0TFBXKsH681pKdCrELDVmeDN135C2W6SABI4Qq4VeIol -mCAQHn8gxzyl9Kvkk8AVIfZ/fJDBve5Qbm2+iEye1uSEa/68aEST2Kod9B7JvVKZ -4Nq78vwPH+v2JsZlfNvyuiakGWkOb47eHqVfQIyybaebwzkgxKEmUvGnuIfw0rUP -ubI4FVx9/iVIxZYAckHEuQh3HYOD9TmdcK4h79dDWnXP6G6hg3/rwbsT+fR+0aBQ -9rkKnA4uToGikYmplixAQ/jDBwMs3VQqenO+YBIsC4HEZ0fJUbs+l4LEnuUJxYcR -UlAvnVQXa1WGne3Yzb2xONWeiocKfhcdJ2JuQo00UR74+2Qonxn/WpimvlLCBDgI -uKxHCSWOgv5yPpU2kwTPIjORXcy/y2G9K2bnsQCzznPRDyNkZmavQxxG6greFcrO -/0yhRPuBgxKBRvXPO+F5fybKFlU9IPLFehV60jLUybBejab/lMJyxdkh9UMu2Xqy -FVsRGazJt6T6AGp6TFEEcFUQw7qXNhVo9S7zGGaJFJdYc+Vx8QJRoCe8EAYVH7Mp -b/eYGhHaKg6iG7QCjPPxAoIBAQDN54wtuDqpAA+4PmqhiEhQKhabNqAoVmAWUxnJ -Db4Zzvkkc3Fo/Yg0HnQVaT0KmkcxY7397lTdtiwNkWPgJ0f6+g7L4K7PA7xh/q84 -IoXFGvYWwVdiVXLR1l06jorpA20clnba6CsbezwcllTq4bWvNnrAcM8l1YrAlRnV -qqqbPL78Rnba4C8q+VFy8r0d9OGnbvFcV7VWJjhr0a3aZbHQ67jPinNiUWvBVFFx -yGrqPMjkeHyiTLMhqQpaSHH67S88rj0g9RKexBaSUrl18QO7xnQHHSCcFWMQOiSN -shNvFri48dnU+Ms6ZLc3MBHbTK6uzP8xJCVnmsz/MWPGkQZFAoIBAQDI/vj/3/y/ -EpIawyHN7PQAMoto4AQF6sVasrgGd1tRsJnGKrCugH9gILvyke3L7qg0JTV3bDJY -e8+vH1vC3NV7PsOlCFjMtRWG0lRbCh/b7Qe3pCvPu4mbFhJgMT/mz+vbl5zvcdgX -kvne+St/267NKnY5gHBDhqitBwkZwNlTWJ0zVmTecKXn/KwjS9lX1qU3HiT3UFkd -5Y5Nt5lj1IOK/6NCXkxVkgOc4Zjcxx138Cg03VJhIiHTusRq6z9iTSTDubhkaSbi -2nadptFBiQtkVhAJ5G53U7pl/pIhhiJy901bu/v/wrIMJ2l6hiZIcLrbg6VGXxjV -5dB7LDEtKoL7AoIBAQC8+ffA+mX0N9c1nSuWh5L+6DIJUHBbtTLJKonu6gsAeuJU -3xNGbfK1CwI1qHnaolAW91knlrcTKaBy726ACu1YXmp4GgW2f9JFCk/csGqfxaf4 -qIg/+va/ugOku7CoPXnGFB6PuSffOBKqlhrn3DI41kKBHsgwDDYlnHKylMmyYmVS -+oUZS0pfIaXsXvbNaLQ2TG9+9gy7Pabo5e+vE0jI25+p84MEyH+iV3XMfUoLI7Cp -aB/TgZuimBelVvotd8Sz56K4/dSSHJwuvXfz1Dk9/Nz+rnAAcOyTtxlXZwnJGkx9 -iZMIkTNMq6UwJJEu+ckVK5ZHjso5tWzSBo1xcCcVAoIBAQCPL0x1A7zK5VDd7cqE -J1w/U8KKiKN1D6VeElkUiiysyjERwdGxzmpvMYKSsDCGCdMbqrInDBXlgPYXnDBD -ZgxSywiW5ZZU5l+advWPEWxWwMmxoitvxfqmV5fpnMwYAmDUQ3KSBTjaumJ03G6H -nBkvoSMtnXjcMe6xrIRoK0Dmpgb+znn3GKqn1BFQ57TCZW+3DytoX33M1X6FkNie -DINVHv3Pxtt8ThNyzCeYh+RPT+9kkZIhDi6o5bENNd8miSw6nnBkX6BLFTRQ5MjH -dfh+luzAD1I+gZAVHsA9T4/09IXQZt+DeNBb5iu3FB/rlRsYS/UOZ6qKnjfhtz6l -HVbHAoIBAFjNY/UPJDxQ/uG+rMU0nrmSBRGdgBvQkcefjWX/LIZV3MjNilUQ+B2a -lXz5AHGmHRnnwQsBVfN8rf4qQLln8l34Kgm7+cIFavgfg2oqVbNyNgezSlUmRq0J -Ttf3xYJtRgRUx8F+BcgJXMqlNGTMQJY8wawM/ATkwkbmSwGOKe04sBeIkwEycMId -BupvfN5lxDrKqJVPSl1t5Rh4us95CNh22/c5Tq5rsynl02ZB4swlcsVTdv8FSGmM -QVf/MkWXGN/x4lHJhKyklHMGv15GGvys1nlPTstMfUYs55ioWRW46TXQ8vOyzzpg -67xzBKYFEde+hgYk7X1Xeqj8A6bsqro= ------END PRIVATE KEY----- diff --git a/venv/lib/python3.9/site-packages/gevent/tests/sha256.pem b/venv/lib/python3.9/site-packages/gevent/tests/sha256.pem deleted file mode 100644 index 01878e9..0000000 --- a/venv/lib/python3.9/site-packages/gevent/tests/sha256.pem +++ /dev/null @@ -1,33 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIFxzCCA6+gAwIBAgIJALnlnf5uzTkIMA0GCSqGSIb3DQEBCwUAMEsxCzAJBgNV -BAYTAkRFMRcwFQYDVQQKEw5zY2hva29rZWtzLm9yZzEjMCEGCSqGSIb3DQEJARYU -aGFubm9Ac2Nob2tva2Vrcy5vcmcwHhcNMTAwMTI3MDAyMTI1WhcNMjAwMTI1MDAy -MTI1WjBLMQswCQYDVQQGEwJERTEXMBUGA1UEChMOc2Nob2tva2Vrcy5vcmcxIzAh -BgkqhkiG9w0BCQEWFGhhbm5vQHNjaG9rb2tla3Mub3JnMIICIjANBgkqhkiG9w0B -AQEFAAOCAg8AMIICCgKCAgEApJ4ODPwEooMW35dQPlBqdvcfkEvjhcsA7jmJfFqN -e/1T34zT44X9+KnMBSG2InacbD7eyFgjfaENFsZ87YkEBDIFZ/SHotLJZORQ8PUj -YoxPG4mjKN+yL2WthNcYbRyJreTbbDroNMuw6tkTSxeSXyYFQrKMCUfErVbZa/d5 -RvfFVk+Au9dVUFhed/Stn5cv+a0ffvpyA7ygihm1kMFICbvPeI0846tmC2Ph7rM5 -pYQyNBDOVpULODTk5Wu6jiiJJygvJWCZ1FdpsdBs5aKWHWdRhX++quGuflTTjH5d -qaIka4op9H7XksYphTDXmV+qHnva5jbPogwutDQcVsGBQcJaLmQqhsQK13bf4khE -iWJvfBLfHn8OOpY25ZwwuigJIwifNCxQeeT1FrLmyuYNhz2phPpzx065kqSUSR+A -Iw8DPE6e65UqMDKqZnID3dQeiQaFrHEV+Ibo0U/tD0YSBw5p33TMh0Es33IBWMac -m7x4hIFWdhl8W522u6qOrTswY3s8vB7blNWqMc9n7oWH8ybFf7EgKeDVtEN9AyBE -0WotXIEZWI+WvDbU1ACJXau9sQhYP/eerg7Zwr3iGUy4IQ5oUJibnjtcE+z8zmDN -pE6YcMCLJyLjXiQ3iHG9mNXzw7wPnslTbEEEukrfSlHGgW8Dm+VrNyW0JUM1bntx -vbMCAwEAAaOBrTCBqjAdBgNVHQ4EFgQUCedv7pDTuXtCxm4HTw9hUtrTvsowewYD -VR0jBHQwcoAUCedv7pDTuXtCxm4HTw9hUtrTvsqhT6RNMEsxCzAJBgNVBAYTAkRF -MRcwFQYDVQQKEw5zY2hva29rZWtzLm9yZzEjMCEGCSqGSIb3DQEJARYUaGFubm9A -c2Nob2tva2Vrcy5vcmeCCQC55Z3+bs05CDAMBgNVHRMEBTADAQH/MA0GCSqGSIb3 -DQEBCwUAA4ICAQBHKAxA7WA/MEFjet03K8ouzEOr6Jrk2fZOuRhoDZ+9gr4FtaJB -P3Hh5D00kuSOvDnwsvCohxeNd1KTMAwVmVoH+NZkHERn3UXniUENlp18koI1ehlr -CZbXbzzE9Te9BelliSFA63q0cq0yJN1x9GyabU34XkAouCAmOqfSpKNZWZHGBHPF -bbYnZrHEMcsye6vKeTOcg1GqUHGrQM2WK0QaOwnCQv2RblI9VN+SeRoUJ44qTXdW -TwIYStsIPesacNcAQTStnHgKqIPx4zCwdx5xo8zONbXJfocqwyFqiAofvb9dN1nW -g1noVBcXB+oRBZW5CjFw87U88itq39i9+BWl835DWLBW2pVmx1QTLGv0RNgs/xVx -mWnjH4nNHvrjn6pRmqHZTk/SS0Hkl2qtDsynVxIl8EiMTfWSU3DBTuD2J/RSzuOE -eKtAbaoXkXE31jCl4FEZLITIZd8UkXacb9rN304tAK92L76JOAV+xOZxFRipmvx4 -+A9qQXgLhtP4VaDajb44V/kCKPSA0Vm3apehke9Wl8dDtagfos1e6MxSu3EVLXRF -SP2U777V77pdMSd0f/7cerKn5FjrxW1v1FaP1oIGniMk4qQNTgA/jvvhjybsPlVA -jsfnhWGbh1voJa0RQcMiRMsxpw2P1KNOEu37W2eq/vFghVztZJQUmb5iNw== ------END CERTIFICATE----- diff --git a/venv/lib/python3.9/site-packages/gevent/tests/test__GreenletExit.py b/venv/lib/python3.9/site-packages/gevent/tests/test__GreenletExit.py deleted file mode 100644 index acad1bb..0000000 --- a/venv/lib/python3.9/site-packages/gevent/tests/test__GreenletExit.py +++ /dev/null @@ -1,4 +0,0 @@ -from gevent import GreenletExit - -assert issubclass(GreenletExit, BaseException) -assert not issubclass(GreenletExit, Exception) diff --git a/venv/lib/python3.9/site-packages/gevent/tests/test___config.py b/venv/lib/python3.9/site-packages/gevent/tests/test___config.py deleted file mode 100644 index a512bbe..0000000 --- a/venv/lib/python3.9/site-packages/gevent/tests/test___config.py +++ /dev/null @@ -1,159 +0,0 @@ -# Copyright 2018 gevent contributors. See LICENSE for details. - -import os -import unittest -import sys - -from gevent import _config - -class TestResolver(unittest.TestCase): - - old_resolver = None - - def setUp(self): - if 'GEVENT_RESOLVER' in os.environ: - self.old_resolver = os.environ['GEVENT_RESOLVER'] - del os.environ['GEVENT_RESOLVER'] - - def tearDown(self): - if self.old_resolver: - os.environ['GEVENT_RESOLVER'] = self.old_resolver - - def test_key(self): - self.assertEqual(_config.Resolver.environment_key, 'GEVENT_RESOLVER') - - def test_default(self): - from gevent.resolver.thread import Resolver - - conf = _config.Resolver() - self.assertEqual(conf.get(), Resolver) - - def test_env(self): - from gevent.resolver.blocking import Resolver - - os.environ['GEVENT_RESOLVER'] = 'foo,bar,block,dnspython' - - conf = _config.Resolver() - self.assertEqual(conf.get(), Resolver) - - os.environ['GEVENT_RESOLVER'] = 'dnspython' - - # The existing value is unchanged - self.assertEqual(conf.get(), Resolver) - - # A new object reflects it - try: - from gevent.resolver.dnspython import Resolver as DResolver - except ImportError: # pragma: no cover - # dnspython is optional; skip it. - import warnings - warnings.warn('dnspython not installed') - else: - conf = _config.Resolver() - - self.assertEqual(conf.get(), DResolver) - - def test_set_str_long(self): - from gevent.resolver.blocking import Resolver - conf = _config.Resolver() - conf.set('gevent.resolver.blocking.Resolver') - - self.assertEqual(conf.get(), Resolver) - - def test_set_str_short(self): - from gevent.resolver.blocking import Resolver - conf = _config.Resolver() - conf.set('block') - - self.assertEqual(conf.get(), Resolver) - - def test_set_class(self): - from gevent.resolver.blocking import Resolver - conf = _config.Resolver() - conf.set(Resolver) - - self.assertEqual(conf.get(), Resolver) - - - def test_set_through_config(self): - from gevent.resolver.thread import Resolver as Default - from gevent.resolver.blocking import Resolver - - conf = _config.Config() - self.assertEqual(conf.resolver, Default) - - conf.resolver = 'block' - self.assertEqual(conf.resolver, Resolver) - -class TestFunctions(unittest.TestCase): - - def test_validate_bool(self): - self.assertTrue(_config.validate_bool('on')) - self.assertTrue(_config.validate_bool('1')) - self.assertFalse(_config.validate_bool('off')) - self.assertFalse(_config.validate_bool('0')) - self.assertFalse(_config.validate_bool('')) - - with self.assertRaises(ValueError): - _config.validate_bool(' hmm ') - - def test_validate_invalid(self): - with self.assertRaises(ValueError): - _config.validate_invalid(self) - -class TestConfig(unittest.TestCase): - - def test__dir__(self): - self.assertEqual(sorted(_config.config.settings), - sorted(dir(_config.config))) - - def test_getattr(self): - # Bypass the property that might be set here - self.assertIsNotNone(_config.config.__getattr__('resolver')) - - def test__getattr__invalid(self): - with self.assertRaises(AttributeError): - getattr(_config.config, 'no_such_setting') - - def test_set_invalid(self): - with self.assertRaises(AttributeError): - _config.config.set('no such setting', True) - -class TestImportableSetting(unittest.TestCase): - - def test_empty_list(self): - i = _config.ImportableSetting() - with self.assertRaisesRegex(ImportError, - "Cannot import from empty list"): - i._import_one_of([]) - - def test_path_not_supported(self): - import warnings - i = _config.ImportableSetting() - path = list(sys.path) - with warnings.catch_warnings(record=True) as w: - warnings.simplefilter("always") - with self.assertRaisesRegex(ImportError, - "Cannot import 'foo/bar/gevent.no_such_module'"): - i._import_one('foo/bar/gevent.no_such_module') - - # We restored the path - self.assertEqual(path, sys.path) - - # We did not issue a warning - self.assertEqual(len(w), 0) - - def test_non_string(self): - i = _config.ImportableSetting() - self.assertIs(i._import_one(self), self) - - def test_get_options(self): - i = _config.ImportableSetting() - self.assertEqual({}, i.get_options()) - - i.shortname_map = {'foo': 'bad/path'} - options = i.get_options() - self.assertIn('foo', options) - -if __name__ == '__main__': - unittest.main() diff --git a/venv/lib/python3.9/site-packages/gevent/tests/test___ident.py b/venv/lib/python3.9/site-packages/gevent/tests/test___ident.py deleted file mode 100644 index 34d76d1..0000000 --- a/venv/lib/python3.9/site-packages/gevent/tests/test___ident.py +++ /dev/null @@ -1,80 +0,0 @@ -# -*- coding: utf-8 -*- -# copyright 2018 gevent contributors. See LICENSE for details. - -from __future__ import absolute_import -from __future__ import division -from __future__ import print_function - -import gc - - -import gevent.testing as greentest -from gevent._ident import IdentRegistry -from gevent._compat import PYPY - -class Target(object): - pass - -class TestIdent(greentest.TestCase): - - def setUp(self): - self.reg = IdentRegistry() - - def tearDown(self): - self.reg = None - - def test_basic(self): - target = Target() - self.assertEqual(0, self.reg.get_ident(target)) - self.assertEqual(1, len(self.reg)) - - self.assertEqual(0, self.reg.get_ident(target)) - self.assertEqual(1, len(self.reg)) - - target2 = Target() - self.assertEqual(1, self.reg.get_ident(target2)) - self.assertEqual(2, len(self.reg)) - - self.assertEqual(1, self.reg.get_ident(target2)) - self.assertEqual(2, len(self.reg)) - - self.assertEqual(0, self.reg.get_ident(target)) - - # When an object dies, we can re-use - # its id. Under PyPy we need to collect garbage first. - del target - if PYPY: - for _ in range(3): - gc.collect() - - self.assertEqual(1, len(self.reg)) - - target3 = Target() - self.assertEqual(1, self.reg.get_ident(target2)) - self.assertEqual(0, self.reg.get_ident(target3)) - self.assertEqual(2, len(self.reg)) - - @greentest.skipOnPyPy("This would need to GC very frequently") - def test_circle(self): - keep_count = 3 - keepalive = [None] * keep_count - - for i in range(1000): - target = Target() - # Drop an old one. - keepalive[i % keep_count] = target - self.assertLessEqual(self.reg.get_ident(target), keep_count) - - -@greentest.skipOnPurePython("Needs C extension") -class TestCExt(greentest.TestCase): - - def test_c_extension(self): - self.assertEqual(IdentRegistry.__module__, - 'gevent._gevent_c_ident') - - - - -if __name__ == '__main__': - greentest.main() diff --git a/venv/lib/python3.9/site-packages/gevent/tests/test___monitor.py b/venv/lib/python3.9/site-packages/gevent/tests/test___monitor.py deleted file mode 100644 index 71aba10..0000000 --- a/venv/lib/python3.9/site-packages/gevent/tests/test___monitor.py +++ /dev/null @@ -1,386 +0,0 @@ -# Copyright 2018 gevent contributors. See LICENSE for details. - -import gc -import unittest - - -from greenlet import gettrace -from greenlet import settrace - -from gevent.monkey import get_original -from gevent._compat import thread_mod_name -from gevent._compat import NativeStrIO - -from gevent.testing import verify -from gevent.testing.skipping import skipWithoutPSUtil - -from gevent import _monitor as monitor -from gevent import config as GEVENT_CONFIG - -get_ident = get_original(thread_mod_name, 'get_ident') - -class MockHub(object): - _threadpool = None - _resolver = None - - def __init__(self): - self.thread_ident = get_ident() - self.exception_stream = NativeStrIO() - self.dead = False - - def __bool__(self): - return not self.dead - - __nonzero__ = __bool__ - - def handle_error(self, *args): # pylint:disable=unused-argument - raise # pylint:disable=misplaced-bare-raise - - @property - def loop(self): - return self - - def reinit(self): - "mock loop.reinit" - -class _AbstractTestPeriodicMonitoringThread(object): - # Makes sure we don't actually spin up a new monitoring thread. - - # pylint:disable=no-member - - def setUp(self): - super(_AbstractTestPeriodicMonitoringThread, self).setUp() - self._orig_start_new_thread = monitor.start_new_thread - self._orig_thread_sleep = monitor.thread_sleep - monitor.thread_sleep = lambda _s: gc.collect() # For PyPy - self.tid = 0xDEADBEEF - def start_new_thread(_f, _a): - r = self.tid - self.tid += 1 - return r - - monitor.start_new_thread = start_new_thread - self.hub = MockHub() - self.pmt = monitor.PeriodicMonitoringThread(self.hub) - self.hub.periodic_monitoring_thread = self.pmt - self.pmt_default_funcs = self.pmt.monitoring_functions()[:] - self.len_pmt_default_funcs = len(self.pmt_default_funcs) - - def tearDown(self): - monitor.start_new_thread = self._orig_start_new_thread - monitor.thread_sleep = self._orig_thread_sleep - prev = self.pmt._greenlet_tracer.previous_trace_function - self.pmt.kill() - assert gettrace() is prev, (gettrace(), prev) - settrace(None) - super(_AbstractTestPeriodicMonitoringThread, self).tearDown() - - -class TestPeriodicMonitoringThread(_AbstractTestPeriodicMonitoringThread, - unittest.TestCase): - - def test_constructor(self): - self.assertEqual(0xDEADBEEF, self.pmt.monitor_thread_ident) - self.assertEqual(gettrace(), self.pmt._greenlet_tracer) - - @skipWithoutPSUtil("Verifies the process") - def test_get_process(self): - proc = self.pmt._get_process() - self.assertIsNotNone(proc) - # Same object is returned each time. - self.assertIs(proc, self.pmt._get_process()) - - def test_hub_wref(self): - self.assertIs(self.hub, self.pmt.hub) - del self.hub - - gc.collect() - self.assertIsNone(self.pmt.hub) - - # And it killed itself. - self.assertFalse(self.pmt.should_run) - self.assertIsNone(gettrace()) - - - def test_add_monitoring_function(self): - - self.assertRaises(ValueError, self.pmt.add_monitoring_function, None, 1) - self.assertRaises(ValueError, self.pmt.add_monitoring_function, lambda: None, -1) - - def f(): - "Does nothing" - - # Add - self.pmt.add_monitoring_function(f, 1) - self.assertEqual(self.len_pmt_default_funcs + 1, len(self.pmt.monitoring_functions())) - self.assertEqual(1, self.pmt.monitoring_functions()[1].period) - - # Update - self.pmt.add_monitoring_function(f, 2) - self.assertEqual(self.len_pmt_default_funcs + 1, len(self.pmt.monitoring_functions())) - self.assertEqual(2, self.pmt.monitoring_functions()[1].period) - - # Remove - self.pmt.add_monitoring_function(f, None) - self.assertEqual(self.len_pmt_default_funcs, len(self.pmt.monitoring_functions())) - - def test_calculate_sleep_time(self): - self.assertEqual( - self.pmt.monitoring_functions()[0].period, - self.pmt.calculate_sleep_time()) - - # Pretend that GEVENT_CONFIG.max_blocking_time was set to 0, - # to disable this monitor. - self.pmt._calculated_sleep_time = 0 - self.assertEqual( - self.pmt.inactive_sleep_time, - self.pmt.calculate_sleep_time() - ) - - # Getting the list of monitoring functions will also - # do this, if it looks like it has changed - self.pmt.monitoring_functions()[0].period = -1 - self.pmt._calculated_sleep_time = 0 - self.pmt.monitoring_functions() - self.assertEqual( - self.pmt.monitoring_functions()[0].period, - self.pmt.calculate_sleep_time()) - self.assertEqual( - self.pmt.monitoring_functions()[0].period, - self.pmt._calculated_sleep_time) - - def test_call_destroyed_hub(self): - # Add a function that destroys the hub so we break out (eventually) - # This clears the wref, which eventually calls kill() - def f(_hub): - _hub = None - self.hub = None - gc.collect() - - self.pmt.add_monitoring_function(f, 0.1) - self.pmt() - self.assertFalse(self.pmt.should_run) - - def test_call_dead_hub(self): - # Add a function that makes the hub go false (e.g., it quit) - # This causes the function to kill itself. - def f(hub): - hub.dead = True - self.pmt.add_monitoring_function(f, 0.1) - self.pmt() - self.assertFalse(self.pmt.should_run) - - def test_call_SystemExit(self): - # breaks the loop - def f(_hub): - raise SystemExit() - - self.pmt.add_monitoring_function(f, 0.1) - self.pmt() - - def test_call_other_error(self): - class MyException(Exception): - pass - - def f(_hub): - raise MyException() - - self.pmt.add_monitoring_function(f, 0.1) - with self.assertRaises(MyException): - self.pmt() - - def test_hub_reinit(self): - import os - from gevent.hub import reinit - self.pmt.pid = -1 - old_tid = self.pmt.monitor_thread_ident - - reinit(self.hub) - - self.assertEqual(os.getpid(), self.pmt.pid) - self.assertEqual(old_tid + 1, self.pmt.monitor_thread_ident) - - - -class TestPeriodicMonitorBlocking(_AbstractTestPeriodicMonitoringThread, - unittest.TestCase): - - def test_previous_trace(self): - self.pmt.kill() - self.assertIsNone(gettrace()) - - called = [] - def f(*args): - called.append(args) - - settrace(f) - - self.pmt = monitor.PeriodicMonitoringThread(self.hub) - self.assertEqual(gettrace(), self.pmt._greenlet_tracer) - self.assertIs(self.pmt._greenlet_tracer.previous_trace_function, f) - - self.pmt._greenlet_tracer('event', ('args',)) - - self.assertEqual([('event', ('args',))], called) - - def test__greenlet_tracer(self): - self.assertEqual(0, self.pmt._greenlet_tracer.greenlet_switch_counter) - # Unknown event still counts as a switch (should it?) - self.pmt._greenlet_tracer('unknown', None) - self.assertEqual(1, self.pmt._greenlet_tracer.greenlet_switch_counter) - self.assertIsNone(self.pmt._greenlet_tracer.active_greenlet) - - origin = object() - target = object() - - self.pmt._greenlet_tracer('switch', (origin, target)) - self.assertEqual(2, self.pmt._greenlet_tracer.greenlet_switch_counter) - self.assertIs(target, self.pmt._greenlet_tracer.active_greenlet) - - # Unknown event removes active greenlet - self.pmt._greenlet_tracer('unknown', ()) - self.assertEqual(3, self.pmt._greenlet_tracer.greenlet_switch_counter) - self.assertIsNone(self.pmt._greenlet_tracer.active_greenlet) - - def test_monitor_blocking(self): - # Initially there's no active greenlet and no switches, - # so nothing is considered blocked - from gevent.events import subscribers - from gevent.events import IEventLoopBlocked - events = [] - subscribers.append(events.append) - - self.assertFalse(self.pmt.monitor_blocking(self.hub)) - - # Give it an active greenlet - origin = object() - target = object() - self.pmt._greenlet_tracer('switch', (origin, target)) - - # We've switched, so we're not blocked - self.assertFalse(self.pmt.monitor_blocking(self.hub)) - self.assertFalse(events) - - # Again without switching is a problem. - self.assertTrue(self.pmt.monitor_blocking(self.hub)) - self.assertTrue(events) - verify.verifyObject(IEventLoopBlocked, events[0]) - del events[:] - - # But we can order it not to be a problem - self.pmt.ignore_current_greenlet_blocking() - self.assertFalse(self.pmt.monitor_blocking(self.hub)) - self.assertFalse(events) - - # And back again - self.pmt.monitor_current_greenlet_blocking() - self.assertTrue(self.pmt.monitor_blocking(self.hub)) - - # A bad thread_ident in the hub doesn't mess things up - self.hub.thread_ident = -1 - self.assertTrue(self.pmt.monitor_blocking(self.hub)) - - -class MockProcess(object): - - def __init__(self, rss): - self.rss = rss - - def memory_full_info(self): - return self - - -@skipWithoutPSUtil("Accessess memory info") -class TestPeriodicMonitorMemory(_AbstractTestPeriodicMonitoringThread, - unittest.TestCase): - - rss = 0 - - def setUp(self): - _AbstractTestPeriodicMonitoringThread.setUp(self) - self._old_max = GEVENT_CONFIG.max_memory_usage - GEVENT_CONFIG.max_memory_usage = None - - self.pmt._get_process = lambda: MockProcess(self.rss) - - def tearDown(self): - GEVENT_CONFIG.max_memory_usage = self._old_max - _AbstractTestPeriodicMonitoringThread.tearDown(self) - - def test_can_monitor_and_install(self): - # We run tests with psutil installed, and we have access to our - # process. - self.assertTrue(self.pmt.can_monitor_memory_usage()) - # No warning, adds a function - - self.pmt.install_monitor_memory_usage() - self.assertEqual(self.len_pmt_default_funcs + 1, len(self.pmt.monitoring_functions())) - - def test_cannot_monitor_and_install(self): - import warnings - self.pmt._get_process = lambda: None - self.assertFalse(self.pmt.can_monitor_memory_usage()) - - # This emits a warning, visible by default - with warnings.catch_warnings(record=True) as ws: - self.pmt.install_monitor_memory_usage() - - self.assertEqual(1, len(ws)) - self.assertIs(monitor.MonitorWarning, ws[0].category) - - def test_monitor_no_allowed(self): - self.assertEqual(-1, self.pmt.monitor_memory_usage(None)) - - def test_monitor_greater(self): - from gevent import events - - self.rss = 2 - GEVENT_CONFIG.max_memory_usage = 1 - - # Initial event - event = self.pmt.monitor_memory_usage(None) - self.assertIsInstance(event, events.MemoryUsageThresholdExceeded) - self.assertEqual(2, event.mem_usage) - self.assertEqual(1, event.max_allowed) # pylint:disable=no-member - self.assertIsInstance(event.memory_info, MockProcess) # pylint:disable=no-member - - # No growth, no event - event = self.pmt.monitor_memory_usage(None) - self.assertIsNone(event) - - # Growth, event - self.rss = 3 - event = self.pmt.monitor_memory_usage(None) - self.assertIsInstance(event, events.MemoryUsageThresholdExceeded) - self.assertEqual(3, event.mem_usage) - - # Shrinking below gets us back - self.rss = 1 - event = self.pmt.monitor_memory_usage(None) - self.assertIsInstance(event, events.MemoryUsageUnderThreshold) - self.assertEqual(1, event.mem_usage) - - # coverage - repr(event) - - # No change, no event - event = self.pmt.monitor_memory_usage(None) - self.assertIsNone(event) - - # Growth, event - self.rss = 3 - event = self.pmt.monitor_memory_usage(None) - self.assertIsInstance(event, events.MemoryUsageThresholdExceeded) - self.assertEqual(3, event.mem_usage) - - - def test_monitor_initial_below(self): - self.rss = 1 - GEVENT_CONFIG.max_memory_usage = 10 - - - event = self.pmt.monitor_memory_usage(None) - self.assertIsNone(event) - -if __name__ == '__main__': - unittest.main() diff --git a/venv/lib/python3.9/site-packages/gevent/tests/test___monkey_patching.py b/venv/lib/python3.9/site-packages/gevent/tests/test___monkey_patching.py deleted file mode 100644 index d7fcb16..0000000 --- a/venv/lib/python3.9/site-packages/gevent/tests/test___monkey_patching.py +++ /dev/null @@ -1,102 +0,0 @@ -import sys -import os -import glob - -import atexit -# subprocess: include in subprocess tests - -from gevent.testing import util -from gevent.testing import sysinfo -from gevent.testing.support import is_resource_enabled - -TIMEOUT = 120 - -# XXX: Generalize this so other packages can use it. - - -def get_absolute_pythonpath(): - paths = [os.path.abspath(p) for p in os.environ.get('PYTHONPATH', '').split(os.pathsep)] - return os.pathsep.join(paths) - - -def TESTRUNNER(tests=None): - if not is_resource_enabled('gevent_monkey'): - util.log('WARNING: Testing monkey-patched stdlib has been disabled', - color="suboptimal-behaviour") - return - - try: - test_dir, version_test_dir = util.find_stdlib_tests() - except util.NoSetupPyFound as e: - util.log("WARNING: No setup.py and src/greentest found: %r", e, - color="suboptimal-behaviour") - return - - if not os.path.exists(test_dir): - util.log('WARNING: No test directory found at %s', test_dir, - color="suboptimal-behaviour") - return - - # pylint:disable=unspecified-encoding - with open(os.path.join(test_dir, 'version')) as f: - preferred_version = f.read().strip() - - running_version = sysinfo.get_python_version() - if preferred_version != running_version: - util.log('WARNING: The tests in %s/ are from version %s and your Python is %s', - test_dir, preferred_version, running_version, - color="suboptimal-behaviour") - - version_tests = glob.glob('%s/test_*.py' % version_test_dir) - version_tests = sorted(version_tests) - if not tests: - tests = glob.glob('%s/test_*.py' % test_dir) - tests = sorted(tests) - - PYTHONPATH = (os.getcwd() + os.pathsep + get_absolute_pythonpath()).rstrip(':') - - tests = sorted(set(os.path.basename(x) for x in tests)) - version_tests = sorted(set(os.path.basename(x) for x in version_tests)) - - util.log("Discovered %d tests in %s", len(tests), test_dir) - util.log("Discovered %d version-specific tests in %s", len(version_tests), version_test_dir) - - options = { - 'cwd': test_dir, - 'timeout': TIMEOUT, - 'setenv': { - 'PYTHONPATH': PYTHONPATH, - # debug produces resource tracking warnings for the - # CFFI backends. On Python 2, many of the stdlib tests - # rely on refcounting to close sockets so they produce - # lots of noise. Python 3 is not completely immune; - # test_ftplib.py tends to produce warnings---and the Python 3 - # test framework turns those into test failures! - 'GEVENT_DEBUG': 'error', - } - } - - if tests and not sys.platform.startswith("win"): - atexit.register(os.system, 'rm -f */@test*') - - basic_args = [sys.executable, '-u', '-W', 'ignore', '-m', 'gevent.testing.monkey_test'] - for filename in tests: - if filename in version_tests: - util.log("Overriding %s from %s with file from %s", filename, test_dir, version_test_dir) - continue - yield basic_args + [filename], options.copy() - - options['cwd'] = version_test_dir - for filename in version_tests: - yield basic_args + [filename], options.copy() - - -def main(): - from gevent.testing import testrunner - discovered_tests = TESTRUNNER(sys.argv[1:]) - discovered_tests = list(discovered_tests) - return testrunner.Runner(discovered_tests, quiet=None)() - - -if __name__ == '__main__': - main() diff --git a/venv/lib/python3.9/site-packages/gevent/tests/test__all__.py b/venv/lib/python3.9/site-packages/gevent/tests/test__all__.py deleted file mode 100644 index 0752ecc..0000000 --- a/venv/lib/python3.9/site-packages/gevent/tests/test__all__.py +++ /dev/null @@ -1,322 +0,0 @@ -# Check __all__, __implements__, __extensions__, __imports__ of the modules - -import functools -import sys -import unittest -import types -import importlib -import warnings - -from gevent.testing import modules -from gevent.testing.sysinfo import PLATFORM_SPECIFIC_SUFFIXES -from gevent.testing.util import debug - -from gevent._patcher import MAPPING - -class ANY: - def __contains__(self, item): - return True - -ANY = ANY() - -NOT_IMPLEMENTED = { - 'socket': ['CAPI'], - 'thread': ['allocate', 'exit_thread', 'interrupt_main', 'start_new'], - 'select': ANY, - 'os': ANY, - 'threading': ANY, - 'builtins': ANY, - 'signal': ANY, -} - -COULD_BE_MISSING = { - 'socket': ['create_connection', 'RAND_add', 'RAND_egd', 'RAND_status'], - 'subprocess': ['_posixsubprocess'], -} - -# Things without an __all__ should generally be internal implementation -# helpers -NO_ALL = { - 'gevent.threading', - 'gevent._compat', - 'gevent._corecffi', - 'gevent._ffi', - 'gevent._fileobjectcommon', - 'gevent._fileobjectposix', - 'gevent._patcher', - 'gevent._socketcommon', - 'gevent._tblib', - 'gevent._util', - 'gevent.resolver._addresses', - 'gevent.resolver._hostsfile', - # gevent.monkey is handled specially. -} - -ALLOW_IMPLEMENTS = [ - 'gevent._queue', - # 'gevent.resolver.dnspython', - # 'gevent.resolver_thread', - # 'gevent.resolver.blocking', - # 'gevent.resolver_ares', - # 'gevent.server', - # 'gevent._resolver.hostfile', - # 'gevent.util', - # 'gevent.threadpool', - # 'gevent.timeout', -] - -# A list of modules that may contain things that aren't actually, technically, -# extensions, but that need to be in __extensions__ anyway due to the way, -# for example, monkey patching, needs to work. -EXTRA_EXTENSIONS = [] -if sys.platform.startswith('win'): - EXTRA_EXTENSIONS.append('gevent.signal') - - - -_MISSING = '' - -def skip_if_no_stdlib_counterpart(f): - @functools.wraps(f) - def m(self): - if not self.stdlib_module: - self.skipTest("Need stdlib counterpart to %s" % self.modname) - f(self) - - return m - -class AbstractTestMixin: - modname = None - stdlib_has_all = False - stdlib_all = None - stdlib_name = None - stdlib_module = None - - @classmethod - def setUpClass(cls): - modname = cls.modname - if modname.endswith(PLATFORM_SPECIFIC_SUFFIXES): - raise unittest.SkipTest("Module %s is platform specific" % modname) - - - with warnings.catch_warnings(): - warnings.simplefilter('ignore', DeprecationWarning) - try: - cls.module = importlib.import_module(modname) - except ImportError: - if modname in modules.OPTIONAL_MODULES: - msg = "Unable to import %s" % modname - raise unittest.SkipTest(msg) - raise - - cls.__implements__ = getattr(cls.module, '__implements__', None) - cls.__imports__ = getattr(cls.module, '__imports__', []) - cls.__extensions__ = getattr(cls.module, '__extensions__', []) - - cls.stdlib_name = MAPPING.get(modname) - - if cls.stdlib_name is not None: - try: - cls.stdlib_module = __import__(cls.stdlib_name) - except ImportError: - pass - else: - cls.stdlib_has_all = True - cls.stdlib_all = getattr(cls.stdlib_module, '__all__', None) - if cls.stdlib_all is None: - cls.stdlib_has_all = False - cls.stdlib_all = [ - name - for name in dir(cls.stdlib_module) - if not name.startswith('_') - and not isinstance(getattr(cls.stdlib_module, name), types.ModuleType) - ] - - def skipIfNoAll(self): - if not hasattr(self.module, '__all__'): - self.assertTrue( - self.modname in NO_ALL or self.modname.startswith('gevent.monkey.'), - "Module has no all" - ) - - self.skipTest("%s Needs __all__" % self.modname) - - def test_all(self): - # Check that __all__ is present in the gevent module, - # and only includes things that actually exist and can be - # imported from it. - self.skipIfNoAll() - names = {} - exec("from %s import *" % self.modname, names) - names.pop('__builtins__', None) - self.maxDiff = None - - # It should match both as a set - self.assertEqual(set(names), set(self.module.__all__)) - # and it should not contain duplicates. - self.assertEqual(sorted(names), sorted(self.module.__all__)) - - def test_all_formula(self): - self.skipIfNoAll() - # Check __all__ = __implements__ + __extensions__ + __imported__ - # This is disabled because it was previously being skipped entirely - # back when we had to call things manually. In that time, it drifted - # out of sync. It should be enabled again and problems corrected. - all_calculated = ( - tuple(self.__implements__ or ()) - + tuple(self.__imports__ or ()) - + tuple(self.__extensions__ or ()) - ) - try: - self.assertEqual(sorted(all_calculated), - sorted(self.module.__all__)) - except AssertionError: - self.skipTest("Module %s fails the all formula; fix it" % self.modname) - except TypeError: - # TypeError: '<' not supported between instances of 'type' and 'str' - raise AssertionError( - "Unable to sort %r from all %s in %s" % ( - all_calculated, self.module.__all__, self.module - ) - ) - - def test_implements_presence_justified(self): - # Check that __implements__ is present only if the module is modeled - # after a module from stdlib (like gevent.socket). - - if self.modname in ALLOW_IMPLEMENTS: - return - if self.__implements__ is not None and self.stdlib_module is None: - raise AssertionError( - '%s (%r) has __implements__ (%s) but no stdlib counterpart module exists (%s)' - % (self.modname, self.module, self.__implements__, self.stdlib_name)) - - @skip_if_no_stdlib_counterpart - def test_implements_subset_of_stdlib_all(self): - # Check that __implements__ + __imports__ is a subset of the - # corresponding standard module __all__ or dir() - for name in tuple(self.__implements__ or ()) + tuple(self.__imports__): - if name in self.stdlib_all: - continue - if name in COULD_BE_MISSING.get(self.stdlib_name, ()): - continue - if name in dir(self.stdlib_module): # like thread._local which is not in thread.__all__ - continue - raise AssertionError('%r is not found in %r.__all__ nor in dir(%r)' % (name, self.stdlib_module, self.stdlib_module)) - - @skip_if_no_stdlib_counterpart - def test_implements_actually_implements(self): - # Check that the module actually implements the entries from - # __implements__ - - for name in self.__implements__ or (): - item = getattr(self.module, name) - try: - stdlib_item = getattr(self.stdlib_module, name) - self.assertIsNot(item, stdlib_item) - except AttributeError: - if name not in COULD_BE_MISSING.get(self.stdlib_name, []): - raise - - @skip_if_no_stdlib_counterpart - def test_imports_actually_imports(self): - # Check that the module actually imports the entries from - # __imports__ - for name in self.__imports__: - item = getattr(self.module, name) - stdlib_item = getattr(self.stdlib_module, name) - self.assertIs(item, stdlib_item) - - @skip_if_no_stdlib_counterpart - def test_extensions_actually_extend(self): - # Check that the module actually defines new entries in - # __extensions__ - - if self.modname in EXTRA_EXTENSIONS: - return - for name in self.__extensions__: - try: - if hasattr(self.stdlib_module, name): - raise AssertionError("'%r' is not an extension, it is found in %r" % ( - name, self.stdlib_module - )) - except TypeError as ex: - # TypeError: attribute name must be string, not 'type' - raise AssertionError( - "Got TypeError (%r) getting %r (of %s) from %s/%s" % ( - ex, name, self.__extensions__, self.stdlib_module, self.modname - ) - ) - - @skip_if_no_stdlib_counterpart - def test_completeness(self): # pylint:disable=too-many-branches - # Check that __all__ (or dir()) of the corresponsing stdlib is - # a subset of __all__ of this module - - missed = [] - for name in self.stdlib_all: - if name not in getattr(self.module, '__all__', []): - missed.append(name) - - # handle stuff like ssl.socket and ssl.socket_error which have no reason to be in gevent.ssl.__all__ - if not self.stdlib_has_all: - for name in missed[:]: - if hasattr(self.module, name): - missed.remove(name) - - # remove known misses - not_implemented = NOT_IMPLEMENTED.get(self.stdlib_name) - if not_implemented is not None: - result = [] - for name in missed: - if name in not_implemented: - # We often don't want __all__ to be set because we wind up - # documenting things that we just copy in from the stdlib. - # But if we implement it, don't print a warning - if getattr(self.module, name, _MISSING) is _MISSING: - debug('IncompleteImplWarning: %s.%s' % (self.modname, name)) - else: - result.append(name) - missed = result - - if missed: - if self.stdlib_has_all: - msg = '''The following items - in %r.__all__ -are missing from %r: - %r''' % (self.stdlib_module, self.module, missed) - else: - msg = '''The following items - in dir(%r) -are missing from %r: - %r''' % (self.stdlib_module, self.module, missed) - raise AssertionError(msg) - - -def _create_tests(): - for _, modname in modules.walk_modules(include_so=False, recursive=True, - check_optional=False): - if modname.endswith(PLATFORM_SPECIFIC_SUFFIXES): - continue - if modname.endswith('__main__'): - # gevent.monkey.__main__ especially is a problem. - # These aren't meant to be imported anyway. - continue - - orig_modname = modname - modname_no_period = orig_modname.replace('.', '_') - - cls = type( - 'Test_' + modname_no_period, - (AbstractTestMixin, unittest.TestCase), - { - '__module__': __name__, - 'modname': orig_modname - } - ) - globals()[cls.__name__] = cls - -_create_tests() - -if __name__ == "__main__": - unittest.main() diff --git a/venv/lib/python3.9/site-packages/gevent/tests/test__api.py b/venv/lib/python3.9/site-packages/gevent/tests/test__api.py deleted file mode 100644 index 697a3e0..0000000 --- a/venv/lib/python3.9/site-packages/gevent/tests/test__api.py +++ /dev/null @@ -1,132 +0,0 @@ -# Copyright (c) 2008 AG Projects -# Author: Denis Bilenko -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. - -import gevent.testing as greentest -import gevent -from gevent import util, socket - -DELAY = 0.1 - - -class Test(greentest.TestCase): - - @greentest.skipOnAppVeyor("Timing causes the state to often be [start,finished]") - def test_killing_dormant(self): - state = [] - - def test(): - try: - state.append('start') - gevent.sleep(DELAY * 3.0) - except: # pylint:disable=bare-except - state.append('except') - # catching GreenletExit - - state.append('finished') - - g = gevent.spawn(test) - gevent.sleep(DELAY / 2) - assert state == ['start'], state - g.kill() - # will not get there, unless switching is explicitly scheduled by kill - self.assertEqual(state, ['start', 'except', 'finished']) - - def test_nested_with_timeout(self): - def func(): - return gevent.with_timeout(0.2, gevent.sleep, 2, timeout_value=1) - self.assertRaises(gevent.Timeout, gevent.with_timeout, 0.1, func) - - def test_sleep_invalid_switch(self): - p = gevent.spawn(util.wrap_errors(AssertionError, gevent.sleep), 2) - gevent.sleep(0) # wait for p to start, because actual order of switching is reversed - switcher = gevent.spawn(p.switch, None) - result = p.get() - assert isinstance(result, AssertionError), result - assert 'Invalid switch' in str(result), repr(str(result)) - switcher.kill() - - if hasattr(socket, 'socketpair'): - - def _test_wait_read_invalid_switch(self, sleep): - sock1, sock2 = socket.socketpair() - try: - p = gevent.spawn(util.wrap_errors(AssertionError, - socket.wait_read), # pylint:disable=no-member - sock1.fileno()) - gevent.get_hub().loop.run_callback(switch_None, p) - if sleep is not None: - gevent.sleep(sleep) - result = p.get() - assert isinstance(result, AssertionError), result - assert 'Invalid switch' in str(result), repr(str(result)) - finally: - sock1.close() - sock2.close() - - def test_invalid_switch_None(self): - self._test_wait_read_invalid_switch(None) - - def test_invalid_switch_0(self): - self._test_wait_read_invalid_switch(0) - - def test_invalid_switch_1(self): - self._test_wait_read_invalid_switch(0.001) - - # we don't test wait_write the same way, because socket is always ready to write - - -def switch_None(g): - g.switch(None) - - -class TestTimers(greentest.TestCase): - - def test_timer_fired(self): - lst = [1] - - def func(): - gevent.spawn_later(0.01, lst.pop) - gevent.sleep(0.02) - - gevent.spawn(func) - # Func has not run yet - self.assertEqual(lst, [1]) - # Run callbacks but don't yield. - gevent.sleep() - - # Let timers fire. Func should be done. - gevent.sleep(0.1) - self.assertEqual(lst, []) - - - def test_spawn_is_not_cancelled(self): - lst = [1] - - def func(): - gevent.spawn(lst.pop) - # exiting immediately, but self.lst.pop must be called - gevent.spawn(func) - gevent.sleep(0.1) - self.assertEqual(lst, []) - - -if __name__ == '__main__': - greentest.main() diff --git a/venv/lib/python3.9/site-packages/gevent/tests/test__api_timeout.py b/venv/lib/python3.9/site-packages/gevent/tests/test__api_timeout.py deleted file mode 100644 index c208399..0000000 --- a/venv/lib/python3.9/site-packages/gevent/tests/test__api_timeout.py +++ /dev/null @@ -1,210 +0,0 @@ -# Copyright (c) 2008 AG Projects -# Author: Denis Bilenko -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. - -import sys -import gevent.testing as greentest -import weakref -import time -import gc - -from gevent import sleep -from gevent import Timeout -from gevent import get_hub - - -from gevent.testing.timing import SMALL_TICK as DELAY -from gevent.testing import flaky - - -class Error(Exception): - pass - - -class _UpdateNowProxy(object): - - update_now_calls = 0 - - def __init__(self, loop): - self.loop = loop - - def __getattr__(self, name): - return getattr(self.loop, name) - - def update_now(self): - self.update_now_calls += 1 - self.loop.update_now() - -class _UpdateNowWithTimerProxy(_UpdateNowProxy): - - def timer(self, *_args, **_kwargs): - return _Timer(self) - -class _Timer(object): - - pending = False - active = False - - def __init__(self, loop): - self.loop = loop - - def start(self, *_args, **kwargs): - if kwargs.get("update"): - self.loop.update_now() - self.pending = self.active = True - - def stop(self): - self.active = self.pending = False - - def close(self): - "Does nothing" - - -class Test(greentest.TestCase): - - def test_timeout_calls_update_now(self): - hub = get_hub() - loop = hub.loop - proxy = _UpdateNowWithTimerProxy(loop) - hub.loop = proxy - - try: - with Timeout(DELAY * 2) as t: - self.assertTrue(t.pending) - finally: - hub.loop = loop - - self.assertEqual(1, proxy.update_now_calls) - - def test_sleep_calls_update_now(self): - hub = get_hub() - loop = hub.loop - proxy = _UpdateNowProxy(loop) - hub.loop = proxy - try: - sleep(0.01) - finally: - hub.loop = loop - - self.assertEqual(1, proxy.update_now_calls) - - - @greentest.skipOnAppVeyor("Timing is flaky, especially under Py 3.4/64-bit") - @greentest.skipOnPyPy3OnCI("Timing is flaky, especially under Py 3.4/64-bit") - @greentest.reraises_flaky_timeout((Timeout, AssertionError)) - def test_api(self): - # Nothing happens if with-block finishes before the timeout expires - t = Timeout(DELAY * 2) - self.assertFalse(t.pending, t) - with t: - self.assertTrue(t.pending, t) - sleep(DELAY) - # check if timer was actually cancelled - self.assertFalse(t.pending, t) - sleep(DELAY * 2) - - # An exception will be raised if it's not - with self.assertRaises(Timeout) as exc: - with Timeout(DELAY) as t: - sleep(DELAY * 10) - - self.assertIs(exc.exception, t) - - # You can customize the exception raised: - with self.assertRaises(IOError): - with Timeout(DELAY, IOError("Operation takes way too long")): - sleep(DELAY * 10) - - # Providing classes instead of values should be possible too: - with self.assertRaises(ValueError): - with Timeout(DELAY, ValueError): - sleep(DELAY * 10) - - - try: - 1 / 0 - except ZeroDivisionError: - with self.assertRaises(ZeroDivisionError): - with Timeout(DELAY, sys.exc_info()[0]): - sleep(DELAY * 10) - raise AssertionError('should not get there') - raise AssertionError('should not get there') - else: - raise AssertionError('should not get there') - - # It's possible to cancel the timer inside the block: - with Timeout(DELAY) as timer: - timer.cancel() - sleep(DELAY * 2) - - # To silent the exception before exiting the block, pass False as second parameter. - XDELAY = 0.1 - start = time.time() - with Timeout(XDELAY, False): - sleep(XDELAY * 2) - delta = time.time() - start - self.assertTimeWithinRange(delta, 0, XDELAY * 2) - - # passing None as seconds disables the timer - with Timeout(None): - sleep(DELAY) - sleep(DELAY) - - def test_ref(self): - err = Error() - err_ref = weakref.ref(err) - with Timeout(DELAY * 2, err): - sleep(DELAY) - del err - gc.collect() - self.assertFalse(err_ref(), err_ref) - - @flaky.reraises_flaky_race_condition() - def test_nested_timeout(self): - with Timeout(DELAY, False): - with Timeout(DELAY * 10, False): - sleep(DELAY * 3 * 20) - raise AssertionError('should not get there') - - with Timeout(DELAY) as t1: - with Timeout(DELAY * 20) as t2: - with self.assertRaises(Timeout) as exc: - sleep(DELAY * 30) - self.assertIs(exc.exception, t1) - - self.assertFalse(t1.pending, t1) - self.assertTrue(t2.pending, t2) - - self.assertFalse(t2.pending) - - with Timeout(DELAY * 20) as t1: - with Timeout(DELAY) as t2: - with self.assertRaises(Timeout) as exc: - sleep(DELAY * 30) - self.assertIs(exc.exception, t2) - - self.assertTrue(t1.pending, t1) - self.assertFalse(t2.pending, t2) - - self.assertFalse(t1.pending) - - -if __name__ == '__main__': - greentest.main() diff --git a/venv/lib/python3.9/site-packages/gevent/tests/test__ares_host_result.py b/venv/lib/python3.9/site-packages/gevent/tests/test__ares_host_result.py deleted file mode 100644 index c65a9db..0000000 --- a/venv/lib/python3.9/site-packages/gevent/tests/test__ares_host_result.py +++ /dev/null @@ -1,32 +0,0 @@ -from __future__ import print_function - -import pickle -import gevent.testing as greentest -try: - from gevent.resolver.cares import ares_host_result -except ImportError: # pragma: no cover - ares_host_result = None - - -@greentest.skipIf(ares_host_result is None, - "Must be able to import ares") -class TestPickle(greentest.TestCase): - # Issue 104: ares.ares_host_result unpickleable - - def _test(self, protocol): - r = ares_host_result('family', ('arg1', 'arg2', )) - dumped = pickle.dumps(r, protocol) - loaded = pickle.loads(dumped) - self.assertEqual(r, loaded) - # pylint:disable=no-member - self.assertEqual(r.family, loaded.family) - - -for i in range(0, pickle.HIGHEST_PROTOCOL): - def make_test(j): - return lambda self: self._test(j) - setattr(TestPickle, 'test' + str(i), make_test(i)) - - -if __name__ == '__main__': - greentest.main() diff --git a/venv/lib/python3.9/site-packages/gevent/tests/test__ares_timeout.py b/venv/lib/python3.9/site-packages/gevent/tests/test__ares_timeout.py deleted file mode 100644 index cb88ff2..0000000 --- a/venv/lib/python3.9/site-packages/gevent/tests/test__ares_timeout.py +++ /dev/null @@ -1,44 +0,0 @@ -from __future__ import print_function - -import unittest - -import gevent -try: - from gevent.resolver.ares import Resolver -except ImportError as ex: - Resolver = None -from gevent import socket - -import gevent.testing as greentest -from gevent.testing.sockets import udp_listener - -@unittest.skipIf( - Resolver is None, - "Needs ares resolver" -) -class TestTimeout(greentest.TestCase): - - __timeout__ = 30 - - def test(self): - listener = self._close_on_teardown(udp_listener()) - address = listener.getsockname() - - - def reader(): - while True: - listener.recvfrom(10000) - - greader = gevent.spawn(reader) - self._close_on_teardown(greader.kill) - - r = Resolver(servers=[address[0]], timeout=0.001, tries=1, - udp_port=address[-1]) - self._close_on_teardown(r) - - with self.assertRaisesRegex(socket.herror, "ARES_ETIMEOUT"): - r.gethostbyname('www.google.com') - - -if __name__ == '__main__': - greentest.main() diff --git a/venv/lib/python3.9/site-packages/gevent/tests/test__backdoor.py b/venv/lib/python3.9/site-packages/gevent/tests/test__backdoor.py deleted file mode 100644 index 3dccf98..0000000 --- a/venv/lib/python3.9/site-packages/gevent/tests/test__backdoor.py +++ /dev/null @@ -1,211 +0,0 @@ -import os -import tempfile - -import gevent -import gevent.testing as greentest -from gevent import backdoor -from gevent import socket -from gevent.testing.params import DEFAULT_BIND_ADDR_TUPLE -from gevent.testing.params import DEFAULT_CONNECT - - -def read_until(conn, postfix): - read = b'' - assert isinstance(postfix, bytes) - - while not read.endswith(postfix): - result = conn.recv(1) - if not result: - raise AssertionError('Connection ended before %r. Data read:\n%r' % (postfix, read)) - read += result - - return read if isinstance(read, str) else read.decode('utf-8') - -def readline(conn): - with conn.makefile() as f: - return f.readline() - - -class WorkerGreenlet(gevent.Greenlet): - spawning_stack_limit = 2 - -class SocketWithBanner(socket.socket): - __slots__ = ('banner',) - - def __init__(self, *args, **kwargs): - self.banner = None - super(SocketWithBanner, self).__init__(*args, **kwargs) - - def __enter__(self): - return socket.socket.__enter__(self) - - def __exit__(self, t, v, tb): - return socket.socket.__exit__(self, t, v, tb) - - -@greentest.skipOnAppVeyor( - "With the update to libev 4.31 and potentially closing sockets in the background, " - "alternate tests started hanging on appveyor. Something like .E.E.E. " - "See https://ci.appveyor.com/project/denik/gevent/build/job/n9fynkoyt2bvk8b5 " - "It's not clear why, but presumably a socket isn't getting closed and a watcher is tied " - "to the wrong file descriptor. I haven't been able to reproduce. If it were a systemic " - "problem I'd expect to see more failures, so it is probably specific to resource management " - "in this test." -) -class Test(greentest.TestCase): - - __timeout__ = 10 - - def tearDown(self): - gevent.sleep() # let spawned greenlets die - super(Test, self).tearDown() - - def _server_listen_argument(self): - return DEFAULT_BIND_ADDR_TUPLE - - def _make_and_start_server(self, *args, **kwargs): - server = backdoor.BackdoorServer(self._server_listen_argument(), *args, **kwargs) - server.start() - return server - - def _connection_arguments(self, server): - return ((DEFAULT_CONNECT, server.server_port),) - - def _socket_arguments(self): - return () - - def _create_connection(self, server): - conn = SocketWithBanner(*self._socket_arguments()) - - try: - conn.connect(*self._connection_arguments(server)) # pylint:disable=not-callable - banner = self._wait_for_prompt(conn) - except: - conn.close() - raise - - conn.banner = banner - return conn - - def _wait_for_prompt(self, conn): - return read_until(conn, b'>>> ') - - def _close(self, conn, cmd=b'quit()\r\n)'): - conn.sendall(cmd) - line = readline(conn) - self.assertEqual(line, '') - conn.close() - - @greentest.skipOnMacOnCI( - "Sometimes fails to get the right answers; " - "https://travis-ci.org/github/gevent/gevent/jobs/692184822" - ) - def test_multi(self): - with self._make_and_start_server() as server: - def connect(): - with self._create_connection(server) as conn: - conn.sendall(b'2+2\r\n') - line = readline(conn) - self.assertEqual(line.strip(), '4', repr(line)) - self._close(conn) - - jobs = [WorkerGreenlet.spawn(connect) for _ in range(10)] - try: - done = gevent.joinall(jobs, raise_error=True) - finally: - gevent.joinall(jobs, raise_error=False) - - self.assertEqual(len(done), len(jobs), done) - - def test_quit(self): - with self._make_and_start_server() as server: - with self._create_connection(server) as conn: - self._close(conn) - - def test_sys_exit(self): - with self._make_and_start_server() as server: - with self._create_connection(server) as conn: - self._close(conn, b'import sys; sys.exit(0)\r\n') - - def test_banner(self): - expected_banner = "Welcome stranger!" # native string - with self._make_and_start_server(banner=expected_banner) as server: - with self._create_connection(server) as conn: - banner = conn.banner - self._close(conn) - - self.assertEqual(banner[:len(expected_banner)], expected_banner, banner) - - - def test_builtins(self): - with self._make_and_start_server() as server: - with self._create_connection(server) as conn: - conn.sendall(b'locals()["__builtins__"]\r\n') - response = read_until(conn, b'>>> ') - self._close(conn) - - self.assertLess( - len(response), 300, - msg="locals() unusable: %s..." % response) - - def test_switch_exc(self): - from gevent.queue import Empty - from gevent.queue import Queue - - def bad(): - q = Queue() - print('switching out, then throwing in') - try: - q.get(block=True, timeout=0.1) - except Empty: - print("Got Empty") - print('switching out') - gevent.sleep(0.1) - print('switched in') - - with self._make_and_start_server(locals={'bad': bad}) as server: - with self._create_connection(server) as conn: - conn.sendall(b'bad()\r\n') - response = self._wait_for_prompt(conn) - self._close(conn) - - response = response.replace('\r\n', '\n') - self.assertEqual( - 'switching out, then throwing in\nGot Empty\nswitching out\nswitched in\n>>> ', - response) - -@greentest.skipUnless( - hasattr(socket, 'AF_UNIX'), - "Needs AF_UNIX support" -) -class TestUnixSocket(Test): - def setUp(self): - super().setUp() - # Create a temporary file for the Unix socket - self.unix_socket_path = tempfile.mktemp() - - def tearDown(self): - # Clean up the Unix socket file - if os.path.exists(self.unix_socket_path): - os.unlink(self.unix_socket_path) - super().tearDown() - - def _server_listen_argument(self): - # Use the Unix socket for the BackdoorServer - listener = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) - try: - listener.bind(self.unix_socket_path) - listener.listen(socket.SOMAXCONN) - except Exception as ex: - listener.close() - raise RuntimeError(f"Failed to bind Unix socket at {self.unix_socket_path}: {ex}") - return listener - - def _connection_arguments(self, server): - return (self.unix_socket_path,) - - def _socket_arguments(self): - return (socket.AF_UNIX, socket.SOCK_STREAM) - -if __name__ == '__main__': - greentest.main() # pragma: testrunner-no-combine diff --git a/venv/lib/python3.9/site-packages/gevent/tests/test__close_backend_fd.py b/venv/lib/python3.9/site-packages/gevent/tests/test__close_backend_fd.py deleted file mode 100644 index 977b275..0000000 --- a/venv/lib/python3.9/site-packages/gevent/tests/test__close_backend_fd.py +++ /dev/null @@ -1,114 +0,0 @@ -from __future__ import print_function -import os -import unittest - -import gevent -from gevent import core -from gevent.hub import Hub - -from gevent.testing import sysinfo - -@unittest.skipUnless( - getattr(core, 'LIBEV_EMBED', False), - "Needs embedded libev. " - "hub.loop.fileno is only defined when " - "we embed libev for some reason. " - "Choosing specific backends is also only supported by libev " - "(not libuv), and besides, libuv has a nasty tendency to " - "abort() the process if its FD gets closed. " -) -class Test(unittest.TestCase): - # NOTE that we extend unittest.TestCase, not greentest.TestCase - # Extending the later causes the wrong hub to get used. - - BACKENDS_THAT_SUCCEED_WHEN_FD_CLOSED = ( - 'kqueue', - 'epoll', - 'linux_aio', - 'linux_iouring', - ) - - BACKENDS_THAT_WILL_FAIL_TO_CREATE_AT_RUNTIME = ( - # This fails on the Fedora Rawhide 33 image. It's not clear - # why; needs investigated. - 'linux_iouring', - ) if not sysinfo.libev_supports_linux_iouring() else ( - # Even on systems that ought to support it, according to the - # version number, it often fails to actually work. See the - # manylinux_2_28_x86_64 image as-of 2024-10-03; it seems that - # 6.8.0-1014-azure, as used in the Ubuntu 22.04 Github Actions - # runner works fine, though. So it's not clear what we can do - # other than skip it. It's possible this has to do with - # running the manylinux images in docker? " Docker also - # consequently disabled io_uring from their default seccomp - # profile." - ) - - BACKENDS_TO_SKIP = ( - 'linux_iouring', - ) - - BACKENDS_THAT_WILL_FAIL_TO_CREATE_AT_RUNTIME += ( - # This can be compiled on any (?) version of - # linux, but there's a runtime check that you're - # running at least kernel 4.19, so we can fail to create - # the hub. When we updated to libev 4.31 from 4.25, Travis Ci - # was still on kernel 1.15 (Ubuntu 16.04). - 'linux_aio', - ) if not sysinfo.libev_supports_linux_aio() else ( - ) - - def _check_backend(self, backend): - hub = Hub(backend, default=False) - - try: - self.assertEqual(hub.loop.backend, backend) - - gevent.sleep(0.001) - fileno = hub.loop.fileno() - if fileno is None: - return # nothing to close, test implicitly passes. - - os.close(fileno) - - if backend in self.BACKENDS_THAT_SUCCEED_WHEN_FD_CLOSED: - gevent.sleep(0.001) - else: - with self.assertRaisesRegex(SystemError, "(libev)"): - gevent.sleep(0.001) - - hub.destroy() - self.assertIn('destroyed', repr(hub)) - finally: - if hub.loop is not None: - hub.destroy() - - @classmethod - def _make_test(cls, count, backend): # pylint:disable=no-self-argument - if backend in cls.BACKENDS_TO_SKIP: - def test(self): - self.skipTest('Expecting %s to fail' % (backend, )) - elif backend in cls.BACKENDS_THAT_WILL_FAIL_TO_CREATE_AT_RUNTIME: - def test(self): - with self.assertRaisesRegex(SystemError, 'ev_loop_new'): - Hub(backend, default=False) - else: - def test(self): - self._check_backend(backend) - test.__name__ = 'test_' + backend + '_' + str(count) - return test.__name__, test - - @classmethod - def _make_tests(cls): - count = backend = None - - for count in range(2): - for backend in core.supported_backends(): - name, func = cls._make_test(count, backend) - setattr(cls, name, func) - name = func = None - -Test._make_tests() - -if __name__ == '__main__': - unittest.main() diff --git a/venv/lib/python3.9/site-packages/gevent/tests/test__compat.py b/venv/lib/python3.9/site-packages/gevent/tests/test__compat.py deleted file mode 100644 index 7679597..0000000 --- a/venv/lib/python3.9/site-packages/gevent/tests/test__compat.py +++ /dev/null @@ -1,56 +0,0 @@ -from __future__ import absolute_import, print_function, division - -import os -import unittest - -class TestFSPath(unittest.TestCase): - - def setUp(self): - self.__path = None - - def __fspath__(self): - if self.__path is not None: - return self.__path - raise AttributeError("Accessing path data") - - def _callFUT(self, arg): - from gevent._compat import _fspath - return _fspath(arg) - - def test_text(self): - s = u'path' - self.assertIs(s, self._callFUT(s)) - - def test_bytes(self): - s = b'path' - self.assertIs(s, self._callFUT(s)) - - def test_None(self): - with self.assertRaises(TypeError): - self._callFUT(None) - - def test_working_path(self): - self.__path = u'text' - self.assertIs(self.__path, self._callFUT(self)) - - self.__path = b'bytes' - self.assertIs(self.__path, self._callFUT(self)) - - def test_failing_path_AttributeError(self): - self.assertIsNone(self.__path) - with self.assertRaises(AttributeError): - self._callFUT(self) - - def test_fspath_non_str(self): - self.__path = object() - with self.assertRaises(TypeError): - self._callFUT(self) - -@unittest.skipUnless(hasattr(os, 'fspath'), "Tests native os.fspath") -class TestNativeFSPath(TestFSPath): - - def _callFUT(self, arg): - return os.fspath(arg) - -if __name__ == '__main__': - unittest.main() diff --git a/venv/lib/python3.9/site-packages/gevent/tests/test__contextvars.py b/venv/lib/python3.9/site-packages/gevent/tests/test__contextvars.py deleted file mode 100644 index 883e83a..0000000 --- a/venv/lib/python3.9/site-packages/gevent/tests/test__contextvars.py +++ /dev/null @@ -1,1088 +0,0 @@ -# gevent: copied from 3.7 to test our monkey-patch. -# Modified to work on all versions of Python. -from gevent import monkey -monkey.patch_all() - -# pylint:disable=superfluous-parens,pointless-statement,not-callable -# pylint:disable=unused-argument,too-many-public-methods,unused-variable -# pylint:disable=too-many-branches,too-many-statements - -import concurrent.futures -try: - import contextvars -except ImportError: - from gevent import contextvars -import functools -# import gc -import random -import time -import unittest -# import weakref - -# try: -# from _testcapi import hamt -# except ImportError: -# hamt = None -hamt = None - -def isolated_context(func): - """Needed to make reftracking test mode work.""" - @functools.wraps(func) - def wrapper(*args, **kwargs): - ctx = contextvars.Context() - return ctx.run(func, *args, **kwargs) - return wrapper - - -class ContextTest(unittest.TestCase): - - if not hasattr(unittest.TestCase, 'assertRaisesRegex'): - assertRaisesRegex = unittest.TestCase.assertRaisesRegexp - - def test_context_var_new_1(self): - with self.assertRaises(TypeError): - contextvars.ContextVar() - - # gevent: Doesn't raise - # with self.assertRaisesRegex(TypeError, 'must be a str'): - # contextvars.ContextVar(1) - - c = contextvars.ContextVar('aaa') - self.assertEqual(c.name, 'aaa') - - with self.assertRaises(AttributeError): - c.name = 'bbb' - - self.assertNotEqual(hash(c), hash('aaa')) - - @isolated_context - def test_context_var_repr_1(self): - c = contextvars.ContextVar('a') - self.assertIn('a', repr(c)) - - c = contextvars.ContextVar('a', default=123) - self.assertIn('123', repr(c)) - - lst = [] - c = contextvars.ContextVar('a', default=lst) - lst.append(c) - self.assertIn('...', repr(c)) - self.assertIn('...', repr(lst)) - - t = c.set(1) - self.assertIn(repr(c), repr(t)) - self.assertNotIn(' used ', repr(t)) - c.reset(t) - self.assertIn(' used ', repr(t)) - - # gevent: Doesn't raise - # def test_context_subclassing_1(self): - # with self.assertRaisesRegex(TypeError, 'not an acceptable base type'): - # class MyContextVar(contextvars.ContextVar): - # # Potentially we might want ContextVars to be subclassable. - # pass - - # with self.assertRaisesRegex(TypeError, 'not an acceptable base type'): - # class MyContext(contextvars.Context): - # pass - - # with self.assertRaisesRegex(TypeError, 'not an acceptable base type'): - # class MyToken(contextvars.Token): - # pass - - def test_context_new_1(self): - with self.assertRaises(TypeError): - contextvars.Context(1) - with self.assertRaises(TypeError): - contextvars.Context(1, a=1) - with self.assertRaises(TypeError): - contextvars.Context(a=1) - contextvars.Context(**{}) - - def test_context_typerrors_1(self): - ctx = contextvars.Context() - - with self.assertRaisesRegex(TypeError, 'ContextVar key was expected'): - ctx[1] - with self.assertRaisesRegex(TypeError, 'ContextVar key was expected'): - 1 in ctx - with self.assertRaisesRegex(TypeError, 'ContextVar key was expected'): - ctx.get(1) - - def test_context_get_context_1(self): - ctx = contextvars.copy_context() - self.assertIsInstance(ctx, contextvars.Context) - - # gevent: This doesn't raise - # def test_context_run_1(self): - # ctx = contextvars.Context() - - # with self.assertRaisesRegex(TypeError, 'missing 1 required'): - # ctx.run() - - def test_context_run_2(self): - ctx = contextvars.Context() - - def func(*args, **kwargs): - kwargs['spam'] = 'foo' - args += ('bar',) - return args, kwargs - - for f in (func, functools.partial(func)): - # partial doesn't support FASTCALL - - self.assertEqual(ctx.run(f), (('bar',), {'spam': 'foo'})) - self.assertEqual(ctx.run(f, 1), ((1, 'bar'), {'spam': 'foo'})) - - self.assertEqual( - ctx.run(f, a=2), - (('bar',), {'a': 2, 'spam': 'foo'})) - - self.assertEqual( - ctx.run(f, 11, a=2), - ((11, 'bar'), {'a': 2, 'spam': 'foo'})) - - a = {} - self.assertEqual( - ctx.run(f, 11, **a), - ((11, 'bar'), {'spam': 'foo'})) - self.assertEqual(a, {}) - - def test_context_run_3(self): - ctx = contextvars.Context() - - def func(*args, **kwargs): - 1 / 0 - - with self.assertRaises(ZeroDivisionError): - ctx.run(func) - with self.assertRaises(ZeroDivisionError): - ctx.run(func, 1, 2) - with self.assertRaises(ZeroDivisionError): - ctx.run(func, 1, 2, a=123) - - @isolated_context - def test_context_run_4(self): - ctx1 = contextvars.Context() - ctx2 = contextvars.Context() - var = contextvars.ContextVar('var') - - def func2(): - self.assertIsNone(var.get(None)) - - def func1(): - self.assertIsNone(var.get(None)) - var.set('spam') - ctx2.run(func2) - self.assertEqual(var.get(None), 'spam') - - cur = contextvars.copy_context() - self.assertEqual(len(cur), 1) - self.assertEqual(cur[var], 'spam') - return cur - - returned_ctx = ctx1.run(func1) - self.assertEqual(ctx1, returned_ctx) - self.assertEqual(returned_ctx[var], 'spam') - self.assertIn(var, returned_ctx) - - def test_context_run_5(self): - ctx = contextvars.Context() - var = contextvars.ContextVar('var') - - def func(): - self.assertIsNone(var.get(None)) - var.set('spam') - 1 / 0 - - with self.assertRaises(ZeroDivisionError): - ctx.run(func) - - self.assertIsNone(var.get(None)) - - def test_context_run_6(self): - ctx = contextvars.Context() - c = contextvars.ContextVar('a', default=0) - - def fun(): - self.assertEqual(c.get(), 0) - self.assertIsNone(ctx.get(c)) - - c.set(42) - self.assertEqual(c.get(), 42) - self.assertEqual(ctx.get(c), 42) - - ctx.run(fun) - - def test_context_run_7(self): - ctx = contextvars.Context() - - def fun(): - with self.assertRaisesRegex(RuntimeError, 'is already entered'): - ctx.run(fun) - - ctx.run(fun) - - @isolated_context - def test_context_getset_1(self): - c = contextvars.ContextVar('c') - with self.assertRaises(LookupError): - c.get() - - self.assertIsNone(c.get(None)) - - t0 = c.set(42) - self.assertEqual(c.get(), 42) - self.assertEqual(c.get(None), 42) - self.assertIs(t0.old_value, t0.MISSING) - self.assertIs(t0.old_value, contextvars.Token.MISSING) - self.assertIs(t0.var, c) - - t = c.set('spam') - self.assertEqual(c.get(), 'spam') - self.assertEqual(c.get(None), 'spam') - self.assertEqual(t.old_value, 42) - c.reset(t) - - self.assertEqual(c.get(), 42) - self.assertEqual(c.get(None), 42) - - c.set('spam2') - with self.assertRaisesRegex(RuntimeError, 'has already been used'): - c.reset(t) - self.assertEqual(c.get(), 'spam2') - - ctx1 = contextvars.copy_context() - self.assertIn(c, ctx1) - - c.reset(t0) - with self.assertRaisesRegex(RuntimeError, 'has already been used'): - c.reset(t0) - self.assertIsNone(c.get(None)) - - self.assertIn(c, ctx1) - self.assertEqual(ctx1[c], 'spam2') - self.assertEqual(ctx1.get(c, 'aa'), 'spam2') - self.assertEqual(len(ctx1), 1) - self.assertEqual(list(ctx1.items()), [(c, 'spam2')]) - self.assertEqual(list(ctx1.values()), ['spam2']) - self.assertEqual(list(ctx1.keys()), [c]) - self.assertEqual(list(ctx1), [c]) - - ctx2 = contextvars.copy_context() - self.assertNotIn(c, ctx2) - with self.assertRaises(KeyError): - ctx2[c] - self.assertEqual(ctx2.get(c, 'aa'), 'aa') - self.assertEqual(len(ctx2), 0) - self.assertEqual(list(ctx2), []) - - @isolated_context - def test_context_getset_2(self): - v1 = contextvars.ContextVar('v1') - v2 = contextvars.ContextVar('v2') - - t1 = v1.set(42) - with self.assertRaisesRegex(ValueError, 'by a different'): - v2.reset(t1) - - @isolated_context - def test_context_getset_3(self): - c = contextvars.ContextVar('c', default=42) - ctx = contextvars.Context() - - def fun(): - self.assertEqual(c.get(), 42) - with self.assertRaises(KeyError): - ctx[c] - self.assertIsNone(ctx.get(c)) - self.assertEqual(ctx.get(c, 'spam'), 'spam') - self.assertNotIn(c, ctx) - self.assertEqual(list(ctx.keys()), []) - - t = c.set(1) - self.assertEqual(list(ctx.keys()), [c]) - self.assertEqual(ctx[c], 1) - - c.reset(t) - self.assertEqual(list(ctx.keys()), []) - with self.assertRaises(KeyError): - ctx[c] - - ctx.run(fun) - - @isolated_context - def test_context_getset_4(self): - c = contextvars.ContextVar('c', default=42) - ctx = contextvars.Context() - - tok = ctx.run(c.set, 1) - - with self.assertRaisesRegex(ValueError, 'different Context'): - c.reset(tok) - - @isolated_context - def test_context_getset_5(self): - c = contextvars.ContextVar('c', default=42) - c.set([]) - - def fun(): - c.set([]) - c.get().append(42) - self.assertEqual(c.get(), [42]) - - contextvars.copy_context().run(fun) - self.assertEqual(c.get(), []) - - def test_context_copy_1(self): - ctx1 = contextvars.Context() - c = contextvars.ContextVar('c', default=42) - - def ctx1_fun(): - c.set(10) - - ctx2 = ctx1.copy() - self.assertEqual(ctx2[c], 10) - - c.set(20) - self.assertEqual(ctx1[c], 20) - self.assertEqual(ctx2[c], 10) - - ctx2.run(ctx2_fun) - self.assertEqual(ctx1[c], 20) - self.assertEqual(ctx2[c], 30) - - def ctx2_fun(): - self.assertEqual(c.get(), 10) - c.set(30) - self.assertEqual(c.get(), 30) - - ctx1.run(ctx1_fun) - - @isolated_context - def test_context_threads_1(self): - cvar = contextvars.ContextVar('cvar') - - def sub(num): - for i in range(10): - cvar.set(num + i) - time.sleep(random.uniform(0.001, 0.05)) - self.assertEqual(cvar.get(), num + i) - return num - - with concurrent.futures.ThreadPoolExecutor(max_workers=10) as tp: - results = list(tp.map(sub, range(10))) - - self.assertEqual(results, list(range(10))) - - # gevent: clases's can't be subscripted on Python 3.6 - # def test_contextvar_getitem(self): - # clss = contextvars.ContextVar - # self.assertEqual(clss[str], clss) - - -# HAMT Tests - - -# class HashKey: -# _crasher = None - -# def __init__(self, hash, name, error_on_eq_to=None): -# assert hash != -1 -# self.name = name -# self.hash = hash -# self.error_on_eq_to = error_on_eq_to - -# # def __repr__(self): -# # return f'' - -# def __hash__(self): -# if self._crasher is not None and self._crasher.error_on_hash: -# raise HashingError - -# return self.hash - -# def __eq__(self, other): -# if not isinstance(other, HashKey): -# return NotImplemented - -# if self._crasher is not None and self._crasher.error_on_eq: -# raise EqError - -# if self.error_on_eq_to is not None and self.error_on_eq_to is other: -# raise ValueError#(f'cannot compare {self!r} to {other!r}') -# if other.error_on_eq_to is not None and other.error_on_eq_to is self: -# raise ValueError#(f'cannot compare {other!r} to {self!r}') - -# return (self.name, self.hash) == (other.name, other.hash) - - -# class KeyStr(str): -# def __hash__(self): -# if HashKey._crasher is not None and HashKey._crasher.error_on_hash: -# raise HashingError -# return super().__hash__() - -# def __eq__(self, other): -# if HashKey._crasher is not None and HashKey._crasher.error_on_eq: -# raise EqError -# return super().__eq__(other) - - -# class HaskKeyCrasher: -# def __init__(self, error_on_hash=False, error_on_eq=False): -# self.error_on_hash = error_on_hash -# self.error_on_eq = error_on_eq - -# def __enter__(self): -# if HashKey._crasher is not None: -# raise RuntimeError('cannot nest crashers') -# HashKey._crasher = self - -# def __exit__(self, *exc): -# HashKey._crasher = None - - -# class HashingError(Exception): -# pass - - -# class EqError(Exception): -# pass - - -# @unittest.skipIf(hamt is None, '_testcapi lacks "hamt()" function') -# class HamtTest(unittest.TestCase): - -# def test_hashkey_helper_1(self): -# k1 = HashKey(10, 'aaa') -# k2 = HashKey(10, 'bbb') - -# self.assertNotEqual(k1, k2) -# self.assertEqual(hash(k1), hash(k2)) - -# d = dict() -# d[k1] = 'a' -# d[k2] = 'b' - -# self.assertEqual(d[k1], 'a') -# self.assertEqual(d[k2], 'b') - -# def test_hamt_basics_1(self): -# h = hamt() -# h = None # NoQA - -# def test_hamt_basics_2(self): -# h = hamt() -# self.assertEqual(len(h), 0) - -# h2 = h.set('a', 'b') -# self.assertIsNot(h, h2) -# self.assertEqual(len(h), 0) -# self.assertEqual(len(h2), 1) - -# self.assertIsNone(h.get('a')) -# self.assertEqual(h.get('a', 42), 42) - -# self.assertEqual(h2.get('a'), 'b') - -# h3 = h2.set('b', 10) -# self.assertIsNot(h2, h3) -# self.assertEqual(len(h), 0) -# self.assertEqual(len(h2), 1) -# self.assertEqual(len(h3), 2) -# self.assertEqual(h3.get('a'), 'b') -# self.assertEqual(h3.get('b'), 10) - -# self.assertIsNone(h.get('b')) -# self.assertIsNone(h2.get('b')) - -# self.assertIsNone(h.get('a')) -# self.assertEqual(h2.get('a'), 'b') - -# h = h2 = h3 = None - -# def test_hamt_basics_3(self): -# h = hamt() -# o = object() -# h1 = h.set('1', o) -# h2 = h1.set('1', o) -# self.assertIs(h1, h2) - -# def test_hamt_basics_4(self): -# h = hamt() -# h1 = h.set('key', []) -# h2 = h1.set('key', []) -# self.assertIsNot(h1, h2) -# self.assertEqual(len(h1), 1) -# self.assertEqual(len(h2), 1) -# self.assertIsNot(h1.get('key'), h2.get('key')) - -# def test_hamt_collision_1(self): -# k1 = HashKey(10, 'aaa') -# k2 = HashKey(10, 'bbb') -# k3 = HashKey(10, 'ccc') - -# h = hamt() -# h2 = h.set(k1, 'a') -# h3 = h2.set(k2, 'b') - -# self.assertEqual(h.get(k1), None) -# self.assertEqual(h.get(k2), None) - -# self.assertEqual(h2.get(k1), 'a') -# self.assertEqual(h2.get(k2), None) - -# self.assertEqual(h3.get(k1), 'a') -# self.assertEqual(h3.get(k2), 'b') - -# h4 = h3.set(k2, 'cc') -# h5 = h4.set(k3, 'aa') - -# self.assertEqual(h3.get(k1), 'a') -# self.assertEqual(h3.get(k2), 'b') -# self.assertEqual(h4.get(k1), 'a') -# self.assertEqual(h4.get(k2), 'cc') -# self.assertEqual(h4.get(k3), None) -# self.assertEqual(h5.get(k1), 'a') -# self.assertEqual(h5.get(k2), 'cc') -# self.assertEqual(h5.get(k2), 'cc') -# self.assertEqual(h5.get(k3), 'aa') - -# self.assertEqual(len(h), 0) -# self.assertEqual(len(h2), 1) -# self.assertEqual(len(h3), 2) -# self.assertEqual(len(h4), 2) -# self.assertEqual(len(h5), 3) - -# def test_hamt_stress(self): -# COLLECTION_SIZE = 7000 -# TEST_ITERS_EVERY = 647 -# CRASH_HASH_EVERY = 97 -# CRASH_EQ_EVERY = 11 -# RUN_XTIMES = 3 - -# for _ in range(RUN_XTIMES): -# h = hamt() -# d = dict() - -# for i in range(COLLECTION_SIZE): -# key = KeyStr(i) - -# if not (i % CRASH_HASH_EVERY): -# with HaskKeyCrasher(error_on_hash=True): -# with self.assertRaises(HashingError): -# h.set(key, i) - -# h = h.set(key, i) - -# if not (i % CRASH_EQ_EVERY): -# with HaskKeyCrasher(error_on_eq=True): -# with self.assertRaises(EqError): -# h.get(KeyStr(i)) # really trigger __eq__ - -# d[key] = i -# self.assertEqual(len(d), len(h)) - -# if not (i % TEST_ITERS_EVERY): -# self.assertEqual(set(h.items()), set(d.items())) -# self.assertEqual(len(h.items()), len(d.items())) - -# self.assertEqual(len(h), COLLECTION_SIZE) - -# for key in range(COLLECTION_SIZE): -# self.assertEqual(h.get(KeyStr(key), 'not found'), key) - -# keys_to_delete = list(range(COLLECTION_SIZE)) -# random.shuffle(keys_to_delete) -# for iter_i, i in enumerate(keys_to_delete): -# key = KeyStr(i) - -# if not (iter_i % CRASH_HASH_EVERY): -# with HaskKeyCrasher(error_on_hash=True): -# with self.assertRaises(HashingError): -# h.delete(key) - -# if not (iter_i % CRASH_EQ_EVERY): -# with HaskKeyCrasher(error_on_eq=True): -# with self.assertRaises(EqError): -# h.delete(KeyStr(i)) - -# h = h.delete(key) -# self.assertEqual(h.get(key, 'not found'), 'not found') -# del d[key] -# self.assertEqual(len(d), len(h)) - -# if iter_i == COLLECTION_SIZE // 2: -# hm = h -# dm = d.copy() - -# if not (iter_i % TEST_ITERS_EVERY): -# self.assertEqual(set(h.keys()), set(d.keys())) -# self.assertEqual(len(h.keys()), len(d.keys())) - -# self.assertEqual(len(d), 0) -# self.assertEqual(len(h), 0) - -# # ============ - -# for key in dm: -# self.assertEqual(hm.get(str(key)), dm[key]) -# self.assertEqual(len(dm), len(hm)) - -# for i, key in enumerate(keys_to_delete): -# hm = hm.delete(str(key)) -# self.assertEqual(hm.get(str(key), 'not found'), 'not found') -# dm.pop(str(key), None) -# self.assertEqual(len(d), len(h)) - -# if not (i % TEST_ITERS_EVERY): -# self.assertEqual(set(h.values()), set(d.values())) -# self.assertEqual(len(h.values()), len(d.values())) - -# self.assertEqual(len(d), 0) -# self.assertEqual(len(h), 0) -# self.assertEqual(list(h.items()), []) - -# def test_hamt_delete_1(self): -# A = HashKey(100, 'A') -# B = HashKey(101, 'B') -# C = HashKey(102, 'C') -# D = HashKey(103, 'D') -# E = HashKey(104, 'E') -# Z = HashKey(-100, 'Z') - -# Er = HashKey(103, 'Er', error_on_eq_to=D) - -# h = hamt() -# h = h.set(A, 'a') -# h = h.set(B, 'b') -# h = h.set(C, 'c') -# h = h.set(D, 'd') -# h = h.set(E, 'e') - -# orig_len = len(h) - -# # BitmapNode(size=10 bitmap=0b111110000 id=0x10eadc618): -# # : 'a' -# # : 'b' -# # : 'c' -# # : 'd' -# # : 'e' - -# h = h.delete(C) -# self.assertEqual(len(h), orig_len - 1) - -# with self.assertRaisesRegex(ValueError, 'cannot compare'): -# h.delete(Er) - -# h = h.delete(D) -# self.assertEqual(len(h), orig_len - 2) - -# h2 = h.delete(Z) -# self.assertIs(h2, h) - -# h = h.delete(A) -# self.assertEqual(len(h), orig_len - 3) - -# self.assertEqual(h.get(A, 42), 42) -# self.assertEqual(h.get(B), 'b') -# self.assertEqual(h.get(E), 'e') - -# def test_hamt_delete_2(self): -# A = HashKey(100, 'A') -# B = HashKey(201001, 'B') -# C = HashKey(101001, 'C') -# D = HashKey(103, 'D') -# E = HashKey(104, 'E') -# Z = HashKey(-100, 'Z') - -# Er = HashKey(201001, 'Er', error_on_eq_to=B) - -# h = hamt() -# h = h.set(A, 'a') -# h = h.set(B, 'b') -# h = h.set(C, 'c') -# h = h.set(D, 'd') -# h = h.set(E, 'e') - -# orig_len = len(h) - -# # BitmapNode(size=8 bitmap=0b1110010000): -# # : 'a' -# # : 'd' -# # : 'e' -# # NULL: -# # BitmapNode(size=4 bitmap=0b100000000001000000000): -# # : 'b' -# # : 'c' - -# with self.assertRaisesRegex(ValueError, 'cannot compare'): -# h.delete(Er) - -# h = h.delete(Z) -# self.assertEqual(len(h), orig_len) - -# h = h.delete(C) -# self.assertEqual(len(h), orig_len - 1) - -# h = h.delete(B) -# self.assertEqual(len(h), orig_len - 2) - -# h = h.delete(A) -# self.assertEqual(len(h), orig_len - 3) - -# self.assertEqual(h.get(D), 'd') -# self.assertEqual(h.get(E), 'e') - -# h = h.delete(A) -# h = h.delete(B) -# h = h.delete(D) -# h = h.delete(E) -# self.assertEqual(len(h), 0) - -# def test_hamt_delete_3(self): -# A = HashKey(100, 'A') -# B = HashKey(101, 'B') -# C = HashKey(100100, 'C') -# D = HashKey(100100, 'D') -# E = HashKey(104, 'E') - -# h = hamt() -# h = h.set(A, 'a') -# h = h.set(B, 'b') -# h = h.set(C, 'c') -# h = h.set(D, 'd') -# h = h.set(E, 'e') - -# orig_len = len(h) - -# # BitmapNode(size=6 bitmap=0b100110000): -# # NULL: -# # BitmapNode(size=4 bitmap=0b1000000000000000000001000): -# # : 'a' -# # NULL: -# # CollisionNode(size=4 id=0x108572410): -# # : 'c' -# # : 'd' -# # : 'b' -# # : 'e' - -# h = h.delete(A) -# self.assertEqual(len(h), orig_len - 1) - -# h = h.delete(E) -# self.assertEqual(len(h), orig_len - 2) - -# self.assertEqual(h.get(C), 'c') -# self.assertEqual(h.get(B), 'b') - -# def test_hamt_delete_4(self): -# A = HashKey(100, 'A') -# B = HashKey(101, 'B') -# C = HashKey(100100, 'C') -# D = HashKey(100100, 'D') -# E = HashKey(100100, 'E') - -# h = hamt() -# h = h.set(A, 'a') -# h = h.set(B, 'b') -# h = h.set(C, 'c') -# h = h.set(D, 'd') -# h = h.set(E, 'e') - -# orig_len = len(h) - -# # BitmapNode(size=4 bitmap=0b110000): -# # NULL: -# # BitmapNode(size=4 bitmap=0b1000000000000000000001000): -# # : 'a' -# # NULL: -# # CollisionNode(size=6 id=0x10515ef30): -# # : 'c' -# # : 'd' -# # : 'e' -# # : 'b' - -# h = h.delete(D) -# self.assertEqual(len(h), orig_len - 1) - -# h = h.delete(E) -# self.assertEqual(len(h), orig_len - 2) - -# h = h.delete(C) -# self.assertEqual(len(h), orig_len - 3) - -# h = h.delete(A) -# self.assertEqual(len(h), orig_len - 4) - -# h = h.delete(B) -# self.assertEqual(len(h), 0) - -# def test_hamt_delete_5(self): -# h = hamt() - -# keys = [] -# for i in range(17): -# key = HashKey(i, str(i)) -# keys.append(key) -# h = h.set(key, 'val-{i}'.format(i=i)) - -# collision_key16 = HashKey(16, '18') -# h = h.set(collision_key16, 'collision') - -# # ArrayNode(id=0x10f8b9318): -# # 0:: -# # BitmapNode(size=2 count=1 bitmap=0b1): -# # : 'val-0' -# # -# # ... 14 more BitmapNodes ... -# # -# # 15:: -# # BitmapNode(size=2 count=1 bitmap=0b1): -# # : 'val-15' -# # -# # 16:: -# # BitmapNode(size=2 count=1 bitmap=0b1): -# # NULL: -# # CollisionNode(size=4 id=0x10f2f5af8): -# # : 'val-16' -# # : 'collision' - -# self.assertEqual(len(h), 18) - -# h = h.delete(keys[2]) -# self.assertEqual(len(h), 17) - -# h = h.delete(collision_key16) -# self.assertEqual(len(h), 16) -# h = h.delete(keys[16]) -# self.assertEqual(len(h), 15) - -# h = h.delete(keys[1]) -# self.assertEqual(len(h), 14) -# h = h.delete(keys[1]) -# self.assertEqual(len(h), 14) - -# for key in keys: -# h = h.delete(key) -# self.assertEqual(len(h), 0) - -# def test_hamt_items_1(self): -# A = HashKey(100, 'A') -# B = HashKey(201001, 'B') -# C = HashKey(101001, 'C') -# D = HashKey(103, 'D') -# E = HashKey(104, 'E') -# F = HashKey(110, 'F') - -# h = hamt() -# h = h.set(A, 'a') -# h = h.set(B, 'b') -# h = h.set(C, 'c') -# h = h.set(D, 'd') -# h = h.set(E, 'e') -# h = h.set(F, 'f') - -# it = h.items() -# self.assertEqual( -# set(list(it)), -# {(A, 'a'), (B, 'b'), (C, 'c'), (D, 'd'), (E, 'e'), (F, 'f')}) - -# def test_hamt_items_2(self): -# A = HashKey(100, 'A') -# B = HashKey(101, 'B') -# C = HashKey(100100, 'C') -# D = HashKey(100100, 'D') -# E = HashKey(100100, 'E') -# F = HashKey(110, 'F') - -# h = hamt() -# h = h.set(A, 'a') -# h = h.set(B, 'b') -# h = h.set(C, 'c') -# h = h.set(D, 'd') -# h = h.set(E, 'e') -# h = h.set(F, 'f') - -# it = h.items() -# self.assertEqual( -# set(list(it)), -# {(A, 'a'), (B, 'b'), (C, 'c'), (D, 'd'), (E, 'e'), (F, 'f')}) - -# def test_hamt_keys_1(self): -# A = HashKey(100, 'A') -# B = HashKey(101, 'B') -# C = HashKey(100100, 'C') -# D = HashKey(100100, 'D') -# E = HashKey(100100, 'E') -# F = HashKey(110, 'F') - -# h = hamt() -# h = h.set(A, 'a') -# h = h.set(B, 'b') -# h = h.set(C, 'c') -# h = h.set(D, 'd') -# h = h.set(E, 'e') -# h = h.set(F, 'f') - -# self.assertEqual(set(list(h.keys())), {A, B, C, D, E, F}) -# self.assertEqual(set(list(h)), {A, B, C, D, E, F}) - -# def test_hamt_items_3(self): -# h = hamt() -# self.assertEqual(len(h.items()), 0) -# self.assertEqual(list(h.items()), []) - -# def test_hamt_eq_1(self): -# A = HashKey(100, 'A') -# B = HashKey(101, 'B') -# C = HashKey(100100, 'C') -# D = HashKey(100100, 'D') -# E = HashKey(120, 'E') - -# h1 = hamt() -# h1 = h1.set(A, 'a') -# h1 = h1.set(B, 'b') -# h1 = h1.set(C, 'c') -# h1 = h1.set(D, 'd') - -# h2 = hamt() -# h2 = h2.set(A, 'a') - -# self.assertFalse(h1 == h2) -# self.assertTrue(h1 != h2) - -# h2 = h2.set(B, 'b') -# self.assertFalse(h1 == h2) -# self.assertTrue(h1 != h2) - -# h2 = h2.set(C, 'c') -# self.assertFalse(h1 == h2) -# self.assertTrue(h1 != h2) - -# h2 = h2.set(D, 'd2') -# self.assertFalse(h1 == h2) -# self.assertTrue(h1 != h2) - -# h2 = h2.set(D, 'd') -# self.assertTrue(h1 == h2) -# self.assertFalse(h1 != h2) - -# h2 = h2.set(E, 'e') -# self.assertFalse(h1 == h2) -# self.assertTrue(h1 != h2) - -# h2 = h2.delete(D) -# self.assertFalse(h1 == h2) -# self.assertTrue(h1 != h2) - -# h2 = h2.set(E, 'd') -# self.assertFalse(h1 == h2) -# self.assertTrue(h1 != h2) - -# def test_hamt_eq_2(self): -# A = HashKey(100, 'A') -# Er = HashKey(100, 'Er', error_on_eq_to=A) - -# h1 = hamt() -# h1 = h1.set(A, 'a') - -# h2 = hamt() -# h2 = h2.set(Er, 'a') - -# with self.assertRaisesRegex(ValueError, 'cannot compare'): -# h1 == h2 - -# with self.assertRaisesRegex(ValueError, 'cannot compare'): -# h1 != h2 - -# def test_hamt_gc_1(self): -# A = HashKey(100, 'A') - -# h = hamt() -# h = h.set(0, 0) # empty HAMT node is memoized in hamt.c -# ref = weakref.ref(h) - -# a = [] -# a.append(a) -# a.append(h) -# b = [] -# a.append(b) -# b.append(a) -# h = h.set(A, b) - -# del h, a, b - -# gc.collect() -# gc.collect() -# gc.collect() - -# self.assertIsNone(ref()) - -# def test_hamt_gc_2(self): -# A = HashKey(100, 'A') -# B = HashKey(101, 'B') - -# h = hamt() -# h = h.set(A, 'a') -# h = h.set(A, h) - -# ref = weakref.ref(h) -# hi = h.items() -# next(hi) - -# del h, hi - -# gc.collect() -# gc.collect() -# gc.collect() - -# self.assertIsNone(ref()) - -# def test_hamt_in_1(self): -# A = HashKey(100, 'A') -# AA = HashKey(100, 'A') - -# B = HashKey(101, 'B') - -# h = hamt() -# h = h.set(A, 1) - -# self.assertTrue(A in h) -# self.assertFalse(B in h) - -# with self.assertRaises(EqError): -# with HaskKeyCrasher(error_on_eq=True): -# AA in h - -# with self.assertRaises(HashingError): -# with HaskKeyCrasher(error_on_hash=True): -# AA in h - -# def test_hamt_getitem_1(self): -# A = HashKey(100, 'A') -# AA = HashKey(100, 'A') - -# B = HashKey(101, 'B') - -# h = hamt() -# h = h.set(A, 1) - -# self.assertEqual(h[A], 1) -# self.assertEqual(h[AA], 1) - -# with self.assertRaises(KeyError): -# h[B] - -# with self.assertRaises(EqError): -# with HaskKeyCrasher(error_on_eq=True): -# h[AA] - -# with self.assertRaises(HashingError): -# with HaskKeyCrasher(error_on_hash=True): -# h[AA] - - -if __name__ == "__main__": - unittest.main() diff --git a/venv/lib/python3.9/site-packages/gevent/tests/test__core.py b/venv/lib/python3.9/site-packages/gevent/tests/test__core.py deleted file mode 100644 index 14e6e82..0000000 --- a/venv/lib/python3.9/site-packages/gevent/tests/test__core.py +++ /dev/null @@ -1,164 +0,0 @@ - -from __future__ import absolute_import, print_function, division - -# Important: This file should have no dependencies that are part of the -# ``test`` extra, because it is sometimes run for quick checks without those -# installed. - -import unittest -import sys -import gevent.testing as greentest - -from gevent._config import Loop - -available_loops = Loop().get_options() -available_loops.pop('libuv', None) - -def not_available(name): - return isinstance(available_loops[name], ImportError) - - -class WatcherTestMixin(object): - kind = None - - def _makeOne(self): - return self.kind(default=False) # pylint:disable=not-callable - - def destroyOne(self, loop): - loop.destroy() - - def setUp(self): - self.loop = self._makeOne() - self.core = sys.modules[self.kind.__module__] - - def tearDown(self): - self.destroyOne(self.loop) - del self.loop - - def test_get_version(self): - version = self.core.get_version() # pylint: disable=no-member - self.assertIsInstance(version, str) - self.assertTrue(version) - header_version = self.core.get_header_version() # pylint: disable=no-member - self.assertIsInstance(header_version, str) - self.assertTrue(header_version) - self.assertEqual(version, header_version) - - def test_events_conversion(self): - self.assertEqual(self.core._events_to_str(self.core.READ | self.core.WRITE), # pylint: disable=no-member - 'READ|WRITE') - - def test_EVENTS(self): - self.assertEqual(str(self.core.EVENTS), # pylint: disable=no-member - 'gevent.core.EVENTS') - self.assertEqual(repr(self.core.EVENTS), # pylint: disable=no-member - 'gevent.core.EVENTS') - - def test_io(self): - if greentest.WIN: - # libev raises IOError, libuv raises ValueError - Error = (IOError, ValueError) - else: - Error = ValueError - - with self.assertRaises(Error): - self.loop.io(-1, 1) - - if hasattr(self.core, 'TIMER'): - # libev - with self.assertRaises(ValueError): - self.loop.io(1, self.core.TIMER) # pylint:disable=no-member - - # Test we can set events and io before it's started - if not greentest.WIN: - # We can't do this with arbitrary FDs on windows; - # see libev_vfd.h - io = self.loop.io(1, self.core.READ) # pylint:disable=no-member - io.fd = 2 - self.assertEqual(io.fd, 2) - io.events = self.core.WRITE # pylint:disable=no-member - if not hasattr(self.core, 'libuv'): - # libev - # pylint:disable=no-member - self.assertEqual(self.core._events_to_str(io.events), 'WRITE|_IOFDSET') - else: - - self.assertEqual(self.core._events_to_str(io.events), # pylint:disable=no-member - 'WRITE') - io.start(lambda: None) - io.close() - - def test_timer_constructor(self): - with self.assertRaises(ValueError): - self.loop.timer(1, -1) - - def test_signal_constructor(self): - with self.assertRaises(ValueError): - self.loop.signal(1000) - - -class LibevTestMixin(WatcherTestMixin): - - def test_flags_conversion(self): - # pylint: disable=no-member - core = self.core - if not greentest.WIN: - self.assertEqual(core.loop(2, default=False).backend_int, 2) - self.assertEqual(core.loop('select', default=False).backend, 'select') - self.assertEqual(core._flags_to_int(None), 0) - self.assertEqual(core._flags_to_int(['kqueue', 'SELECT']), core.BACKEND_KQUEUE | core.BACKEND_SELECT) - self.assertEqual(core._flags_to_list(core.BACKEND_PORT | core.BACKEND_POLL), ['port', 'poll']) - self.assertRaises(ValueError, core.loop, ['port', 'blabla']) - self.assertRaises(TypeError, core.loop, object()) - -@unittest.skipIf(not_available('libev-cext'), "Needs libev-cext") -class TestLibevCext(LibevTestMixin, unittest.TestCase): - kind = available_loops['libev-cext'] - -@unittest.skipIf(not_available('libev-cffi'), "Needs libev-cffi") -class TestLibevCffi(LibevTestMixin, unittest.TestCase): - kind = available_loops['libev-cffi'] - -@unittest.skipIf(not_available('libuv-cffi'), "Needs libuv-cffi") -class TestLibuvCffi(WatcherTestMixin, unittest.TestCase): - kind = available_loops['libuv-cffi'] - - @greentest.skipOnLibev("libuv-specific") - @greentest.skipOnWindows("Destroying the loop somehow fails") - def test_io_multiplex_events(self): - # pylint:disable=no-member - import socket - sock = socket.socket() - fd = sock.fileno() - core = self.core - read = self.loop.io(fd, core.READ) - write = self.loop.io(fd, core.WRITE) - - try: - real_watcher = read._watcher_ref - - read.start(lambda: None) - self.assertEqual(real_watcher.events, core.READ) - - write.start(lambda: None) - self.assertEqual(real_watcher.events, core.READ | core.WRITE) - - write.stop() - self.assertEqual(real_watcher.events, core.READ) - - write.start(lambda: None) - self.assertEqual(real_watcher.events, core.READ | core.WRITE) - - read.stop() - self.assertEqual(real_watcher.events, core.WRITE) - - write.stop() - self.assertEqual(real_watcher.events, 0) - finally: - read.close() - write.close() - sock.close() - - -if __name__ == '__main__': - greentest.main() diff --git a/venv/lib/python3.9/site-packages/gevent/tests/test__core_async.py b/venv/lib/python3.9/site-packages/gevent/tests/test__core_async.py deleted file mode 100644 index 1a9a435..0000000 --- a/venv/lib/python3.9/site-packages/gevent/tests/test__core_async.py +++ /dev/null @@ -1,31 +0,0 @@ -from __future__ import print_function -import gevent -import gevent.core -import time -try: - import thread -except ImportError: - import _thread as thread - -from gevent import testing as greentest - -class Test(greentest.TestCase): - def test(self): - hub = gevent.get_hub() - watcher = hub.loop.async_() - - # BWC for <3.7: This should still be an attribute - assert hasattr(hub.loop, 'async') - - gevent.spawn_later(0.1, thread.start_new_thread, watcher.send, ()) - - start = time.time() - - with gevent.Timeout(1.0): # Large timeout for appveyor - hub.wait(watcher) - - print('Watcher %r reacted after %.6f seconds' % (watcher, time.time() - start - 0.1)) - - -if __name__ == '__main__': - greentest.main() diff --git a/venv/lib/python3.9/site-packages/gevent/tests/test__core_callback.py b/venv/lib/python3.9/site-packages/gevent/tests/test__core_callback.py deleted file mode 100644 index f5af088..0000000 --- a/venv/lib/python3.9/site-packages/gevent/tests/test__core_callback.py +++ /dev/null @@ -1,32 +0,0 @@ -import gevent -from gevent.hub import get_hub - -from gevent import testing as greentest - -class Test(greentest.TestCase): - - def test(self): - loop = get_hub().loop - called = [] - - def f(): - called.append(1) - - x = loop.run_callback(f) - - assert x, x - gevent.sleep(0) - assert called == [1], called - assert not x, (x, bool(x)) - - x = loop.run_callback(f) - assert x, x - x.stop() - assert not x, x - gevent.sleep(0) - assert called == [1], called - assert not x, x - - -if __name__ == '__main__': - greentest.main() diff --git a/venv/lib/python3.9/site-packages/gevent/tests/test__core_fork.py b/venv/lib/python3.9/site-packages/gevent/tests/test__core_fork.py deleted file mode 100644 index db51703..0000000 --- a/venv/lib/python3.9/site-packages/gevent/tests/test__core_fork.py +++ /dev/null @@ -1,84 +0,0 @@ -from __future__ import print_function -from gevent import monkey -monkey.patch_all() - -import os -import unittest -import multiprocessing - -import gevent - -hub = gevent.get_hub() -pid = os.getpid() -newpid = None - - -def on_fork(): - global newpid - newpid = os.getpid() - -fork_watcher = hub.loop.fork(ref=False) -fork_watcher.start(on_fork) - - -def in_child(q): - # libev only calls fork callbacks at the beginning of - # the loop; we use callbacks extensively so it takes *two* - # calls to sleep (with a timer) to actually get wrapped - # around to the beginning of the loop. - gevent.sleep(0.001) - gevent.sleep(0.001) - q.put(newpid) - - -class Test(unittest.TestCase): - - def test(self): - self.assertEqual(hub.threadpool.size, 0) - # Use a thread to make us multi-threaded - hub.threadpool.apply(lambda: None) - self.assertEqual(hub.threadpool.size, 1) - - # Not all platforms use fork by default, so we want to force it, - # where possible. The test is still useful even if we can't - # fork though. - try: - fork_ctx = multiprocessing.get_context('fork') - except (AttributeError, ValueError): - # ValueError if fork isn't supported. - # AttributeError on Python 2, which doesn't have get_context - fork_ctx = multiprocessing - - # If the Queue is global, q.get() hangs on Windows; must pass as - # an argument. - q = fork_ctx.Queue() - p = fork_ctx.Process(target=in_child, args=(q,)) - p.start() - p.join() - p_val = q.get() - - self.assertIsNone( - newpid, - "The fork watcher ran in the parent for some reason." - ) - self.assertIsNotNone( - p_val, - "The child process returned nothing, meaning the fork watcher didn't run in the child." - ) - self.assertNotEqual(p_val, pid) - assert p_val != pid - -if __name__ == '__main__': - # Must call for Windows to fork properly; the fork can't be in the top-level - multiprocessing.freeze_support() - - # fork watchers weren't firing in multi-threading processes. - # This test is designed to prove that they are. - # However, it fails on Windows: The fork watcher never runs! - # This makes perfect sense: on Windows, our patches to os.fork() - # that call gevent.hub.reinit() don't get used; os.fork doesn't - # exist and multiprocessing.Process uses the windows-specific _subprocess.CreateProcess() - # to create a whole new process that has no relation to the current process; - # that process then calls multiprocessing.forking.main() to do its work. - # Since no state is shared, a fork watcher cannot exist in that process. - unittest.main() diff --git a/venv/lib/python3.9/site-packages/gevent/tests/test__core_loop_run.py b/venv/lib/python3.9/site-packages/gevent/tests/test__core_loop_run.py deleted file mode 100644 index 64c4c04..0000000 --- a/venv/lib/python3.9/site-packages/gevent/tests/test__core_loop_run.py +++ /dev/null @@ -1,22 +0,0 @@ -from __future__ import print_function -import sys -from gevent import core -from gevent import signal_handler as signal -loop = core.loop(default=False) - - -signal = signal(2, sys.stderr.write, 'INTERRUPT!') - -print('must exit immediately...') -loop.run() # must exit immediately -print('...and once more...') -loop.run() # repeating does not fail -print('..done') - -print('must exit after 0.5 seconds.') -timer = loop.timer(0.5) -timer.start(lambda: None) -loop.run() -timer.close() -loop.destroy() -del loop diff --git a/venv/lib/python3.9/site-packages/gevent/tests/test__core_stat.py b/venv/lib/python3.9/site-packages/gevent/tests/test__core_stat.py deleted file mode 100644 index d022d90..0000000 --- a/venv/lib/python3.9/site-packages/gevent/tests/test__core_stat.py +++ /dev/null @@ -1,118 +0,0 @@ -from __future__ import print_function - -import os -import tempfile -import time - -import gevent -import gevent.core - -import gevent.testing as greentest -import gevent.testing.flaky - -#pylint: disable=protected-access - - -DELAY = 0.5 - -WIN = greentest.WIN - -LIBUV = greentest.LIBUV - -class TestCoreStat(greentest.TestCase): - - __timeout__ = greentest.LARGE_TIMEOUT - - def setUp(self): - super(TestCoreStat, self).setUp() - fd, path = tempfile.mkstemp(suffix='.gevent_test_core_stat') - os.close(fd) - self.temp_path = path - self.hub = gevent.get_hub() - # If we don't specify an interval, we default to zero. - # libev interprets that as meaning to use its default interval, - # which is about 5 seconds. If we go below it's minimum check - # threshold, it bumps it up to the minimum. - self.watcher = self.hub.loop.stat(self.temp_path, interval=-1) - - def tearDown(self): - self.watcher.close() - if os.path.exists(self.temp_path): - os.unlink(self.temp_path) - super(TestCoreStat, self).tearDown() - - def _write(self): - with open(self.temp_path, 'wb', buffering=0) as f: - f.write(b'x') - - def _check_attr(self, name, none): - # Deals with the complex behaviour of the 'attr' and 'prev' - # attributes on Windows. This codifies it, rather than simply letting - # the test fail, so we know exactly when and what changes it. - try: - x = getattr(self.watcher, name) - except ImportError: - if WIN: - # the 'posix' module is not available - pass - else: - raise - else: - if WIN and not LIBUV: - # The ImportError is only raised for the first time; - # after that, the attribute starts returning None - self.assertIsNone(x, "Only None is supported on Windows") - if none: - self.assertIsNone(x, name) - else: - self.assertIsNotNone(x, name) - - def _wait_on_greenlet(self, func, *greenlet_args): - start = time.time() - - self.hub.loop.update_now() - greenlet = gevent.spawn_later(DELAY, func, *greenlet_args) - with gevent.Timeout(5 + DELAY + 0.5): - self.hub.wait(self.watcher) - now = time.time() - - self.assertGreaterEqual(now, start, "Time must move forward") - - wait_duration = now - start - reaction = wait_duration - DELAY - - if reaction <= 0.0: - # Sigh. This is especially true on PyPy on Windows - raise gevent.testing.flaky.FlakyTestRaceCondition( - "Bad timer resolution (on Windows?), test is useless. Start %s, now %s" % (start, now)) - - self.assertGreaterEqual( - reaction, 0.0, - 'Watcher %s reacted too early: %.3fs' % (self.watcher, reaction)) - - greenlet.join() - - def test_watcher_basics(self): - watcher = self.watcher - filename = self.temp_path - self.assertEqual(watcher.path, filename) - filenames = filename if isinstance(filename, bytes) else filename.encode('ascii') - self.assertEqual(watcher._paths, filenames) - self.assertEqual(watcher.interval, -1) - - def test_write(self): - self._wait_on_greenlet(self._write) - - self._check_attr('attr', False) - self._check_attr('prev', False) - # The watcher interval changed after it started; -1 is illegal - self.assertNotEqual(self.watcher.interval, -1) - - def test_unlink(self): - self._wait_on_greenlet(os.unlink, self.temp_path) - - self._check_attr('attr', True) - self._check_attr('prev', False) - -if __name__ == '__main__': - greentest.main() diff --git a/venv/lib/python3.9/site-packages/gevent/tests/test__core_timer.py b/venv/lib/python3.9/site-packages/gevent/tests/test__core_timer.py deleted file mode 100644 index 97caa75..0000000 --- a/venv/lib/python3.9/site-packages/gevent/tests/test__core_timer.py +++ /dev/null @@ -1,157 +0,0 @@ -from __future__ import print_function -from gevent import config - -import gevent.testing as greentest -from gevent.testing import TestCase -from gevent.testing import LARGE_TIMEOUT -from gevent.testing.sysinfo import CFFI_BACKEND -from gevent.testing.flaky import reraises_flaky_timeout - - -class Test(TestCase): - __timeout__ = LARGE_TIMEOUT - - repeat = 0 - timer_duration = 0.001 - - def setUp(self): - super(Test, self).setUp() - self.called = [] - self.loop = config.loop(default=False) - self.timer = self.loop.timer(self.timer_duration, repeat=self.repeat) - assert not self.loop.default - - def cleanup(self): - # cleanup instead of tearDown to cooperate well with - # leakcheck.py - self.timer.close() - # cycle the loop so libuv close callbacks fire - self.loop.run() - self.loop.destroy() - self.loop = None - self.timer = None - - def f(self, x=None): - self.called.append(1) - if x is not None: - x.stop() - - def assertTimerInKeepalive(self): - if CFFI_BACKEND: - self.assertIn(self.timer, self.loop._keepaliveset) - - def assertTimerNotInKeepalive(self): - if CFFI_BACKEND: - self.assertNotIn(self.timer, self.loop._keepaliveset) - - def test_main(self): - loop = self.loop - x = self.timer - x.start(self.f) - self.assertTimerInKeepalive() - self.assertTrue(x.active, x) - - with self.assertRaises((AttributeError, ValueError)): - x.priority = 1 - - loop.run() - self.assertEqual(x.pending, 0) - self.assertEqual(self.called, [1]) - self.assertIsNone(x.callback) - self.assertIsNone(x.args) - - if x.priority is not None: - self.assertEqual(x.priority, 0) - x.priority = 1 - self.assertEqual(x.priority, 1) - - x.stop() - self.assertTimerNotInKeepalive() - -class TestAgain(Test): - repeat = 1 - - def test_main(self): - # Again works for a new timer - x = self.timer - x.again(self.f, x) - self.assertTimerInKeepalive() - - self.assertEqual(x.args, (x,)) - - # XXX: On libev, this takes 1 second. On libuv, - # it takes the expected time. - self.loop.run() - - self.assertEqual(self.called, [1]) - - x.stop() - self.assertTimerNotInKeepalive() - - -class TestTimerResolution(Test): - - # On CI, with *all* backends, sometimes we get timer values of - # 0.02 or higher. - @reraises_flaky_timeout(AssertionError) - def test_resolution(self): # pylint:disable=too-many-locals - # Make sure that having an active IO watcher - # doesn't badly throw off our timer resolution. - # (This was a specific problem with libuv) - - # https://github.com/gevent/gevent/pull/1194 - from gevent._compat import perf_counter - - import socket - s = socket.socket() - self._close_on_teardown(s) - fd = s.fileno() - - ran_at_least_once = False - fired_at = [] - - def timer_counter(): - fired_at.append(perf_counter()) - - loop = self.loop - - timer_multiplier = 11 - max_time = self.timer_duration * timer_multiplier - assert max_time < 0.3 - - for _ in range(150): - # in libuv, our signal timer fires every 300ms; depending on - # when this runs, we could artificially get a better - # resolution than we expect. Run it multiple times to be more sure. - io = loop.io(fd, 1) - io.start(lambda events=None: None) - - - now = perf_counter() - del fired_at[:] - timer = self.timer - timer.start(timer_counter) - - loop.run(once=True) - - io.stop() - io.close() - - timer.stop() - - if fired_at: - ran_at_least_once = True - self.assertEqual(1, len(fired_at)) - self.assertTimeWithinRange(fired_at[0] - now, - 0, - max_time) - - - if not greentest.RUNNING_ON_CI: - # Hmm, this always fires locally on mocOS but - # not an Travis? - self.assertTrue(ran_at_least_once) - - -if __name__ == '__main__': - greentest.main() diff --git a/venv/lib/python3.9/site-packages/gevent/tests/test__core_watcher.py b/venv/lib/python3.9/site-packages/gevent/tests/test__core_watcher.py deleted file mode 100644 index bd52805..0000000 --- a/venv/lib/python3.9/site-packages/gevent/tests/test__core_watcher.py +++ /dev/null @@ -1,124 +0,0 @@ -from __future__ import absolute_import, print_function - -import gevent.testing as greentest -from gevent import config -from gevent.testing.sysinfo import CFFI_BACKEND - -from gevent.core import READ # pylint:disable=no-name-in-module -from gevent.core import WRITE # pylint:disable=no-name-in-module - - -class Test(greentest.TestCase): - - __timeout__ = None - - def setUp(self): - super(Test, self).setUp() - self.loop = config.loop(default=False) - self.timer = self.loop.timer(0.01) - - def tearDown(self): - if self.timer is not None: - self.timer.close() - if self.loop is not None: - self.loop.destroy() - self.loop = self.timer = None - super(Test, self).tearDown() - - def test_non_callable_to_start(self): - # test that cannot pass non-callable thing to start() - self.assertRaises(TypeError, self.timer.start, None) - self.assertRaises(TypeError, self.timer.start, 5) - - def test_non_callable_after_start(self): - # test that cannot set 'callback' to non-callable thing later either - lst = [] - timer = self.timer - timer.start(lst.append) - - - with self.assertRaises(TypeError): - timer.callback = False - - with self.assertRaises(TypeError): - timer.callback = 5 - - def test_args_can_be_changed_after_start(self): - lst = [] - timer = self.timer - self.timer.start(lst.append) - self.assertEqual(timer.args, ()) - timer.args = (1, 2, 3) - self.assertEqual(timer.args, (1, 2, 3)) - - # Only tuple can be args - with self.assertRaises(TypeError): - timer.args = 5 - with self.assertRaises(TypeError): - timer.args = [4, 5] - - self.assertEqual(timer.args, (1, 2, 3)) - - # None also works, means empty tuple - # XXX why? - timer.args = None - self.assertEqual(timer.args, None) - - - def test_run(self): - loop = self.loop - lst = [] - - self.timer.start(lambda *args: lst.append(args)) - - loop.run() - loop.update_now() - - self.assertEqual(lst, [()]) - - # Even if we lose all references to it, the ref in the callback - # keeps it alive - self.timer.start(reset, self.timer, lst) - self.timer = None - loop.run() - self.assertEqual(lst, [(), 25]) - - def test_invalid_fd(self): - loop = self.loop - - # Negative case caught everywhere. ValueError - # on POSIX, OSError on Windows Py3, IOError on Windows Py2 - with self.assertRaises((ValueError, OSError, IOError)): - loop.io(-1, READ) - - - @greentest.skipOnWindows("Stdout can't be watched on Win32") - def test_reuse_io(self): - loop = self.loop - - # Watchers aren't reused once all outstanding - # refs go away BUT THEY MUST BE CLOSED - tty_watcher = loop.io(1, WRITE) - watcher_handle = tty_watcher._watcher if CFFI_BACKEND else tty_watcher - tty_watcher.close() - del tty_watcher - # XXX: Note there is a cycle in the CFFI code - # from watcher_handle._handle -> watcher_handle. - # So it doesn't go away until a GC runs. - import gc - gc.collect() - - tty_watcher = loop.io(1, WRITE) - self.assertIsNot(tty_watcher._watcher if CFFI_BACKEND else tty_watcher, watcher_handle) - tty_watcher.close() - - -def reset(watcher, lst): - watcher.args = None - watcher.callback = lambda: None - lst.append(25) - watcher.close() - - -if __name__ == '__main__': - greentest.main() diff --git a/venv/lib/python3.9/site-packages/gevent/tests/test__destroy.py b/venv/lib/python3.9/site-packages/gevent/tests/test__destroy.py deleted file mode 100644 index 0c37c4a..0000000 --- a/venv/lib/python3.9/site-packages/gevent/tests/test__destroy.py +++ /dev/null @@ -1,52 +0,0 @@ -from __future__ import absolute_import, print_function - -import gevent -import unittest - -class TestDestroyHub(unittest.TestCase): - - def test_destroy_hub(self): - # Loop of initial Hub is default loop. - hub = gevent.get_hub() - self.assertTrue(hub.loop.default) - - # Save `gevent.core.loop` object for later comparison. - initloop = hub.loop - - # Increase test complexity via threadpool creation. - # Implicitly creates fork watcher connected to the current event loop. - tp = hub.threadpool - self.assertIsNotNone(tp) - - # Destroy hub. Does not destroy libev default loop if not explicitly told to. - hub.destroy() - - # Create new hub. Must re-use existing libev default loop. - hub = gevent.get_hub() - self.assertTrue(hub.loop.default) - - # Ensure that loop object is identical to the initial one. - self.assertIs(hub.loop, initloop) - - # Destroy hub including default loop. - hub.destroy(destroy_loop=True) - - # Create new hub and explicitly request creation of a new default loop. - # (using default=True, but that's no longer possible.) - hub = gevent.get_hub() - self.assertTrue(hub.loop.default) - - # `gevent.core.loop` objects as well as libev loop pointers must differ. - self.assertIsNot(hub.loop, initloop) - self.assertIsNot(hub.loop.ptr, initloop.ptr) - self.assertNotEqual(hub.loop.ptr, initloop.ptr) - - # Destroy hub including default loop. The default loop regenerates. - hub.destroy(destroy_loop=True) - hub = gevent.get_hub() - self.assertTrue(hub.loop.default) - - hub.destroy() - -if __name__ == '__main__': - unittest.main() # pragma: testrunner-no-combine diff --git a/venv/lib/python3.9/site-packages/gevent/tests/test__destroy_default_loop.py b/venv/lib/python3.9/site-packages/gevent/tests/test__destroy_default_loop.py deleted file mode 100644 index 79bcd63..0000000 --- a/venv/lib/python3.9/site-packages/gevent/tests/test__destroy_default_loop.py +++ /dev/null @@ -1,72 +0,0 @@ -from __future__ import print_function -import gevent - -import unittest - -class TestDestroyDefaultLoop(unittest.TestCase): - - def tearDown(self): - self._reset_hub() - super(TestDestroyDefaultLoop, self).tearDown() - - def _reset_hub(self): - from gevent._hub_local import set_hub - from gevent._hub_local import set_loop - from gevent._hub_local import get_hub_if_exists - hub = get_hub_if_exists() - if hub is not None: - hub.destroy(destroy_loop=True) - set_hub(None) - set_loop(None) - - def test_destroy_gc(self): - # Issue 1098: destroying the default loop - # while using the C extension could crash - # the interpreter when it exits - - # Create the hub greenlet. This creates one loop - # object pointing to the default loop. - gevent.get_hub() - - # Get a new loop object, but using the default - # C loop - loop = gevent.config.loop(default=True) - self.assertTrue(loop.default) - # Destroy it - - loop.destroy() - # It no longer claims to be the default - self.assertFalse(loop.default) - - # Delete it - del loop - # Delete the hub. This prompts garbage - # collection of it and its loop object. - # (making this test more repeatable; the exit - # crash only happened when that greenlet object - # was collected at exit time, which was most common - # in CPython 3.5) - self._reset_hub() - - def test_destroy_two(self): - # Get two new loop object, but using the default - # C loop - loop1 = gevent.config.loop(default=True) - loop2 = gevent.config.loop(default=True) - self.assertTrue(loop1.default) - self.assertTrue(loop2.default) - # Destroy the first - loop1.destroy() - # It no longer claims to be the default - self.assertFalse(loop1.default) - - # Destroy the second. This doesn't crash. - loop2.destroy() - self.assertFalse(loop2.default) - self.assertFalse(loop2.ptr) - self._reset_hub() - self.assertTrue(gevent.get_hub().loop.ptr) - - -if __name__ == '__main__': - unittest.main() diff --git a/venv/lib/python3.9/site-packages/gevent/tests/test__doctests.py b/venv/lib/python3.9/site-packages/gevent/tests/test__doctests.py deleted file mode 100644 index 731a9ee..0000000 --- a/venv/lib/python3.9/site-packages/gevent/tests/test__doctests.py +++ /dev/null @@ -1,133 +0,0 @@ -from __future__ import print_function - -import doctest -import functools -import os -import re -import sys -import unittest - - - -# Ignore tracebacks: ZeroDivisionError - - -def myfunction(*_args, **_kwargs): - pass - - -class RENormalizingOutputChecker(doctest.OutputChecker): - """ - Pattern-normalizing output checker. Inspired by one used in zope.testing. - """ - - def __init__(self, patterns): - self.transformers = [functools.partial(re.sub, replacement) for re, replacement in patterns] - - def check_output(self, want, got, optionflags): - if got == want: - return True - - for transformer in self.transformers: - want = transformer(want) - got = transformer(got) - - return doctest.OutputChecker.check_output(self, want, got, optionflags) - -FORBIDDEN_MODULES = set() - - -class Modules(object): - - def __init__(self, allowed_modules): - from gevent.testing import walk_modules - self.allowed_modules = allowed_modules - self.modules = set() - - for path, module in walk_modules(recursive=True): - self.add_module(module, path) - - - def add_module(self, name, path): - if self.allowed_modules and name not in self.allowed_modules: - return - if name in FORBIDDEN_MODULES: - return - self.modules.add((name, path)) - - def __bool__(self): - return bool(self.modules) - - __nonzero__ = __bool__ - - def __iter__(self): - return iter(self.modules) - - -def main(): # pylint:disable=too-many-locals - cwd = os.getcwd() - # Use pure_python to get the correct module source and docstrings - os.environ['PURE_PYTHON'] = '1' - - import gevent - from gevent import socket - - - from gevent.testing import util - from gevent.testing import sysinfo - - if sysinfo.WIN: - FORBIDDEN_MODULES.update({ - # Uses commands only found on posix - 'gevent.subprocess', - }) - - try: - allowed_modules = sys.argv[1:] - sys.path.append('.') - - globs = { - 'myfunction': myfunction, - 'gevent': gevent, - 'socket': socket, - } - - modules = Modules(allowed_modules) - - if not modules: - sys.exit('No modules found matching %s' % ' '.join(allowed_modules)) - - suite = unittest.TestSuite() - checker = RENormalizingOutputChecker(( - # Normalize subprocess.py: BSD ls is in the example, gnu ls outputs - # 'cannot access' - (re.compile( - "ls: cannot access 'non_existent_file': No such file or directory"), - "ls: non_existent_file: No such file or directory"), - # Python 3 bytes add a "b". - (re.compile(r'b(".*?")'), r"\1"), - (re.compile(r"b('.*?')"), r"\1"), - )) - - tests_count = 0 - modules_count = 0 - for m, path in sorted(modules): - with open(path, 'rb') as f: - contents = f.read() - if re.search(br'^\s*>>> ', contents, re.M): - s = doctest.DocTestSuite(m, extraglobs=globs, checker=checker) - test_count = len(s._tests) - util.log('%s (from %s): %s tests', m, path, test_count) - suite.addTest(s) - modules_count += 1 - tests_count += test_count - - util.log('Total: %s tests in %s modules', tests_count, modules_count) - # TODO: Pass this off to unittest.main() - runner = unittest.TextTestRunner(verbosity=2) - runner.run(suite) - finally: - os.chdir(cwd) - -if __name__ == '__main__': - main() diff --git a/venv/lib/python3.9/site-packages/gevent/tests/test__environ.py b/venv/lib/python3.9/site-packages/gevent/tests/test__environ.py deleted file mode 100644 index 5fb9166..0000000 --- a/venv/lib/python3.9/site-packages/gevent/tests/test__environ.py +++ /dev/null @@ -1,19 +0,0 @@ -import os -import sys -import gevent -import gevent.core -import subprocess - -if not sys.argv[1:]: - os.environ['GEVENT_BACKEND'] = 'select' - # (not in Py2) pylint:disable=consider-using-with - popen = subprocess.Popen([sys.executable, __file__, '1']) - assert popen.wait() == 0, popen.poll() -else: # pragma: no cover - hub = gevent.get_hub() - # pylint:disable-next=no-member - if 'select' in gevent.core.supported_backends(): - assert hub.loop.backend == 'select', hub.loop.backend - else: - # libuv isn't configurable - assert hub.loop.backend == 'default', hub.loop.backend diff --git a/venv/lib/python3.9/site-packages/gevent/tests/test__event.py b/venv/lib/python3.9/site-packages/gevent/tests/test__event.py deleted file mode 100644 index b35c759..0000000 --- a/venv/lib/python3.9/site-packages/gevent/tests/test__event.py +++ /dev/null @@ -1,443 +0,0 @@ -import weakref - -import gevent -from gevent.event import Event, AsyncResult - -import gevent.testing as greentest - -from gevent.testing.timing import AbstractGenericGetTestCase -from gevent.testing.timing import AbstractGenericWaitTestCase -from gevent.testing.timing import SMALL_TICK -from gevent.testing.timing import SMALL_TICK_MAX_ADJ - -DELAY = SMALL_TICK + SMALL_TICK_MAX_ADJ - - -class TestEventWait(AbstractGenericWaitTestCase): - - def wait(self, timeout): - Event().wait(timeout=timeout) - - def test_cover(self): - str(Event()) - - -class TestGeventWaitOnEvent(AbstractGenericWaitTestCase): - - def wait(self, timeout): - gevent.wait([Event()], timeout=timeout) - - def test_set_during_wait(self): - # https://github.com/gevent/gevent/issues/771 - # broke in the refactoring. we must not add new links - # while we're running the callback - - event = Event() - - def setter(): - event.set() - - def waiter(): - s = gevent.spawn(setter) - # let the setter set() the event; - # when this method returns we'll be running in the Event._notify_links callback - # (that is, it switched to us) - res = event.wait() - self.assertTrue(res) - self.assertTrue(event.ready()) - s.join() # make sure it's dead - # Clear the event. Now we can't wait for the event without - # another set to happen. - event.clear() - self.assertFalse(event.ready()) - - # Before the bug fix, this would return "immediately" with - # event in the result list, because the _notify_links loop would - # immediately add the waiter and call it - o = gevent.wait((event,), timeout=0.01) - self.assertFalse(event.ready()) - self.assertNotIn(event, o) - - gevent.spawn(waiter).join() - - -class TestAsyncResultWait(AbstractGenericWaitTestCase): - - def wait(self, timeout): - AsyncResult().wait(timeout=timeout) - - -class TestWaitAsyncResult(AbstractGenericWaitTestCase): - - def wait(self, timeout): - gevent.wait([AsyncResult()], timeout=timeout) - - -class TestAsyncResultGet(AbstractGenericGetTestCase): - - def wait(self, timeout): - AsyncResult().get(timeout=timeout) - -class MyException(Exception): - pass - -class TestAsyncResult(greentest.TestCase): - - def test_link(self): - ar = AsyncResult() - self.assertRaises(TypeError, ar.rawlink, None) - ar.unlink(None) # doesn't raise - ar.unlink(None) # doesn't raise - str(ar) # cover - - def test_set_exc(self): - log = [] - e = AsyncResult() - self.assertEqual(e.exc_info, ()) - self.assertEqual(e.exception, None) - - def waiter(): - with self.assertRaises(MyException) as exc: - e.get() - log.append(('caught', exc.exception)) - gevent.spawn(waiter) - obj = MyException() - e.set_exception(obj) - gevent.sleep(0) - self.assertEqual(log, [('caught', obj)]) - - def test_set(self): - event1 = AsyncResult() - timer_exc = MyException('interrupted') - - # Notice that this test is racy: - # After DELAY, we set the event. We also try to immediately - # raise the exception with a timer of 0 --- but that depends - # on cycling the loop. Hence the fairly large value for DELAY. - g = gevent.spawn_later(DELAY, event1.set, 'hello event1') - self._close_on_teardown(g.kill) - with gevent.Timeout.start_new(0, timer_exc): - with self.assertRaises(MyException) as exc: - event1.get() - self.assertIs(timer_exc, exc.exception) - - def test_set_with_timeout(self): - event2 = AsyncResult() - - X = object() - result = gevent.with_timeout(DELAY, event2.get, timeout_value=X) - self.assertIs( - result, X, - 'Nobody sent anything to event2 yet it received %r' % (result, )) - - def test_nonblocking_get(self): - ar = AsyncResult() - self.assertRaises(gevent.Timeout, ar.get, block=False) - self.assertRaises(gevent.Timeout, ar.get_nowait) - -class TestAsyncResultCrossThread(greentest.TestCase): - - def _makeOne(self): - return AsyncResult() - - def _setOne(self, one): - one.set('from main') - - BG_WAIT_DELAY = 60 - - def _check_pypy_switch(self): - # On PyPy 7.3.3, switching to the main greenlet of a thread from a - # different thread silently does nothing. We can't detect the cross-thread - # switch, and so this test breaks - # https://foss.heptapod.net/pypy/pypy/-/issues/3381 - if greentest.PYPY: - import sys - if sys.pypy_version_info[:3] <= (7, 3, 3): # pylint:disable=no-member - self.skipTest("PyPy bug: https://foss.heptapod.net/pypy/pypy/-/issues/3381") - - @greentest.ignores_leakcheck - def test_cross_thread_use(self, timed_wait=False, wait_in_bg=False): - # Issue 1739. - # AsyncResult has *never* been thread safe, and using it from one - # thread to another is not safe. However, in some very careful use cases - # that can actually work. - # - # This test makes sure it doesn't hang in one careful use - # scenario. - self.assertNotMonkeyPatched() # Need real threads, event objects - from threading import Thread as NativeThread - from threading import Event as NativeEvent - - if not wait_in_bg: - self._check_pypy_switch() - - test = self - class Thread(NativeThread): - def __init__(self): - NativeThread.__init__(self) - self.daemon = True - self.running_event = NativeEvent() - self.finished_event = NativeEvent() - - self.async_result = test._makeOne() - self.result = '' - - def run(self): - # Give the loop in this thread something to do - g_event = Event() - def spin(): - while not g_event.is_set(): - g_event.wait(DELAY * 2) - glet = gevent.spawn(spin) - - def work(): - self.running_event.set() - # If we use a timed wait(), the bug doesn't manifest. - # This is probably because the loop wakes up to handle the timer, - # and notices the callback. - # See https://github.com/gevent/gevent/issues/1735 - if timed_wait: - self.result = self.async_result.wait(test.BG_WAIT_DELAY) - else: - self.result = self.async_result.wait() - - if wait_in_bg: - # This results in a separate code path - worker = gevent.spawn(work) - worker.join() - del worker - else: - work() - - g_event.set() - glet.join() - del glet - self.finished_event.set() - gevent.get_hub().destroy(destroy_loop=True) - - thread = Thread() - thread.start() - try: - thread.running_event.wait() - self._setOne(thread.async_result) - thread.finished_event.wait(DELAY * 5) - finally: - thread.join(DELAY * 15) - - self._check_result(thread.result) - - def _check_result(self, result): - self.assertEqual(result, 'from main') - - def test_cross_thread_use_bg(self): - self.test_cross_thread_use(timed_wait=False, wait_in_bg=True) - - def test_cross_thread_use_timed(self): - self.test_cross_thread_use(timed_wait=True, wait_in_bg=False) - - def test_cross_thread_use_timed_bg(self): - self.test_cross_thread_use(timed_wait=True, wait_in_bg=True) - - @greentest.ignores_leakcheck - def test_cross_thread_use_set_in_bg(self): - self.assertNotMonkeyPatched() # Need real threads, event objects - from threading import Thread as NativeThread - from threading import Event as NativeEvent - - self._check_pypy_switch() - test = self - class Thread(NativeThread): - def __init__(self): - NativeThread.__init__(self) - self.daemon = True - self.running_event = NativeEvent() - self.finished_event = NativeEvent() - - self.async_result = test._makeOne() - self.result = '' - - def run(self): - self.running_event.set() - test._setOne(self.async_result) - - self.finished_event.set() - gevent.get_hub().destroy(destroy_loop=True) - - thread = Thread() - glet = None - try: - glet = gevent.spawn(thread.start) - result = thread.async_result.wait(self.BG_WAIT_DELAY) - finally: - thread.join(DELAY * 15) - if glet is not None: - glet.join(DELAY) - self._check_result(result) - - @greentest.ignores_leakcheck - def test_cross_thread_use_set_in_bg2(self): - # Do it again to make sure it works multiple times. - self.test_cross_thread_use_set_in_bg() - -class TestEventCrossThread(TestAsyncResultCrossThread): - - def _makeOne(self): - return Event() - - def _setOne(self, one): - one.set() - - def _check_result(self, result): - self.assertTrue(result) - - -class TestAsyncResultAsLinkTarget(greentest.TestCase): - error_fatal = False - - def test_set(self): - g = gevent.spawn(lambda: 1) - s1, s2, s3 = AsyncResult(), AsyncResult(), AsyncResult() - g.link(s1) - g.link_value(s2) - g.link_exception(s3) - self.assertEqual(s1.get(), 1) - self.assertEqual(s2.get(), 1) - X = object() - result = gevent.with_timeout(DELAY, s3.get, timeout_value=X) - self.assertIs(result, X) - - def test_set_exception(self): - def func(): - raise greentest.ExpectedException('TestAsyncResultAsLinkTarget.test_set_exception') - g = gevent.spawn(func) - s1, s2, s3 = AsyncResult(), AsyncResult(), AsyncResult() - g.link(s1) - g.link_value(s2) - g.link_exception(s3) - self.assertRaises(greentest.ExpectedException, s1.get) - X = object() - result = gevent.with_timeout(DELAY, s2.get, timeout_value=X) - self.assertIs(result, X) - self.assertRaises(greentest.ExpectedException, s3.get) - - -class TestEvent_SetThenClear(greentest.TestCase): - N = 1 - - def test(self): - e = Event() - waiters = [gevent.spawn(e.wait) for i in range(self.N)] - gevent.sleep(0.001) - e.set() - e.clear() - for greenlet in waiters: - greenlet.join() - - -class TestEvent_SetThenClear100(TestEvent_SetThenClear): - N = 100 - - -class TestEvent_SetThenClear1000(TestEvent_SetThenClear): - N = 1000 - - -class TestWait(greentest.TestCase): - N = 5 - count = None - timeout = 1 - period = timeout / 100.0 - - def _sender(self, events, asyncs): - while events or asyncs: - gevent.sleep(self.period) - if events: - events.pop().set() - gevent.sleep(self.period) - if asyncs: - asyncs.pop().set() - - @greentest.skipOnAppVeyor("Not all results have arrived sometimes due to timer issues") - def test(self): - events = [Event() for _ in range(self.N)] - asyncs = [AsyncResult() for _ in range(self.N)] - max_len = len(events) + len(asyncs) - sender = gevent.spawn(self._sender, events, asyncs) - results = gevent.wait(events + asyncs, count=self.count, timeout=self.timeout) - if self.timeout is None: - expected_len = max_len - else: - expected_len = min(max_len, self.timeout / self.period) - if self.count is None: - self.assertTrue(sender.ready(), sender) - else: - expected_len = min(self.count, expected_len) - self.assertFalse(sender.ready(), sender) - sender.kill() - self.assertEqual(expected_len, len(results), (expected_len, len(results), results)) - - -class TestWait_notimeout(TestWait): - timeout = None - - -class TestWait_count1(TestWait): - count = 1 - - -class TestWait_count2(TestWait): - count = 2 - -class TestEventBasics(greentest.TestCase): - - def test_weakref(self): - # Event objects should allow weakrefs - e = Event() - r = weakref.ref(e) - self.assertIs(e, r()) - del e - del r - - def test_wait_while_notifying(self): - # If someone calls wait() on an Event that is - # ready, and notifying other waiters, that new - # waiter still runs at the end, but this does not - # require a trip around the event loop. - # See https://github.com/gevent/gevent/issues/1520 - event = Event() - results = [] - - def wait_then_append(arg): - event.wait() - results.append(arg) - - gevent.spawn(wait_then_append, 1) - gevent.spawn(wait_then_append, 2) - gevent.idle() - self.assertEqual(2, event.linkcount()) - check = gevent.get_hub().loop.check() - check.start(results.append, 4) - event.set() - wait_then_append(3) - self.assertEqual(results, [1, 2, 3]) - # Note that the check event DID NOT run. - check.stop() - check.close() - - def test_gevent_wait_twice_when_already_set(self): - event = Event() - event.set() - # First one works fine. - result = gevent.wait([event]) - self.assertEqual(result, [event]) - # Second one used to fail with an AssertionError, - # now it passes - result = gevent.wait([event]) - self.assertEqual(result, [event]) - - -del AbstractGenericGetTestCase -del AbstractGenericWaitTestCase - -if __name__ == '__main__': - greentest.main() diff --git a/venv/lib/python3.9/site-packages/gevent/tests/test__events.py b/venv/lib/python3.9/site-packages/gevent/tests/test__events.py deleted file mode 100644 index d5af423..0000000 --- a/venv/lib/python3.9/site-packages/gevent/tests/test__events.py +++ /dev/null @@ -1,50 +0,0 @@ -# -*- coding: utf-8 -*- -# Copyright 2018 gevent. See LICENSE. -from __future__ import absolute_import -from __future__ import division -from __future__ import print_function - - -import unittest - -from gevent import events - -try: - from zope.interface import verify -except ImportError: - verify = None - -try: - from zope import event -except ImportError: - event = None - - -@unittest.skipIf(verify is None, "Needs zope.interface") -class TestImplements(unittest.TestCase): - - def test_event_loop_blocked(self): - verify.verifyClass(events.IEventLoopBlocked, events.EventLoopBlocked) - - def test_mem_threshold(self): - verify.verifyClass(events.IMemoryUsageThresholdExceeded, - events.MemoryUsageThresholdExceeded) - verify.verifyObject(events.IMemoryUsageThresholdExceeded, - events.MemoryUsageThresholdExceeded(0, 0, 0)) - - def test_mem_decreased(self): - verify.verifyClass(events.IMemoryUsageUnderThreshold, - events.MemoryUsageUnderThreshold) - verify.verifyObject(events.IMemoryUsageUnderThreshold, - events.MemoryUsageUnderThreshold(0, 0, 0, 0)) - - -@unittest.skipIf(event is None, "Needs zope.event") -class TestEvents(unittest.TestCase): - - def test_is_zope(self): - self.assertIs(events.subscribers, event.subscribers) - self.assertIs(events.notify, event.notify) - -if __name__ == '__main__': - unittest.main() diff --git a/venv/lib/python3.9/site-packages/gevent/tests/test__example_echoserver.py b/venv/lib/python3.9/site-packages/gevent/tests/test__example_echoserver.py deleted file mode 100644 index 816851a..0000000 --- a/venv/lib/python3.9/site-packages/gevent/tests/test__example_echoserver.py +++ /dev/null @@ -1,36 +0,0 @@ -from gevent.socket import create_connection, timeout -import gevent.testing as greentest -import gevent - -from gevent.testing import util -from gevent.testing import params - -class Test(util.TestServer): - example = 'echoserver.py' - - def _run_all_tests(self): - def test_client(message): - kwargs = {'buffering': 1, 'mode': 'rb'} - conn = create_connection((params.DEFAULT_LOCAL_HOST_ADDR, 16000)) - conn.settimeout(greentest.DEFAULT_XPC_SOCKET_TIMEOUT) - rfile = conn.makefile(**kwargs) - - welcome = rfile.readline() - self.assertIn(b'Welcome', welcome) - - conn.sendall(message) - received = rfile.read(len(message)) - self.assertEqual(received, message) - - self.assertRaises(timeout, conn.recv, 1) - - rfile.close() - conn.close() - - client1 = gevent.spawn(test_client, b'hello\r\n') - client2 = gevent.spawn(test_client, b'world\r\n') - gevent.joinall([client1, client2], raise_error=True) - - -if __name__ == '__main__': - greentest.main() diff --git a/venv/lib/python3.9/site-packages/gevent/tests/test__example_portforwarder.py b/venv/lib/python3.9/site-packages/gevent/tests/test__example_portforwarder.py deleted file mode 100644 index 6910b3b..0000000 --- a/venv/lib/python3.9/site-packages/gevent/tests/test__example_portforwarder.py +++ /dev/null @@ -1,67 +0,0 @@ -from __future__ import print_function, absolute_import -from gevent import monkey; monkey.patch_all() -import signal - -import socket -from time import sleep - -import gevent -from gevent.server import StreamServer - -import gevent.testing as greentest -from gevent.testing import util - -@greentest.skipOnLibuvOnCIOnPyPy("Timing issues sometimes lead to connection refused") -class Test(util.TestServer): - example = 'portforwarder.py' - # [listen on, forward to] - example_args = ['127.0.0.1:10011', '127.0.0.1:10012'] - - if greentest.WIN: - from subprocess import CREATE_NEW_PROCESS_GROUP - # Must be in a new process group to use CTRL_C_EVENT, otherwise - # we get killed too - start_kwargs = {'creationflags': CREATE_NEW_PROCESS_GROUP} - - def after(self): - if greentest.WIN: - self.assertIsNotNone(self.popen.poll()) - else: - self.assertEqual(self.popen.poll(), 0) - - def _run_all_tests(self): - log = [] - - def handle(sock, _address): - while True: - data = sock.recv(1024) - print('got %r' % data) - if not data: - break - log.append(data) - - server = StreamServer(self.example_args[1], handle) - server.start() - try: - conn = socket.create_connection(('127.0.0.1', 10011)) - conn.sendall(b'msg1') - sleep(0.1) - # On Windows, SIGTERM actually abruptly terminates the process; - # it can't be caught. However, CTRL_C_EVENT results in a KeyboardInterrupt - # being raised, so we can shut down properly. - self.popen.send_signal(getattr(signal, 'CTRL_C_EVENT', signal.SIGTERM)) - sleep(0.1) - - conn.sendall(b'msg2') - conn.close() - - with gevent.Timeout(2.1): - self.popen.wait() - finally: - server.close() - - self.assertEqual([b'msg1', b'msg2'], log) - - -if __name__ == '__main__': - greentest.main() diff --git a/venv/lib/python3.9/site-packages/gevent/tests/test__example_udp_client.py b/venv/lib/python3.9/site-packages/gevent/tests/test__example_udp_client.py deleted file mode 100644 index ac27af1..0000000 --- a/venv/lib/python3.9/site-packages/gevent/tests/test__example_udp_client.py +++ /dev/null @@ -1,35 +0,0 @@ -from gevent import monkey -monkey.patch_all() - - -from gevent.server import DatagramServer - -from gevent.testing import util -from gevent.testing import main - -class Test_udp_client(util.TestServer): - - start_kwargs = {'timeout': 10} - example = 'udp_client.py' - example_args = ['Test_udp_client'] - - def test(self): - log = [] - - def handle(message, address): - log.append(message) - server.sendto(b'reply-from-server', address) - - server = DatagramServer('127.0.0.1:9001', handle) - server.start() - try: - self.run_example() - finally: - server.close() - self.assertEqual(log, [b'Test_udp_client']) - - -if __name__ == '__main__': - # Running this following test__example_portforwarder on Appveyor - # doesn't work in the same process for some reason. - main() # pragma: testrunner-no-combine diff --git a/venv/lib/python3.9/site-packages/gevent/tests/test__example_udp_server.py b/venv/lib/python3.9/site-packages/gevent/tests/test__example_udp_server.py deleted file mode 100644 index b1a6db0..0000000 --- a/venv/lib/python3.9/site-packages/gevent/tests/test__example_udp_server.py +++ /dev/null @@ -1,22 +0,0 @@ -import socket - -from gevent.testing import util -from gevent.testing import main - - -class Test(util.TestServer): - example = 'udp_server.py' - - def _run_all_tests(self): - sock = socket.socket(type=socket.SOCK_DGRAM) - try: - sock.connect(('127.0.0.1', 9000)) - sock.send(b'Test udp_server') - data, _address = sock.recvfrom(8192) - self.assertEqual(data, b'Received 15 bytes') - finally: - sock.close() - - -if __name__ == '__main__': - main() diff --git a/venv/lib/python3.9/site-packages/gevent/tests/test__example_webproxy.py b/venv/lib/python3.9/site-packages/gevent/tests/test__example_webproxy.py deleted file mode 100644 index 6f9ae63..0000000 --- a/venv/lib/python3.9/site-packages/gevent/tests/test__example_webproxy.py +++ /dev/null @@ -1,29 +0,0 @@ -from unittest import SkipTest - - -import gevent.testing as greentest - -from . import test__example_wsgiserver - - -@greentest.skipOnCI("Timing issues sometimes lead to a connection refused") -@greentest.skipWithoutExternalNetwork("Tries to reach google.com") -class Test_webproxy(test__example_wsgiserver.Test_wsgiserver): - example = 'webproxy.py' - - def _run_all_tests(self): - status, data = self.read('/') - self.assertEqual(status, '200 OK') - self.assertIn(b"gevent example", data) - status, data = self.read('/http://www.google.com') - self.assertEqual(status, '200 OK') - self.assertIn(b'google', data.lower()) - - def test_a_blocking_client(self): - # Not applicable - raise SkipTest("Not applicable") - - - -if __name__ == '__main__': - greentest.main() diff --git a/venv/lib/python3.9/site-packages/gevent/tests/test__example_wsgiserver.py b/venv/lib/python3.9/site-packages/gevent/tests/test__example_wsgiserver.py deleted file mode 100644 index 367ec40..0000000 --- a/venv/lib/python3.9/site-packages/gevent/tests/test__example_wsgiserver.py +++ /dev/null @@ -1,94 +0,0 @@ -import sys - -try: - from urllib import request as urllib2 -except ImportError: - import urllib2 - - -import socket -import ssl - -import gevent.testing as greentest -from gevent.testing import DEFAULT_XPC_SOCKET_TIMEOUT -from gevent.testing import util -from gevent.testing import params - -@greentest.skipOnCI("Timing issues sometimes lead to a connection refused") -class Test_wsgiserver(util.TestServer): - example = 'wsgiserver.py' - URL = 'http://%s:8088' % (params.DEFAULT_LOCAL_HOST_ADDR,) - PORT = 8088 - not_found_message = b'

    Not Found

    ' - ssl_ctx = None - _use_ssl = False - - def read(self, path='/'): - url = self.URL + path - try: - kwargs = {} - if self.ssl_ctx is not None: - kwargs = {'context': self.ssl_ctx} - - response = urllib2.urlopen(url, None, - DEFAULT_XPC_SOCKET_TIMEOUT, - **kwargs) - except urllib2.HTTPError: - response = sys.exc_info()[1] - result = '%s %s' % (response.code, response.msg), response.read() - # XXX: It looks like under PyPy this isn't directly closing the socket - # when SSL is in use. It takes a GC cycle to make that true. - response.close() - return result - - def _test_hello(self): - status, data = self.read('/') - self.assertEqual(status, '200 OK') - self.assertEqual(data, b"hello world") - - def _test_not_found(self): - status, data = self.read('/xxx') - self.assertEqual(status, '404 Not Found') - self.assertEqual(data, self.not_found_message) - - def _do_test_a_blocking_client(self): - # We spawn this in a separate server because if it's broken - # the whole server hangs - with self.running_server(): - # First, make sure we can talk to it. - self._test_hello() - # Now create a connection and only partway finish - # the transaction - sock = socket.create_connection((params.DEFAULT_LOCAL_HOST_ADDR, self.PORT)) - ssl_sock = None - if self._use_ssl: - context = ssl.SSLContext() - ssl_sock = context.wrap_socket(sock) - sock_file = ssl_sock.makefile(mode='rwb') - else: - sock_file = sock.makefile(mode='rwb') - # write an incomplete request - sock_file.write(b'GET /xxx HTTP/1.0\r\n') - sock_file.flush() - # Leave it open and not doing anything - # while the other request runs to completion. - # This demonstrates that a blocking client - # doesn't hang the whole server - self._test_hello() - - # now finish the original request - sock_file.write(b'\r\n') - sock_file.flush() - line = sock_file.readline() - self.assertEqual(line, b'HTTP/1.1 404 Not Found\r\n') - - sock_file.close() - if ssl_sock is not None: - ssl_sock.close() - sock.close() - - def test_a_blocking_client(self): - self._do_test_a_blocking_client() - -if __name__ == '__main__': - greentest.main() diff --git a/venv/lib/python3.9/site-packages/gevent/tests/test__example_wsgiserver_ssl.py b/venv/lib/python3.9/site-packages/gevent/tests/test__example_wsgiserver_ssl.py deleted file mode 100644 index c2bdec3..0000000 --- a/venv/lib/python3.9/site-packages/gevent/tests/test__example_wsgiserver_ssl.py +++ /dev/null @@ -1,24 +0,0 @@ -import ssl - -import gevent.testing as greentest - -from gevent.testing import params - -from . import test__example_wsgiserver - - -@greentest.skipOnCI("Timing issues sometimes lead to a connection refused") -class Test_wsgiserver_ssl(test__example_wsgiserver.Test_wsgiserver): - example = 'wsgiserver_ssl.py' - URL = 'https://%s:8443' % (params.DEFAULT_LOCAL_HOST_ADDR,) - PORT = 8443 - _use_ssl = True - - if hasattr(ssl, '_create_unverified_context'): - # Disable verification for our self-signed cert - # on Python >= 2.7.9 and 3.4 - ssl_ctx = ssl._create_unverified_context() - - -if __name__ == '__main__': - greentest.main() diff --git a/venv/lib/python3.9/site-packages/gevent/tests/test__examples.py b/venv/lib/python3.9/site-packages/gevent/tests/test__examples.py deleted file mode 100644 index e428349..0000000 --- a/venv/lib/python3.9/site-packages/gevent/tests/test__examples.py +++ /dev/null @@ -1,109 +0,0 @@ -""" -Test the contents of the ``examples/`` directory. - -If an existing test in *this* directory named ``test__example_.py`` exists, -where ```` is the base filename of an example file, it will not be tested -here. - -Examples can specify that they need particular test resources to be enabled -by commenting (one per line) ``# gevent-test-requires-resource: ``; -most commonly the resource will be ``network``. You can use this technique to specify -non-existant resources for things that should never be tested. -""" -import re -import os -import glob -import time -import unittest - -import gevent.testing as greentest -from gevent.testing import util - -this_dir = os.path.dirname(__file__) - -def _find_files_to_ignore(): - old_dir = os.getcwd() - try: - os.chdir(this_dir) - - result = [x[14:] for x in glob.glob('test__example_*.py')] - if greentest.PYPY and greentest.RUNNING_ON_APPVEYOR: - # For some reason on Windows with PyPy, this times out, - # when it should be very fast. - result.append("processes.py") - finally: - os.chdir(old_dir) - - return result - -default_time_range = (2, 10) -time_ranges = { # what is this even supposed to mean? pylint:disable=consider-using-namedtuple-or-dataclass - 'concurrent_download.py': (0, 30), - 'processes.py': (0, default_time_range[-1]) -} - -class _AbstractTestMixin(util.ExampleMixin): - time_range = default_time_range - example = None - - def _check_resources(self): - from gevent.testing import resources - - # pylint:disable=unspecified-encoding - with open(os.path.join(self.cwd, self.example), 'r') as f: - contents = f.read() - - pattern = re.compile('^# gevent-test-requires-resource: (.*)$', re.MULTILINE) - resources_needed = re.finditer(pattern, contents) - for match in resources_needed: - needed = contents[match.start(1):match.end(1)] - resources.skip_without_resource(needed) - - def test_runs(self): - self._check_resources() - - start = time.time() - min_time, max_time = self.time_range - self.start_kwargs = { - 'timeout': max_time, - 'quiet': True, - 'buffer_output': True, - 'nested': True, - 'setenv': {'GEVENT_DEBUG': 'error'} - } - if not self.run_example(): - self.fail("Failed example: " + self.example) - else: - took = time.time() - start - self.assertGreaterEqual(took, min_time) - -def _build_test_classes(): - result = {} - try: - example_dir = util.ExampleMixin().cwd - except unittest.SkipTest: - util.log("WARNING: No examples dir found", color='suboptimal-behaviour') - return result - - ignore = _find_files_to_ignore() - for filename in glob.glob(example_dir + '/*.py'): - bn = os.path.basename(filename) - if bn in ignore: - continue - - tc = type( - 'Test_' + bn, - (_AbstractTestMixin, greentest.TestCase), - { - 'example': bn, - 'time_range': time_ranges.get(bn, _AbstractTestMixin.time_range) - } - ) - result[tc.__name__] = tc - return result - -for k, v in _build_test_classes().items(): - locals()[k] = v - -if __name__ == '__main__': - greentest.main() diff --git a/venv/lib/python3.9/site-packages/gevent/tests/test__exc_info.py b/venv/lib/python3.9/site-packages/gevent/tests/test__exc_info.py deleted file mode 100644 index c8ea52e..0000000 --- a/venv/lib/python3.9/site-packages/gevent/tests/test__exc_info.py +++ /dev/null @@ -1,54 +0,0 @@ -import gevent -import sys -import gevent.testing as greentest -from gevent.testing import ExpectedException as ExpectedError - -class RawException(Exception): - pass - - -def hello(err): - assert sys.exc_info() == (None, None, None), sys.exc_info() - raise err - - -def hello2(): - try: - hello(ExpectedError('expected exception in hello')) - except ExpectedError: - pass - - -class Test(greentest.TestCase): - - def test1(self): - error = RawException('hello') - expected_error = ExpectedError('expected exception in hello') - try: - raise error - except RawException: - self.expect_one_error() - g = gevent.spawn(hello, expected_error) - g.join() - self.assert_error(ExpectedError, expected_error) - self.assertIsInstance(g.exception, ExpectedError) - - try: - raise - except: # pylint:disable=bare-except - ex = sys.exc_info()[1] - self.assertIs(ex, error) - - def test2(self): - timer = gevent.get_hub().loop.timer(0) - timer.start(hello2) - try: - gevent.sleep(0.1) - self.assertEqual(sys.exc_info(), (None, None, None)) - finally: - timer.close() - - - -if __name__ == '__main__': - greentest.main() diff --git a/venv/lib/python3.9/site-packages/gevent/tests/test__execmodules.py b/venv/lib/python3.9/site-packages/gevent/tests/test__execmodules.py deleted file mode 100644 index 394b4da..0000000 --- a/venv/lib/python3.9/site-packages/gevent/tests/test__execmodules.py +++ /dev/null @@ -1,54 +0,0 @@ -import unittest -import warnings - -from gevent.testing import modules -from gevent.testing import main -from gevent.testing.sysinfo import NON_APPLICABLE_SUFFIXES - -import pathlib - -def make_exec_test(path, module): - path = pathlib.Path(path) - - def test(_): - - with open(path, 'rb') as f: - src = f.read() - with warnings.catch_warnings(): - warnings.simplefilter('ignore', DeprecationWarning) - globs = {'__file__': path, '__name__': module} - if path.name == '__init__.py': - globs['__path__'] = [path] - globs['__package__'] = module - elif '.' in module: - globs['__package__'] = module.rsplit('.', 1)[0] - try: - exec(src, globs) - except ImportError: - if module in modules.OPTIONAL_MODULES: - raise unittest.SkipTest("Unable to import optional module %s" % module) - raise - - name = "test_" + module.replace(".", "_") - test.__name__ = name - return test - -def make_all_tests(cls): - for path, module in modules.walk_modules(recursive=True, check_optional=False): - if module.endswith(NON_APPLICABLE_SUFFIXES): - continue - test = make_exec_test(path, module) - setattr(cls, test.__name__, test) - return cls - - -@make_all_tests -class Test(unittest.TestCase): - pass - - -if __name__ == '__main__': - # This should not be combined with other tests in the same process - # because it messes with global shared state. - # pragma: testrunner-no-combine - main() diff --git a/venv/lib/python3.9/site-packages/gevent/tests/test__fileobject.py b/venv/lib/python3.9/site-packages/gevent/tests/test__fileobject.py deleted file mode 100644 index 606e915..0000000 --- a/venv/lib/python3.9/site-packages/gevent/tests/test__fileobject.py +++ /dev/null @@ -1,575 +0,0 @@ -from __future__ import print_function -from __future__ import absolute_import - -import functools -import gc -import io -import os -import sys -import tempfile -import unittest - -import gevent -from gevent import fileobject -from gevent._fileobjectcommon import OpenDescriptor -try: - from gevent._fileobjectposix import GreenOpenDescriptor -except ImportError: - GreenOpenDescriptor = None - - -import gevent.testing as greentest -from gevent.testing import sysinfo - - -# pylint:disable=unspecified-encoding - -def Writer(fobj, line): - for character in line: - fobj.write(character) - fobj.flush() - fobj.close() - - -def close_fd_quietly(fd): - try: - os.close(fd) - except OSError: - pass - -def skipUnlessWorksWithRegularFiles(func): - @functools.wraps(func) - def f(self): - if not self.WORKS_WITH_REGULAR_FILES: - self.skipTest("Doesn't work with regular files") - func(self) - return f - - -class CleanupMixin(object): - def _mkstemp(self, suffix): - fileno, path = tempfile.mkstemp(suffix) - self.addCleanup(os.remove, path) - self.addCleanup(close_fd_quietly, fileno) - return fileno, path - - def _pipe(self): - r, w = os.pipe() - self.addCleanup(close_fd_quietly, r) - self.addCleanup(close_fd_quietly, w) - return r, w - - -class TestFileObjectBlock(CleanupMixin, - greentest.TestCase): - # serves as a base for the concurrent tests too - - WORKS_WITH_REGULAR_FILES = True - - def setUp(self): - super().setUp() - # Try our best to run any pending __del__ methods. When we run - # multiple tests in sequence, because file descriptor numbers get - # reused, a test could open new FDs with the same numbers as some - # object (FileObjectPosix/GreenFileDescriptorIO) still waiting for - # __del__ to get called to close the FD. If GC runs and - # __del__ gets called while that second test is running, we - # get unexpected errors. - # This shows up on PyPy 3.11. - gc.collect() - - def _getTargetClass(self): - return fileobject.FileObjectBlock - - def _makeOne(self, *args, **kwargs): - return self._getTargetClass()(*args, **kwargs) - - def _test_del(self, **kwargs): - r, w = self._pipe() - self._do_test_del((r, w), **kwargs) - - def _do_test_del(self, pipe, **kwargs): - read_fd, write_fd = pipe - writer = self._makeOne(write_fd, 'wb', **kwargs) - writer.write(b'x') - try: - writer.flush() - except IOError: - # Sometimes seen on Windows/AppVeyor - print("Failed flushing fileobject", repr(writer), file=sys.stderr) - import traceback - traceback.print_exc() - - import warnings - with warnings.catch_warnings(): - warnings.simplefilter('ignore', ResourceWarning) - # Deliberately getting ResourceWarning with FileObject(Thread) under Py3 - del writer - # PyPy, run RawIO.__del__ to close FD. - gc.collect() - - if kwargs.get("close", True): - with self.assertRaises((OSError, IOError)): - # expected, because FileObject already closed it - os.close(write_fd) - else: - os.close(write_fd) - - with self._makeOne(read_fd, 'rb') as fobj: - self.assertEqual(fobj.read(), b'x') - - def test_del(self): - # Close should be true by default - self._test_del() - - def test_del_close(self): - self._test_del(close=True) - - - @skipUnlessWorksWithRegularFiles - def test_seek(self): - fileno, path = self._mkstemp('.gevent.test__fileobject.test_seek') - - s = b'a' * 1024 - os.write(fileno, b'B' * 15) - os.write(fileno, s) - os.close(fileno) - - with open(path, 'rb') as f: - f.seek(15) - native_data = f.read(1024) - - with open(path, 'rb') as f_raw: - f = self._makeOne(f_raw, 'rb', close=False) - # On Python 3, all objects should have seekable. - # On Python 2, only our custom objects do. - self.assertTrue(f.seekable()) - f.seek(15) - self.assertEqual(15, f.tell()) - - # Note that a duplicate close() of the underlying - # file descriptor can look like an OSError from this line - # as we exit the with block - fileobj_data = f.read(1024) - - self.assertEqual(native_data, s) - self.assertEqual(native_data, fileobj_data) - - def __check_native_matches(self, byte_data, open_mode, - meth='read', open_path=True, - **open_kwargs): - fileno, path = self._mkstemp('.gevent_test_' + open_mode) - - os.write(fileno, byte_data) - os.close(fileno) - - with io.open(path, open_mode, **open_kwargs) as f: - native_data = getattr(f, meth)() - - if open_path: - with self._makeOne(path, open_mode, **open_kwargs) as f: - gevent_data = getattr(f, meth)() - else: - # Note that we don't use ``io.open()`` for the raw file, - # on Python 2. We want 'r' to mean what the usual call to open() means. - opener = io.open - with opener(path, open_mode, **open_kwargs) as raw: - with self._makeOne(raw) as f: - gevent_data = getattr(f, meth)() - - self.assertEqual(native_data, gevent_data) - return gevent_data - - @skipUnlessWorksWithRegularFiles - def test_str_default_to_native(self): - # With no 'b' or 't' given, read and write native str. - gevent_data = self.__check_native_matches(b'abcdefg', 'r') - self.assertIsInstance(gevent_data, str) - - @skipUnlessWorksWithRegularFiles - def test_text_encoding(self): - gevent_data = self.__check_native_matches( - u'\N{SNOWMAN}'.encode('utf-8'), - 'r+', - buffering=5, encoding='utf-8' - ) - self.assertIsInstance(gevent_data, str) - - @skipUnlessWorksWithRegularFiles - def test_does_not_leak_on_exception(self): - # If an exception occurs during opening, - # everything still gets cleaned up. - pass - - @skipUnlessWorksWithRegularFiles - def test_rbU_produces_bytes_readline(self): - if sys.version_info > (3, 11): - self.skipTest("U file mode was removed in 3.11") - # Including U in rb still produces bytes. - # Note that the universal newline behaviour is - # essentially ignored in explicit bytes mode. - gevent_data = self.__check_native_matches( - b'line1\nline2\r\nline3\rlastline\n\n', - 'rbU', - meth='readlines', - ) - self.assertIsInstance(gevent_data[0], bytes) - self.assertEqual(len(gevent_data), 4) - - @skipUnlessWorksWithRegularFiles - def test_rU_produces_native(self): - if sys.version_info > (3, 11): - self.skipTest("U file mode was removed in 3.11") - gevent_data = self.__check_native_matches( - b'line1\nline2\r\nline3\rlastline\n\n', - 'rU', - meth='readlines', - ) - self.assertIsInstance(gevent_data[0], str) - - @skipUnlessWorksWithRegularFiles - def test_r_readline_produces_native(self): - gevent_data = self.__check_native_matches( - b'line1\n', - 'r', - meth='readline', - ) - self.assertIsInstance(gevent_data, str) - - @skipUnlessWorksWithRegularFiles - def test_r_readline_on_fobject_produces_native(self): - gevent_data = self.__check_native_matches( - b'line1\n', - 'r', - meth='readline', - open_path=False, - ) - self.assertIsInstance(gevent_data, str) - - def test_close_pipe(self): - # Issue #190, 203 - r, w = os.pipe() - x = self._makeOne(r) - y = self._makeOne(w, 'w') - x.close() - y.close() - - @skipUnlessWorksWithRegularFiles - @greentest.ignores_leakcheck - def test_name_after_close(self): - fileno, path = self._mkstemp('.gevent_test_named_path_after_close') - - # Passing the fileno; the name is the same as the fileno, and - # doesn't change when closed. - f = self._makeOne(fileno) - nf = os.fdopen(fileno) - # On Python 2, os.fdopen() produces a name of ; - # we follow the Python 3 semantics everywhere. - nf_name = fileno - self.assertEqual(f.name, fileno) - self.assertEqual(nf.name, nf_name) - - # A file-like object that has no name; we'll close the - # `f` after this because we reuse the fileno, which - # gets passed to fcntl and so must still be valid - class Nameless(object): - def fileno(self): - return fileno - close = flush = isatty = closed = writable = lambda self: False - seekable = readable = lambda self: True - - nameless = self._makeOne(Nameless(), 'rb') - with self.assertRaises(AttributeError): - getattr(nameless, 'name') - nameless.close() - with self.assertRaises(AttributeError): - getattr(nameless, 'name') - - f.close() - try: - nf.close() - except OSError: - # OSError: Py3, IOError: Py2 - pass - self.assertEqual(f.name, fileno) - self.assertEqual(nf.name, nf_name) - - def check(arg): - f = self._makeOne(arg) - self.assertEqual(f.name, path) - f.close() - # Doesn't change after closed. - self.assertEqual(f.name, path) - - # Passing the string - check(path) - - # Passing an opened native object - with open(path) as nf: - check(nf) - - # An io object - with io.open(path) as nf: - check(nf) - - @skipUnlessWorksWithRegularFiles - def test_readinto_serial(self): - fileno, path = self._mkstemp('.gevent_test_readinto') - os.write(fileno, b'hello world') - os.close(fileno) - - buf = bytearray(32) - mbuf = memoryview(buf) - - def assertReadInto(byte_count, expected_data): - bytes_read = f.readinto(mbuf[:byte_count]) - self.assertEqual(bytes_read, len(expected_data)) - self.assertEqual(buf[:bytes_read], expected_data) - - with self._makeOne(path, 'rb') as f: - assertReadInto(2, b'he') - assertReadInto(1, b'l') - assertReadInto(32, b'lo world') - assertReadInto(32, b'') - - -class ConcurrentFileObjectMixin(object): - # Additional tests for fileobjects that cooperate - # and we have full control of the implementation - - def test_read1_binary_present(self): - # Issue #840 - r, w = self._pipe() - reader = self._makeOne(r, 'rb') - self._close_on_teardown(reader) - writer = self._makeOne(w, 'w') - self._close_on_teardown(writer) - self.assertTrue(hasattr(reader, 'read1'), dir(reader)) - - def test_read1_text_not_present(self): - # Only defined for binary. - r, w = self._pipe() - reader = self._makeOne(r, 'rt') - self._close_on_teardown(reader) - self.addCleanup(os.close, w) - self.assertFalse(hasattr(reader, 'read1'), dir(reader)) - - def test_read1_default(self): - # If just 'r' is given, whether it has one or not - # depends on if we're Python 2 or 3. - r, w = self._pipe() - self.addCleanup(os.close, w) - reader = self._makeOne(r) - self._close_on_teardown(reader) - self.assertFalse(hasattr(reader, 'read1')) - - def test_bufsize_0(self): - # Issue #840 - r, w = self._pipe() - x = self._makeOne(r, 'rb', bufsize=0) - y = self._makeOne(w, 'wb', bufsize=0) - self._close_on_teardown(x) - self._close_on_teardown(y) - y.write(b'a') - b = x.read(1) - self.assertEqual(b, b'a') - - y.writelines([b'2']) - b = x.read(1) - self.assertEqual(b, b'2') - - def test_newlines(self): - import warnings - r, w = self._pipe() - lines = [b'line1\n', b'line2\r', b'line3\r\n', b'line4\r\nline5', b'\nline6'] - g = gevent.spawn(Writer, self._makeOne(w, 'wb'), lines) - - try: - with warnings.catch_warnings(): - if sys.version_info > (3, 11): - # U is removed in Python 3.11 - mode = 'r' - self.skipTest("U file mode was removed in 3.11") - else: - # U is deprecated in Python 3, shows up on FileObjectThread - warnings.simplefilter('ignore', DeprecationWarning) - mode = 'rU' - fobj = self._makeOne(r, mode) - result = fobj.read() - fobj.close() - self.assertEqual('line1\nline2\nline3\nline4\nline5\nline6', result) - finally: - g.kill() - - def test_readinto(self): - # verify that .readinto() is cooperative. - # if .readinto() is not cooperative spawned greenlet will not be able - # to run and call to .readinto() will block forever. - r, w = self._pipe() - rf = self._close_on_teardown(self._makeOne(r, 'rb')) - wf = self._close_on_teardown(self._makeOne(w, 'wb')) - g = gevent.spawn(Writer, wf, [b'hello']) - - try: - buf1 = bytearray(32) - buf2 = bytearray(32) - - n1 = rf.readinto(buf1) - n2 = rf.readinto(buf2) - - self.assertEqual(n1, 5) - self.assertEqual(buf1[:n1], b'hello') - self.assertEqual(n2, 0) - finally: - g.kill() - - -class TestFileObjectThread(ConcurrentFileObjectMixin, # pylint:disable=too-many-ancestors - TestFileObjectBlock): - - def _getTargetClass(self): - return fileobject.FileObjectThread - - def test_del_noclose(self): - # In the past, we used os.fdopen() when given a file descriptor, - # and that has a destructor that can't be bypassed, so - # close=false wasn't allowed. Now that we do everything with the - # io module, it is allowed. - self._test_del(close=False) - - # We don't test this with FileObjectThread. Sometimes the - # visibility of the 'close' operation, which happens in a - # background thread, doesn't make it to the foreground - # thread in a timely fashion, leading to 'os.close(4) must - # not succeed' in test_del_close. We have the same thing - # with flushing and closing in test_newlines. Both of - # these are most commonly (only?) observed on Py27/64-bit. - # They also appear on 64-bit 3.6 with libuv - - def test_del(self): - raise unittest.SkipTest("Race conditions") - - def test_del_close(self): - raise unittest.SkipTest("Race conditions") - - -@unittest.skipUnless( - hasattr(fileobject, 'FileObjectPosix'), - "Needs FileObjectPosix" -) -class TestFileObjectPosix(ConcurrentFileObjectMixin, # pylint:disable=too-many-ancestors - TestFileObjectBlock): - - if sysinfo.LIBUV and sysinfo.LINUX: - # On Linux, initializing the watcher for a regular - # file results in libuv raising EPERM. But that works - # fine on other platforms. - WORKS_WITH_REGULAR_FILES = False - - def _getTargetClass(self): - return fileobject.FileObjectPosix - - def test_seek_raises_ioerror(self): - # https://github.com/gevent/gevent/issues/1323 - - # Get a non-seekable file descriptor - r, _w = self._pipe() - - with self.assertRaises(OSError) as ctx: - os.lseek(r, 0, os.SEEK_SET) - os_ex = ctx.exception - - with self.assertRaises(IOError) as ctx: - f = self._makeOne(r, 'r', close=False) - # Seek directly using the underlying GreenFileDescriptorIO; - # the buffer may do different things, depending - # on the version of Python (especially 3.7+) - f.fileio.seek(0) - io_ex = ctx.exception - - self.assertEqual(io_ex.errno, os_ex.errno) - self.assertEqual(io_ex.strerror, os_ex.strerror) - self.assertEqual(io_ex.args, os_ex.args) - self.assertEqual(str(io_ex), str(os_ex)) - -class TestTextMode(CleanupMixin, unittest.TestCase): - - def test_default_mode_writes_linesep(self): - # See https://github.com/gevent/gevent/issues/1282 - # libuv 1.x interferes with the default line mode on - # Windows. - # First, make sure we initialize gevent - gevent.get_hub() - - fileno, path = self._mkstemp('.gevent.test__fileobject.test_default') - os.close(fileno) - - with open(path, "w") as f: - f.write("\n") - - with open(path, "rb") as f: - data = f.read() - - self.assertEqual(data, os.linesep.encode('ascii')) - -class TestOpenDescriptor(CleanupMixin, greentest.TestCase): - - def _getTargetClass(self): - return OpenDescriptor - - def _makeOne(self, *args, **kwargs): - return self._getTargetClass()(*args, **kwargs) - - def _check(self, regex, kind, *args, **kwargs): - with self.assertRaisesRegex(kind, regex): - self._makeOne(*args, **kwargs) - - case = lambda re, **kwargs: (re, TypeError, kwargs) - vase = lambda re, **kwargs: (re, ValueError, kwargs) - CASES = ( - case('mode', mode=42), - case('buffering', buffering='nope'), - case('encoding', encoding=42), - case('errors', errors=42), - vase('mode', mode='aoeug'), - vase('mode U cannot be combined', mode='wU'), - vase('text and binary', mode='rtb'), - vase('append mode at once', mode='rw'), - vase('exactly one', mode='+'), - vase('take an encoding', mode='rb', encoding='ascii'), - vase('take an errors', mode='rb', errors='strict'), - vase('take a newline', mode='rb', newline='\n'), - ) - - def test_atomicwrite_fd(self): - from gevent._fileobjectcommon import WriteallMixin - # It basically only does something when buffering is otherwise disabled - fileno, _w = self._pipe() - desc = self._makeOne(fileno, 'wb', - buffering=0, - closefd=False, - atomic_write=True) - self.assertTrue(desc.atomic_write) - - fobj = desc.opened() - self.assertIsInstance(fobj, WriteallMixin) - os.close(fileno) - -def pop(): - for regex, kind, kwargs in TestOpenDescriptor.CASES: - setattr( - TestOpenDescriptor, 'test_' + regex.replace(' ', '_'), - lambda self, _re=regex, _kind=kind, _kw=kwargs: self._check(_re, _kind, 1, **_kw) - ) -pop() - -@unittest.skipIf(GreenOpenDescriptor is None, "No support for non-blocking IO") -class TestGreenOpenDescripton(TestOpenDescriptor): - def _getTargetClass(self): - return GreenOpenDescriptor - - - - -if __name__ == '__main__': - greentest.main() diff --git a/venv/lib/python3.9/site-packages/gevent/tests/test__getaddrinfo_import.py b/venv/lib/python3.9/site-packages/gevent/tests/test__getaddrinfo_import.py deleted file mode 100644 index 182501c..0000000 --- a/venv/lib/python3.9/site-packages/gevent/tests/test__getaddrinfo_import.py +++ /dev/null @@ -1,11 +0,0 @@ -# On Python 2, a deadlock is possible if we import a module that runs gevent's getaddrinfo -# with a unicode hostname, which starts Python's getaddrinfo on a thread, which -# attempts to import encodings.idna but blocks on the import lock. Verify -# that gevent avoids this deadlock. - -try: - import getaddrinfo_module # pylint:disable=import-error -except ModuleNotFoundError: - from gevent.tests import getaddrinfo_module - -del getaddrinfo_module # fix pyflakes diff --git a/venv/lib/python3.9/site-packages/gevent/tests/test__greenio.py b/venv/lib/python3.9/site-packages/gevent/tests/test__greenio.py deleted file mode 100644 index f89123a..0000000 --- a/venv/lib/python3.9/site-packages/gevent/tests/test__greenio.py +++ /dev/null @@ -1,146 +0,0 @@ -# Copyright (c) 2006-2007, Linden Research, Inc. -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. -import sys - -import gevent -from gevent import socket - -from gevent import testing as greentest -from gevent.testing import TestCase, tcp_listener -from gevent.testing import gc_collect_if_needed -from gevent.testing import skipOnPyPy -from gevent.testing import params - - -PY3 = sys.version_info[0] >= 3 - - -def _write_to_closed(f, s): - try: - r = f.write(s) - except ValueError: - assert PY3 - else: - assert r is None, r - - -class TestGreenIo(TestCase): - - def test_close_with_makefile(self): - - def accept_close_early(listener): - # verify that the makefile and the socket are truly independent - # by closing the socket prior to using the made file - try: - conn, _ = listener.accept() - fd = conn.makefile(mode='wb') - conn.close() - fd.write(b'hello\n') - fd.close() - _write_to_closed(fd, b'a') - self.assertRaises(socket.error, conn.send, b'b') - finally: - listener.close() - - def accept_close_late(listener): - # verify that the makefile and the socket are truly independent - # by closing the made file and then sending a character - try: - conn, _ = listener.accept() - fd = conn.makefile(mode='wb') - fd.write(b'hello') - fd.close() - conn.send(b'\n') - conn.close() - _write_to_closed(fd, b'a') - self.assertRaises(socket.error, conn.send, b'b') - finally: - listener.close() - - def did_it_work(server): - client = socket.create_connection((params.DEFAULT_CONNECT, server.getsockname()[1])) - fd = client.makefile(mode='rb') - client.close() - self.assertEqual(fd.readline(), b'hello\n') - self.assertFalse(fd.read()) - fd.close() - - server = tcp_listener() - server_greenlet = gevent.spawn(accept_close_early, server) - did_it_work(server) - server_greenlet.kill() - - server = tcp_listener() - server_greenlet = gevent.spawn(accept_close_late, server) - did_it_work(server) - server_greenlet.kill() - - @skipOnPyPy("Takes multiple GCs and issues a warning we can't catch") - def test_del_closes_socket(self): - import warnings - def accept_once(listener): - # delete/overwrite the original conn - # object, only keeping the file object around - # closing the file object should close everything - - # This is not *exactly* true on Python 3. This produces - # a ResourceWarning, which we silence below. (Previously we actually - # *saved* a reference to the socket object, so we - # weren't testing what we thought we were.) - - # It's definitely not true on PyPy, which needs GC to - # reliably close everything; sometimes this is more than - # one collection cycle. And PyPy issues a warning with -X - # track-resources that we cannot catch. - with warnings.catch_warnings(): - warnings.simplefilter('ignore') - - try: - conn = listener.accept()[0] - # Note that we overwrite the original variable, - # losing our reference to the socket. - conn = conn.makefile(mode='wb') - conn.write(b'hello\n') - conn.close() - _write_to_closed(conn, b'a') - finally: - listener.close() - del listener - del conn - gc_collect_if_needed() - gc_collect_if_needed() - - server = tcp_listener() - gevent.spawn(accept_once, server) - client = socket.create_connection((params.DEFAULT_CONNECT, server.getsockname()[1])) - with gevent.Timeout.start_new(0.5): - fd = client.makefile() - client.close() - self.assertEqual(fd.read(), 'hello\n') - # If the socket isn't closed when 'accept_once' finished, - # then this will hang and exceed the timeout - self.assertEqual(fd.read(), '') - - fd.close() - del client - del fd - - -if __name__ == '__main__': - greentest.main() diff --git a/venv/lib/python3.9/site-packages/gevent/tests/test__greenlet.py b/venv/lib/python3.9/site-packages/gevent/tests/test__greenlet.py deleted file mode 100644 index 8cb6f83..0000000 --- a/venv/lib/python3.9/site-packages/gevent/tests/test__greenlet.py +++ /dev/null @@ -1,1078 +0,0 @@ -# Copyright (c) 2008-2009 AG Projects -# Author: Denis Bilenko -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. -import functools -import unittest -from unittest.mock import patch as Patch - -import gevent.testing as greentest -import gevent - -from gevent import sleep, with_timeout, getcurrent -from gevent import greenlet -from gevent.event import AsyncResult -from gevent.queue import Queue, Channel - -from gevent.testing.timing import AbstractGenericWaitTestCase -from gevent.testing.timing import AbstractGenericGetTestCase -from gevent.testing import timing -from gevent.testing import ignores_leakcheck - -DELAY = timing.SMALL_TICK -greentest.TestCase.error_fatal = False - - -class ExpectedError(greentest.ExpectedException): - pass - -class ExpectedJoinError(ExpectedError): - pass - -class SuiteExpectedException(ExpectedError): - pass - -class GreenletRaisesJoin(gevent.Greenlet): - killed = False - joined = False - raise_on_join = True - - def join(self, timeout=None): - self.joined += 1 - if self.raise_on_join: - raise ExpectedJoinError - return gevent.Greenlet.join(self, timeout) - - def kill(self, *args, **kwargs): # pylint:disable=signature-differs - self.killed += 1 - return gevent.Greenlet.kill(self, *args, **kwargs) - -class TestLink(greentest.TestCase): - - def test_link_to_asyncresult(self): - p = gevent.spawn(lambda: 100) - event = AsyncResult() - p.link(event) - self.assertEqual(event.get(), 100) - - for _ in range(3): - event2 = AsyncResult() - p.link(event2) - self.assertEqual(event2.get(), 100) - - def test_link_to_asyncresult_exception(self): - err = ExpectedError('test_link_to_asyncresult_exception') - p = gevent.spawn(lambda: getcurrent().throw(err)) - event = AsyncResult() - p.link(event) - with self.assertRaises(ExpectedError) as exc: - event.get() - - self.assertIs(exc.exception, err) - - for _ in range(3): - event2 = AsyncResult() - p.link(event2) - with self.assertRaises(ExpectedError) as exc: - event2.get() - self.assertIs(exc.exception, err) - - def test_link_to_queue(self): - p = gevent.spawn(lambda: 100) - q = Queue() - p.link(q.put) - self.assertEqual(q.get().get(), 100) - - for _ in range(3): - p.link(q.put) - self.assertEqual(q.get().get(), 100) - - def test_link_to_channel(self): - p1 = gevent.spawn(lambda: 101) - p2 = gevent.spawn(lambda: 102) - p3 = gevent.spawn(lambda: 103) - q = Channel() - p1.link(q.put) - p2.link(q.put) - p3.link(q.put) - results = [q.get().get(), q.get().get(), q.get().get()] - self.assertEqual(sorted(results), [101, 102, 103], results) - - -class TestUnlink(greentest.TestCase): - switch_expected = False - - def _test_func(self, p, link): - link(dummy_test_func) - self.assertEqual(1, p.has_links()) - - p.unlink(dummy_test_func) - self.assertEqual(0, p.has_links()) - - link(self.setUp) - self.assertEqual(1, p.has_links()) - - p.unlink(self.setUp) - self.assertEqual(0, p.has_links()) - - p.kill() - - def test_func_link(self): - p = gevent.spawn(dummy_test_func) - self._test_func(p, p.link) - - def test_func_link_value(self): - p = gevent.spawn(dummy_test_func) - self._test_func(p, p.link_value) - - def test_func_link_exception(self): - p = gevent.spawn(dummy_test_func) - self._test_func(p, p.link_exception) - - -class LinksTestCase(greentest.TestCase): - - link_method = None - - def link(self, p, listener=None): - getattr(p, self.link_method)(listener) - - def set_links(self, p): - event = AsyncResult() - self.link(p, event) - - queue = Queue(1) - self.link(p, queue.put) - - callback_flag = ['initial'] - self.link(p, lambda *args: callback_flag.remove('initial')) - - for _ in range(10): - self.link(p, AsyncResult()) - self.link(p, Queue(1).put) - - return event, queue, callback_flag - - def set_links_timeout(self, link): - # stuff that won't be touched - event = AsyncResult() - link(event) - - queue = Channel() - link(queue.put) - return event, queue - - def check_timed_out(self, event, queue): - got = with_timeout(DELAY, event.get, timeout_value=X) - self.assertIs(got, X) - got = with_timeout(DELAY, queue.get, timeout_value=X) - self.assertIs(got, X) - - -def return25(): - return 25 - - - -class TestReturn_link(LinksTestCase): - link_method = 'link' - - p = None - - def cleanup(self): - self.p.unlink_all() - self.p = None - - def test_return(self): - self.p = gevent.spawn(return25) - for _ in range(3): - self._test_return(self.p, 25) - self.p.kill() - - def _test_return(self, p, result): - event, queue, callback_flag = self.set_links(p) - - # stuff that will time out because there's no unhandled exception: - xxxxx = self.set_links_timeout(p.link_exception) - - sleep(DELAY * 2) - self.assertFalse(p) - - self.assertEqual(event.get(), result) - self.assertEqual(queue.get().get(), result) - - sleep(DELAY) - self.assertFalse(callback_flag) - - self.check_timed_out(*xxxxx) - - def _test_kill(self, p): - event, queue, callback_flag = self.set_links(p) - xxxxx = self.set_links_timeout(p.link_exception) - - p.kill() - sleep(DELAY) - self.assertFalse(p) - - - self.assertIsInstance(event.get(), gevent.GreenletExit) - self.assertIsInstance(queue.get().get(), gevent.GreenletExit) - - sleep(DELAY) - self.assertFalse(callback_flag) - - self.check_timed_out(*xxxxx) - - def test_kill(self): - p = self.p = gevent.spawn(sleep, DELAY) - for _ in range(3): - self._test_kill(p) - - -class TestReturn_link_value(TestReturn_link): - link_method = 'link_value' - - -class TestRaise_link(LinksTestCase): - link_method = 'link' - - def _test_raise(self, p): - event, queue, callback_flag = self.set_links(p) - xxxxx = self.set_links_timeout(p.link_value) - - sleep(DELAY) - self.assertFalse(p, p) - - self.assertRaises(ExpectedError, event.get) - self.assertEqual(queue.get(), p) - sleep(DELAY) - self.assertFalse(callback_flag, callback_flag) - - self.check_timed_out(*xxxxx) - - def test_raise(self): - p = gevent.spawn(lambda: getcurrent().throw(ExpectedError('test_raise'))) - for _ in range(3): - self._test_raise(p) - - -class TestRaise_link_exception(TestRaise_link): - link_method = 'link_exception' - - -class TestStuff(greentest.TestCase): - - def test_minimal_id(self): - g = gevent.spawn(lambda: 1) - self.assertGreaterEqual(g.minimal_ident, 0) - self.assertGreaterEqual(g.parent.minimal_ident, 0) - g.join() # don't leave dangling, breaks the leak checks - - def test_wait_noerrors(self): - x = gevent.spawn(lambda: 1) - y = gevent.spawn(lambda: 2) - z = gevent.spawn(lambda: 3) - gevent.joinall([x, y, z], raise_error=True) - self.assertEqual([x.value, y.value, z.value], [1, 2, 3]) - e = AsyncResult() - x.link(e) - self.assertEqual(e.get(), 1) - x.unlink(e) - e = AsyncResult() - x.link(e) - self.assertEqual(e.get(), 1) - - @ignores_leakcheck - def test_wait_error(self): - - def x(): - sleep(DELAY) - return 1 - x = gevent.spawn(x) - y = gevent.spawn(lambda: getcurrent().throw(ExpectedError('test_wait_error'))) - self.assertRaises(ExpectedError, gevent.joinall, [x, y], raise_error=True) - self.assertRaises(ExpectedError, gevent.joinall, [y], raise_error=True) - x.join() - - @ignores_leakcheck - def test_joinall_exception_order(self): - # if there're several exceptions raised, the earliest one must be raised by joinall - def first(): - sleep(0.1) - raise ExpectedError('first') - a = gevent.spawn(first) - b = gevent.spawn(lambda: getcurrent().throw(ExpectedError('second'))) - with self.assertRaisesRegex(ExpectedError, 'second'): - gevent.joinall([a, b], raise_error=True) - - gevent.joinall([a, b]) - - def test_joinall_count_raise_error(self): - # When joinall is asked not to raise an error, the 'count' param still - # works. - def raises_but_ignored(): - raise ExpectedError("count") - - def sleep_forever(): - while True: - sleep(0.1) - - sleeper = gevent.spawn(sleep_forever) - raiser = gevent.spawn(raises_but_ignored) - - gevent.joinall([sleeper, raiser], raise_error=False, count=1) - self.assert_greenlet_ready(raiser) - self.assert_greenlet_not_ready(sleeper) - - # Clean up our mess - sleeper.kill() - self.assert_greenlet_ready(sleeper) - - def test_multiple_listeners_error(self): - # if there was an error while calling a callback - # it should not prevent the other listeners from being called - # also, all of the errors should be logged, check the output - # manually that they are - p = gevent.spawn(lambda: 5) - results = [] - - def listener1(*_args): - results.append(10) - raise ExpectedError('listener1') - - def listener2(*_args): - results.append(20) - raise ExpectedError('listener2') - - def listener3(*_args): - raise ExpectedError('listener3') - - p.link(listener1) - p.link(listener2) - p.link(listener3) - sleep(DELAY * 10) - self.assertIn(results, [[10, 20], [20, 10]]) - - p = gevent.spawn(lambda: getcurrent().throw(ExpectedError('test_multiple_listeners_error'))) - results = [] - p.link(listener1) - p.link(listener2) - p.link(listener3) - sleep(DELAY * 10) - self.assertIn(results, [[10, 20], [20, 10]]) - - class Results(object): - - def __init__(self): - self.results = [] - - def listener1(self, p): - p.unlink(self.listener2) - self.results.append(5) - raise ExpectedError('listener1') - - def listener2(self, p): - p.unlink(self.listener1) - self.results.append(5) - raise ExpectedError('listener2') - - def listener3(self, _p): - raise ExpectedError('listener3') - - def _test_multiple_listeners_error_unlink(self, _p, link): - # notification must not happen after unlink even - # though notification process has been already started - results = self.Results() - - link(results.listener1) - link(results.listener2) - link(results.listener3) - sleep(DELAY * 10) - self.assertEqual([5], results.results) - - - def test_multiple_listeners_error_unlink_Greenlet_link(self): - p = gevent.spawn(lambda: 5) - self._test_multiple_listeners_error_unlink(p, p.link) - p.kill() - - def test_multiple_listeners_error_unlink_Greenlet_rawlink(self): - p = gevent.spawn(lambda: 5) - self._test_multiple_listeners_error_unlink(p, p.rawlink) - - def test_multiple_listeners_error_unlink_AsyncResult_rawlink(self): - e = AsyncResult() - gevent.spawn(e.set, 6) - self._test_multiple_listeners_error_unlink(e, e.rawlink) - - -def dummy_test_func(*_args): - pass - - -class A(object): - - def method(self): - pass - -class Subclass(gevent.Greenlet): - pass - -class TestStr(greentest.TestCase): - - def test_function(self): - g = gevent.Greenlet.spawn(dummy_test_func) - self.assert_nstr_endswith(g, 'at X: dummy_test_func>') - self.assert_greenlet_not_ready(g) - g.join() - self.assert_greenlet_ready(g) - self.assert_nstr_endswith(g, 'at X: dummy_test_func>') - - - def test_method(self): - g = gevent.Greenlet.spawn(A().method) - self.assert_nstr_startswith(g, '>>') - self.assert_greenlet_not_ready(g) - g.join() - self.assert_greenlet_ready(g) - self.assert_nstr_endswith(g, 'at X: >>') - - def test_subclass(self): - g = Subclass() - self.assert_nstr_startswith(g, '') - - g = Subclass(None, 'question', answer=42) - self.assert_nstr_endswith(g, " at X: _run('question', answer=42)>") - - -class TestJoin(AbstractGenericWaitTestCase): - - def wait(self, timeout): - g = gevent.spawn(gevent.sleep, 10) - try: - return g.join(timeout=timeout) - finally: - g.kill() - - -class TestGet(AbstractGenericGetTestCase): - - def wait(self, timeout): - g = gevent.spawn(gevent.sleep, 10) - try: - return g.get(timeout=timeout) - finally: - g.kill() - - -class TestJoinAll0(AbstractGenericWaitTestCase): - - g = gevent.Greenlet() - - def wait(self, timeout): - gevent.joinall([self.g], timeout=timeout) - - -class TestJoinAll(AbstractGenericWaitTestCase): - - def wait(self, timeout): - g = gevent.spawn(gevent.sleep, 10) - try: - gevent.joinall([g], timeout=timeout) - finally: - g.kill() - - -class TestBasic(greentest.TestCase): - - def test_spawn_non_callable(self): - self.assertRaises(TypeError, gevent.spawn, 1) - self.assertRaises(TypeError, gevent.spawn_raw, 1) - - # Not passing the run argument, just the seconds argument - self.assertRaises(TypeError, gevent.spawn_later, 1) - # Passing both, but not implemented - self.assertRaises(TypeError, gevent.spawn_later, 1, 1) - - def test_spawn_raw_kwargs(self): - value = [] - - def f(*args, **kwargs): - value.append(args) - value.append(kwargs) - - g = gevent.spawn_raw(f, 1, name='value') - gevent.sleep(0.01) - self.assertFalse(g) - self.assertEqual(value[0], (1,)) - self.assertEqual(value[1], {'name': 'value'}) - - def test_simple_exit(self): - link_test = [] - - def func(delay, return_value=4): - gevent.sleep(delay) - return return_value - - g = gevent.Greenlet(func, 0.01, return_value=5) - g.rawlink(link_test.append) # use rawlink to avoid timing issues on Appveyor/Travis (not always successful) - self.assertFalse(g, g) - self.assertFalse(g.dead, g) - self.assertFalse(g.started, g) - self.assertFalse(g.ready(), g) - self.assertFalse(g.successful(), g) - self.assertIsNone(g.value, g) - self.assertIsNone(g.exception, g) - - g.start() - self.assertTrue(g, g) # changed - self.assertFalse(g.dead, g) - self.assertTrue(g.started, g) # changed - self.assertFalse(g.ready(), g) - self.assertFalse(g.successful(), g) - self.assertIsNone(g.value, g) - self.assertIsNone(g.exception, g) - - gevent.sleep(0.001) - self.assertTrue(g) - self.assertFalse(g.dead, g) - self.assertTrue(g.started, g) - self.assertFalse(g.ready(), g) - self.assertFalse(g.successful(), g) - self.assertIsNone(g.value, g) - self.assertIsNone(g.exception, g) - self.assertFalse(link_test) - - gevent.sleep(0.02) - self.assertFalse(g, g) # changed - self.assertTrue(g.dead, g) # changed - self.assertFalse(g.started, g) # changed - self.assertTrue(g.ready(), g) # changed - self.assertTrue(g.successful(), g) # changed - self.assertEqual(g.value, 5) # changed - self.assertIsNone(g.exception, g) - - self._check_flaky_eq(link_test, g) - - def _check_flaky_eq(self, link_test, g): - if not greentest.RUNNING_ON_CI: - # TODO: Change this to assertEqualFlakyRaceCondition and figure - # out what the CI issue is. - self.assertEqual(link_test, [g]) # changed - - def test_error_exit(self): - link_test = [] - - def func(delay, return_value=4): - gevent.sleep(delay) - error = ExpectedError('test_error_exit') - setattr(error, 'myattr', return_value) - raise error - - g = gevent.Greenlet(func, timing.SMALLEST_RELIABLE_DELAY, return_value=5) - # use rawlink to avoid timing issues on Appveyor (not always successful) - g.rawlink(link_test.append) - g.start() - gevent.sleep() - gevent.sleep(timing.LARGE_TICK) - self.assertFalse(g) - self.assertTrue(g.dead) - self.assertFalse(g.started) - self.assertTrue(g.ready()) - self.assertFalse(g.successful()) - self.assertIsNone(g.value) # not changed - self.assertEqual(g.exception.myattr, 5) - self._check_flaky_eq(link_test, g) - - def test_exc_info_no_error(self): - # Before running - self.assertFalse(greenlet.Greenlet().exc_info) - g = greenlet.Greenlet(gevent.sleep) - g.start() - g.join() - self.assertFalse(g.exc_info) - - @greentest.skipOnCI( - "Started getting a Fatal Python error on " - "Github Actions on 2020-12-18, even with recursion limits " - "in place. It was fine before that." - ) - def test_recursion_error(self): - # https://github.com/gevent/gevent/issues/1704 - # A RuntimeError: recursion depth exceeded - # does not break things. - # - # However, sometimes, on some interpreter versions on some - # systems, actually exhausting the stack results in "Fatal - # Python error: Cannot recover from stack overflow.". So we - # need to use a low recursion limit so that doesn't happen. - # Doesn't seem to help though. - # See https://github.com/gevent/gevent/runs/1577692901?check_suite_focus=true#step:21:46 - import sys - limit = sys.getrecursionlimit() - self.addCleanup(sys.setrecursionlimit, limit) - sys.setrecursionlimit(limit // 4) - def recur(): - recur() # This is expected to raise RecursionError - - errors = [] - def handle_error(glet, t, v, tb): - errors.append((glet, t, v, tb)) - - try: - gevent.get_hub().handle_error = handle_error - - g = gevent.spawn(recur) - def wait(): - return gevent.joinall([g]) - - g2 = gevent.spawn(wait) - - gevent.joinall([g2]) - finally: - del gevent.get_hub().handle_error - - try: - expected_exc = RecursionError - except NameError: - expected_exc = RuntimeError - with self.assertRaises(expected_exc): - g.get() - - self.assertFalse(g.successful()) - self.assertTrue(g.dead) - - self.assertTrue(errors) - self.assertEqual(1, len(errors)) - self.assertIs(errors[0][0], g) - self.assertEqual(errors[0][1], expected_exc) - del errors[:] - - - def test_tree_locals(self): - g = g2 = None - def func(): - child = greenlet.Greenlet() - self.assertIs(child.spawn_tree_locals, getcurrent().spawn_tree_locals) - self.assertIs(child.spawning_greenlet(), getcurrent()) - g = greenlet.Greenlet(func) - g2 = greenlet.Greenlet(func) - # Creating those greenlets did not give the main greenlet - # a locals dict. - self.assertFalse(hasattr(getcurrent(), 'spawn_tree_locals'), - getcurrent()) - self.assertIsNot(g.spawn_tree_locals, g2.spawn_tree_locals) - g.start() - g.join() - - raw = gevent.spawn_raw(func) - self.assertIsNotNone(raw.spawn_tree_locals) - self.assertIsNot(raw.spawn_tree_locals, g.spawn_tree_locals) - self.assertIs(raw.spawning_greenlet(), getcurrent()) - while not raw.dead: - gevent.sleep(0.01) - - def test_add_spawn_callback(self): - called = {'#': 0} - - def cb(gr): - called['#'] += 1 - gr._called_test = True - - gevent.Greenlet.add_spawn_callback(cb) - try: - g = gevent.spawn(lambda: None) - self.assertTrue(hasattr(g, '_called_test')) - g.join() - self.assertEqual(called['#'], 1) - - g = gevent.spawn_later(1e-5, lambda: None) - self.assertTrue(hasattr(g, '_called_test')) - g.join() - self.assertEqual(called['#'], 2) - - g = gevent.Greenlet(lambda: None) - g.start() - self.assertTrue(hasattr(g, '_called_test')) - g.join() - self.assertEqual(called['#'], 3) - - gevent.Greenlet.remove_spawn_callback(cb) - g = gevent.spawn(lambda: None) - self.assertFalse(hasattr(g, '_called_test')) - g.join() - self.assertEqual(called['#'], 3) - finally: - gevent.Greenlet.remove_spawn_callback(cb) - - def test_getframe_value_error(self): - def get(): - raise ValueError("call stack is not deep enough") - try: - ogf = greenlet.sys_getframe - except AttributeError: # pragma: no cover - # Must be running cython compiled - raise unittest.SkipTest("Cannot mock when Cython compiled") - greenlet.sys_getframe = get - try: - child = greenlet.Greenlet() - self.assertIsNone(child.spawning_stack) - finally: - greenlet.sys_getframe = ogf - - def test_minimal_ident_parent_not_hub(self): - - g = gevent.spawn(lambda: 1) - self.assertIs(g.parent, gevent.get_hub()) - g.parent = getcurrent() - try: - self.assertIsNot(g.parent, gevent.get_hub()) - - with self.assertRaisesRegex((TypeError, # Cython - AttributeError), # PyPy - 'Cannot convert|ident_registry'): - getattr(g, 'minimal_ident') - finally: - # Attempting to switch into this later, when we next cycle the - # loop, would raise an InvalidSwitchError if we don't put - # things back the way they were (or kill the greenlet) - g.parent = gevent.get_hub() - g.kill() - - -class TestKill(greentest.TestCase): - - def setUp(self): - super().setUp() - hub = gevent.get_hub() - patcher = Patch.object(hub, 'print_exception', autospec=True) - patcher.start() - self.addCleanup(patcher.stop) - - - def __assertKilled(self, g, successful): - self.assertFalse(g) - self.assertTrue(g.dead) - self.assertFalse(g.started) - self.assertTrue(g.ready()) - if successful: - self.assertTrue(g.successful(), (repr(g), g.value, g.exception)) - self.assertIsInstance(g.value, gevent.GreenletExit) - self.assertIsNone(g.exception) - else: - self.assertFalse(g.successful(), (repr(g), g.value, g.exception)) - self.assertNotIsInstance(g.value, gevent.GreenletExit) - self.assertIsNotNone(g.exception) - - def assertKilled(self, g, successful=True): - self.__assertKilled(g, successful) - gevent.sleep(0.01) # spin the loop to make sure it doesn't run. - self.__assertKilled(g, successful) - - def __kill_greenlet(self, g, block, killall, exc=None): - if exc is None: - exc = gevent.GreenletExit - if killall: - killer = functools.partial(gevent.killall, [g], - exception=exc, block=block) - else: - killer = functools.partial(g.kill, exception=exc, block=block) - killer() - if not block: - # Must spin the loop to take effect (if it was scheduled) - gevent.sleep(timing.SMALLEST_RELIABLE_DELAY) - - successful = exc is None or (isinstance(exc, type) and issubclass(exc, gevent.GreenletExit)) - self.assertKilled(g, successful) - # kill second time must not hurt - killer() - self.assertKilled(g, successful) - - @staticmethod - def _run_in_greenlet(result_collector): - result_collector.append(1) - - def _start_greenlet(self, g): - """ - Subclasses should override. This doesn't actually start a greenlet. - """ - - _after_kill_greenlet = _start_greenlet - - - def _do_test(self, block, killall, exc=None): - link_test = [] - result = [] - g = gevent.Greenlet(self._run_in_greenlet, result) - g.link(link_test.append) - - self._start_greenlet(g) - - self.__kill_greenlet(g, block, killall, exc) - - self._after_kill_greenlet(g) - - self.assertFalse(result) - self.assertEqual(link_test, [g]) - - def test_block(self): - self._do_test(block=True, killall=False) - - def test_non_block(self): - self._do_test(block=False, killall=False) - - def test_block_killall(self): - self._do_test(block=True, killall=True) - - def test_non_block_killal(self): - self._do_test(block=False, killall=True) - - def test_non_type_exception(self): - self._do_test(block=True, killall=False, exc=Exception()) - - def test_non_type_exception_non_block(self): - self._do_test(block=False, killall=False, exc=Exception()) - - def test_non_type_exception_killall(self): - self._do_test(block=True, killall=True, exc=Exception()) - - def test_non_type_exception_killall_non_block(self): - self._do_test(block=False, killall=True, exc=Exception()) - - def test_non_exc_exception(self): - self._do_test(block=True, killall=False, exc=42) - - def test_non_exc_exception_non_block(self): - self._do_test(block=False, killall=False, exc=42) - - def test_non_exc_exception_killall(self): - self._do_test(block=True, killall=True, exc=42) - - def test_non_exc_exception_killall_non_block(self): - self._do_test(block=False, killall=True, exc=42) - - -class TestKillAfterStart(TestKill): - - def _start_greenlet(self, g): - g.start() - -class TestKillAfterStartLater(TestKill): - - def _start_greenlet(self, g): - g.start_later(timing.LARGE_TICK) - -class TestKillWhileRunning(TestKill): - - @staticmethod - def _run_in_greenlet(result_collector): - gevent.sleep(10) - # The above should die with the GreenletExit exception, - # so this should never run - TestKill._run_in_greenlet(result_collector) - - def _after_kill_greenlet(self, g): - TestKill._after_kill_greenlet(self, g) - gevent.sleep(0.01) - -class TestKillallRawGreenlet(greentest.TestCase): - - def test_killall_raw(self): - g = gevent.spawn_raw(lambda: 1) - gevent.killall([g]) - - -class TestContextManager(greentest.TestCase): - - def test_simple(self): - with gevent.spawn(gevent.sleep, timing.SMALL_TICK) as g: - self.assert_greenlet_spawned(g) - # It is completed after the suite - self.assert_greenlet_finished(g) - - def test_wait_in_suite(self): - with gevent.spawn(self._raise_exception) as g: - with self.assertRaises(greentest.ExpectedException): - g.get() - self.assert_greenlet_finished(g) - - @staticmethod - def _raise_exception(): - raise greentest.ExpectedException - - def test_greenlet_raises(self): - with gevent.spawn(self._raise_exception) as g: - pass - - self.assert_greenlet_finished(g) - with self.assertRaises(greentest.ExpectedException): - g.get() - - def test_join_raises(self): - suite_ran = 0 - with self.assertRaises(ExpectedJoinError): - with GreenletRaisesJoin.spawn(gevent.sleep, timing.SMALL_TICK) as g: - self.assert_greenlet_spawned(g) - suite_ran = 1 - - self.assertTrue(suite_ran) - self.assert_greenlet_finished(g) - self.assertTrue(g.killed) - - def test_suite_body_raises(self, delay=None): - greenlet_sleep = timing.SMALL_TICK if not delay else timing.LARGE_TICK - with self.assertRaises(SuiteExpectedException): - with GreenletRaisesJoin.spawn(gevent.sleep, greenlet_sleep) as g: - self.assert_greenlet_spawned(g) - if delay: - g.raise_on_join = False - gevent.sleep(delay) - raise SuiteExpectedException - - self.assert_greenlet_finished(g) - self.assertTrue(g.killed) - if delay: - self.assertTrue(g.joined) - else: - self.assertFalse(g.joined) - self.assertFalse(g.successful()) - - with self.assertRaises(SuiteExpectedException): - g.get() - - def test_suite_body_raises_with_delay(self): - self.test_suite_body_raises(delay=timing.SMALL_TICK) - -class TestStart(greentest.TestCase): - - def test_start(self): - g = gevent.spawn(gevent.sleep, timing.SMALL_TICK) - self.assert_greenlet_spawned(g) - - g.start() - self.assert_greenlet_started(g) - - g.join() - self.assert_greenlet_finished(g) - - # cannot start again - g.start() - self.assert_greenlet_finished(g) - - -class TestRef(greentest.TestCase): - - def test_init(self): - self.switch_expected = False - # in python-dbg mode this will check that Greenlet() does not create any circular refs - gevent.Greenlet() - - def test_kill_scheduled(self): - gevent.spawn(gevent.sleep, timing.LARGE_TICK).kill() - - def test_kill_started(self): - g = gevent.spawn(gevent.sleep, timing.LARGE_TICK) - try: - gevent.sleep(timing.SMALLEST_RELIABLE_DELAY) - finally: - g.kill() - - -@greentest.skipOnPurePython("Needs C extension") -class TestCExt(greentest.TestCase): # pragma: no cover (we only do coverage on pure-Python) - - def test_c_extension(self): - self.assertEqual(greenlet.Greenlet.__module__, - 'gevent._gevent_cgreenlet') - self.assertEqual(greenlet.SpawnedLink.__module__, - 'gevent._gevent_cgreenlet') - -@greentest.skipWithCExtensions("Needs pure python") -class TestPure(greentest.TestCase): - - def test_pure(self): - self.assertEqual(greenlet.Greenlet.__module__, - 'gevent.greenlet') - self.assertEqual(greenlet.SpawnedLink.__module__, - 'gevent.greenlet') - - -class TestDeadPropertyDuringSwitch(greentest.TestCase): - """Regression test: Greenlet.dead must not return True for an active greenlet. - - During the bootstrap phase of a freshly started greenlet, the event loop - consumes the start callback (setting _start_event.pending to False) before - run() sets _start_event = _start_completed_event. In that window, - __started_but_aborted() would incorrectly return True, making the ``dead`` - property report the greenlet as dead while it is actually running. - - This matters because ``dead`` returning True makes ``ready()`` return True, - which causes ``rawlink()`` to immediately schedule ``_notify_links`` -- - dispatching all registered link callbacks prematurely. - """ - - def test_dead_is_false_for_current_greenlet_during_switch(self): - from greenlet import settrace - - dead_values = [] - - def tracer(event, args): - if event == 'switch': - _origin, target = args - # The target is the greenlet being switched into. - # It must NOT appear dead. - dead_values.append(target.dead) - - old_trace = settrace(tracer) - try: - g = gevent.spawn(lambda: 42) - g.join() - finally: - settrace(old_trace) - - # There should be at least one switch event where target was our - # greenlet. None of the dead observations should be True for a - # greenlet that is actively running. - self.assertTrue(len(dead_values) > 0, "tracer was never called") - for i, val in enumerate(dead_values): - self.assertFalse( - val, - "dead returned True during switch event #%d" % i, - ) - - -X = object() - -del AbstractGenericGetTestCase -del AbstractGenericWaitTestCase - - -if __name__ == '__main__': - greentest.main() diff --git a/venv/lib/python3.9/site-packages/gevent/tests/test__greenletset.py b/venv/lib/python3.9/site-packages/gevent/tests/test__greenletset.py deleted file mode 100644 index f8d544f..0000000 --- a/venv/lib/python3.9/site-packages/gevent/tests/test__greenletset.py +++ /dev/null @@ -1,183 +0,0 @@ -from __future__ import print_function, division, absolute_import -import time -import gevent.testing as greentest - -from gevent.testing import timing -import gevent -from gevent import pool -from gevent.timeout import Timeout - -DELAY = timing.LARGE_TICK - - -class SpecialError(Exception): - pass - - -class Undead(object): - - def __init__(self): - self.shot_count = 0 - - def __call__(self): - while True: - try: - gevent.sleep(1) - except SpecialError: - break - except: # pylint:disable=bare-except - self.shot_count += 1 - - -class Test(greentest.TestCase): - - __timeout__ = greentest.LARGE_TIMEOUT - - def test_basic(self): - s = pool.Group() - s.spawn(gevent.sleep, timing.LARGE_TICK) - self.assertEqual(len(s), 1, s) - s.spawn(gevent.sleep, timing.LARGE_TICK * 5) - self.assertEqual(len(s), 2, s) - gevent.sleep() - gevent.sleep(timing.LARGE_TICK * 2 + timing.LARGE_TICK_MIN_ADJ) - self.assertEqual(len(s), 1, s) - gevent.sleep(timing.LARGE_TICK * 5 + timing.LARGE_TICK_MIN_ADJ) - self.assertFalse(s) - - def test_waitall(self): - s = pool.Group() - s.spawn(gevent.sleep, DELAY) - s.spawn(gevent.sleep, DELAY * 2) - assert len(s) == 2, s - start = time.time() - s.join(raise_error=True) - delta = time.time() - start - self.assertFalse(s) - self.assertEqual(len(s), 0) - self.assertTimeWithinRange(delta, DELAY * 1.9, DELAY * 2.5) - - def test_kill_block(self): - s = pool.Group() - s.spawn(gevent.sleep, DELAY) - s.spawn(gevent.sleep, DELAY * 2) - assert len(s) == 2, s - start = time.time() - s.kill() - self.assertFalse(s) - self.assertEqual(len(s), 0) - delta = time.time() - start - assert delta < DELAY * 0.8, delta - - def test_kill_noblock(self): - s = pool.Group() - s.spawn(gevent.sleep, DELAY) - s.spawn(gevent.sleep, DELAY * 2) - assert len(s) == 2, s - s.kill(block=False) - assert len(s) == 2, s - gevent.sleep(0.0001) - self.assertFalse(s) - self.assertEqual(len(s), 0) - - def test_kill_fires_once(self): - u1 = Undead() - u2 = Undead() - p1 = gevent.spawn(u1) - p2 = gevent.spawn(u2) - - def check(count1, count2): - self.assertTrue(p1) - self.assertTrue(p2) - self.assertFalse(p1.dead, p1) - self.assertFalse(p2.dead, p2) - self.assertEqual(u1.shot_count, count1) - self.assertEqual(u2.shot_count, count2) - - gevent.sleep(0.01) - s = pool.Group([p1, p2]) - self.assertEqual(len(s), 2, s) - check(0, 0) - s.killone(p1, block=False) - check(0, 0) - gevent.sleep(0) - check(1, 0) - s.killone(p1) - check(1, 0) - s.killone(p1) - check(1, 0) - s.kill(block=False) - s.kill(block=False) - s.kill(block=False) - check(1, 0) - gevent.sleep(DELAY) - check(1, 1) - X = object() - kill_result = gevent.with_timeout(DELAY, s.kill, block=True, timeout_value=X) - assert kill_result is X, repr(kill_result) - assert len(s) == 2, s - check(1, 1) - - p1.kill(SpecialError) - p2.kill(SpecialError) - - def test_killall_subclass(self): - p1 = GreenletSubclass.spawn(lambda: 1 / 0) - p2 = GreenletSubclass.spawn(lambda: gevent.sleep(10)) - s = pool.Group([p1, p2]) - s.kill() - - def test_killall_iterable_argument_non_block(self): - p1 = GreenletSubclass.spawn(lambda: gevent.sleep(0.5)) - p2 = GreenletSubclass.spawn(lambda: gevent.sleep(0.5)) - s = set() - s.add(p1) - s.add(p2) - gevent.killall(s, block=False) - gevent.sleep(0.5) - for g in s: - assert g.dead - - def test_killall_iterable_argument_timeout_not_started(self): - def f(): - try: - gevent.sleep(1.5) - except: # pylint:disable=bare-except - gevent.sleep(1) - p1 = GreenletSubclass.spawn(f) - p2 = GreenletSubclass.spawn(f) - s = set() - s.add(p1) - s.add(p2) - gevent.killall(s, timeout=0.5) - - for g in s: - self.assertTrue(g.dead, g) - - def test_killall_iterable_argument_timeout_started(self): - def f(): - try: - gevent.sleep(1.5) - except: # pylint:disable=bare-except - gevent.sleep(1) - p1 = GreenletSubclass.spawn(f) - p2 = GreenletSubclass.spawn(f) - - s = set() - s.add(p1) - s.add(p2) - # Get them both running. - gevent.sleep(timing.SMALLEST_RELIABLE_DELAY) - with self.assertRaises(Timeout): - gevent.killall(s, timeout=0.5) - - for g in s: - self.assertFalse(g.dead, g) - - -class GreenletSubclass(gevent.Greenlet): - pass - - -if __name__ == '__main__': - greentest.main() diff --git a/venv/lib/python3.9/site-packages/gevent/tests/test__greenness.py b/venv/lib/python3.9/site-packages/gevent/tests/test__greenness.py deleted file mode 100644 index bf0cb1f..0000000 --- a/venv/lib/python3.9/site-packages/gevent/tests/test__greenness.py +++ /dev/null @@ -1,87 +0,0 @@ -# Copyright (c) 2008 AG Projects -# Author: Denis Bilenko -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. - -""" -Trivial test that a single process (and single thread) can both read -and write from green sockets (when monkey patched). -""" -from __future__ import print_function -from __future__ import absolute_import -from __future__ import division - -from gevent import monkey -monkey.patch_all() - - -import gevent.testing as greentest - -try: - from urllib import request as urllib2 - from http.server import HTTPServer - from http.server import SimpleHTTPRequestHandler -except ImportError: - # Python 2 - import urllib2 - from BaseHTTPServer import HTTPServer - from SimpleHTTPServer import SimpleHTTPRequestHandler - - -import gevent -from gevent.testing import params - -class QuietHandler(SimpleHTTPRequestHandler, object): - - def log_message(self, *args): # pylint:disable=arguments-differ - self.server.messages += ((args,),) - -class Server(HTTPServer, object): - - messages = () - requests_handled = 0 - - def __init__(self): - HTTPServer.__init__(self, - params.DEFAULT_BIND_ADDR_TUPLE, - QuietHandler) - - def handle_request(self): - HTTPServer.handle_request(self) - self.requests_handled += 1 - - -class TestGreenness(greentest.TestCase): - check_totalrefcount = False - - def test_urllib2(self): - httpd = Server() - server_greenlet = gevent.spawn(httpd.handle_request) - - port = httpd.socket.getsockname()[1] - rsp = urllib2.urlopen('http://127.0.0.1:%s' % port) - rsp.read() - rsp.close() - server_greenlet.join() - self.assertEqual(httpd.requests_handled, 1) - httpd.server_close() - - -if __name__ == '__main__': - greentest.main() diff --git a/venv/lib/python3.9/site-packages/gevent/tests/test__hub.py b/venv/lib/python3.9/site-packages/gevent/tests/test__hub.py deleted file mode 100644 index 4c29df7..0000000 --- a/venv/lib/python3.9/site-packages/gevent/tests/test__hub.py +++ /dev/null @@ -1,404 +0,0 @@ -# Copyright (c) 2009 AG Projects -# Author: Denis Bilenko -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. - -import re -import time -import unittest - -import gevent.testing as greentest -import gevent.testing.timing - -import gevent -from gevent import socket -from gevent.hub import Waiter, get_hub -from gevent._compat import NativeStrIO -from gevent._compat import get_this_psutil_process - -DELAY = 0.1 - - -class TestCloseSocketWhilePolling(greentest.TestCase): - - def test(self): - sock = socket.socket() - self._close_on_teardown(sock) - t = get_hub().loop.timer(0) - t.start(sock.close) - with self.assertRaises(socket.error): - try: - sock.connect(('python.org', 81)) - finally: - t.close() - - gevent.sleep(0) - - -class TestExceptionInMainloop(greentest.TestCase): - - def test_sleep(self): - # even if there was an error in the mainloop, the hub should continue to work - start = time.time() - gevent.sleep(DELAY) - delay = time.time() - start - - delay_range = DELAY * 0.9 - self.assertTimeWithinRange(delay, DELAY - delay_range, DELAY + delay_range) - - error = greentest.ExpectedException('TestExceptionInMainloop.test_sleep/fail') - - def fail(): - raise error - - with get_hub().loop.timer(0.001) as t: - t.start(fail) - - self.expect_one_error() - - start = time.time() - gevent.sleep(DELAY) - delay = time.time() - start - - self.assert_error(value=error) - self.assertTimeWithinRange(delay, DELAY - delay_range, DELAY + delay_range) - - - -class TestSleep(gevent.testing.timing.AbstractGenericWaitTestCase): - - def wait(self, timeout): - gevent.sleep(timeout) - - def test_simple(self): - gevent.sleep(0) - - -class TestWaiterGet(gevent.testing.timing.AbstractGenericWaitTestCase): - - def setUp(self): - super(TestWaiterGet, self).setUp() - self.waiter = Waiter() - - def wait(self, timeout): - with get_hub().loop.timer(timeout) as evt: - evt.start(self.waiter.switch, None) - return self.waiter.get() - - -class TestWaiter(greentest.TestCase): - - def test(self): - waiter = Waiter() - self.assertEqual(str(waiter), '') - waiter.switch(25) - self.assertEqual(str(waiter), '') - self.assertEqual(waiter.get(), 25) - - waiter = Waiter() - waiter.throw(ZeroDivisionError) - assert re.match('^ count_before: - # We could be off by exactly 1. Not entirely clear where. - # But it only happens the first time. - count_after -= 1 - # If we were run in multiple process, our count could actually have - # gone down due to the GC's we did. - self.assertEqual(count_after, count_before) - - @ignores_leakcheck - def test_join_in_new_thread_doesnt_leak_hub_or_greenlet(self): - # https://github.com/gevent/gevent/issues/1601 - import threading - clean = self.__clean - - def thread_main(): - g = gevent.Greenlet(run=lambda: 0) - g.start() - g.join() - hub = gevent.get_hub() - hub.join() - hub.destroy(destroy_loop=True) - del hub - - def tester(main): - t = threading.Thread(target=main) - t.start() - t.join() - - clean() - - with self.assert_no_greenlet_growth(): - for _ in range(10): - tester(thread_main) - - del tester - del thread_main - - @ignores_leakcheck - def test_destroy_in_main_thread_from_new_thread(self): - # https://github.com/gevent/gevent/issues/1631 - import threading - - clean = self.__clean - class Thread(threading.Thread): - hub = None - def run(self): - g = gevent.Greenlet(run=lambda: 0) - g.start() - g.join() - del g - hub = gevent.get_hub() - hub.join() - self.hub = hub - - def tester(Thread, clean): - t = Thread() - t.start() - t.join() - t.hub.destroy(destroy_loop=True) - t.hub = None - del t - clean() - - # Unfortunately, this WILL leak greenlets, - # at least on CPython. The frames of the dead threads - # are referenced by the hub in some sort of cycle, and - # greenlets don't particpate in GC. - for _ in range(10): - tester(Thread, clean) - - del tester - del Thread - - -if __name__ == '__main__': - unittest.main() diff --git a/venv/lib/python3.9/site-packages/gevent/tests/test__hub_join_timeout.py b/venv/lib/python3.9/site-packages/gevent/tests/test__hub_join_timeout.py deleted file mode 100644 index b80457a..0000000 --- a/venv/lib/python3.9/site-packages/gevent/tests/test__hub_join_timeout.py +++ /dev/null @@ -1,99 +0,0 @@ -import functools -import unittest - -import gevent -import gevent.core -from gevent.event import Event - -from gevent.testing.testcase import TimeAssertMixin - -SMALL_TICK = 0.05 - -# setting up signal does not affect join() -gevent.signal_handler(1, lambda: None) # wouldn't work on windows - - -def repeated(func, repetitions=2): - @functools.wraps(func) - def f(self): - for _ in range(repetitions): - func(self) - return f - -class Test(TimeAssertMixin, unittest.TestCase): - - @repeated - def test_callback(self): - # exiting because the spawned greenlet finished execution (spawn (=callback) variant) - x = gevent.spawn(lambda: 5) - with self.runs_in_no_time(): - result = gevent.wait(timeout=10) - self.assertTrue(result) - self.assertTrue(x.dead, x) - self.assertEqual(x.value, 5) - - @repeated - def test_later(self): - # exiting because the spawned greenlet finished execution (spawn_later (=timer) variant) - x = gevent.spawn_later(SMALL_TICK, lambda: 5) - with self.runs_in_given_time(SMALL_TICK): - result = gevent.wait(timeout=10) - self.assertTrue(result) - self.assertTrue(x.dead, x) - - @repeated - def test_timeout(self): - # exiting because of timeout (the spawned greenlet still runs) - x = gevent.spawn_later(10, lambda: 5) - with self.runs_in_given_time(SMALL_TICK): - result = gevent.wait(timeout=SMALL_TICK) - self.assertFalse(result) - self.assertFalse(x.dead, x) - x.kill() - with self.runs_in_no_time(): - result = gevent.wait() - - self.assertTrue(result) - - @repeated - def test_event(self): - # exiting because of event (the spawned greenlet still runs) - x = gevent.spawn_later(10, lambda: 5) - event = Event() - event_set = gevent.spawn_later(SMALL_TICK, event.set) - with self.runs_in_given_time(SMALL_TICK): - result = gevent.wait([event]) - self.assertEqual(result, [event]) - self.assertFalse(x.dead, x) - self.assertTrue(event_set.dead) - self.assertTrue(event.is_set) - x.kill() - with self.runs_in_no_time(): - result = gevent.wait() - - self.assertTrue(result) - - @repeated - def test_ref_arg(self): - # checking "ref=False" argument - gevent.get_hub().loop.timer(10, ref=False).start(lambda: None) - with self.runs_in_no_time(): - result = gevent.wait() - self.assertTrue(result) - - @repeated - def test_ref_attribute(self): - # checking "ref=False" attribute - w = gevent.get_hub().loop.timer(10) - w.start(lambda: None) - w.ref = False - with self.runs_in_no_time(): - result = gevent.wait() - self.assertTrue(result) - - -class TestAgain(Test): - "Repeat the same tests" - -if __name__ == '__main__': - unittest.main() diff --git a/venv/lib/python3.9/site-packages/gevent/tests/test__import_blocking_in_greenlet.py b/venv/lib/python3.9/site-packages/gevent/tests/test__import_blocking_in_greenlet.py deleted file mode 100644 index ecf0a11..0000000 --- a/venv/lib/python3.9/site-packages/gevent/tests/test__import_blocking_in_greenlet.py +++ /dev/null @@ -1,42 +0,0 @@ -#!/usr/bin/python -# See https://github.com/gevent/gevent/issues/108 -import gevent -from gevent import monkey - -import_errors = [] - - -def some_func(): - try: - from _blocks_at_top_level import x - assert x == 'done' - except ImportError as e: - import_errors.append(e) - raise - -if __name__ == '__main__': - import sys - if sys.version_info[:2] == (3, 13): - import unittest - class Test(unittest.TestCase): - def test_it(self): - self.skipTest( - 'On Python 3.13, no matter how I arrange the PYTHONPATH/sys.path ' - 'we get "cannot import name x from partially initialized module ' - '_blocks_at_top_level". It is unclear why. Limiting the scope of ' - 'the exclusion for now.' - ) - unittest.main() - else: - - monkey.patch_all() - import sys - import os - p = os.path.dirname(__file__) - sys.path.insert(0, p) - - - gs = [gevent.spawn(some_func) for i in range(2)] - gevent.joinall(gs) - - assert not import_errors, import_errors diff --git a/venv/lib/python3.9/site-packages/gevent/tests/test__import_wait.py b/venv/lib/python3.9/site-packages/gevent/tests/test__import_wait.py deleted file mode 100644 index e085659..0000000 --- a/venv/lib/python3.9/site-packages/gevent/tests/test__import_wait.py +++ /dev/null @@ -1,10 +0,0 @@ -# https://github.com/gevent/gevent/issues/652 and 651 -from gevent import monkey -monkey.patch_all() - -try: - import _import_wait # pylint:disable=import-error -except ModuleNotFoundError: - from gevent.tests import _import_wait - -assert _import_wait.x diff --git a/venv/lib/python3.9/site-packages/gevent/tests/test__issue112.py b/venv/lib/python3.9/site-packages/gevent/tests/test__issue112.py deleted file mode 100644 index df2be0c..0000000 --- a/venv/lib/python3.9/site-packages/gevent/tests/test__issue112.py +++ /dev/null @@ -1,19 +0,0 @@ -import sys -import unittest -import threading -import gevent -import gevent.monkey -gevent.monkey.patch_all() - - -@unittest.skipUnless( - sys.version_info[0] == 2, - "Only on Python 2" -) -class Test(unittest.TestCase): - - def test(self): - self.assertIs(threading._sleep, gevent.sleep) - -if __name__ == '__main__': - unittest.main() diff --git a/venv/lib/python3.9/site-packages/gevent/tests/test__issue1686.py b/venv/lib/python3.9/site-packages/gevent/tests/test__issue1686.py deleted file mode 100644 index dfb1893..0000000 --- a/venv/lib/python3.9/site-packages/gevent/tests/test__issue1686.py +++ /dev/null @@ -1,85 +0,0 @@ -# -*- coding: utf-8 -*- -""" -Tests for https://github.com/gevent/gevent/issues/1686 -which is about destroying a hub when there are active -callbacks or IO in operation. -""" -from __future__ import absolute_import -from __future__ import division -from __future__ import print_function - -import os -import unittest - -from gevent import testing as greentest - -# Don't let the testrunner put us in a process with other -# tests; we are strict on the state of the hub and greenlets. -# pragma: testrunner-no-combine - -@greentest.skipOnWindows("Uses os.fork") -class TestDestroyInChildWithActiveSpawn(unittest.TestCase): - - def test(self): # pylint:disable=too-many-locals - # If this test is broken, there are a few failure modes. - # - In the original examples, the parent process just hangs, because the - # child has raced ahead, spawned the greenlet and read the data. When the - # greenlet goes to read in the parent, it blocks, and the hub and loop - # wait for it. - # - Here, our child detects the greenlet ran when it shouldn't and - # raises an error, which translates to a non-zero exit status, - # which the parent checks for and fails by raising an exception before - # returning control to the hub. We can replicate the hang by removing the - # assertion in the child. - from time import sleep as hang - - from gevent import get_hub - from gevent import spawn - from gevent.socket import wait_read - from gevent.os import nb_read - from gevent.os import nb_write - from gevent.os import make_nonblocking - from gevent.os import fork - from gevent.os import waitpid - - pipe_read_fd, pipe_write_fd = os.pipe() - make_nonblocking(pipe_read_fd) - make_nonblocking(pipe_write_fd) - - run = [] - - def reader(): - run.append(1) - return nb_read(pipe_read_fd, 4096) - - # Put data in the pipe - DATA = b'test' - nb_write(pipe_write_fd, DATA) - # Make sure we're ready to read it - wait_read(pipe_read_fd) - - # Schedule a greenlet to start - reader = spawn(reader) - - hub = get_hub() - pid = fork() - if pid == 0: - # Child destroys the hub. The reader should not have run. - hub.destroy(destroy_loop=True) - self.assertFalse(run) - os._exit(0) - return # pylint:disable=unreachable - - # The parent. - # Briefly prevent us from spinning our event loop. - hang(0.5) - wait_child_result = waitpid(pid, 0) - self.assertEqual(wait_child_result, (pid, 0)) - # We should get the data; the greenlet only runs in the parent. - data = reader.get() - self.assertEqual(run, [1]) - self.assertEqual(data, DATA) - - -if __name__ == '__main__': - greentest.main() diff --git a/venv/lib/python3.9/site-packages/gevent/tests/test__issue1864.py b/venv/lib/python3.9/site-packages/gevent/tests/test__issue1864.py deleted file mode 100644 index dccef30..0000000 --- a/venv/lib/python3.9/site-packages/gevent/tests/test__issue1864.py +++ /dev/null @@ -1,28 +0,0 @@ -import sys -import unittest -from gevent import testing as greentest - - -class TestSubnormalFloatsAreNotDisabled(unittest.TestCase): - - @greentest.skipOnCI('Some of our tests we compile with -Ofast, which breaks this.') - def test_subnormal_is_not_zero(self): - # Enabling the -Ofast compiler flag resulted in subnormal floats getting - # disabled the moment when gevent was imported. This impacted libraries - # that expect subnormal floats to be enabled. - # - # NOTE: This test is supposed to catch that. It doesn't seem to work perfectly, though. - # The test passes under Python 2 on macOS no matter whether -ffast-math is given or not; - # perhaps this is a difference in clang vs gcc? In contrast, the test on Python 2.7 always - # *fails* on GitHub actions (in both CPython 2.7 and PyPy). We're far past the EOL of - # Python 2.7 so I'm not going to spend much time investigating. - __import__('gevent') - - # `sys.float_info.min` is the minimum representable positive normalized - # float, so dividing it by two gives us a positive subnormal float, - # as long as subnormals floats are not disabled. - self.assertGreater(sys.float_info.min / 2, 0.0) - - -if __name__ == "__main__": - unittest.main() diff --git a/venv/lib/python3.9/site-packages/gevent/tests/test__issue230.py b/venv/lib/python3.9/site-packages/gevent/tests/test__issue230.py deleted file mode 100644 index d17582c..0000000 --- a/venv/lib/python3.9/site-packages/gevent/tests/test__issue230.py +++ /dev/null @@ -1,27 +0,0 @@ -import gevent.monkey -gevent.monkey.patch_all() - -import socket -import multiprocessing - -from gevent import testing as greentest - -# Make sure that using the resolver in a forked process -# doesn't hang forever. - - -def block(): - socket.getaddrinfo('localhost', 8001) - - - -class Test(greentest.TestCase): - def test(self): - socket.getaddrinfo('localhost', 8001) - - p = multiprocessing.Process(target=block) - p.start() - p.join() - -if __name__ == '__main__': - greentest.main() diff --git a/venv/lib/python3.9/site-packages/gevent/tests/test__issue330.py b/venv/lib/python3.9/site-packages/gevent/tests/test__issue330.py deleted file mode 100644 index 5005ed6..0000000 --- a/venv/lib/python3.9/site-packages/gevent/tests/test__issue330.py +++ /dev/null @@ -1,82 +0,0 @@ -# A greenlet that's killed before it is ever started -# should never be switched to -import gevent -import gevent.testing as greentest - - -class MyException(Exception): - pass - -class TestSwitch(greentest.TestCase): - - def setUp(self): - super(TestSwitch, self).setUp() - self.switched_to = [False, False] - self.caught = None - - def should_never_run(self, i): # pragma: no cover - self.switched_to[i] = True - - def check(self, g, g2): - gevent.joinall((g, g2)) - self.assertEqual([False, False], self.switched_to) - - # They both have a GreenletExit as their value - self.assertIsInstance(g.value, gevent.GreenletExit) - self.assertIsInstance(g2.value, gevent.GreenletExit) - - # They both have no reported exc_info - self.assertIsNone(g.exc_info) - self.assertIsNone(g2.exc_info) - self.assertIsNone(g.exception) - self.assertIsNone(g2.exception) - - - def test_gevent_kill(self): - g = gevent.spawn(self.should_never_run, 0) # create but do not switch to - g2 = gevent.spawn(self.should_never_run, 1) # create but do not switch to - # Using gevent.kill - gevent.kill(g) - gevent.kill(g2) - self.check(g, g2) - - def test_greenlet_kill(self): - # killing directly - g = gevent.spawn(self.should_never_run, 0) - g2 = gevent.spawn(self.should_never_run, 1) - g.kill() - g2.kill() - self.check(g, g2) - - def test_throw(self): - # throwing - g = gevent.spawn(self.should_never_run, 0) - g2 = gevent.spawn(self.should_never_run, 1) - g.throw(gevent.GreenletExit) - g2.throw(gevent.GreenletExit) - self.check(g, g2) - - - def catcher(self): - try: - while True: - gevent.sleep(0) - except MyException as e: - self.caught = e - - def test_kill_exception(self): - # Killing with gevent.kill gets the right exception, - # and we can pass exception objects, not just exception classes. - - g = gevent.spawn(self.catcher) - g.start() - gevent.sleep() - gevent.kill(g, MyException()) - gevent.sleep() - - self.assertIsInstance(self.caught, MyException) - self.assertIsNone(g.exception, MyException) - - -if __name__ == '__main__': - greentest.main() diff --git a/venv/lib/python3.9/site-packages/gevent/tests/test__issue467.py b/venv/lib/python3.9/site-packages/gevent/tests/test__issue467.py deleted file mode 100644 index abee04f..0000000 --- a/venv/lib/python3.9/site-packages/gevent/tests/test__issue467.py +++ /dev/null @@ -1,40 +0,0 @@ -import gevent -from gevent import testing as greentest - -#import socket # on windows - -# iwait should not raise `LoopExit: This operation would block forever` -# or `AssertionError: Invalid switch into ...` -# if the caller of iwait causes greenlets to switch in between -# return values - - -def worker(i): - # Have one of them raise an exception to test that case - if i == 2: - raise ValueError(i) - return i - -class Test(greentest.TestCase): - def test(self): - finished = 0 - # Wait on a group that includes one that will already be - # done, plus some that will finish as we watch - done_worker = gevent.spawn(worker, "done") - gevent.joinall((done_worker,)) - - workers = [gevent.spawn(worker, i) for i in range(3)] - workers.append(done_worker) - for _ in gevent.iwait(workers): - finished += 1 - # Simulate doing something that causes greenlets to switch; - # a non-zero timeout is crucial - try: - gevent.sleep(0.01) - except ValueError as ex: - self.assertEqual(ex.args[0], 2) - - self.assertEqual(finished, 4) - -if __name__ == '__main__': - greentest.main() diff --git a/venv/lib/python3.9/site-packages/gevent/tests/test__issue6.py b/venv/lib/python3.9/site-packages/gevent/tests/test__issue6.py deleted file mode 100644 index 8faaf1e..0000000 --- a/venv/lib/python3.9/site-packages/gevent/tests/test__issue6.py +++ /dev/null @@ -1,39 +0,0 @@ -from __future__ import print_function -from __future__ import absolute_import -from __future__ import division - -import sys - -if not sys.argv[1:]: - from subprocess import Popen, PIPE - # not on Py2 pylint:disable=consider-using-with - p = Popen([sys.executable, __file__, 'subprocess'], stdin=PIPE, stdout=PIPE, stderr=PIPE) - out, err = p.communicate(b'hello world\n') - code = p.poll() - assert p.poll() == 0, (out, err, code) - assert out.strip() == b'11 chars.', (out, err, code) - # XXX: This is seen sometimes to fail on Travis with the following value in err but a code of 0; - # it seems load related: - # 'Unhandled exception in thread started by \nsys.excepthook is missing\nlost sys.stderr\n'. - # If warnings are enabled, Python 3 has started producing this: - # '...importlib/_bootstrap.py:219: ImportWarning: can't resolve package from __spec__ - # or __package__, falling back on __name__ and __path__\n return f(*args, **kwds)\n' - assert err == b'' or b'sys.excepthook' in err or b'Warning' in err, (out, err, code) - -elif sys.argv[1:] == ['subprocess']: # pragma: no cover - import gevent - import gevent.monkey - gevent.monkey.patch_all(sys=True) - - def printline(): - try: - line = raw_input() - except NameError: - line = input() # pylint:disable=bad-builtin - print('%s chars.' % len(line)) - sys.stdout.flush() - - gevent.spawn(printline).join() - -else: # pragma: no cover - sys.exit('Invalid arguments: %r' % (sys.argv, )) diff --git a/venv/lib/python3.9/site-packages/gevent/tests/test__issue600.py b/venv/lib/python3.9/site-packages/gevent/tests/test__issue600.py deleted file mode 100644 index 19d10ed..0000000 --- a/venv/lib/python3.9/site-packages/gevent/tests/test__issue600.py +++ /dev/null @@ -1,48 +0,0 @@ -# Make sure that libev child watchers, implicitly installed through the use -# of subprocess, do not cause waitpid() to fail to poll for processes. -# NOTE: This was only reproducible under python 2. -from __future__ import print_function -import gevent -from gevent import monkey -monkey.patch_all() - -import sys -from multiprocessing import Process -from subprocess import Popen, PIPE - -from gevent import testing as greentest - -def f(sleep_sec): - gevent.sleep(sleep_sec) - - - -class TestIssue600(greentest.TestCase): - - __timeout__ = greentest.LARGE_TIMEOUT - - @greentest.skipOnLibuvOnPyPyOnWin("hangs") - def test_invoke(self): - # Run a subprocess through Popen to make sure - # libev is handling SIGCHLD. This could *probably* be simplified to use - # just hub.loop.install_sigchld - # (no __enter__/__exit__ on Py2) pylint:disable=consider-using-with - p = Popen([sys.executable, '-V'], stdout=PIPE, stderr=PIPE) - gevent.sleep(0) - p.communicate() - gevent.sleep(0) - - def test_process(self): - # Launch - p = Process(target=f, args=(0.5,)) - p.start() - - with gevent.Timeout(3): - # Poll for up to 10 seconds. If the bug exists, - # this will timeout because our subprocess should - # be long gone by now - p.join(10) - - -if __name__ == '__main__': - greentest.main() diff --git a/venv/lib/python3.9/site-packages/gevent/tests/test__issue607.py b/venv/lib/python3.9/site-packages/gevent/tests/test__issue607.py deleted file mode 100644 index e4ab1c5..0000000 --- a/venv/lib/python3.9/site-packages/gevent/tests/test__issue607.py +++ /dev/null @@ -1,47 +0,0 @@ -# A greenlet that's killed with an exception should fail. -import gevent.testing as greentest -import gevent - - -class ExpectedError(greentest.ExpectedException): - pass - - -def f(): - gevent.sleep(999) - - -class TestKillWithException(greentest.TestCase): - - def test_kill_without_exception(self): - g = gevent.spawn(f) - g.kill() - assert g.successful() - assert isinstance(g.get(), gevent.GreenletExit) - - def test_kill_with_exception(self): - # issue-607 pointed this case. - g = gevent.spawn(f) - with gevent.get_hub().ignoring_expected_test_error(): - # Hmm, this only needs the `with ignoring...` in - # PURE_PYTHON mode (or PyPy). - g.kill(ExpectedError) - self.assertFalse(g.successful()) - self.assertRaises(ExpectedError, g.get) - self.assertIsNone(g.value) - self.assertIsInstance(g.exception, ExpectedError) - - def test_kill_with_exception_after_started(self): - with gevent.get_hub().ignoring_expected_test_error(): - g = gevent.spawn(f) - g.join(0) - g.kill(ExpectedError) - - self.assertFalse(g.successful()) - self.assertRaises(ExpectedError, g.get) - self.assertIsNone(g.value) - self.assertIsInstance(g.exception, ExpectedError) - - -if __name__ == '__main__': - greentest.main() diff --git a/venv/lib/python3.9/site-packages/gevent/tests/test__issue639.py b/venv/lib/python3.9/site-packages/gevent/tests/test__issue639.py deleted file mode 100644 index 935cab3..0000000 --- a/venv/lib/python3.9/site-packages/gevent/tests/test__issue639.py +++ /dev/null @@ -1,12 +0,0 @@ -# Test idle -import gevent - -from gevent import testing as greentest - -class Test(greentest.TestCase): - def test(self): - gevent.sleep() - gevent.idle() - -if __name__ == '__main__': - greentest.main() diff --git a/venv/lib/python3.9/site-packages/gevent/tests/test__issue_728.py b/venv/lib/python3.9/site-packages/gevent/tests/test__issue_728.py deleted file mode 100644 index fc61fc2..0000000 --- a/venv/lib/python3.9/site-packages/gevent/tests/test__issue_728.py +++ /dev/null @@ -1,9 +0,0 @@ -#!/usr/bin/env python -from gevent.monkey import patch_all -patch_all() - - -if __name__ == '__main__': - # Reproducing #728 requires a series of nested - # imports - __import__('_imports_imports_at_top_level') diff --git a/venv/lib/python3.9/site-packages/gevent/tests/test__issues461_471.py b/venv/lib/python3.9/site-packages/gevent/tests/test__issues461_471.py deleted file mode 100644 index c7208da..0000000 --- a/venv/lib/python3.9/site-packages/gevent/tests/test__issues461_471.py +++ /dev/null @@ -1,95 +0,0 @@ -'''Test for GitHub issues 461 and 471. - -When moving to Python 3, handling of KeyboardInterrupt exceptions caused -by a Ctrl-C raised an exception while printing the traceback for a -greenlet preventing the process from exiting. This test tests for proper -handling of KeyboardInterrupt. -''' - -import sys - -if sys.argv[1:] == ['subprocess']: # pragma: no cover - import gevent - - def task(): - sys.stdout.write('ready\n') - sys.stdout.flush() - gevent.sleep(30) - - try: - gevent.spawn(task).get() - except KeyboardInterrupt: - pass - - sys.exit(0) - -else: - import signal - from subprocess import Popen, PIPE - import time - - import unittest - import gevent.testing as greentest - from gevent.testing.sysinfo import CFFI_BACKEND - from gevent.testing.sysinfo import RUN_COVERAGE - from gevent.testing.sysinfo import WIN - from gevent.testing.sysinfo import PYPY3 - - class Test(unittest.TestCase): - - @unittest.skipIf( - (CFFI_BACKEND and RUN_COVERAGE) or (PYPY3 and WIN), - "Interferes with the timing; times out waiting for the child") - def test_hang(self): - # XXX: Why does PyPy3 on Win fail to kill the child? (This was before we switched - # to pypy3w; perhaps that makes a difference?) - if WIN: - from subprocess import CREATE_NEW_PROCESS_GROUP - kwargs = {'creationflags': CREATE_NEW_PROCESS_GROUP} - else: - kwargs = {} - # (not on Py2) pylint:disable=consider-using-with - p = Popen([sys.executable, __file__, 'subprocess'], stdout=PIPE, **kwargs) - line = p.stdout.readline() - if not isinstance(line, str): - line = line.decode('ascii') - # Windows needs the \n in the string to write (because of buffering), but - # because of newline handling it doesn't make it through the read; whereas - # it does on other platforms. Universal newlines is broken on Py3, so the best - # thing to do is to strip it - line = line.strip() - self.assertEqual(line, 'ready') - # On Windows, we have to send the CTRL_BREAK_EVENT (which seems to terminate the process); SIGINT triggers - # "ValueError: Unsupported signal: 2". The CTRL_C_EVENT is ignored on Python 3 (but not Python 2). - # So this test doesn't test much on Windows. - signal_to_send = signal.SIGINT if not WIN else getattr(signal, 'CTRL_BREAK_EVENT') - p.send_signal(signal_to_send) - # Wait a few seconds for child process to die. Sometimes signal delivery is delayed - # or even swallowed by Python, so send the signal a few more times if necessary - wait_seconds = 25.0 - now = time.time() - midtime = now + (wait_seconds / 2.0) - endtime = time.time() + wait_seconds - while time.time() < endtime: - if p.poll() is not None: - break - if time.time() > midtime: - p.send_signal(signal_to_send) - midtime = endtime + 1 # only once - time.sleep(0.1) - else: - # Kill unresponsive child and exit with error 1 - p.terminate() - p.wait() - raise AssertionError("Failed to wait for child") - - # If we get here, it's because we caused the process to exit; it - # didn't hang. Under Windows, however, we have to use CTRL_BREAK_EVENT, - # which has an arbitrary returncode depending on versions (so does CTRL_C_EVENT - # on Python 2). We still - # count this as success. - self.assertEqual(p.returncode if not WIN else 0, 0) - p.stdout.close() - - if __name__ == '__main__': - greentest.main() diff --git a/venv/lib/python3.9/site-packages/gevent/tests/test__iwait.py b/venv/lib/python3.9/site-packages/gevent/tests/test__iwait.py deleted file mode 100644 index 0976e40..0000000 --- a/venv/lib/python3.9/site-packages/gevent/tests/test__iwait.py +++ /dev/null @@ -1,42 +0,0 @@ -import gevent -import gevent.testing as greentest -from gevent.lock import Semaphore - - -class Testiwait(greentest.TestCase): - - def test_noiter(self): - # Test that gevent.iwait returns objects which can be iterated upon - # without additional calls to iter() - - sem1 = Semaphore() - sem2 = Semaphore() - - gevent.spawn(sem1.release) - ready = next(gevent.iwait((sem1, sem2))) - self.assertEqual(sem1, ready) - - def test_iwait_partial(self): - # Test that the iwait context manager allows the iterator to be - # consumed partially without a memory leak. - - sem = Semaphore() - let = gevent.spawn(sem.release) - with gevent.iwait((sem,), timeout=0.01) as iterator: - self.assertEqual(sem, next(iterator)) - let.get() - - def test_iwait_nogarbage(self): - sem1 = Semaphore() - sem2 = Semaphore() - let = gevent.spawn(sem1.release) - with gevent.iwait((sem1, sem2)) as iterator: - self.assertEqual(sem1, next(iterator)) - self.assertEqual(sem2.linkcount(), 1) - - self.assertEqual(sem2.linkcount(), 0) - let.get() - - -if __name__ == '__main__': - greentest.main() diff --git a/venv/lib/python3.9/site-packages/gevent/tests/test__joinall.py b/venv/lib/python3.9/site-packages/gevent/tests/test__joinall.py deleted file mode 100644 index 1651d9f..0000000 --- a/venv/lib/python3.9/site-packages/gevent/tests/test__joinall.py +++ /dev/null @@ -1,20 +0,0 @@ -import gevent - -from gevent import testing as greentest - - -class Test(greentest.TestCase): - - def test(self): - - def func(): - pass - - - a = gevent.spawn(func) - b = gevent.spawn(func) - gevent.joinall([a, b, a]) - - -if __name__ == '__main__': - greentest.main() diff --git a/venv/lib/python3.9/site-packages/gevent/tests/test__local.py b/venv/lib/python3.9/site-packages/gevent/tests/test__local.py deleted file mode 100644 index 0565860..0000000 --- a/venv/lib/python3.9/site-packages/gevent/tests/test__local.py +++ /dev/null @@ -1,425 +0,0 @@ -import gevent.testing as greentest -from copy import copy -# Comment the line below to see that the standard thread.local is working correct -from gevent import monkey; monkey.patch_all() - - -from threading import local -from threading import Thread - -from zope import interface - -try: - from collections.abc import Mapping -except ImportError: - from collections import Mapping # pylint:disable=deprecated-class - -class ReadProperty(object): - """A property that can be overridden""" - - # A non-data descriptor - - def __get__(self, inst, klass): - return 42 if inst is not None else self - - -class A(local): - __slots__ = ['initialized', 'obj'] - - path = '' - - type_path = 'MyPath' - - read_property = ReadProperty() - - def __init__(self, obj): - super(A, self).__init__() - if not hasattr(self, 'initialized'): - self.obj = obj - self.path = '' - - -class Obj(object): - pass - -# These next two classes have to be global to avoid the leakchecks -deleted_sentinels = [] -created_sentinels = [] - -class Sentinel(object): - def __del__(self): - deleted_sentinels.append(id(self)) - - -class MyLocal(local): - - CLASS_PROP = 42 - - def __init__(self): - local.__init__(self) - self.sentinel = Sentinel() - created_sentinels.append(id(self.sentinel)) - - @property - def desc(self): - return self - -class MyLocalSubclass(MyLocal): - pass - -class WithGetattr(local): - - def __getattr__(self, name): - if name == 'foo': - return 42 - return super(WithGetattr, self).__getattr__(name) # pylint:disable=no-member - -class LocalWithABC(local, Mapping): - - def __getitem__(self, name): - return self.d[name] - - def __iter__(self): - return iter(self.d) - - def __len__(self): - return len(self.d) - -class LocalWithStaticMethod(local): - - @staticmethod - def a_staticmethod(): - return 42 - -class LocalWithClassMethod(local): - - @classmethod - def a_classmethod(cls): - return cls - - - - -class TestGeventLocal(greentest.TestCase): - # pylint:disable=attribute-defined-outside-init,blacklisted-name - - def setUp(self): - del deleted_sentinels[:] - del created_sentinels[:] - - tearDown = setUp - - def test_create_local_subclass_init_args(self): - with self.assertRaisesRegex(TypeError, - "Initialization arguments are not supported"): - local("foo") - - with self.assertRaisesRegex(TypeError, - "Initialization arguments are not supported"): - local(kw="foo") - - - def test_local_opts_not_subclassed(self): - l = local() - l.attr = 1 - self.assertEqual(l.attr, 1) - - def test_cannot_set_delete_dict(self): - l = local() - with self.assertRaises(AttributeError): - l.__dict__ = 1 - - with self.assertRaises(AttributeError): - del l.__dict__ - - def test_delete_with_no_dict(self): - l = local() - with self.assertRaises(AttributeError): - delattr(l, 'thing') - - def del_local(): - with self.assertRaises(AttributeError): - delattr(l, 'thing') - - t = Thread(target=del_local) - t.start() - t.join() - - def test_slot_and_type_attributes(self): - a = A(Obj()) - a.initialized = 1 - self.assertEqual(a.initialized, 1) - - # The slot is shared - def demonstrate_slots_shared(): - self.assertEqual(a.initialized, 1) - a.initialized = 2 - - greenlet = Thread(target=demonstrate_slots_shared) - greenlet.start() - greenlet.join() - - self.assertEqual(a.initialized, 2) - - # The slot overrides dict values - a.__dict__['initialized'] = 42 # pylint:disable=unsupported-assignment-operation - self.assertEqual(a.initialized, 2) - - # Deleting the slot deletes the slot, but not the dict - del a.initialized - self.assertFalse(hasattr(a, 'initialized')) - self.assertIn('initialized', a.__dict__) - - # We can delete the 'path' ivar - # and fall back to the type - del a.path - self.assertEqual(a.path, '') - - with self.assertRaises(AttributeError): - del a.path - - # A read property calls get - self.assertEqual(a.read_property, 42) - a.read_property = 1 - self.assertEqual(a.read_property, 1) - self.assertIsInstance(A.read_property, ReadProperty) - - # Type attributes can be read - self.assertEqual(a.type_path, 'MyPath') - self.assertNotIn('type_path', a.__dict__) - - # and replaced in the dict - a.type_path = 'Local' - self.assertEqual(a.type_path, 'Local') - self.assertIn('type_path', a.__dict__) - - def test_attribute_error(self): - # pylint:disable=attribute-defined-outside-init - a = A(Obj()) - with self.assertRaises(AttributeError): - getattr(a, 'fizz_buzz') - - def set_fizz_buzz(): - a.fizz_buzz = 1 - - greenlet = Thread(target=set_fizz_buzz) - greenlet.start() - greenlet.join() - - with self.assertRaises(AttributeError): - getattr(a, 'fizz_buzz') - - def test_getattr_called(self): - getter = WithGetattr() - self.assertEqual(42, getter.foo) - getter.foo = 'baz' - self.assertEqual('baz', getter.foo) - - - def test_copy(self): - a = A(Obj()) - a.path = '123' - a.obj.echo = 'test' - b = copy(a) - - # Copy makes a shallow copy. Meaning that the attribute path - # has to be independent in the original and the copied object because the - # value is a string, but the attribute obj should be just reference to - # the instance of the class Obj - - self.assertEqual(a.path, b.path, 'The values in the two objects must be equal') - self.assertEqual(a.obj, b.obj, 'The values must be equal') - - b.path = '321' - self.assertNotEqual(a.path, b.path, 'The values in the two objects must be different') - - a.obj.echo = "works" - self.assertEqual(a.obj, b.obj, 'The values must be equal') - - def test_copy_no_subclass(self): - - a = local() - setattr(a, 'thing', 42) - b = copy(a) - self.assertEqual(b.thing, 42) - self.assertIsNot(a.__dict__, b.__dict__) - - def test_objects(self): - # Test which failed in the eventlet?! - - a = A({}) - a.path = '123' - b = A({'one': 2}) - b.path = '123' - self.assertEqual(a.path, b.path, 'The values in the two objects must be equal') - - b.path = '321' - - self.assertNotEqual(a.path, b.path, 'The values in the two objects must be different') - - def test_class_attr(self, kind=MyLocal): - mylocal = kind() - self.assertEqual(42, mylocal.CLASS_PROP) - - mylocal.CLASS_PROP = 1 - self.assertEqual(1, mylocal.CLASS_PROP) - self.assertEqual(mylocal.__dict__['CLASS_PROP'], 1) # pylint:disable=unsubscriptable-object - - del mylocal.CLASS_PROP - self.assertEqual(42, mylocal.CLASS_PROP) - - self.assertIs(mylocal, mylocal.desc) - - def test_class_attr_subclass(self): - self.test_class_attr(kind=MyLocalSubclass) - - def test_locals_collected_when_greenlet_dead_but_still_referenced(self): - # https://github.com/gevent/gevent/issues/387 - import gevent - - my_local = MyLocal() - my_local.sentinel = None - greentest.gc_collect_if_needed() - - del created_sentinels[:] - del deleted_sentinels[:] - - def demonstrate_my_local(): - # Get the important parts - getattr(my_local, 'sentinel') - - # Create and reference greenlets - greenlets = [Thread(target=demonstrate_my_local) for _ in range(5)] - for t in greenlets: - t.start() - gevent.sleep() - - self.assertEqual(len(created_sentinels), len(greenlets)) - - for g in greenlets: - assert not g.is_alive() - gevent.sleep() # let the callbacks run - greentest.gc_collect_if_needed() - - # The sentinels should be gone too - self.assertEqual(len(deleted_sentinels), len(greenlets)) - - @greentest.skipOnLibuvOnPyPyOnWin("GC makes this non-deterministic, especially on Windows") - def test_locals_collected_when_unreferenced_even_in_running_greenlet(self): - # In fact only on Windows do we see GC being an issue; - # pypy2 5.0 on macos and travis don't have a problem. - # https://github.com/gevent/gevent/issues/981 - import gevent - import gc - gc.collect() - - count = 1000 - - running_greenlet = None - - def demonstrate_my_local(): - for _ in range(1000): - x = MyLocal() - self.assertIsNotNone(x.sentinel) - x = None - - gc.collect() - gc.collect() - - self.assertEqual(count, len(created_sentinels)) - # They're all dead, even though this greenlet is - # still running - self.assertEqual(count, len(deleted_sentinels)) - - # The links were removed as well. - self.assertFalse(running_greenlet.has_links()) - - - running_greenlet = gevent.spawn(demonstrate_my_local) - gevent.sleep() - running_greenlet.join() - - self.assertEqual(count, len(deleted_sentinels)) - - @greentest.ignores_leakcheck - def test_local_dicts_for_greenlet(self): - import gevent - from gevent.local import all_local_dicts_for_greenlet - - class MyGreenlet(gevent.Greenlet): - results = None - id_x = None - def _run(self): # pylint:disable=method-hidden - x = local() - x.foo = 42 - self.id_x = id(x) - self.results = all_local_dicts_for_greenlet(self) - - g = MyGreenlet() - g.start() - g.join() - self.assertTrue(g.successful, g) - self.assertEqual(g.results, - [((local, g.id_x), {'foo': 42})]) - - def test_local_with_abc(self): - # an ABC (or generally any non-exact-type) in the MRO doesn't - # break things. See https://github.com/gevent/gevent/issues/1201 - - x = LocalWithABC() - x.d = {'a': 1} - self.assertEqual({'a': 1}, x.d) - # The ABC part works - self.assertIn('a', x.d) - self.assertEqual(['a'], list(x.keys())) - - def test_local_with_staticmethod(self): - x = LocalWithStaticMethod() - self.assertEqual(42, x.a_staticmethod()) - - def test_local_with_classmethod(self): - x = LocalWithClassMethod() - self.assertIs(LocalWithClassMethod, x.a_classmethod()) - - -class TestLocalInterface(greentest.TestCase): - __timeout__ = None - - @greentest.ignores_leakcheck - def test_provides(self): - # https://github.com/gevent/gevent/issues/1122 - - # pylint:disable=inherit-non-class - class IFoo(interface.Interface): - pass - - @interface.implementer(IFoo) - class Base(object): - pass - - class Derived(Base, local): - pass - - d = Derived() - p = list(interface.providedBy(d)) - self.assertEqual([IFoo], p) - - - -@greentest.skipOnPurePython("Needs C extension") -class TestCExt(greentest.TestCase): # pragma: no cover - - def test_c_extension(self): - self.assertEqual(local.__module__, - 'gevent._gevent_clocal') - -@greentest.skipWithCExtensions("Needs pure-python") -class TestPure(greentest.TestCase): - - def test_extension(self): - self.assertEqual(local.__module__, - 'gevent.local') - - -if __name__ == '__main__': - greentest.main() diff --git a/venv/lib/python3.9/site-packages/gevent/tests/test__lock.py b/venv/lib/python3.9/site-packages/gevent/tests/test__lock.py deleted file mode 100644 index 9dd37ea..0000000 --- a/venv/lib/python3.9/site-packages/gevent/tests/test__lock.py +++ /dev/null @@ -1,78 +0,0 @@ -from gevent import lock - - -import gevent.testing as greentest -from gevent.tests import test__semaphore - - -class TestRLockMultiThread(test__semaphore.TestSemaphoreMultiThread): - - def _makeOne(self): - # If we don't set the hub before returning, - # there's a potential race condition, if the implementation - # isn't careful. If it's the background hub that winds up capturing - # the hub, it will ask the hub to switch back to itself and - # then switch to the hub, which will raise LoopExit (nothing - # for the background thread to do). What is supposed to happen - # is that the background thread realizes it's the background thread, - # starts an async watcher and then switches to the hub. - # - # So we deliberately don't set the hub to help test that condition. - return lock.RLock() - - def assertOneHasNoHub(self, sem): - self.assertIsNone(sem._block.hub) - - -class TestLockReinitAfterFork(greentest.TestCase): - - def test_it(self): - # See https://github.com/gevent/gevent/issues/1895 - - # Make sure we carefully handle forking while running callbacks - # of a lock/_AbstractLinkable object. - import sys - import subprocess - import textwrap - import os - - if not hasattr(os, 'fork'): - self.skipTest('Requires os.fork') - - script =textwrap.dedent("""\ - from gevent import monkey - monkey.patch_all() - - from gevent import spawn - - import os - from logging import Handler - from threading import Event - handler = Handler() - handler.acquire() - - event = Event() - - def forker(): - event.set() - handler.acquire() - handler.release() - os.fork() - - g = spawn(forker) - event.wait() - handler.release() - g.join() - """) - - output = subprocess.check_output( - [sys.executable, '-c', script], - stderr=subprocess.STDOUT, - ).decode('utf-8') - - # We used to print a failing AssertionError to stdout, - # that should no longer be the case. - self.assertFalse(output) - -if __name__ == '__main__': - greentest.main() diff --git a/venv/lib/python3.9/site-packages/gevent/tests/test__loop_callback.py b/venv/lib/python3.9/site-packages/gevent/tests/test__loop_callback.py deleted file mode 100644 index dca0656..0000000 --- a/venv/lib/python3.9/site-packages/gevent/tests/test__loop_callback.py +++ /dev/null @@ -1,18 +0,0 @@ -from gevent import get_hub -from gevent import testing as greentest - -class Test(greentest.TestCase): - def test(self): - count = [0] - - def incr(): - count[0] += 1 - - loop = get_hub().loop - loop.run_callback(incr) - loop.run() - self.assertEqual(count, [1]) - - -if __name__ == '__main__': - greentest.main() diff --git a/venv/lib/python3.9/site-packages/gevent/tests/test__makefile_ref.py b/venv/lib/python3.9/site-packages/gevent/tests/test__makefile_ref.py deleted file mode 100644 index 15cf3c8..0000000 --- a/venv/lib/python3.9/site-packages/gevent/tests/test__makefile_ref.py +++ /dev/null @@ -1,553 +0,0 @@ -from __future__ import print_function -import os -from gevent import monkey; monkey.patch_all() -import socket -import ssl -import threading -import errno - - -import gevent.testing as greentest -from gevent.testing.params import DEFAULT_BIND_ADDR_TUPLE -from gevent.testing.params import DEFAULT_CONNECT -from gevent.testing.sockets import tcp_listener - -dirname = os.path.dirname(os.path.abspath(__file__)) -CERTFILE = os.path.join(dirname, '2_7_keycert.pem') -pid = os.getpid() - -PYPY = greentest.PYPY -CPYTHON = not PYPY -fd_types = int - -WIN = greentest.WIN - -from gevent.testing import get_open_files -try: - import psutil -except ImportError: - psutil = None - -# wrap_socket() is considered deprecated in 3.9 -# pylint:disable=deprecated-method - -class Test(greentest.TestCase): - - extra_allowed_open_states = () - - def tearDown(self): - self.extra_allowed_open_states = () - super(Test, self).tearDown() - - def assert_raises_EBADF(self, func): - try: - result = func() - except OSError as ex: - # Windows/Py3 raises "OSError: [WinError 10038]" - if ex.args[0] == errno.EBADF: - return - if WIN and ex.args[0] == 10038: - return - raise - raise AssertionError('NOT RAISED EBADF: %r() returned %r' % (func, result)) - - if WIN or (PYPY and greentest.LINUX): - def __assert_fd_open(self, fileno): - # We can't detect open file descriptors on Windows. - # On PyPy 3.6-7.3 on Travis CI (linux), for some reason the - # client file descriptors don't always show as open. Don't know why, - # was fine in 7.2. - # On March 23 2020 we had to pin psutil back to a version - # for PyPy 2 (see setup.py) and this same problem started happening there. - # PyPy on macOS was unaffected. - pass - else: - def __assert_fd_open(self, fileno): - assert isinstance(fileno, fd_types) - open_files = get_open_files() - if fileno not in open_files: - raise AssertionError('%r is not open:\n%s' % (fileno, open_files['data'])) - - def assert_fd_closed(self, fileno): - assert isinstance(fileno, fd_types), repr(fileno) - assert fileno > 0, fileno - # Here, if we're in the process of closing, don't consider it open. - # This goes into details of psutil - open_files = get_open_files(count_closing_as_open=False) - if fileno in open_files: - raise AssertionError('%r is not closed:\n%s' % (fileno, open_files['data'])) - - def _assert_sock_open(self, sock): - # requires the psutil output - open_files = get_open_files() - sockname = sock.getsockname() - for x in open_files['data']: - if getattr(x, 'laddr', None) == sockname: - assert x.status in (psutil.CONN_LISTEN, psutil.CONN_ESTABLISHED) + self.extra_allowed_open_states, x.status - return - raise AssertionError("%r is not open:\n%s" % (sock, open_files['data'])) - - def assert_open(self, sock, *rest): - if isinstance(sock, fd_types): - self.__assert_fd_open(sock) - else: - fileno = sock.fileno() - assert isinstance(fileno, fd_types), fileno - sockname = sock.getsockname() - assert isinstance(sockname, tuple), sockname - if not WIN: - self.__assert_fd_open(fileno) - else: - self._assert_sock_open(sock) - if rest: - self.assert_open(rest[0], *rest[1:]) - - def assert_closed(self, sock, *rest): - if isinstance(sock, fd_types): - self.assert_fd_closed(sock) - else: - # Under Python3, the socket module returns -1 for a fileno - # of a closed socket; under Py2 it raises - self.assertEqual(sock.fileno(), -1) - self.assert_raises_EBADF(sock.getsockname) - self.assert_raises_EBADF(sock.accept) - if rest: - self.assert_closed(rest[0], *rest[1:]) - - def make_open_socket(self): - s = socket.socket() - try: - s.bind(DEFAULT_BIND_ADDR_TUPLE) - if WIN or greentest.LINUX: - # Windows and linux (with psutil) doesn't show as open until - # we call listen (linux with lsof accepts either) - s.listen(1) - self.assert_open(s, s.fileno()) - except: - s.close() - s = None - raise - return s - -# Sometimes its this one, sometimes it's test_ssl. No clue why or how. -@greentest.skipOnAppVeyor("This sometimes times out for no apparent reason.") -class TestSocket(Test): - - def test_simple_close(self): - with Closing() as closer: - s = closer(self.make_open_socket()) - fileno = s.fileno() - s.close() - self.assert_closed(s, fileno) - - def test_makefile1(self): - with Closing() as closer: - s = closer(self.make_open_socket()) - fileno = s.fileno() - f = closer(s.makefile()) - - self.assert_open(s, fileno) - # Under python 2, this closes socket wrapper object but not the file descriptor; - # under python 3, both stay open - s.close() - self.assert_open(s, fileno) - - f.close() - self.assert_closed(s) - self.assert_closed(fileno) - - def test_makefile2(self): - with Closing() as closer: - s = closer(self.make_open_socket()) - fileno = s.fileno() - self.assert_open(s, fileno) - f = closer(s.makefile()) - self.assert_open(s) - self.assert_open(s, fileno) - f.close() - # closing fileobject does not close the socket - self.assert_open(s, fileno) - s.close() - self.assert_closed(s, fileno) - - def test_server_simple(self): - with Closing() as closer: - listener = closer(tcp_listener(backlog=1)) - port = listener.getsockname()[1] - - connector = closer(socket.socket()) - - def connect(): - connector.connect((DEFAULT_CONNECT, port)) - - closer.running_task(threading.Thread(target=connect)) - - client_socket = closer.accept(listener) - fileno = client_socket.fileno() - self.assert_open(client_socket, fileno) - client_socket.close() - self.assert_closed(client_socket) - - def test_server_makefile1(self): - with Closing() as closer: - listener = closer(tcp_listener(backlog=1)) - port = listener.getsockname()[1] - - connector = closer(socket.socket()) - - def connect(): - connector.connect((DEFAULT_CONNECT, port)) - - closer.running_task(threading.Thread(target=connect)) - - - client_socket = closer.accept(listener) - fileno = client_socket.fileno() - f = closer(client_socket.makefile()) - self.assert_open(client_socket, fileno) - client_socket.close() - # Under python 2, this closes socket wrapper object but not the file descriptor; - # under python 3, both stay open - self.assert_open(client_socket, fileno) - - f.close() - self.assert_closed(client_socket, fileno) - - def test_server_makefile2(self): - with Closing() as closer: - listener = closer(tcp_listener(backlog=1)) - port = listener.getsockname()[1] - - connector = closer(socket.socket()) - - def connect(): - connector.connect((DEFAULT_CONNECT, port)) - - closer.running_task(threading.Thread(target=connect)) - client_socket = closer.accept(listener) - - fileno = client_socket.fileno() - f = closer(client_socket.makefile()) - self.assert_open(client_socket, fileno) - # closing fileobject does not close the socket - f.close() - self.assert_open(client_socket, fileno) - client_socket.close() - self.assert_closed(client_socket, fileno) - - -@greentest.skipOnAppVeyor("This sometimes times out for no apparent reason.") -class TestSSL(Test): - - - def _ssl_connect_task(self, connector, port, accepted_event): - connector.connect((DEFAULT_CONNECT, port)) - - try: - # Note: We get ResourceWarning about 'x' - # on Python 3 if we don't join the spawned thread - ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT) - ctx.check_hostname = False - ctx.verify_mode = ssl.CERT_NONE - x = ctx.wrap_socket(connector) - # Wait to be fully accepted. We could otherwise raise ahead - # of the server and close ourself before it's ready to read. - accepted_event.wait() - except socket.error: - # Observed on Windows with PyPy2 5.9.0 and libuv: - # if we don't switch in a timely enough fashion, - # the server side runs ahead of us and closes - # our socket first, so this fails. - pass - else: - x.close() - - def _make_ssl_connect_task(self, connector, port): - accepted_event = threading.Event() - t = threading.Thread(target=self._ssl_connect_task, - args=(connector, port, accepted_event)) - t.daemon = True - t.accepted_event = accepted_event - return t - - def test_simple_close(self): - with Closing() as closer: - s = closer(self.make_open_socket()) - fileno = s.fileno() - ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT) - ctx.check_hostname = False - ctx.verify_mode = ssl.CERT_NONE - s = closer(ctx.wrap_socket(s)) - fileno = s.fileno() - self.assert_open(s, fileno) - s.close() - self.assert_closed(s, fileno) - - def test_makefile1(self): - with Closing() as closer: - raw_s = closer(self.make_open_socket()) - s = closer(ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER).wrap_socket(raw_s)) - - fileno = s.fileno() - self.assert_open(s, fileno) - f = closer(s.makefile()) - self.assert_open(s, fileno) - s.close() - self.assert_open(s, fileno) - f.close() - raw_s.close() - self.assert_closed(s, fileno) - - def test_makefile2(self): - with Closing() as closer: - s = closer(self.make_open_socket()) - fileno = s.fileno() - - s = closer(ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER).wrap_socket(s)) - fileno = s.fileno() - self.assert_open(s, fileno) - f = closer(s.makefile()) - self.assert_open(s, fileno) - f.close() - # closing fileobject does not close the socket - self.assert_open(s, fileno) - s.close() - self.assert_closed(s, fileno) - - def _wrap_socket(self, sock, *, keyfile, certfile, server_side=False): - context = ssl.SSLContext( - ssl.PROTOCOL_TLS_SERVER - if server_side - else ssl.PROTOCOL_TLS_CLIENT - ) - context.check_hostname = False - context.verify_mode = ssl.CERT_NONE - context.load_cert_chain(certfile=certfile, keyfile=keyfile) - return context.wrap_socket(sock, server_side=server_side) - - def test_server_simple(self): - with Closing() as closer: - listener = closer(tcp_listener(backlog=1)) - port = listener.getsockname()[1] - - connector = closer(socket.socket()) - - t = self._make_ssl_connect_task(connector, port) - closer.running_task(t) - - client_socket = closer.accept(listener) - t.accepted_event.set() - client_socket = closer( - self._wrap_socket(client_socket, keyfile=CERTFILE, certfile=CERTFILE, - server_side=True)) - fileno = client_socket.fileno() - self.assert_open(client_socket, fileno) - client_socket.close() - self.assert_closed(client_socket, fileno) - - def test_server_makefile1(self): - with Closing() as closer: - listener = closer(tcp_listener(backlog=1)) - port = listener.getsockname()[1] - - connector = closer(socket.socket()) - - t = self._make_ssl_connect_task(connector, port) - closer.running_task(t) - - client_socket = closer.accept(listener) - t.accepted_event.set() - client_socket = closer( - self._wrap_socket(client_socket, keyfile=CERTFILE, certfile=CERTFILE, - server_side=True)) - fileno = client_socket.fileno() - self.assert_open(client_socket, fileno) - f = client_socket.makefile() - self.assert_open(client_socket, fileno) - client_socket.close() - self.assert_open(client_socket, fileno) - f.close() - self.assert_closed(client_socket, fileno) - - def test_server_makefile2(self): - with Closing() as closer: - listener = closer(tcp_listener(backlog=1)) - port = listener.getsockname()[1] - - connector = closer(socket.socket()) - t = self._make_ssl_connect_task(connector, port) - closer.running_task(t) - - t.accepted_event.set() - client_socket = closer.accept(listener) - client_socket = closer( - self._wrap_socket(client_socket, keyfile=CERTFILE, certfile=CERTFILE, - server_side=True)) - - fileno = client_socket.fileno() - self.assert_open(client_socket, fileno) - f = client_socket.makefile() - self.assert_open(client_socket, fileno) - # Closing fileobject does not close SSLObject - f.close() - self.assert_open(client_socket, fileno) - client_socket.close() - self.assert_closed(client_socket, fileno) - - def test_serverssl_makefile1(self): - raw_listener = tcp_listener(backlog=1) - fileno = raw_listener.fileno() - port = raw_listener.getsockname()[1] - listener = self._wrap_socket(raw_listener, keyfile=CERTFILE, certfile=CERTFILE, - server_side=True) - - connector = socket.socket() - t = self._make_ssl_connect_task(connector, port) - t.start() - - with CleaningUp(t, listener, raw_listener, connector) as client_socket: - t.accepted_event.set() - fileno = client_socket.fileno() - self.assert_open(client_socket, fileno) - f = client_socket.makefile() - self.assert_open(client_socket, fileno) - client_socket.close() - self.assert_open(client_socket, fileno) - f.close() - self.assert_closed(client_socket, fileno) - - def test_serverssl_makefile2(self): - raw_listener = tcp_listener(backlog=1) - port = raw_listener.getsockname()[1] - listener = self._wrap_socket(raw_listener, keyfile=CERTFILE, certfile=CERTFILE, - server_side=True) - - accepted_event = threading.Event() - read_event = threading.Event() - def connect(connector=socket.socket()): - try: - connector.connect((DEFAULT_CONNECT, port)) - ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT) - ctx.check_hostname = False - ctx.verify_mode = ssl.CERT_NONE - s = ctx.wrap_socket(connector) - accepted_event.wait() - s.sendall(b'test_serverssl_makefile2') - s.shutdown(socket.SHUT_RDWR) - read_event.wait() - s.close() - finally: - connector.close() - - t = threading.Thread(target=connect) - t.daemon = True - t.start() - client_socket = None - with CleaningUp(t, listener, raw_listener) as client_socket: - accepted_event.set() - fileno = client_socket.fileno() - self.assert_open(client_socket, fileno) - f = client_socket.makefile() - self.assert_open(client_socket, fileno) - self.assertEqual(f.read(), 'test_serverssl_makefile2') - # Closing the other end of the socket - # before we finish reading can result in us - # getting EPIPE from OpenSSL 3.5 on certain - # systems, notably the manylinux images on Github - # actions. This hasn't shown up anywhere else. - read_event.set() - self.assertEqual(f.read(), '') - # Closing file object does not close the socket. - f.close() - if WIN and psutil: - # Hmm? - self.extra_allowed_open_states = (psutil.CONN_CLOSE_WAIT,) - - self.assert_open(client_socket, fileno) - client_socket.close() - self.assert_closed(client_socket, fileno) - - -class Closing(object): - - def __init__(self, *init): - self._objects = [] - for i in init: - self.closing(i) - self.task = None - - def accept(self, listener): - client_socket, _addr = listener.accept() - return self.closing(client_socket) - - def __enter__(self): - o = self.objects() - if len(o) == 1: - return o[0] - return self - - def objects(self): - # PyPy returns an object without __len__... - return list(reversed(self._objects)) - - def closing(self, o): - self._objects.append(o) - return o - - __call__ = closing - - def running_task(self, thread): - assert self.task is None - self.task = thread - self.task.start() - return self.task - - def __exit__(self, t, v, tb): - # workaround for test_server_makefile1, test_server_makefile2, - # test_server_simple, test_serverssl_makefile1. - - # On PyPy on Linux, it is important to join the SSL Connect - # Task FIRST, before closing the sockets. If we do it after - # (which makes more sense) we hang. It's not clear why, except - # that it has something to do with context switches. Inserting a call to - # gevent.sleep(0.1) instead of joining the task has the same - # effect. If the previous tests hang, then later tests can fail with - # SSLError: unknown alert type. - - # XXX: Why do those two things happen? - - # On PyPy on macOS, we don't have that problem and can use the - # more logical order. - try: - if self.task is not None: - self.task.join() - finally: - self.task = None - for o in self.objects(): - try: - o.close() - except Exception: # pylint:disable=broad-except - pass - - self._objects = () - -class CleaningUp(Closing): - - def __init__(self, task, listener, *other_sockets): - super(CleaningUp, self).__init__(listener, *other_sockets) - self.task = task - self.listener = listener - - def __enter__(self): - return self.accept(self.listener) - - def __exit__(self, t, v, tb): - try: - Closing.__exit__(self, t, v, tb) - finally: - self.listener = None - - - -if __name__ == '__main__': - greentest.main() diff --git a/venv/lib/python3.9/site-packages/gevent/tests/test__memleak.py b/venv/lib/python3.9/site-packages/gevent/tests/test__memleak.py deleted file mode 100644 index 408a748..0000000 --- a/venv/lib/python3.9/site-packages/gevent/tests/test__memleak.py +++ /dev/null @@ -1,47 +0,0 @@ -import sys -import unittest - -from gevent.testing import TestCase -import gevent -from gevent.timeout import Timeout - -@unittest.skipUnless( - hasattr(sys, 'gettotalrefcount'), - "Needs debug build" -) -# XXX: This name makes no sense. What was this for originally? -class TestQueue(TestCase): # pragma: no cover - # pylint:disable=bare-except,no-member - - def test(self): - - refcounts = [] - for _ in range(15): - try: - Timeout.start_new(0.01) - gevent.sleep(0.1) - self.fail('must raise Timeout') - except Timeout: - pass - refcounts.append(sys.gettotalrefcount()) - - # Refcounts may go down, but not up - # XXX: JAM: I think this may just be broken. Each time we add - # a new integer to our list of refcounts, we'll be - # creating a new reference. This makes sense when we see the list - # go up by one each iteration: - # - # AssertionError: 530631 not less than or equal to 530630 - # : total refcount mismatch: - # [530381, 530618, 530619, 530620, 530621, - # 530622, 530623, 530624, 530625, 530626, - # 530627, 530628, 530629, 530630, 530631] - final = refcounts[-1] - previous = refcounts[-2] - self.assertLessEqual( - final, previous, - "total refcount mismatch: %s" % refcounts) - - -if __name__ == '__main__': - unittest.main() diff --git a/venv/lib/python3.9/site-packages/gevent/tests/test__monkey.py b/venv/lib/python3.9/site-packages/gevent/tests/test__monkey.py deleted file mode 100644 index b8747f2..0000000 --- a/venv/lib/python3.9/site-packages/gevent/tests/test__monkey.py +++ /dev/null @@ -1,165 +0,0 @@ -from gevent import monkey -monkey.patch_all() - -import sys -import unittest -from gevent.testing.testcase import SubscriberCleanupMixin - -class TestMonkey(SubscriberCleanupMixin, unittest.TestCase): - - maxDiff = None - - def setUp(self): - super(TestMonkey, self).setUp() - - self.all_events = [] - self.addSubscriber(self.all_events.append) - self.orig_saved = orig_saved = {} - for k, v in monkey.saved.items(): - orig_saved[k] = v.copy() - - - def tearDown(self): - monkey.saved = self.orig_saved - del self.orig_saved - del self.all_events - super(TestMonkey, self).tearDown() - - def test_time(self): - import time - from gevent import time as gtime - self.assertIs(time.sleep, gtime.sleep) - - def test_thread(self): - import _thread as thread - import threading - - from gevent import thread as gthread - self.assertIs(thread.start_new_thread, gthread.start_new_thread) - if sys.version_info[:2] < (3, 13): - self.assertIs(threading._start_new_thread, gthread.start_new_thread) - else: - self.assertIs(threading._start_joinable_thread, gthread.start_joinable_thread) - - # Event patched by default - self.assertTrue(monkey.is_object_patched('threading', 'Event')) - - if sys.version_info[0] == 2: - from gevent import threading as gthreading - from gevent.event import Event as GEvent - self.assertIs(threading._sleep, gthreading._sleep) - self.assertTrue(monkey.is_object_patched('threading', '_Event')) - self.assertIs(threading._Event, GEvent) - - def test_socket(self): - import socket - from gevent import socket as gevent_socket - self.assertIs(socket.create_connection, gevent_socket.create_connection) - - def test_os(self): - import os - import types - from gevent import os as gos - for name in ('fork', 'forkpty'): - if hasattr(os, name): - attr = getattr(os, name) - self.assertNotIn('built-in', repr(attr)) - self.assertNotIsInstance(attr, types.BuiltinFunctionType) - self.assertIsInstance(attr, types.FunctionType) - self.assertIs(attr, getattr(gos, name)) - - def test_saved(self): - self.assertTrue(monkey.saved) - for modname, objects in monkey.saved.items(): - self.assertTrue(monkey.is_module_patched(modname)) - - for objname in objects: - self.assertTrue(monkey.is_object_patched(modname, objname)) - - def test_patch_subprocess_twice(self): - Popen = monkey.get_original('subprocess', 'Popen') - self.assertNotIn('gevent', repr(Popen)) - self.assertIs(Popen, monkey.get_original('subprocess', 'Popen')) - monkey.patch_subprocess() - self.assertIs(Popen, monkey.get_original('subprocess', 'Popen')) - - def test_patch_twice_warnings_events(self): - import warnings - - all_events = self.all_events - - with warnings.catch_warnings(record=True) as issued_warnings: - # Patch again, triggering just one warning, for - # a different set of arguments. Because we're going to False instead of - # turning something on, nothing is actually done, no events are issued. - monkey.patch_all(os=False, extra_kwarg=42) - self.assertEqual(len(issued_warnings), 1) - self.assertIn('more than once', str(issued_warnings[0].message)) - self.assertEqual(all_events, []) - - # Same warning again, but still nothing is done. - del issued_warnings[:] - monkey.patch_all(os=False) - self.assertEqual(len(issued_warnings), 1) - self.assertIn('more than once', str(issued_warnings[0].message)) - self.assertEqual(all_events, []) - self.orig_saved['_gevent_saved_patch_all_module_settings'] = monkey.saved[ - '_gevent_saved_patch_all_module_settings'] - - # Make sure that re-patching did not change the monkey.saved - # attribute, overwriting the original functions. - if 'logging' in monkey.saved and 'logging' not in self.orig_saved: - # some part of the warning or unittest machinery imports logging - self.orig_saved['logging'] = monkey.saved['logging'] - self.assertEqual(self.orig_saved, monkey.saved) - - # Make sure some problematic attributes stayed correct. - # NOTE: This was only a problem if threading was not previously imported. - for k, v in monkey.saved['threading'].items(): - self.assertNotIn('gevent', str(v), (k, v)) - - def test_patch_events(self): - from gevent import events - from gevent.testing import verify - all_events = self.all_events - - def veto(event): - if isinstance(event, events.GeventWillPatchModuleEvent) and event.module_name == 'ssl': - raise events.DoNotPatch - self.addSubscriber(veto) - - monkey.saved = {} # Reset - monkey.patch_all(thread=False, select=False, extra_kwarg=42) # Go again - - self.assertIsInstance(all_events[0], events.GeventWillPatchAllEvent) - self.assertEqual({'extra_kwarg': 42}, all_events[0].patch_all_kwargs) - verify.verifyObject(events.IGeventWillPatchAllEvent, all_events[0]) - - self.assertIsInstance(all_events[1], events.GeventWillPatchModuleEvent) - verify.verifyObject(events.IGeventWillPatchModuleEvent, all_events[1]) - - self.assertIsInstance(all_events[2], events.GeventDidPatchModuleEvent) - verify.verifyObject(events.IGeventWillPatchModuleEvent, all_events[1]) - - self.assertIsInstance(all_events[-2], events.GeventDidPatchBuiltinModulesEvent) - verify.verifyObject(events.IGeventDidPatchBuiltinModulesEvent, all_events[-2]) - - self.assertIsInstance(all_events[-1], events.GeventDidPatchAllEvent) - verify.verifyObject(events.IGeventDidPatchAllEvent, all_events[-1]) - - for e in all_events: - self.assertFalse(isinstance(e, events.GeventDidPatchModuleEvent) - and e.module_name == 'ssl') - - def test_patch_queue(self): - import queue - import gevent.queue as gq - - # pylint:disable=no-member - self.assertIs(queue.SimpleQueue, gq.SimpleQueue) - self.assertIs(queue.LifoQueue, gq.LifoQueue) - self.assertIs(queue.Queue, gq.Queue) - self.assertIs(queue.PriorityQueue, gq.PriorityQueue) - -if __name__ == '__main__': - unittest.main() diff --git a/venv/lib/python3.9/site-packages/gevent/tests/test__monkey_builtins_future.py b/venv/lib/python3.9/site-packages/gevent/tests/test__monkey_builtins_future.py deleted file mode 100644 index 599253d..0000000 --- a/venv/lib/python3.9/site-packages/gevent/tests/test__monkey_builtins_future.py +++ /dev/null @@ -1,16 +0,0 @@ -# Under Python 2, if the `future` module is installed, we get -# a `builtins` module, which mimics the `builtins` module from -# Python 3, but does not have the __import__ and some other functions. -# Make sure we can still run in that case. -import sys -try: - # fake out a "broken" builtins module - import builtins -except ImportError: - class builtins(object): - pass - sys.modules['builtins'] = builtins() - -if not hasattr(builtins, '__import__'): - import gevent.monkey - gevent.monkey.patch_builtins() diff --git a/venv/lib/python3.9/site-packages/gevent/tests/test__monkey_hub_in_thread.py b/venv/lib/python3.9/site-packages/gevent/tests/test__monkey_hub_in_thread.py deleted file mode 100644 index 981ca6c..0000000 --- a/venv/lib/python3.9/site-packages/gevent/tests/test__monkey_hub_in_thread.py +++ /dev/null @@ -1,28 +0,0 @@ -from gevent.monkey import patch_all -patch_all(thread=False) -from threading import Thread -import time - -# The first time we init the hub is in the native -# thread with time.sleep(), needing multiple -# threads at the same time. Note: this is very timing -# dependent. -# See #687 - - -def func(): - time.sleep() - - -def main(): - threads = [] - for _ in range(3): - th = Thread(target=func) - th.start() - threads.append(th) - for th in threads: - th.join() - - -if __name__ == '__main__': - main() diff --git a/venv/lib/python3.9/site-packages/gevent/tests/test__monkey_logging.py b/venv/lib/python3.9/site-packages/gevent/tests/test__monkey_logging.py deleted file mode 100644 index 7089444..0000000 --- a/venv/lib/python3.9/site-packages/gevent/tests/test__monkey_logging.py +++ /dev/null @@ -1,57 +0,0 @@ -# If the logging module is imported *before* monkey patching, -# the existing handlers are correctly monkey patched to use gevent locks -import logging -logging.basicConfig() - -import threading - - -def _inner_lock(lock): - try: - return lock._block - except AttributeError: - return None - - -def _check_type(root, lock, inner_semaphore, kind): - if not isinstance(inner_semaphore, kind): - raise AssertionError( - "Expected .[_]lock._block to be of type %s, " - "but it was of type %s.\n" - "\t.[_]lock=%r\n" - "\t.[_]lock._block=%r\n" - "\t=%r" % ( - kind, - type(inner_semaphore), - lock, - inner_semaphore, - root - ) - ) - -def checkLocks(kind, ignore_none=True): - handlers = logging._handlerList - assert handlers - - for weakref in handlers: - # In py26, these are actual handlers, not weakrefs - handler = weakref() if callable(weakref) else weakref - block = _inner_lock(handler.lock) - if block is None and ignore_none: - continue - _check_type(handler, handler.lock, block, kind) - - attr = _inner_lock(logging._lock) - if attr is None and ignore_none: - return - _check_type(logging, logging._lock, attr, kind) - -checkLocks(type(threading._allocate_lock())) - -import gevent.monkey -gevent.monkey.patch_all() - -import gevent.lock -import gevent.thread - -checkLocks(type(gevent.thread.allocate_lock()), ignore_none=False) diff --git a/venv/lib/python3.9/site-packages/gevent/tests/test__monkey_module_run.py b/venv/lib/python3.9/site-packages/gevent/tests/test__monkey_module_run.py deleted file mode 100644 index 5c7d51b..0000000 --- a/venv/lib/python3.9/site-packages/gevent/tests/test__monkey_module_run.py +++ /dev/null @@ -1,127 +0,0 @@ -""" -Tests for running ``gevent.monkey`` as a module to launch a -patched script. - -Uses files in the ``monkey_package/`` directory. -""" -from __future__ import print_function -from __future__ import absolute_import -from __future__ import division - - -import os -import os.path -import sys - -from gevent import testing as greentest -from gevent.testing.util import absolute_pythonpath -from gevent.testing.util import run - -class TestRun(greentest.TestCase): - maxDiff = None - - def setUp(self): - self.abs_pythonpath = absolute_pythonpath() # before we cd - self.cwd = os.getcwd() - os.chdir(os.path.dirname(__file__)) - - def tearDown(self): - os.chdir(self.cwd) - - def _run(self, script, module=False): - env = os.environ.copy() - env['PYTHONWARNINGS'] = 'ignore' - if self.abs_pythonpath: - env['PYTHONPATH'] = self.abs_pythonpath - run_kwargs = dict( - buffer_output=True, - quiet=True, - nested=True, - env=env, - timeout=10, - ) - - args = [sys.executable, '-m', 'gevent.monkey'] - if module: - args.append('--module') - args += [script, 'patched'] - monkey_result = run( - args, - **run_kwargs - ) - self.assertTrue(monkey_result) - - if module: - args = [sys.executable, "-m", script, 'stdlib'] - else: - args = [sys.executable, script, 'stdlib'] - std_result = run( - args, - **run_kwargs - ) - self.assertTrue(std_result) - - monkey_out_lines = monkey_result.output_lines - std_out_lines = std_result.output_lines - self.assertEqual(monkey_out_lines, std_out_lines) - self.assertEqual(monkey_result.error, std_result.error) - - return monkey_out_lines - - def test_run_simple(self): - self._run(os.path.join('monkey_package', 'script.py')) - - def _run_package(self, module): - lines = self._run('monkey_package', module=module) - - self.assertTrue(lines[0].endswith(u'__main__.py'), lines[0]) - self.assertEqual(lines[1].strip(), u'__main__') - - def test_run_package(self): - # Run a __main__ inside a package, even without specifying -m - self._run_package(module=False) - - def test_run_module(self): - # Run a __main__ inside a package, when specifying -m - self._run_package(module=True) - - def test_issue_302(self): - monkey_lines = self._run(os.path.join('monkey_package', 'issue302monkey.py')) - - self.assertEqual(monkey_lines[0].strip(), u'True') - monkey_lines[1] = monkey_lines[1].replace(u'\\', u'/') # windows path - self.assertTrue(monkey_lines[1].strip().endswith(u'monkey_package/issue302monkey.py')) - self.assertEqual(monkey_lines[2].strip(), u'True', monkey_lines) - - # These three tests all sometimes fail on Py2 on CI, writing - # to stderr: - # Unhandled exception in thread started by \n - # sys.excepthook is missing\n - # lost sys.stderr\n - # Fatal Python error: PyImport_GetModuleDict: no module dictionary!\n' - # I haven't been able to produce this locally on macOS or Linux. - # The last line seems new with 2.7.17? - # Also, occasionally, they get '3' instead of '2' for the number of threads. - # That could have something to do with...? Most commonly that's PyPy, but - # sometimes CPython. Again, haven't reproduced. - # Not relevant since Py2 has been dropped. - def test_threadpool_in_patched_after_patch(self): - # Issue 1484 - # If we don't have this correct, then we get exceptions - out = self._run(os.path.join('monkey_package', 'threadpool_monkey_patches.py')) - self.assertEqual(out, ['False', '2']) - - def test_threadpool_in_patched_after_patch_module(self): - # Issue 1484 - # If we don't have this correct, then we get exceptions - out = self._run('monkey_package.threadpool_monkey_patches', module=True) - self.assertEqual(out, ['False', '2']) - - def test_threadpool_not_patched_after_patch_module(self): - # Issue 1484 - # If we don't have this correct, then we get exceptions - out = self._run('monkey_package.threadpool_no_monkey', module=True) - self.assertEqual(out, ['False', 'False', '2']) - -if __name__ == '__main__': - greentest.main() diff --git a/venv/lib/python3.9/site-packages/gevent/tests/test__monkey_multiple_imports.py b/venv/lib/python3.9/site-packages/gevent/tests/test__monkey_multiple_imports.py deleted file mode 100644 index 576062e..0000000 --- a/venv/lib/python3.9/site-packages/gevent/tests/test__monkey_multiple_imports.py +++ /dev/null @@ -1,6 +0,0 @@ -# https://github.com/gevent/gevent/issues/615 -# Under Python 3, with its use of importlib, -# if the monkey patch is done when the importlib import lock is held -# (e.g., during recursive imports) we could fail to release the lock. -# This is surprisingly common. -__import__('_import_import_patch') diff --git a/venv/lib/python3.9/site-packages/gevent/tests/test__monkey_queue.py b/venv/lib/python3.9/site-packages/gevent/tests/test__monkey_queue.py deleted file mode 100644 index f240abf..0000000 --- a/venv/lib/python3.9/site-packages/gevent/tests/test__monkey_queue.py +++ /dev/null @@ -1,331 +0,0 @@ -# Some simple queue module tests, plus some failure conditions -# to ensure the Queue locks remain stable. -from gevent import monkey -monkey.patch_all() - -from gevent import queue as Queue -import threading -import time -import unittest - - -QUEUE_SIZE = 5 - -# A thread to run a function that unclogs a blocked Queue. -class _TriggerThread(threading.Thread): - def __init__(self, fn, args): - self.fn = fn - self.args = args - #self.startedEvent = threading.Event() - from gevent.event import Event - self.startedEvent = Event() - threading.Thread.__init__(self) - - def run(self): - # The sleep isn't necessary, but is intended to give the blocking - # function in the main thread a chance at actually blocking before - # we unclog it. But if the sleep is longer than the timeout-based - # tests wait in their blocking functions, those tests will fail. - # So we give them much longer timeout values compared to the - # sleep here (I aimed at 10 seconds for blocking functions -- - # they should never actually wait that long - they should make - # progress as soon as we call self.fn()). - time.sleep(0.01) - self.startedEvent.set() - self.fn(*self.args) - - -# Execute a function that blocks, and in a separate thread, a function that -# triggers the release. Returns the result of the blocking function. Caution: -# block_func must guarantee to block until trigger_func is called, and -# trigger_func must guarantee to change queue state so that block_func can make -# enough progress to return. In particular, a block_func that just raises an -# exception regardless of whether trigger_func is called will lead to -# timing-dependent sporadic failures, and one of those went rarely seen but -# undiagnosed for years. Now block_func must be unexceptional. If block_func -# is supposed to raise an exception, call do_exceptional_blocking_test() -# instead. - -class BlockingTestMixin(object): - - def do_blocking_test(self, block_func, block_args, trigger_func, trigger_args): - self.t = _TriggerThread(trigger_func, trigger_args) - self.t.start() - self.result = block_func(*block_args) - # If block_func returned before our thread made the call, we failed! - if not self.t.startedEvent.isSet(): - self.fail("blocking function '%r' appeared not to block" % - block_func) - self.t.join(10) # make sure the thread terminates - if self.t.is_alive(): - self.fail("trigger function '%r' appeared to not return" % - trigger_func) - return self.result - - # Call this instead if block_func is supposed to raise an exception. - def do_exceptional_blocking_test(self, block_func, block_args, trigger_func, - trigger_args, expected_exception_class): - self.t = _TriggerThread(trigger_func, trigger_args) - self.t.start() - try: - with self.assertRaises(expected_exception_class): - block_func(*block_args) - finally: - self.t.join(10) # make sure the thread terminates - if self.t.is_alive(): - self.fail("trigger function '%r' appeared to not return" % - trigger_func) - if not self.t.startedEvent.isSet(): - self.fail("trigger thread ended but event never set") - - -class BaseQueueTest(unittest.TestCase, BlockingTestMixin): - type2test = Queue.Queue - - def setUp(self): - self.cum = 0 - self.cumlock = threading.Lock() - - def simple_queue_test(self, q): - if not q.empty(): - raise RuntimeError("Call this function with an empty queue") - # I guess we better check things actually queue correctly a little :) - q.put(111) - q.put(333) - q.put(222) - q.put(444) - target_first_items = dict( - Queue=111, - LifoQueue=444, - PriorityQueue=111) - actual_first_item = (q.peek(), q.get()) - self.assertEqual(actual_first_item, - (target_first_items[q.__class__.__name__], - target_first_items[q.__class__.__name__]), - "q.peek() and q.get() are not equal!") - target_order = dict(Queue=[333, 222, 444], - LifoQueue=[222, 333, 111], - PriorityQueue=[222, 333, 444]) - actual_order = [q.get(), q.get(), q.get()] - self.assertEqual(actual_order, target_order[q.__class__.__name__], - "Didn't seem to queue the correct data!") - for i in range(QUEUE_SIZE-1): - q.put(i) - self.assertFalse(q.empty(), "Queue should not be empty") - self.assertFalse(q.full(), "Queue should not be full") - q.put(999) - self.assertTrue(q.full(), "Queue should be full") - try: - q.put(888, block=0) - self.fail("Didn't appear to block with a full queue") - except Queue.Full: - pass - try: - q.put(888, timeout=0.01) - self.fail("Didn't appear to time-out with a full queue") - except Queue.Full: - pass - self.assertEqual(q.qsize(), QUEUE_SIZE) - # Test a blocking put - self.do_blocking_test(q.put, (888,), q.get, ()) - self.do_blocking_test(q.put, (888, True, 10), q.get, ()) - # Empty it - for i in range(QUEUE_SIZE): - q.get() - self.assertTrue(q.empty(), "Queue should be empty") - try: - q.get(block=0) - self.fail("Didn't appear to block with an empty queue") - except Queue.Empty: - pass - try: - q.get(timeout=0.01) - self.fail("Didn't appear to time-out with an empty queue") - except Queue.Empty: - pass - # Test a blocking get - self.do_blocking_test(q.get, (), q.put, ('empty',)) - self.do_blocking_test(q.get, (True, 10), q.put, ('empty',)) - - def worker(self, q): - while True: - x = q.get() - if x is None: - q.task_done() - return - #with self.cumlock: - self.cum += x - q.task_done() - - def queue_join_test(self, q): - self.cum = 0 - for i in (0, 1): - threading.Thread(target=self.worker, args=(q,)).start() - for i in range(100): - q.put(i) - q.join() - self.assertEqual(self.cum, sum(range(100)), - "q.join() did not block until all tasks were done") - for i in (0, 1): - q.put(None) # instruct the threads to close - q.join() # verify that you can join twice - - def test_queue_task_done(self): - # Test to make sure a queue task completed successfully. - q = Queue.JoinableQueue() # self.type2test() - # XXX the same test in subclasses - try: - q.task_done() - except ValueError: - pass - else: - self.fail("Did not detect task count going negative") - - def test_queue_join(self): - # Test that a queue join()s successfully, and before anything else - # (done twice for insurance). - q = Queue.JoinableQueue() # self.type2test() - # XXX the same test in subclass - self.queue_join_test(q) - self.queue_join_test(q) - try: - q.task_done() - except ValueError: - pass - else: - self.fail("Did not detect task count going negative") - - def test_queue_task_done_with_items(self): - # Passing items to the constructor allows for as - # many task_done calls. Joining before all the task done - # are called returns false - # XXX the same test in subclass - l = [1, 2, 3] - q = Queue.JoinableQueue(items=l) - for i in l: - self.assertFalse(q.join(timeout=0.001)) - self.assertEqual(i, q.get()) - q.task_done() - - try: - q.task_done() - except ValueError: - pass - else: - self.fail("Did not detect task count going negative") - self.assertTrue(q.join(timeout=0.001)) - - def test_simple_queue(self): - # Do it a couple of times on the same queue. - # Done twice to make sure works with same instance reused. - q = self.type2test(QUEUE_SIZE) - self.simple_queue_test(q) - self.simple_queue_test(q) - -class LifoQueueTest(BaseQueueTest): - type2test = Queue.LifoQueue - -class PriorityQueueTest(BaseQueueTest): - type2test = Queue.PriorityQueue - - def test__init(self): - item1 = (2, 'b') - item2 = (1, 'a') - q = self.type2test(items=[item1, item2]) - self.assertTupleEqual(item2, q.get_nowait()) - self.assertTupleEqual(item1, q.get_nowait()) - - -# A Queue subclass that can provoke failure at a moment's notice :) -class FailingQueueException(Exception): - pass - -class FailingQueue(Queue.Queue): - def __init__(self, *args): - self.fail_next_put = False - self.fail_next_get = False - Queue.Queue.__init__(self, *args) - def _put(self, item): - if self.fail_next_put: - self.fail_next_put = False - raise FailingQueueException("You Lose") - return Queue.Queue._put(self, item) - def _get(self): - if self.fail_next_get: - self.fail_next_get = False - raise FailingQueueException("You Lose") - return Queue.Queue._get(self) - -class FailingQueueTest(unittest.TestCase, BlockingTestMixin): - - def failing_queue_test(self, q): - if not q.empty(): - raise RuntimeError("Call this function with an empty queue") - for i in range(QUEUE_SIZE-1): - q.put(i) - # Test a failing non-blocking put. - q.fail_next_put = True - with self.assertRaises(FailingQueueException): - q.put("oops", block=0) - - q.fail_next_put = True - with self.assertRaises(FailingQueueException): - q.put("oops", timeout=0.1) - q.put(999) - self.assertTrue(q.full(), "Queue should be full") - # Test a failing blocking put - q.fail_next_put = True - with self.assertRaises(FailingQueueException): - self.do_blocking_test(q.put, (888,), q.get, ()) - - # Check the Queue isn't damaged. - # put failed, but get succeeded - re-add - q.put(999) - # Test a failing timeout put - q.fail_next_put = True - self.do_exceptional_blocking_test(q.put, (888, True, 10), q.get, (), - FailingQueueException) - # Check the Queue isn't damaged. - # put failed, but get succeeded - re-add - q.put(999) - self.assertTrue(q.full(), "Queue should be full") - q.get() - self.assertFalse(q.full(), "Queue should not be full") - q.put(999) - self.assertTrue(q.full(), "Queue should be full") - # Test a blocking put - self.do_blocking_test(q.put, (888,), q.get, ()) - # Empty it - for i in range(QUEUE_SIZE): - q.get() - self.assertTrue(q.empty(), "Queue should be empty") - q.put("first") - q.fail_next_get = True - with self.assertRaises(FailingQueueException): - q.get() - - self.assertFalse(q.empty(), "Queue should not be empty") - q.fail_next_get = True - with self.assertRaises(FailingQueueException): - q.get(timeout=0.1) - self.assertFalse(q.empty(), "Queue should not be empty") - q.get() - self.assertTrue(q.empty(), "Queue should be empty") - q.fail_next_get = True - self.do_exceptional_blocking_test(q.get, (), q.put, ('empty',), - FailingQueueException) - # put succeeded, but get failed. - self.assertFalse(q.empty(), "Queue should not be empty") - q.get() - self.assertTrue(q.empty(), "Queue should be empty") - - def test_failing_queue(self): - # Test to make sure a queue is functioning correctly. - # Done twice to the same instance. - q = FailingQueue(QUEUE_SIZE) - self.failing_queue_test(q) - self.failing_queue_test(q) - - -if __name__ == "__main__": - unittest.main() diff --git a/venv/lib/python3.9/site-packages/gevent/tests/test__monkey_select.py b/venv/lib/python3.9/site-packages/gevent/tests/test__monkey_select.py deleted file mode 100644 index 663afea..0000000 --- a/venv/lib/python3.9/site-packages/gevent/tests/test__monkey_select.py +++ /dev/null @@ -1,32 +0,0 @@ -# Tests for the monkey-patched select module. -from gevent import monkey -monkey.patch_all() - -import select - -import gevent.testing as greentest - - -class TestSelect(greentest.TestCase): - - def _make_test(name, ns): # pylint:disable=no-self-argument - def test(self): - self.assertIs(getattr(select, name, self), self) - self.assertFalse(hasattr(select, name)) - test.__name__ = 'test_' + name + '_removed' - ns[test.__name__] = test - - for name in ( - 'epoll', - 'kqueue', - 'kevent', - 'devpoll', - ): - _make_test(name, locals()) # pylint:disable=too-many-function-args - - del name - del _make_test - - -if __name__ == '__main__': - greentest.main() diff --git a/venv/lib/python3.9/site-packages/gevent/tests/test__monkey_selectors.py b/venv/lib/python3.9/site-packages/gevent/tests/test__monkey_selectors.py deleted file mode 100644 index e7c5afc..0000000 --- a/venv/lib/python3.9/site-packages/gevent/tests/test__monkey_selectors.py +++ /dev/null @@ -1,79 +0,0 @@ - -try: - # Do this before the patch to be sure we clean - # things up properly if the order is wrong. - import selectors -except ImportError: - import selectors2 as selectors - -from gevent.monkey import patch_all -import gevent.testing as greentest - -patch_all() - -from gevent.selectors import DefaultSelector -from gevent.selectors import GeventSelector -from gevent.tests.test__selectors import SelectorTestMixin - -class TestSelectors(SelectorTestMixin, greentest.TestCase): - - @greentest.skipOnWindows( - "SelectSelector._select is a normal function on Windows" - ) - def test_selectors_select_is_patched(self): - # https://github.com/gevent/gevent/issues/835 - _select = selectors.SelectSelector._select - self.assertIn('_gevent_monkey', dir(_select)) - - def test_default(self): - # Depending on the order of imports, gevent.select.poll may be defined but - # selectors.PollSelector may not be defined. - # https://github.com/gevent/gevent/issues/1466 - self.assertIs(DefaultSelector, GeventSelector) - self.assertIs(selectors.DefaultSelector, GeventSelector) - - def test_import_selectors(self): - # selectors can always be imported once monkey-patched. On Python 2, - # this is an alias for gevent.selectors. - __import__('selectors') - - def _make_test(name, kind): # pylint:disable=no-self-argument - if kind is None: - def m(self): - self.skipTest(name + ' is not defined') - else: - def m(self, k=kind): - with k() as sel: - self._check_selector(sel) - m.__name__ = 'test_selector_' + name - return m - - SelKind = SelKindName = None - for SelKindName in ( - # The subclass hierarchy changes between versions, and is - # complex (e.g, BaseSelector <- BaseSelectorImpl <- - # _PollLikSelector <- PollSelector) so its easier to check against - # names. - 'KqueueSelector', - 'EpollSelector', - 'DevpollSelector', - 'PollSelector', - 'SelectSelector', - GeventSelector, - ): - if not isinstance(SelKindName, type): - SelKind = getattr(selectors, SelKindName, None) - else: - SelKind = SelKindName - SelKindName = SelKind.__name__ - m = _make_test(SelKindName, SelKind) # pylint:disable=too-many-function-args - locals()[m.__name__] = m - - del SelKind - del SelKindName - del _make_test - - - -if __name__ == '__main__': - greentest.main() diff --git a/venv/lib/python3.9/site-packages/gevent/tests/test__monkey_sigchld.py b/venv/lib/python3.9/site-packages/gevent/tests/test__monkey_sigchld.py deleted file mode 100644 index fbff0c9..0000000 --- a/venv/lib/python3.9/site-packages/gevent/tests/test__monkey_sigchld.py +++ /dev/null @@ -1,89 +0,0 @@ -import errno -import os -import sys - -import gevent -import gevent.monkey -gevent.monkey.patch_all() - -pid = None -awaiting_child = [] - - -def handle_sigchld(*_args): - # Make sure we can do a blocking operation - gevent.sleep() - # Signal completion - awaiting_child.pop() - # Raise an ignored error - raise TypeError("This should be ignored but printed") - -# Try to produce output compatible with unittest output so -# our status parsing functions work. - -import signal -if hasattr(signal, 'SIGCHLD'): - # In Python 3.8.0 final, on both Travis CI/Linux and locally - # on macOS, the *child* process started crashing on exit with a memory - # error: - # - # Debug memory block at address p=0x7fcf5d6b5000: API '' - # 6508921152173528397 bytes originally requested - # The 7 pad bytes at p-7 are not all FORBIDDENBYTE (0xfd): - # - # When PYTHONDEVMODE is set. This happens even if we just simply fork - # the child process and don't have gevent even /imported/ in the most - # minimal test case. It's not clear what caused that. - if sys.version_info[:2] >= (3, 8) and os.environ.get("PYTHONDEVMODE"): - print("Ran 1 tests in 0.0s (skipped=1)") - sys.exit(0) - - - assert signal.getsignal(signal.SIGCHLD) == signal.SIG_DFL - signal.signal(signal.SIGCHLD, handle_sigchld) - handler = signal.getsignal(signal.SIGCHLD) - assert signal.getsignal(signal.SIGCHLD) is handle_sigchld, handler - - if hasattr(os, 'forkpty'): - def forkpty(): - # For printing in errors - return os.forkpty()[0] - funcs = (os.fork, forkpty) - else: - funcs = (os.fork,) - - for func in funcs: - awaiting_child = [True] - pid = func() - if not pid: - # child - gevent.sleep(0.3) - sys.exit(0) - else: - timeout = gevent.Timeout(1) - try: - while awaiting_child: - gevent.sleep(0.01) - # We should now be able to waitpid() for an arbitrary child - wpid, status = os.waitpid(-1, os.WNOHANG) - if wpid != pid: - raise AssertionError("Failed to wait on a child pid forked with a function", - wpid, pid, func) - - # And a second call should raise ECHILD - try: - wpid, status = os.waitpid(-1, os.WNOHANG) - raise AssertionError("Should not be able to wait again") - except OSError as e: - assert e.errno == errno.ECHILD - except gevent.Timeout as t: - if timeout is not t: - raise - raise AssertionError("Failed to wait using", func) - finally: - timeout.close() - print("Ran 1 tests in 0.0s") - sys.exit(0) -else: - print("No SIGCHLD, not testing") - print("Ran 1 tests in 0.0s (skipped=1)") diff --git a/venv/lib/python3.9/site-packages/gevent/tests/test__monkey_sigchld_2.py b/venv/lib/python3.9/site-packages/gevent/tests/test__monkey_sigchld_2.py deleted file mode 100644 index 51ca4fd..0000000 --- a/venv/lib/python3.9/site-packages/gevent/tests/test__monkey_sigchld_2.py +++ /dev/null @@ -1,57 +0,0 @@ -# Mimics what gunicorn workers do: monkey patch in the child process -# and try to reset signal handlers to SIG_DFL. -# NOTE: This breaks again when gevent.subprocess is used, or any child -# watcher. -import os -import sys - -import signal - -pid = None - -def handle(*_args): - if not pid: - # We only do this is the child so our - # parent's waitpid can get the status. - # This is the opposite of gunicorn. - os.waitpid(-1, os.WNOHANG) -# The signal watcher must be installed *before* monkey patching -if hasattr(signal, 'SIGCHLD'): - if sys.version_info[:2] >= (3, 8) and os.environ.get("PYTHONDEVMODE"): - # See test__monkey_sigchld.py - print("Ran 1 tests in 0.0s (skipped=1)") - sys.exit(0) - - # On Python 2, the signal handler breaks the platform - # module, because it uses os.popen. pkg_resources uses the platform - # module. - # Cache that info. - import platform - platform.uname() - signal.signal(signal.SIGCHLD, handle) - - pid = os.fork() - - if pid: # parent - try: - _, stat = os.waitpid(pid, 0) - except OSError: - # Interrupted system call - _, stat = os.waitpid(pid, 0) - assert stat == 0, stat - else: - # Under Python 2, os.popen() directly uses the popen call, and - # popen's file uses the pclose() system call to - # wait for the child. If it's already waited on, - # it raises the same exception. - # Python 3 uses the subprocess module directly which doesn't - # have this problem. - import gevent.monkey - gevent.monkey.patch_all() - signal.signal(signal.SIGCHLD, signal.SIG_DFL) - f = os.popen('true') - f.close() - - sys.exit(0) -else: - print("No SIGCHLD, not testing") diff --git a/venv/lib/python3.9/site-packages/gevent/tests/test__monkey_sigchld_3.py b/venv/lib/python3.9/site-packages/gevent/tests/test__monkey_sigchld_3.py deleted file mode 100644 index 2060c44..0000000 --- a/venv/lib/python3.9/site-packages/gevent/tests/test__monkey_sigchld_3.py +++ /dev/null @@ -1,59 +0,0 @@ -# Mimics what gunicorn workers do *if* the arbiter is also monkey-patched: -# After forking from the master monkey-patched process, the child -# resets signal handlers to SIG_DFL. If we then fork and watch *again*, -# we shouldn't hang. (Note that we carefully handle this so as not to break -# os.popen) -from __future__ import print_function -# Patch in the parent process. -import gevent.monkey -gevent.monkey.patch_all() - -from gevent import get_hub - -import os -import sys - -import signal -import subprocess - -def _waitpid(p): - try: - _, stat = os.waitpid(p, 0) - except OSError: - # Interrupted system call - _, stat = os.waitpid(p, 0) - assert stat == 0, stat - -if hasattr(signal, 'SIGCHLD'): - if sys.version_info[:2] >= (3, 8) and os.environ.get("PYTHONDEVMODE"): - # See test__monkey_sigchld.py - print("Ran 1 tests in 0.0s (skipped=1)") - sys.exit(0) - - # Do what subprocess does and make sure we have the watcher - # in the parent - get_hub().loop.install_sigchld() - - - pid = os.fork() - - if pid: # parent - _waitpid(pid) - else: - # Child resets. - signal.signal(signal.SIGCHLD, signal.SIG_DFL) - - # Go through subprocess because we expect it to automatically - # set up the waiting for us. - # not on Py2 pylint:disable=consider-using-with - popen = subprocess.Popen([sys.executable, '-c', 'import sys'], - stdout=subprocess.PIPE, stderr=subprocess.PIPE) - popen.stderr.read() - popen.stdout.read() - popen.wait() # This hangs if it doesn't. - popen.stderr.close() - popen.stdout.close() - sys.exit(0) -else: - print("No SIGCHLD, not testing") - print("Ran 1 tests in 0.0s (skipped=1)") diff --git a/venv/lib/python3.9/site-packages/gevent/tests/test__monkey_sigchld_wakeup_fd.py b/venv/lib/python3.9/site-packages/gevent/tests/test__monkey_sigchld_wakeup_fd.py deleted file mode 100644 index a68947a..0000000 --- a/venv/lib/python3.9/site-packages/gevent/tests/test__monkey_sigchld_wakeup_fd.py +++ /dev/null @@ -1,46 +0,0 @@ -import gevent.monkey - -gevent.monkey.patch_all() - -import signal -import sys - -# Try to produce output compatible with unittest output so -# our status parsing functions work. - -if hasattr(signal, 'SIGCHLD'): - import os - import subprocess - from signal import SIGCHLD - from signal import set_wakeup_fd - from signal import signal - - from gevent import Timeout - from gevent.os import make_nonblocking - from gevent.os import nb_read - - pipe_r, pipe_w = os.pipe() - make_nonblocking(pipe_r) - make_nonblocking(pipe_w) - - - def signal_handler(_signum, _frame): - pass - - - signal(SIGCHLD, signal_handler) - set_wakeup_fd(pipe_w, warn_on_full_buffer=True) - - with subprocess.Popen([sys.executable, "-c", "pass"]) as proc: - pass - - with Timeout(5): - read_signals = nb_read(pipe_r, 65535) - if read_signals != bytes((SIGCHLD.value,)): # pylint: disable=no-member - raise AssertionError(read_signals) - - print("Ran 1 tests in 0.0s") - sys.exit(0) -else: - print("No SIGCHLD, not testing") - print("Ran 1 tests in 0.0s (skipped=1)") diff --git a/venv/lib/python3.9/site-packages/gevent/tests/test__monkey_ssl_warning.py b/venv/lib/python3.9/site-packages/gevent/tests/test__monkey_ssl_warning.py deleted file mode 100644 index 6794e3d..0000000 --- a/venv/lib/python3.9/site-packages/gevent/tests/test__monkey_ssl_warning.py +++ /dev/null @@ -1,39 +0,0 @@ -import unittest -import warnings - -# This file should only have this one test in it -# because we have to be careful about our imports -# and because we need to be careful about our patching. - -class Test(unittest.TestCase): - - def test_with_pkg_resources(self): - # Issue 1108: Python 2, importing pkg_resources, - # as is done for namespace packages, imports ssl, - # leading to an unwanted SSL warning. - # This is a deprecated API though. - with warnings.catch_warnings(): - try: - __import__('pkg_resources') - except ImportError: - self.skipTest('Uses pkg_resources (setuptools) which is not installed') - - from gevent import monkey - - self.assertFalse(monkey.saved) - - with warnings.catch_warnings(record=True) as issued_warnings: - warnings.simplefilter('always') - - monkey.patch_all() - monkey.patch_all() - - issued_warnings = [x for x in issued_warnings - if isinstance(x.message, monkey.MonkeyPatchWarning)] - - self.assertFalse(issued_warnings, [str(i) for i in issued_warnings]) - self.assertEqual(0, len(issued_warnings)) - - -if __name__ == '__main__': - unittest.main() diff --git a/venv/lib/python3.9/site-packages/gevent/tests/test__monkey_ssl_warning2.py b/venv/lib/python3.9/site-packages/gevent/tests/test__monkey_ssl_warning2.py deleted file mode 100644 index c7c1239..0000000 --- a/venv/lib/python3.9/site-packages/gevent/tests/test__monkey_ssl_warning2.py +++ /dev/null @@ -1,44 +0,0 @@ -import unittest -import warnings -import sys - -# All supported python versions now provide SSLContext. -# We import it by name and subclass it here by name. -# compare with warning3.py -from ssl import SSLContext - -class MySubclass(SSLContext): - pass - -# This file should only have this one test in it -# because we have to be careful about our imports -# and because we need to be careful about our patching. - -class Test(unittest.TestCase): - - @unittest.skipIf(sys.version_info[:2] < (3, 6), - "Only on Python 3.6+") - def test_ssl_subclass_and_module_reference(self): - - from gevent import monkey - - self.assertFalse(monkey.saved) - - with warnings.catch_warnings(record=True) as issued_warnings: - warnings.simplefilter('always') - - monkey.patch_all() - monkey.patch_all() - - issued_warnings = [x for x in issued_warnings - if isinstance(x.message, monkey.MonkeyPatchWarning)] - - self.assertEqual(1, len(issued_warnings)) - message = issued_warnings[0].message - self.assertIn("Modules that had direct imports", str(message)) - self.assertIn("Subclasses (NOT patched)", str(message)) - - - -if __name__ == '__main__': - unittest.main() diff --git a/venv/lib/python3.9/site-packages/gevent/tests/test__monkey_ssl_warning3.py b/venv/lib/python3.9/site-packages/gevent/tests/test__monkey_ssl_warning3.py deleted file mode 100644 index 76b2a79..0000000 --- a/venv/lib/python3.9/site-packages/gevent/tests/test__monkey_ssl_warning3.py +++ /dev/null @@ -1,47 +0,0 @@ -import unittest -import warnings -import sys - -# All supported python versions now provide SSLContext. -# We subclass without importing by name. Compare with -# warning2.py -import ssl - -class MySubclass(ssl.SSLContext): - pass - -# This file should only have this one test in it -# because we have to be careful about our imports -# and because we need to be careful about our patching. - -class Test(unittest.TestCase): - - @unittest.skipIf(sys.version_info[:2] < (3, 6), - "Only on Python 3.6+") - def test_ssl_subclass_and_module_reference(self): - - from gevent import monkey - - self.assertFalse(monkey.saved) - - with warnings.catch_warnings(record=True) as issued_warnings: - warnings.simplefilter('always') - - monkey.patch_all() - monkey.patch_all() - - issued_warnings = [x for x in issued_warnings - if isinstance(x.message, monkey.MonkeyPatchWarning)] - - self.assertEqual(1, len(issued_warnings)) - message = str(issued_warnings[0].message) - - self.assertNotIn("Modules that had direct imports", message) - self.assertIn("Subclasses (NOT patched)", message) - # the gevent subclasses should not be in here. - self.assertNotIn('gevent.', message) - - - -if __name__ == '__main__': - unittest.main() diff --git a/venv/lib/python3.9/site-packages/gevent/tests/test__nondefaultloop.py b/venv/lib/python3.9/site-packages/gevent/tests/test__nondefaultloop.py deleted file mode 100644 index 489ff52..0000000 --- a/venv/lib/python3.9/site-packages/gevent/tests/test__nondefaultloop.py +++ /dev/null @@ -1,12 +0,0 @@ -# test for issue #210 -from gevent import core -from gevent.testing.util import alarm - - -alarm(1) - -log = [] -loop = core.loop(default=False) -loop.run_callback(log.append, 1) -loop.run() -assert log == [1], log diff --git a/venv/lib/python3.9/site-packages/gevent/tests/test__order.py b/venv/lib/python3.9/site-packages/gevent/tests/test__order.py deleted file mode 100644 index 9cfbba0..0000000 --- a/venv/lib/python3.9/site-packages/gevent/tests/test__order.py +++ /dev/null @@ -1,60 +0,0 @@ -import gevent -import gevent.testing as greentest - - -class appender(object): - - def __init__(self, lst, item): - self.lst = lst - self.item = item - - def __call__(self, *args): - self.lst.append(self.item) - - -class Test(greentest.TestCase): - - count = 2 - - def test_greenlet_link(self): - lst = [] - - # test that links are executed in the same order as they were added - g = gevent.spawn(lst.append, 0) - - for i in range(1, self.count): - g.link(appender(lst, i)) - g.join() - self.assertEqual(lst, list(range(self.count))) - - -class Test3(Test): - count = 3 - - -class Test4(Test): - count = 4 - - -class TestM(Test): - count = 1000 - - -class TestSleep0(greentest.TestCase): - - def test(self): - lst = [] - gevent.spawn(sleep0, lst, '1') - gevent.spawn(sleep0, lst, '2') - gevent.wait() - self.assertEqual(' '.join(lst), '1A 2A 1B 2B') - - -def sleep0(lst, param): - lst.append(param + 'A') - gevent.sleep(0) - lst.append(param + 'B') - - -if __name__ == '__main__': - greentest.main() diff --git a/venv/lib/python3.9/site-packages/gevent/tests/test__os.py b/venv/lib/python3.9/site-packages/gevent/tests/test__os.py deleted file mode 100644 index 7207ded..0000000 --- a/venv/lib/python3.9/site-packages/gevent/tests/test__os.py +++ /dev/null @@ -1,171 +0,0 @@ - -from os import pipe - - -import gevent -from gevent import os -from gevent import Greenlet, joinall - -from gevent import testing as greentest -from gevent.testing import mock -from gevent.testing import six -from gevent.testing.skipping import skipOnLibuvOnPyPyOnWin - - -class TestOS_tp(greentest.TestCase): - - __timeout__ = greentest.LARGE_TIMEOUT - - def pipe(self): - return pipe() - - read = staticmethod(os.tp_read) - write = staticmethod(os.tp_write) - - @skipOnLibuvOnPyPyOnWin("Sometimes times out") - def _test_if_pipe_blocks(self, buffer_class): - r, w = self.pipe() - # set nbytes such that for sure it is > maximum pipe buffer - nbytes = 1000000 - block = b'x' * 4096 - buf = buffer_class(block) - # Lack of "nonlocal" keyword in Python 2.x: - bytesread = [0] - byteswritten = [0] - - def produce(): - while byteswritten[0] != nbytes: - bytesleft = nbytes - byteswritten[0] - byteswritten[0] += self.write(w, buf[:min(bytesleft, 4096)]) - - def consume(): - while bytesread[0] != nbytes: - bytesleft = nbytes - bytesread[0] - bytesread[0] += len(self.read(r, min(bytesleft, 4096))) - - producer = Greenlet(produce) - producer.start() - consumer = Greenlet(consume) - consumer.start_later(1) - # If patching was not succesful, the producer will have filled - # the pipe before the consumer starts, and would block the entire - # process. Therefore the next line would never finish. - joinall([producer, consumer]) - self.assertEqual(bytesread[0], nbytes) - self.assertEqual(bytesread[0], byteswritten[0]) - - def test_if_pipe_blocks_memoryview(self): - self._test_if_pipe_blocks(six.builtins.memoryview) - - -@greentest.skipUnless(hasattr(os, 'make_nonblocking'), - "Only on POSIX") -class TestOS_nb(TestOS_tp): - - def read(self, fd, count): - return os.nb_read(fd, count) - - def write(self, fd, count): - return os.nb_write(fd, count) - - def pipe(self): - r, w = super(TestOS_nb, self).pipe() - os.make_nonblocking(r) - os.make_nonblocking(w) - return r, w - - def _make_ignored_oserror(self): - import errno - ignored_oserror = OSError() - ignored_oserror.errno = errno.EINTR - return ignored_oserror - - - def _check_hub_event_closed(self, mock_get_hub, fd, event): - mock_get_hub.assert_called_once_with() - hub = mock_get_hub.return_value - io = hub.loop.io - io.assert_called_once_with(fd, event) - - event = io.return_value - event.close.assert_called_once_with() - - def _test_event_closed_on_normal_io(self, nb_func, nb_arg, - mock_io, mock_get_hub, event): - mock_io.side_effect = [self._make_ignored_oserror(), 42] - - fd = 100 - result = nb_func(fd, nb_arg) - self.assertEqual(result, 42) - - self._check_hub_event_closed(mock_get_hub, fd, event) - - def _test_event_closed_on_io_error(self, nb_func, nb_arg, - mock_io, mock_get_hub, event): - mock_io.side_effect = [self._make_ignored_oserror(), ValueError()] - - fd = 100 - - with self.assertRaises(ValueError): - nb_func(fd, nb_arg) - - self._check_hub_event_closed(mock_get_hub, fd, event) - - @mock.patch('gevent.os.get_hub') - @mock.patch('gevent.os._write') - def test_event_closed_on_write(self, mock_write, mock_get_hub): - self._test_event_closed_on_normal_io(os.nb_write, b'buf', - mock_write, mock_get_hub, - 2) - - @mock.patch('gevent.os.get_hub') - @mock.patch('gevent.os._write') - def test_event_closed_on_write_error(self, mock_write, mock_get_hub): - self._test_event_closed_on_io_error(os.nb_write, b'buf', - mock_write, mock_get_hub, - 2) - - @mock.patch('gevent.os.get_hub') - @mock.patch('gevent.os._read') - def test_event_closed_on_read(self, mock_read, mock_get_hub): - self._test_event_closed_on_normal_io(os.nb_read, b'buf', - mock_read, mock_get_hub, - 1) - - @mock.patch('gevent.os.get_hub') - @mock.patch('gevent.os._read') - def test_event_closed_on_read_error(self, mock_read, mock_get_hub): - self._test_event_closed_on_io_error(os.nb_read, b'buf', - mock_read, mock_get_hub, - 1) - - -@greentest.skipUnless(hasattr(os, 'fork_and_watch'), - "Only on POSIX") -class TestForkAndWatch(greentest.TestCase): - - __timeout__ = greentest.LARGE_TIMEOUT - - def test_waitpid_all(self): - # Cover this specific case. - pid = os.fork_and_watch() - if pid: - os.waitpid(-1, 0) - # Can't assert on what the found pid actually was, - # our testrunner may have spawned multiple children. - os._reap_children(0) # make the leakchecker happy - else: # pragma: no cover - gevent.sleep(2) - # The test framework will catch a regular SystemExit - # from sys.exit(), we need to just kill the process. - os._exit(0) - - def test_waitpid_wrong_neg(self): - self.assertRaises(OSError, os.waitpid, -2, 0) - - def test_waitpid_wrong_pos(self): - self.assertRaises(OSError, os.waitpid, 1, 0) - - -if __name__ == '__main__': - greentest.main() diff --git a/venv/lib/python3.9/site-packages/gevent/tests/test__pool.py b/venv/lib/python3.9/site-packages/gevent/tests/test__pool.py deleted file mode 100644 index 1081282..0000000 --- a/venv/lib/python3.9/site-packages/gevent/tests/test__pool.py +++ /dev/null @@ -1,607 +0,0 @@ -from time import time -import gevent -import gevent.pool -from gevent.event import Event -from gevent.queue import Queue - -import gevent.testing as greentest -import gevent.testing.timing -import random -from gevent.testing import ExpectedException - -import unittest - - -class TestCoroutinePool(unittest.TestCase): - klass = gevent.pool.Pool - - def test_apply_async(self): - done = Event() - - def some_work(_): - done.set() - - pool = self.klass(2) - pool.apply_async(some_work, ('x', )) - done.wait() - - def test_apply(self): - value = 'return value' - - def some_work(): - return value - - pool = self.klass(2) - result = pool.apply(some_work) - self.assertEqual(value, result) - - def test_apply_raises(self): - pool = self.klass(1) - - def raiser(): - raise ExpectedException() - try: - pool.apply(raiser) - except ExpectedException: - pass - else: - self.fail("Should have raised ExpectedException") - # Don't let the metaclass automatically force any error - # that reaches the hub from a spawned greenlet to become - # fatal; that defeats the point of the test. - test_apply_raises.error_fatal = False - - def test_multiple_coros(self): - evt = Event() - results = [] - - def producer(): - gevent.sleep(0.001) - results.append('prod') - evt.set() - - def consumer(): - results.append('cons1') - evt.wait() - results.append('cons2') - - pool = self.klass(2) - done = pool.spawn(consumer) - pool.apply_async(producer) - done.get() - self.assertEqual(['cons1', 'prod', 'cons2'], results) - - def dont_test_timer_cancel(self): - timer_fired = [] - - def fire_timer(): - timer_fired.append(True) - - def some_work(): - gevent.timer(0, fire_timer) # pylint:disable=no-member - - pool = self.klass(2) - pool.apply(some_work) - gevent.sleep(0) - self.assertEqual(timer_fired, []) - - def test_reentrant(self): - pool = self.klass(1) - result = pool.apply(pool.apply, (lambda a: a + 1, (5, ))) - self.assertEqual(result, 6) - evt = Event() - pool.apply_async(evt.set) - evt.wait() - - @greentest.skipOnPyPy("Does not work on PyPy") # Why? - def test_stderr_raising(self): - # testing that really egregious errors in the error handling code - # (that prints tracebacks to stderr) don't cause the pool to lose - # any members - import sys - pool = self.klass(size=1) - - # we're going to do this by causing the traceback.print_exc in - # safe_apply to raise an exception and thus exit _main_loop - normal_err = sys.stderr - try: - sys.stderr = FakeFile() - waiter = pool.spawn(crash) - with gevent.Timeout(2): - # Without the timeout, we can get caught...doing something? - # If we call PyErr_WriteUnraisable at a certain point, - # we appear to switch back to the hub and do nothing, - # meaning we sit forever. The timeout at least keeps us from - # doing that and fails the test if we mess up error handling. - self.assertRaises(RuntimeError, waiter.get) - # the pool should have something free at this point since the - # waiter returned - # pool.Pool change: if an exception is raised during execution of a link, - # the rest of the links are scheduled to be executed on the next hub iteration - # this introduces a delay in updating pool.sem which makes pool.free_count() report 0 - # therefore, sleep: - gevent.sleep(0) - self.assertEqual(pool.free_count(), 1) - # shouldn't block when trying to get - with gevent.Timeout.start_new(0.1): - pool.apply(gevent.sleep, (0, )) - finally: - sys.stderr = normal_err - pool.join() - - -def crash(*_args, **_kw): - raise RuntimeError("Raising an error from the crash() function") - - -class FakeFile(object): - - def write(self, *_args): - raise RuntimeError('Writing to the file failed') - - -class PoolBasicTests(greentest.TestCase): - klass = gevent.pool.Pool - - def test_execute_async(self): - p = self.klass(size=2) - self.assertEqual(p.free_count(), 2) - r = [] - - first = p.spawn(r.append, 1) - self.assertEqual(p.free_count(), 1) - first.get() - self.assertEqual(r, [1]) - gevent.sleep(0) - self.assertEqual(p.free_count(), 2) - - #Once the pool is exhausted, calling an execute forces a yield. - - p.apply_async(r.append, (2, )) - self.assertEqual(1, p.free_count()) - self.assertEqual(r, [1]) - - p.apply_async(r.append, (3, )) - self.assertEqual(0, p.free_count()) - self.assertEqual(r, [1]) - - p.apply_async(r.append, (4, )) - self.assertEqual(r, [1]) - gevent.sleep(0.01) - self.assertEqual(sorted(r), [1, 2, 3, 4]) - - def test_discard(self): - p = self.klass(size=1) - first = p.spawn(gevent.sleep, 1000) - p.discard(first) - first.kill() - self.assertFalse(first) - self.assertEqual(len(p), 0) - self.assertEqual(p._semaphore.counter, 1) - - def test_add_method(self): - p = self.klass(size=1) - first = gevent.spawn(gevent.sleep, 1000) - try: - second = gevent.spawn(gevent.sleep, 1000) - try: - self.assertEqual(p.free_count(), 1) - self.assertEqual(len(p), 0) - p.add(first) - self.assertEqual(p.free_count(), 0) - self.assertEqual(len(p), 1) - - with self.assertRaises(gevent.Timeout): - with gevent.Timeout(0.1): - p.add(second) - - self.assertEqual(p.free_count(), 0) - self.assertEqual(len(p), 1) - finally: - second.kill() - finally: - first.kill() - - @greentest.ignores_leakcheck - def test_add_method_non_blocking(self): - p = self.klass(size=1) - first = gevent.spawn(gevent.sleep, 1000) - try: - second = gevent.spawn(gevent.sleep, 1000) - try: - p.add(first) - with self.assertRaises(gevent.pool.PoolFull): - p.add(second, blocking=False) - finally: - second.kill() - finally: - first.kill() - - @greentest.ignores_leakcheck - def test_add_method_timeout(self): - p = self.klass(size=1) - first = gevent.spawn(gevent.sleep, 1000) - try: - second = gevent.spawn(gevent.sleep, 1000) - try: - p.add(first) - with self.assertRaises(gevent.pool.PoolFull): - p.add(second, timeout=0.100) - finally: - second.kill() - finally: - first.kill() - - @greentest.ignores_leakcheck - def test_start_method_timeout(self): - p = self.klass(size=1) - first = gevent.spawn(gevent.sleep, 1000) - try: - second = gevent.Greenlet(gevent.sleep, 1000) - try: - p.add(first) - with self.assertRaises(gevent.pool.PoolFull): - p.start(second, timeout=0.100) - finally: - second.kill() - finally: - first.kill() - - def test_apply(self): - p = self.klass() - result = p.apply(lambda a: ('foo', a), (1, )) - self.assertEqual(result, ('foo', 1)) - - def test_init_error(self): - self.switch_expected = False - self.assertRaises(ValueError, self.klass, -1) - -# -# tests from standard library test/test_multiprocessing.py - - -class TimingWrapper(object): - - def __init__(self, func): - self.func = func - self.elapsed = None - - def __call__(self, *args, **kwds): - t = time() - try: - return self.func(*args, **kwds) - finally: - self.elapsed = time() - t - - -def sqr(x, wait=0.0): - gevent.sleep(wait) - return x * x - - -def squared(x): - return x * x - - -def sqr_random_sleep(x): - gevent.sleep(random.random() * 0.1) - return x * x - - -def final_sleep(): - yield from range(3) - gevent.sleep(0.2) - - -TIMEOUT1, TIMEOUT2, TIMEOUT3 = 0.082, 0.035, 0.14 - - -SMALL_RANGE = 10 -LARGE_RANGE = 1000 - -if (greentest.PYPY and greentest.WIN) or greentest.RUN_LEAKCHECKS or greentest.RUN_COVERAGE: - # See comments in test__threadpool.py. - LARGE_RANGE = 25 -elif greentest.RUNNING_ON_CI or greentest.EXPECT_POOR_TIMER_RESOLUTION: - LARGE_RANGE = 100 - -class TestPool(greentest.TestCase): # pylint:disable=too-many-public-methods - __timeout__ = greentest.LARGE_TIMEOUT - size = 1 - - def setUp(self): - greentest.TestCase.setUp(self) - self.pool = gevent.pool.Pool(self.size) - - def cleanup(self): - self.pool.join() - - def test_apply(self): - papply = self.pool.apply - self.assertEqual(papply(sqr, (5,)), 25) - self.assertEqual(papply(sqr, (), {'x': 3}), 9) - - def test_map(self): - pmap = self.pool.map - self.assertEqual(pmap(sqr, range(SMALL_RANGE)), list(map(squared, range(SMALL_RANGE)))) - self.assertEqual(pmap(sqr, range(100)), list(map(squared, range(100)))) - - def test_async(self): - res = self.pool.apply_async(sqr, (7, TIMEOUT1,)) - get = TimingWrapper(res.get) - self.assertEqual(get(), 49) - self.assertTimeoutAlmostEqual(get.elapsed, TIMEOUT1, 1) - - def test_async_callback(self): - result = [] - res = self.pool.apply_async(sqr, (7, TIMEOUT1,), callback=result.append) - get = TimingWrapper(res.get) - self.assertEqual(get(), 49) - self.assertTimeoutAlmostEqual(get.elapsed, TIMEOUT1, 1) - gevent.sleep(0) # lets the callback run - self.assertEqual(result, [49]) - - def test_async_timeout(self): - res = self.pool.apply_async(sqr, (6, TIMEOUT2 + 0.2)) - get = TimingWrapper(res.get) - self.assertRaises(gevent.Timeout, get, timeout=TIMEOUT2) - self.assertTimeoutAlmostEqual(get.elapsed, TIMEOUT2, 1) - self.pool.join() - - def test_imap_list_small(self): - it = self.pool.imap(sqr, range(SMALL_RANGE)) - self.assertEqual(list(it), list(map(sqr, range(SMALL_RANGE)))) - - def test_imap_it_small(self): - it = self.pool.imap(sqr, range(SMALL_RANGE)) - for i in range(SMALL_RANGE): - self.assertEqual(next(it), i * i) - self.assertRaises(StopIteration, next, it) - - def test_imap_it_large(self): - it = self.pool.imap(sqr, range(LARGE_RANGE)) - for i in range(LARGE_RANGE): - self.assertEqual(next(it), i * i) - self.assertRaises(StopIteration, next, it) - - def test_imap_random(self): - it = self.pool.imap(sqr_random_sleep, range(SMALL_RANGE)) - self.assertEqual(list(it), list(map(squared, range(SMALL_RANGE)))) - - def test_imap_unordered(self): - it = self.pool.imap_unordered(sqr, range(LARGE_RANGE)) - self.assertEqual(sorted(it), list(map(squared, range(LARGE_RANGE)))) - - it = self.pool.imap_unordered(sqr, range(LARGE_RANGE)) - self.assertEqual(sorted(it), list(map(squared, range(LARGE_RANGE)))) - - def test_imap_unordered_random(self): - it = self.pool.imap_unordered(sqr_random_sleep, range(SMALL_RANGE)) - self.assertEqual(sorted(it), list(map(squared, range(SMALL_RANGE)))) - - def test_empty_imap_unordered(self): - it = self.pool.imap_unordered(sqr, []) - self.assertEqual(list(it), []) - - def test_empty_imap(self): - it = self.pool.imap(sqr, []) - self.assertEqual(list(it), []) - - def test_empty_map(self): - self.assertEqual(self.pool.map(sqr, []), []) - - def test_terminate(self): - result = self.pool.map_async(gevent.sleep, [0.1] * ((self.size or 10) * 2)) - gevent.sleep(0.1) - kill = TimingWrapper(self.pool.kill) - kill() - self.assertTimeWithinRange(kill.elapsed, 0.0, 0.5) - result.join() - - def sleep(self, x): - gevent.sleep(float(x) / 10.) - return str(x) - - def test_imap_unordered_sleep(self): - # testing that imap_unordered returns items in competion order - result = list(self.pool.imap_unordered(self.sleep, [10, 1, 2])) - if self.pool.size == 1: - expected = ['10', '1', '2'] - else: - expected = ['1', '2', '10'] - self.assertEqual(result, expected) - - # https://github.com/gevent/gevent/issues/423 - def test_imap_no_stop(self): - q = Queue() - q.put(123) - gevent.spawn_later(0.1, q.put, StopIteration) - result = list(self.pool.imap(lambda _: _, q)) - self.assertEqual(result, [123]) - - def test_imap_unordered_no_stop(self): - q = Queue() - q.put(1234) - gevent.spawn_later(0.1, q.put, StopIteration) - result = list(self.pool.imap_unordered(lambda _: _, q)) - self.assertEqual(result, [1234]) - - # same issue, but different test: https://github.com/gevent/gevent/issues/311 - def test_imap_final_sleep(self): - result = list(self.pool.imap(sqr, final_sleep())) - self.assertEqual(result, [0, 1, 4]) - - def test_imap_unordered_final_sleep(self): - result = list(self.pool.imap_unordered(sqr, final_sleep())) - self.assertEqual(result, [0, 1, 4]) - - # Issue 638 - def test_imap_unordered_bounded_queue(self): - iterable = list(range(100)) - - running = [0] - - def short_running_func(i, _j): - running[0] += 1 - return i - - def make_reader(mapping): - # Simulate a long running reader. No matter how many workers - # we have, we will never have a queue more than size 1 - def reader(): - result = [] - for i, x in enumerate(mapping): - self.assertTrue(running[0] <= i + 2, running[0]) - result.append(x) - gevent.sleep(0.01) - self.assertTrue(len(mapping.queue) <= 2, len(mapping.queue)) - return result - return reader - - # Send two iterables to make sure varargs and kwargs are handled - # correctly - for meth in self.pool.imap_unordered, self.pool.imap: - running[0] = 0 - mapping = meth(short_running_func, iterable, iterable, - maxsize=1) - - reader = make_reader(mapping) - l = reader() - self.assertEqual(sorted(l), iterable) - -@greentest.ignores_leakcheck -class TestPool2(TestPool): - size = 2 - -@greentest.ignores_leakcheck -class TestPool3(TestPool): - size = 3 - -@greentest.ignores_leakcheck -class TestPool10(TestPool): - size = 10 - - -class TestPoolUnlimit(TestPool): - size = None - - -class TestPool0(greentest.TestCase): - size = 0 - - def test_wait_full(self): - p = gevent.pool.Pool(size=0) - self.assertEqual(0, p.free_count()) - self.assertTrue(p.full()) - self.assertEqual(0, p.wait_available(timeout=0.01)) - - -class TestJoinSleep(gevent.testing.timing.AbstractGenericWaitTestCase): - - def wait(self, timeout): - p = gevent.pool.Pool() - g = p.spawn(gevent.sleep, 10) - try: - p.join(timeout=timeout) - finally: - g.kill() - - -class TestJoinSleep_raise_error(gevent.testing.timing.AbstractGenericWaitTestCase): - - def wait(self, timeout): - p = gevent.pool.Pool() - g = p.spawn(gevent.sleep, 10) - try: - p.join(timeout=timeout, raise_error=True) - finally: - g.kill() - - -class TestJoinEmpty(greentest.TestCase): - switch_expected = False - - def test(self): - p = gevent.pool.Pool() - res = p.join() - self.assertTrue(res, "empty should return true") - - -class TestSpawn(greentest.TestCase): - switch_expected = True - - def test(self): - p = gevent.pool.Pool(1) - self.assertEqual(len(p), 0) - p.spawn(gevent.sleep, 0.1) - self.assertEqual(len(p), 1) - p.spawn(gevent.sleep, 0.1) # this spawn blocks until the old one finishes - self.assertEqual(len(p), 1) - gevent.sleep(0.19 if not greentest.EXPECT_POOR_TIMER_RESOLUTION else 0.5) - self.assertEqual(len(p), 0) - - def testSpawnAndWait(self): - p = gevent.pool.Pool(1) - self.assertEqual(len(p), 0) - p.spawn(gevent.sleep, 0.1) - self.assertEqual(len(p), 1) - res = p.join(0.01) - self.assertFalse(res, "waiting on a full pool should return false") - res = p.join() - self.assertTrue(res, "waiting to finish should be true") - self.assertEqual(len(p), 0) - -def error_iter(): - yield 1 - yield 2 - raise ExpectedException - - -class TestErrorInIterator(greentest.TestCase): - error_fatal = False - - def test(self): - p = gevent.pool.Pool(3) - self.assertRaises(ExpectedException, p.map, lambda x: None, error_iter()) - gevent.sleep(0.001) - - def test_unordered(self): - p = gevent.pool.Pool(3) - - def unordered(): - return list(p.imap_unordered(lambda x: None, error_iter())) - - self.assertRaises(ExpectedException, unordered) - gevent.sleep(0.001) - - -def divide_by(x): - return 1.0 / x - - -class TestErrorInHandler(greentest.TestCase): - error_fatal = False - - def test_map(self): - p = gevent.pool.Pool(3) - self.assertRaises(ZeroDivisionError, p.map, divide_by, [1, 0, 2]) - - def test_imap(self): - p = gevent.pool.Pool(1) - it = p.imap(divide_by, [1, 0, 2]) - self.assertEqual(next(it), 1.0) - self.assertRaises(ZeroDivisionError, next, it) - self.assertEqual(next(it), 0.5) - self.assertRaises(StopIteration, next, it) - - def test_imap_unordered(self): - p = gevent.pool.Pool(1) - it = p.imap_unordered(divide_by, [1, 0, 2]) - self.assertEqual(next(it), 1.0) - self.assertRaises(ZeroDivisionError, next, it) - self.assertEqual(next(it), 0.5) - self.assertRaises(StopIteration, next, it) - - -if __name__ == '__main__': - greentest.main() diff --git a/venv/lib/python3.9/site-packages/gevent/tests/test__pywsgi.py b/venv/lib/python3.9/site-packages/gevent/tests/test__pywsgi.py deleted file mode 100644 index 9166f25..0000000 --- a/venv/lib/python3.9/site-packages/gevent/tests/test__pywsgi.py +++ /dev/null @@ -1,2055 +0,0 @@ -# Copyright (c) 2007, Linden Research, Inc. -# Copyright (c) 2009-2010 gevent contributors -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. -# pylint: disable=too-many-lines,unused-argument,too-many-ancestors -from gevent import monkey - -monkey.patch_all() - -from contextlib import contextmanager -from urllib.parse import parse_qs -import os -import sys -from io import BytesIO as StringIO - -import unittest -from wsgiref.validate import validator - -import gevent.testing as greentest -import gevent - -from gevent.testing.exception import ExpectedException -from gevent import socket -from gevent import pywsgi -from gevent.pywsgi import Input - - -class ExpectedAssertionError(ExpectedException, AssertionError): - """An expected assertion error""" - -CONTENT_LENGTH = 'Content-Length' -CONN_ABORTED_ERRORS = greentest.CONN_ABORTED_ERRORS - -REASONS = { - 200: 'OK', - 500: 'Internal Server Error' -} - - -class ConnectionClosed(Exception): - pass - - -def read_headers(fd): - response_line = fd.readline() - if not response_line: - raise ConnectionClosed - response_line = response_line.decode('latin-1') - headers = {} - while True: - line = fd.readline().strip() - if not line: - break - line = line.decode('latin-1') - try: - key, value = line.split(': ', 1) - except: - print('Failed to split: %r' % (line, )) - raise - assert key.lower() not in {x.lower() for x in headers}, 'Header %r:%r sent more than once: %r' % (key, value, headers) - headers[key] = value - return response_line, headers - - -def iread_chunks(fd): - while True: - line = fd.readline() - chunk_size = line.strip() - chunk_size = int(chunk_size, 16) - if chunk_size == 0: - crlf = fd.read(2) - assert crlf == b'\r\n', repr(crlf) - break - data = fd.read(chunk_size) - yield data - crlf = fd.read(2) - assert crlf == b'\r\n', repr(crlf) - - -class Response(object): - - def __init__(self, status_line, headers): - self.status_line = status_line - self.headers = headers - self.body = None - self.chunks = False - try: - version, code, self.reason = status_line[:-2].split(' ', 2) - self.code = int(code) - HTTP, self.version = version.split('/') - assert HTTP == 'HTTP', repr(HTTP) - assert self.version in ('1.0', '1.1'), repr(self.version) - except Exception: - print('Error: %r' % status_line) - raise - - def __iter__(self): - yield self.status_line - yield self.headers - yield self.body - - def __str__(self): - args = (self.__class__.__name__, self.status_line, self.headers, self.body, self.chunks) - return '<%s status_line=%r headers=%r body=%r chunks=%r>' % args - - def assertCode(self, code): - if hasattr(code, '__contains__'): - assert self.code in code, 'Unexpected code: %r (expected %r)\n%s' % (self.code, code, self) - else: - assert self.code == code, 'Unexpected code: %r (expected %r)\n%s' % (self.code, code, self) - - def assertReason(self, reason): - assert self.reason == reason, 'Unexpected reason: %r (expected %r)\n%s' % (self.reason, reason, self) - - def assertVersion(self, version): - assert self.version == version, 'Unexpected version: %r (expected %r)\n%s' % (self.version, version, self) - - def assertHeader(self, header, value): - real_value = self.headers.get(header, False) - assert real_value == value, \ - 'Unexpected header %r: %r (expected %r)\n%s' % (header, real_value, value, self) - - def assertBody(self, body): - if isinstance(body, str): - body = body.encode("ascii") - assert self.body == body, 'Unexpected body: %r (expected %r)\n%s' % (self.body, body, self) - - @classmethod - def read(cls, fd, code=200, reason='default', version='1.1', - body=None, chunks=None, content_length=None): - """ - Read an HTTP response, optionally perform assertions, - and return the Response object. - """ - # pylint:disable=too-many-branches - _status_line, headers = read_headers(fd) - self = cls(_status_line, headers) - if code is not None: - self.assertCode(code) - if reason == 'default': - reason = REASONS.get(code) - if reason is not None: - self.assertReason(reason) - if version is not None: - self.assertVersion(version) - if self.code == 100: - return self - if content_length is not None: - if isinstance(content_length, int): - content_length = str(content_length) - self.assertHeader('Content-Length', content_length) - - if 'chunked' in headers.get('Transfer-Encoding', ''): - if CONTENT_LENGTH in headers: - print("WARNING: server used chunked transfer-encoding despite having Content-Length header (libevent 1.x's bug)") - self.chunks = list(iread_chunks(fd)) - self.body = b''.join(self.chunks) - elif CONTENT_LENGTH in headers: - num = int(headers[CONTENT_LENGTH]) - self.body = fd.read(num) - else: - self.body = fd.read() - - if body is not None: - self.assertBody(body) - if chunks is not None: - assert chunks == self.chunks, (chunks, self.chunks) - return self - -read_http = Response.read - - -class TestCase(greentest.TestCase): - server = None - validator = staticmethod(validator) - application = None - - # Bind to default address, which should give us ipv6 (when available) - # and ipv4. (see self.connect()) - listen_addr = greentest.DEFAULT_BIND_ADDR - # connect on ipv4, even though we bound to ipv6 too - # to prove ipv4 works...except on Windows, it apparently doesn't. - # So use the hostname. - connect_addr = greentest.DEFAULT_LOCAL_HOST_ADDR - - class handler_class(pywsgi.WSGIHandler): - ApplicationError = ExpectedAssertionError - - def init_logger(self): - import logging - logger = logging.getLogger('gevent.tests.pywsgi') - logger.setLevel(logging.CRITICAL) - return logger - - def init_server(self, application): - logger = self.logger = self.init_logger() - self.server = pywsgi.WSGIServer( - (self.listen_addr, 0), - application, - log=logger, error_log=logger, - handler_class=self.handler_class, - ) - - def setUp(self): - application = self.application - if self.validator is not None: - application = self.validator(application) - self.init_server(application) - self.server.start() - while not self.server.server_port: - print("Waiting on server port") - self.port = self.server.server_port - assert self.port - greentest.TestCase.setUp(self) - - def tearDown(self): - greentest.TestCase.tearDown(self) - if self.server is not None: - with gevent.Timeout.start_new(0.5): - self.server.stop() - self.server = None - if greentest.PYPY: - import gc - gc.collect() - gc.collect() - - - @contextmanager - def connect(self): - conn = socket.create_connection((self.connect_addr, self.port)) - result = conn - - conn_makefile = conn.makefile - - def makefile(*args, **kwargs): - if 'bufsize' in kwargs: - kwargs['buffering'] = kwargs.pop('bufsize') - - if 'mode' in kwargs: - return conn_makefile(*args, **kwargs) - - # Under Python3, you can't read and write to the same - # makefile() opened in (default) r, and r+ is not allowed - kwargs['mode'] = 'rwb' - rconn = conn_makefile(*args, **kwargs) - _rconn_write = rconn.write - - def write(data): - if isinstance(data, str): - data = data.encode('ascii') - return _rconn_write(data) - rconn.write = write - self._close_on_teardown(rconn) - return rconn - - class proxy(object): - def __getattribute__(self, name): - if name == 'makefile': - return makefile - return getattr(conn, name) - result = proxy() - try: - yield result - finally: - result.close() - - @contextmanager - def makefile(self): - with self.connect() as sock: - try: - result = sock.makefile(bufsize=1) # pylint:disable=unexpected-keyword-arg - yield result - finally: - result.close() - - def urlopen(self, *args, **kwargs): - with self.connect() as sock: - with sock.makefile(bufsize=1) as fd: # pylint:disable=unexpected-keyword-arg - fd.write('GET / HTTP/1.1\r\nHost: localhost\r\n\r\n') - return read_http(fd, *args, **kwargs) - - HTTP_CLIENT_VERSION = '1.1' - DEFAULT_EXTRA_CLIENT_HEADERS = {} - - def format_request(self, method='GET', path='/', **headers): - def_headers = self.DEFAULT_EXTRA_CLIENT_HEADERS.copy() - def_headers.update(headers) - headers = def_headers - - headers = '\r\n'.join('%s: %s' % item for item in headers.items()) - headers = headers + '\r\n' if headers else headers - result = ( - '%(method)s %(path)s HTTP/%(http_ver)s\r\n' - 'Host: localhost\r\n' - '%(headers)s' - '\r\n' - ) - result = result % dict( - method=method, - path=path, - http_ver=self.HTTP_CLIENT_VERSION, - headers=headers - ) - return result - - -class CommonTestMixin(object): - PIPELINE_NOT_SUPPORTED_EXS = () - EXPECT_CLOSE = False - EXPECT_KEEPALIVE = False - - def test_basic(self): - with self.makefile() as fd: - fd.write(self.format_request()) - response = read_http(fd, body='hello world') - if response.headers.get('Connection') == 'close': - self.assertTrue(self.EXPECT_CLOSE, "Server closed connection, not expecting that") - return response, None - - self.assertFalse(self.EXPECT_CLOSE) - if self.EXPECT_KEEPALIVE: - response.assertHeader('Connection', 'keep-alive') - fd.write(self.format_request(path='/notexist')) - dne_response = read_http(fd, code=404, reason='Not Found', body='not found') - fd.write(self.format_request()) - response = read_http(fd, body='hello world') - return response, dne_response - - - - def test_pipeline(self): - exception = AssertionError('HTTP pipelining not supported; the second request is thrown away') - with self.makefile() as fd: - fd.write(self.format_request() + self.format_request(path='/notexist')) - read_http(fd, body='hello world') - - try: - timeout = gevent.Timeout.start_new(0.5, exception=exception) - try: - read_http(fd, code=404, reason='Not Found', body='not found') - finally: - timeout.close() - except self.PIPELINE_NOT_SUPPORTED_EXS: - pass - except AssertionError as ex: - if ex is not exception: - raise - - def test_connection_close(self): - with self.makefile() as fd: - fd.write(self.format_request()) - response = read_http(fd) - if response.headers.get('Connection') == 'close': - self.assertTrue(self.EXPECT_CLOSE, "Server closed connection, not expecting that") - return - self.assertFalse(self.EXPECT_CLOSE) - if self.EXPECT_KEEPALIVE: - response.assertHeader('Connection', 'keep-alive') - - fd.write(self.format_request(Connection='close')) - read_http(fd) - fd.write(self.format_request()) - # This may either raise, or it may return an empty response, - # depend on timing and the Python version. - try: - result = fd.readline() - except socket.error as ex: - if ex.args[0] not in CONN_ABORTED_ERRORS: - raise - else: - self.assertFalse( - result, - 'The remote side is expected to close the connection, but it sent %r' - % (result,)) - - @unittest.skip("Not sure") - def test_006_reject_long_urls(self): - path_parts = [] - for _ in range(3000): - path_parts.append('path') - path = '/'.join(path_parts) - - with self.makefile() as fd: - request = 'GET /%s HTTP/1.0\r\nHost: localhost\r\n\r\n' % path - fd.write(request) - result = fd.readline() - status = result.split(' ')[1] - self.assertEqual(status, '414') - - -class TestNoChunks(CommonTestMixin, TestCase): - # when returning a list of strings a shortcut is employed by the server: - # it calculates the content-length and joins all the chunks before sending - validator = None - last_environ = None - - def _check_environ(self, input_terminated=True): - if input_terminated: - self.assertTrue(self.last_environ.get('wsgi.input_terminated')) - else: - self.assertFalse(self.last_environ['wsgi.input_terminated']) - - def application(self, env, start_response): - self.last_environ = env - path = env['PATH_INFO'] - if path == '/': - start_response('200 OK', [('Content-Type', 'text/plain')]) - return [b'hello ', b'world'] - if path == '/websocket': - write = start_response('101 Switching Protocols', - [('Content-Type', 'text/plain'), - # Con:close is to make our simple client - # happy; otherwise it wants to read data from the - # body thot's being kept open. - ('Connection', 'close')]) - write(b'') # Trigger finalizing the headers now. - return [b'upgrading to', b'websocket'] - start_response('404 Not Found', [('Content-Type', 'text/plain')]) - return [b'not ', b'found'] - - def test_basic(self): - response, dne_response = super(TestNoChunks, self).test_basic() - self._check_environ() - self.assertFalse(response.chunks) - response.assertHeader('Content-Length', '11') - if dne_response is not None: - self.assertFalse(dne_response.chunks) - dne_response.assertHeader('Content-Length', '9') - - def test_dne(self): - with self.makefile() as fd: - fd.write(self.format_request(path='/notexist')) - response = read_http(fd, code=404, reason='Not Found', body='not found') - self.assertFalse(response.chunks) - self._check_environ() - response.assertHeader('Content-Length', '9') - -class TestConnectionUpgrades(TestNoChunks): - - def test_connection_upgrade(self): - with self.makefile() as fd: - fd.write(self.format_request(path='/websocket', Connection='upgrade')) - response = read_http(fd, code=101) - - self._check_environ(input_terminated=False) - self.assertFalse(response.chunks) - - def test_upgrade_websocket(self): - with self.makefile() as fd: - fd.write(self.format_request(path='/websocket', Upgrade='websocket')) - response = read_http(fd, code=101) - - self._check_environ(input_terminated=False) - self.assertFalse(response.chunks) - - -class TestNoChunks10(TestNoChunks): - HTTP_CLIENT_VERSION = '1.0' - PIPELINE_NOT_SUPPORTED_EXS = (ConnectionClosed,) - EXPECT_CLOSE = True - -class TestNoChunks10KeepAlive(TestNoChunks10): - DEFAULT_EXTRA_CLIENT_HEADERS = { - 'Connection': 'keep-alive', - } - EXPECT_CLOSE = False - EXPECT_KEEPALIVE = True - - -class TestExplicitContentLength(TestNoChunks): # pylint:disable=too-many-ancestors - # when returning a list of strings a shortcut is employed by the - # server - it caculates the content-length - - def application(self, env, start_response): - self.last_environ = env - self.assertTrue(env.get('wsgi.input_terminated')) - path = env['PATH_INFO'] - if path == '/': - start_response('200 OK', [('Content-Type', 'text/plain'), ('Content-Length', '11')]) - return [b'hello ', b'world'] - - start_response('404 Not Found', [('Content-Type', 'text/plain'), ('Content-Length', '9')]) - return [b'not ', b'found'] - - -class TestYield(CommonTestMixin, TestCase): - - @staticmethod - def application(env, start_response): - path = env['PATH_INFO'] - if path == '/': - start_response('200 OK', [('Content-Type', 'text/plain')]) - yield b"hello world" - else: - start_response('404 Not Found', [('Content-Type', 'text/plain')]) - yield b"not found" - - -class TestBytearray(CommonTestMixin, TestCase): - - validator = None - - @staticmethod - def application(env, start_response): - path = env['PATH_INFO'] - if path == '/': - start_response('200 OK', [('Content-Type', 'text/plain')]) - return [bytearray(b"hello "), bytearray(b"world")] - start_response('404 Not Found', [('Content-Type', 'text/plain')]) - return [bytearray(b"not found")] - - -class TestMultiLineHeader(TestCase): - @staticmethod - def application(env, start_response): - assert "test.submit" in env["CONTENT_TYPE"] - start_response('200 OK', [('Content-Type', 'text/plain')]) - return [b"ok"] - - def test_multiline_116(self): - """issue #116""" - request = '\r\n'.join(( - 'POST / HTTP/1.0', - 'Host: localhost', - 'Content-Type: multipart/related; boundary="====XXXX====";', - ' type="text/xml";start="test.submit"', - 'Content-Length: 0', - '', '')) - with self.makefile() as fd: - fd.write(request) - read_http(fd) - - -class TestGetArg(TestCase): - - @staticmethod - def application(env, start_response): - body = env['wsgi.input'].read(3) - body = body.decode('ascii') - a = parse_qs(body).get('a', [1])[0] - start_response('200 OK', [('Content-Type', 'text/plain')]) - return [('a is %s, body is %s' % (a, body)).encode('ascii')] - - def test_007_get_arg(self): - # define a new handler that does a get_arg as well as a read_body - - request = '\r\n'.join(( - 'POST / HTTP/1.0', - 'Host: localhost', - 'Content-Length: 3', - '', - 'a=a')) - with self.makefile() as fd: - fd.write(request) - - # send some junk after the actual request - fd.write('01234567890123456789') - read_http(fd, body='a is a, body is a=a') - - -class TestCloseIter(TestCase): - - # The *Validator* closes the iterators! - validator = None - - def application(self, env, start_response): - start_response('200 OK', [('Content-Type', 'text/plain')]) - return self - - def __iter__(self): - yield bytearray(b"Hello World") - yield b"!" - - closed = False - - def close(self): - self.closed += 1 - - def test_close_is_called(self): - self.closed = False - with self.makefile() as fd: - fd.write('GET / HTTP/1.1\r\nHost: localhost\r\n\r\n') - read_http(fd, body=b"Hello World!", chunks=[b'Hello World', b'!']) - # We got closed exactly once. - self.assertEqual(self.closed, 1) - -class TestChunkedApp(TestCase): - - chunks = [b'this', b'is', b'chunked'] - - def body(self): - return b''.join(self.chunks) - - def application(self, env, start_response): - self.assertTrue(env.get('wsgi.input_terminated')) - start_response('200 OK', [('Content-Type', 'text/plain')]) - yield from self.chunks - - def test_chunked_response(self): - with self.makefile() as fd: - fd.write('GET / HTTP/1.1\r\nHost: localhost\r\nConnection: close\r\n\r\n') - response = read_http(fd, body=self.body(), chunks=None) - - response.assertHeader('Transfer-Encoding', 'chunked') - self.assertEqual(response.chunks, self.chunks) - - def test_no_chunked_http_1_0(self): - with self.makefile() as fd: - fd.write('GET / HTTP/1.0\r\nHost: localhost\r\nConnection: close\r\n\r\n') - response = read_http(fd) - self.assertEqual(response.body, self.body()) - self.assertEqual(response.headers.get('Transfer-Encoding'), None) - content_length = response.headers.get('Content-Length') - if content_length is not None: - self.assertEqual(content_length, str(len(self.body()))) - - -class TestBigChunks(TestChunkedApp): - chunks = [b'a' * 8192] * 3 - - -class TestNegativeRead(TestCase): - - def application(self, env, start_response): - self.assertTrue(env.get('wsgi.input_terminated')) - start_response('200 OK', [('Content-Type', 'text/plain')]) - if env['PATH_INFO'] == '/read': - data = env['wsgi.input'].read(-1) - return [data] - - def test_negative_chunked_read(self): - data = (b'POST /read HTTP/1.1\r\nHost: localhost\r\nConnection: close\r\n' - b'Transfer-Encoding: chunked\r\n\r\n' - b'2\r\noh\r\n4\r\n hai\r\n0\r\n\r\n') - with self.makefile() as fd: - fd.write(data) - read_http(fd, body='oh hai') - - def test_negative_nonchunked_read(self): - data = (b'POST /read HTTP/1.1\r\nHost: localhost\r\nConnection: close\r\n' - b'Content-Length: 6\r\n\r\n' - b'oh hai') - with self.makefile() as fd: - fd.write(data) - read_http(fd, body='oh hai') - - -class TestNegativeReadline(TestCase): - validator = None - - @staticmethod - def application(env, start_response): - start_response('200 OK', [('Content-Type', 'text/plain')]) - if env['PATH_INFO'] == '/readline': - data = env['wsgi.input'].readline(-1) - return [data] - - def test_negative_chunked_readline(self): - data = (b'POST /readline HTTP/1.1\r\nHost: localhost\r\nConnection: close\r\n' - b'Transfer-Encoding: chunked\r\n\r\n' - b'2\r\noh\r\n4\r\n hai\r\n0\r\n\r\n') - with self.makefile() as fd: - fd.write(data) - read_http(fd, body='oh hai') - - def test_negative_nonchunked_readline(self): - data = (b'POST /readline HTTP/1.1\r\nHost: localhost\r\nConnection: close\r\n' - b'Content-Length: 6\r\n\r\n' - b'oh hai') - with self.makefile() as fd: - fd.write(data) - read_http(fd, body='oh hai') - - -class TestChunkedPost(TestCase): - - calls = 0 - - def setUp(self): - super().setUp() - self.calls = 0 - - def application(self, env, start_response): - self.calls += 1 - self.assertTrue(env.get('wsgi.input_terminated')) - start_response('200 OK', [('Content-Type', 'text/plain')]) - if env['PATH_INFO'] == '/a': - data = env['wsgi.input'].read(6) - return [data] - - if env['PATH_INFO'] == '/b': - lines = list(iter(lambda: env['wsgi.input'].read(6), b'')) - return lines - - if env['PATH_INFO'] == '/c': - return list(iter(lambda: env['wsgi.input'].read(1), b'')) - - return [b'We should not get here', env['PATH_INFO'].encode('ascii')] - - def test_014_chunked_post(self): - data = (b'POST /a HTTP/1.1\r\nHost: localhost\r\nConnection: close\r\n' - b'Transfer-Encoding: chunked\r\n\r\n' - b'2\r\noh\r\n4\r\n hai\r\n0\r\n\r\n') - with self.makefile() as fd: - fd.write(data) - read_http(fd, body='oh hai') - # self.close_opened() # XXX: Why? - - with self.makefile() as fd: - fd.write(data.replace(b'/a', b'/b')) - read_http(fd, body='oh hai') - - with self.makefile() as fd: - fd.write(data.replace(b'/a', b'/c')) - read_http(fd, body='oh hai') - - def test_229_incorrect_chunk_no_newline(self): - # Giving both a Content-Length and a Transfer-Encoding, - # TE is preferred. But if the chunking is bad from the client, - # missing its terminating newline, - # the server doesn't hang - data = (b'POST /a HTTP/1.1\r\nHost: localhost\r\nConnection: close\r\n' - b'Content-Length: 12\r\n' - b'Transfer-Encoding: chunked\r\n\r\n' - b'{"hi": "ho"}') - with self.makefile() as fd: - fd.write(data) - read_http(fd, code=400) - - def test_229_incorrect_chunk_non_hex(self): - # Giving both a Content-Length and a Transfer-Encoding, - # TE is preferred. But if the chunking is bad from the client, - # the server doesn't hang - data = (b'POST /a HTTP/1.1\r\nHost: localhost\r\nConnection: close\r\n' - b'Content-Length: 12\r\n' - b'Transfer-Encoding: chunked\r\n\r\n' - b'{"hi": "ho"}\r\n') - with self.makefile() as fd: - fd.write(data) - read_http(fd, code=400) - - def test_229_correct_chunk_quoted_ext(self): - data = (b'POST /a HTTP/1.1\r\nHost: localhost\r\nConnection: close\r\n' - b'Transfer-Encoding: chunked\r\n\r\n' - b'2;token="oh hi"\r\noh\r\n4\r\n hai\r\n0\r\n\r\n') - with self.makefile() as fd: - fd.write(data) - read_http(fd, body='oh hai') - - def test_229_correct_chunk_token_ext(self): - data = (b'POST /a HTTP/1.1\r\nHost: localhost\r\nConnection: close\r\n' - b'Transfer-Encoding: chunked\r\n\r\n' - b'2;token=oh_hi\r\noh\r\n4\r\n hai\r\n0\r\n\r\n') - with self.makefile() as fd: - fd.write(data) - read_http(fd, body='oh hai') - - def test_229_incorrect_chunk_token_ext_too_long(self): - data = (b'POST /a HTTP/1.1\r\nHost: localhost\r\nConnection: close\r\n' - b'Transfer-Encoding: chunked\r\n\r\n' - b'2;token=oh_hi\r\noh\r\n4\r\n hai\r\n0\r\n\r\n') - data = data.replace(b'oh_hi', b'_oh_hi' * 4000) - with self.makefile() as fd: - fd.write(data) - read_http(fd, code=400) - - # XXX: Not sure which one, but one (or more) of these is leading to a - # test timeout on Windows. Figure out what/why and solve. - - @greentest.skipOnWindows('Maybe hangs') - def test_trailers_keepalive_ignored(self): - # Trailers after a chunk are ignored. - data1 = ( - b'POST /a HTTP/1.1\r\n' - b'Host: localhost\r\n' - b'Connection: keep-alive\r\n' - b'Transfer-Encoding: chunked\r\n' - b'\r\n' - b'2\r\noh\r\n' - b'4\r\n hai\r\n' - b'0\r\n' # last-chunk - # Normally the final CRLF would go here, but if you put in a - # trailer, it doesn't. - b'trailer1: value1\r\n' - b'trailer2: value2\r\n' - b'\r\n' # Really terminate the chunk. - ) - data2 = ( - b'POST /a HTTP/1.1\r\n' - b'Host: localhost\r\n' - b'Connection: close\r\n' - b'Transfer-Encoding: chunked\r\n' - b'\r\n' - b'2\r\noh\r\n' - b'4\r\n bye\r\n' - b'0\r\n' # last-chunk - ) - with self.makefile() as fd: - fd.write(data1) - read_http(fd, body='oh hai') - fd.write(data2) - read_http(fd, body='oh bye') - - self.assertEqual(self.calls, 2) - - @greentest.skipOnWindows('Maybe hangs') - def test_trailers_close_ignored(self): - data = ( - b'POST /a HTTP/1.1\r\n' - b'Host: localhost\r\n' - b'Connection: close\r\n' - b'Transfer-Encoding: chunked\r\n' - b'\r\n' - b'2\r\noh\r\n' - b'4\r\n hai\r\n' - b'0\r\n' # last-chunk - # Normally the final CRLF would go here, but if you put in a - # trailer, it doesn't. - # b'\r\n' - b'GETpath2a:123 HTTP/1.1\r\n' - b'Host: a.com\r\n' - b'Connection: close\r\n' - b'\r\n' - ) - with self.makefile() as fd: - fd.write(data) - read_http(fd, body='oh hai') - with self.assertRaises(ConnectionClosed): - read_http(fd) - - @greentest.skipOnWindows('Maybe hangs') - def test_trailers_too_long(self): - # Trailers after a chunk are ignored. - data = ( - b'POST /a HTTP/1.1\r\n' - b'Host: localhost\r\n' - b'Connection: keep-alive\r\n' - b'Transfer-Encoding: chunked\r\n' - b'\r\n' - b'2\r\noh\r\n' - b'4\r\n hai\r\n' - b'0\r\n' # last-chunk - # Normally the final CRLF would go here, but if you put in a - # trailer, it doesn't. - b'trailer2: value2' # note lack of \r\n - ) - data += b't' * pywsgi.MAX_REQUEST_LINE - # No termination, because we detect the trailer as being too - # long and abort the connection. - with self.makefile() as fd: - fd.write(data) - read_http(fd, body='oh hai') - with self.assertRaises(ConnectionClosed): - read_http(fd, body='oh bye') - - @greentest.skipOnWindows('Maybe hangs') - def test_trailers_request_smuggling_missing_last_chunk_keep_alive(self): - # When something that looks like a request line comes in the trailer - # as the first line, immediately after an invalid last chunk. - # We detect this and abort the connection, because the - # whitespace in the GET line isn't a legal part of a trailer. - # If we didn't abort the connection, then, because we specified - # keep-alive, the server would be hanging around waiting for more input. - data = ( - b'POST /a HTTP/1.1\r\n' - b'Host: localhost\r\n' - b'Connection: keep-alive\r\n' - b'Transfer-Encoding: chunked\r\n' - b'\r\n' - b'2\r\noh\r\n' - b'4\r\n hai\r\n' - b'0' # last-chunk, but missing the \r\n - # Normally the final CRLF would go here, but if you put in a - # trailer, it doesn't. - # b'\r\n' - b'GET /path2?a=:123 HTTP/1.1\r\n' - b'Host: a.com\r\n' - b'Connection: close\r\n' - b'\r\n' - ) - with self.makefile() as fd: - fd.write(data) - read_http(fd, body='oh hai') - with self.assertRaises(ConnectionClosed): - read_http(fd) - - self.assertEqual(self.calls, 1) - - @greentest.skipOnWindows('Maybe hangs') - def test_trailers_request_smuggling_header_first(self): - # When something that looks like a header comes in the first line. - data = ( - b'POST /a HTTP/1.1\r\n' - b'Host: localhost\r\n' - b'Connection: keep-alive\r\n' - b'Transfer-Encoding: chunked\r\n' - b'\r\n' - b'2\r\noh\r\n' - b'4\r\n hai\r\n' - b'0\r\n' # last-chunk, but only one CRLF - b'Header: value\r\n' - b'GET /path2?a=:123 HTTP/1.1\r\n' - b'Host: a.com\r\n' - b'Connection: close\r\n' - b'\r\n' - ) - with self.makefile() as fd: - fd.write(data) - read_http(fd, body='oh hai') - with self.assertRaises(ConnectionClosed): - read_http(fd, code=400) - - self.assertEqual(self.calls, 1) - - @greentest.skipOnWindows('Maybe hangs') - def test_trailers_request_smuggling_request_terminates_then_header(self): - data = ( - b'POST /a HTTP/1.1\r\n' - b'Host: localhost\r\n' - b'Connection: keep-alive\r\n' - b'Transfer-Encoding: chunked\r\n' - b'\r\n' - b'2\r\noh\r\n' - b'4\r\n hai\r\n' - b'0\r\n' # last-chunk - b'\r\n' - b'Header: value' - b'GET /path2?a=:123 HTTP/1.1\r\n' - b'Host: a.com\r\n' - b'Connection: close\r\n' - b'\r\n' - ) - with self.makefile() as fd: - fd.write(data) - read_http(fd, body='oh hai') - read_http(fd, code=400) - - self.assertEqual(self.calls, 1) - - -class TestUseWrite(TestCase): - - body = b'abcde' - end = b'end' - content_length = str(len(body + end)) - - def application(self, env, start_response): - if env['PATH_INFO'] == '/explicit-content-length': - write = start_response('200 OK', [('Content-Type', 'text/plain'), - ('Content-Length', self.content_length)]) - write(self.body) - elif env['PATH_INFO'] == '/no-content-length': - write = start_response('200 OK', [('Content-Type', 'text/plain')]) - write(self.body) - elif env['PATH_INFO'] == '/no-content-length-twice': - write = start_response('200 OK', [('Content-Type', 'text/plain')]) - write(self.body) - write(self.body) - else: - # pylint:disable-next=broad-exception-raised - raise Exception('Invalid url') - return [self.end] - - def test_explicit_content_length(self): - with self.makefile() as fd: - fd.write('GET /explicit-content-length HTTP/1.1\r\nHost: localhost\r\nConnection: close\r\n\r\n') - response = read_http(fd, body=self.body + self.end) - response.assertHeader('Content-Length', self.content_length) - response.assertHeader('Transfer-Encoding', False) - - def test_no_content_length(self): - with self.makefile() as fd: - fd.write('GET /no-content-length HTTP/1.1\r\nHost: localhost\r\nConnection: close\r\n\r\n') - response = read_http(fd, body=self.body + self.end) - - response.assertHeader('Content-Length', False) - response.assertHeader('Transfer-Encoding', 'chunked') - - def test_no_content_length_twice(self): - with self.makefile() as fd: - fd.write('GET /no-content-length-twice HTTP/1.1\r\nHost: localhost\r\nConnection: close\r\n\r\n') - response = read_http(fd, body=self.body + self.body + self.end) - - response.assertHeader('Content-Length', False) - response.assertHeader('Transfer-Encoding', 'chunked') - self.assertEqual(response.chunks, [self.body, self.body, self.end]) - - -class HttpsTestCase(TestCase): - - certfile = os.path.join(os.path.dirname(__file__), 'test_server.crt') - keyfile = os.path.join(os.path.dirname(__file__), 'test_server.key') - - def init_server(self, application): - self.server = pywsgi.WSGIServer((self.listen_addr, 0), application, - certfile=self.certfile, keyfile=self.keyfile) - - def urlopen(self, method='GET', post_body=None, **kwargs): # pylint:disable=arguments-differ - import ssl - with self.connect() as raw_sock: - with ssl.wrap_socket(raw_sock) as sock: # pylint:disable=deprecated-method,no-member - with sock.makefile(bufsize=1) as fd: # pylint:disable=unexpected-keyword-arg - fd.write('%s / HTTP/1.1\r\nHost: localhost\r\n' % method) - if post_body is not None: - fd.write('Content-Length: %s\r\n\r\n' % len(post_body)) - fd.write(post_body) - if kwargs.get('body') is None: - kwargs['body'] = post_body - else: - fd.write('\r\n') - fd.flush() - - return read_http(fd, **kwargs) - - def application(self, environ, start_response): - assert environ['wsgi.url_scheme'] == 'https', environ['wsgi.url_scheme'] - start_response('200 OK', [('Content-Type', 'text/plain')]) - return [environ['wsgi.input'].read(10)] - - -import gevent.ssl -HAVE_SSLCONTEXT = getattr(gevent.ssl, 'create_default_context') -if HAVE_SSLCONTEXT: - - class HttpsSslContextTestCase(HttpsTestCase): - def init_server(self, application): - # On 2.7, our certs don't line up with hostname. - # If we just use create_default_context as-is, we get - # `ValueError: check_hostname requires server_hostname`. - # If we set check_hostname to False, we get - # `SSLError: [SSL: PEER_DID_NOT_RETURN_A_CERTIFICATE] peer did not return a certificate` - # (Neither of which happens in Python 3.) But the unverified context - # works both places. See also test___example_servers.py - from gevent.ssl import _create_unverified_context # pylint:disable=no-name-in-module - context = _create_unverified_context() - context.load_cert_chain(certfile=self.certfile, keyfile=self.keyfile) - self.server = pywsgi.WSGIServer((self.listen_addr, 0), - application, ssl_context=context) - -class TestHttps(HttpsTestCase): - - if hasattr(socket, 'ssl'): - - def test_012_ssl_server(self): - result = self.urlopen(method="POST", post_body='abc') - self.assertEqual(result.body, 'abc') - - def test_013_empty_return(self): - result = self.urlopen() - self.assertEqual(result.body, '') - -if HAVE_SSLCONTEXT: - class TestHttpsWithContext(HttpsSslContextTestCase, TestHttps): # pylint:disable=too-many-ancestors - pass - -class TestInternational(TestCase): - validator = None # wsgiref.validate.IteratorWrapper([]) does not have __len__ - - def application(self, environ, start_response): - path_bytes = b'/\xd0\xbf\xd1\x80\xd0\xb8\xd0\xb2\xd0\xb5\xd1\x82' - # Under PY3, the escapes were decoded as latin-1 - path_bytes = path_bytes.decode('latin-1') - - self.assertEqual(environ['PATH_INFO'], path_bytes) - self.assertEqual(environ['QUERY_STRING'], '%D0%B2%D0%BE%D0%BF%D1%80%D0%BE%D1%81=%D0%BE%D1%82%D0%B2%D0%B5%D1%82') - start_response("200 PASSED", [('Content-Type', 'text/plain')]) - return [] - - def test(self): - with self.connect() as sock: - sock.sendall( - b'''GET /%D0%BF%D1%80%D0%B8%D0%B2%D0%B5%D1%82?%D0%B2%D0%BE%D0%BF%D1%80%D0%BE%D1%81=%D0%BE%D1%82%D0%B2%D0%B5%D1%82 HTTP/1.1 -Host: localhost -Connection: close - -'''.replace(b'\n', b'\r\n')) - with sock.makefile() as fd: - read_http(fd, reason='PASSED', chunks=False, body='', content_length=0) - - -class TestNonLatin1HeaderFromApplication(TestCase): - error_fatal = False # Allow sending the exception response, don't kill the greenlet - - validator = None # Don't validate the application, it's deliberately bad - header = b'\xe1\xbd\x8a3' # bomb in utf-8 bytes - should_error = True # non-native string under Py3 - - def setUp(self): - super(TestNonLatin1HeaderFromApplication, self).setUp() - self.errors = [] - - def tearDown(self): - self.errors = [] - super(TestNonLatin1HeaderFromApplication, self).tearDown() - - def application(self, environ, start_response): - # We return a header that cannot be encoded in latin-1 - try: - start_response("200 PASSED", - [('Content-Type', 'text/plain'), - ('Custom-Header', self.header)]) - except: - self.errors.append(sys.exc_info()[:2]) - raise - return [] - - def test(self): - with self.connect() as sock: - self.expect_one_error() - sock.sendall(b'''GET / HTTP/1.1\r\n\r\n''') - with sock.makefile() as fd: - if self.should_error: - read_http(fd, code=500, reason='Internal Server Error') - self.assert_error(where_type=pywsgi.SecureEnviron) - self.assertEqual(len(self.errors), 1) - _, v = self.errors[0] - self.assertIsInstance(v, UnicodeError) - else: - read_http(fd, code=200, reason='PASSED') - self.assertEqual(len(self.errors), 0) - - -class TestNonLatin1UnicodeHeaderFromApplication(TestNonLatin1HeaderFromApplication): - # Flip-flop of the superclass: Python 3 native string, Python 2 unicode object - header = u"\u1f4a3" # bomb in unicode - # Error both on py3 and py2. On py2, non-native string. On py3, native string - # that cannot be encoded to latin-1 - should_error = True - - -class TestInputReadline(TestCase): - # this test relies on the fact that readline() returns '' after it reached EOF - # this behaviour is not mandated by WSGI spec, it's just happens that gevent.wsgi behaves like that - # as such, this may change in the future - - validator = None - - def application(self, environ, start_response): - input = environ['wsgi.input'] - lines = [] - while True: - line = input.readline() - if not line: - break - line = line.decode('ascii') - lines.append(repr(line) + ' ') - start_response('200 hello', []) - return [l.encode('ascii') for l in lines] - - def test(self): - with self.makefile() as fd: - content = 'hello\n\nworld\n123' - fd.write('POST / HTTP/1.1\r\nHost: localhost\r\nConnection: close\r\n' - 'Content-Length: %s\r\n\r\n%s' % (len(content), content)) - fd.flush() - read_http(fd, reason='hello', body="'hello\\n' '\\n' 'world\\n' '123' ") - - -class TestInputIter(TestInputReadline): - - def application(self, environ, start_response): - input = environ['wsgi.input'] - lines = [] - for line in input: - if not line: - break - line = line.decode('ascii') - lines.append(repr(line) + ' ') - start_response('200 hello', []) - return [l.encode('ascii') for l in lines] - - -class TestInputReadlines(TestInputReadline): - - def application(self, environ, start_response): - input = environ['wsgi.input'] - lines = [l.decode('ascii') for l in input.readlines()] - lines = [repr(line) + ' ' for line in lines] - start_response('200 hello', []) - return [l.encode('ascii') for l in lines] - - -class TestInputN(TestCase): - # testing for this: - # File "/home/denis/work/gevent/gevent/pywsgi.py", line 70, in _do_read - # if length and length > self.content_length - self.position: - # TypeError: unsupported operand type(s) for -: 'NoneType' and 'int' - - validator = None - - def application(self, environ, start_response): - environ['wsgi.input'].read(5) - start_response('200 OK', []) - return [] - - def test(self): - self.urlopen() - - -class TestErrorInApplication(TestCase): - - error = object() - error_fatal = False - - def application(self, env, start_response): - self.error = greentest.ExpectedException('TestError.application') - raise self.error - - def test(self): - self.expect_one_error() - self.urlopen(code=500) - self.assert_error(greentest.ExpectedException, self.error) - - -class TestError_after_start_response(TestErrorInApplication): - - def application(self, env, start_response): - self.error = greentest.ExpectedException('TestError_after_start_response.application') - start_response('200 OK', [('Content-Type', 'text/plain')]) - raise self.error - - -class TestEmptyYield(TestCase): - - @staticmethod - def application(env, start_response): - start_response('200 OK', [('Content-Type', 'text/plain')]) - yield b"" - yield b"" - - def test_err(self): - chunks = [] - - with self.makefile() as fd: - fd.write('GET / HTTP/1.1\r\nHost: localhost\r\nConnection: close\r\n\r\n') - - read_http(fd, body='', chunks=chunks) - - garbage = fd.read() - self.assertEqual(garbage, b"", "got garbage: %r" % garbage) - - -class TestFirstEmptyYield(TestCase): - - @staticmethod - def application(env, start_response): - start_response('200 OK', [('Content-Type', 'text/plain')]) - yield b"" - yield b"hello" - - def test_err(self): - chunks = [b'hello'] - - with self.makefile() as fd: - fd.write('GET / HTTP/1.1\r\nHost: localhost\r\nConnection: close\r\n\r\n') - - read_http(fd, body='hello', chunks=chunks) - - garbage = fd.read() - self.assertEqual(garbage, b"") - - -class TestEmptyYield304(TestCase): - - @staticmethod - def application(env, start_response): - start_response('304 Not modified', []) - yield b"" - yield b"" - - def test_err(self): - with self.makefile() as fd: - fd.write('GET / HTTP/1.1\r\nHost: localhost\r\nConnection: close\r\n\r\n') - read_http(fd, code=304, body='', chunks=False) - garbage = fd.read() - self.assertEqual(garbage, b"") - - -class TestContentLength304(TestCase): - validator = None - - def application(self, env, start_response): - try: - start_response('304 Not modified', [('Content-Length', '100')]) - except AssertionError as ex: - start_response('200 Raised', []) - return ex.args - raise AssertionError('start_response did not fail but it should') - - def test_err(self): - body = "Invalid Content-Length for 304 response: '100' (must be absent or zero)" - with self.makefile() as fd: - fd.write('GET / HTTP/1.1\r\nHost: localhost\r\nConnection: close\r\n\r\n') - - read_http(fd, code=200, reason='Raised', body=body, chunks=False) - garbage = fd.read() - self.assertEqual(garbage, b"") - - -class TestBody304(TestCase): - validator = None - - def application(self, env, start_response): - start_response('304 Not modified', []) - return [b'body'] - - def test_err(self): - with self.makefile() as fd: - fd.write('GET / HTTP/1.1\r\nHost: localhost\r\nConnection: close\r\n\r\n') - with self.assertRaises(AssertionError) as exc: - read_http(fd) - ex = exc.exception - self.assertEqual(str(ex), 'The 304 response must have no body') - - -class TestWrite304(TestCase): - validator = None - error_raised = None - - def application(self, env, start_response): - write = start_response('304 Not modified', []) - self.error_raised = False - try: - write('body') - except AssertionError as ex: - self.error_raised = True - raise ExpectedAssertionError(*ex.args) - - def test_err(self): - with self.makefile() as fd: - fd.write(b'GET / HTTP/1.1\r\nHost: localhost\r\nConnection: close\r\n\r\n') - with self.assertRaises(AssertionError) as exc: - read_http(fd) - ex = exc.exception - - self.assertEqual(str(ex), 'The 304 response must have no body') - self.assertTrue(self.error_raised, 'write() must raise') - - -class TestEmptyWrite(TestEmptyYield): - - @staticmethod - def application(env, start_response): - write = start_response('200 OK', [('Content-Type', 'text/plain')]) - write(b"") - write(b"") - return [] - - -class BadRequestTests(TestCase): - validator = None - # pywsgi checks content-length, but wsgi does not - content_length = None - - assert TestCase.handler_class._print_unexpected_exc - - class handler_class(TestCase.handler_class): - def _print_unexpected_exc(self): - raise AssertionError("Should not print a traceback") - - def application(self, env, start_response): - self.assertEqual(env['CONTENT_LENGTH'], self.content_length) - start_response('200 OK', [('Content-Type', 'text/plain')]) - return [b'hello'] - - def test_negative_content_length(self): - self.content_length = '-100' - with self.makefile() as fd: - fd.write('GET / HTTP/1.1\r\nHost: localhost\r\nContent-Length: %s\r\n\r\n' % self.content_length) - read_http(fd, code=(200, 400)) - - def test_illegal_content_length(self): - self.content_length = 'abc' - with self.makefile() as fd: - fd.write('GET / HTTP/1.1\r\nHost: localhost\r\nContent-Length: %s\r\n\r\n' % self.content_length) - read_http(fd, code=(200, 400)) - - def test_bad_request_line_with_percent(self): - # If the request is invalid and contains Python formatting characters (%) - # we don't fail to log the error and we do generate a 400. - # https://github.com/gevent/gevent/issues/1708 - bad_request = 'GET / HTTP %\r\n' - with self.makefile() as fd: - fd.write(bad_request) - read_http(fd, code=400) - - -class ChunkedInputTests(TestCase): - dirt = "" - validator = None - - def application(self, env, start_response): - input = env['wsgi.input'] - response = [] - - pi = env["PATH_INFO"] - - if pi == "/short-read": - d = input.read(10) - response = [d] - elif pi == "/lines": - for x in input: - response.append(x) - elif pi == "/ping": - input.read(1) - response.append(b"pong") - else: - raise RuntimeError("bad path") - - start_response('200 OK', [('Content-Type', 'text/plain')]) - return response - - def chunk_encode(self, chunks, dirt=None): - if dirt is None: - dirt = self.dirt - - return chunk_encode(chunks, dirt=dirt) - - def body(self, dirt=None): - return self.chunk_encode(["this", " is ", "chunked", "\nline", " 2", "\n", "line3", ""], dirt=dirt) - - def ping(self, fd): - fd.write("GET /ping HTTP/1.1\r\n\r\n") - read_http(fd, body="pong") - - def ping_if_possible(self, fd): - self.ping(fd) - - def test_short_read_with_content_length(self): - body = self.body() - req = b"POST /short-read HTTP/1.1\r\ntransfer-encoding: Chunked\r\nContent-Length:1000\r\n\r\n" + body - with self.connect() as conn: - with conn.makefile(bufsize=1) as fd: # pylint:disable=unexpected-keyword-arg - fd.write(req) - read_http(fd, body="this is ch") - - self.ping_if_possible(fd) - - def test_short_read_with_zero_content_length(self): - body = self.body() - req = b"POST /short-read HTTP/1.1\r\ntransfer-encoding: Chunked\r\nContent-Length:0\r\n\r\n" + body - #print("REQUEST:", repr(req)) - - with self.makefile() as fd: - fd.write(req) - read_http(fd, body="this is ch") - - self.ping_if_possible(fd) - - def test_short_read(self): - body = self.body() - req = b"POST /short-read HTTP/1.1\r\ntransfer-encoding: Chunked\r\n\r\n" + body - - with self.makefile() as fd: - fd.write(req) - read_http(fd, body="this is ch") - - self.ping_if_possible(fd) - - def test_dirt(self): - body = self.body(dirt="; here is dirt\0bla") - req = b"POST /ping HTTP/1.1\r\ntransfer-encoding: Chunked\r\n\r\n" + body - - with self.makefile() as fd: - fd.write(req) - read_http(fd, body="pong") - - self.ping_if_possible(fd) - - def test_chunked_readline(self): - body = self.body() - req = "POST /lines HTTP/1.1\r\nContent-Length: %s\r\ntransfer-encoding: Chunked\r\n\r\n" % (len(body)) - req = req.encode('latin-1') - req += body - - with self.makefile() as fd: - fd.write(req) - read_http(fd, body='this is chunked\nline 2\nline3') - - def test_close_before_finished(self): - self.expect_one_error() - body = b'4\r\nthi' - req = b"POST /short-read HTTP/1.1\r\ntransfer-encoding: Chunked\r\n\r\n" + body - with self.connect() as sock: - with sock.makefile(bufsize=1, mode='wb') as fd:# pylint:disable=unexpected-keyword-arg - fd.write(req) - fd.close() - - # Python 3 keeps the socket open even though the only - # makefile is gone; python 2 closed them both (because there were - # no outstanding references to the socket). Closing is essential for the server - # to get the message that the read will fail. It's better to be explicit - # to avoid a ResourceWarning - sock.close() - # Under Py2 it still needs to go away, which was implicit before - del fd - del sock - - gevent.get_hub().loop.update_now() - gevent.sleep(0.01) # timing needed for cpython - - if greentest.PYPY: - # XXX: Something is keeping the socket alive, - # by which I mean, the close event is not propagating to the server - # and waking up its recv() loop...we are stuck with the three bytes of - # 'thi' in the buffer and trying to read the forth. No amount of tinkering - # with the timing changes this...the only thing that does is running a - # GC and letting some object get collected. Might this be a problem in real life? - - import gc - gc.collect() - gevent.sleep(0.01) - gevent.get_hub().loop.update_now() - gc.collect() - gevent.sleep(0.01) - - # XXX2: Sometimes windows and PyPy/Travis fail to get this error, leading to a test failure. - # This would have to be due to the socket being kept around and open, - # not closed at the low levels. I haven't seen this locally. - # In the PyPy case, I've seen the IOError reported on the console, but not - # captured in the variables. - # https://travis-ci.org/gevent/gevent/jobs/329232976#L1374 - self.assert_error(IOError, 'unexpected end of file while parsing chunked data') - - -class Expect100ContinueTests(TestCase): - validator = None - - def application(self, environ, start_response): - content_length = int(environ['CONTENT_LENGTH']) - if content_length > 1024: - start_response('417 Expectation Failed', [('Content-Length', '7'), ('Content-Type', 'text/plain')]) - return [b'failure'] - - # pywsgi did sent a "100 continue" for each read - # see http://code.google.com/p/gevent/issues/detail?id=93 - text = environ['wsgi.input'].read(1) - text += environ['wsgi.input'].read(content_length - 1) - start_response('200 OK', [('Content-Length', str(len(text))), ('Content-Type', 'text/plain')]) - return [text] - - def test_continue(self): - with self.makefile() as fd: - padding = 'a'*1025 - fd.write('PUT / HTTP/1.1\r\nHost: localhost\r\nContent-length: 1025\r\nExpect: 100-continue\r\n\r\n' + padding) - read_http(fd, code=417, body="failure") - - fd.write('PUT / HTTP/1.1\r\nHost: localhost\r\nContent-length: 7\r\nExpect: 100-continue\r\n\r\ntesting') - read_http(fd, code=100) - read_http(fd, body="testing") - - with self.makefile() as fd: - padding = 'a'*947 - body = 'PUT / HTTP/1.1\r\nHost: localhost\r\nContent-length: {}\r\nExpect: 100-continue\r\n\r\n{}'.format(len(padding), padding) - # The following content should be regarded as one request. - fd.write('PUT / HTTP/1.1\r\nHost: localhost\r\nContent-length: {}\r\nExpect: 100-continue\r\n\r\n{}'.format(len(body), body)) - read_http(fd, code=417, body="failure") - - fd.write('PUT / HTTP/1.1\r\nHost: localhost\r\nContent-length: 7\r\nExpect: 100-continue\r\n\r\ntesting') - read_http(fd, code=100) - # If there was a smuggling issue beforehand, what is obtained here will be aaa..aaa - read_http(fd, body="testing") - - -class MultipleCookieHeadersTest(TestCase): - - validator = None - - def application(self, environ, start_response): - self.assertEqual(environ['HTTP_COOKIE'], 'name1="value1"; name2="value2"') - self.assertEqual(environ['HTTP_COOKIE2'], 'nameA="valueA"; nameB="valueB"') - start_response('200 OK', []) - return [] - - def test(self): - with self.makefile() as fd: - fd.write('''GET / HTTP/1.1 -Host: localhost -Cookie: name1="value1" -Cookie2: nameA="valueA" -Cookie2: nameB="valueB" -Cookie: name2="value2"\n\n'''.replace('\n', '\r\n')) - read_http(fd) - - -class TestLeakInput(TestCase): - - _leak_wsgi_input = None - _leak_environ = None - - def tearDown(self): - TestCase.tearDown(self) - self._leak_wsgi_input = None - self._leak_environ = None - - def application(self, environ, start_response): - pi = environ["PATH_INFO"] - self._leak_wsgi_input = environ["wsgi.input"] - self._leak_environ = environ - if pi == "/leak-frame": - environ["_leak"] = sys._getframe(0) - - text = b"foobar" - start_response('200 OK', [('Content-Length', str(len(text))), ('Content-Type', 'text/plain')]) - return [text] - - def test_connection_close_leak_simple(self): - with self.makefile() as fd: - fd.write(b"GET / HTTP/1.0\r\nConnection: close\r\n\r\n") - d = fd.read() - self.assertTrue(d.startswith(b"HTTP/1.1 200 OK"), d) - - def test_connection_close_leak_frame(self): - with self.makefile() as fd: - fd.write(b"GET /leak-frame HTTP/1.0\r\nConnection: close\r\n\r\n") - d = fd.read() - self.assertTrue(d.startswith(b"HTTP/1.1 200 OK"), d) - self._leak_environ.pop('_leak') - -class TestHTTPResponseSplitting(TestCase): - # The validator would prevent the app from doing the - # bad things it needs to do - validator = None - - status = '200 OK' - headers = () - start_exc = None - - def setUp(self): - TestCase.setUp(self) - self.start_exc = None - self.status = TestHTTPResponseSplitting.status - self.headers = TestHTTPResponseSplitting.headers - - def tearDown(self): - TestCase.tearDown(self) - self.start_exc = None - - def application(self, environ, start_response): - try: - start_response(self.status, self.headers) - except Exception as e: # pylint: disable=broad-except - self.start_exc = e - else: - self.start_exc = None - return () - - def _assert_failure(self, message): - with self.makefile() as fd: - fd.write('GET / HTTP/1.0\r\nHost: localhost\r\n\r\n') - fd.read() - self.assertIsInstance(self.start_exc, ValueError) - self.assertEqual(self.start_exc.args[0], message) - - def test_newline_in_status(self): - self.status = '200 OK\r\nConnection: close\r\nContent-Length: 0\r\n\r\n' - self._assert_failure('carriage return or newline in status') - - def test_newline_in_header_value(self): - self.headers = [('Test', 'Hi\r\nConnection: close')] - self._assert_failure('carriage return or newline in header value') - - def test_newline_in_header_name(self): - self.headers = [('Test\r\n', 'Hi')] - self._assert_failure('carriage return or newline in header name') - - -class TestInvalidEnviron(TestCase): - validator = None - # check that WSGIServer does not insert any default values for CONTENT_LENGTH - - def application(self, environ, start_response): - for key, value in environ.items(): - if key in ('CONTENT_LENGTH', 'CONTENT_TYPE') or key.startswith('HTTP_'): - if key != 'HTTP_HOST': - raise ExpectedAssertionError('Unexpected environment variable: %s=%r' % ( - key, value)) - start_response('200 OK', []) - return [] - - def test(self): - with self.makefile() as fd: - fd.write('GET / HTTP/1.0\r\nHost: localhost\r\n\r\n') - read_http(fd) - with self.makefile() as fd: - fd.write('GET / HTTP/1.1\r\nHost: localhost\r\n\r\n') - read_http(fd) - - -class TestInvalidHeadersDropped(TestCase): - validator = None - # check that invalid headers with a _ are dropped - - def application(self, environ, start_response): - self.assertNotIn('HTTP_X_AUTH_USER', environ) - start_response('200 OK', []) - return [] - - def test(self): - with self.makefile() as fd: - fd.write('GET / HTTP/1.0\r\nx-auth_user: bob\r\n\r\n') - read_http(fd) - - -class TestHandlerSubclass(TestCase): - - validator = None - - class handler_class(TestCase.handler_class): - - def read_requestline(self): - data = self.rfile.read(7) - if data[0] == b'<'[0]: # py3: indexing bytes returns ints. sigh. - # Returning nothing stops handle_one_request() - # Note that closing or even deleting self.socket() here - # can lead to the read side throwing Connection Reset By Peer, - # depending on the Python version and OS - data += self.rfile.read(15) - if data.lower() == b'': - self.socket.sendall(b'HELLO') - else: - self.log_error('Invalid request: %r', data) - return None - return data + self.rfile.readline() - - def application(self, environ, start_response): - start_response('200 OK', []) - return [] - - def test(self): - with self.makefile() as fd: - fd.write(b'\x00') - fd.flush() # flush() is needed on PyPy, apparently it buffers slightly differently - self.assertEqual(fd.read(), b'HELLO') - - with self.makefile() as fd: - fd.write('GET / HTTP/1.1\r\nHost: localhost\r\nConnection: close\r\n\r\n') - fd.flush() - read_http(fd) - - with self.makefile() as fd: - # Trigger an error - fd.write('\x00') - fd.flush() - self.assertEqual(fd.read(), b'') - - -class TestErrorAfterChunk(TestCase): - validator = None - - @staticmethod - def application(env, start_response): - start_response('200 OK', [('Content-Type', 'text/plain')]) - yield b"hello" - raise greentest.ExpectedException('TestErrorAfterChunk') - - def test(self): - with self.makefile() as fd: - self.expect_one_error() - fd.write('GET / HTTP/1.1\r\nHost: localhost\r\nConnection: keep-alive\r\n\r\n') - with self.assertRaises(ValueError): - read_http(fd) - self.assert_error(greentest.ExpectedException) - - -def chunk_encode(chunks, dirt=None): - if dirt is None: - dirt = "" - - b = b"" - for c in chunks: - x = "%x%s\r\n%s\r\n" % (len(c), dirt, c) - b += x.encode('ascii') - return b - - -class TestInputRaw(greentest.BaseTestCase): - def make_input(self, data, content_length=None, chunked_input=False): - if isinstance(data, list): - data = chunk_encode(data) - chunked_input = True - elif isinstance(data, str): - data = data.encode("ascii") - return Input(StringIO(data), content_length=content_length, chunked_input=chunked_input) - - def assertEqual(self, first, second, msg=None): - if isinstance(second, str): - second = second.encode('ascii') - super(TestInputRaw, self).assertEqual(first, second, msg) - - def test_short_post(self): - i = self.make_input("1", content_length=2) - self.assertRaises(IOError, i.read) - - def test_short_post_read_with_length(self): - i = self.make_input("1", content_length=2) - self.assertRaises(IOError, i.read, 2) - - def test_short_post_readline(self): - i = self.make_input("1", content_length=2) - self.assertRaises(IOError, i.readline) - - def test_post(self): - i = self.make_input("12", content_length=2) - data = i.read() - self.assertEqual(data, "12") - - def test_post_read_with_length(self): - i = self.make_input("12", content_length=2) - data = i.read(10) - self.assertEqual(data, "12") - - def test_chunked(self): - i = self.make_input(["1", "2", ""]) - data = i.read() - self.assertEqual(data, "12") - - def test_chunked_read_with_length(self): - i = self.make_input(["1", "2", ""]) - data = i.read(10) - self.assertEqual(data, "12") - - def test_chunked_missing_chunk(self): - i = self.make_input(["1", "2"]) - self.assertRaises(IOError, i.read) - - def test_chunked_missing_chunk_read_with_length(self): - i = self.make_input(["1", "2"]) - self.assertRaises(IOError, i.read, 10) - - def test_chunked_missing_chunk_readline(self): - i = self.make_input(["1", "2"]) - self.assertRaises(IOError, i.readline) - - def test_chunked_short_chunk(self): - i = self.make_input("2\r\n1", chunked_input=True) - self.assertRaises(IOError, i.read) - - def test_chunked_short_chunk_read_with_length(self): - i = self.make_input("2\r\n1", chunked_input=True) - self.assertRaises(IOError, i.read, 2) - - def test_chunked_short_chunk_readline(self): - i = self.make_input("2\r\n1", chunked_input=True) - self.assertRaises(IOError, i.readline) - - def test_32bit_overflow(self): - # https://github.com/gevent/gevent/issues/289 - # Should not raise an OverflowError on Python 2 - data = b'asdf\nghij\n' - long_data = b'a' * (pywsgi.MAX_REQUEST_LINE + 10) - long_data += b'\n' - data += long_data - partial_data = b'qjk\n' # Note terminating \n - n = 25 * 1000000000 - if hasattr(n, 'bit_length'): - self.assertEqual(n.bit_length(), 35) - - i = self.make_input(data, content_length=n) - # No size hint, but we have too large a content_length to fit - self.assertEqual(i.readline(), b'asdf\n') - # Large size hint - self.assertEqual(i.readline(n), b'ghij\n') - self.assertEqual(i.readline(n), long_data) - - # Now again with the real content length, assuring we can't read past it - i = self.make_input(data + partial_data, content_length=len(data) + 1) - self.assertEqual(i.readline(), b'asdf\n') - self.assertEqual(i.readline(n), b'ghij\n') - self.assertEqual(i.readline(n), long_data) - # Now we've reached content_length so we shouldn't be able to - # read anymore except the one byte remaining - self.assertEqual(i.readline(n), b'q') - - -class Test414(TestCase): - - @staticmethod - def application(env, start_response): - raise AssertionError('should not get there') - - def test(self): - longline = 'x' * 20000 - with self.makefile() as fd: - fd.write(('''GET /%s HTTP/1.0\r\nHello: world\r\n\r\n''' % longline).encode('latin-1')) - read_http(fd, code=414) - - -class TestLogging(TestCase): - - # Something that gets wrapped in a LoggingLogAdapter - class Logger(object): - accessed = None - logged = None - thing = None - - def log(self, level, msg): - self.logged = (level, msg) - - def access(self, msg): - self.accessed = msg - - def get_thing(self): - return self.thing - - def init_logger(self): - return self.Logger() - - @staticmethod - def application(env, start_response): - start_response('200 OK', [('Content-Type', 'text/plain')]) - return [b'hello'] - - # Tests for issue #663 - - def test_proxy_methods_on_log(self): - # An object that looks like a logger gets wrapped - # with a proxy that - self.assertTrue(isinstance(self.server.log, pywsgi.LoggingLogAdapter)) - self.server.log.access("access") - self.server.log.write("write") - self.assertEqual(self.server.log.accessed, "access") - self.assertEqual(self.server.log.logged, (20, "write")) - - def test_set_attributes(self): - # Not defined by the wrapper, it goes to the logger - self.server.log.thing = 42 - self.assertEqual(self.server.log.get_thing(), 42) - - del self.server.log.thing - self.assertEqual(self.server.log.get_thing(), None) - - def test_status_log(self): - # Issue 664: Make sure we format the status line as a string - self.urlopen() - msg = self.server.log.logged[1] - self.assertTrue('"GET / HTTP/1.1" 200 ' in msg, msg) - - # Issue 756: Make sure we don't throw a newline on the end - self.assertTrue('\n' not in msg, msg) - -class TestEnviron(TestCase): - - # The wsgiref validator asserts type(environ) is dict. - # https://mail.python.org/pipermail/web-sig/2016-March/005455.html - validator = None - - def init_server(self, application): - super(TestEnviron, self).init_server(application) - self.server.environ_class = pywsgi.SecureEnviron - - def application(self, env, start_response): - self.assertIsInstance(env, pywsgi.SecureEnviron) - start_response('200 OK', [('Content-Type', 'text/plain')]) - return [] - - def test_environ_is_secure_by_default(self): - self.urlopen() - - def test_default_secure_repr(self): - environ = pywsgi.SecureEnviron() - self.assertIn('"}), str(environ)) - self.assertEqual(repr({'key': ""}), repr(environ)) - - environ.whitelist_keys = ('key',) - self.assertEqual(str({'key': 'value'}), str(environ)) - self.assertEqual(repr({'key': 'value'}), repr(environ)) - - del environ.whitelist_keys - - def test_override_class_defaults(self): - class EnvironClass(pywsgi.SecureEnviron): - __slots__ = () - - environ = EnvironClass() - - self.assertTrue(environ.secure_repr) - EnvironClass.default_secure_repr = False - self.assertFalse(environ.secure_repr) - - self.assertEqual(str({}), str(environ)) - self.assertEqual(repr({}), repr(environ)) - - EnvironClass.default_secure_repr = True - EnvironClass.default_whitelist_keys = ('key',) - - environ['key'] = 1 - self.assertEqual(str({'key': 1}), str(environ)) - self.assertEqual(repr({'key': 1}), repr(environ)) - - # Clean up for leaktests - del environ - del EnvironClass - import gc; gc.collect() - - - def test_copy_still_secure(self): - for cls in (pywsgi.Environ, pywsgi.SecureEnviron): - self.assertIsInstance(cls().copy(), cls) - - def test_pickle_copy_returns_dict(self): - # Anything going through copy.copy/pickle should - # return the same pickle that a dict would. - import pickle - import json - - for cls in (pywsgi.Environ, pywsgi.SecureEnviron): - bltin = {'key': 'value'} - env = cls(bltin) - self.assertIsInstance(env, cls) - self.assertEqual(bltin, env) - self.assertEqual(env, bltin) - - for protocol in range(0, pickle.HIGHEST_PROTOCOL + 1): - # It's impossible to get a subclass of dict to pickle - # identically, but it can restore identically - env_dump = pickle.dumps(env, protocol) - self.assertNotIn(b'Environ', env_dump) - loaded = pickle.loads(env_dump) - self.assertEqual(type(loaded), dict) - - self.assertEqual(json.dumps(bltin), json.dumps(env)) - - -if __name__ == '__main__': - greentest.main() diff --git a/venv/lib/python3.9/site-packages/gevent/tests/test__queue.py b/venv/lib/python3.9/site-packages/gevent/tests/test__queue.py deleted file mode 100644 index c128637..0000000 --- a/venv/lib/python3.9/site-packages/gevent/tests/test__queue.py +++ /dev/null @@ -1,607 +0,0 @@ -import unittest - -import gevent.testing as greentest -from gevent.testing import TestCase -import gevent -from gevent.hub import get_hub, LoopExit -from gevent import util -from gevent import queue -from gevent.queue import Empty, Full -from gevent.event import AsyncResult -from gevent.testing.timing import AbstractGenericGetTestCase - -# pylint:disable=too-many-ancestors -class UsesOnlyOneItemMixin: - # These tests only place one item at a time in - # the queue, so they can work for Queue, SimpleQueue, LifoQueue, - # and Channel - - SUPPORTS_PUTTING_WITHOUT_GETTING = True - - def test_put_nowait_simple(self): - result = [] - q = self._makeOne(1) - - def store_result(func, *args): - result.append(func(*args)) - - run_callback = get_hub().loop.run_callback - - run_callback(store_result, util.wrap_errors(Full, q.put_nowait), 2) - run_callback(store_result, util.wrap_errors(Full, q.put_nowait), 3) - gevent.sleep(0) - self.assertEqual(len(result), 2) - if self.SUPPORTS_PUTTING_WITHOUT_GETTING: - self.assertIsNone(result[0], result) - else: - self.assertIsInstance(result[0], queue.Full, result) - self.assertIsInstance(result[1], queue.Full, result) - - # put_nowait must work from the mainloop - def test_put_nowait_unlock(self): - result = [] - q = self._makeOne() - p = gevent.spawn(q.get) - - def store_result(func, *args): - result.append(func(*args)) - - self.assertTrue(q.empty(), q) - if self.SUPPORTS_PUTTING_WITHOUT_GETTING: - assertFull = self.assertFalse - else: - assertFull = self.assertTrue - - assertFull(q.full(), q) - gevent.sleep(0.001) - - self.assertTrue(q.empty(), q) - assertFull(q.full(), q) - - get_hub().loop.run_callback(store_result, q.put_nowait, 10) - - self.assertFalse(p.ready(), p) - gevent.sleep(0.001) - - self.assertEqual(result, [None]) - self.assertTrue(p.ready(), p) - assertFull(q.full(), q) - self.assertTrue(q.empty(), q) - - def test_send_last(self): - q = self._makeOne() - - def waiter(q): - with gevent.Timeout(0.1 if not greentest.RUNNING_ON_APPVEYOR else 0.5): - self.assertEqual(q.get(), 'hi2') - return "OK" - - p = gevent.spawn(waiter, q) - gevent.sleep(0.01) - q.put('hi2') - gevent.sleep(0.01) - assert p.get(timeout=0) == "OK" - - - def test_init_and_bottleneck_methods(self): - if not self.SUPPORTS_PUTTING_WITHOUT_GETTING: - self.skipTest('Needs to be able to put and get') - - # subclasses of stdlib queues. - class X(self._getFUT()): - initted = None - get_count = 0 - put_count = 0 - - def _init(self, maxsize): - super()._init(maxsize) - self.initted = True - - def _get(self): - self.get_count += 1 - return super()._get() - - def _put(self, item): - self.put_count += 1 - return super()._put(item) - - x = X() - x.put('hi') - self.assertEqual(x.get(), 'hi') - self.assertEqual(x.put_count, 1) - self.assertEqual(x.get_count, 1) - self.assertTrue(x.initted) - - -class SubscriptMixin: - def _getFUT(self): - raise NotImplementedError - - def _makeOne(self, *args, **kwargs): - return self._getFUT()(*args, **kwargs) - - def test_subscript(self): - import queue as stdlib_queue - kind = self._getFUT() - try: - stdlib_kind = getattr(stdlib_queue, kind.__name__) - except AttributeError: - assert kind.__name__ == 'Channel' - import types - self.assertIsInstance(kind[int], types.GenericAlias) - else: - self.assertIsNot(kind, stdlib_kind) - self.assertIsInstance(kind[int], type(stdlib_kind[int])) - - -class TestSimpleQueue(SubscriptMixin, UsesOnlyOneItemMixin, TestCase): - - def _getFUT(self): - return queue.SimpleQueue - - def test_get_nowait_simple(self): - result = [] - q = self._makeOne(1) - q.put(4) - - def store_result(func, *args): - result.append(func(*args)) - - run_callback = get_hub().loop.run_callback - - run_callback(store_result, util.wrap_errors(Empty, q.get_nowait)) - run_callback(store_result, util.wrap_errors(Empty, q.get_nowait)) - gevent.sleep(0) - self.assertEqual(len(result), 2) - self.assertEqual(result[0], 4) - self.assertIsInstance(result[1], Empty) - - # get_nowait must work from the mainloop - def test_get_nowait_unlock(self): - result = [] - q = self._makeOne(1) - p = gevent.spawn(q.put, 5) - - def store_result(func, *args): - result.append(func(*args)) - - assert q.empty(), q - gevent.sleep(0) - assert q.full(), q - get_hub().loop.run_callback(store_result, q.get_nowait) - gevent.sleep(0) - assert q.empty(), q - assert result == [5], result - assert p.ready(), p - assert p.dead, p - assert q.empty(), q - - def test_send_first(self): - self.switch_expected = False - q = self._makeOne() - q.put('hi') - self.assertEqual(q.peek(), 'hi') - self.assertEqual(q.get(), 'hi') - - def test_peek_empty(self): - q = self._makeOne() - # No putters waiting, in the main loop: LoopExit - with self.assertRaises(LoopExit): - q.peek() - - def waiter(q): - self.assertRaises(Empty, q.peek, timeout=0.01) - g = gevent.spawn(waiter, q) - gevent.sleep(0.1) - g.join() - - def test_peek_multi_greenlet(self): - q = self._makeOne() - g = gevent.spawn(q.peek) - g.start() - gevent.sleep(0) - q.put(1) - g.join() - self.assertTrue(g.exception is None) - self.assertEqual(q.peek(), 1) - - def test_max_size(self): - q = self._makeOne(2) - results = [] - - def putter(q): - q.put('a') - results.append('a') - q.put('b') - results.append('b') - q.put('c') - results.append('c') - return "OK" - - p = gevent.spawn(putter, q) - gevent.sleep(0) - self.assertEqual(results, ['a', 'b']) - self.assertEqual(q.get(), 'a') - gevent.sleep(0) - self.assertEqual(results, ['a', 'b', 'c']) - self.assertEqual(q.get(), 'b') - self.assertEqual(q.get(), 'c') - assert p.get(timeout=0) == "OK" - - def test_multiple_waiters(self): - # tests that multiple waiters get their results back - q = self._makeOne() - - def waiter(q, evt): - evt.set(q.get()) - - sendings = ['1', '2', '3', '4'] - evts = [AsyncResult() for x in sendings] - for i, _ in enumerate(sendings): - gevent.spawn(waiter, q, evts[i]) # XXX use waitall for them - - gevent.sleep(0.01) # get 'em all waiting - - results = set() - - def collect_pending_results(): - for e in evts: - with gevent.Timeout(0.001, False): - x = e.get() - results.add(x) - return len(results) - - q.put(sendings[0]) - self.assertEqual(collect_pending_results(), 1) - q.put(sendings[1]) - self.assertEqual(collect_pending_results(), 2) - q.put(sendings[2]) - q.put(sendings[3]) - self.assertEqual(collect_pending_results(), 4) - - def test_waiters_that_cancel(self): - q = self._makeOne() - - def do_receive(q, evt): - with gevent.Timeout(0, RuntimeError()): - try: - result = q.get() - evt.set(result) # pragma: no cover (should have raised) - except RuntimeError: - evt.set('timed out') - - evt = AsyncResult() - gevent.spawn(do_receive, q, evt) - self.assertEqual(evt.get(), 'timed out') - - q.put('hi') - self.assertEqual(q.get(), 'hi') - - def test_senders_that_die(self): - q = self._makeOne() - - def do_send(q): - q.put('sent') - - gevent.spawn(do_send, q) - self.assertEqual(q.get(), 'sent') - - def test_two_waiters_one_dies(self): - - def waiter(q, evt): - evt.set(q.get()) - - def do_receive(q, evt): - with gevent.Timeout(0, RuntimeError()): - try: - result = q.get() - evt.set(result) # pragma: no cover (should have raised) - except RuntimeError: - evt.set('timed out') - - q = self._makeOne() - dying_evt = AsyncResult() - waiting_evt = AsyncResult() - gevent.spawn(do_receive, q, dying_evt) - gevent.spawn(waiter, q, waiting_evt) - gevent.sleep(0.1) - q.put('hi') - self.assertEqual(dying_evt.get(), 'timed out') - self.assertEqual(waiting_evt.get(), 'hi') - - def test_two_bogus_waiters(self): - def do_receive(q, evt): - with gevent.Timeout(0, RuntimeError()): - try: - result = q.get() - evt.set(result) # pragma: no cover (should have raised) - except RuntimeError: - evt.set('timed out') - - q = self._makeOne() - e1 = AsyncResult() - e2 = AsyncResult() - gevent.spawn(do_receive, q, e1) - gevent.spawn(do_receive, q, e2) - gevent.sleep(0.1) - q.put('sent') - self.assertEqual(e1.get(), 'timed out') - self.assertEqual(e2.get(), 'timed out') - self.assertEqual(q.get(), 'sent') - - def test_subclass_assign_queue(self): - # https://github.com/gevent/gevent/issues/2136 - - self.assertTrue(hasattr(self._makeOne(), 'queue')) - - my_queue = [] - class Q(self._getFUT()): - def _init(self, _maxsize): # pylint: disable=arguments-differ - self.queue = my_queue - - q = Q() - self.assertIs(q.queue, my_queue) - - -class TestChannel(SubscriptMixin, UsesOnlyOneItemMixin, TestCase): - - SUPPORTS_PUTTING_WITHOUT_GETTING = False - def _getFUT(self): - return queue.Channel - - def test_get_nowait_unlock_channel(self): - # get_nowait runs fine in the hub, and - # it switches to a waiting putter if needed. - result = [] - q = self._makeOne() - p = gevent.spawn(q.put, 5) - - def store_result(func, *args): - result.append(func(*args)) - - self.assertTrue(q.empty()) - self.assertTrue(q.full()) - - gevent.sleep(0.001) - self.assertTrue(q.empty()) - self.assertTrue(q.full()) - - get_hub().loop.run_callback(store_result, q.get_nowait) - gevent.sleep(0.001) - self.assertTrue(q.empty()) - self.assertTrue(q.full()) - self.assertEqual(result, [5]) - self.assertTrue(p.ready()) - self.assertTrue(p.dead) - self.assertTrue(q.empty()) - - def test_zero_max_size(self): - q = self._makeOne() - - def sender(evt, q): - q.put('hi') - evt.set('done') - - def receiver(evt, q): - x = q.get() - evt.set(x) - - e1 = AsyncResult() - e2 = AsyncResult() - - p1 = gevent.spawn(sender, e1, q) - gevent.sleep(0.001) - self.assertTrue(not e1.ready()) - p2 = gevent.spawn(receiver, e2, q) - self.assertEqual(e2.get(), 'hi') - self.assertEqual(e1.get(), 'done') - with gevent.Timeout(0): - gevent.joinall([p1, p2]) - - def test_send(self): - channel = self._makeOne() - - events = [] - - def another_greenlet(): - events.append(channel.get()) - events.append(channel.get()) - - g = gevent.spawn(another_greenlet) - - events.append('sending') - channel.put('hello') - events.append('sent hello') - channel.put('world') - events.append('sent world') - - self.assertEqual(['sending', 'hello', 'sent hello', 'world', 'sent world'], events) - g.get() - - def test_wait(self): - channel = self._makeOne() - events = [] - - def another_greenlet(): - events.append('sending hello') - channel.put('hello') - events.append('sending world') - channel.put('world') - events.append('sent world') - - g = gevent.spawn(another_greenlet) - - events.append('waiting') - events.append(channel.get()) - events.append(channel.get()) - - self.assertEqual(['waiting', 'sending hello', 'hello', 'sending world', 'world'], events) - gevent.sleep(0) - self.assertEqual(['waiting', 'sending hello', 'hello', 'sending world', 'world', 'sent world'], events) - g.get() - - def test_iterable(self): - channel = self._makeOne() - gevent.spawn(channel.put, StopIteration) - r = list(channel) - self.assertEqual(r, []) - - -class TestQueue(TestSimpleQueue): - queue = queue - - def _getFUT(self): - return queue.Queue - - def test_task_done(self): - channel = self._makeOne() - X = object() - gevent.spawn(channel.put, X) - result = channel.get() - self.assertIs(result, X) - self.assertEqual(1, channel.unfinished_tasks) - channel.task_done() - self.assertEqual(0, channel.unfinished_tasks) - - - def _shutdown_all_methods_in_one_thread(self, immediate): - q = self._makeOne() - q.put("L") - q.put_nowait("O") - q.shutdown(immediate) - - with self.assertRaises(self.queue.ShutDown): - q.put("E") - with self.assertRaises(self.queue.ShutDown): - q.put_nowait("W") - if immediate: - with self.assertRaises(self.queue.ShutDown): - q.get() - with self.assertRaises(self.queue.ShutDown): - q.get_nowait() - with self.assertRaises(ValueError): - q.task_done() - q.join() - else: - self.assertIn(q.get(), "LO") - q.task_done() - self.assertIn(q.get(), "LO") - q.task_done() - q.join() - # on shutdown(immediate=False) - # when queue is empty, should raise ShutDown Exception - with self.assertRaises(self.queue.ShutDown): - q.get() # p.get(True) - with self.assertRaises(self.queue.ShutDown): - q.get_nowait() # p.get(False) - with self.assertRaises(self.queue.ShutDown): - q.get(True, 1.0) - - def test_shutdown_all_methods_in_one_thread(self): - return self._shutdown_all_methods_in_one_thread(False) - - def test_shutdown_immediate_all_methods_in_one_thread(self): - return self._shutdown_all_methods_in_one_thread(True) - - - def test_issue_45(self): - """Test that join() exits immediately if not jobs were put into the queue""" - self.switch_expected = False - q = self._makeOne() - q.join() - - -class TestLifoQueue(SubscriptMixin, TestCase): - def _getFUT(self): - return queue.LifoQueue - - -class TestPriorityQueue(SubscriptMixin, TestCase): - def _getFUT(self): - return queue.PriorityQueue - - -class AbstractTestWeakRefMixin(object): - - def test_weak_reference(self): - import weakref - one = self._makeOne() - ref = weakref.ref(one) - self.assertIs(one, ref()) - - -class TestGetInterrupt(AbstractTestWeakRefMixin, AbstractGenericGetTestCase): - - Timeout = Empty - - kind = queue.SimpleQueue - - def wait(self, timeout): - return self._makeOne().get(timeout=timeout) - - def _makeOne(self): - return self.kind() - -class TestGetInterruptJoinableQueue(TestGetInterrupt): - kind = queue.Queue - -class TestGetInterruptLifoQueue(TestGetInterrupt): - kind = queue.LifoQueue - -class TestGetInterruptPriorityQueue(TestGetInterrupt): - kind = queue.PriorityQueue - -class TestGetInterruptChannel(TestGetInterrupt): - kind = queue.Channel - - -class TestPutInterrupt(AbstractGenericGetTestCase): - kind = queue.SimpleQueue - Timeout = Full - - def setUp(self): - super(TestPutInterrupt, self).setUp() - self.queue = self._makeOne() - - def wait(self, timeout): - while not self.queue.full(): - self.queue.put(1) - return self.queue.put(2, timeout=timeout) - - def _makeOne(self): - return self.kind(1) - - -class TestPutInterruptJoinableQueue(TestPutInterrupt): - kind = queue.Queue - -class TestPutInterruptLifoQueue(TestPutInterrupt): - kind = queue.LifoQueue - -class TestPutInterruptPriorityQueue(TestPutInterrupt): - kind = queue.PriorityQueue - -class TestPutInterruptChannel(TestPutInterrupt): - kind = queue.Channel - - def _makeOne(self): - return self.kind() - - - - -class TestGetInterruptSimpleQueue(TestGetInterrupt): - kind = queue.SimpleQueue - - def test_raises_timeout_Timeout(self): - raise unittest.SkipTest("Not supported") - - test_raises_timeout_Timeout_exc_customized = test_raises_timeout_Timeout - test_outer_timeout_is_not_lost = test_raises_timeout_Timeout - - -del AbstractGenericGetTestCase - - -if __name__ == '__main__': - greentest.main() diff --git a/venv/lib/python3.9/site-packages/gevent/tests/test__real_greenlet.py b/venv/lib/python3.9/site-packages/gevent/tests/test__real_greenlet.py deleted file mode 100644 index a5e572a..0000000 --- a/venv/lib/python3.9/site-packages/gevent/tests/test__real_greenlet.py +++ /dev/null @@ -1,34 +0,0 @@ -"""Testing that greenlet restores sys.exc_info. - -Passes with CPython + greenlet 0.4.0 - -Fails with PyPy 2.2.1 -""" -from __future__ import print_function -import sys - -from gevent import testing as greentest - -class Test(greentest.TestCase): - - def test(self): - import greenlet - - print('Your greenlet version: %s' % (getattr(greenlet, '__version__', None), )) - - result = [] - - def func(): - result.append(repr(sys.exc_info())) - - g = greenlet.greenlet(func) - try: - 1 / 0 - except ZeroDivisionError: - g.switch() - - - self.assertEqual(result, ['(None, None, None)']) - -if __name__ == '__main__': - greentest.main() diff --git a/venv/lib/python3.9/site-packages/gevent/tests/test__refcount.py b/venv/lib/python3.9/site-packages/gevent/tests/test__refcount.py deleted file mode 100644 index b95558f..0000000 --- a/venv/lib/python3.9/site-packages/gevent/tests/test__refcount.py +++ /dev/null @@ -1,189 +0,0 @@ -# Copyright (c) 2008 AG Projects -# Author: Denis Bilenko -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. - -"""This test checks that underlying socket instances (gevent.socket.socket._sock) -are not leaked by the hub. -""" -from __future__ import print_function - -from _socket import socket as c_socket -import sys -if sys.version_info[0] >= 3: - # Python3 enforces that __weakref__ appears only once, - # and not when a slotted class inherits from an unslotted class. - # We mess around with the class MRO below and violate that rule - # (because socket.socket defines __slots__ with __weakref__), - # so import socket.socket before that can happen. - __import__('socket') - Socket = c_socket -else: - class Socket(c_socket): - "Something we can have a weakref to" - -import _socket -_socket.socket = Socket - - -from gevent import monkey; monkey.patch_all() - -import gevent.testing as greentest -from gevent.testing import support -from gevent.testing import params - - -try: - from thread import start_new_thread -except ImportError: - from _thread import start_new_thread -from time import sleep -import weakref -import gc - -import socket -socket._realsocket = Socket - -SOCKET_TIMEOUT = 0.1 -if greentest.RESOLVER_DNSPYTHON: - # Takes a bit longer to resolve the client - # address initially. - SOCKET_TIMEOUT *= 2 - -if greentest.RUNNING_ON_CI: - SOCKET_TIMEOUT *= 2 - - -class Server(object): - - listening = False - client_data = None - server_port = None - - def __init__(self, raise_on_timeout): - self.raise_on_timeout = raise_on_timeout - self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) - try: - self.server_port = support.bind_port(self.socket, params.DEFAULT_BIND_ADDR) - except: - self.close() - raise - - def close(self): - self.socket.close() - self.socket = None - - def handle_request(self): - try: - self.socket.settimeout(SOCKET_TIMEOUT) - - self.socket.listen(5) - - self.listening = True - - try: - conn, _ = self.socket.accept() # pylint:disable=no-member - except socket.timeout: - if self.raise_on_timeout: - raise - return - - try: - self.client_data = conn.recv(100) - conn.send(b'bye') - finally: - conn.close() - finally: - self.close() - - -class Client(object): - - server_data = None - - def __init__(self, server_port): - self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) - self.server_port = server_port - - - def close(self): - self.socket.close() - self.socket = None - - def make_request(self): - try: - self.socket.connect((params.DEFAULT_CONNECT, self.server_port)) - self.socket.send(b'hello') - self.server_data = self.socket.recv(100) - finally: - self.close() - - -class Test(greentest.TestCase): - __timeout__ = greentest.LARGE_TIMEOUT - - def run_interaction(self, run_client): - server = Server(raise_on_timeout=run_client) - wref_to_hidden_server_socket = weakref.ref(server.socket._sock) - client = None - start_new_thread(server.handle_request) - if run_client: - client = Client(server.server_port) - start_new_thread(client.make_request) - - # Wait until we do our business; we will always close - # the server; We may also close the client. - # On PyPy, we may not actually see the changes they write to - # their dicts immediately. - for obj in server, client: - if obj is None: - continue - while obj.socket is not None: - sleep(0.01) - - # If we have a client, then we should have data - if run_client: - self.assertEqual(server.client_data, b'hello') - self.assertEqual(client.server_data, b'bye') - - return wref_to_hidden_server_socket - - def run_and_check(self, run_client): - wref_to_hidden_server_socket = self.run_interaction(run_client=run_client) - greentest.gc_collect_if_needed() - if wref_to_hidden_server_socket(): - from pprint import pformat - print(pformat(gc.get_referrers(wref_to_hidden_server_socket()))) - for x in gc.get_referrers(wref_to_hidden_server_socket()): - print(pformat(x)) - for y in gc.get_referrers(x): - print('-', pformat(y)) - self.fail('server socket should be dead by now') - - def test_clean_exit(self): - self.run_and_check(True) - self.run_and_check(True) - - def test_timeout_exit(self): - self.run_and_check(False) - self.run_and_check(False) - - -if __name__ == '__main__': - greentest.main() diff --git a/venv/lib/python3.9/site-packages/gevent/tests/test__refcount_core.py b/venv/lib/python3.9/site-packages/gevent/tests/test__refcount_core.py deleted file mode 100644 index e9eb9f4..0000000 --- a/venv/lib/python3.9/site-packages/gevent/tests/test__refcount_core.py +++ /dev/null @@ -1,25 +0,0 @@ -import sys -import weakref - -from gevent import testing as greentest - - -class Dummy(object): - def __init__(self): - __import__('gevent.core') - -@greentest.skipIf(weakref.ref(Dummy())() is not None, - "Relies on refcounting for fast weakref cleanup") -class Test(greentest.TestCase): - def test(self): - from gevent import socket - s = socket.socket() - r = weakref.ref(s) - s.close() - del s - self.assertIsNone(r()) - -assert weakref.ref(Dummy())() is None or hasattr(sys, 'pypy_version_info') - -if __name__ == '__main__': - greentest.main() diff --git a/venv/lib/python3.9/site-packages/gevent/tests/test__resolver_dnspython.py b/venv/lib/python3.9/site-packages/gevent/tests/test__resolver_dnspython.py deleted file mode 100644 index 4b0ec9e..0000000 --- a/venv/lib/python3.9/site-packages/gevent/tests/test__resolver_dnspython.py +++ /dev/null @@ -1,43 +0,0 @@ -# -*- coding: utf-8 -*- -""" -Tests explicitly using the DNS python resolver. - -""" -from __future__ import absolute_import -from __future__ import division -from __future__ import print_function - -import sys -import unittest -import subprocess -import os - -from gevent import testing as greentest - -@unittest.skipUnless(greentest.resolver_dnspython_available(), - "dnspython not available") -class TestDnsPython(unittest.TestCase): - - def _run_one(self, mod_name): - cmd = [ - sys.executable, - '-m', - 'gevent.tests.monkey_package.' + mod_name - ] - - env = dict(os.environ) - env['GEVENT_RESOLVER'] = 'dnspython' - - output = subprocess.check_output(cmd, env=env) - self.assertIn(b'_g_patched_module_dns', output) - self.assertNotIn(b'_g_patched_module_dns.rdtypes', output) - return output - - def test_import_dns_no_monkey_patch(self): - self._run_one('issue1526_no_monkey') - - def test_import_dns_with_monkey_patch(self): - self._run_one('issue1526_with_monkey') - -if __name__ == '__main__': - greentest.main() diff --git a/venv/lib/python3.9/site-packages/gevent/tests/test__select.py b/venv/lib/python3.9/site-packages/gevent/tests/test__select.py deleted file mode 100644 index dae9b82..0000000 --- a/venv/lib/python3.9/site-packages/gevent/tests/test__select.py +++ /dev/null @@ -1,275 +0,0 @@ -import errno -import sys -import unittest -from contextlib import contextmanager -from unittest.mock import patch as Patch - -import gevent.core -import gevent.testing as greentest -from gevent import get_hub -from gevent import os -from gevent import select -from gevent import socket -from gevent.testing import timing - - -class TestSelect(gevent.testing.timing.AbstractGenericWaitTestCase): - - def wait(self, timeout): - select.select([], [], [], timeout) - - - -@greentest.skipOnWindows("Cant select on files") -class TestSelectRead(gevent.testing.timing.AbstractGenericWaitTestCase): - - def wait(self, timeout): - r, w = os.pipe() - try: - select.select([r], [], [], timeout) - finally: - os.close(r) - os.close(w) - - # Issue #12367: http://www.freebsd.org/cgi/query-pr.cgi?pr=kern/155606 - @unittest.skipIf(sys.platform.startswith('freebsd'), - 'skip because of a FreeBSD bug: kern/155606') - def test_errno(self): - # Backported from test_select.py in 3.4 - with open(__file__, 'rb') as fp: - fd = fp.fileno() - fp.close() - try: - select.select([fd], [], [], 0) - except OSError as err: - # Python 3 - self.assertEqual(err.errno, errno.EBADF) - else: - self.fail("exception not raised") - - -@unittest.skipUnless(hasattr(select, 'poll'), "Needs poll") -@greentest.skipOnWindows("Cant poll on files") -class TestPollRead(gevent.testing.timing.AbstractGenericWaitTestCase): - def wait(self, timeout): - # On darwin, the read pipe is reported as writable - # immediately, for some reason. So we carefully register - # it only for read events (the default is read and write) - r, w = os.pipe() - try: - poll = select.poll() - poll.register(r, select.POLLIN) - poll.poll(timeout * 1000) - finally: - poll.unregister(r) - os.close(r) - os.close(w) - - def test_unregister_never_registered(self): - # "Attempting to remove a file descriptor that was - # never registered causes a KeyError exception to be - # raised." - poll = select.poll() - self.assertRaises(KeyError, poll.unregister, 5) - - def test_poll_invalid(self): - self.skipTest( - "libev >= 4.27 aborts the process if built with EV_VERIFY >= 2. " - "For libuv, depending on whether the fileno is reused or not " - "this either crashes or does nothing.") - with open(__file__, 'rb') as fp: - fd = fp.fileno() - - poll = select.poll() - poll.register(fd, select.POLLIN) - # Close after registering; libuv refuses to even - # create a watcher if it would get EBADF (so this turns into - # a test of whether or not we successfully initted the watcher). - fp.close() - result = poll.poll(0) - self.assertEqual(result, [(fd, select.POLLNVAL)]) # pylint:disable=no-member - -class TestSelectTypes(greentest.TestCase): - - def test_int(self): - sock = socket.socket() - try: - select.select([int(sock.fileno())], [], [], 0.001) - finally: - sock.close() - - def test_iterable(self): - sock = socket.socket() - - def fileno_iter(): - yield int(sock.fileno()) - - try: - select.select(fileno_iter(), [], [], 0.001) - finally: - sock.close() - - def test_string(self): - self.switch_expected = False - self.assertRaises(TypeError, select.select, ['hello'], [], [], 0.001) - - -@greentest.skipOnWindows("Things like os.close don't work on Windows") -class TestPossibleCrashes(greentest.TestCase): - """ - Tests for the crashes and unexpected exceptions - that happen when we try to use or create (depending on - loop implementation) a IO watcher for a closed/invalid file descriptor. - - See https://github.com/gevent/gevent/issues/2100 - See test__selectors.py - """ - - def test_closing_object_while_selecting(self): - # This one crashed libuv on Linux, at least, with - # libuv/src/unix/linux.c:1430: uv__io_poll: Assertion `errno == EEXIST' failed. - # - # The expected sequence here is that - # ``select.select`` creates the watcher objects and starts them. - # Then, it goes back to the hub, which spawns and runs the greenlet - # that closes the socket. The hub then goes into the IO waiting loop, - # at which point libuv calls ``epoll_ctl``, gets EBADF instead of - # EEXIST, and aborts. - # - # Why did this happen? We weren't actually *in* libuv yet when - # the call to ``socket.close`` happened. - # I think we deferred the callbacks that *actually* close the socket - # because a watcher was active. Those run first, then the IO polling - # begins. - # Unlike libev, which calls ``epoll_ctl`` at watcher init time, - # libuv defers this part. - # - # We were trying to defer the close of the socket to the next iteration fo - # the event loop, but: - # (1) we were using run_callback(), and because we are in a greenlet spawn, - # we were already running callbacks; in that situation, a new callback - # can run immediately. Which it did, and closed the FD, breaking the loops. - # The fix is to use a check watcher instead. - # (2) libuv doesn't implement the function that lets us determine that we - # need to defer the check. (fixing this involved rolling our own.) - sock = socket.socket() - self.addCleanup(sock.close) - gevent.spawn(sock.close) - - - # This call needs to be blocking so we get all the way - # to having an open, started IO watcher when the - # socket gets closed. - with Patch.object(select, '_original_select', return_value=((), (), ())): - select.select([sock], (), (), timing.SMALLEST_RELIABLE_DELAY) - - def _close_invalid_sock(self, sock): - # Because we closed the FD already (which raises EBADF when done again), but we - # still need to take care of the gevent-resources - try: - sock.close() - except OSError: - pass - - def _close_invalid_fd(self, fd): - try: - os.close(fd) - except OSError: - pass - - def test_closing_fd_while_selecting(self): - # As above, this causes libuv to crash for the same reasons. - # On linux/libev with -UNDEBUG to enable assertions, this - # crashes with: - # ev_epoll.c:134: epoll_modify: Assertion - # `("libev: I/O watcher with invalid fd found in epoll_ctl", - # errno != EBADF && errno != ELOOP && errno != EINVAL) - # - # called from ev_run:ev.c:4075 via ev.c:4021 - sock = socket.socket() - self.addCleanup(self._close_invalid_sock, sock) - gevent.spawn(self._close_invalid_fd, sock.fileno()) - with Patch.object(select, '_original_select', return_value=((), (), ())): - select.select([sock], (), (), timing.SMALLEST_RELIABLE_DELAY) - - def test_closing_fd_before_selecting(self): - # As above, this crashes libuv/linux at: - # libuv/src/unix/linux.c:1434 - # - # if (!epoll_ctl(epollfd, op, fd, &e)) - # continue; - # - # assert(op == EPOLL_CTL_ADD); - # assert(errno == EEXIST); - # - # /* File descriptor that's been watched before, update event mask. */ - # if (epoll_ctl(epollfd, EPOLL_CTL_MOD, fd, &e)) - # abort(); // <--- 1434 - # - # Which is UV calling epoll_ctl because it thinks - # Fatal Python error: Aborted - # Current thread 0x00007ffffe8450c0 (most recent call first): - # File "/project/src/gevent/libuv/loop.py", line 557 in run - # File "/project/src/gevent/hub.py", line 647 in run - - sock = socket.socket() - self.addCleanup(self._close_invalid_sock, sock) - os.close(sock.fileno()) - with Patch.object(select, '_original_select', return_value=((), (), ())): - with self._check_os_error_on_libuv(): - select.select([sock], (), (), timing.SMALLEST_RELIABLE_DELAY) - - - @contextmanager - def _check_os_error_on_libuv(self): - try: - yield - except OSError: - self.assertIn('gevent.libuv', type(get_hub().loop).__module__ ) - - - def test_closing_object_while_polling(self): - # Polling is different because registering is when we - # create the IO watcher; we just don't start it until - # we poll. - sock = socket.socket() - self.addCleanup(sock.close) - orig_fileno = sock.fileno() - gevent.spawn(sock.close) - # This call needs to be blocking so we get all the way - # to having an open, started IO watcher when the - # socket gets closed. - poller = select.poll() - poller.register(sock, select.POLLIN) - - with Patch.object(select, '_original_select', return_value=((), (), ())): - fds_and_events = None - # pylint:disable=unbalanced-tuple-unpacking - with self._check_os_error_on_libuv(): - # libuv gives us POLLIN and POLLNVAL - # On 3.14.3 ubunto, libuv gives us POLLIN | POLLOUT; possibly it was hitting the - # OSError case on other versions. - fds_and_events = poller.poll(timing.SMALLEST_RELIABLE_DELAY) - print('========') - print('Fds and events', fds_and_events) - print('=========') - if fds_and_events is not None: - self.assertTrue(len(fds_and_events) >= 1) - poll_ins = [x for x in fds_and_events if x[1] & select.POLLIN] - for fd, event in poll_ins: - self.assertEqual(fd, orig_fileno) - self.assertIn(event, (select.POLLIN, - (select.POLLIN | select.POLLOUT), - (select.POLLIN | select.POLLNVAL))) - - fds_and_events = None - with self._check_os_error_on_libuv(): - fds_and_events = poller.poll(timing.SMALLEST_RELIABLE_DELAY) # this one - # crashes # the process - if fds_and_events is not None: - [(fd, event)] = fds_and_events - self.assertEqual(fd, orig_fileno) - self.assertEqual(event, select.POLLNVAL) - -if __name__ == '__main__': - greentest.main() diff --git a/venv/lib/python3.9/site-packages/gevent/tests/test__selectors.py b/venv/lib/python3.9/site-packages/gevent/tests/test__selectors.py deleted file mode 100644 index 9ca0a76..0000000 --- a/venv/lib/python3.9/site-packages/gevent/tests/test__selectors.py +++ /dev/null @@ -1,171 +0,0 @@ -# Tests for gevent.selectors in its native form, without -# monkey-patching. - -import gevent -from gevent import socket -from gevent import selectors - -import gevent.testing as greentest -from gevent.testing import timing - -class SelectorTestMixin(object): - - @staticmethod - def run_selector_once(sel, timeout=3): - # Run in a background greenlet, leaving the main - # greenlet free to send data. - events = sel.select(timeout=timeout) - for key, mask in events: - key.data(sel, key.fileobj, mask) - gevent.sleep() - - unregister_after_send = True - - def read_from_ready_socket_and_reply(self, selector, conn, _events): - data = conn.recv(100) # Should be ready - if data: - conn.send(data) # Hope it won't block - - # Must unregister before we close. - if self.unregister_after_send: - selector.unregister(conn) - conn.close() - - def _check_selector(self, sel): - server, client = socket.socketpair() - glet = None - try: - sel.register(server, selectors.EVENT_READ, self.read_from_ready_socket_and_reply) - glet = gevent.spawn(self.run_selector_once, sel) - DATA = b'abcdef' - client.send(DATA) - data = client.recv(50) # here is probably where we yield to the event loop - self.assertEqual(data, DATA) - finally: - sel.close() - server.close() - client.close() - if glet is not None: - glet.join(10) - self.assertTrue(glet is not None and glet.ready()) - - -class GeventSelectorTest(SelectorTestMixin, - greentest.TestCase): - - def test_select_using_socketpair(self): - # Basic test. - with selectors.GeventSelector() as sel: - self._check_selector(sel) - - def test_select_many_sockets(self): - try: - AF_UNIX = socket.AF_UNIX - except AttributeError: - AF_UNIX = None - - pairs = [socket.socketpair() for _ in range(10)] - - try: - server_sel = selectors.GeventSelector() - client_sel = selectors.GeventSelector() - for i, pair in enumerate(pairs): - server, client = pair - server_sel.register(server, selectors.EVENT_READ, - self.read_from_ready_socket_and_reply) - client_sel.register(client, selectors.EVENT_READ, i) - # Prime them all to be ready at once. - data = str(i).encode('ascii') - client.send(data) - - # Read and reply to all the clients.. - # Everyone should be ready, so we ask not to block. - # The call to gevent.idle() is there to make sure that - # all event loop implementations (looking at you, libuv) - # get a chance to poll for IO. Without it, libuv - # doesn't find any results here. - # Not blocking only works for AF_UNIX sockets, though. - # If we got AF_INET (Windows) the data may need some time to - # traverse through the layers. - gevent.idle() - self.run_selector_once( - server_sel, - timeout=-1 if pairs[0][0].family == AF_UNIX else 3) - - found = 0 - for key, _ in client_sel.select(timeout=3): - expected = str(key.data).encode('ascii') - data = key.fileobj.recv(50) - self.assertEqual(data, expected) - found += 1 - self.assertEqual(found, len(pairs)) - finally: - server_sel.close() - client_sel.close() - for pair in pairs: - for s in pair: - s.close() - - -@greentest.skipOnWindows("Things like os.close don't work on Windows") -class TestPossibleCrashes(greentest.TestCase): - """ - Tests for the crashes and unexpected exceptions - that happen when we try to use or create (depending on - loop implementation) a IO watcher for a closed/invalid file descriptor. - - See https://github.com/gevent/gevent/issues/2100 - See test__select.py - """ - - def test_closing_object_while_selecting(self): - sock = socket.socket() - self.addCleanup(sock.close) - gevent.spawn(sock.close) - - sel = selectors.GeventSelector() - sel.register(sock, selectors.EVENT_READ) - # This call needs to be blocking so we get all the way - # to having an open, started IO watcher when the - # socket gets closed. - with sel: - sel.select(timeout=timing.SMALLEST_RELIABLE_DELAY) - - - def _close_invalid_sock(self, sock): - # Because we closed the FD already (which raises EBADF when done again), but we - # still need to take care of the gevent-resources - try: - sock.close() - except OSError: - pass - - def test_closing_fd_while_selecting(self): - # using regular os.close will - # crash under libuv - from gevent import os - - sock = socket.socket() - self.addCleanup(self._close_invalid_sock, sock) - gevent.spawn(os.close, sock.fileno()) - - sel = selectors.GeventSelector() - sel.register(sock, selectors.EVENT_READ) - - with sel: - sel.select(timeout=timing.SMALLEST_RELIABLE_DELAY) - - def test_closing_fd_before_selecting(self): - import os - sock = socket.socket() - self.addCleanup(self._close_invalid_sock, sock) - os.close(sock.fileno()) - - sel = selectors.GeventSelector() - with self.assertRaisesRegex(ValueError, 'Invalid file'): - sel.register(sock, selectors.EVENT_READ) - - - -if __name__ == '__main__': - greentest.main() diff --git a/venv/lib/python3.9/site-packages/gevent/tests/test__semaphore.py b/venv/lib/python3.9/site-packages/gevent/tests/test__semaphore.py deleted file mode 100644 index 6036b61..0000000 --- a/venv/lib/python3.9/site-packages/gevent/tests/test__semaphore.py +++ /dev/null @@ -1,425 +0,0 @@ -### -# This file is test__semaphore.py only for organization purposes. -# The public API, -# and the *only* correct place to import Semaphore --- even in tests --- -# is ``gevent.lock``, never ``gevent._semaphore``. -## -from __future__ import print_function -from __future__ import absolute_import - -import weakref - -import gevent -import gevent.exceptions -from gevent.lock import Semaphore -from gevent.lock import BoundedSemaphore - -import gevent.testing as greentest -from gevent.testing import timing - -class TestSemaphore(greentest.TestCase): - - # issue 39 - def test_acquire_returns_false_after_timeout(self): - s = Semaphore(value=0) - result = s.acquire(timeout=0.01) - assert result is False, repr(result) - - def test_release_twice(self): - s = Semaphore() - result = [] - s.rawlink(lambda s: result.append('a')) - s.release() - s.rawlink(lambda s: result.append('b')) - s.release() - gevent.sleep(0.001) - # The order, though, is not guaranteed. - self.assertEqual(sorted(result), ['a', 'b']) - - def test_semaphore_weakref(self): - s = Semaphore() - r = weakref.ref(s) - self.assertEqual(s, r()) - - @greentest.ignores_leakcheck - def test_semaphore_in_class_with_del(self): - # Issue #704. This used to crash the process - # under PyPy through at least 4.0.1 if the Semaphore - # was implemented with Cython. - class X(object): - def __init__(self): - self.s = Semaphore() - - def __del__(self): - self.s.acquire() - - X() - import gc - gc.collect() - gc.collect() - - - def test_rawlink_on_unacquired_runs_notifiers(self): - # https://github.com/gevent/gevent/issues/1287 - - # Rawlinking a ready semaphore should fire immediately, - # not raise LoopExit - s = Semaphore() - gevent.wait([s]) - - -class TestSemaphoreMultiThread(greentest.TestCase): - # Tests that the object can be acquired correctly across - # multiple threads. - # Used as a base class. - - # See https://github.com/gevent/gevent/issues/1437 - - def _getTargetClass(self): - return Semaphore - - def _makeOne(self): - # Create an object that is associated with the current hub. If - # we don't do this now, it gets initialized lazily the first - # time it would have to block, which, in the event of threads, - # would be from an arbitrary thread. - return self._getTargetClass()(1) - - def _makeThreadMain(self, thread_running, thread_acquired, sem, - acquired, exc_info, - **thread_acquire_kwargs): - from gevent._hub_local import get_hub_if_exists - import sys - - def thread_main(): - thread_running.set() - try: - acquired.append( - sem.acquire(**thread_acquire_kwargs) - ) - except: - exc_info[:] = sys.exc_info() - raise # Print - finally: - hub = get_hub_if_exists() - if hub is not None: - hub.join() - hub.destroy(destroy_loop=True) - thread_acquired.set() - return thread_main - - IDLE_ITERATIONS = 5 - - def _do_test_acquire_in_one_then_another(self, - release=True, - require_thread_acquired_to_finish=False, - **thread_acquire_kwargs): - from gevent import monkey - self.assertFalse(monkey.is_module_patched('threading')) - - import threading - thread_running = threading.Event() - thread_acquired = threading.Event() - - sem = self._makeOne() - # Make future acquires block - sem.acquire() - - exc_info = [] - acquired = [] - - t = threading.Thread(target=self._makeThreadMain( - thread_running, thread_acquired, sem, - acquired, exc_info, - **thread_acquire_kwargs - )) - t.daemon = True - t.start() - thread_running.wait(10) # implausibly large time - if release: - sem.release() - # Spin the loop to be sure the release gets through. - # (Release schedules the notifier to run, and when the - # notifier run it sends the async notification to the - # other thread. Depending on exactly where we are in the - # event loop, and the limit to the number of callbacks - # that get run (including time-based) the notifier may or - # may not be immediately ready to run, so this can take up - # to two iterations.) - for _ in range(self.IDLE_ITERATIONS): - gevent.idle() - if thread_acquired.wait(timing.LARGE_TICK): - break - - self.assertEqual(acquired, [True]) - - if not release and thread_acquire_kwargs.get("timeout"): - # Spin the loop to be sure that the timeout has a chance to - # process. Interleave this with something that drops the GIL - # so the background thread has a chance to notice that. - for _ in range(self.IDLE_ITERATIONS): - gevent.idle() - if thread_acquired.wait(timing.LARGE_TICK): - break - thread_acquired.wait(timing.LARGE_TICK * 5) - - if require_thread_acquired_to_finish: - self.assertTrue(thread_acquired.is_set()) - try: - self.assertEqual(exc_info, []) - finally: - exc_info = None - - return sem, acquired - - def test_acquire_in_one_then_another(self): - self._do_test_acquire_in_one_then_another(release=True) - - def test_acquire_in_one_then_another_timed(self): - sem, acquired_in_thread = self._do_test_acquire_in_one_then_another( - release=False, - require_thread_acquired_to_finish=True, - timeout=timing.SMALLEST_RELIABLE_DELAY) - self.assertEqual([False], acquired_in_thread) - # This doesn't, of course, notify anything, because - # the waiter has given up. - sem.release() - notifier = getattr(sem, '_notifier', None) - self.assertIsNone(notifier) - - def test_acquire_in_one_wait_greenlet_wait_thread_gives_up(self): - # The waiter in the thread both arrives and gives up while - # the notifier is already running...or at least, that's what - # we'd like to arrange, but the _notify_links function doesn't - # drop the GIL/object lock, so the other thread is stuck and doesn't - # actually get to call into the acquire method. - - from gevent import monkey - self.assertFalse(monkey.is_module_patched('threading')) - - import threading - - sem = self._makeOne() - # Make future acquires block - sem.acquire() - - def greenlet_one(): - ack = sem.acquire() - # We're running in the notifier function right now. It switched to - # us. - thread.start() - gevent.sleep(timing.LARGE_TICK) - return ack - - exc_info = [] - acquired = [] - - glet = gevent.spawn(greenlet_one) - thread = threading.Thread(target=self._makeThreadMain( - threading.Event(), threading.Event(), - sem, - acquired, exc_info, - timeout=timing.LARGE_TICK - )) - thread.daemon = True - gevent.idle() - sem.release() - glet.join() - for _ in range(3): - gevent.idle() - thread.join(timing.LARGE_TICK) - - self.assertEqual(glet.value, True) - self.assertEqual([], exc_info) - self.assertEqual([False], acquired) - self.assertTrue(glet.dead, glet) - glet = None - - def assertOneHasNoHub(self, sem): - self.assertIsNone(sem.hub, sem) - - @greentest.skipOnPyPyOnWindows("Flaky there; can't reproduce elsewhere") - def test_dueling_threads(self, acquire_args=(), create_hub=None): - # pylint:disable=too-many-locals,too-many-statements - - # Threads doing nothing but acquiring and releasing locks, without - # having any other greenlets to switch to. - # https://github.com/gevent/gevent/issues/1698 - from gevent import monkey - from gevent._hub_local import get_hub_if_exists - - self.assertFalse(monkey.is_module_patched('threading')) - - import threading - from time import sleep as native_sleep - - sem = self._makeOne() - self.assertOneHasNoHub(sem) - count = 10000 - results = [-1, -1] - run = True - def do_it(ix): - if create_hub: - gevent.get_hub() - - try: - for i in range(count): - if not run: - break - - acquired = sem.acquire(*acquire_args) - assert acquire_args or acquired - if acquired: - sem.release() - results[ix] = i - if not create_hub: - # We don't artificially create the hub. - self.assertIsNone( - get_hub_if_exists(), - (get_hub_if_exists(), ix, i) - ) - if create_hub and i % 10 == 0: - gevent.sleep(timing.SMALLEST_RELIABLE_DELAY) - elif i % 100 == 0: - native_sleep(timing.SMALLEST_RELIABLE_DELAY) - except Exception as ex: # pylint:disable=broad-except - import traceback; traceback.print_exc() - results[ix] = str(ex) - ex = None - finally: - hub = get_hub_if_exists() - if hub is not None: - hub.join() - hub.destroy(destroy_loop=True) - - t1 = threading.Thread(target=do_it, args=(0,)) - t1.daemon = True - t2 = threading.Thread(target=do_it, args=(1,)) - t2.daemon = True - t1.start() - t2.start() - - t1.join(1) - t2.join(1) - - while t1.is_alive() or t2.is_alive(): - cur = list(results) - t1.join(7) - t2.join(7) - if cur == results: - # Hmm, after two seconds, no progress - run = False - break - - self.assertEqual(results, [count - 1, count - 1]) - - def test_dueling_threads_timeout(self): - self.test_dueling_threads((True, 4)) - - def test_dueling_threads_with_hub(self): - self.test_dueling_threads(create_hub=True) - - - # XXX: Need a test with multiple greenlets in a non-primary - # thread. Things should work, just very slowly; instead of moving through - # greenlet.switch(), they'll be moving with async watchers. - -class TestBoundedSemaphoreMultiThread(TestSemaphoreMultiThread): - - def _getTargetClass(self): - return BoundedSemaphore - -@greentest.skipOnPurePython("Needs C extension") -class TestCExt(greentest.TestCase): - - def test_c_extension(self): - self.assertEqual(Semaphore.__module__, - 'gevent._gevent_c_semaphore') - - -class SwitchWithFixedHash(object): - # Replaces greenlet.switch with a callable object - # with a hash code we control. This only matters if - # we're hashing this somewhere (which we used to), but - # that doesn't preserve order, so we don't do - # that anymore. - - def __init__(self, greenlet, hashcode): - self.switch = greenlet.switch - self.hashcode = hashcode - - def __hash__(self): - raise AssertionError - - def __eq__(self, other): - raise AssertionError - - def __call__(self, *args, **kwargs): - return self.switch(*args, **kwargs) - - def __repr__(self): - return repr(self.switch) - -class FirstG(gevent.Greenlet): - # A greenlet whose switch method will have a low hashcode. - - hashcode = 10 - - def __init__(self, *args, **kwargs): - gevent.Greenlet.__init__(self, *args, **kwargs) - self.switch = SwitchWithFixedHash(self, self.hashcode) - - -class LastG(FirstG): - # A greenlet whose switch method will have a high hashcode. - hashcode = 12 - - -def acquire_then_exit(sem, should_quit): - sem.acquire() - should_quit.append(True) - - -def acquire_then_spawn(sem, should_quit): - if should_quit: - return - sem.acquire() - g = FirstG.spawn(release_then_spawn, sem, should_quit) - g.join() - -def release_then_spawn(sem, should_quit): - sem.release() - if should_quit: # pragma: no cover - return - g = FirstG.spawn(acquire_then_spawn, sem, should_quit) - g.join() - -class TestSemaphoreFair(greentest.TestCase): - - def test_fair_or_hangs(self): - # If the lock isn't fair, this hangs, spinning between - # the last two greenlets. - # See https://github.com/gevent/gevent/issues/1487 - sem = Semaphore() - should_quit = [] - - keep_going1 = FirstG.spawn(acquire_then_spawn, sem, should_quit) - keep_going2 = FirstG.spawn(acquire_then_spawn, sem, should_quit) - exiting = LastG.spawn(acquire_then_exit, sem, should_quit) - - with self.assertRaises(gevent.exceptions.LoopExit): - gevent.joinall([keep_going1, keep_going2, exiting]) - - self.assertTrue(exiting.dead, exiting) - self.assertTrue(keep_going2.dead, keep_going2) - self.assertFalse(keep_going1.dead, keep_going1) - - sem.release() - keep_going1.kill() - keep_going2.kill() - exiting.kill() - - gevent.idle() - -if __name__ == '__main__': - greentest.main() diff --git a/venv/lib/python3.9/site-packages/gevent/tests/test__server.py b/venv/lib/python3.9/site-packages/gevent/tests/test__server.py deleted file mode 100644 index d670dae..0000000 --- a/venv/lib/python3.9/site-packages/gevent/tests/test__server.py +++ /dev/null @@ -1,567 +0,0 @@ -from __future__ import print_function, division -from contextlib import contextmanager -import unittest -import errno -import os - - -import gevent.testing as greentest -from gevent.testing import sysinfo -from gevent.testing import DEFAULT_SOCKET_TIMEOUT as _DEFAULT_SOCKET_TIMEOUT -from gevent.testing.timing import SMALLEST_RELIABLE_DELAY -from gevent.testing.sockets import tcp_listener -from gevent.testing import WIN - -from gevent import socket -import gevent -from gevent.server import StreamServer -from gevent.exceptions import LoopExit - - -class SimpleStreamServer(StreamServer): - - def handle(self, client_socket, _address): # pylint:disable=method-hidden - fd = client_socket.makefile() - try: - request_line = fd.readline() - if not request_line: - return - try: - _method, path, _rest = request_line.split(' ', 3) - except Exception: - print('Failed to parse request line: %r' % (request_line, )) - raise - if path == '/ping': - client_socket.sendall(b'HTTP/1.0 200 OK\r\n\r\nPONG') - elif path in ['/long', '/short']: - client_socket.sendall(b'hello') - while True: - data = client_socket.recv(1) - if not data: - break - else: - client_socket.sendall(b'HTTP/1.0 404 WTF?\r\n\r\n') - finally: - fd.close() - -def sleep_to_clear_old_sockets(*_args): - try: - # Allow any queued callbacks needed to close sockets - # to run. On Windows, this needs to spin the event loop to - # allow proper FD cleanup. Otherwise we risk getting an - # old FD that's being closed and then get spurious connection - # errors. - gevent.sleep(0 if not WIN else SMALLEST_RELIABLE_DELAY) - except Exception: # pylint:disable=broad-except - pass - - -class Settings(object): - ServerClass = StreamServer - ServerSubClass = SimpleStreamServer - restartable = True - close_socket_detected = True - - @staticmethod - def assertAcceptedConnectionError(inst): - with inst.makefile() as conn: - try: - result = conn.read() - except socket.timeout: - result = None - inst.assertFalse(result) - - assert500 = assertAcceptedConnectionError - - @staticmethod - def assert503(inst): - # regular reads timeout - inst.assert500() - # attempt to send anything reset the connection - try: - inst.send_request() - except socket.error as ex: - if ex.args[0] not in greentest.CONN_ABORTED_ERRORS: - raise - - @staticmethod - def assertPoolFull(inst): - with inst.assertRaises(socket.timeout): - inst.assertRequestSucceeded(timeout=0.01) - - @staticmethod - def fill_default_server_args(inst, kwargs): - kwargs.setdefault('spawn', inst.get_spawn()) - return kwargs - -class TestCase(greentest.TestCase): - # pylint: disable=too-many-public-methods - __timeout__ = greentest.LARGE_TIMEOUT - Settings = Settings - server = None - - def cleanup(self): - if getattr(self, 'server', None) is not None: - self.server.stop() - self.server = None - sleep_to_clear_old_sockets() - - def get_listener(self): - return self._close_on_teardown(tcp_listener(backlog=5)) - - def get_server_host_port_family(self): - server_host = self.server.server_host - if not server_host: - server_host = greentest.DEFAULT_LOCAL_HOST_ADDR - elif server_host == '::': - server_host = greentest.DEFAULT_LOCAL_HOST_ADDR6 - - try: - family = self.server.socket.family - except AttributeError: - # server deletes socket when closed - family = socket.AF_INET - - return server_host, self.server.server_port, family - - @contextmanager - def makefile(self, timeout=_DEFAULT_SOCKET_TIMEOUT, bufsize=1, include_raw_socket=False): - server_host, server_port, family = self.get_server_host_port_family() - # Under Python3, you can't read and write to the same - # makefile() opened in r, and r+ is not allowed - makefile_kwargs = {'buffering': bufsize, 'mode': 'rwb'} - - with socket.socket(family=family) as sock: - rconn = None - # We want the socket to be accessible from the fileobject - # we return. On Python 2, natively this is available as - # _sock, but Python 3 doesn't have that. - sock.connect((server_host, server_port)) - sock.settimeout(timeout) - with sock.makefile(**makefile_kwargs) as rconn: - result = rconn if not include_raw_socket else (rconn, sock) - yield result - - def send_request(self, url='/', timeout=_DEFAULT_SOCKET_TIMEOUT, bufsize=1): - with self.makefile(timeout=timeout, bufsize=bufsize) as conn: - self.send_request_to_fd(conn, url) - - def send_request_to_fd(self, fd, url='/'): - fd.write(('GET %s HTTP/1.0\r\n\r\n' % url).encode('latin-1')) - fd.flush() - - LOCAL_CONN_REFUSED_ERRORS = () - if greentest.OSX: - # A kernel bug in OS X sometimes results in this - LOCAL_CONN_REFUSED_ERRORS = (errno.EPROTOTYPE,) - elif greentest.WIN and greentest.PYPY3: - # We see WinError 10049: The requested address is not valid - # which is not one of the errors we get anywhere else. - # Not sure which errno constant this is? - LOCAL_CONN_REFUSED_ERRORS = (10049,) - elif greentest.RUNNING_ON_MANYLINUX: - # In https://github.com/pypa/manylinux/pull/1785 the manylinux images updated to - # OpenSSL 3.5. While that has been tested to work before without producing this - # error (https://github.com/gevent/gevent/pull/2103), it _is_ doing so in github - # actions. - # XXX: Not sure this is really the right way to handle this. - LOCAL_CONN_REFUSED_ERRORS += (errno.EPIPE,) - - def assertConnectionRefused(self, in_proc_server=True): - try: - with self.assertRaises(socket.error) as exc: - with self.makefile() as conn: - conn.close() - except LoopExit: - if not in_proc_server: - raise - # A LoopExit is fine. If we've killed the server - # and don't have any other greenlets to run, then - # blocking to open the connection might raise this. - # This became likely on Windows once we stopped - # passing IP addresses through an extra call to - # ``getaddrinfo``, which changed the number of switches - return - - ex = exc.exception - self.assertIn(ex.args[0], - (errno.ECONNREFUSED, errno.EADDRNOTAVAIL, - errno.ECONNRESET, errno.ECONNABORTED) + self.LOCAL_CONN_REFUSED_ERRORS, - (ex, ex.args)) - - def assert500(self): - self.Settings.assert500(self) - - def assert503(self): - self.Settings.assert503(self) - - def assertAcceptedConnectionError(self): - self.Settings.assertAcceptedConnectionError(self) - - def assertPoolFull(self): - self.Settings.assertPoolFull(self) - - def assertNotAccepted(self): - try: - with self.makefile(include_raw_socket=True) as (conn, sock): - conn.write(b'GET / HTTP/1.0\r\n\r\n') - conn.flush() - result = b'' - try: - while True: - data = sock.recv(1) - if not data: - break - result += data - except socket.timeout: - self.assertFalse(result) - return - except LoopExit: - # See assertConnectionRefused - return - - self.assertTrue(result.startswith(b'HTTP/1.0 500 Internal Server Error'), repr(result)) - - - def assertRequestSucceeded(self, timeout=_DEFAULT_SOCKET_TIMEOUT): - with self.makefile(timeout=timeout) as conn: - conn.write(b'GET /ping HTTP/1.0\r\n\r\n') - result = conn.read() - - self.assertTrue(result.endswith(b'\r\n\r\nPONG'), repr(result)) - - def start_server(self): - self.server.start() - self.assertRequestSucceeded() - self.assertRequestSucceeded() - - def stop_server(self): - self.server.stop() - self.assertConnectionRefused() - - def report_netstat(self, _msg): - # At one point this would call 'sudo netstat -anp | grep PID' - # with os.system. We can probably do better with psutil. - return - - def _create_server(self, *args, **kwargs): - kind = kwargs.pop('server_kind', self.ServerSubClass) - addr = kwargs.pop('server_listen_addr', (greentest.DEFAULT_BIND_ADDR, 0)) - return kind(addr, *args, **kwargs) - - def init_server(self, *args, **kwargs): - self.server = self._create_server(*args, **kwargs) - self.server.start() - sleep_to_clear_old_sockets() - - @property - def socket(self): - return self.server.socket - - def _test_invalid_callback(self): - if sysinfo.RUNNING_ON_APPVEYOR: - self.skipTest("Sometimes misses the error") # XXX: Why? - - try: - # Can't use a kwarg here, WSGIServer and StreamServer - # take different things (application and handle) - self.init_server(lambda: None) - self.expect_one_error() - - self.assert500() - self.assert_error(TypeError) - finally: - self.server.stop() - # XXX: There's something unreachable (with a traceback?) - # We need to clear it to make the leak checks work on Travis; - # so far I can't reproduce it locally on OS X. - import gc; gc.collect() - - def fill_default_server_args(self, kwargs): - return self.Settings.fill_default_server_args(self, kwargs) - - def ServerClass(self, *args, **kwargs): - return self.Settings.ServerClass(*args, - **self.fill_default_server_args(kwargs)) - - def ServerSubClass(self, *args, **kwargs): - return self.Settings.ServerSubClass(*args, - **self.fill_default_server_args(kwargs)) - - def get_spawn(self): - return None - -class TestDefaultSpawn(TestCase): - - def get_spawn(self): - return gevent.spawn - - def _test_server_start_stop(self, restartable): - self.report_netstat('before start') - self.start_server() - self.report_netstat('after start') - if restartable and self.Settings.restartable: - self.server.stop_accepting() - self.report_netstat('after stop_accepting') - self.assertNotAccepted() - self.server.start_accepting() - self.report_netstat('after start_accepting') - sleep_to_clear_old_sockets() - self.assertRequestSucceeded() - self.stop_server() - self.report_netstat('after stop') - - def test_backlog_is_not_accepted_for_socket(self): - self.switch_expected = False - with self.assertRaises(TypeError): - self.ServerClass(self.get_listener(), backlog=25) - - @greentest.skipOnLibuvOnCIOnPyPy("Sometimes times out") - @greentest.skipOnAppVeyor("Sometimes times out.") - def test_backlog_is_accepted_for_address(self): - self.server = self.ServerSubClass((greentest.DEFAULT_BIND_ADDR, 0), backlog=25) - self.assertConnectionRefused() - self._test_server_start_stop(restartable=False) - - def test_subclass_just_create(self): - self.server = self.ServerSubClass(self.get_listener()) - self.assertNotAccepted() - - @greentest.skipOnAppVeyor("Sometimes times out.") - def test_subclass_with_socket(self): - self.server = self.ServerSubClass(self.get_listener()) - # the connection won't be refused, because there exists a - # listening socket, but it won't be handled also - self.assertNotAccepted() - self._test_server_start_stop(restartable=True) - - def test_subclass_with_address(self): - self.server = self.ServerSubClass((greentest.DEFAULT_BIND_ADDR, 0)) - self.assertConnectionRefused() - self._test_server_start_stop(restartable=True) - - def test_invalid_callback(self): - self._test_invalid_callback() - - @greentest.reraises_flaky_timeout(socket.timeout) - def _test_serve_forever(self): - g = gevent.spawn(self.server.serve_forever) - try: - sleep_to_clear_old_sockets() - self.assertRequestSucceeded() - self.server.stop() - self.assertFalse(self.server.started) - self.assertConnectionRefused() - finally: - g.kill() - g.get() - self.server.stop() - - def test_serve_forever(self): - self.server = self.ServerSubClass((greentest.DEFAULT_BIND_ADDR, 0)) - self.assertFalse(self.server.started) - self.assertConnectionRefused() - self._test_serve_forever() - - def test_serve_forever_after_start(self): - self.server = self.ServerSubClass((greentest.DEFAULT_BIND_ADDR, 0)) - self.assertConnectionRefused() - self.assertFalse(self.server.started) - self.server.start() - self.assertTrue(self.server.started) - self._test_serve_forever() - - @greentest.skipIf(greentest.EXPECT_POOR_TIMER_RESOLUTION, "Sometimes spuriously fails") - def test_server_closes_client_sockets(self): - self.server = self.ServerClass((greentest.DEFAULT_BIND_ADDR, 0), lambda *args: []) - self.server.start() - sleep_to_clear_old_sockets() - with self.makefile() as conn: - self.send_request_to_fd(conn) - # use assert500 below? - with gevent.Timeout._start_new_or_dummy(1): - try: - result = conn.read() - if result: - assert result.startswith('HTTP/1.0 500 Internal Server Error'), repr(result) - except socket.timeout: - pass - except socket.error as ex: - if ex.args[0] == 10053: - pass # "established connection was aborted by the software in your host machine" - elif ex.args[0] == errno.ECONNRESET: - pass - else: - raise - - self.stop_server() - - @property - def socket(self): - return self.server.socket - - def test_error_in_spawn(self): - self.init_server() - self.assertTrue(self.server.started) - error = ExpectedError('test_error_in_spawn') - def _spawn(*_args): - gevent.getcurrent().throw(error) - self.server._spawn = _spawn - self.expect_one_error() - self.assertAcceptedConnectionError() - self.assert_error(ExpectedError, error) - - def test_server_repr_when_handle_is_instancemethod(self): - # PR 501 - self.init_server() - assert self.server.started - self.assertIn('Server', repr(self.server)) - - self.server.set_handle(self.server.handle) - self.assertIn('handle=', repr(self.server)) - - self.server.set_handle(self.test_server_repr_when_handle_is_instancemethod) - self.assertIn('test_server_repr_when_handle_is_instancemethod', repr(self.server)) - - def handle(): - pass - self.server.set_handle(handle) - self.assertIn('handle= returned a result with an error set - - # It's not safe to continue after a SystemError, so we just skip the test there. - - # As of Jan 2018 with CFFI 1.11.2 this happens reliably on macOS 3.6 and 3.7 - # as well. - - # See https://bitbucket.org/cffi/cffi/issues/352/systemerror-returned-a-result-with-an - - # This is fixed in 1.11.3 - - import gevent.signal # make sure it's in sys.modules pylint:disable=redefined-outer-name - assert gevent.signal - import site - from importlib import reload as reload_module - - try: - reload_module(site) - except TypeError: - # Non-CFFI on Travis triggers this, for some reason, - # but only on 3.6, not 3.4 or 3.5, and not yet on 3.7. - - # The only module seen to trigger this is __main__, i.e., this module. - - # This is hard to trigger in a virtualenv since it appears they - # install their own site.py, different from the one that ships with - # Python 3.6., and at least the version I have doesn't mess with - # __cached__ - import sys - for m in set(sys.modules.values()): - try: - if m.__cached__ is None: - print("Module has None __cached__", m, file=sys.stderr) - except AttributeError: - continue - -if __name__ == '__main__': - greentest.main() diff --git a/venv/lib/python3.9/site-packages/gevent/tests/test__sleep0.py b/venv/lib/python3.9/site-packages/gevent/tests/test__sleep0.py deleted file mode 100644 index d95d677..0000000 --- a/venv/lib/python3.9/site-packages/gevent/tests/test__sleep0.py +++ /dev/null @@ -1,10 +0,0 @@ -import gevent -from gevent.testing.util import alarm - - -alarm(3) - - -with gevent.Timeout(0.01, False): - while True: - gevent.sleep(0) diff --git a/venv/lib/python3.9/site-packages/gevent/tests/test__socket.py b/venv/lib/python3.9/site-packages/gevent/tests/test__socket.py deleted file mode 100644 index ab37e62..0000000 --- a/venv/lib/python3.9/site-packages/gevent/tests/test__socket.py +++ /dev/null @@ -1,657 +0,0 @@ -from __future__ import print_function -from __future__ import absolute_import - -from gevent import monkey -# This line can be commented out so that most tests run with the -# system socket for comparison. -monkey.patch_all() - -import sys -import array -import socket -import time -import unittest -from functools import wraps - -import gevent -from gevent._compat import reraise - -import gevent.testing as greentest - - -from gevent.testing import LARGE_TIMEOUT -from gevent.testing import support -from gevent.testing import params -from gevent.testing.sockets import tcp_listener -from gevent.testing.skipping import skipWithoutExternalNetwork -from gevent.testing.skipping import skipOnMacOnCI - -# we use threading on purpose so that we can test both regular and -# gevent sockets with the same code -from threading import Thread as _Thread -from threading import Event - -errno_types = int - -# socket.accept/unwrap/makefile aren't found for some reason -# pylint:disable=no-member - -class BaseThread(object): - terminal_exc = None - - def __init__(self, target): - @wraps(target) - def errors_are_fatal(*args, **kwargs): - try: - return target(*args, **kwargs) - except: # pylint:disable=bare-except - self.terminal_exc = sys.exc_info() - raise - self.target = errors_are_fatal - -class GreenletThread(BaseThread): - - def __init__(self, target=None, args=()): - BaseThread.__init__(self, target) - self.glet = gevent.spawn(self.target, *args) - - def join(self, *args, **kwargs): - return self.glet.join(*args, **kwargs) - - def is_alive(self): - return not self.glet.ready() - -if not monkey.is_module_patched('threading'): - class ThreadThread(BaseThread, _Thread): - def __init__(self, **kwargs): - target = kwargs.pop('target') - BaseThread.__init__(self, target) - _Thread.__init__(self, target=self.target, **kwargs) - self.start() - Thread = ThreadThread -else: - Thread = GreenletThread - -class TestTCP(greentest.TestCase): - __timeout__ = None - TIMEOUT_ERROR = socket.timeout - long_data = ", ".join([str(x) for x in range(20000)]) - if not isinstance(long_data, bytes): - long_data = long_data.encode('ascii') - - def setUp(self): - super(TestTCP, self).setUp() - if '-v' in sys.argv: - printed = [] - try: - from time import perf_counter as now - except ImportError: - from time import time as now - def log(*args): - if not printed: - print() - printed.append(1) - print("\t -> %0.6f" % now(), *args) - - orig_cot = self._close_on_teardown - def cot(o): - log("Registering for teardown", o) - def c(o=o): - log("Closing on teardown", o) - o.close() - o = None - orig_cot(c) - return o - self._close_on_teardown = cot - - else: - def log(*_args): - "Does nothing" - self.log = log - - - self.listener = self._close_on_teardown(self._setup_listener()) - # It is important to watch the lifetimes of socket objects and - # ensure that: - # (1) they are closed; and - # (2) *before* the next test begins. - # - # For example, it's a bad bad thing to leave a greenlet running past the - # scope of the individual test method if that greenlet will close - # a socket object --- especially if that socket object might also have been - # closed explicitly. - # - # On Windows, we've seen issue with filenos getting reused while something - # still thinks they have the original fileno around. When they later - # close that fileno, a completely unrelated object is closed. - self.port = self.listener.getsockname()[1] - - def _setup_listener(self): - return tcp_listener() - - def create_connection(self, host=None, port=None, timeout=None, - blocking=None): - sock = self._close_on_teardown(socket.socket()) - sock.connect((host or params.DEFAULT_CONNECT, port or self.port)) - if timeout is not None: - sock.settimeout(timeout) - if blocking is not None: - sock.setblocking(blocking) - return sock - - def _test_sendall(self, data, match_data=None, client_method='sendall', - **client_args): - # pylint:disable=too-many-locals,too-many-branches,too-many-statements - log = self.log - log("test_sendall using method", client_method) - - read_data = [] - accepted_event = Event() - - def accept_and_read(): - log("\taccepting", self.listener) - conn, _ = self.listener.accept() - try: - with conn.makefile(mode='rb') as r: - log("\taccepted on server; client conn is", conn, "file is", r) - accepted_event.set() - log("\treading") - read_data.append(r.read()) - log("\tdone reading", r, "got bytes", len(read_data[0])) - del r - finally: - conn.close() - del conn - - - server = Thread(target=accept_and_read) - try: - log("creating client connection") - client = self.create_connection(**client_args) - - # It's important to wait for the server to fully accept before - # we shutdown and close the socket. In SSL mode, the number - # and timing of data exchanges to complete the handshake and - # thus exactly when greenlet switches occur, varies by TLS version. - # - # It turns out that on < TLS1.3, we were getting lucky and the - # server was the greenlet that raced ahead and blocked in r.read() - # before the client returned from create_connection(). - # - # But when TLS 1.3 was deployed (OpenSSL 1.1), the *client* was the - # one that raced ahead while the server had yet to return from - # self.listener.accept(). So the client sent the data to the socket, - # and closed, before the server could do anything, and the server, - # when it got switched to by server.join(), found its new socket - # dead. - accepted_event.wait() - log("Client got accepted event from server", client, "; sending data", len(data)) - try: - x = getattr(client, client_method)(data) - log("Client sent data: result from method", x) - finally: - log("Client will unwrap and shutdown") - if hasattr(client, 'unwrap'): - # Are we dealing with an SSLSocket? If so, unwrap it - # before attempting to shut down the socket. This does the - # SSL shutdown handshake and (hopefully) stops ``accept_and_read`` - # from generating ``ConnectionResetError`` on AppVeyor. - try: - client = client.unwrap() - except (ValueError, OSError): - # PyPy raises _cffi_ssl._stdssl.error.SSLSyscallError, - # which is an IOError in 2.7 and OSError in 3.7 - pass - - try: - # The implicit reference-based nastiness of Python 2 - # sockets interferes, especially when using SSL sockets. - # The best way to get a decent FIN to the server is to shutdown - # the output. Doing that on Python 3, OTOH, is contraindicated - # except on PyPy, so this used to read ``PY2 or PYPY``. But - # it seems that a shutdown is generally good practice, and I didn't - # document what errors we saw without it. Per issue #1637 - # lets do a shutdown everywhere, but only after removing any - # SSL wrapping. - client.shutdown(socket.SHUT_RDWR) - except OSError: - pass - - log("Client will close") - client.close() - finally: - server.join(10) - assert not server.is_alive() - - if server.terminal_exc: - reraise(*server.terminal_exc) - - if match_data is None: - match_data = self.long_data - read_data = read_data[0].split(b',') - match_data = match_data.split(b',') - self.assertEqual(read_data[0], match_data[0]) - self.assertEqual(len(read_data), len(match_data)) - self.assertEqual(read_data, match_data) - - def test_sendall_str(self): - self._test_sendall(self.long_data) - - @skipOnMacOnCI("Sometimes fails for no apparent reason (buffering?)") - def test_sendall_array(self): - data = array.array("B", self.long_data) - self._test_sendall(data) - - def test_sendall_empty(self): - data = b'' - self._test_sendall(data, data) - - def test_sendall_empty_with_timeout(self): - # Issue 719 - data = b'' - self._test_sendall(data, data, timeout=10) - - def test_sendall_nonblocking(self): - # https://github.com/benoitc/gunicorn/issues/1282 - # Even if the socket is non-blocking, we make at least - # one attempt to send data. Under Py2 before this fix, we - # would incorrectly immediately raise a timeout error - data = b'hi\n' - self._test_sendall(data, data, blocking=False) - - def test_empty_send(self): - # Issue 719 - data = b'' - self._test_sendall(data, data, client_method='send') - - def test_fullduplex(self): - N = 100000 - - def server(): - remote_client, _ = self.listener.accept() - self._close_on_teardown(remote_client) - # start reading, then, while reading, start writing. the reader should not hang forever - - sender = Thread(target=remote_client.sendall, - args=((b't' * N),)) - try: - result = remote_client.recv(1000) - self.assertEqual(result, b'hello world') - finally: - sender.join() - - server_thread = Thread(target=server) - client = self.create_connection() - client_file = self._close_on_teardown(client.makefile()) - client_reader = Thread(target=client_file.read, args=(N, )) - time.sleep(0.1) - client.sendall(b'hello world') - time.sleep(0.1) - - # close() used to hang - client_file.close() - client.close() - - # this tests "full duplex" bug; - server_thread.join() - - client_reader.join() - - def test_recv_timeout(self): - def accept(): - # make sure the conn object stays alive until the end; - # premature closing triggers a ResourceWarning and - # EOF on the client. - conn, _ = self.listener.accept() - self._close_on_teardown(conn) - - acceptor = Thread(target=accept) - client = self.create_connection() - try: - client.settimeout(1) - start = time.time() - with self.assertRaises(self.TIMEOUT_ERROR): - client.recv(1024) - took = time.time() - start - self.assertTimeWithinRange(took, 1 - 0.1, 1 + 0.1) - finally: - acceptor.join() - - # Subclasses can disable this - _test_sendall_timeout_check_time = True - - # Travis-CI container infrastructure is configured with - # large socket buffers, at least 2MB, as-of Jun 3, 2015, - # so we must be sure to send more data than that. - # In 2018, this needs to be increased *again* as a smaller value was - # still often being sent. - _test_sendall_data = b'hello' * 100000000 - - # This doesn't make much sense...why are we really skipping this? - @greentest.skipOnWindows("On Windows send() accepts whatever is thrown at it") - def test_sendall_timeout(self): - client_sock = [] - acceptor = Thread(target=lambda: client_sock.append(self.listener.accept())) - client = self.create_connection() - time.sleep(0.1) - assert client_sock - client.settimeout(0.1) - start = time.time() - try: - with self.assertRaises(self.TIMEOUT_ERROR): - client.sendall(self._test_sendall_data) - if self._test_sendall_timeout_check_time: - took = time.time() - start - self.assertTimeWithinRange(took, 0.09, 0.21) - finally: - acceptor.join() - client.close() - client_sock[0][0].close() - - def test_makefile(self): - def accept_once(): - conn, _ = self.listener.accept() - fd = conn.makefile(mode='wb') - fd.write(b'hello\n') - fd.flush() - fd.close() - conn.close() # for pypy - - acceptor = Thread(target=accept_once) - try: - client = self.create_connection() - # Closing the socket doesn't close the file - client_file = client.makefile(mode='rb') - client.close() - line = client_file.readline() - self.assertEqual(line, b'hello\n') - self.assertEqual(client_file.read(), b'') - client_file.close() - finally: - acceptor.join() - - def test_makefile_timeout(self): - - def accept_once(): - conn, _ = self.listener.accept() - try: - time.sleep(0.3) - finally: - conn.close() # for pypy - - acceptor = Thread(target=accept_once) - try: - client = self.create_connection() - client.settimeout(0.1) - fd = client.makefile(mode='rb') - self.assertRaises(self.TIMEOUT_ERROR, fd.readline) - client.close() - fd.close() - finally: - acceptor.join() - - def test_attributes(self): - s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, 0) - self.assertIs(s.family, socket.AF_INET) - self.assertEqual(s.type, socket.SOCK_DGRAM) - self.assertEqual(0, s.proto) - - if hasattr(socket, 'SOCK_NONBLOCK'): - s.settimeout(1) - self.assertIs(s.family, socket.AF_INET) - - s.setblocking(0) - std_socket = monkey.get_original('socket', 'socket')(socket.AF_INET, socket.SOCK_DGRAM, 0) - try: - std_socket.setblocking(0) - self.assertEqual(std_socket.type, s.type) - finally: - std_socket.close() - - s.close() - - def test_connect_ex_nonblocking_bad_connection(self): - # Issue 841 - s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) - try: - s.setblocking(False) - ret = s.connect_ex((greentest.DEFAULT_LOCAL_HOST_ADDR, support.find_unused_port())) - self.assertIsInstance(ret, errno_types) - finally: - s.close() - - @skipWithoutExternalNetwork("Tries to resolve hostname") - def test_connect_ex_gaierror(self): - # Issue 841 - s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) - try: - with self.assertRaises(socket.gaierror): - s.connect_ex(('foo.bar.fizzbuzz', support.find_unused_port())) - finally: - s.close() - - @skipWithoutExternalNetwork("Tries to resolve hostname") - def test_connect_ex_not_call_connect(self): - # Issue 1931 - - def do_it(sock): - try: - with self.assertRaises(socket.gaierror): - sock.connect_ex(('foo.bar.fizzbuzz', support.find_unused_port())) - finally: - sock.close() - - # An instance attribute doesn't matter because we can't set it - s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) - with self.assertRaises(AttributeError): - s.connect = None - s.close() - - # A subclass - class S(socket.socket): - def connect(self, *args): - raise AssertionError('Should not be called') - - s = S(socket.AF_INET, socket.SOCK_STREAM) - do_it(s) - - def test_connect_ex_nonblocking_overflow(self): - # Issue 841 - s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) - try: - s.setblocking(False) - with self.assertRaises(OverflowError): - s.connect_ex((greentest.DEFAULT_LOCAL_HOST_ADDR, 65539)) - finally: - s.close() - - @unittest.skipUnless(hasattr(socket, 'SOCK_CLOEXEC'), - "Requires SOCK_CLOEXEC") - def test_connect_with_type_flags_ignored(self): - # Issue 944 - # If we have SOCK_CLOEXEC or similar, we shouldn't be passing - # them through to the getaddrinfo call that connect() makes - SOCK_CLOEXEC = socket.SOCK_CLOEXEC # pylint:disable=no-member - s = socket.socket(socket.AF_INET, socket.SOCK_STREAM | SOCK_CLOEXEC) - - def accept_once(): - conn, _ = self.listener.accept() - fd = conn.makefile(mode='wb') - fd.write(b'hello\n') - fd.close() - conn.close() - - acceptor = Thread(target=accept_once) - try: - s.connect((params.DEFAULT_CONNECT, self.port)) - fd = s.makefile(mode='rb') - self.assertEqual(fd.readline(), b'hello\n') - - fd.close() - s.close() - finally: - acceptor.join() - - -class TestCreateConnection(greentest.TestCase): - - __timeout__ = LARGE_TIMEOUT - - def test_refuses(self, **conn_args): - connect_port = support.find_unused_port() - - with self.assertRaisesRegex( - socket.error, - # We really expect "connection refused". It's unclear - # where/why we would get '[errno -2] name or service - # not known' but it seems some systems generate that. - # https://github.com/gevent/gevent/issues/1389 Somehow - # extremly rarely we've also seen 'address already in - # use', which makes even less sense. The manylinux - # 2010 environment produces 'errno 99 Cannot assign - # requested address', which, I guess? - # Meanwhile, the musllinux_1 environment produces - # '[Errno 99] Address not available' - 'refused|not known|already in use|assign|not available' - ): - socket.create_connection( - (greentest.DEFAULT_BIND_ADDR, connect_port), - timeout=30, - **conn_args - ) - - def test_refuses_from_port(self): - source_port = support.find_unused_port() - # Usually we don't want to bind/connect to '', but - # using it as the source is required if we don't want to hang, - # at least on some systems (OS X) - self.test_refuses(source_address=('', source_port)) - - - @greentest.ignores_leakcheck - @skipWithoutExternalNetwork("Tries to resolve hostname") - def test_base_exception(self): - # such as a GreenletExit or a gevent.timeout.Timeout - - class E(BaseException): - pass - - class MockSocket(object): - - created = () - closed = False - - def __init__(self, *_): - MockSocket.created += (self,) - - def connect(self, _): - raise E(_) - - def close(self): - self.closed = True - - def mockgetaddrinfo(*_): - return [(1, 2, 3, 3, 5),] - - import gevent.socket as gsocket - # Make sure we're monkey patched - self.assertEqual(gsocket.create_connection, socket.create_connection) - orig_socket = gsocket.socket - orig_getaddrinfo = gsocket.getaddrinfo - - try: - gsocket.socket = MockSocket - gsocket.getaddrinfo = mockgetaddrinfo - - with self.assertRaises(E): - socket.create_connection(('host', 'port')) - - self.assertEqual(1, len(MockSocket.created)) - self.assertTrue(MockSocket.created[0].closed) - - finally: - MockSocket.created = () - gsocket.socket = orig_socket - gsocket.getaddrinfo = orig_getaddrinfo - -class TestFunctions(greentest.TestCase): - - @greentest.ignores_leakcheck - # Creating new types in the function takes a cycle to cleanup. - def test_wait_timeout(self): - # Issue #635 - from gevent import socket as gsocket - class io(object): - callback = None - - def start(self, *_args): - gevent.sleep(10) - - with self.assertRaises(gsocket.timeout): - gsocket.wait(io(), timeout=0.01) # pylint:disable=no-member - - - def test_signatures(self): - # https://github.com/gevent/gevent/issues/960 - exclude = [] - if greentest.PYPY: - # Up through at least PyPy 5.7.1, they define these as - # gethostbyname(host), whereas the official CPython argument name - # is hostname. But cpython doesn't allow calling with keyword args. - # Likewise for gethostbyaddr: PyPy uses host, cpython uses ip_address - exclude.append('gethostbyname') - exclude.append('gethostbyname_ex') - exclude.append('gethostbyaddr') - if sys.version_info[:2] < (3, 11): - # 3.11+ add ``*, all_errors=False``. We allow that on all versions, - # forcing it to a false value if the user sends a true value before - # exception groups exist. - exclude.append('create_connection') - self.assertMonkeyPatchedFuncSignatures('socket', exclude=exclude) - - def test_resolve_ipv6_scope_id(self): - from gevent import _socketcommon as SC - if not SC.__socket__.has_ipv6: - self.skipTest("Needs IPv6") # pragma: no cover - if not hasattr(SC.__socket__, 'inet_pton'): - self.skipTest("Needs inet_pton") # pragma: no cover - - # A valid IPv6 address, with a scope. - addr = ('2607:f8b0:4000:80e::200e', 80, 0, 9) - # Mock socket - class sock(object): - family = SC.AF_INET6 # pylint:disable=no-member - self.assertIs(addr, SC._resolve_addr(sock, addr)) - -class TestSocket(greentest.TestCase): - - def test_shutdown_when_closed(self): - # https://github.com/gevent/gevent/issues/1089 - # we once raised an AttributeError. - s = socket.socket() - s.close() - with self.assertRaises(socket.error): - s.shutdown(socket.SHUT_RDWR) - - def test_can_be_weak_ref(self): - # stdlib socket can be weak reffed. - import weakref - s = socket.socket() - try: - w = weakref.ref(s) - self.assertIsNotNone(w) - finally: - s.close() - - def test_has_no_dict(self): - # stdlib socket has no dict - s = socket.socket() - try: - with self.assertRaises(AttributeError): - getattr(s, '__dict__') - finally: - s.close() - - -if __name__ == '__main__': - greentest.main() diff --git a/venv/lib/python3.9/site-packages/gevent/tests/test__socket_close.py b/venv/lib/python3.9/site-packages/gevent/tests/test__socket_close.py deleted file mode 100644 index b67adae..0000000 --- a/venv/lib/python3.9/site-packages/gevent/tests/test__socket_close.py +++ /dev/null @@ -1,58 +0,0 @@ -import gevent -from gevent import socket -from gevent import server -import gevent.testing as greentest - -# XXX also test: send, sendall, recvfrom, recvfrom_into, sendto - - -def readall(sock, _): - while sock.recv(1024): - pass # pragma: no cover we never actually send the data - sock.close() - - -class Test(greentest.TestCase): - - error_fatal = False - - def setUp(self): - self.server = server.StreamServer(greentest.DEFAULT_BIND_ADDR_TUPLE, readall) - self.server.start() - - def tearDown(self): - self.server.stop() - - def test_recv_closed(self): - sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) - sock.connect((greentest.DEFAULT_CONNECT_HOST, self.server.server_port)) - receiver = gevent.spawn(sock.recv, 25) - try: - gevent.sleep(0.001) - sock.close() - receiver.join(timeout=0.1) - self.assertTrue(receiver.ready(), receiver) - self.assertEqual(receiver.value, None) - self.assertIsInstance(receiver.exception, socket.error) - self.assertEqual(receiver.exception.errno, socket.EBADF) - finally: - receiver.kill() - - # XXX: This is possibly due to the bad behaviour of small sleeps? - # The timeout is the global test timeout, 10s - @greentest.skipOnLibuvOnCI("Sometimes randomly times out") - def test_recv_twice(self): - sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) - sock.connect((greentest.DEFAULT_CONNECT_HOST, self.server.server_port)) - receiver = gevent.spawn(sock.recv, 25) - try: - gevent.sleep(0.001) - self.assertRaises(AssertionError, sock.recv, 25) - self.assertRaises(AssertionError, sock.recv, 25) - finally: - receiver.kill() - sock.close() - - -if __name__ == '__main__': - greentest.main() diff --git a/venv/lib/python3.9/site-packages/gevent/tests/test__socket_dns.py b/venv/lib/python3.9/site-packages/gevent/tests/test__socket_dns.py deleted file mode 100644 index ff631b3..0000000 --- a/venv/lib/python3.9/site-packages/gevent/tests/test__socket_dns.py +++ /dev/null @@ -1,931 +0,0 @@ -#!/usr/bin/python -# -*- coding: utf-8 -*- -from __future__ import print_function -from __future__ import absolute_import -from __future__ import division -import gevent -from gevent import monkey - -import os -import re - -import unittest -import socket -from time import time -import traceback - -import gevent.socket as gevent_socket -import gevent.testing as greentest - -from gevent.testing import util -from gevent.testing import flaky -from gevent.testing.skipping import skipWithoutExternalNetwork - - -resolver = gevent.get_hub().resolver -util.debug('Resolver: %s', resolver) - -if getattr(resolver, 'pool', None) is not None: - resolver.pool.size = 1 - -from gevent.testing.sysinfo import RESOLVER_NOT_SYSTEM -from gevent.testing.sysinfo import RESOLVER_DNSPYTHON -from gevent.testing.sysinfo import RESOLVER_ARES -from gevent.testing.sysinfo import PYPY - -import gevent.testing.timing - - -assert gevent_socket.gaierror is socket.gaierror -assert gevent_socket.error is socket.error - - -RUN_ALL_HOST_TESTS = os.getenv('GEVENTTEST_RUN_ALL_ETC_HOST_TESTS', '') - - -def add(klass, hostname, name=None, - skip=None, skip_reason=None, - require_equal_errors=True): - - call = callable(hostname) - - def _setattr(k, n, func): - if skip: - func = greentest.skipIf(skip, skip_reason,)(func) - if not hasattr(k, n): - setattr(k, n, func) - - if name is None: - if call: - name = hostname.__name__ - else: - name = re.sub(r'[^\w]+', '_', repr(hostname)) - assert name, repr(hostname) - - def test_getaddrinfo_http(self): - x = hostname() if call else hostname - self._test('getaddrinfo', x, 'http', - require_equal_errors=require_equal_errors) - test_getaddrinfo_http.__name__ = 'test_%s_getaddrinfo_http' % name - _setattr(klass, test_getaddrinfo_http.__name__, test_getaddrinfo_http) - - def test_gethostbyname(self): - x = hostname() if call else hostname - ipaddr = self._test('gethostbyname', x, - require_equal_errors=require_equal_errors) - if not isinstance(ipaddr, Exception): - self._test('gethostbyaddr', ipaddr, - require_equal_errors=require_equal_errors) - test_gethostbyname.__name__ = 'test_%s_gethostbyname' % name - _setattr(klass, test_gethostbyname.__name__, test_gethostbyname) - - def test_gethostbyname_ex(self): - x = hostname() if call else hostname - self._test('gethostbyname_ex', x, - require_equal_errors=require_equal_errors) - test_gethostbyname_ex.__name__ = 'test_%s_gethostbyname_ex' % name - _setattr(klass, test_gethostbyname_ex.__name__, test_gethostbyname_ex) - - def test4(self): - x = hostname() if call else hostname - self._test('gethostbyaddr', x, - require_equal_errors=require_equal_errors) - test4.__name__ = 'test_%s_gethostbyaddr' % name - _setattr(klass, test4.__name__, test4) - - def test5(self): - x = hostname() if call else hostname - self._test('getnameinfo', (x, 80), 0, - require_equal_errors=require_equal_errors) - test5.__name__ = 'test_%s_getnameinfo' % name - _setattr(klass, test5.__name__, test5) - -@skipWithoutExternalNetwork("Tries to resolve and compare hostnames/addrinfo") -class TestCase(greentest.TestCase): - maxDiff = None - __timeout__ = 30 - switch_expected = None - - TRACE = not util.QUIET and os.getenv('GEVENT_DEBUG', '') == 'trace' - verbose_dns = TRACE - - def trace(self, message, *args, **kwargs): - if self.TRACE: - util.debug(message, *args, **kwargs) - - # Things that the stdlib should never raise and neither should we; - # these indicate bugs in our code and we want to raise them. - REAL_ERRORS = (AttributeError, ValueError, NameError) - - def __run_resolver(self, function, args): - try: - result = function(*args) - assert not isinstance(result, BaseException), repr(result) - return result - except self.REAL_ERRORS: - raise - except Exception as ex: # pylint:disable=broad-except - if self.TRACE: - traceback.print_exc() - return ex - - def __trace_call(self, result, runtime, function, *args): - util.debug(self.__format_call(function, args)) - self.__trace_fresult(result, runtime) - - def __format_call(self, function, args): - args = repr(args) - if args.endswith(',)'): - args = args[:-2] + ')' - try: - module = function.__module__.replace('gevent._socketcommon', 'gevent') - name = function.__name__ - return '%s:%s%s' % (module, name, args) - except AttributeError: - return function + args - - def __trace_fresult(self, result, seconds): - if isinstance(result, Exception): - msg = ' -=> raised %r' % (result, ) - else: - msg = ' -=> returned %r' % (result, ) - time_ms = ' %.2fms' % (seconds * 1000.0, ) - space = 80 - len(msg) - len(time_ms) - if space > 0: - space = ' ' * space - else: - space = '' - util.debug(msg + space + time_ms) - - if not TRACE: - def run_resolver(self, function, func_args): - now = time() - return self.__run_resolver(function, func_args), time() - now - else: - def run_resolver(self, function, func_args): - self.trace(self.__format_call(function, func_args)) - delta = time() - result = self.__run_resolver(function, func_args) - delta = time() - delta - self.__trace_fresult(result, delta) - return result, delta - - def setUp(self): - super(TestCase, self).setUp() - if not self.verbose_dns: - # Silence the default reporting of errors from the ThreadPool, - # we handle those here. - gevent.get_hub().exception_stream = None - - def tearDown(self): - if not self.verbose_dns: - try: - del gevent.get_hub().exception_stream - except AttributeError: - pass # Happens under leak tests - super(TestCase, self).tearDown() - - def should_log_results(self, result1, result2): - if not self.verbose_dns: - return False - - if isinstance(result1, BaseException) and isinstance(result2, BaseException): - return type(result1) is not type(result2) - return repr(result1) != repr(result2) - - def _test(self, func_name, *args, **kwargs): - """ - Runs the function *func_name* with *args* and compares gevent and the system. - - Keyword arguments are passed to the function itself; variable args are - used for the socket function. - - Returns the gevent result. - """ - gevent_func = getattr(gevent_socket, func_name) - real_func = monkey.get_original('socket', func_name) - - tester = getattr(self, '_run_test_' + func_name, self._run_test_generic) - result = tester(func_name, real_func, gevent_func, args, **kwargs) - _real_result, time_real, gevent_result, time_gevent = result - - if self.verbose_dns and time_gevent > time_real + 0.02 and time_gevent > 0.03: - msg = 'gevent:%s%s took %dms versus %dms stdlib' % ( - func_name, args, time_gevent * 1000.0, time_real * 1000.0) - - if time_gevent > time_real + 1: - word = 'VERY' - else: - word = 'quite' - - util.log('\nWARNING: %s slow: %s', word, msg, color='warning') - - return gevent_result - - def _run_test_generic(self, func_name, real_func, gevent_func, func_args, - require_equal_errors=True): - real_result, time_real = self.run_resolver(real_func, func_args) - gevent_result, time_gevent = self.run_resolver(gevent_func, func_args) - if util.QUIET and self.should_log_results(real_result, gevent_result): - util.log('') - self.__trace_call(real_result, time_real, real_func, func_args) - self.__trace_call(gevent_result, time_gevent, gevent_func, func_args) - - self.assertEqualResults(real_result, gevent_result, func_name, - require_equal_errors=require_equal_errors) - return real_result, time_real, gevent_result, time_gevent - - def _normalize_result(self, result, func_name): - norm_name = '_normalize_result_' + func_name - if hasattr(self, norm_name): - return getattr(self, norm_name)(result) - return result - - NORMALIZE_GAI_IGNORE_CANONICAL_NAME = RESOLVER_ARES # It tends to return them even when not asked for - if not RESOLVER_NOT_SYSTEM: - def _normalize_result_getaddrinfo(self, result): - return result - def _normalize_result_gethostbyname_ex(self, result): - return result - else: - def _normalize_result_gethostbyname_ex(self, result): - # Often the second and third part of the tuple (hostname, aliaslist, ipaddrlist) - # can be in different orders if we're hitting different servers, - # or using the native and ares resolvers due to load-balancing techniques. - # We sort them. - if isinstance(result, BaseException): - return result - # result[1].sort() # we wind up discarding this - - # On Py2 in test_russion_gethostbyname_ex, this - # is actually an integer, for some reason. In TestLocalhost.tets__ip6_localhost, - # the result isn't this long (maybe an error?). - try: - result[2].sort() - except AttributeError: - pass - except IndexError: - return result - # On some systems, a random alias is found in the aliaslist - # by the system resolver, but not by cares, and vice versa. We deem the aliaslist - # unimportant and discard it. - # On some systems (Travis CI), the ipaddrlist for 'localhost' can come back - # with two entries 127.0.0.1 (presumably two interfaces?) for c-ares - ips = result[2] - if ips == ['127.0.0.1', '127.0.0.1']: - ips = ['127.0.0.1'] - # On some systems, the hostname can get caps - return (result[0].lower(), [], ips) - - def _normalize_result_getaddrinfo(self, result): - # Result is a list - # (family, socktype, proto, canonname, sockaddr) - # e.g., - # (AF_INET, SOCK_STREAM, IPPROTO_TCP, 'readthedocs.io', (127.0.0.1, 80)) - if isinstance(result, BaseException): - return result - - # On Python 3, the builtin resolver can return SOCK_RAW results, but - # c-ares doesn't do that. So we remove those if we find them. - # Likewise, on certain Linux systems, even on Python 2, IPPROTO_SCTP (132) - # results may be returned --- but that may not even have a constant in the - # socket module! So to be safe, we strip out anything that's not - # SOCK_STREAM or SOCK_DGRAM - if isinstance(result, list): - result = [ - x - for x in result - if x[1] in (socket.SOCK_STREAM, socket.SOCK_DGRAM) - and x[2] in (socket.IPPROTO_TCP, socket.IPPROTO_UDP) - ] - - if self.NORMALIZE_GAI_IGNORE_CANONICAL_NAME: - result = [ - (family, kind, proto, '', addr) - for family, kind, proto, _, addr - in result - ] - - if isinstance(result, list): - result.sort() - return result - - def _normalize_result_getnameinfo(self, result): - return result - - NORMALIZE_GHBA_IGNORE_ALIAS = False - def _normalize_result_gethostbyaddr(self, result): - if not RESOLVER_NOT_SYSTEM: - return result - - if self.NORMALIZE_GHBA_IGNORE_ALIAS and isinstance(result, tuple): - # On some systems, a random alias is found in the aliaslist - # by the system resolver, but not by cares and vice versa. This is *probably* only the - # case for localhost or things otherwise in /etc/hosts. We deem the aliaslist - # unimportant and discard it. - return (result[0], [], result[2]) - return result - - def _compare_exceptions_strict(self, real_result, gevent_result, func_name): - if repr(real_result) == repr(gevent_result): - # Catch things like `OverflowError('port must be 0-65535.',)``` - return - - msg = (func_name, 'system:', repr(real_result), 'gevent:', repr(gevent_result)) - self.assertIs(type(gevent_result), type(real_result), msg) - - if isinstance(real_result, TypeError): - return - - if PYPY and isinstance(real_result, socket.herror): - # PyPy doesn't do errno or multiple arguments in herror; - # it just puts a string like 'host lookup failed: '; - # it must be doing that manually. - return - - self.assertEqual(real_result.args, gevent_result.args, msg) - if hasattr(real_result, 'errno'): - self.assertEqual(real_result.errno, gevent_result.errno) - - def _compare_exceptions_lenient(self, real_result, gevent_result, func_name): - try: - self._compare_exceptions_strict(real_result, gevent_result, func_name) - except AssertionError: - # Allow raising different things in a few rare cases. - if ( - func_name not in ( - 'getaddrinfo', - 'gethostbyaddr', - 'gethostbyname', - 'gethostbyname_ex', - 'getnameinfo', - ) - or type(real_result) not in (socket.herror, socket.gaierror) - or type(gevent_result) not in (socket.herror, socket.gaierror, socket.error) - ): - raise - util.log('WARNING: error type mismatch for %s: %r (gevent) != %r (stdlib)', - func_name, - gevent_result, real_result, - color='warning') - - _compare_exceptions = _compare_exceptions_lenient if RESOLVER_NOT_SYSTEM else _compare_exceptions_strict - - def _compare_results(self, real_result, gevent_result, func_name): - if real_result == gevent_result: - return True - - compare_func = getattr(self, '_compare_results_' + func_name, - self._generic_compare_results) - return compare_func(real_result, gevent_result, func_name) - - def _generic_compare_results(self, real_result, gevent_result, func_name): - try: - if len(real_result) != len(gevent_result): - return False - except TypeError: - return False - - return all(self._compare_results(x, y, func_name) - for (x, y) - in zip(real_result, gevent_result)) - - def _compare_results_getaddrinfo(self, real_result, gevent_result, func_name): - # On some systems, we find more results with - # one resolver than we do with the other resolver. - # So as long as they have some subset in common, - # we'll take it. - errors = isinstance(real_result, Exception) + isinstance(gevent_result, Exception) - if errors == 2: - return True - if errors == 1: - return False - - if not set(real_result).isdisjoint(set(gevent_result)): - return True - return self._generic_compare_results(real_result, gevent_result, func_name) - - def _compare_address_strings(self, a, b): - # IPv6 address from different requests might be different - a_segments = a.count(':') - b_segments = b.count(':') - if a_segments and b_segments: - if a_segments == b_segments and a_segments in (4, 5, 6, 7): - return True - if a.rstrip(':').startswith(b.rstrip(':')) or b.rstrip(':').startswith(a.rstrip(':')): - return True - if a_segments >= 2 and b_segments >= 2 and a.split(':')[:2] == b.split(':')[:2]: - return True - - return a.split('.', 1)[-1] == b.split('.', 1)[-1] - - def _compare_results_gethostbyname(self, real_result, gevent_result, _func_name): - # Both strings. - return self._compare_address_strings(real_result, gevent_result) - - def _compare_results_gethostbyname_ex(self, real_result, gevent_result, _func_name): - # Results are IPv4 only: - # (hostname, [aliaslist], [ipaddrlist]) - # As for getaddrinfo, we'll just check the ipaddrlist has something in common. - return not set(real_result[2]).isdisjoint(set(gevent_result[2])) - - def assertEqualResults(self, real_result, gevent_result, func_name, - require_equal_errors=True): - errors = ( - OverflowError, - TypeError, - UnicodeError, - socket.error, - socket.gaierror, - socket.herror, - ) - if isinstance(real_result, errors) and isinstance(gevent_result, errors): - if require_equal_errors: - self._compare_exceptions(real_result, gevent_result, func_name) - return - - real_result = self._normalize_result(real_result, func_name) - gevent_result = self._normalize_result(gevent_result, func_name) - - if self._compare_results(real_result, gevent_result, func_name): - return - - # If we're using a different resolver, allow the real resolver to generate an - # error that the gevent resolver actually gets an answer to. - if ( - RESOLVER_NOT_SYSTEM - and isinstance(real_result, errors) - and not isinstance(gevent_result, errors) - ): - return - - # On PyPy, socket.getnameinfo() can produce results even when the hostname resolves to - # multiple addresses, like www.gevent.org does. DNSPython (and c-ares?) don't do that, - # they refuse to pick a name and raise ``socket.error`` - if ( - RESOLVER_NOT_SYSTEM - and PYPY - and func_name == 'getnameinfo' - and isinstance(gevent_result, socket.error) - and not isinstance(real_result, socket.error) - ): - return - - - # From 2.7 on, assertEqual does a better job highlighting the results than we would - # because it calls assertSequenceEqual, which highlights the exact - # difference in the tuple - self.assertEqual(real_result, gevent_result) - - -class TestTypeError(TestCase): - pass - -add(TestTypeError, None) -add(TestTypeError, 25) - - -class TestHostname(TestCase): - NORMALIZE_GHBA_IGNORE_ALIAS = True - - def __normalize_name(self, result): - if (RESOLVER_ARES or RESOLVER_DNSPYTHON) and isinstance(result, tuple): - # The system resolver can return the FQDN, in the first result, - # when given certain configurations. But c-ares and dnspython - # do not. - name = result[0] - name = name.split('.', 1)[0] - result = (name,) + result[1:] - return result - - def _normalize_result_gethostbyaddr(self, result): - result = TestCase._normalize_result_gethostbyaddr(self, result) - return self.__normalize_name(result) - - def _normalize_result_getnameinfo(self, result): - result = TestCase._normalize_result_getnameinfo(self, result) - return result - -add( - TestHostname, - socket.gethostname, - skip=greentest.RUNNING_ON_TRAVIS and greentest.RESOLVER_NOT_SYSTEM, - skip_reason=("Sometimes get a different result for getaddrinfo " - "with dnspython; c-ares produces different results for " - "localhost on Travis beginning Sept 2019") -) - - -class TestLocalhost(TestCase): - # certain tests in test_patched_socket.py only work if getaddrinfo('localhost') does not switch - # (e.g. NetworkConnectionAttributesTest.testSourceAddress) - #switch_expected = False - # XXX: The above has been commented out for some time. Apparently this isn't the case - # anymore. - - def _normalize_result_getaddrinfo(self, result): - if RESOLVER_NOT_SYSTEM: - # We see that some impls (OS X) return extra results - # like DGRAM that ares does not. - return () - return super(TestLocalhost, self)._normalize_result_getaddrinfo(result) - - NORMALIZE_GHBA_IGNORE_ALIAS = True - - -add( - TestLocalhost, 'ip6-localhost', - skip=RESOLVER_DNSPYTHON, # XXX: Fix these. - skip_reason="Can return gaierror(-2)" -) -add( - TestLocalhost, 'localhost', - skip=greentest.RUNNING_ON_TRAVIS, - skip_reason="Can return gaierror(-2)" -) - - - - -class TestNonexistent(TestCase): - pass - -add(TestNonexistent, 'nonexistentxxxyyy') - - -class Test1234(TestCase): - pass - -add(Test1234, '1.2.3.4') - - -class Test127001(TestCase): - NORMALIZE_GHBA_IGNORE_ALIAS = True - -add( - Test127001, '127.0.0.1', - # skip=RESOLVER_DNSPYTHON, - # skip_reason="Beginning Dec 1 2017, ares started returning ip6-localhost " - # "instead of localhost" -) - - - -class TestBroadcast(TestCase): - switch_expected = False - - if RESOLVER_DNSPYTHON: - # dnspython raises errors for broadcasthost/255.255.255.255, but the system - # can resolve it. - - @unittest.skip('ares raises errors for broadcasthost/255.255.255.255') - def test__broadcast__gethostbyaddr(self): - return - - test__broadcast__gethostbyname = test__broadcast__gethostbyaddr - -add(TestBroadcast, '') - - -from gevent.resolver._hostsfile import HostsFile -class SanitizedHostsFile(HostsFile): - def iter_all_host_addr_pairs(self): - for name, addr in super(SanitizedHostsFile, self).iter_all_host_addr_pairs(): - if (RESOLVER_NOT_SYSTEM - and (name.endswith('local') # ignore bonjour, ares can't find them - # ignore common aliases that ares can't find - or addr == '255.255.255.255' - or name == 'broadcasthost' - # We get extra results from some impls, like OS X - # it returns DGRAM results - or name == 'localhost')): - continue # pragma: no cover - if name.endswith('local'): - # These can only be found if bonjour is running, - # and are very slow to do so with the system resolver on OS X - continue - yield name, addr - - -@greentest.skipIf(greentest.RUNNING_ON_CI, - "This sometimes randomly fails on Travis with ares and on appveyor, beginning Feb 13, 2018") -# Probably due to round-robin DNS, -# since this is not actually the system's etc hosts file. -# TODO: Rethink this. We need something reliable. Go back to using -# the system's etc hosts? -class TestEtcHosts(TestCase): - - MAX_HOSTS = int(os.getenv('GEVENTTEST_MAX_ETC_HOSTS', '10')) - - @classmethod - def populate_tests(cls): - hf = SanitizedHostsFile(os.path.join(os.path.dirname(__file__), - 'hosts_file.txt')) - all_etc_hosts = sorted(hf.iter_all_host_addr_pairs()) - if len(all_etc_hosts) > cls.MAX_HOSTS and not RUN_ALL_HOST_TESTS: - all_etc_hosts = all_etc_hosts[:cls.MAX_HOSTS] - - for host, ip in all_etc_hosts: - add(cls, host) - add(cls, ip) - - - -TestEtcHosts.populate_tests() - - - -class TestGeventOrg(TestCase): - # For this test to work correctly, it needs to resolve to - # an address with a single A record; round-robin DNS and multiple A records - # may mess it up (subsequent requests---and we always make two---may return - # unequal results). We used to use gevent.org, but that now has multiple A records; - # trying www.gevent.org which is a CNAME to readthedocs.org then worked, but it became - # an alias for python-gevent.readthedocs.org, which is an alias for readthedocs.io, - # and which also has multiple addresses. So we run the resolver twice to try to get - # the different answers, if needed. Even then it's not enough, so - # we normalize the two addresses we get to a single one. - HOSTNAME = 'www.gevent.org' - - - - def _normalize_result_gethostbyname(self, result): - if result == '104.17.33.82': - result = '104.17.32.82' - if result == '104.16.254.120': - result = '104.16.253.120' - return result - - def _normalize_result_gethostbyname_ex(self, result): - result = super(TestGeventOrg, self)._normalize_result_gethostbyname_ex(result) - if result[0] == 'python-gevent.readthedocs.org': - result = ('readthedocs.io', ) + result[1:] - return result - - def test_AI_CANONNAME(self): - # Not all systems support AI_CANONNAME; notably tha manylinux - # resolvers *sometimes* do not. Specifically, sometimes they - # provide the canonical name *only* on the first result. - - args = ( - # host - TestGeventOrg.HOSTNAME, - # port - None, - # family - socket.AF_INET, - # type - 0, - # proto - 0, - # flags - socket.AI_CANONNAME - ) - gevent_result = gevent_socket.getaddrinfo(*args) - self.assertEqual(gevent_result[0][3], 'readthedocs.io') - real_result = socket.getaddrinfo(*args) - - self.NORMALIZE_GAI_IGNORE_CANONICAL_NAME = not all(r[3] for r in real_result) - try: - self.assertEqualResults(real_result, gevent_result, 'getaddrinfo') - finally: - del self.NORMALIZE_GAI_IGNORE_CANONICAL_NAME - -add(TestGeventOrg, TestGeventOrg.HOSTNAME) - - -class TestFamily(TestCase): - def test_inet(self): - self._test('getaddrinfo', TestGeventOrg.HOSTNAME, None, socket.AF_INET) - - def test_unspec(self): - self._test('getaddrinfo', TestGeventOrg.HOSTNAME, None, socket.AF_UNSPEC) - - def test_badvalue(self): - self._test('getaddrinfo', TestGeventOrg.HOSTNAME, None, 255) - self._test('getaddrinfo', TestGeventOrg.HOSTNAME, None, 255000) - self._test('getaddrinfo', TestGeventOrg.HOSTNAME, None, -1) - - @unittest.skipIf(RESOLVER_DNSPYTHON, "Raises the wrong errno") - def test_badtype(self): - self._test('getaddrinfo', TestGeventOrg.HOSTNAME, 'x') - - -class Test_getaddrinfo(TestCase): - - def _test_getaddrinfo(self, *args): - self._test('getaddrinfo', *args) - - def test_80(self): - self._test_getaddrinfo(TestGeventOrg.HOSTNAME, 80) - - def test_int_string(self): - self._test_getaddrinfo(TestGeventOrg.HOSTNAME, '80') - - def test_0(self): - self._test_getaddrinfo(TestGeventOrg.HOSTNAME, 0) - - def test_http(self): - self._test_getaddrinfo(TestGeventOrg.HOSTNAME, 'http') - - def test_notexistent_tld(self): - self._test_getaddrinfo('myhost.mytld', 53) - - def test_notexistent_dot_com(self): - self._test_getaddrinfo('sdfsdfgu5e66098032453245wfdggd.com', 80) - - def test1(self): - return self._test_getaddrinfo(TestGeventOrg.HOSTNAME, 52, socket.AF_UNSPEC, socket.SOCK_STREAM, 0, 0) - - def test2(self): - return self._test_getaddrinfo(TestGeventOrg.HOSTNAME, 53, socket.AF_INET, socket.SOCK_DGRAM, 17) - - @unittest.skipIf(RESOLVER_DNSPYTHON, - "dnspython only returns some of the possibilities") - def test3(self): - return self._test_getaddrinfo('google.com', 'http', socket.AF_INET6) - - - def test_enums(self): - # https://github.com/gevent/gevent/issues/1310 - - # On Python 3, getaddrinfo does special things to make sure that - # the fancy enums are returned. - - gai = gevent_socket.getaddrinfo('example.com', 80, - socket.AF_INET, - socket.SOCK_STREAM, socket.IPPROTO_TCP) - af, socktype, _proto, _canonname, _sa = gai[0] - self.assertIs(socktype, socket.SOCK_STREAM) - self.assertIs(af, socket.AF_INET) - -class TestInternational(TestCase): - pass - - -# dns python can actually resolve these: it uses -# the 2008 version of idna encoding, whereas on Python 2, -# with the default resolver, it tries to encode to ascii and -# raises a UnicodeEncodeError. So we get different results. - -# Starting 20221027, on GitHub Actions and *some* versions of Python, -# we started getting a different error result from our own resolver -# compared to the system. This is very weird because our own resolver -# calls the system. I can't reproduce locally. Perhaps the two -# different answers are because of caching? One from the real DNS -# server, one from the local resolver library? Hence -# require_equal_errors=False -# ('system:', "herror(2, 'Host name lookup failure')", -# 'gevent:', "herror(1, 'Unknown host')") -add(TestInternational, u'президент.рф', 'russian', - require_equal_errors=False) -add(TestInternational, u'президент.рф'.encode('idna'), 'idna', - require_equal_errors=False) - -@skipWithoutExternalNetwork("Tries to resolve and compare hostnames/addrinfo") -class TestInterrupted_gethostbyname(gevent.testing.timing.AbstractGenericWaitTestCase): - - # There are refs to a Waiter in the C code that don't go - # away yet; one gc may or may not do it. - @greentest.ignores_leakcheck - def test_returns_none_after_timeout(self): - super(TestInterrupted_gethostbyname, self).test_returns_none_after_timeout() - - def wait(self, timeout): - with gevent.Timeout(timeout, False): - for index in range(1000000): - try: - gevent_socket.gethostbyname('www.x%s.com' % index) - except socket.error: - pass - raise AssertionError('Timeout was not raised') - - def cleanup(self): - # Depending on timing, this can raise: - # (This suddenly started happening on Apr 6 2016; www.x1000000.com - # is apparently no longer around) - - # File "test__socket_dns.py", line 538, in cleanup - # gevent.get_hub().threadpool.join() - # File "/home/travis/build/gevent/gevent/src/gevent/threadpool.py", line 108, in join - # sleep(delay) - # File "/home/travis/build/gevent/gevent/src/gevent/hub.py", line 169, in sleep - # hub.wait(loop.timer(seconds, ref=ref)) - # File "/home/travis/build/gevent/gevent/src/gevent/hub.py", line 651, in wait - # result = waiter.get() - # File "/home/travis/build/gevent/gevent/src/gevent/hub.py", line 899, in get - # return self.hub.switch() - # File "/home/travis/build/gevent/gevent/src/greentest/greentest.py", line 520, in switch - # return _original_Hub.switch(self, *args) - # File "/home/travis/build/gevent/gevent/src/gevent/hub.py", line 630, in switch - # return RawGreenlet.switch(self) - # gaierror: [Errno -2] Name or service not known - try: - gevent.get_hub().threadpool.join() - except Exception: # pragma: no cover pylint:disable=broad-except - traceback.print_exc() - - -# class TestInterrupted_getaddrinfo(greentest.GenericWaitTestCase): -# -# def wait(self, timeout): -# with gevent.Timeout(timeout, False): -# for index in range(1000): -# try: -# gevent_socket.getaddrinfo('www.a%s.com' % index, 'http') -# except socket.gaierror: -# pass - - -class TestBadName(TestCase): - pass - -add(TestBadName, 'xxxxxxxxxxxx') - -class TestBadIP(TestCase): - pass - -add(TestBadIP, '1.2.3.400') - - -@greentest.skipIf(greentest.RUNNING_ON_TRAVIS, "Travis began returning ip6-localhost") -class Test_getnameinfo_127001(TestCase): - - def test(self): - self._test('getnameinfo', ('127.0.0.1', 80), 0) - - def test_DGRAM(self): - self._test('getnameinfo', ('127.0.0.1', 779), 0) - self._test('getnameinfo', ('127.0.0.1', 779), socket.NI_DGRAM) - - def test_NOFQDN(self): - # I get ('localhost', 'www') with _socket but ('localhost.localdomain', 'www') with gevent.socket - self._test('getnameinfo', ('127.0.0.1', 80), socket.NI_NOFQDN) - - def test_NAMEREQD(self): - self._test('getnameinfo', ('127.0.0.1', 80), socket.NI_NAMEREQD) - - -class Test_getnameinfo_geventorg(TestCase): - - @unittest.skipIf(RESOLVER_DNSPYTHON, - "dnspython raises an error when multiple results are returned") - def test_NUMERICHOST(self): - self._test('getnameinfo', (TestGeventOrg.HOSTNAME, 80), 0) - self._test('getnameinfo', (TestGeventOrg.HOSTNAME, 80), socket.NI_NUMERICHOST) - - @unittest.skipIf(RESOLVER_DNSPYTHON, - "dnspython raises an error when multiple results are returned") - def test_NUMERICSERV(self): - self._test('getnameinfo', (TestGeventOrg.HOSTNAME, 80), socket.NI_NUMERICSERV) - - def test_domain1(self): - self._test('getnameinfo', (TestGeventOrg.HOSTNAME, 80), 0) - - def test_domain2(self): - self._test('getnameinfo', ('www.gevent.org', 80), 0) - - def test_port_zero(self): - self._test('getnameinfo', ('www.gevent.org', 0), 0) - - -class Test_getnameinfo_fail(TestCase): - - def test_port_string(self): - self._test('getnameinfo', ('www.gevent.org', 'http'), 0) - - def test_bad_flags(self): - self._test('getnameinfo', ('localhost', 80), 55555555) - - -class TestInvalidPort(TestCase): - - @flaky.reraises_flaky_race_condition() - def test_overflow_neg_one(self): - # An Appveyor beginning 2019-03-21, the system resolver - # sometimes returns ('23.100.69.251', '65535') instead of - # raising an error. That IP address belongs to - # readthedocs[.io?] which is where www.gevent.org is a CNAME - # to...but it doesn't actually *reverse* to readthedocs.io. - # Can't reproduce locally, not sure what's happening - self._test('getnameinfo', ('www.gevent.org', -1), 0) - - # Beginning with PyPy 2.7 7.1 on Appveyor, we sometimes see this - # return an OverflowError instead of the TypeError about None - @greentest.skipOnLibuvOnPyPyOnWin("Errors dont match") - def test_typeerror_none(self): - self._test('getnameinfo', ('www.gevent.org', None), 0) - - # Beginning with PyPy 2.7 7.1 on Appveyor, we sometimes see this - # return an TypeError instead of the OverflowError. - # XXX: But see Test_getnameinfo_fail.test_port_string where this does work. - @greentest.skipOnLibuvOnPyPyOnWin("Errors don't match") - def test_typeerror_str(self): - self._test('getnameinfo', ('www.gevent.org', 'x'), 0) - - def test_overflow_port_too_large(self): - self._test('getnameinfo', ('www.gevent.org', 65536), 0) - - -if __name__ == '__main__': - greentest.main() diff --git a/venv/lib/python3.9/site-packages/gevent/tests/test__socket_dns6.py b/venv/lib/python3.9/site-packages/gevent/tests/test__socket_dns6.py deleted file mode 100644 index 7c3c0f5..0000000 --- a/venv/lib/python3.9/site-packages/gevent/tests/test__socket_dns6.py +++ /dev/null @@ -1,101 +0,0 @@ -#!/usr/bin/python -# -*- coding: utf-8 -*- -from __future__ import print_function, absolute_import, division - -import socket -import unittest - -import gevent.testing as greentest -from gevent.tests.test__socket_dns import TestCase, add - -from gevent.testing.sysinfo import OSX -from gevent.testing.sysinfo import RESOLVER_DNSPYTHON -from gevent.testing.sysinfo import PYPY - - -# We can't control the DNS servers on CI (or in general...) -# for the system. This works best with the google DNS servers -# The getnameinfo test can fail on CI. - -# Previously only Test6_ds failed, but as of Jan 2018, Test6 -# and Test6_google begin to fail: - -# First differing element 0: -# 'vm2.test-ipv6.com' -# 'ip119.gigo.com' - -# - ('vm2.test-ipv6.com', [], ['2001:470:1:18::125']) -# ? --------- ^^ ^^ - -# + ('ip119.gigo.com', [], ['2001:470:1:18::119']) -# ? ^^^^^^^^ ^^ - -# These are known to work on jamadden's OS X machine using the google -# resolvers (but not with DNSPython; things don't *quite* match)...so -# by default we skip the tests everywhere else. - -class Test6(TestCase): - NORMALIZE_GHBA_IGNORE_ALIAS = True - # host that only has AAAA record - host = 'aaaa.test-ipv6.com' - - def _normalize_result_gethostbyaddr(self, result): - # This part of the test is effectively disabled. There are multiple address - # that resolve and which ones you get depend on the settings - # of the system and ares. They don't match exactly. - return () - - if not OSX and RESOLVER_DNSPYTHON: - # It raises gaierror instead of socket.error, - # which is not great and leads to failures. - def _run_test_getnameinfo(self, *_args, **_kwargs): - return (), 0, (), 0 - - def _run_test_gethostbyname(self, *_args, **_kwargs): - raise unittest.SkipTest("gethostbyname[_ex] does not support IPV6") - - _run_test_gethostbyname_ex = _run_test_gethostbyname - - def test_empty(self): - self._test('getaddrinfo', self.host, 'http') - - def test_inet(self): - self._test('getaddrinfo', self.host, None, socket.AF_INET) - - def test_inet6(self): - self._test('getaddrinfo', self.host, None, socket.AF_INET6) - - def test_unspec(self): - self._test('getaddrinfo', self.host, None, socket.AF_UNSPEC) - - -class Test6_google(Test6): - host = 'ipv6.google.com' - - if greentest.RUNNING_ON_CI: - # Disabled, there are multiple possibilities - # and we can get different ones. Even the system resolvers - # can go round-robin and provide different answers. - def _normalize_result_getnameinfo(self, result): - return () - - if PYPY: - # PyPy tends to be especially problematic in that area. - _normalize_result_getaddrinfo = _normalize_result_getnameinfo - -add(Test6, Test6.host) -add(Test6_google, Test6_google.host) - - - -class Test6_ds(Test6): - # host that has both A and AAAA records - host = 'ds.test-ipv6.com' - - _normalize_result_gethostbyname = Test6._normalize_result_gethostbyaddr - -add(Test6_ds, Test6_ds.host) - - -if __name__ == '__main__': - greentest.main() diff --git a/venv/lib/python3.9/site-packages/gevent/tests/test__socket_errors.py b/venv/lib/python3.9/site-packages/gevent/tests/test__socket_errors.py deleted file mode 100644 index 1b9b30c..0000000 --- a/venv/lib/python3.9/site-packages/gevent/tests/test__socket_errors.py +++ /dev/null @@ -1,48 +0,0 @@ -# Copyright (c) 2008-2009 AG Projects -# Author: Denis Bilenko -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. - -import gevent.testing as greentest -from gevent.testing import support -from gevent.testing import sysinfo - -from gevent.socket import socket, error -from gevent.exceptions import LoopExit - - -class TestSocketErrors(greentest.TestCase): - - __timeout__ = 5 - - def test_connection_refused(self): - port = support.find_unused_port() - with socket() as s: - try: - with self.assertRaises(error) as exc: - s.connect((greentest.DEFAULT_CONNECT_HOST, port)) - except LoopExit: - return - ex = exc.exception - self.assertIn(ex.args[0], sysinfo.CONN_REFUSED_ERRORS, ex) - self.assertIn('refused', str(ex).lower()) - - -if __name__ == '__main__': - greentest.main() diff --git a/venv/lib/python3.9/site-packages/gevent/tests/test__socket_ex.py b/venv/lib/python3.9/site-packages/gevent/tests/test__socket_ex.py deleted file mode 100644 index 8ce77a9..0000000 --- a/venv/lib/python3.9/site-packages/gevent/tests/test__socket_ex.py +++ /dev/null @@ -1,44 +0,0 @@ -import gevent.testing as greentest -from gevent import socket -import errno -import sys - - -class TestClosedSocket(greentest.TestCase): - - switch_expected = False - - def test(self): - sock = socket.socket() - sock.close() - try: - sock.send(b'a', timeout=1) - self.fail("Should raise socket error") - except OSError as ex: - if ex.args[0] != errno.EBADF: - if sys.platform.startswith('win'): - # Windows/Py3 raises "OSError: [WinError 10038] " - # which is not standard and not what it does - # on Py2. - pass - else: - raise - - -class TestRef(greentest.TestCase): - - switch_expected = False - - def test(self): - # pylint:disable=no-member - sock = socket.socket() - self.assertTrue(sock.ref) - sock.ref = False - self.assertFalse(sock.ref) - self.assertFalse(sock._read_event.ref) - self.assertFalse(sock._write_event.ref) - sock.close() - - -if __name__ == '__main__': - greentest.main() diff --git a/venv/lib/python3.9/site-packages/gevent/tests/test__socket_send_memoryview.py b/venv/lib/python3.9/site-packages/gevent/tests/test__socket_send_memoryview.py deleted file mode 100644 index 5c5036c..0000000 --- a/venv/lib/python3.9/site-packages/gevent/tests/test__socket_send_memoryview.py +++ /dev/null @@ -1,40 +0,0 @@ -# See issue #466 -import unittest -import ctypes - -import gevent.testing as greentest - -class AnStructure(ctypes.Structure): - _fields_ = [("x", ctypes.c_int)] - - -def _send(socket): - for meth in ('sendall', 'send'): - anStructure = AnStructure() - sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) - sock.connect((greentest.DEFAULT_CONNECT_HOST, 12345)) - getattr(sock, meth)(anStructure) - sock.close() - - sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) - sock.connect((greentest.DEFAULT_CONNECT_HOST, 12345)) - sock.settimeout(1.0) - getattr(sock, meth)(anStructure) - sock.close() - -class TestSendBuiltinSocket(unittest.TestCase): - - def test_send(self): - import socket - _send(socket) - - -class TestSendGeventSocket(unittest.TestCase): - - def test_send(self): - import gevent.socket - _send(gevent.socket) - - -if __name__ == '__main__': - greentest.main() diff --git a/venv/lib/python3.9/site-packages/gevent/tests/test__socket_ssl.py b/venv/lib/python3.9/site-packages/gevent/tests/test__socket_ssl.py deleted file mode 100644 index 07ec936..0000000 --- a/venv/lib/python3.9/site-packages/gevent/tests/test__socket_ssl.py +++ /dev/null @@ -1,39 +0,0 @@ -#!/usr/bin/python -from gevent import monkey -monkey.patch_all() - - -try: - import httplib -except ImportError: - from http import client as httplib -import socket - - -import gevent.testing as greentest - - -@greentest.skipUnless( - hasattr(socket, 'ssl'), - "Needs socket.ssl (Python 2)" -) -@greentest.skipWithoutExternalNetwork("Tries to access amazon.com") -class AmazonHTTPSTests(greentest.TestCase): - - __timeout__ = 30 - - def test_amazon_response(self): - conn = httplib.HTTPSConnection('sdb.amazonaws.com') - conn.request('GET', '/') - conn.getresponse() - - def test_str_and_repr(self): - conn = socket.socket() - conn.connect(('sdb.amazonaws.com', 443)) - ssl_conn = socket.ssl(conn) # pylint:disable=no-member - assert str(ssl_conn) - assert repr(ssl_conn) - - -if __name__ == "__main__": - greentest.main() diff --git a/venv/lib/python3.9/site-packages/gevent/tests/test__socket_timeout.py b/venv/lib/python3.9/site-packages/gevent/tests/test__socket_timeout.py deleted file mode 100644 index b7d4d8f..0000000 --- a/venv/lib/python3.9/site-packages/gevent/tests/test__socket_timeout.py +++ /dev/null @@ -1,51 +0,0 @@ -import gevent -from gevent import socket -import gevent.testing as greentest - - -class Test(greentest.TestCase): - - server = None - acceptor = None - server_port = None - - def _accept(self): - try: - conn, _ = self.server.accept() - self._close_on_teardown(conn) - except socket.error: - pass - - def setUp(self): - super(Test, self).setUp() - self.server = self._close_on_teardown(greentest.tcp_listener(backlog=1)) - self.server_port = self.server.getsockname()[1] - self.acceptor = gevent.spawn(self._accept) - gevent.sleep(0) - - def tearDown(self): - if self.acceptor is not None: - self.acceptor.kill() - self.acceptor = None - if self.server is not None: - self.server.close() - self.server = None - super(Test, self).tearDown() - - def test_timeout(self): - gevent.sleep(0) - sock = socket.socket() - self._close_on_teardown(sock) - sock.connect((greentest.DEFAULT_CONNECT_HOST, self.server_port)) - - sock.settimeout(0.1) - with self.assertRaises(socket.error) as cm: - sock.recv(1024) - - ex = cm.exception - self.assertEqual(ex.args, ('timed out',)) - self.assertEqual(str(ex), 'timed out') - - -if __name__ == '__main__': - greentest.main() diff --git a/venv/lib/python3.9/site-packages/gevent/tests/test__socketpair.py b/venv/lib/python3.9/site-packages/gevent/tests/test__socketpair.py deleted file mode 100644 index f17ad9f..0000000 --- a/venv/lib/python3.9/site-packages/gevent/tests/test__socketpair.py +++ /dev/null @@ -1,37 +0,0 @@ -from gevent import monkey; monkey.patch_all() -import socket -import unittest - - -class TestSocketpair(unittest.TestCase): - - def test_makefile(self): - msg = b'hello world' - x, y = socket.socketpair() - x.sendall(msg) - x.close() - with y.makefile('rb') as f: - read = f.read() - self.assertEqual(msg, read) - y.close() - - @unittest.skipUnless(hasattr(socket, 'fromfd'), - 'Needs socket.fromfd') - def test_fromfd(self): - msg = b'hello world' - x, y = socket.socketpair() - xx = socket.fromfd(x.fileno(), x.family, socket.SOCK_STREAM) - x.close() - yy = socket.fromfd(y.fileno(), y.family, socket.SOCK_STREAM) - y.close() - - xx.sendall(msg) - xx.close() - with yy.makefile('rb') as f: - read = f.read() - self.assertEqual(msg, read) - yy.close() - - -if __name__ == '__main__': - unittest.main() diff --git a/venv/lib/python3.9/site-packages/gevent/tests/test__ssl.py b/venv/lib/python3.9/site-packages/gevent/tests/test__ssl.py deleted file mode 100644 index ed09548..0000000 --- a/venv/lib/python3.9/site-packages/gevent/tests/test__ssl.py +++ /dev/null @@ -1,140 +0,0 @@ -from __future__ import print_function, division, absolute_import -from gevent import monkey -monkey.patch_all() -import os - -import socket -import gevent.testing as greentest -# Be careful not to have TestTCP as a bare attribute in this module, -# even aliased, to avoid running duplicate tests -from gevent.tests import test__socket -import ssl - - -def ssl_listener(private_key, certificate): - raw_listener = socket.socket() - greentest.bind_and_listen(raw_listener) - # pylint:disable=deprecated-method - sock = wrap_socket(raw_listener, keyfile=private_key, certfile=certificate, - server_side=True) - return sock, raw_listener - -def wrap_socket(sock, *, keyfile=None, certfile=None, server_side=False): - context = ssl.SSLContext( - protocol=(ssl.PROTOCOL_TLS_SERVER - if server_side - else ssl.PROTOCOL_TLS_CLIENT) - ) - context.check_hostname = False - context.verify_mode = ssl.CERT_NONE - context.load_default_certs() - if keyfile is not None or certfile is not None: - context.load_cert_chain(certfile=certfile, keyfile=keyfile) - return context.wrap_socket(sock, server_side=server_side) - -class TestSSL(test__socket.TestTCP): - - # To generate: - # openssl req -x509 -newkey rsa:4096 -keyout test_server.key -out test_server.crt -days 36500 -nodes -subj '/CN=localhost' - certfile = os.path.join(os.path.dirname(__file__), 'test_server.crt') - privfile = os.path.join(os.path.dirname(__file__), 'test_server.key') - # Python 2.x has socket.sslerror (which is an alias for - # ssl.SSLError); That's gone in Py3 though. In Python 2, most timeouts are raised - # as SSLError, but Python 3 raises the normal socket.timeout instead. So this has - # the effect of making TIMEOUT_ERROR be SSLError on Py2 and socket.timeout on Py3 - # See https://bugs.python.org/issue10272. - # PyPy3 7.2 has a bug, though: it shares much of the SSL implementation with Python 2, - # and it unconditionally does `socket.sslerror = SSLError` when ssl is imported. - # So we can't rely on getattr/hasattr tests, we must be explicit. - TIMEOUT_ERROR = socket.timeout # pylint:disable=no-member - - def _setup_listener(self): - listener, raw_listener = ssl_listener(self.privfile, self.certfile) - self._close_on_teardown(raw_listener) - return listener - - def create_connection(self, *args, **kwargs): # pylint:disable=signature-differs - return self._close_on_teardown( - # pylint:disable=deprecated-method - wrap_socket(super(TestSSL, self).create_connection(*args, **kwargs))) - - # The SSL library can take a long time to buffer the large amount of data we're trying - # to send, so we can't compare to the timeout values - _test_sendall_timeout_check_time = False - - # The SSL layer has extra buffering, so test_sendall needs - # to send a very large amount to make it timeout - _test_sendall_data = data_sent = b'hello' * 100000000 - - test_sendall_array = greentest.skipOnMacOnCI("Sometimes misses data")( - greentest.skipOnManylinux("Sometimes misses data")( - test__socket.TestTCP.test_sendall_array - ) - ) - - test_sendall_str = greentest.skipOnMacOnCI("Sometimes misses data")( - greentest.skipOnManylinux("Sometimes misses data")( - test__socket.TestTCP.test_sendall_str - ) - ) - - @greentest.skipOnWindows("Not clear why we're skipping") - def test_ssl_sendall_timeout0(self): - # Issue #317: SSL_WRITE_PENDING in some corner cases - - server_sock = [] - acceptor = test__socket.Thread(target=lambda: server_sock.append( - # pylint:disable=no-member - self.listener.accept())) - client = self.create_connection() - client.setblocking(False) - try: - # Python 3 raises ssl.SSLWantWriteError; Python 2 simply *hangs* - # on non-blocking sockets because it's a simple loop around - # send(). Python 2.6 doesn't have SSLWantWriteError - expected = getattr(ssl, 'SSLWantWriteError', ssl.SSLError) - with self.assertRaises(expected): - client.sendall(self._test_sendall_data) - finally: - acceptor.join() - client.close() - server_sock[0][0].close() - - # def test_fullduplex(self): - # try: - # super(TestSSL, self).test_fullduplex() - # except LoopExit: - # if greentest.LIBUV and greentest.WIN: - # # XXX: Unable to duplicate locally - # raise greentest.SkipTest("libuv on Windows sometimes raises LoopExit") - # raise - - @greentest.ignores_leakcheck - @greentest.skipOnPy310("No longer raises SSLError") - def test_empty_send(self): - # Issue 719 - # Sending empty bytes with the 'send' method raises - # ssl.SSLEOFError in the stdlib. PyPy 4.0 and CPython 2.6 - # both just raise the superclass, ssl.SSLError. - - # Ignored during leakchecks because the third or fourth iteration of the - # test hangs on CPython 2/posix for some reason, likely due to - # the use of _close_on_teardown keeping something alive longer than intended. - # cf test__makefile_ref - with self.assertRaises(ssl.SSLError): - super(TestSSL, self).test_empty_send() - - @greentest.ignores_leakcheck - def test_sendall_nonblocking(self): - # Override; doesn't work with SSL sockets. - pass - - @greentest.ignores_leakcheck - def test_connect_with_type_flags_ignored(self): - # Override; doesn't work with SSL sockets. - pass - - - -if __name__ == '__main__': - greentest.main() diff --git a/venv/lib/python3.9/site-packages/gevent/tests/test__subprocess.py b/venv/lib/python3.9/site-packages/gevent/tests/test__subprocess.py deleted file mode 100644 index d3b2d84..0000000 --- a/venv/lib/python3.9/site-packages/gevent/tests/test__subprocess.py +++ /dev/null @@ -1,517 +0,0 @@ -import sys -import os -import errno -import unittest - -import time -import tempfile - -import gevent.testing as greentest -import gevent -from gevent.testing import mock -from gevent import subprocess - -if not hasattr(subprocess, 'mswindows'): - # PyPy3, native python subprocess - subprocess.mswindows = False - - -PYPY = hasattr(sys, 'pypy_version_info') -PY3 = sys.version_info[0] >= 3 - - -if subprocess.mswindows: - SETBINARY = 'import msvcrt; msvcrt.setmode(sys.stdout.fileno(), os.O_BINARY);' -else: - SETBINARY = '' - - -python_universal_newlines = hasattr(sys.stdout, 'newlines') -# The stdlib of Python 3 on Windows doesn't properly handle universal newlines -# (it produces broken results compared to Python 2) -# See gevent.subprocess for more details. -python_universal_newlines_broken = PY3 and subprocess.mswindows - -@greentest.skipWithoutResource('subprocess') -class TestPopen(greentest.TestCase): - - # Use the normal error handling. Make sure that any background greenlets - # subprocess spawns propagate errors as expected. - error_fatal = False - - def test_exit(self): - popen = subprocess.Popen([sys.executable, '-c', 'import sys; sys.exit(10)']) - self.assertEqual(popen.wait(), 10) - - def test_wait(self): - popen = subprocess.Popen([sys.executable, '-c', 'import sys; sys.exit(11)']) - gevent.wait([popen]) - self.assertEqual(popen.poll(), 11) - - def test_child_exception(self): - with self.assertRaises(OSError) as exc: - subprocess.Popen(['*']).wait() - - self.assertEqual(exc.exception.errno, 2) - - def test_leak(self): - num_before = greentest.get_number_open_files() - p = subprocess.Popen([sys.executable, "-c", "print()"], - stdout=subprocess.PIPE) - p.wait() - p.stdout.close() - del p - - num_after = greentest.get_number_open_files() - self.assertEqual(num_before, num_after) - - @greentest.skipOnLibuvOnPyPyOnWin("hangs") - def test_communicate(self): - p = subprocess.Popen([sys.executable, "-W", "ignore", - "-c", - 'import sys,os;' - 'sys.stderr.write("pineapple");' - 'sys.stdout.write(sys.stdin.read())'], - stdin=subprocess.PIPE, - stdout=subprocess.PIPE, - stderr=subprocess.PIPE) - (stdout, stderr) = p.communicate(b"banana") - self.assertEqual(stdout, b"banana") - if sys.executable.endswith('-dbg'): - assert stderr.startswith(b'pineapple') - else: - self.assertEqual(stderr, b"pineapple") - - @greentest.skipIf(subprocess.mswindows, - "Windows does weird things here") - @greentest.skipOnLibuvOnCIOnPyPy("Sometimes segfaults") - def test_communicate_universal(self): - # Native string all the things. See https://github.com/gevent/gevent/issues/1039 - p = subprocess.Popen( - [ - sys.executable, - "-W", "ignore", - "-c", - 'import sys,os;' - 'sys.stderr.write("pineapple\\r\\n\\xff\\xff\\xf2\\xf9\\r\\n");' - 'sys.stdout.write(sys.stdin.read())' - ], - stdin=subprocess.PIPE, - stdout=subprocess.PIPE, - stderr=subprocess.PIPE, - universal_newlines=True - ) - (stdout, stderr) = p.communicate('banana\r\n\xff\xff\xf2\xf9\r\n') - self.assertIsInstance(stdout, str) - self.assertIsInstance(stderr, str) - self.assertEqual(stdout, - 'banana\n\xff\xff\xf2\xf9\n') - - self.assertEqual(stderr, - 'pineapple\n\xff\xff\xf2\xf9\n') - - @greentest.skipOnWindows("Windows IO is weird; this doesn't raise") - def test_communicate_undecodable(self): - # If the subprocess writes non-decodable data, `communicate` raises the - # same UnicodeDecodeError that the stdlib does, instead of - # printing it to the hub. This only applies to Python 3, because only it - # will actually use text mode. - # See https://github.com/gevent/gevent/issues/1510 - with subprocess.Popen( - [ - sys.executable, - '-W', 'ignore', - '-c', - "import os, sys; " - r'os.write(sys.stdout.fileno(), b"\xff")' - ], - stdin=subprocess.PIPE, stdout=subprocess.PIPE, - stderr=subprocess.PIPE, - text=True, universal_newlines=True - ) as p: - with self.assertRaises(UnicodeDecodeError): - p.communicate() - - @greentest.skipOnLibuvOnPyPyOnWin("hangs") - def test_universal1(self): - with subprocess.Popen( - [ - sys.executable, "-c", - 'import sys,os;' + SETBINARY + - 'sys.stdout.write("line1\\n");' - 'sys.stdout.flush();' - 'sys.stdout.write("line2\\r");' - 'sys.stdout.flush();' - 'sys.stdout.write("line3\\r\\n");' - 'sys.stdout.flush();' - 'sys.stdout.write("line4\\r");' - 'sys.stdout.flush();' - 'sys.stdout.write("\\nline5");' - 'sys.stdout.flush();' - 'sys.stdout.write("\\nline6");' - ], - stdout=subprocess.PIPE, - universal_newlines=1, - bufsize=1 - ) as p: - stdout = p.stdout.read() - if python_universal_newlines: - # Interpreter with universal newline support - if not python_universal_newlines_broken: - self.assertEqual(stdout, - "line1\nline2\nline3\nline4\nline5\nline6") - else: - # Note the extra newline after line 3 - self.assertEqual(stdout, - 'line1\nline2\nline3\n\nline4\n\nline5\nline6') - else: - # Interpreter without universal newline support - self.assertEqual(stdout, - "line1\nline2\rline3\r\nline4\r\nline5\nline6") - - @greentest.skipOnLibuvOnPyPyOnWin("hangs") - def test_universal2(self): - with subprocess.Popen( - [ - sys.executable, "-c", - 'import sys,os;' + SETBINARY + - 'sys.stdout.write("line1\\n");' - 'sys.stdout.flush();' - 'sys.stdout.write("line2\\r");' - 'sys.stdout.flush();' - 'sys.stdout.write("line3\\r\\n");' - 'sys.stdout.flush();' - 'sys.stdout.write("line4\\r\\nline5");' - 'sys.stdout.flush();' - 'sys.stdout.write("\\nline6");' - ], - stdout=subprocess.PIPE, - universal_newlines=1, - bufsize=1 - ) as p: - stdout = p.stdout.read() - if python_universal_newlines: - # Interpreter with universal newline support - if not python_universal_newlines_broken: - self.assertEqual(stdout, - "line1\nline2\nline3\nline4\nline5\nline6") - else: - # Note the extra newline after line 3 - self.assertEqual(stdout, - 'line1\nline2\nline3\n\nline4\n\nline5\nline6') - else: - # Interpreter without universal newline support - self.assertEqual(stdout, - "line1\nline2\rline3\r\nline4\r\nline5\nline6") - - @greentest.skipOnWindows("Uses 'grep' command") - def test_nonblock_removed(self): - # see issue #134 - r, w = os.pipe() - stdin = subprocess.FileObject(r) - with subprocess.Popen(['grep', 'text'], stdin=stdin) as p: - try: - # Closing one half of the pipe causes Python 3 on OS X to terminate the - # child process; it exits with code 1 and the assert that p.poll is None - # fails. Removing the close lets it pass under both Python 3 and 2.7. - # If subprocess.Popen._remove_nonblock_flag is changed to a noop, then - # the test fails (as expected) even with the close removed - #os.close(w) - time.sleep(0.1) - self.assertEqual(p.poll(), None) - finally: - if p.poll() is None: - p.kill() - stdin.close() - os.close(w) - - def test_issue148(self): - for _ in range(7): - with self.assertRaises(OSError) as exc: - with subprocess.Popen('this_name_must_not_exist'): - pass - - self.assertEqual(exc.exception.errno, errno.ENOENT) - - @greentest.skipOnLibuvOnPyPyOnWin("hangs") - def test_check_output_keyword_error(self): - with self.assertRaises(subprocess.CalledProcessError) as exc: # pylint:disable=no-member - subprocess.check_output([sys.executable, '-c', 'import sys; sys.exit(44)']) - - self.assertEqual(exc.exception.returncode, 44) - - @greentest.skipOnPy3("The default buffer changed in Py3") - def test_popen_bufsize(self): - # Test that subprocess has unbuffered output by default - # (as the vanilla subprocess module) - with subprocess.Popen( - [sys.executable, '-u', '-c', - 'import sys; sys.stdout.write(sys.stdin.readline())'], - stdin=subprocess.PIPE, stdout=subprocess.PIPE - ) as p: - p.stdin.write(b'foobar\n') - r = p.stdout.readline() - self.assertEqual(r, b'foobar\n') - - @greentest.ignores_leakcheck - @greentest.skipOnWindows("Not sure why?") - def test_subprocess_in_native_thread(self): - # gevent.subprocess doesn't work from a background - # native thread. See #688 - from gevent import monkey - - # must be a native thread; defend against monkey-patching - ex = [] - Thread = monkey.get_original('threading', 'Thread') - - def fn(): - with self.assertRaises(TypeError) as exc: - gevent.subprocess.Popen('echo 123', shell=True) - ex.append(exc.exception) - - thread = Thread(target=fn) - thread.start() - thread.join() - - self.assertEqual(len(ex), 1) - self.assertTrue(isinstance(ex[0], TypeError), ex) - self.assertEqual(ex[0].args[0], 'child watchers are only available on the default loop') - - - @greentest.skipOnLibuvOnPyPyOnWin("hangs") - def __test_no_output(self, kwargs, kind): - with subprocess.Popen( - [sys.executable, '-c', 'pass'], - stdout=subprocess.PIPE, - **kwargs - ) as proc: - stdout, stderr = proc.communicate() - - self.assertIsInstance(stdout, kind) - self.assertIsNone(stderr) - - @greentest.skipOnLibuvOnCIOnPyPy("Sometimes segfaults; " - "https://travis-ci.org/gevent/gevent/jobs/327357682") - def test_universal_newlines_text_mode_no_output_is_always_str(self): - # If the file is in universal_newlines mode, we should always get a str when - # there is no output. - # https://github.com/gevent/gevent/pull/939 - self.__test_no_output({'universal_newlines': True}, str) - - @greentest.skipIf(sys.version_info[:2] < (3, 6), "Need encoding argument") - def test_encoded_text_mode_no_output_is_str(self): - # If the file is in universal_newlines mode, we should always get a str when - # there is no output. - # https://github.com/gevent/gevent/pull/939 - self.__test_no_output({'encoding': 'utf-8'}, str) - - def test_default_mode_no_output_is_always_str(self): - # If the file is in default mode, we should always get a str when - # there is no output. - # https://github.com/gevent/gevent/pull/939 - self.__test_no_output({}, bytes) - -@greentest.skipOnWindows("Testing POSIX fd closing") -class TestFDs(unittest.TestCase): - - @mock.patch('os.closerange') - @mock.patch('gevent.subprocess._set_inheritable') - @mock.patch('gevent.subprocess.os_close') - def test_close_fds_brute_force(self, close, set_inheritable, closerange): - keep = ( - 4, 5, - # Leave a hole - # 6, - 7, - ) - subprocess.Popen._close_fds_brute_force(keep, None) - - closerange.assert_has_calls([ - mock.call(3, 4), - mock.call(8, subprocess.MAXFD), - ]) - - set_inheritable.assert_has_calls([ - mock.call(4, True), - mock.call(5, True), - ]) - - close.assert_called_once_with(6) - - @mock.patch('gevent.subprocess.Popen._close_fds_brute_force') - @mock.patch('os.listdir') - def test_close_fds_from_path_bad_values(self, listdir, brute_force): - listdir.return_value = 'Not an Integer' - - subprocess.Popen._close_fds_from_path('path', [], 42) - brute_force.assert_called_once_with([], 42) - - @mock.patch('os.listdir') - @mock.patch('os.closerange') - @mock.patch('gevent.subprocess._set_inheritable') - @mock.patch('gevent.subprocess.os_close') - def test_close_fds_from_path(self, close, set_inheritable, closerange, listdir): - keep = ( - 4, 5, - # Leave a hole - # 6, - 7, - ) - listdir.return_value = ['1', '6', '37'] - - subprocess.Popen._close_fds_from_path('path', keep, 5) - - self.assertEqual([], closerange.mock_calls) - - set_inheritable.assert_has_calls([ - mock.call(4, True), - mock.call(7, True), - ]) - - close.assert_has_calls([ - mock.call(6), - mock.call(37), - ]) - - @mock.patch('gevent.subprocess.Popen._close_fds_brute_force') - @mock.patch('os.path.isdir') - def test_close_fds_no_dir(self, isdir, brute_force): - isdir.return_value = False - - subprocess.Popen._close_fds([], 42) - brute_force.assert_called_once_with([], 42) - isdir.assert_has_calls([ - mock.call('/proc/self/fd'), - mock.call('/dev/fd'), - ]) - - @mock.patch('gevent.subprocess.Popen._close_fds_from_path') - @mock.patch('gevent.subprocess.Popen._close_fds_brute_force') - @mock.patch('os.path.isdir') - def test_close_fds_with_dir(self, isdir, brute_force, from_path): - isdir.return_value = True - - subprocess.Popen._close_fds([7], 42) - - self.assertEqual([], brute_force.mock_calls) - from_path.assert_called_once_with('/proc/self/fd', [7], 42) - -class RunFuncTestCase(greentest.TestCase): - # Based on code from python 3.6+ - - __timeout__ = greentest.LARGE_TIMEOUT - - @greentest.skipWithoutResource('subprocess') - def run_python(self, code, **kwargs): - """Run Python code in a subprocess using subprocess.run""" - argv = [sys.executable, "-c", code] - return subprocess.run(argv, **kwargs) - - def test_returncode(self): - # call() function with sequence argument - cp = self.run_python("import sys; sys.exit(47)") - self.assertEqual(cp.returncode, 47) - with self.assertRaises(subprocess.CalledProcessError): # pylint:disable=no-member - cp.check_returncode() - - def test_check(self): - with self.assertRaises(subprocess.CalledProcessError) as c: # pylint:disable=no-member - self.run_python("import sys; sys.exit(47)", check=True) - self.assertEqual(c.exception.returncode, 47) - - def test_check_zero(self): - # check_returncode shouldn't raise when returncode is zero - cp = self.run_python("import sys; sys.exit(0)", check=True) - self.assertEqual(cp.returncode, 0) - - def test_timeout(self): - # run() function with timeout argument; we want to test that the child - # process gets killed when the timeout expires. If the child isn't - # killed, this call will deadlock since subprocess.run waits for the - # child. - with self.assertRaises(subprocess.TimeoutExpired): - self.run_python("while True: pass", timeout=0.0001) - - @greentest.skipOnLibuvOnPyPyOnWin("hangs") - def test_capture_stdout(self): - # capture stdout with zero return code - cp = self.run_python("print('BDFL')", stdout=subprocess.PIPE) - self.assertIn(b'BDFL', cp.stdout) - - @greentest.skipOnLibuvOnPyPyOnWin("hangs") - def test_capture_stderr(self): - cp = self.run_python("import sys; sys.stderr.write('BDFL')", - stderr=subprocess.PIPE) - self.assertIn(b'BDFL', cp.stderr) - - @greentest.skipOnLibuvOnPyPyOnWin("hangs") - def test_check_output_stdin_arg(self): - # run() can be called with stdin set to a file - with tempfile.TemporaryFile() as tf: - tf.write(b'pear') - tf.seek(0) - cp = self.run_python( - "import sys; sys.stdout.write(sys.stdin.read().upper())", - stdin=tf, stdout=subprocess.PIPE) - self.assertIn(b'PEAR', cp.stdout) - - @greentest.skipOnLibuvOnPyPyOnWin("hangs") - def test_check_output_input_arg(self): - # check_output() can be called with input set to a string - cp = self.run_python( - "import sys; sys.stdout.write(sys.stdin.read().upper())", - input=b'pear', stdout=subprocess.PIPE) - self.assertIn(b'PEAR', cp.stdout) - - @greentest.skipOnLibuvOnPyPyOnWin("hangs") - def test_check_output_stdin_with_input_arg(self): - # run() refuses to accept 'stdin' with 'input' - with tempfile.TemporaryFile() as tf: - tf.write(b'pear') - tf.seek(0) - with self.assertRaises(ValueError, - msg="Expected ValueError when stdin and input args supplied.") as c: - self.run_python("print('will not be run')", - stdin=tf, input=b'hare') - self.assertIn('stdin', c.exception.args[0]) - self.assertIn('input', c.exception.args[0]) - - @greentest.skipOnLibuvOnPyPyOnWin("hangs") - def test_check_output_timeout(self): - with self.assertRaises(subprocess.TimeoutExpired) as c: - self.run_python( - ( - "import sys, time\n" - "sys.stdout.write('BDFL')\n" - "sys.stdout.flush()\n" - "time.sleep(3600)" - ), - # Some heavily loaded buildbots (sparc Debian 3.x) require - # this much time to start and print. - timeout=3, stdout=subprocess.PIPE) - self.assertEqual(c.exception.output, b'BDFL') - # output is aliased to stdout - self.assertEqual(c.exception.stdout, b'BDFL') - - def test_run_kwargs(self): - newenv = os.environ.copy() - newenv["FRUIT"] = "banana" - cp = self.run_python(('import sys, os;' - 'sys.exit(33 if os.getenv("FRUIT")=="banana" else 31)'), - env=newenv) - self.assertEqual(cp.returncode, 33) - - # This test _might_ wind up a bit fragile on loaded build+test machines - # as it depends on the timing with wide enough margins for normal situations - # but does assert that it happened "soon enough" to believe the right thing - # happened. - @greentest.skipOnWindows("requires posix like 'sleep' shell command") - def test_run_with_shell_timeout_and_capture_output(self): - #Output capturing after a timeout mustn't hang forever on open filehandles - with self.runs_in_given_time(0.1): - with self.assertRaises(subprocess.TimeoutExpired): - subprocess.run('sleep 3', shell=True, timeout=0.1, - capture_output=True) # New session unspecified. - -if __name__ == '__main__': - greentest.main() diff --git a/venv/lib/python3.9/site-packages/gevent/tests/test__subprocess_interrupted.py b/venv/lib/python3.9/site-packages/gevent/tests/test__subprocess_interrupted.py deleted file mode 100644 index 9684222..0000000 --- a/venv/lib/python3.9/site-packages/gevent/tests/test__subprocess_interrupted.py +++ /dev/null @@ -1,42 +0,0 @@ -import sys - -if 'runtestcase' in sys.argv[1:]: # pragma: no cover - import gevent - import gevent.subprocess - gevent.spawn(sys.exit, 'bye') - # Look closely, this doesn't actually do anything, that's a string - # not a division - gevent.subprocess.Popen([sys.executable, '-c', '"1/0"']) - gevent.sleep(1) -else: - # XXX: Handle this more automatically. See comments in the testrunner. - from gevent.testing.resources import exit_without_resource - exit_without_resource('subprocess') - - import subprocess - for _ in range(5): - # not on Py2 pylint:disable=consider-using-with - out, err = subprocess.Popen([sys.executable, '-W', 'ignore', - __file__, 'runtestcase'], - stderr=subprocess.PIPE).communicate() - # We've seen a few unexpected forms of output. - # - # The first involves 'refs'; I don't remember what that was - # about, but I think it had to do with debug builds of Python. - # - # The second is the classic "Unhandled exception in thread - # started by \nsys.excepthook is missing\nlost sys.stderr". - # This is a race condition between closing sys.stderr and - # writing buffered data to a pipe that hasn't been read. We - # only see this using GEVENT_FILE=thread (which makes sense); - # likewise, on Python 2 with thread, we can sometimes get - # `super() argument 1 must be type, not None`; this happens on module - # cleanup. - # - # The third is similar to the second: "AssertionError: - # ...\nIOError: close() called during concurrent operation on - # the same file object.\n" - if b'refs' in err or b'sys.excepthook' in err or b'concurrent' in err: - assert err.startswith(b'bye'), repr(err) # pragma: no cover - else: - assert err.strip() == b'bye', repr(err) diff --git a/venv/lib/python3.9/site-packages/gevent/tests/test__subprocess_poll.py b/venv/lib/python3.9/site-packages/gevent/tests/test__subprocess_poll.py deleted file mode 100644 index 1a569d5..0000000 --- a/venv/lib/python3.9/site-packages/gevent/tests/test__subprocess_poll.py +++ /dev/null @@ -1,13 +0,0 @@ -import sys -# XXX: Handle this more automatically. See comments in the testrunner. -from gevent.testing.resources import exit_without_resource -exit_without_resource('subprocess') - -from gevent.subprocess import Popen -from gevent.testing.util import alarm - -alarm(3) - -popen = Popen([sys.executable, '-c', 'pass']) -while popen.poll() is None: - pass diff --git a/venv/lib/python3.9/site-packages/gevent/tests/test__systemerror.py b/venv/lib/python3.9/site-packages/gevent/tests/test__systemerror.py deleted file mode 100644 index 1fcc7e7..0000000 --- a/venv/lib/python3.9/site-packages/gevent/tests/test__systemerror.py +++ /dev/null @@ -1,110 +0,0 @@ -import sys -import gevent.testing as greentest -import gevent -from gevent.hub import get_hub - -def raise_(ex): - raise ex - - -MSG = 'should be re-raised and caught' - - -class Test(greentest.TestCase): - x = None - error_fatal = False - - def start(self, *args): - raise NotImplementedError - - def setUp(self): - self.x = None - - def test_sys_exit(self): - self.start(sys.exit, MSG) - - try: - gevent.sleep(0.001) - except SystemExit as ex: - assert str(ex) == MSG, repr(str(ex)) - else: - raise AssertionError('must raise SystemExit') - - def test_keyboard_interrupt(self): - self.start(raise_, KeyboardInterrupt) - - try: - gevent.sleep(0.001) - except KeyboardInterrupt: - pass - else: - raise AssertionError('must raise KeyboardInterrupt') - - def test_keyboard_interrupt_stderr_patched(self): - # XXX: This one non-top-level call prevents us from being - # run in a process with other tests. - from gevent import monkey - monkey.patch_sys(stdin=False, stdout=False, stderr=True) - try: - try: - self.start(raise_, KeyboardInterrupt) - while True: - gevent.sleep(0.1) - except KeyboardInterrupt: - pass # expected - finally: - sys.stderr = monkey.get_original('sys', 'stderr') - - def test_system_error(self): - self.start(raise_, SystemError(MSG)) - - with self.assertRaisesRegex(SystemError, - MSG): - gevent.sleep(0.002) - - def test_exception(self): - self.start(raise_, Exception('regular exception must not kill the program')) - gevent.sleep(0.001) - - -class TestCallback(Test): - - def tearDown(self): - if self.x is not None: - # libuv: See the notes in libuv/loop.py:loop._start_callback_timer - # If that's broken, test_exception can fail sporadically. - # If the issue is the same, then adding `gevent.sleep(0)` here - # will solve it. There's also a race condition for the first loop, - # so we sleep twice. - assert not self.x.pending, self.x - - def start(self, *args): - self.x = get_hub().loop.run_callback(*args) - - if greentest.LIBUV: - def test_exception(self): - # This call will enter the loop for the very first time (if we're running - # standalone). On libuv, where timers run first, that means that depending on the - # amount of time that elapses between the call to uv_timer_start and uv_run, - # this timer might fire before our check or prepare watchers, and hence callbacks, - # run. - # We make this call now so that the call in the super class is guaranteed to be - # somewhere in the loop and not subject to that race condition. - gevent.sleep(0.001) - super(TestCallback, self).test_exception() - -class TestSpawn(Test): - - def tearDown(self): - gevent.sleep(0.0001) - if self.x is not None: - assert self.x.dead, self.x - - def start(self, *args): - self.x = gevent.spawn(*args) - - -del Test - -if __name__ == '__main__': - greentest.main() diff --git a/venv/lib/python3.9/site-packages/gevent/tests/test__thread.py b/venv/lib/python3.9/site-packages/gevent/tests/test__thread.py deleted file mode 100644 index 01d0036..0000000 --- a/venv/lib/python3.9/site-packages/gevent/tests/test__thread.py +++ /dev/null @@ -1,31 +0,0 @@ -from __future__ import print_function -from __future__ import absolute_import - -from gevent.thread import allocate_lock - -import gevent.testing as greentest - -try: - from _thread import allocate_lock as std_allocate_lock -except ImportError: # Py2 - from thread import allocate_lock as std_allocate_lock - - -class TestLock(greentest.TestCase): - - def test_release_unheld_lock(self): - std_lock = std_allocate_lock() - g_lock = allocate_lock() - with self.assertRaises(Exception) as exc: - std_lock.release() - std_exc = exc.exception - - with self.assertRaises(Exception) as exc: - g_lock.release() - g_exc = exc.exception - - self.assertIsInstance(g_exc, type(std_exc)) - - -if __name__ == '__main__': - greentest.main() diff --git a/venv/lib/python3.9/site-packages/gevent/tests/test__threading.py b/venv/lib/python3.9/site-packages/gevent/tests/test__threading.py deleted file mode 100644 index 25a377d..0000000 --- a/venv/lib/python3.9/site-packages/gevent/tests/test__threading.py +++ /dev/null @@ -1,92 +0,0 @@ -""" -Tests specifically for the monkey-patched threading module. -""" -from gevent import monkey; monkey.patch_all() # pragma: testrunner-no-monkey-combine -import gevent.hub - -# check that the locks initialized by 'threading' did not init the hub -assert gevent.hub._get_hub() is None, 'monkey.patch_all() should not init hub' - -import gevent -import gevent.testing as greentest -import threading - - -def helper(): - threading.current_thread() - gevent.sleep(0.2) - -class TestCleanup(greentest.TestCase): - - def _do_test(self, spawn): - before = len(threading._active) - - g = spawn(helper) - gevent.sleep(0.1) - self.assertEqual(len(threading._active), before + 1) - - try: - g.join() - except AttributeError: - while not g.dead: - gevent.sleep() - # Raw greenlet has no join(), uses a weakref to cleanup. - # so the greenlet has to die. On CPython, it's enough to - # simply delete our reference. - del g - # On PyPy, it might take a GC, but for some reason, even - # running several GC's doesn't clean it up under 5.6.0. - # So we skip the test. - #import gc - #gc.collect() - - self.assertEqual(len(threading._active), before) - - - def test_cleanup_gevent(self): - self._do_test(gevent.spawn) - - @greentest.skipOnPyPy("weakref is not cleaned up in a timely fashion") - def test_cleanup_raw(self): - self._do_test(gevent.spawn_raw) - - -class TestLockThread(greentest.TestCase): - - def _spawn(self, func): - t = threading.Thread(target=func) - t.start() - return t - - def test_spin_lock_switches(self): - # https://github.com/gevent/gevent/issues/1464 - # pylint:disable=consider-using-with - lock = threading.Lock() - lock.acquire() - spawned = [] - - def background(): - spawned.append(True) - while not lock.acquire(False): - pass - - thread = threading.Thread(target=background) - # If lock.acquire(False) doesn't yield when it fails, - # then this never returns. - thread.start() - # Verify it tried to run - self.assertEqual(spawned, [True]) - # We can attempt to join it, which won't work. - thread.join(0) - # We can release the lock and then it will acquire. - lock.release() - thread.join() - - -class TestLockGreenlet(TestLockThread): - - def _spawn(self, func): - return gevent.spawn(func) - -if __name__ == '__main__': - greentest.main() diff --git a/venv/lib/python3.9/site-packages/gevent/tests/test__threading_2.py b/venv/lib/python3.9/site-packages/gevent/tests/test__threading_2.py deleted file mode 100644 index e5ecc45..0000000 --- a/venv/lib/python3.9/site-packages/gevent/tests/test__threading_2.py +++ /dev/null @@ -1,641 +0,0 @@ -# testing gevent's Event, Lock, RLock, Semaphore, BoundedSemaphore with standard test_threading - -import gevent.testing as greentest - -setup_ = """from gevent import monkey; monkey.patch_all() -from gevent.event import Event -from gevent.lock import RLock, Semaphore, BoundedSemaphore -from gevent.thread import allocate_lock as Lock -import threading -threading.Event = Event -threading.Lock = Lock -# NOTE: We're completely patching around the allocate_lock -# patch we try to do with RLock; our monkey patch doesn't -# behave this way, but we do it in tests to make sure that -# our RLock implementation behaves correctly by itself. -# However, we must test the patched version too, so make it -# available. -threading.NativeRLock = threading.RLock -threading.RLock = RLock -threading.Semaphore = Semaphore -threading.BoundedSemaphore = BoundedSemaphore -""" - -exec(setup_) - -setup_3 = '\n'.join(' %s' % line for line in setup_.split('\n')) -setup_4 = '\n'.join(' %s' % line for line in setup_.split('\n')) - -from gevent.testing import support -verbose = support.verbose - -import random -import re -import sys -import threading -import _thread as thread -import time -import unittest -import weakref - - -from gevent.tests import lock_tests -verbose = False -# pylint:disable=consider-using-with - -from unittest.mock import patch as Patch - - - -def skipDueToHang(cls): - return unittest.skipIf( - greentest.PYPY3 and greentest.RUNNING_ON_CI, - "SKIPPED: Timeout on PyPy3 on Travis" - )(cls) - -class Counter(object): - # A trivial mutable counter. - def __init__(self): - self.value = 0 - - def inc(self): - self.value += 1 - - def dec(self): - self.value -= 1 - - def get(self): - return self.value - - -class TestThread(threading.Thread): - def __init__(self, name, testcase, sema, mutex, nrunning): - threading.Thread.__init__(self, name=name) - - self.testcase = testcase - self.sema = sema - self.mutex = mutex - self.nrunning = nrunning - - def run(self): - delay = random.random() / 10000.0 - if verbose: - print('task %s will run for %.1f usec' % ( - self.name, delay * 1e6)) - - with self.sema: - with self.mutex: - self.nrunning.inc() - if verbose: - print(self.nrunning.get(), 'tasks are running') - self.testcase.assertLessEqual(self.nrunning.get(), 3) - - time.sleep(delay) - if verbose: - print('task', self.name, 'done') - - with self.mutex: - self.nrunning.dec() - self.testcase.assertGreaterEqual(self.nrunning.get(), 0) - if verbose: - print('%s is finished. %d tasks are running' % ( - self.name, self.nrunning.get())) - -@skipDueToHang -class ThreadTests(unittest.TestCase): - maxDiff = None - - # Create a bunch of threads, let each do some work, wait until all are - # done. - def test_various_ops(self): - # This takes about n/3 seconds to run (about n/3 clumps of tasks, - # times about 1 second per clump). - NUMTASKS = 10 - - # no more than 3 of the 10 can run at once - sema = threading.BoundedSemaphore(value=3) - mutex = threading.RLock() - numrunning = Counter() - - threads = [] - - initial_regex = r'' - if sys.version_info[:2] < (3, 13): - # prior to 3.13, they distinguished the initial state from - # the stopped state. - initial_regex = r'' - - for i in range(NUMTASKS): - t = TestThread("" % i, self, sema, mutex, numrunning) - threads.append(t) - # pylint:disable-next=attribute-defined-outside-init - t.daemon = False # Under PYPY we get daemon by default? - self.assertIsNone(t.ident) - self.assertFalse(t.daemon) - self.assertTrue(re.match(initial_regex, repr(t)), - repr(t)) - t.start() - - if verbose: - print('waiting for all tasks to complete') - for t in threads: - t.join(NUMTASKS) - self.assertFalse(t.is_alive(), t.__dict__) - if hasattr(t, 'ident'): - self.assertNotEqual(t.ident, 0) - self.assertFalse(t.ident is None) - self.assertTrue(re.match(r'', repr(t))) - if verbose: - print('all tasks done') - self.assertEqual(numrunning.get(), 0) - - def test_ident_of_no_threading_threads(self): - # The ident still must work for the main thread and dummy threads, - # as must the repr and str. - - t = threading.current_thread() - self.assertFalse(t.ident is None) - str(t) - repr(t) - - def f(): - t = threading.current_thread() - ident.append(t.ident) - str(t) - repr(t) - done.set() - - done = threading.Event() - ident = [] - thread.start_new_thread(f, ()) - done.wait() - self.assertFalse(ident[0] is None) - # Kill the "immortal" _DummyThread - del threading._active[ident[0]] - - # run with a small(ish) thread stack size (256kB) - def test_various_ops_small_stack(self): - if verbose: - print('with 256kB thread stack size...') - try: - threading.stack_size(262144) - except thread.error: - if verbose: - print('platform does not support changing thread stack size') - return - self.test_various_ops() - threading.stack_size(0) - - # run with a large thread stack size (1MB) - def test_various_ops_large_stack(self): - if verbose: - print('with 1MB thread stack size...') - try: - threading.stack_size(0x100000) - except thread.error: - if verbose: - print('platform does not support changing thread stack size') - return - self.test_various_ops() - threading.stack_size(0) - - def test_foreign_thread(self): - # Check that a "foreign" thread can use the threading module. - def f(mutex): - # Calling current_thread() forces an entry for the foreign - # thread to get made in the threading._active map. - threading.current_thread() - mutex.release() - - mutex = threading.Lock() - mutex.acquire() - tid = thread.start_new_thread(f, (mutex,)) - # Wait for the thread to finish. - mutex.acquire() - self.assertIn(tid, threading._active) - self.assertIsInstance(threading._active[tid], - threading._DummyThread) - del threading._active[tid] - # in gevent, we actually clean up threading._active, but it's not happended there yet - - # PyThreadState_SetAsyncExc() is a CPython-only gimmick, not (currently) - # exposed at the Python level. This test relies on ctypes to get at it. - def SKIP_test_PyThreadState_SetAsyncExc(self): - try: - import ctypes - except ImportError: - if verbose: - print("test_PyThreadState_SetAsyncExc can't import ctypes") - return # can't do anything - - set_async_exc = ctypes.pythonapi.PyThreadState_SetAsyncExc - - class AsyncExc(Exception): - pass - - exception = ctypes.py_object(AsyncExc) - - # `worker_started` is set by the thread when it's inside a try/except - # block waiting to catch the asynchronously set AsyncExc exception. - # `worker_saw_exception` is set by the thread upon catching that - # exception. - worker_started = threading.Event() - worker_saw_exception = threading.Event() - - class Worker(threading.Thread): - id = None - finished = False - - def run(self): - self.id = thread.get_ident() - self.finished = False - - try: - while True: - worker_started.set() - time.sleep(0.1) - except AsyncExc: - self.finished = True - worker_saw_exception.set() - - t = Worker() - # pylint:disable-next=attribute-defined-outside-init - t.daemon = True # so if this fails, we don't hang Python at shutdown - t.start() - if verbose: - print(" started worker thread") - - # Try a thread id that doesn't make sense. - if verbose: - print(" trying nonsensical thread id") - result = set_async_exc(ctypes.c_long(-1), exception) - self.assertEqual(result, 0) # no thread states modified - - # Now raise an exception in the worker thread. - if verbose: - print(" waiting for worker thread to get started") - worker_started.wait() - if verbose: - print(" verifying worker hasn't exited") - self.assertFalse(t.finished) - if verbose: - print(" attempting to raise asynch exception in worker") - result = set_async_exc(ctypes.c_long(t.id), exception) - self.assertEqual(result, 1) # one thread state modified - if verbose: - print(" waiting for worker to say it caught the exception") - worker_saw_exception.wait(timeout=10) - self.assertTrue(t.finished) - if verbose: - print(" all OK -- joining worker") - if t.finished: - t.join() - # else the thread is still running, and we have no way to kill it - - def test_limbo_cleanup(self): - # Issue 7481: Failure to start thread should cleanup the limbo map. - def fail_new_thread(*_args, **_kw): - raise thread.error() - if hasattr(threading, '_start_new_thread'): - patcher = Patch.object(threading, '_start_new_thread', new=fail_new_thread) - else: - # 3.13 or later - patcher = Patch.object(threading, '_start_joinable_thread', new=fail_new_thread) - - self.addCleanup(patcher.stop) - patcher.start() - - t = threading.Thread(target=lambda: None) - self.assertRaises(thread.error, t.start) - self.assertFalse( - t in threading._limbo, - "Failed to cleanup _limbo map on failure of Thread.start().") - - def test_finalize_runnning_thread(self): - # Issue 1402: the PyGILState_Ensure / _Release functions may be called - # very late on python exit: on deallocation of a running thread for - # example. - try: - import ctypes - getattr(ctypes, 'pythonapi') # not available on PyPy - getattr(ctypes.pythonapi, 'PyGILState_Ensure') # not available on PyPy3 - except (ImportError, AttributeError): - if verbose: - print("test_finalize_with_runnning_thread can't import ctypes") - return # can't do anything - - del ctypes # pyflakes fix - - import subprocess - rc = subprocess.call([sys.executable, "-W", "ignore", "-c", """if 1: -%s - import ctypes, sys, time - try: - import thread - except ImportError: - import _thread as thread # Py3 - - # This lock is used as a simple event variable. - ready = thread.allocate_lock() - ready.acquire() - - # Module globals are cleared before __del__ is run - # So we save the functions in class dict - class C: - ensure = ctypes.pythonapi.PyGILState_Ensure - release = ctypes.pythonapi.PyGILState_Release - def __del__(self): - state = self.ensure() - self.release(state) - - def waitingThread(): - x = C() - ready.release() - time.sleep(100) - - thread.start_new_thread(waitingThread, ()) - ready.acquire() # Be sure the other thread is waiting. - sys.exit(42) - """ % setup_3]) - self.assertEqual(rc, 42) - - @greentest.skipOnLibuvOnPyPyOnWin("hangs") - def test_join_nondaemon_on_shutdown(self): - # Issue 1722344 - # Raising SystemExit skipped threading._shutdown - import subprocess - script = """if 1: -%s - import threading - from time import sleep - - def child(): - sleep(0.3) - # As a non-daemon thread we SHOULD wake up and nothing - # should be torn down yet - print("Woke up, sleep function is: %%s.%%s" %% (sleep.__module__, sleep.__name__)) - - threading.Thread(target=child).start() - raise SystemExit - """ % setup_4 - p = subprocess.Popen([sys.executable, "-W", "ignore", "-c", script], - stdout=subprocess.PIPE, - stderr=subprocess.PIPE) - stdout, stderr = p.communicate() - stdout = stdout.strip() - stdout = stdout.decode('utf-8') - stderr = stderr.decode('utf-8') - - - self.assertEqual( - 'Woke up, sleep function is: gevent.hub.sleep', - stdout) - - # On Python 2, importing pkg_resources tends to result in some 'ImportWarning' - # being printed to stderr about packages missing __init__.py; the -W ignore is... - # ignored. - # self.assertEqual(stderr, "") - - @greentest.skipIf( - not(hasattr(sys, 'getcheckinterval')), - "Needs sys.getcheckinterval" - ) - def test_enumerate_after_join(self): - # Try hard to trigger #1703448: a thread is still returned in - # threading.enumerate() after it has been join()ed. - enum = threading.enumerate - import warnings - with warnings.catch_warnings(): - warnings.simplefilter('ignore', DeprecationWarning) - # get/set checkinterval are deprecated in Python 3, - # and removed in Python 3.9 - old_interval = sys.getcheckinterval() # pylint:disable=no-member - try: - for i in range(1, 100): - # Try a couple times at each thread-switching interval - # to get more interleavings. - sys.setcheckinterval(i // 5) # pylint:disable=no-member - t = threading.Thread(target=lambda: None) - t.start() - t.join() - l = enum() - self.assertFalse(t in l, - "#1703448 triggered after %d trials: %s" % (i, l)) - finally: - sys.setcheckinterval(old_interval) # pylint:disable=no-member - - if not hasattr(sys, 'pypy_version_info'): - def test_no_refcycle_through_target(self): - class RunSelfFunction(object): - def __init__(self, should_raise): - # The links in this refcycle from Thread back to self - # should be cleaned up when the thread completes. - self.should_raise = should_raise - self.thread = threading.Thread(target=self._run, - args=(self,), - kwargs={'_yet_another': self}) - self.thread.start() - - def _run(self, _other_ref, _yet_another): - if self.should_raise: - raise SystemExit - - cyclic_object = RunSelfFunction(should_raise=False) - weak_cyclic_object = weakref.ref(cyclic_object) - cyclic_object.thread.join() - del cyclic_object - self.assertIsNone(weak_cyclic_object(), - msg=('%d references still around' % - sys.getrefcount(weak_cyclic_object()))) - - raising_cyclic_object = RunSelfFunction(should_raise=True) - weak_raising_cyclic_object = weakref.ref(raising_cyclic_object) - raising_cyclic_object.thread.join() - del raising_cyclic_object - self.assertIsNone(weak_raising_cyclic_object(), - msg=('%d references still around' % - sys.getrefcount(weak_raising_cyclic_object()))) - -@skipDueToHang -class ThreadJoinOnShutdown(unittest.TestCase): - - maxDiff = None - - def _run_and_join(self, script): - script = """if 1: -%s - import sys, os, time, threading - # a thread, which waits for the main program to terminate - def joiningfunc(mainthread): - mainthread.join() - print('end of thread') - \n""" % setup_3 + script - - import subprocess - p = subprocess.Popen([sys.executable, "-W", "ignore", "-c", script], stdout=subprocess.PIPE) - rc = p.wait(60) - data = p.stdout.read().replace(b'\r', b'') - p.stdout.close() - data = data.decode('utf-8') - self.assertEqual(data, "end of main\nend of thread\n") - self.assertNotEqual(rc, 2, "interpreter was blocked") - self.assertEqual(rc, 0, "Unexpected error") - - @greentest.skipOnLibuvOnPyPyOnWin("hangs") - def test_1_join_on_shutdown(self): - # The usual case: on exit, wait for a non-daemon thread - script = """if 1: - import os - t = threading.Thread(target=joiningfunc, - args=(threading.current_thread(),)) - t.start() - time.sleep(0.2) - print('end of main') - """ - self._run_and_join(script) - - @greentest.skipOnPyPy3OnCI("Sometimes randomly times out") - def test_2_join_in_forked_process(self): - # Like the test above, but from a forked interpreter - import os - if not hasattr(os, 'fork'): - return - script = """if 1: - childpid = os.fork() - if childpid != 0: - os.waitpid(childpid, 0) - sys.exit(0) - - t = threading.Thread(target=joiningfunc, - args=(threading.current_thread(),)) - t.start() - print('end of main') - """ - self._run_and_join(script) - - def test_3_join_in_forked_from_thread(self): - # Like the test above, but fork() was called from a worker thread - # In the forked process, the main Thread object must be marked as stopped. - import os - if not hasattr(os, 'fork'): - return - # Skip platforms with known problems forking from a worker thread. - # See http://bugs.python.org/issue3863. - # skip disable because I think the bug shouldn't apply to gevent -- denis - #if sys.platform in ('freebsd4', 'freebsd5', 'freebsd6', 'os2emx'): - # print(('Skipping test_3_join_in_forked_from_thread' - # ' due to known OS bugs on'), sys.platform, file=sys.stderr) - # return - - # A note on CFFI: Under Python 3, using CFFI tends to initialize the GIL, - # whether or not we spawn any actual threads. Now, os.fork() calls - # PyEval_ReInitThreads, which only does any work of the GIL has been taken. - # One of the things it does is call threading._after_fork to reset - # some thread state, which causes the main thread (threading._main_thread) - # to be reset to the current thread---which for Python >= 3.4 happens - # to be our version of thread, gevent.threading.Thread, which doesn't - # initialize the _tstate_lock ivar. This causes threading._shutdown to crash - # with an AssertionError and this test to fail. We hack around this by - # making sure _after_fork is not called in the child process. - # XXX: Figure out how to really fix that. - - script = """if 1: - main_thread = threading.current_thread() - def worker(): - childpid = os.fork() - if childpid != 0: - os.waitpid(childpid, 0) - sys.exit(0) - - t = threading.Thread(target=joiningfunc, - args=(main_thread,)) - print('end of main') - t.start() - # Should not block: main_thread object is already stopped - # because we're running in a non-main thread of - # the child process - t.join(30) - assert not t.is_alive() - - w = threading.Thread(target=worker) - w.start() - import sys - if sys.version_info[:2] >= (3, 7) or (sys.version_info[:2] >= (3, 5) and hasattr(sys, 'pypy_version_info') and sys.platform != 'darwin'): - w.join(45) - if w.is_alive(): - print('OH NO, failed to join worker') - """ - # In PyPy3 5.8.0, if we don't wait on this top-level "thread", 'w', - # we never see "end of thread". It's not clear why, since that's being - # done in a child of this process. Yet in normal CPython 3, waiting on this - # causes the whole process to lock up (possibly because of some loop within - # the interpreter waiting on thread locks, like the issue described in threading.py - # for Python 3.4? in any case, it doesn't hang in Python 2.) This changed in - # 3.7a1 and waiting on it is again necessary and doesn't hang. - # PyPy3 5.10.1 is back to the "old" cpython behaviour, and waiting on it - # causes the whole process to hang, but apparently only on OS X---linux was fine without it - self._run_and_join(script) - - -@skipDueToHang -class ThreadingExceptionTests(unittest.TestCase): - # A RuntimeError should be raised if Thread.start() is called - # multiple times. - # pylint:disable=bad-thread-instantiation - def test_start_thread_again(self): - thread_ = threading.Thread() - thread_.start() - self.assertRaises(RuntimeError, thread_.start) - - def test_joining_current_thread(self): - current_thread = threading.current_thread() - self.assertRaises(RuntimeError, current_thread.join) - - def test_joining_inactive_thread(self): - thread_ = threading.Thread() - self.assertRaises(RuntimeError, thread_.join) - - def test_daemonize_active_thread(self): - thread_ = threading.Thread() - thread_.start() - self.assertRaises(RuntimeError, setattr, thread_, "daemon", True) - - -@skipDueToHang -class LockTests(lock_tests.LockTests): - locktype = staticmethod(threading.Lock) - -@skipDueToHang -class RLockTests(lock_tests.RLockTests): - locktype = staticmethod(threading.RLock) - -@skipDueToHang -class NativeRLockTests(lock_tests.RLockTests): - # See comments at the top of the file for the difference - # between this and RLockTests, and why they both matter - locktype = staticmethod(threading.NativeRLock) - -@skipDueToHang -class EventTests(lock_tests.EventTests): - eventtype = staticmethod(threading.Event) - -@skipDueToHang -class ConditionAsRLockTests(lock_tests.RLockTests): - # An Condition uses an RLock by default and exports its API. - locktype = staticmethod(threading.Condition) - -@skipDueToHang -class ConditionTests(lock_tests.ConditionTests): - condtype = staticmethod(threading.Condition) - -@skipDueToHang -class SemaphoreTests(lock_tests.SemaphoreTests): - semtype = staticmethod(threading.Semaphore) - -@skipDueToHang -class BoundedSemaphoreTests(lock_tests.BoundedSemaphoreTests): - semtype = staticmethod(threading.BoundedSemaphore) - - -if __name__ == "__main__": - greentest.main() diff --git a/venv/lib/python3.9/site-packages/gevent/tests/test__threading_before_monkey.py b/venv/lib/python3.9/site-packages/gevent/tests/test__threading_before_monkey.py deleted file mode 100644 index b84ecec..0000000 --- a/venv/lib/python3.9/site-packages/gevent/tests/test__threading_before_monkey.py +++ /dev/null @@ -1,23 +0,0 @@ -# If stdlib threading is imported *BEFORE* monkey patching, -# we can still get the current (main) thread, and it's not a DummyThread. - -import threading -from gevent import monkey -monkey.patch_all() # pragma: testrunner-no-monkey-combine - -import gevent.testing as greentest - - -class Test(greentest.TestCase): - - def test_main_thread(self): - current = threading.current_thread() - self.assertFalse(isinstance(current, threading._DummyThread)) - self.assertTrue(isinstance(current, monkey.get_original('threading', 'Thread'))) - # in 3.4, if the patch is incorrectly done, getting the repr - # of the thread fails - repr(current) - - -if __name__ == '__main__': - greentest.main() diff --git a/venv/lib/python3.9/site-packages/gevent/tests/test__threading_fork_from_dummy.py b/venv/lib/python3.9/site-packages/gevent/tests/test__threading_fork_from_dummy.py deleted file mode 100644 index 2f8df88..0000000 --- a/venv/lib/python3.9/site-packages/gevent/tests/test__threading_fork_from_dummy.py +++ /dev/null @@ -1,65 +0,0 @@ -# -*- coding: utf-8 -*- -""" -Tests for `issue 2020 `_: -3.11.8 and 3.12.2 try to swizzle ``__class__`` of the dummy thread -found when forking from inside a greenlet. - -""" -from gevent import monkey; monkey.patch_all() # pragma: testrunner-no-monkey-combine - -import unittest -import gevent.testing as greentest - -import tempfile - -@greentest.skipOnWindows("Uses os.fork") -class Test(greentest.TestCase): - - - def test_fork_from_dummy_thread(self): - import os - import threading - import contextlib - - import gevent - from gevent.threading import _DummyThread - if not _DummyThread._NEEDS_CLASS_FORK_FIXUP: - self.skipTest('No patch need be applied') - - def do_it(out): - # Be sure we've put the DummyThread in the threading - # maps - assert isinstance(threading.current_thread(), threading._DummyThread) - with open(out, 'wt', encoding='utf-8') as f: - with contextlib.redirect_stderr(f): - r = os.fork() - if r == 0: - # In the child. - # Our stderr redirect above will capture the - # "Exception ignored in _after_fork()" that the interpreter - # prints; actually printing the main_thread will result in - # raising an exception if our patch doesn't work. - main = threading.main_thread() - print(main, file=f) - print(type(main), file=f) - return r - - with tempfile.NamedTemporaryFile('w+t', suffix='.gevent_threading.txt') as tf: - glet = gevent.spawn(do_it, tf.name) - glet.join() - pid = glet.get() - if pid == 0: - # Dump the child process quickly - os._exit(0) - - os.waitpid(pid, 0) - tf.seek(0, 0) - contents = tf.read() - - - self.assertIn("", contents) - self.assertNotIn("_DummyThread", contents) - - -if __name__ == '__main__': - unittest.main() diff --git a/venv/lib/python3.9/site-packages/gevent/tests/test__threading_holding_lock_while_monkey.py b/venv/lib/python3.9/site-packages/gevent/tests/test__threading_holding_lock_while_monkey.py deleted file mode 100644 index b12da76..0000000 --- a/venv/lib/python3.9/site-packages/gevent/tests/test__threading_holding_lock_while_monkey.py +++ /dev/null @@ -1,9 +0,0 @@ -from gevent import monkey -import threading -# Make sure that we can patch gevent while holding -# a threading lock. Under Python2, where RLock is implemented -# in python code, this used to throw RuntimeErro("Cannot release un-acquired lock") -# See https://github.com/gevent/gevent/issues/615 -# pylint:disable=useless-with-lock -with threading.RLock(): - monkey.patch_all() # pragma: testrunner-no-monkey-combine diff --git a/venv/lib/python3.9/site-packages/gevent/tests/test__threading_monkey_in_thread.py b/venv/lib/python3.9/site-packages/gevent/tests/test__threading_monkey_in_thread.py deleted file mode 100644 index 2a16ea3..0000000 --- a/venv/lib/python3.9/site-packages/gevent/tests/test__threading_monkey_in_thread.py +++ /dev/null @@ -1,62 +0,0 @@ -# We can monkey-patch in a thread, but things don't work as expected. -from __future__ import print_function - -import threading -from gevent import monkey -import gevent.testing as greentest - - -class Test(greentest.TestCase): - - @greentest.ignores_leakcheck # can't be run multiple times - def test_patch_in_thread(self): - all_warnings = [] - try: - get_ident = threading.get_ident - except AttributeError: - get_ident = threading._get_ident - - def process_warnings(warnings): - all_warnings.extend(warnings) - monkey._process_warnings = process_warnings - - current = threading.current_thread() - current_id = get_ident() - - def target(): - tcurrent = threading.current_thread() - monkey.patch_all() # pragma: testrunner-no-monkey-combine - tcurrent2 = threading.current_thread() - self.assertIsNot(tcurrent, current) - # We get a dummy thread now - self.assertIsNot(tcurrent, tcurrent2) - - thread = threading.Thread(target=target) - thread.start() - try: - thread.join() - except: # pylint:disable=bare-except - # XXX: This can raise LoopExit in some cases. - greentest.reraiseFlakyTestRaceCondition() - - self.assertNotIsInstance(current, threading._DummyThread) - self.assertIsInstance(current, monkey.get_original('threading', 'Thread')) - - - # We generated some warnings - self.assertEqual( - all_warnings, - ['Monkey-patching outside the main native thread. Some APIs will not be ' - 'available. Expect a KeyError to be printed at shutdown.', - 'Monkey-patching not on the main thread; threading.main_thread().join() ' - 'will hang from a greenlet']) - - - # Manual clean up so we don't get a KeyError - del threading._active[current_id] - threading._active[(getattr(threading, 'get_ident', None) or threading._get_ident)()] = current - - - -if __name__ == '__main__': - greentest.main() diff --git a/venv/lib/python3.9/site-packages/gevent/tests/test__threading_native_before_monkey.py b/venv/lib/python3.9/site-packages/gevent/tests/test__threading_native_before_monkey.py deleted file mode 100644 index e015370..0000000 --- a/venv/lib/python3.9/site-packages/gevent/tests/test__threading_native_before_monkey.py +++ /dev/null @@ -1,70 +0,0 @@ -# If stdlib threading is imported *BEFORE* monkey patching, *and* -# there is a native thread created, we can still get the current -# (main) thread, and it's not a DummyThread. -# Joining the native thread also does not fail - -import threading -from time import sleep as time_sleep - -import gevent.testing as greentest - -class NativeThread(threading.Thread): - do_run = True - - def run(self): - while self.do_run: - time_sleep(0.1) - - def stop(self, timeout=None): - self.do_run = False - self.join(timeout=timeout) - -native_thread = None -monkey = None - -class Test(greentest.TestCase): - - @classmethod - def tearDownClass(cls): - global native_thread - if native_thread is not None: - native_thread.stop(1) - native_thread = None - - def test_main_thread(self): - current = threading.current_thread() - self.assertNotIsInstance(current, threading._DummyThread) - # pylint:disable-next=used-before-assignment - self.assertIsInstance(current, monkey.get_original('threading', 'Thread')) - # in 3.4, if the patch is incorrectly done, getting the repr - # of the thread fails - repr(current) - - if hasattr(threading, 'main_thread'): # py 3.4 - self.assertEqual(threading.current_thread(), threading.main_thread()) - - @greentest.ignores_leakcheck # because it can't be run multiple times - def test_join_native_thread(self): - if native_thread is None or not native_thread.do_run: # pragma: no cover - self.skipTest("native_thread already closed") - - self.assertTrue(native_thread.is_alive()) - - native_thread.stop(timeout=1) - self.assertFalse(native_thread.is_alive()) - - # again, idempotent - native_thread.stop() - self.assertFalse(native_thread.is_alive()) - - -if __name__ == '__main__': - native_thread = NativeThread() - native_thread.daemon = True # pylint:disable=attribute-defined-outside-init - native_thread.start() - - # Only patch after we're running - from gevent import monkey - monkey.patch_all() # pragma: testrunner-no-monkey-combine - - greentest.main() diff --git a/venv/lib/python3.9/site-packages/gevent/tests/test__threading_no_monkey.py b/venv/lib/python3.9/site-packages/gevent/tests/test__threading_no_monkey.py deleted file mode 100644 index 44b70ba..0000000 --- a/venv/lib/python3.9/site-packages/gevent/tests/test__threading_no_monkey.py +++ /dev/null @@ -1,30 +0,0 @@ -# -*- coding: utf-8 -*- -""" -Tests for ``gevent.threading`` that DO NOT monkey patch. This -allows easy comparison with the standard module. - -""" -from __future__ import absolute_import -from __future__ import division -from __future__ import print_function - -import threading - -from gevent import threading as gthreading -from gevent import testing - -class TestDummyThread(testing.TestCase): - - def test_name(self): - # Matches the stdlib. - # https://github.com/gevent/gevent/issues/1659 - std_dummy = threading._DummyThread() - gvt_dummy = gthreading._DummyThread() - self.assertIsNot(type(std_dummy), type(gvt_dummy)) - - self.assertStartsWith(std_dummy.name, 'Dummy-') - self.assertStartsWith(gvt_dummy.name, 'Dummy-') - - -if __name__ == '__main__': - testing.main() diff --git a/venv/lib/python3.9/site-packages/gevent/tests/test__threading_patched_local.py b/venv/lib/python3.9/site-packages/gevent/tests/test__threading_patched_local.py deleted file mode 100644 index 6b78d32..0000000 --- a/venv/lib/python3.9/site-packages/gevent/tests/test__threading_patched_local.py +++ /dev/null @@ -1,27 +0,0 @@ -from gevent import monkey; monkey.patch_all() -import threading - - -localdata = threading.local() -localdata.x = "hello" -assert localdata.x == 'hello' -success = [] - - -def func(): - try: - getattr(localdata, 'x') - raise AssertionError('localdata.x must raise AttributeError') - except AttributeError: - pass - # We really want to check this is exactly an empty dict, - # not just anything falsey - # pylint:disable=use-implicit-booleaness-not-comparison - assert localdata.__dict__ == {}, localdata.__dict__ - success.append(1) - -t = threading.Thread(None, func) -t.start() -t.join() -assert success == [1], 'test failed' -assert localdata.x == 'hello' diff --git a/venv/lib/python3.9/site-packages/gevent/tests/test__threading_vs_settrace.py b/venv/lib/python3.9/site-packages/gevent/tests/test__threading_vs_settrace.py deleted file mode 100644 index 7cca26b..0000000 --- a/venv/lib/python3.9/site-packages/gevent/tests/test__threading_vs_settrace.py +++ /dev/null @@ -1,162 +0,0 @@ -from __future__ import print_function -import sys -import subprocess -import unittest -from gevent.thread import allocate_lock -import gevent.testing as greentest - -script = """ -from gevent import monkey -monkey.patch_all() # pragma: testrunner-no-monkey-combine -import sys, os, threading, time - - -# A deadlock-killer, to prevent the -# testsuite to hang forever -def killer(): - time.sleep(0.2) - sys.stdout.write('..program blocked; aborting!') - sys.stdout.flush() - os._exit(2) -t = threading.Thread(target=killer) -t.daemon = True -t.start() - - -def trace(frame, event, arg): - if threading is not None: - threading.current_thread() - return trace - - -def doit(): - sys.stdout.write("..thread started..") - - -def test1(): - t = threading.Thread(target=doit) - t.start() - t.join() - sys.settrace(None) - -sys.settrace(trace) -if len(sys.argv) > 1: - test1() - -sys.stdout.write("..finishing..") -""" - - -class TestTrace(unittest.TestCase): - @greentest.skipOnPurePython("Locks can be traced in Pure Python") - def test_untraceable_lock(self): - # Untraceable locks were part of the solution to https://bugs.python.org/issue1733757 - # which details a deadlock that could happen if a trace function invoked - # threading.currentThread at shutdown time---the cleanup lock would be held - # by the VM, and calling currentThread would try to acquire it again. The interpreter - # changed in 2.6 to use the `with` statement (https://hg.python.org/cpython/rev/76f577a9ec03/), - # which apparently doesn't trace in quite the same way. - if hasattr(sys, 'gettrace'): - old = sys.gettrace() - else: - old = None - - lst = [] - try: - def trace(frame, ev, _arg): - lst.append((frame.f_code.co_filename, frame.f_lineno, ev)) - print("TRACE: %s:%s %s" % lst[-1]) - return trace - - with allocate_lock(): - sys.settrace(trace) - finally: - sys.settrace(old) - - self.assertEqual(lst, [], "trace not empty") - - @greentest.skipOnPurePython("Locks can be traced in Pure Python") - def test_untraceable_lock_uses_different_lock(self): - if hasattr(sys, 'gettrace'): - old = sys.gettrace() - else: - old = None - - lst = [] - # we should be able to use unrelated locks from within the trace function - l = allocate_lock() - try: - def trace(frame, ev, _arg): - with l: - lst.append((frame.f_code.co_filename, frame.f_lineno, ev)) - # print("TRACE: %s:%s %s" % lst[-1]) - return trace - - l2 = allocate_lock() - sys.settrace(trace) - # Separate functions, not the C-implemented `with` so the trace - # function gets a crack at them - l2.acquire() - l2.release() - finally: - sys.settrace(old) - - # Have an assert so that we know if we miscompile - self.assertTrue(lst, "should not compile on pypy") - - @greentest.skipOnPurePython("Locks can be traced in Pure Python") - def test_untraceable_lock_uses_same_lock(self): - from gevent.hub import LoopExit - if hasattr(sys, 'gettrace'): - old = sys.gettrace() - else: - old = None - - lst = [] - e = None - # we should not be able to use the same lock from within the trace function - # because it's over acquired but instead of deadlocking it raises an exception - l = allocate_lock() - try: - def trace(frame, ev, _arg): - with l: - lst.append((frame.f_code.co_filename, frame.f_lineno, ev)) - return trace - - sys.settrace(trace) - # Separate functions, not the C-implemented `with` so the trace - # function gets a crack at them - l.acquire() - except LoopExit as ex: - e = ex - finally: - sys.settrace(old) - - # Have an assert so that we know if we miscompile - self.assertTrue(lst, "should not compile on pypy") - self.assertTrue(isinstance(e, LoopExit)) - - def run_script(self, more_args=()): - if ( - greentest.PYPY3 - and greentest.RUNNING_ON_APPVEYOR - and sys.version_info[:2] == (3, 7) - ): - # Somehow launching the subprocess fails with exit code 1, and - # produces no output. It's not clear why. - self.skipTest("Known to hang on AppVeyor") - args = [sys.executable, "-u", "-c", script] - args.extend(more_args) - rc = subprocess.call(args) - self.assertNotEqual(rc, 2, "interpreter was blocked") - self.assertEqual(rc, 0, "Unexpected error") - - def test_finalize_with_trace(self): - self.run_script() - - def test_bootstrap_inner_with_trace(self): - self.run_script(["1"]) - - -if __name__ == "__main__": - greentest.main() diff --git a/venv/lib/python3.9/site-packages/gevent/tests/test__threadpool.py b/venv/lib/python3.9/site-packages/gevent/tests/test__threadpool.py deleted file mode 100644 index 9616fab..0000000 --- a/venv/lib/python3.9/site-packages/gevent/tests/test__threadpool.py +++ /dev/null @@ -1,825 +0,0 @@ -from __future__ import print_function - -from time import time, sleep -import contextlib -import random -import weakref -import gc - - -import gevent.threadpool -from gevent.threadpool import ThreadPool -import gevent -from gevent.exceptions import InvalidThreadUseError - -import gevent.testing as greentest -from gevent.testing import ExpectedException -from gevent.testing import PYPY - - - -# pylint:disable=too-many-ancestors - - -@contextlib.contextmanager -def disabled_gc(): - was_enabled = gc.isenabled() - gc.disable() - try: - yield - finally: - if was_enabled: - gc.enable() - - -class TestCase(greentest.TestCase): - # These generally need more time - __timeout__ = greentest.LARGE_TIMEOUT - pool = None - _all_pools = () - - ClassUnderTest = ThreadPool - def _FUT(self): - return self.ClassUnderTest - - def _makeOne(self, maxsize, create_all_worker_threads=greentest.RUN_LEAKCHECKS): - self.pool = pool = self._FUT()(maxsize) - self._all_pools += (pool,) - if create_all_worker_threads: - # Max size to help eliminate false positives - self.pool.size = maxsize - return pool - - def cleanup(self): - self.pool = None - all_pools, self._all_pools = self._all_pools, () - for pool in all_pools: - kill = getattr(pool, 'kill', None) or getattr(pool, 'shutdown') - kill() - del kill - - if greentest.RUN_LEAKCHECKS: - # Each worker thread created a greenlet object and switched to it. - # It's a custom subclass, but even if it's not, it appears that - # the root greenlet for the new thread sticks around until there's a - # gc. Simply calling 'getcurrent()' is enough to "leak" a greenlet.greenlet - # and a weakref. - for _ in range(3): - gc.collect() - - -class PoolBasicTests(TestCase): - - def test_execute_async(self): - pool = self._makeOne(2) - r = [] - first = pool.spawn(r.append, 1) - first.get() - self.assertEqual(r, [1]) - gevent.sleep(0) - - pool.apply_async(r.append, (2, )) - self.assertEqual(r, [1]) - - pool.apply_async(r.append, (3, )) - self.assertEqual(r, [1]) - - pool.apply_async(r.append, (4, )) - self.assertEqual(r, [1]) - gevent.sleep(0.01) - self.assertEqualFlakyRaceCondition(sorted(r), [1, 2, 3, 4]) - - def test_apply(self): - pool = self._makeOne(1) - result = pool.apply(lambda a: ('foo', a), (1, )) - self.assertEqual(result, ('foo', 1)) - - def test_apply_raises(self): - pool = self._makeOne(1) - - def raiser(): - raise ExpectedException() - - with self.assertRaises(ExpectedException): - pool.apply(raiser) - # Don't let the metaclass automatically force any error - # that reaches the hub from a spawned greenlet to become - # fatal; that defeats the point of the test. - test_apply_raises.error_fatal = False - - def test_init_valueerror(self): - self.switch_expected = False - with self.assertRaises(ValueError): - self._makeOne(-1) - -# -# tests from standard library test/test_multiprocessing.py - - -class TimingWrapper(object): - - def __init__(self, the_func): - self.func = the_func - self.elapsed = None - - def __call__(self, *args, **kwds): - t = time() - try: - return self.func(*args, **kwds) - finally: - self.elapsed = time() - t - - -def sqr(x, wait=0.0): - sleep(wait) - return x * x - - -def sqr_random_sleep(x): - sleep(random.random() * 0.1) - return x * x - - -TIMEOUT1, TIMEOUT2, TIMEOUT3 = 0.082, 0.035, 0.14 - -class _AbstractPoolTest(TestCase): - - size = 1 - - MAP_IS_GEN = False - - def setUp(self): - greentest.TestCase.setUp(self) - self._makeOne(self.size) - - @greentest.ignores_leakcheck - def test_map(self): - pmap = self.pool.map - if self.MAP_IS_GEN: - pmap = lambda f, i: list(self.pool.map(f, i)) - self.assertEqual(pmap(sqr, range(10)), list(map(sqr, range(10)))) - self.assertEqual(pmap(sqr, range(100)), list(map(sqr, range(100)))) - - self.pool.kill() - del self.pool - del pmap - -SMALL_RANGE = 10 -LARGE_RANGE = 1000 - -if (greentest.PYPY and (greentest.WIN or greentest.RUN_COVERAGE)) or greentest.RUN_LEAKCHECKS: - # PyPy 5.10 is *really* slow at spawning or switching between - # threads (especially on Windows or when coverage is enabled) Tests that happen - # instantaneously on other platforms time out due to the overhead. - - # Leakchecks also take much longer due to all the calls into the GC, - # most especially on Python 3 - LARGE_RANGE = 50 - -class TestPool(_AbstractPoolTest): - - def test_greenlet_class(self): - from greenlet import getcurrent - from gevent.threadpool import _WorkerGreenlet - worker_greenlet = self.pool.apply(getcurrent) - - self.assertIsInstance(worker_greenlet, _WorkerGreenlet) - r = repr(worker_greenlet) - self.assertIn('ThreadPoolWorker', r) - self.assertIn('thread_ident', r) - self.assertIn('hub=', r) - - from gevent.util import format_run_info - - info = '\n'.join(format_run_info()) - self.assertIn("") - - value = hexobj.sub('X', value) - value = value.replace('epoll', 'select') - value = value.replace('select', 'default') - value = value.replace('test__util', '__main__') - value = re.compile(' fileno=.').sub('', value) - value = value.replace('ref=-1', 'ref=0') - value = value.replace("type.current_tree", 'GreenletTree.current_tree') - value = value.replace('gevent.tests.__main__.MyLocal', '__main__.MyLocal') - # The repr in CPython greenlet 1.0a1 added extra info - value = value.replace('(otid=X) ', '') - value = value.replace(' dead>', '>') - value = value.replace(' current active started main>', '>') - return value - - @greentest.ignores_leakcheck - def test_tree(self): - with gevent.get_hub().ignoring_expected_test_error(): - tree, str_tree, tree_format = self._build_tree() - - self.assertTrue(tree.root) - - self.assertNotIn('Parent', str_tree) # Simple output - value = self._normalize_tree_format(tree_format) - - expected = """\ - - : Parent: None - : Greenlet Locals: - : Local at X - : {'foo': 42} - +--- - : Parent: - +--- ; finished with value - | +--- ; finished with exception ExpectedException() - : Parent: - +--- ; finished with value - | +--- ; finished with exception ExpectedException() - : Parent: - +--- ; finished with value - : Spawn Tree Locals - : {'stl': 'STL'} - | +--- ; finished with value - | +--- ; finished with exception ExpectedException() - : Parent: - +--- >>; finished with value - """.strip() - self.assertEqual(expected, value) - - @greentest.ignores_leakcheck - def test_tree_no_track(self): - gevent.config.track_greenlet_tree = False - with gevent.get_hub().ignoring_expected_test_error(): - self._build_tree() - - @greentest.ignores_leakcheck - def test_forest_fake_parent(self): - from greenlet import greenlet as RawGreenlet - - def t4(): - # Ignore this one, make the child the parent, - # and don't be a child of the hub. - c = RawGreenlet(util.GreenletTree.current_tree) - c.parent.greenlet_tree_is_ignored = True - c.greenlet_tree_is_root = True - return c.switch() - - - g = RawGreenlet(t4) - tree = g.switch() - - tree_format = tree.format(details={'running_stacks': False, - 'spawning_stacks': False}) - value = self._normalize_tree_format(tree_format) - - expected = """\ -; not running - : Parent: - """.strip() - - self.assertEqual(expected, value) - - -class TestAssertSwitches(unittest.TestCase): - - def test_time_sleep(self): - # A real blocking function - from time import sleep - - # No time given, we detect the failure to switch immediately - with self.assertRaises(util._FailedToSwitch) as exc: - with util.assert_switches(): - sleep(0.001) - - message = str(exc.exception) - self.assertIn('To any greenlet in', message) - - # Supply a max blocking allowed and exceed it - with self.assertRaises(util._FailedToSwitch): - with util.assert_switches(0.001): - sleep(0.1) - - - # Supply a max blocking allowed, and exit before that happens, - # but don't switch to the hub as requested - with self.assertRaises(util._FailedToSwitch) as exc: - with util.assert_switches(0.001, hub_only=True): - sleep(0) - - message = str(exc.exception) - self.assertIn('To the hub in', message) - self.assertIn('(max allowed 0.0010 seconds)', message) - - # Supply a max blocking allowed, and exit before that happens, - # and allow any switch (or no switch). - # Note that we need to use a relatively long duration; - # sleep(0) on Windows can actually take a substantial amount of time - # sometimes (more than 0.001s) - with util.assert_switches(1.0, hub_only=False): - sleep(0) - - - def test_no_switches_no_function(self): - # No blocking time given, no switch performed: exception - with self.assertRaises(util._FailedToSwitch): - with util.assert_switches(): - pass - - # blocking time given, for all greenlets, no switch performed: nothing - with util.assert_switches(max_blocking_time=1, hub_only=False): - pass - - def test_exception_not_supressed(self): - - with self.assertRaises(NameError): - with util.assert_switches(): - raise NameError() - - def test_nested(self): - from greenlet import gettrace - with util.assert_switches() as outer: - self.assertEqual(gettrace(), outer.tracer) - self.assertIsNotNone(outer.tracer.active_greenlet) - - with util.assert_switches() as inner: - self.assertEqual(gettrace(), inner.tracer) - self.assertEqual(inner.tracer.previous_trace_function, outer.tracer) - - inner.tracer('switch', (self, self)) - - self.assertIs(self, inner.tracer.active_greenlet) - self.assertIs(self, outer.tracer.active_greenlet) - - self.assertEqual(gettrace(), outer.tracer) - - -class TestFuncs(greentest.TestCase): - - def test_clear_stack_frames(self): - import inspect - import threading - completed = [] - def do_it(): - util.clear_stack_frames(inspect.currentframe()) - completed.append(1) - t = threading.Thread(target=do_it) - t.start() - t.join(10) - self.assertEqual(completed, [1]) - -if __name__ == '__main__': - greentest.main() diff --git a/venv/lib/python3.9/site-packages/gevent/tests/test_server.crt b/venv/lib/python3.9/site-packages/gevent/tests/test_server.crt deleted file mode 100644 index 9fde198..0000000 --- a/venv/lib/python3.9/site-packages/gevent/tests/test_server.crt +++ /dev/null @@ -1,29 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIFCzCCAvOgAwIBAgIUFL7iwYYAfAarNFw2C0Q1zEjC4yUwDQYJKoZIhvcNAQEL -BQAwFDESMBAGA1UEAwwJbG9jYWxob3N0MCAXDTIxMDcwODExMzAwN1oYDzIxMjEw -NjE0MTEzMDA3WjAUMRIwEAYDVQQDDAlsb2NhbGhvc3QwggIiMA0GCSqGSIb3DQEB -AQUAA4ICDwAwggIKAoICAQC2v+TV2yx9DK78LWCLhBKl1g0AcdWi4H9LIbc30RbO -5LOnhL+FxPE9vRU1nD5Z01o7zgqJr8boNqU1oOxhOAyUZkSZwd6SeJHQvLRZQDRI -ov3QCL4nYb53T3usSlXw5MuxUql/OwvLcvPO/8FBXKmIBpfOHHxfAwA7+BU8f8ZF -aDB02sNnLlAXZc9xB1FkDNAZnM9fjWAAJbtfRcJO0l7zq8AQ/EdO6YVK6vhScf/I -ovKcMbDV3GPt8YUSlqLAuIv3rFPclDvpDdp+c96OXA3wK6YhsFBvYmzgRnoVfX8V -FQdp4vlcXsqEh9tPhvDmWvfU2xldbX50I1S9/TIucIxrksY7W9787p4lGEjJTfkF -mfo/jdNcY7GE/sHj7aVbbK753ZEWV3j7ZbO1llweI5m6Qk4nPwd/H2CHIKqRbitZ -Qg7ymGAAoCmbbXnrKI4UUrMysQgtuFYUMKstIMYO8bLAF5npVoVuMg10XxNKgBYC -o0+D/RUaTM2rQRtfcwXeIFXNxDuhvblwTTrW2xG+Z2xVENeFVFAjgqEa4YPdjtxO -A3mlldtrM5lLClvCLvcusw79RMYShC3NwMNmVTN9wdX1Vgmcf401dlXN4LCqIj51 -yIfhB7LD6ll3eAM/qK5gwPPvhz330zfWax8f0lzLRQ1r7l9IY/Y91n7KFRLDy9cD -IQIDAQABo1MwUTAdBgNVHQ4EFgQUGSmTQfHLd9mwvtfNtCJykD8F5jkwHwYDVR0j -BBgwFoAUGSmTQfHLd9mwvtfNtCJykD8F5jkwDwYDVR0TAQH/BAUwAwEB/zANBgkq -hkiG9w0BAQsFAAOCAgEAmeKcbwDzSnZhL9H4oPEzOslTEazn1vRGNTkDabGzHlO1 -b56Mw36fOKW9cPSS9By1HiB3iQipUZ6AQ9pIIBv75Z0yNPxsIqhTpDACWEx8jk/k -rhzCIMIoxURfBAKQ3Oml7U++EagyBZgQAHjGEROuRE++kUDeEy0SwIWiXmEX1OZ4 -tBbaW+Q7Gc+CPHVouOZUq8Ogt9zI98rIiT5VFPm2hBZrcguoqmqSN533HJTJVimi -vCBtkRK3YfsMsZYO0jmj8TWsTAZly3wwgMkjV4g5hLtrYOHU6sm8H32QjDcbahLG -7JCgQR5WCgfs/u2RHFysNwURf/Hq+9ieCEtSQrk4u19YvkwpZxVD9xUONaGNZvPR -ottciZKo4pGShJADtUTnkKJEOYLTgg3jSUJPQ55AzVwAJTudLEyUGPwJL1lJ4nFu -WDSSiZXqoAaD1j2CNGhkzWBT1mJEcvPTuKxDNwYzhF44B0KQSeS3vJtMibELCOZ8 -a4WuR4xFe6fleL4fqHYpjI5IWYUDfFRC8lqvWdJl4oCSMH+s0B/m/FWme3lt+7/K -Z0vOk3uvi09OLQZTTuGgcSVPoO+zzJOuhLzTdO+FzlbBHlZax/iNZQ1GYZ0gk6wY -9+gxqdVZQXy4UIhjHV2TbW8OlhVyRC1O+YN5pjyD884aYLD+JrxZXQtSlNlurcw= ------END CERTIFICATE----- diff --git a/venv/lib/python3.9/site-packages/gevent/tests/test_server.key b/venv/lib/python3.9/site-packages/gevent/tests/test_server.key deleted file mode 100644 index e6c979b..0000000 --- a/venv/lib/python3.9/site-packages/gevent/tests/test_server.key +++ /dev/null @@ -1,52 +0,0 @@ ------BEGIN PRIVATE KEY----- -MIIJQQIBADANBgkqhkiG9w0BAQEFAASCCSswggknAgEAAoICAQC2v+TV2yx9DK78 -LWCLhBKl1g0AcdWi4H9LIbc30RbO5LOnhL+FxPE9vRU1nD5Z01o7zgqJr8boNqU1 -oOxhOAyUZkSZwd6SeJHQvLRZQDRIov3QCL4nYb53T3usSlXw5MuxUql/OwvLcvPO -/8FBXKmIBpfOHHxfAwA7+BU8f8ZFaDB02sNnLlAXZc9xB1FkDNAZnM9fjWAAJbtf -RcJO0l7zq8AQ/EdO6YVK6vhScf/IovKcMbDV3GPt8YUSlqLAuIv3rFPclDvpDdp+ -c96OXA3wK6YhsFBvYmzgRnoVfX8VFQdp4vlcXsqEh9tPhvDmWvfU2xldbX50I1S9 -/TIucIxrksY7W9787p4lGEjJTfkFmfo/jdNcY7GE/sHj7aVbbK753ZEWV3j7ZbO1 -llweI5m6Qk4nPwd/H2CHIKqRbitZQg7ymGAAoCmbbXnrKI4UUrMysQgtuFYUMKst -IMYO8bLAF5npVoVuMg10XxNKgBYCo0+D/RUaTM2rQRtfcwXeIFXNxDuhvblwTTrW -2xG+Z2xVENeFVFAjgqEa4YPdjtxOA3mlldtrM5lLClvCLvcusw79RMYShC3NwMNm -VTN9wdX1Vgmcf401dlXN4LCqIj51yIfhB7LD6ll3eAM/qK5gwPPvhz330zfWax8f -0lzLRQ1r7l9IY/Y91n7KFRLDy9cDIQIDAQABAoICAAml7+rqe1rOxJ5Dtwkmm+Vt -e5o+aE0FFTNeQFIOE+owYNvDQmlJkIL17Jy79v6/DdCCfEPwp8uytt4x9MjdMKzV -CWIkvh91hh1DGTJtFVWQZV4KWB+0JV4fMCRUeF0Tdz2RY6l38JN5Ki4PiqBsx/aK -gpE7J8XMXsLLwjNDe7BGY+iHdDGKXGgf0+ffvwhNNN9lS/17dUoMs+u/vxZyPNkY -hDdhWlJsOcFOznVr11k8YRql9PQVgqEZUzE8CrOqCpm022iV2uPe+14Zt/JEIehA -JbE5ocV/qMfecKuZyI/QYGfSt9+MkZyVn5p/QVCoFNWEC77G/Rock2jEaVXSU1dz -uxiU65WrqMdvcetZ6xzhUB/Bz3N5aevjwmFmPjMHzF4npw2xn2dejPkQ31YeIdOF -a9Z1tWq8q/UHA2RoooM2hCMJjaIwcABSemCbuFw7ZXm3YUzUFMycav9RGcQ8Q/0h -ZPZWo52eVWhQdvI7Xy+gsssBS2/bk+nPgdDDSdprt+IiB1WuL762xB5upcim+cUJ -vrx7CiDo5Fh8kJhgvSHjBCON5A/l6eg8XPX56+MBA3t0frTTub3o0tubJlYSlClF -nqoNHlXczd0vdtoMpSSaBj7N2GL3FtaWi0jbyagK0IndaouMQM8njBQoI0bTmvHg -COfd4uDg4h23jgseqmbBAoIBAQDepq2qASQpQ38qeq586a/YoD4PtZOeapjRNfGj -gnvQaSSouaLoq3dRSlKmZwE4nKnSnCKI4Ixje9Likfbdt4/I+hXODTzEy+WpmqlJ -1x4svF6MsB/YZ6r76koGK8/vgPO/w7xLGp5Xi2E5gTaH04o/PuUo/k7yx0FkSHoA -EU7WDoriH/6sgkolUL6xsmq8ljq4kHidP2UfYwzsIwngTL+jFYznzTsr6CXsTdH9 -I7ppvpS3xhFsdDp0YQyMGHdtvAdEeGz/m6cxxsnwAz0EhwN2qYJD9oNCP+uxk0zD -d1QD/XUUcMUrUxyQ1EBn2wAmcj9yYNeMNmhZYz47CowHym0tAoIBAQDSHzwCpk/M -3h5dk0yMgyRMq+flwj1P+eDOrGpmk9VmdCcvIQs1ArbW0/VMQ+lQNXgTZ74o/ccT -ABogeD1WOq3fh5PcU6wHAVD1GL1sZ6ZCP9jQXalxt0/1vooDu+LRDLNhcsFY0AJR -QfPu37beaCFjlwFf5P0lEPcTTpXBfEaqSvjA2kCys2IMeiKce36GQTy2HJBIe0py -Pj+cgxZ3/lg0vGV6SrnMXh5wPbWtsVnhQBilG7niQ15txSrgV5rUYUQPNEfIuDdS -MVjH1USbjoNAMlwYJF5Kcel9fn6neHfWqvW3bregw598iCg0Y67KbJl4iFzOqumh -lZUy1gD2P65FAoIBADA8P+dSs/jUjJoxVdft8JCntopEtiRdx5mbbCwWOqid/rkm -7molq4XK6jjum88d8ZSVCs5Ih2GOE9PN94N1HwtVUp//MikYWzrxLLe4iOr8LCei -iGOjoeFNkpffqf6jGytyRjqnG6KvqXKB0cR/SbYF9DN7VLM4A6ysHvIgzcmGAQSY -Fd5do56N7aIlmwYcLcCKW/cFIu030jbeKGeVePbl1k7poWYTtxOIkHOc5+e8yA9A -M8ohLADGfadkLYtybsigpkyB9ijMfjcnHHL8pP1yH6yFnU4e9vrThI/cLDFpGZJC -FBUcvlWKBiH5ygCKQ8CNxmSz7Mtguryjvk55xkkCggEAQuwRx+JCXkSMNU95vPLz -t7u0oxfHQVabhBej18HT4MqzxC3pDNwtcaSWZtDmWVZ+ROfwx8t0ARgyOg8xseoE -gMIElNLNYnnH2BgmFIW6jTUaj9qU4hP5UpJ6EJBhwCUkaLAM5oVxh4HS+EymSJWv -tLFejbU37vtFRg/sYHB9bTVtnrakjoXVf5XSujYW6RmUBYh5Z6xk3Jf42Jdjq5oF -a95pD5cHMBD17teoqoZm0vgAIW4AOREt3RZD/qnINUY5UAJdro8Fh5cR6KuDK2wr -X2HqtQG4SkuXixGjsyEKQgO3ONH5iCll/Vq8O1tYSz5lbt83d9c1i/JBT6ybJ9LG -ZQKCAQALlAI1Cd8swU1g5a9newXRHfkOYYlJ/CpKbvblBlc0oejEI6oJAD9ykZrE -v3/6JMojI0J7ILjGj5a1eyGtleqY1JyrO5dy/djueaHHgLQNNYBkGWbdFN99XV9s -iE1iuYthyVKXqMkbhxKcW8L1kyer/Z+o4I3LP4NfMzC9ibhPkjyg6JD2zBT1N49t -26SUApm2Icz54+HVVKHbimfVI6R9NqcVjO7TmQae5UjKeiI8xOiBcjDrtU9K5rj3 -O2IOx7mAEc08Mz8ApLo9dnY0+dmPhprJPcpZl1haAvY3CF50iYTcABbAlk1nVfoo -0OV9kUaHy/EaY8/cPeMERFc/SVZi ------END PRIVATE KEY----- diff --git a/venv/lib/python3.9/site-packages/gevent/tests/tests_that_dont_do_leakchecks.txt b/venv/lib/python3.9/site-packages/gevent/tests/tests_that_dont_do_leakchecks.txt deleted file mode 100644 index b2c3623..0000000 --- a/venv/lib/python3.9/site-packages/gevent/tests/tests_that_dont_do_leakchecks.txt +++ /dev/null @@ -1,10 +0,0 @@ -test___monkey_patching.py -test__monkey_ssl_warning.py -test___monitor.py -test__monkey_scope.py -test__ares_timeout.py -test__close_backend_fd.py -test__hub_join.py -test__hub_join_timeout.py -test__issue112.py -test__issue1864.py diff --git a/venv/lib/python3.9/site-packages/gevent/tests/tests_that_dont_monkeypatch.txt b/venv/lib/python3.9/site-packages/gevent/tests/tests_that_dont_monkeypatch.txt deleted file mode 100644 index 1e68c5d..0000000 --- a/venv/lib/python3.9/site-packages/gevent/tests/tests_that_dont_monkeypatch.txt +++ /dev/null @@ -1,29 +0,0 @@ -test___config.py -test___ident.py -test___monitor.py -test__ares_timeout.py -test__backdoor.py -test__close_backend_fd.py -test__events.py -test__example_echoserver.py -test__example_portforwarder.py -test__example_udp_client.py -test__example_wsgiserver.py -test__example_wsgiserver_ssl.py -test__example_webproxy.py -test__examples.py -test__getaddrinfo_import.py -test__hub_join.py -test__hub_join_timeout.py -test__issue1864.py -test__issue330.py -test__iwait.py -test__monkey_scope.py -test__pywsgi.py -test__server.py -test__server_pywsgi.py -test__socket_close.py -test__socket_dns6.py -test__socket_errors.py -test__socket_send_memoryview.py -test__socket_timeout.py diff --git a/venv/lib/python3.9/site-packages/gevent/tests/tests_that_dont_use_resolver.txt b/venv/lib/python3.9/site-packages/gevent/tests/tests_that_dont_use_resolver.txt deleted file mode 100644 index 79a9127..0000000 --- a/venv/lib/python3.9/site-packages/gevent/tests/tests_that_dont_use_resolver.txt +++ /dev/null @@ -1,137 +0,0 @@ -test__all__.py -#uses socket test__api.py -test__api_timeout.py -test__ares_host_result.py -test__ares_timeout.py # explicitly uses ares resolver -# uses socket test__backdoor.py -test__close_backend_fd.py -test__core_async.py -test__core_callback.py -test__core_loop_run.py -test__core.py -test__core_stat.py -test__core_timer.py -test__core_watcher.py -test__destroy.py -# uses socket test__doctests.py -test__environ.py -test__event.py -# uses socket test__example_echoserver.py -# uses socket test__example_portforwarder.py -# uses socket test__example_w*.py -# uses bunch of things test__examples.py -# uses socket test__example_udp_client.py -# uses socket test__example_udp_server.py -test__exc_info.py -#test__execmodules.py -test__fileobject.py -# uses socket test__greenio.py -test__GreenletExit.py -test__greenlet.py -test__greenletset.py -# uses socket test__greenness.py -test__hub_join.py -test__hub_join_timeout.py -# uses socket test__hub.py -test__issue112.py -test__issue1864.py -test__joinall.py -test__local.py -test__loop_callback.py -test__memleak.py -# uses lots of things test___monkey_patching.py -test__monkey.py -test__order.py -test__os.py -test__pool.py -# uses socket test__pywsgi.py -test__queue.py -test__monkey_queue.py -# uses socket test__refcount.py -test__select.py -test__semaphore.py -# uses socket test__server.py -# test__server_pywsgi.py -test__signal.py -# uses socket test__socket_close.py -# test__socket_dns6.py -# test__socket_dns.py -# test__socket_errors.py -# test__socket.py -# test__socket_ssl.py -# test__socket_timeout.py -test__subprocess_interrupted.py -test__subprocess.py -test__systemerror.py -test__threading_2.py -test__threading_patched_local.py -test__threading_vs_settrace.py -test__threadpool.py -test__timeout.py - -test__compat.py -test__core_fork.py -test__doctests.py -test__core_loop_run_sig_mod.py -test__execmodules.py -test__greenio.py -test__greenness.py -test__hub.py -test__import_blocking_in_greenlet.py -test__import_wait.py -test__issue230.py -test__issue330.py -test__issue467.py -test__issue6.py -test__issue600.py -test__issue607.py -test__issue461_471.py -test__monkey_builtins_future.py -test__monkey_hub_in_thread.py -test__monkey_logging.py -test__monkey_multiple_imports.py -test__monkey_scope.py -test__monkey_selectors.py -test__monkey_sigchld.py -test__monkey_sigchld_2.py -test__nondefaultloop.py -test__monkey_sigchld_3.py -test__real_greenlet.py -test__refcount.py -test__sleep0.py -test__subprocess_poll.py -test__threading.py -test__threading_before_monkey.py -test__threading_holding_lock_while_monkey.py -test__threading_monkey_in_thread.py -test__threading_native_before_monkey.py -test__threadpool_executor_patched.py - - -# monkey patched standard tests: -test_queue.py -test_select.py -test_signal.py -test_subprocess.py -test_threading_local.py -test_threading.py -test_thread.py -test_selectors.py -test_timeout.py - -# test_asyncore probably does use the resolver, but only -# implicitly for localhost, which is covered well enough -# elsewhere that we don't need to spend the 20s (*2) -test_asyncore.py - -test___config.py -test__destroy_default_loop.py -test__util.py -test___ident.py -test__issue639.py -test__issue_728.py -test__refcount_core.py -test__api.py -test__monitor.py -test__events.py -test__iwait.py diff --git a/venv/lib/python3.9/site-packages/gevent/tests/wrongcert.pem b/venv/lib/python3.9/site-packages/gevent/tests/wrongcert.pem deleted file mode 100644 index 5f92f9b..0000000 --- a/venv/lib/python3.9/site-packages/gevent/tests/wrongcert.pem +++ /dev/null @@ -1,32 +0,0 @@ ------BEGIN RSA PRIVATE KEY----- -MIICXAIBAAKBgQC89ZNxjTgWgq7Z1g0tJ65w+k7lNAj5IgjLb155UkUrz0XsHDnH -FlbsVUg2Xtk6+bo2UEYIzN7cIm5ImpmyW/2z0J1IDVDlvR2xJ659xrE0v5c2cB6T -f9lnNTwpSoeK24Nd7Jwq4j9vk95fLrdqsBq0/KVlsCXeixS/CaqqduXfvwIDAQAB -AoGAQFko4uyCgzfxr4Ezb4Mp5pN3Npqny5+Jey3r8EjSAX9Ogn+CNYgoBcdtFgbq -1yif/0sK7ohGBJU9FUCAwrqNBI9ZHB6rcy7dx+gULOmRBGckln1o5S1+smVdmOsW -7zUVLBVByKuNWqTYFlzfVd6s4iiXtAE2iHn3GCyYdlICwrECQQDhMQVxHd3EFbzg -SFmJBTARlZ2GKA3c1g/h9/XbkEPQ9/RwI3vnjJ2RaSnjlfoLl8TOcf0uOGbOEyFe -19RvCLXjAkEA1s+UE5ziF+YVkW3WolDCQ2kQ5WG9+ccfNebfh6b67B7Ln5iG0Sbg -ky9cjsO3jbMJQtlzAQnH1850oRD5Gi51dQJAIbHCDLDZU9Ok1TI+I2BhVuA6F666 -lEZ7TeZaJSYq34OaUYUdrwG9OdqwZ9sy9LUav4ESzu2lhEQchCJrKMn23QJAReqs -ZLHUeTjfXkVk7dHhWPWSlUZ6AhmIlA/AQ7Payg2/8wM/JkZEJEPvGVykms9iPUrv -frADRr+hAGe43IewnQJBAJWKZllPgKuEBPwoEldHNS8nRu61D7HzxEzQ2xnfj+Nk -2fgf1MAzzTRsikfGENhVsVWeqOcijWb6g5gsyCmlRpc= ------END RSA PRIVATE KEY----- ------BEGIN CERTIFICATE----- -MIICsDCCAhmgAwIBAgIJAOqYOYFJfEEoMA0GCSqGSIb3DQEBBQUAMEUxCzAJBgNV -BAYTAkFVMRMwEQYDVQQIEwpTb21lLVN0YXRlMSEwHwYDVQQKExhJbnRlcm5ldCBX -aWRnaXRzIFB0eSBMdGQwHhcNMDgwNjI2MTgxNTUyWhcNMDkwNjI2MTgxNTUyWjBF -MQswCQYDVQQGEwJBVTETMBEGA1UECBMKU29tZS1TdGF0ZTEhMB8GA1UEChMYSW50 -ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKB -gQC89ZNxjTgWgq7Z1g0tJ65w+k7lNAj5IgjLb155UkUrz0XsHDnHFlbsVUg2Xtk6 -+bo2UEYIzN7cIm5ImpmyW/2z0J1IDVDlvR2xJ659xrE0v5c2cB6Tf9lnNTwpSoeK -24Nd7Jwq4j9vk95fLrdqsBq0/KVlsCXeixS/CaqqduXfvwIDAQABo4GnMIGkMB0G -A1UdDgQWBBTctMtI3EO9OjLI0x9Zo2ifkwIiNjB1BgNVHSMEbjBsgBTctMtI3EO9 -OjLI0x9Zo2ifkwIiNqFJpEcwRTELMAkGA1UEBhMCQVUxEzARBgNVBAgTClNvbWUt -U3RhdGUxITAfBgNVBAoTGEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZIIJAOqYOYFJ -fEEoMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADgYEAQwa7jya/DfhaDn7E -usPkpgIX8WCL2B1SqnRTXEZfBPPVq/cUmFGyEVRVATySRuMwi8PXbVcOhXXuocA+ -43W+iIsD9pXapCZhhOerCq18TC1dWK98vLUsoK8PMjB6e5H/O8bqojv0EeC+fyCw -eSHj5jpC8iZKjCHBn+mAi4cQ514= ------END CERTIFICATE----- diff --git a/venv/lib/python3.9/site-packages/gevent/thread.py b/venv/lib/python3.9/site-packages/gevent/thread.py deleted file mode 100644 index 696228b..0000000 --- a/venv/lib/python3.9/site-packages/gevent/thread.py +++ /dev/null @@ -1,360 +0,0 @@ -""" -Implementation of the standard :mod:`thread` module that spawns greenlets. - -.. note:: - - This module is a helper for :mod:`gevent.monkey` and is not - intended to be used directly. For spawning greenlets in your - applications, prefer higher level constructs like - :class:`gevent.Greenlet` class or :func:`gevent.spawn`. -""" -import sys - -__implements__ = [ - 'allocate_lock', - 'get_ident', - 'exit', - 'LockType', - 'stack_size', - 'start_new_thread', - '_local', -] + ([ - 'start_joinable_thread', - 'lock', - '_ThreadHandle', - '_make_thread_handle', -] if sys.version_info[:2] >= (3, 13) else [ - -]) - - -__imports__ = ['error'] - -import _thread as __thread__ # pylint:disable=import-error - -__target__ = '_thread' -__imports__ += [ - 'TIMEOUT_MAX', - 'allocate', - 'exit_thread', - 'interrupt_main', - 'start_new' -] - -# We can't actually produce a value that "may be used -# to identify this particular thread system-wide", right? -# Even if we could, I imagine people will want to pass this to -# non-Python (native) APIs, so we shouldn't mess with it. -__imports__.append('get_native_id') - -# Added to 3.12 -if hasattr(__thread__, 'daemon_threads_allowed'): - __imports__.append('daemon_threads_allowed') - -error = __thread__.error - -from gevent._compat import PYPY -from gevent._util import copy_globals -from gevent.hub import getcurrent -from gevent.hub import GreenletExit -from gevent.hub import sleep -from gevent._hub_local import get_hub_if_exists -from gevent.greenlet import Greenlet -from gevent.lock import BoundedSemaphore -from gevent.local import local as _local -from gevent.exceptions import LoopExit - - -if hasattr(__thread__, 'RLock'): - # Added in Python 3.4, backported to PyPy 2.7-7.0 - __imports__.append("RLock") - - -if hasattr(__thread__, 'set_name'): - # Added in Python 3.14 - __imports__.append('set_name') - - - -def get_ident(gr=None): - if gr is None: - gr = getcurrent() - return id(gr) - - -def _start_new_greenlet(function, args=(), kwargs=None): - if kwargs is not None: - greenlet = Greenlet.spawn(function, *args, **kwargs) # pylint:disable=not-a-mapping - else: - greenlet = Greenlet.spawn(function, *args) - return greenlet - -def start_new_thread(function, args=(), kwargs=None): - return get_ident(_start_new_greenlet(function, args, kwargs)) - -def start_joinable_thread(function, handle=None, daemon=True): # pylint:disable=unused-argument - """ - *For internal use only*: start a new thread. - - Like start_new_thread(), this starts a new thread calling the given function. - Unlike start_new_thread(), this returns a handle object with methods to join - or detach the given thread. - This function is not for third-party code, please use the - `threading` module instead. During finalization the runtime will not wait for - the thread to exit if daemon is True. If handle is provided it must be a - newly created thread._ThreadHandle instance. - """ - # The above docstring is from python 3.13. - # - # _thread._ThreadHandle has: - # - readonly property `ident` - # - method is_done - # - method join - # - method _set_done - threading._shutdown calls this - # - # I have no idea what it means if you pass a provided handle, - # because you can't change the ident once created, and - # the constructor of ThreadHande takes arbitrary positional - # and keyword arguments, and throws them away. (The ident is set - # by C code directly accessing internal structure members). - greenlet = _start_new_greenlet(function) # XXX: Daemon is ignored - - # 3.14 tests require always returning a handle object. - if handle is None: - handle = _ThreadHandle() - elif not isinstance(handle, _ThreadHandle): - raise AssertionError('Must be a gevent thread handle') - elif handle._had_greenlet: - raise RuntimeError('thread already started') - - handle._set_greenlet(greenlet) - - return handle - -class _ThreadHandle: - # The constructor must accept and ignore all arguments - # to match the stdlib. - def __init__(self, *_args, **_kwargs): - """Does nothing; ignores args""" - - # Must keep a weak reference to the greenlet - # to avoid problems managing the _active list of - # threads, which can sometimes rely on garbage collection. - # Also, this breaks a cycle. - _greenlet_ref = None - # We also need to keep track of whether we were ever - # actually bound to a greenlet so that our - # behaviour in 'join' is correct. - _had_greenlet = False - - def _set_greenlet(self, glet): - from weakref import ref - assert glet is not None - self._greenlet_ref = ref(glet) - self._had_greenlet = True - - def _get_greenlet(self): - return ( - self._greenlet_ref() - if self._greenlet_ref is not None - else None - ) - - def join(self, timeout=-1): - # TODO: This is what we patch Thread.join to do on all versions, - # so there's another implementation in gevent.monkey._patch_thread_common. - # UNIFY THEM. - - # Python 3.14 makes timeout optional, defaulting to -1; - # we need that to be None - timeout = None if timeout == -1 else timeout - - if not self._had_greenlet: - raise RuntimeError('thread not started') - glet = self._get_greenlet() - if glet is not None: - if glet is getcurrent(): - raise RuntimeError('Cannot join current thread') - if hasattr(glet, 'join'): - return glet.join(timeout) - # working with a raw greenlet. That - # means it's probably the MainThread, because the main - # greenlet is always raw. But it could also be a dummy - from time import time - - end = None - if timeout: - end = time() + timeout - - while not self.is_done(): - if end is not None and time() > end: - return - sleep(0.001) - return None - - @property - def ident(self): - glet = self._get_greenlet() - if glet is not None: - return get_ident(glet) - return None - - def is_done(self): - glet = self._get_greenlet() - if glet is None: - return True - - return glet.dead - - def _set_done(self, enter_hub=True): - """ - Mark the thread as complete. - - This releases our reference (if any) to our greenlet. - - By default, this will bounce back to the hub so that waiters - in ``join`` can get notified. Set *enter_hub* to false not to - do this. This private API is tightly coupled to our ``threading`` - implementation. - """ - if not self._had_greenlet: - raise RuntimeError('thread not started') - self._greenlet_ref = None - # Let the loop go around so that anyone waiting in - # join() gets to know about it. This is particularly - # important during threading/interpreter shutdown. - if enter_hub: - sleep(0.001) - - - def __repr__(self): - return '<%s.%s at 0x%x greenlet=%r>' % ( - self.__class__.__module__, - self.__class__.__name__, - id(self), - self._get_greenlet() - ) - -def _make_thread_handle(*_args): - """ - Called on 3.13 after forking in the child. - Takes ``(module, ident)``, returns a handle object - with that ident. - """ - # The argument _should_ be a thread identifier int - handle = _ThreadHandle() - handle._set_greenlet(getcurrent()) - return handle - -class LockType(BoundedSemaphore): - """ - The basic lock type. - - .. versionchanged:: 24.10.1 - Subclassing this object is no longer allowed. This matches the - Python 3 API. - """ - # Change the ValueError into the appropriate thread error - # and any other API changes we need to make to match behaviour - _OVER_RELEASE_ERROR = __thread__.error - - if PYPY: - _OVER_RELEASE_ERROR = RuntimeError - - - _TIMEOUT_MAX = __thread__.TIMEOUT_MAX # pylint:disable=no-member - - def __init__(self): # pylint: disable=useless-parent-delegation - """ - .. versionchanged:: 24.10.1 - No longer accepts arguments to pass to the super class. If you - want a semaphore with a different count, use a semaphore class directly. - This matches the Lock API of Python 3 - """ - # Yes, we want to override __init__ (to not take arguments) and yes, - # we need to call super's __init__. Pylint is wrong about this - # being useless; our use is to change the signature. - super().__init__() - - @classmethod - def __init_subclass__(cls): - raise TypeError - - def acquire(self, blocking=True, timeout=-1): - # This is the Python 3 signature. - # On Python 2, Lock.acquire has the signature `Lock.acquire([wait])` - # where `wait` is a boolean that cannot be passed by name, only position. - # so we're fine to use the Python 3 signature. - - # Transform the default -1 argument into the None that our - # semaphore implementation expects, and raise the same error - # the stdlib implementation does. - if timeout == -1: - timeout = None - if not blocking and timeout is not None: - raise ValueError("can't specify a timeout for a non-blocking call") - if timeout is not None: - if timeout < 0: - # in C: if(timeout < 0 && timeout != -1) - raise ValueError("timeout value must be strictly positive") - if timeout > self._TIMEOUT_MAX: - raise OverflowError('timeout value is too large') - - - try: - acquired = BoundedSemaphore.acquire(self, blocking, timeout) - except LoopExit: - # Raised when the semaphore was not trivially ours, and we needed - # to block. Some other thread presumably owns the semaphore, and there are no greenlets - # running in this thread to switch to. So the best we can do is - # release the GIL and try again later. - if blocking: # pragma: no cover - raise - acquired = False - - if not acquired and not blocking and getcurrent() is not get_hub_if_exists(): - # Run other callbacks. This makes spin locks works. - # We can't do this if we're in the hub, which we could easily be: - # printing the repr of a thread checks its tstate_lock, and sometimes we - # print reprs in the hub. - # See https://github.com/gevent/gevent/issues/1464 - - # By using sleep() instead of self.wait(0), we don't force a trip - # around the event loop *unless* we've been running callbacks for - # longer than our switch interval. - sleep() - return acquired - - # Should we implement _is_owned, at least for Python 2? See notes in - # monkey.py's patch_existing_locks. - -allocate_lock = lock = LockType - - -def exit(): - raise GreenletExit - - -if hasattr(__thread__, 'stack_size'): - _original_stack_size = __thread__.stack_size - - def stack_size(size=None): - if size is None: - return _original_stack_size() - if size > _original_stack_size(): - return _original_stack_size(size) - # not going to decrease stack_size, because otherwise other - # greenlets in this thread will suffer -else: - __implements__.remove('stack_size') - -__imports__ = copy_globals(__thread__, globals(), - only_names=__imports__, - ignore_missing_names=True) - -__all__ = __implements__ + __imports__ -__all__.remove('_local') - - -# XXX interrupt_main -# XXX _count() diff --git a/venv/lib/python3.9/site-packages/gevent/threading.py b/venv/lib/python3.9/site-packages/gevent/threading.py deleted file mode 100644 index 17a7b76..0000000 --- a/venv/lib/python3.9/site-packages/gevent/threading.py +++ /dev/null @@ -1,480 +0,0 @@ -""" -Implementation of the standard :mod:`threading` using greenlets. - -.. note:: - - This module is a helper for :mod:`gevent.monkey` and is not - intended to be used directly. For spawning greenlets in your - applications, prefer higher level constructs like - :class:`gevent.Greenlet` class or :func:`gevent.spawn`. Attributes - in this module like ``__threading__`` are implementation artifacts subject - to change at any time. - -.. versionchanged:: 1.2.3 - - Defer adjusting the stdlib's list of active threads until we are - monkey patched. Previously this was done at import time. We are - documented to only be used as a helper for monkey patching, so this should - functionally be the same, but some applications ignore the documentation and - directly import this module anyway. - - A positive consequence is that ``import gevent.threading, - threading; threading.current_thread()`` will no longer return a DummyThread - before monkey-patching. -""" - - -import os -import sys - -PY313 = sys.version_info[:2] >= (3, 13) - -__implements__ = [ - 'local', - '_allocate_lock', - 'Lock', - '_get_ident', - '_sleep', - '_DummyThread', - # RLock cannot go here, even though we need to import it. - # If it goes here, it replaces the RLock from the native - # threading module, but we really just need it here when some - # things import this module. - #'RLock', -] + ([ - '_start_new_thread', -] if not PY313 else [ - '_start_joinable_thread', - '_ThreadHandle', - '_make_thread_handle', -]) - - -__extensions__ = [ -] - - -import threading as __threading__ # imports os, sys, _thread, functools, time, itertools -_DummyThread_ = __threading__._DummyThread -_MainThread_ = __threading__._MainThread - - -from gevent.local import local -from gevent.thread import start_new_thread as _start_new_thread -from gevent.thread import start_joinable_thread -from gevent.thread import _ThreadHandle -from gevent.thread import _make_thread_handle -from gevent.thread import allocate_lock as _allocate_lock -from gevent.thread import get_ident as _get_ident -from gevent.hub import sleep as _sleep, getcurrent -from gevent.lock import RLock - - -from gevent._util import LazyOnClass - -# Exports, prevent unused import warnings. -# XXX: Why don't we use __all__? -local = local -start_new_thread = _start_new_thread -_start_joinable_thread = start_joinable_thread -_make_thread_handle = _make_thread_handle -_ThreadHandle = _ThreadHandle -allocate_lock = _allocate_lock -_get_ident = _get_ident -_sleep = _sleep -getcurrent = getcurrent - -Lock = _allocate_lock -RLock = RLock - - -def _cleanup(g): - __threading__._active.pop(_get_ident(g), None) - -def _make_cleanup_id(gid): - def _(_r): - __threading__._active.pop(gid, None) - return _ - -_weakref = None - - -class _DummyThread(_DummyThread_): - # We avoid calling the superclass constructor. This makes us about - # twice as fast: - # - # - 1.16 vs 0.68usec on PyPy (unknown version, older Intel mac) - # - 29.3 vs 17.7usec on CPython 2.7 (older intel Mac) - # - 0.98 vs 2.95usec on CPython 3.12.2 (newer M2 mac) - # - # It als has the important effect of avoiding allocation and then - # immediate deletion of _Thread__block, a lock. This is especially - # important on PyPy where locks go through the cpyext API and - # Cython, which is known to be slow and potentially buggy (e.g., - # https://bitbucket.org/pypy/pypy/issues/2149/memory-leak-for-python-subclass-of-cpyext#comment-22347393) - - # These objects are constructed quite frequently in some cases, so - # the optimization matters: for example, in gunicorn, which uses - # pywsgi.WSGIServer, most every request is handled in a new greenlet, - # and every request uses a logging.Logger to write the access log, - # and every call to a log method captures the current thread (by - # default). - # - # (Obviously we have to duplicate the effects of the constructor, - # at least for external state purposes, which is potentially - # slightly fragile.) - - # For the same reason, instances of this class will cleanup their own entry - # in ``threading._active`` - - # This class also solves a problem forking process with subprocess: after forking, - # Thread.__stop is called, which throws an exception when __block doesn't - # exist. - - # Capture the static things as class vars to save on memory/ - # construction time. - # In Py2, they're all private; in Py3, they become protected - _Thread__stopped = _is_stopped = _stopped = False - _Thread__initialized = _initialized = True - _Thread__daemonic = _daemonic = True - _Thread__args = _args = () - _Thread__kwargs = _kwargs = None - _Thread__target = _target = None - _Thread_ident = _ident = None - _Thread__started = _started = __threading__.Event() - _Thread__started.set() - _tstate_lock = None - - - def __init__(self): # pylint:disable=super-init-not-called - #_DummyThread_.__init__(self) - - # It'd be nice to use a pattern like "greenlet-%d", but there are definitely - # third-party libraries checking thread names to detect DummyThread objects. - self._name = self._Thread__name = __threading__._newname("Dummy-%d") - # All dummy threads in the same native thread share the same ident - # (that of the native thread), unless we're monkey-patched. - self._set_ident() - # 3.13 introduced ``Thread._handle``; - # 3.14 renamed ``Thread._handle`` to ``Thread._os_thread_handle`` to avoid - # conflicts with subclasses. This was intended to be backported to 3.13.4, - # but was controversial and didn't wind up in the final release. - # To avoid issues should the coredevs change their mind again, - # we'll use a private attribute along with a dynamic __getattr__; - # since that isn't invoked if the attribute can otherwise be found, this - # should be safe for subclassers. - # There's no need for this to be available as a class attribute; - # it isn't in the stdlib. - # - # Always set this, no matter the version, for consistency and to - # be able to rely on this attribute distinguishing our objects. - # Note that the name is tightly coupled to our ForkHooks. - # See: - # https://github.com/python/cpython/issues/132578 - # https://github.com/python/cpython/pull/132696 - self.__ghandle = _make_thread_handle(self._ident) - # ``_native_id`` backs the ``native_id`` property, - # when available. - try: - self._native_id = __threading__.get_native_id() - except AttributeError: # pragma: no cover - pass - - g = getcurrent() - gid = _get_ident(g) - __threading__._active[gid] = self - rawlink = getattr(g, 'rawlink', None) - if rawlink is not None: - # raw greenlet.greenlet greenlets don't - # have rawlink... - rawlink(_cleanup) - else: - # ... so for them we use weakrefs. - # See https://github.com/gevent/gevent/issues/918 - ref = self.__weakref_ref - ref = ref(g, _make_cleanup_id(gid)) # pylint:disable=too-many-function-args - self.__raw_ref = ref - assert self.__raw_ref is ref # prevent pylint thinking its unused - - - __ghandle_prop = property( - lambda self: self.__ghandle, - # Ugh, allowing assignment to this is a foot gun, - # but the stdlib allows it, so... - lambda self, new_value: setattr(self, '_DummyThread__ghandle', new_value), - # Likewise. - lambda self: delattr(self, '_DummyThread__ghandle') - ) - - # Dynamically determine what the public name should be. We've already imported - # stdlib threading and initialized its data structures, so accessing - # ``main_thread()`` doesn't introduce any new thread object creation or - # data structure manipulation; in short, it's safe. - if hasattr(__threading__.main_thread(), '_handle'): - _handle = __ghandle_prop - _G_HANDLE_NAME = '_handle' - elif hasattr(__threading__.main_thread(), '_os_thread_handle'): - _os_thread_handle = __ghandle_prop - _G_HANDLE_NAME = '_os_thread_handle' - else: - assert not PY313 - _G_HANDLE_NAME = None - del __ghandle_prop - - def _Thread__stop(self): - pass - - _stop = _Thread__stop # py3 - - def _wait_for_tstate_lock(self, *args, **kwargs): # pylint:disable=signature-differs - pass - - @LazyOnClass - def __weakref_ref(self): - return __import__('weakref').ref - - # In Python 3.11.8+ and 3.12.2+ (yes, minor patch releases), - # CPython's ``threading._after_fork`` hook began swizzling the - # type of the _DummyThread into _MainThread if such a dummy thread - # was the current thread when ``os.fork()`` gets called. - # From CPython's perspective, that's a more-or-less fine thing to do. - # While _DummyThread isn't a subclass of _MainThread, they are both - # subclasses of Thread, and _MainThread doesn't add any new instance - # variables. - # - # From gevent's perspective, that's NOT good. Our _DummyThread - # doesn't have all the instance variables that Thread does, and so - # attempting to do anything with this now-fake _MainThread doesn't work. - # You in fact immediately get assertion errors from inside ``_after_fork``. - # Now, these are basically harmless --- they're printed, and they prevent the cleanup - # of some globals in _threading, but that probably doesn't matter --- but - # people complained, and it could break some test scenarios (due to unexpected - # output on stderr, for example) - # - # We thought of a few options to patch around this: - # - # - Live with the performance penalty. Newer CPythons are making it - # harder and harder to perform well, so if we can possibly avoid - # adding our own performance regressions, that would be good. - # - # - ``after_fork`` uses ``isinstance(current, _DummyThread)`` - # before swizzling, so we could use a metaclass to make that - # check return false. That's a fairly large compatibility risk, - # both because of the use of a metaclass (what if some other - # subclass of _DummyTHread is using an incompatible metaclass?) - # and the change in ``isinstance`` behaviour. We could limit the latter - # to a window around the fork, using ``os.register_at_fork(before, after_in_parent=)``, - # but that's a lot of moving pieces requiring the use of a global or class - # variable to track state. - # - # - We could copy the ivars of the current main thread into the - # _DummyThread in ``register_at_fork(before=)``. That appears to - # work, but also requires the use of - # ``register_at_fork(after_in_parent=)`` to reverse it. - # - # - We could simply prevent swizzling the class in the first - # place. In combination with - # ``register_at_fork(after_in_child=)`` to establish a *real* - # new _MainThread, that's a clean solution. Establishing a real - # new _MainThread is something that CPython itself is prepared - # to do if it can't figure out what the current thread is. The - # compatibility risk of this is relatively low: swizzling - # classes is frowned upon and uncommon, and we can limit it to - # just preventing this specific case. And if somebody was - # attempting this already with some other thread subclass, it - # would (probably?) have the exact same issues, so we can be pretty - # sure nobody is doing that. - # - # We're initially going with the last fix; the __class__ part is here, - # the ``after_in_child`` fixup we only apply if we're monkey-patching. - # - # Now, all of this is moot in 3.13, which takes a very different - # approach to handling this, and also changes some names. See - # https://github.com/python/cpython/commit/0e9c364f4ac18a2237bdbac702b96bcf8ef9cb09 - - # Tests pass just fine in 3.8 (and presumably 3.9 and 3.10) with these fixes - # applied, but just in case, we only do it where we know it's necessary. - _NEEDS_CLASS_FORK_FIXUP = ( - (sys.version_info[:2] == (3, 11) and sys.version_info[:3] >= (3, 11, 8)) - or sys.version_info[:3] >= (3, 12, 2) - ) - - if _NEEDS_CLASS_FORK_FIXUP: - # Override with a property, as opposed to using __setattr__, - # to avoid adding overhead on any other attribute setting. - @property - def __class__(self): - return type(self) - - @__class__.setter - def __class__(self, new_class): - # Even if we wanted to allow setting this, I'm not sure - # exactly how to do so when we have a property object handling it. - # Getting the descriptor from ``object.__dict__['__class__']`` - # and using its ``__set__`` method raises a TypeError (as does - # the simpler ``super().__class__``). - # - # Better allow the TypeError for now as opposed to silently ignoring - # the assignment. - if new_class is not _MainThread_: - object.__dict__['__class__'].__set__(self, new_class) - - - - - - -def main_native_thread(): - return __threading__.main_thread() # pylint:disable=no-member - - -# XXX: Issue 18808 breaks us on Python 3.4+. -# Thread objects now expect a callback from the interpreter itself -# (threadmodule.c:release_sentinel) when the C-level PyThreadState -# object is being deallocated. Because this never happens -# when a greenlet exits, join() and friends will block forever. -# Fortunately this is easy to fix: just ensure that the allocation of the -# lock, _set_sentinel, creates a *gevent* lock, and release it when -# we're done. The main _shutdown code is in Python and deals with -# this gracefully. - -class Thread(__threading__.Thread): - - # Only happens in < 3.13 - def _set_tstate_lock(self): - super(Thread, self)._set_tstate_lock() - greenlet = getcurrent() - greenlet.rawlink(self.__greenlet_finished) - - def __greenlet_finished(self, _): - if self._tstate_lock: - self._tstate_lock.release() - self._stop() - -__implements__.append('Thread') - -class Timer(Thread, __threading__.Timer): # pylint:disable=abstract-method,inherit-non-class - pass - -__implements__.append('Timer') - -_set_sentinel = allocate_lock -if sys.version_info[:2] < (3, 13): - __implements__.append('_set_sentinel') -else: - __extensions__.append('_set_sentinel') -# The main thread is patched up with more care -# in _gevent_will_monkey_patch - -__implements__.remove('_get_ident') -__implements__.append('get_ident') -get_ident = _get_ident -__implements__.remove('_sleep') - -if hasattr(__threading__, '_CRLock'): - # Python 3 changed the implementation of threading.RLock - # Previously it was a factory function around threading._RLock - # which in turn used _allocate_lock. Now, it wants to use - # threading._CRLock, which is imported from _thread.RLock and as such - # is implemented in C. So it bypasses our _allocate_lock function. - # Fortunately they left the Python fallback in place and use it - # if the imported _CRLock is None; this arranges for that to be the case. - - # This was also backported to PyPy 2.7-7.0 - _CRLock = None - __implements__.append('_CRLock') - - -class _ForkHooks: - - _before_fork_current_thread = None - _before_fork_active = None - _before_fork_ident = None - - def before_fork_in_parent(self): - self._before_fork_active = dict(__threading__._active) - self._before_fork_current_thread = __threading__.current_thread() - self._before_fork_ident = get_ident() - - def _stop_running_greenlets_in_child(self): - # We cannot actually kill the greenlets via throw(): - # - If it was the main greenlet, the process will exit - # - In any case, that would unwind the stack and execute - # code that, before 2024-10-03, would never have executed. - # - # But we can take them out of the map and make them appear - # stopped; if they truly are no longer referenced, GC will - # kick in and delete the greenlet. If gevent is still waiting - # to switch to them, that will still happen... - # - # This happens automatically on <= 3.12 which hardcodes the call to - # ``Thread._stop``; for 3.13, we need to go through the handle. - if not _DummyThread._G_HANDLE_NAME: - return - current_ident = get_ident() - for green_ident, thread in self._before_fork_active.items(): - if green_ident == current_ident: - continue - - try: - # Either a _DummyThread from above, or a "real" ``threading.Thread``, using - # our ThreadHandle object - handle = getattr( - thread, '_DummyThread__ghandle', - getattr(thread, _DummyThread._G_HANDLE_NAME) - ) - except AttributeError: # pragma: no cover - # We really shouldn't get here; on this platform, - # _G_HANDLE_NAME should be none. - assert sys.version_info[:2] < (3, 13) - assert not thread.is_alive() - else: - # We DO NOT want to bounce to the hub. We're running - # at a very sensitive time and it's best to keep tight control - # over what gets to run. - handle._set_done(enter_hub=False) - - - def after_fork_in_child(self): - # We've already imported threading, which installed its "after" hook, - # so we're going to be called after that hook. - # Note that this is only installed when monkey-patching. - active = __threading__._active - assert len(active) == 1 - assert __threading__.current_thread() is self._before_fork_current_thread - assert get_ident() == self._before_fork_ident - - self._stop_running_greenlets_in_child() - - main = __threading__._MainThread() - main._ident = get_ident() # 3.13: reset to the greenlet version. - __threading__._active[__threading__.get_ident()] = main - __threading__._main_thread = main - - main = __threading__.main_thread() - assert main.ident == __threading__.get_ident() - -_fork_hooks = _ForkHooks() - -def _gevent_will_monkey_patch(native_module, items, warn): # pylint:disable=unused-argument - # Make sure the MainThread can be found by our current greenlet ID, - # otherwise we get a new DummyThread, which cannot be joined. - # Fixes tests in test_threading_2 under PyPy. - main_thread = main_native_thread() - if __threading__.current_thread() != main_thread: - warn("Monkey-patching outside the main native thread. Some APIs " - "will not be available. Expect a KeyError to be printed at shutdown.") - return - - if _get_ident() not in __threading__._active: - main_id = main_thread.ident - del __threading__._active[main_id] - main_thread._ident = main_thread._Thread__ident = _get_ident() - __threading__._active[_get_ident()] = main_thread - - register_at_fork = getattr(os, 'register_at_fork', None) - if register_at_fork: - #if _DummyThread._NEEDS_CLASS_FORK_FIXUP: - register_at_fork( - before=_fork_hooks.before_fork_in_parent, - after_in_child=_fork_hooks.after_fork_in_child) diff --git a/venv/lib/python3.9/site-packages/gevent/threadpool.py b/venv/lib/python3.9/site-packages/gevent/threadpool.py deleted file mode 100644 index afbc868..0000000 --- a/venv/lib/python3.9/site-packages/gevent/threadpool.py +++ /dev/null @@ -1,819 +0,0 @@ -# Copyright (c) 2012 Denis Bilenko. See LICENSE for details. -from __future__ import absolute_import -from __future__ import division -from __future__ import print_function - -import os -import sys - - -from greenlet import greenlet as RawGreenlet - -from gevent import monkey -from gevent._compat import integer_types -from gevent.event import AsyncResult -from gevent.exceptions import InvalidThreadUseError -from gevent.greenlet import Greenlet - -from gevent._hub_local import get_hub_if_exists -from gevent.hub import _get_hub_noargs as get_hub -from gevent.hub import getcurrent -from gevent.hub import sleep -from gevent.lock import Semaphore -from gevent.pool import GroupMappingMixin -from gevent.util import clear_stack_frames - -from gevent._threading import Queue -from gevent._threading import EmptyTimeout -from gevent._threading import start_new_thread -from gevent._threading import get_thread_ident - - -__all__ = [ - 'ThreadPool', - 'ThreadResult', -] - -def _format_hub(hub): - if hub is None: - return '' - return '<%s at 0x%x thread_ident=0x%x>' % ( - hub.__class__.__name__, id(hub), hub.thread_ident - ) - - -def _get_thread_profile(_sys=sys): - if 'threading' in _sys.modules: - return _sys.modules['threading']._profile_hook - - -def _get_thread_trace(_sys=sys): - if 'threading' in _sys.modules: - return _sys.modules['threading']._trace_hook - - -class _WorkerGreenlet(RawGreenlet): - # Exists to produce a more useful repr for worker pool - # threads/greenlets, and manage the communication of the worker - # thread with the threadpool. - - # Inform the gevent.util.GreenletTree that this should be - # considered the root (for printing purposes) - greenlet_tree_is_root = True - - _thread_ident = 0 - _exc_info = sys.exc_info - _get_hub_if_exists = staticmethod(get_hub_if_exists) - # We capture the hub each time through the loop in case its created - # so we can destroy it after a fork. - _hub_of_worker = None - # The hub of the threadpool we're working for. Just for info. - _hub = None - - # A cookie passed to task_queue.get() - _task_queue_cookie = None - - # If not -1, how long to block waiting for a task before we - # exit. - _idle_task_timeout = -1 - - def __init__(self, threadpool): - # Construct in the main thread (owner of the threadpool) - # The parent greenlet and thread identifier will be set once the - # new thread begins running. - RawGreenlet.__init__(self) - - self._hub = threadpool.hub - # Avoid doing any imports in the background thread if it's not - # necessary (monkey.get_original imports if not patched). - # Background imports can hang Python 2 (gevent's thread resolver runs in the BG, - # and resolving may have to import the idna module, which needs an import lock, so - # resolving at module scope) - if monkey.is_module_patched('sys'): - stderr = monkey.get_original('sys', 'stderr') - else: - stderr = sys.stderr - self._stderr = stderr - # We can capture the task_queue; even though it can change if the threadpool - # is re-innitted, we won't be running in that case - self._task_queue = threadpool.task_queue # type:gevent._threading.Queue - self._task_queue_cookie = self._task_queue.allocate_cookie() - self._unregister_worker = threadpool._unregister_worker - self._idle_task_timeout = threadpool._idle_task_timeout - - threadpool._register_worker(self) - try: - start_new_thread(self._begin, ()) - except: - self._unregister_worker(self) - raise - - def _begin(self, _get_c=getcurrent, _get_ti=get_thread_ident): - # Pass arguments to avoid accessing globals during module shutdown. - - # we're in the new thread (but its root greenlet). Establish invariants and get going - # by making this the current greenlet. - self.parent = _get_c() # pylint:disable=attribute-defined-outside-init - self._thread_ident = _get_ti() - # ignore the parent attribute. (We can't set parent to None.) - self.parent.greenlet_tree_is_ignored = True - try: - self.switch() # goto run() - except: # pylint:disable=bare-except - # run() will attempt to print any exceptions, but that might - # not work during shutdown. sys.excepthook and such may be gone, - # so things might not get printed at all except for a cryptic - # message. This is especially true on Python 2 (doesn't seem to be - # an issue on Python 3). - pass - - def __fixup_hub_before_block(self): - hub = self._get_hub_if_exists() # Don't create one; only set if a worker function did it - if hub is not None: - hub.name = 'ThreadPool Worker Hub' - # While we block, don't let the monitoring thread, if any, - # report us as blocked. Indeed, so long as we never - # try to switch greenlets, don't report us as blocked--- - # the threadpool is *meant* to run blocking tasks - if hub is not None and hub.periodic_monitoring_thread is not None: - hub.periodic_monitoring_thread.ignore_current_greenlet_blocking() - self._hub_of_worker = hub - - @staticmethod - def __print_tb(tb, stderr): - # Extracted from traceback to avoid accessing any module - # globals (these sometimes happen during interpreter shutdown; - # see test__subprocess_interrupted) - while tb is not None: - f = tb.tb_frame - lineno = tb.tb_lineno - co = f.f_code - filename = co.co_filename - name = co.co_name - print(' File "%s", line %d, in %s' % (filename, lineno, name), - file=stderr) - tb = tb.tb_next - - def _before_run_task(self, func, args, kwargs, thread_result, - _sys=sys, - _get_thread_profile=_get_thread_profile, - _get_thread_trace=_get_thread_trace): - # pylint:disable=unused-argument - _sys.setprofile(_get_thread_profile()) - _sys.settrace(_get_thread_trace()) - - def _after_run_task(self, func, args, kwargs, thread_result, _sys=sys): - # pylint:disable=unused-argument - _sys.setprofile(None) - _sys.settrace(None) - - def __run_task(self, func, args, kwargs, thread_result): - self._before_run_task(func, args, kwargs, thread_result) - try: - thread_result.set(func(*args, **kwargs)) - except: # pylint:disable=bare-except - thread_result.handle_error((self, func), self._exc_info()) - finally: - self._after_run_task(func, args, kwargs, thread_result) - del func, args, kwargs, thread_result - - def run(self): - # pylint:disable=too-many-branches - task = None - exc_info = sys.exc_info - fixup_hub_before_block = self.__fixup_hub_before_block - task_queue_get = self._task_queue.get - task_queue_cookie = self._task_queue_cookie - run_task = self.__run_task - task_queue_done = self._task_queue.task_done - idle_task_timeout = self._idle_task_timeout - try: # pylint:disable=too-many-nested-blocks - while 1: # tiny bit faster than True on Py2 - fixup_hub_before_block() - - try: - task = task_queue_get(task_queue_cookie, idle_task_timeout) - except EmptyTimeout: - # Nothing to do, exit the thread. Do not - # go into the next block where we would call - # queue.task_done(), because we didn't actually - # take a task. - return - try: - if task is None: - return - - run_task(*task) - except: - task = repr(task) - raise - finally: - task = None if not isinstance(task, str) else task - task_queue_done() - except Exception as e: # pylint:disable=broad-except - print( - "Failed to run worker thread. Task=%r Exception=%r" % ( - task, e - ), - file=self._stderr) - self.__print_tb(exc_info()[-1], self._stderr) - finally: - # Re-check for the hub in case the task created it but then - # failed. - self.cleanup(self._get_hub_if_exists()) - - def cleanup(self, hub_of_worker): - if self._hub is not None: - self._hub = None - self._unregister_worker(self) - self._unregister_worker = lambda _: None - self._task_queue = None - self._task_queue_cookie = None - - if hub_of_worker is not None: - hub_of_worker.destroy(True) - - def __repr__(self, _format_hub=_format_hub): - return "" % ( - id(self), - self._thread_ident, - _format_hub(self._hub) - ) - - -class ThreadPool(GroupMappingMixin): - """ - A pool of native worker threads. - - This can be useful for CPU intensive functions, or those that - otherwise will not cooperate with gevent. The best functions to execute - in a thread pool are small functions with a single purpose; ideally they release - the CPython GIL. Such functions are extension functions implemented in C. - - It implements the same operations as a :class:`gevent.pool.Pool`, - but using threads instead of greenlets. - - .. note:: The method :meth:`apply_async` will always return a new - greenlet, bypassing the threadpool entirely. - - Most users will not need to create instances of this class. Instead, - use the threadpool already associated with gevent's hub:: - - pool = gevent.get_hub().threadpool - result = pool.spawn(lambda: "Some func").get() - - .. important:: It is only possible to use instances of this class from - the thread running their hub. Typically that means from the thread that - created them. Using the pattern shown above takes care of this. - - There is no gevent-provided way to have a single process-wide limit on the - number of threads in various pools when doing that, however. The suggested - way to use gevent and threadpools is to have a single gevent hub - and its one threadpool (which is the default without doing any extra work). - Only dispatch minimal blocking functions to the threadpool, functions that - do not use the gevent hub. - - The `len` of instances of this class is the number of enqueued - (unfinished) tasks. - - Just before a task starts running in a worker thread, - the values of :func:`threading.setprofile` and :func:`threading.settrace` - are consulted. Any values there are installed in that thread for the duration - of the task (using :func:`sys.setprofile` and :func:`sys.settrace`, respectively). - (Because worker threads are long-lived and outlast any given task, this arrangement - lets the hook functions change between tasks, but does not let them see the - bookkeeping done by the worker thread itself.) - - .. caution:: Instances of this class are only true if they have - unfinished tasks. - - .. versionchanged:: 1.5a3 - The undocumented ``apply_e`` function, deprecated since 1.1, - was removed. - .. versionchanged:: 20.12.0 - Install the profile and trace functions in the worker thread while - the worker thread is running the supplied task. - .. versionchanged:: 22.08.0 - Add the option to let idle threads expire and be removed - from the pool after *idle_task_timeout* seconds (-1 for no - timeout) - """ - - __slots__ = ( - 'hub', - '_maxsize', - # A Greenlet that runs to adjust the number of worker - # threads. - 'manager', - # The PID of the process we were created in. - # Used to help detect a fork and then re-create - # internal state. - 'pid', - 'fork_watcher', - # A semaphore initialized with ``maxsize`` counting the - # number of available worker threads we have. As a - # gevent.lock.Semaphore, this is only safe to use from a single - # native thread. - '_available_worker_threads_greenlet_sem', - # A set of running or pending _WorkerGreenlet objects; - # we rely on the GIL for thread safety. - '_worker_greenlets', - # The task queue is itself safe to use from multiple - # native threads. - 'task_queue', - '_idle_task_timeout', - ) - - _WorkerGreenlet = _WorkerGreenlet - - def __init__(self, maxsize, hub=None, idle_task_timeout=-1): - if hub is None: - hub = get_hub() - self.hub = hub - self.pid = os.getpid() - self.manager = None - self.task_queue = Queue() - self.fork_watcher = None - self._idle_task_timeout = idle_task_timeout - - self._worker_greenlets = set() - self._maxsize = 0 - # Note that by starting with 1, we actually allow - # maxsize + 1 tasks in the queue. - self._available_worker_threads_greenlet_sem = Semaphore(1, hub) - self._set_maxsize(maxsize) - self.fork_watcher = hub.loop.fork(ref=False) - - def _register_worker(self, worker): - self._worker_greenlets.add(worker) - - def _unregister_worker(self, worker): - self._worker_greenlets.discard(worker) - - def _set_maxsize(self, maxsize): - if not isinstance(maxsize, integer_types): - raise TypeError('maxsize must be integer: %r' % (maxsize, )) - if maxsize < 0: - raise ValueError('maxsize must not be negative: %r' % (maxsize, )) - difference = maxsize - self._maxsize - self._available_worker_threads_greenlet_sem.counter += difference - self._maxsize = maxsize - self.adjust() - # make sure all currently blocking spawn() start unlocking if maxsize increased - self._available_worker_threads_greenlet_sem._start_notify() - - def _get_maxsize(self): - return self._maxsize - - maxsize = property(_get_maxsize, _set_maxsize, doc="""\ - The maximum allowed number of worker threads. - - This is also (approximately) a limit on the number of tasks that - can be queued without blocking the waiting greenlet. If this many - tasks are already running, then the next greenlet that submits a task - will block waiting for a task to finish. - """) - - def __repr__(self, _format_hub=_format_hub): - return '<%s at 0x%x tasks=%s size=%s maxsize=%s hub=%s>' % ( - self.__class__.__name__, - id(self), - len(self), self.size, self.maxsize, - _format_hub(self.hub), - ) - - def __len__(self): - # XXX just do unfinished_tasks property - # Note that this becomes the boolean value of this class, - # that's probably not what we want! - return self.task_queue.unfinished_tasks - - def _get_size(self): - return len(self._worker_greenlets) - - def _set_size(self, size): - if size < 0: - raise ValueError('Size of the pool cannot be negative: %r' % (size, )) - if size > self._maxsize: - raise ValueError('Size of the pool cannot be bigger than maxsize: %r > %r' % (size, self._maxsize)) - if self.manager: - self.manager.kill() - while len(self._worker_greenlets) < size: - self._add_thread() - delay = self.hub.loop.approx_timer_resolution - while len(self._worker_greenlets) > size: - while len(self._worker_greenlets) - size > self.task_queue.unfinished_tasks: - self.task_queue.put(None) - if getcurrent() is self.hub: - break - sleep(delay) - delay = min(delay * 2, .05) - if self._worker_greenlets: - self.fork_watcher.start(self._on_fork) - else: - self.fork_watcher.stop() - - size = property(_get_size, _set_size, doc="""\ - The number of running pooled worker threads. - - Setting this attribute will add or remove running - worker threads, up to `maxsize`. - - Initially there are no pooled running worker threads, and - threads are created on demand to satisfy concurrent - requests up to `maxsize` threads. - """) - - - def _on_fork(self): - # fork() only leaves one thread; also screws up locks; - # let's re-create locks and threads, and do our best to - # clean up any worker threads left behind. - # NOTE: See comment in gevent.hub.reinit. - pid = os.getpid() - if pid != self.pid: - # The OS threads have been destroyed, but the Python - # objects may live on, creating refcount "leaks". Python 2 - # leaves dead frames (those that are for dead OS threads) - # around; Python 3.8 does not. - thread_ident_to_frame = dict(sys._current_frames()) - for worker in list(self._worker_greenlets): - frame = thread_ident_to_frame.get(worker._thread_ident) - clear_stack_frames(frame) - worker.cleanup(worker._hub_of_worker) - # We can't throw anything to the greenlet, nor can we - # switch to it or set a parent. Those would all be cross-thread - # operations, which aren't allowed. - worker.__dict__.clear() - - # We've cleared f_locals and on Python 3.4, possibly the actual - # array locals of the stack frame, but the task queue may still be - # referenced if we didn't actually get all the locals. Shut it down - # and clear it before we throw away our reference. - self.task_queue.kill() - self.__init__(self._maxsize) - - - def join(self): - """Waits until all outstanding tasks have been completed.""" - delay = max(0.0005, self.hub.loop.approx_timer_resolution) - while self.task_queue.unfinished_tasks > 0: - sleep(delay) - delay = min(delay * 2, .05) - - def kill(self): - self.size = 0 - self.fork_watcher.close() - - def _adjust_step(self): - # if there is a possibility & necessity for adding a thread, do it - while (len(self._worker_greenlets) < self._maxsize - and self.task_queue.unfinished_tasks > len(self._worker_greenlets)): - self._add_thread() - # while the number of threads is more than maxsize, kill one - # we do not check what's already in task_queue - it could be all Nones - while len(self._worker_greenlets) - self._maxsize > self.task_queue.unfinished_tasks: - self.task_queue.put(None) - if self._worker_greenlets: - self.fork_watcher.start(self._on_fork) - elif self.fork_watcher is not None: - self.fork_watcher.stop() - - def _adjust_wait(self): - delay = self.hub.loop.approx_timer_resolution - while True: - self._adjust_step() - if len(self._worker_greenlets) <= self._maxsize: - return - sleep(delay) - delay = min(delay * 2, .05) - - def adjust(self): - self._adjust_step() - if not self.manager and len(self._worker_greenlets) > self._maxsize: - # might need to feed more Nones into the pool to shutdown - # threads. - self.manager = Greenlet.spawn(self._adjust_wait) - - def _add_thread(self): - self._WorkerGreenlet(self) - - def spawn(self, func, *args, **kwargs): - """ - Add a new task to the threadpool that will run ``func(*args, - **kwargs)``. - - Waits until a slot is available. Creates a new native thread - if necessary. - - This must only be called from the native thread that owns this - object's hub. This is because creating the necessary data - structures to communicate back to this thread isn't thread - safe, so the hub must not be running something else. Also, - ensuring the pool size stays correct only works within a - single thread. - - :return: A :class:`gevent.event.AsyncResult`. - :raises InvalidThreadUseError: If called from a different thread. - - .. versionchanged:: 1.5 - Document the thread-safety requirements. - """ - if self.hub != get_hub(): - raise InvalidThreadUseError - - while 1: - semaphore = self._available_worker_threads_greenlet_sem - semaphore.acquire() - if semaphore is self._available_worker_threads_greenlet_sem: - # If we were asked to change size or re-init we could have changed - # semaphore objects. - break - - # Returned; lets a greenlet in this thread wait - # for the pool thread. Signaled when the async watcher - # is fired from the pool thread back into this thread. - result = AsyncResult() - task_queue = self.task_queue - # Encapsulates the async watcher the worker thread uses to - # call back into this thread. Immediately allocates and starts the - # async watcher in this thread, because it uses this hub/loop, - # which is not thread safe. - thread_result = None - try: - thread_result = ThreadResult(result, self.hub, semaphore.release) - task_queue.put((func, args, kwargs, thread_result)) - self.adjust() - except: - if thread_result is not None: - thread_result.destroy_in_main_thread() - semaphore.release() - raise - return result - - def _apply_immediately(self): - # If we're being called from a different thread than the one that - # created us, e.g., because a worker task is trying to use apply() - # recursively, we have no choice but to run the task immediately; - # if we try to AsyncResult.get() in the worker thread, it's likely to have - # nothing to switch to and lead to a LoopExit. - return get_hub() is not self.hub - - def _apply_async_cb_spawn(self, callback, result): - callback(result) - - def _apply_async_use_greenlet(self): - # Always go to Greenlet because our self.spawn uses threads - return True - -class _FakeAsync(object): - - def send(self): - pass - close = stop = send - - def __call__(self, result): - "fake out for 'receiver'" - - def __bool__(self): - return False - - __nonzero__ = __bool__ - -_FakeAsync = _FakeAsync() - -class ThreadResult(object): - """ - A one-time event for cross-thread communication. - - Uses a hub's "async" watcher capability; it must be constructed and - destroyed in the thread running the hub (because creating, starting, and - destroying async watchers isn't guaranteed to be thread safe). - """ - - # Using slots here helps to debug reference cycles/leaks - __slots__ = ('exc_info', 'async_watcher', '_call_when_ready', 'value', - 'context', 'hub', 'receiver') - - def __init__(self, receiver, hub, call_when_ready): - self.receiver = receiver - self.hub = hub - self.context = None - self.value = None - self.exc_info = () - self.async_watcher = hub.loop.async_() - self._call_when_ready = call_when_ready - self.async_watcher.start(self._on_async) - - @property - def exception(self): - return self.exc_info[1] if self.exc_info else None - - def _on_async(self): - # Called in the hub thread. - - aw = self.async_watcher - self.async_watcher = _FakeAsync - - aw.stop() - aw.close() - - # Typically this is pool.semaphore.release and we have to - # call this in the Hub; if we don't we get the dreaded - # LoopExit (XXX: Why?) - try: - self._call_when_ready() - if self.exc_info: - self.hub.handle_error(self.context, *self.exc_info) - self.context = None - self.async_watcher = _FakeAsync - self.hub = None - self._call_when_ready = _FakeAsync - - self.receiver(self) - finally: - self.receiver = _FakeAsync - self.value = None - if self.exc_info: - self.exc_info = (self.exc_info[0], self.exc_info[1], None) - - def destroy_in_main_thread(self): - """ - This must only be called from the thread running the hub. - """ - self.async_watcher.stop() - self.async_watcher.close() - self.async_watcher = _FakeAsync - - self.context = None - self.hub = None - self._call_when_ready = _FakeAsync - self.receiver = _FakeAsync - - def set(self, value): - self.value = value - self.async_watcher.send() - - def handle_error(self, context, exc_info): - self.context = context - self.exc_info = exc_info - self.async_watcher.send() - - # link protocol: - def successful(self): - return self.exception is None - - -try: - import concurrent.futures -except ImportError: - pass -else: - __all__.append("ThreadPoolExecutor") - - from gevent.timeout import Timeout as GTimeout - from gevent._util import Lazy - from concurrent.futures import _base as cfb - - def _ignore_error(future_proxy, fn): - def cbwrap(_): - del _ - # We're called with the async result (from the threadpool), but - # be sure to pass in the user-visible _FutureProxy object.. - try: - fn(future_proxy) - except Exception: # pylint: disable=broad-except - # Just print, don't raise to the hub's parent. - future_proxy.hub.print_exception((fn, future_proxy), None, None, None) - return cbwrap - - def _wrap(future_proxy, fn): - def f(_): - fn(future_proxy) - return f - - class _FutureProxy(object): - def __init__(self, asyncresult): - self.asyncresult = asyncresult - - # Internal implementation details of a c.f.Future - - @Lazy - def _condition(self): - if monkey.is_module_patched('threading') or self.done(): - import threading - return threading.Condition() - # We can only properly work with conditions - # when we've been monkey-patched. This is necessary - # for the wait/as_completed module functions. - raise AttributeError("_condition") - - @Lazy - def _waiters(self): - self.asyncresult.rawlink(self.__when_done) - return [] - - def __when_done(self, _): - # We should only be called when _waiters has - # already been accessed. - waiters = getattr(self, '_waiters') - for w in waiters: # pylint:disable=not-an-iterable - if self.successful(): - w.add_result(self) - else: - w.add_exception(self) - - @property - def _state(self): - if self.done(): - return cfb.FINISHED - return cfb.RUNNING - - def set_running_or_notify_cancel(self): - # Does nothing, not even any consistency checks. It's - # meant to be internal to the executor and we don't use it. - return - - def result(self, timeout=None): - try: - return self.asyncresult.result(timeout=timeout) - except GTimeout: - # XXX: Theoretically this could be a completely - # unrelated timeout instance. Do we care about that? - raise concurrent.futures.TimeoutError() - - def exception(self, timeout=None): - try: - self.asyncresult.get(timeout=timeout) - return self.asyncresult.exception - except GTimeout: - raise concurrent.futures.TimeoutError() - - def add_done_callback(self, fn): - """Exceptions raised by *fn* are ignored.""" - if self.done(): - fn(self) - else: - self.asyncresult.rawlink(_ignore_error(self, fn)) - - def rawlink(self, fn): - self.asyncresult.rawlink(_wrap(self, fn)) - - def __str__(self): - return str(self.asyncresult) - - def __getattr__(self, name): - return getattr(self.asyncresult, name) - - class ThreadPoolExecutor(concurrent.futures.ThreadPoolExecutor): - """ - A version of :class:`concurrent.futures.ThreadPoolExecutor` that - always uses native threads, even when threading is monkey-patched. - - The ``Future`` objects returned from this object can be used - with gevent waiting primitives like :func:`gevent.wait`. - - .. caution:: If threading is *not* monkey-patched, then the ``Future`` - objects returned by this object are not guaranteed to work with - :func:`~concurrent.futures.as_completed` and :func:`~concurrent.futures.wait`. - The individual blocking methods like :meth:`~concurrent.futures.Future.result` - and :meth:`~concurrent.futures.Future.exception` will always work. - - .. versionadded:: 1.2a1 - This is a provisional API. - """ - - def __init__(self, *args, **kwargs): - """ - Takes the same arguments as ``concurrent.futures.ThreadPoolExecuter``, which - vary between Python versions. - - The first argument is always *max_workers*, the maximum number of - threads to use. Most other arguments, while accepted, are ignored. - """ - super(ThreadPoolExecutor, self).__init__(*args, **kwargs) - self._threadpool = ThreadPool(self._max_workers) - - def submit(self, fn, *args, **kwargs): # pylint:disable=arguments-differ - with self._shutdown_lock: # pylint:disable=not-context-manager - if self._shutdown: - raise RuntimeError('cannot schedule new futures after shutdown') - - future = self._threadpool.spawn(fn, *args, **kwargs) - return _FutureProxy(future) - - def shutdown(self, wait=True, **kwargs): # pylint:disable=arguments-differ - # In 3.9, this added ``cancel_futures=False`` - super(ThreadPoolExecutor, self).shutdown(wait, **kwargs) - # XXX: We don't implement wait properly - kill = getattr(self._threadpool, 'kill', None) - if kill: # pylint:disable=using-constant-test - self._threadpool.kill() - self._threadpool = None - - kill = shutdown # greentest compat - - def _adjust_thread_count(self): - # Does nothing. We don't want to spawn any "threads", - # let the threadpool handle that. - pass diff --git a/venv/lib/python3.9/site-packages/gevent/time.py b/venv/lib/python3.9/site-packages/gevent/time.py deleted file mode 100644 index 34abf85..0000000 --- a/venv/lib/python3.9/site-packages/gevent/time.py +++ /dev/null @@ -1,27 +0,0 @@ -# Copyright (c) 2018 gevent. See LICENSE for details. -""" -The standard library :mod:`time` module, but :func:`sleep` is -gevent-aware. - -.. versionadded:: 1.3a2 -""" - -from __future__ import absolute_import - -__implements__ = [ - 'sleep', -] - -__all__ = __implements__ - -import time as __time__ - -from gevent._util import copy_globals - -__imports__ = copy_globals(__time__, globals(), - names_to_ignore=__implements__) - - - -from gevent.hub import sleep -sleep = sleep # pylint diff --git a/venv/lib/python3.9/site-packages/gevent/timeout.py b/venv/lib/python3.9/site-packages/gevent/timeout.py deleted file mode 100644 index e8a09cd..0000000 --- a/venv/lib/python3.9/site-packages/gevent/timeout.py +++ /dev/null @@ -1,401 +0,0 @@ -# Copyright (c) 2009-2010 Denis Bilenko. See LICENSE for details. -""" -Timeouts. - -Many functions in :mod:`gevent` have a *timeout* argument that allows -limiting the time the function will block. When that is not available, -the :class:`Timeout` class and :func:`with_timeout` function in this -module add timeouts to arbitrary code. - -.. warning:: - - Timeouts can only work when the greenlet switches to the hub. - If a blocking function is called or an intense calculation is ongoing during - which no switches occur, :class:`Timeout` is powerless. -""" -from __future__ import absolute_import, print_function, division - -from gevent._compat import string_types -from gevent._util import _NONE - -from greenlet import getcurrent -from gevent._hub_local import get_hub_noargs as get_hub - -__all__ = [ - 'Timeout', - 'with_timeout', -] - - -class _FakeTimer(object): - # An object that mimics the API of get_hub().loop.timer, but - # without allocating any native resources. This is useful for timeouts - # that will never expire. - # Also partially mimics the API of Timeout itself for use in _start_new_or_dummy - - # This object is used as a singleton, so it should be - # immutable. - __slots__ = () - - @property - def pending(self): - return False - - active = pending - - @property - def seconds(self): - "Always returns None" - - timer = exception = seconds - - def start(self, *args, **kwargs): - # pylint:disable=unused-argument - raise AssertionError("non-expiring timer cannot be started") - - def stop(self): - return - - cancel = stop - - stop = close = cancel - - def __enter__(self): - return self - - def __exit__(self, _t, _v, _tb): - return - -_FakeTimer = _FakeTimer() - - -class Timeout(BaseException): - """ - Timeout(seconds=None, exception=None, ref=True, priority=-1) - - Raise *exception* in the current greenlet after *seconds* - have elapsed:: - - timeout = Timeout(seconds, exception) - timeout.start() - try: - ... # exception will be raised here, after *seconds* passed since start() call - finally: - timeout.close() - - .. warning:: - - You must **always** call `close` on a ``Timeout`` object you have created, - whether or not the code that the timeout was protecting finishes - executing before the timeout elapses (whether or not the - ``Timeout`` exception is raised) This ``try/finally`` - construct or a ``with`` statement is a good pattern. (If - the timeout object will be started again, use `cancel` instead - of `close`; this is rare. You must still `close` it when you are - done.) - - When *exception* is omitted or ``None``, the ``Timeout`` instance - itself is raised:: - - >>> import gevent - >>> gevent.Timeout(0.1).start() - >>> gevent.sleep(0.2) #doctest: +IGNORE_EXCEPTION_DETAIL - Traceback (most recent call last): - ... - Timeout: 0.1 seconds - - If the *seconds* argument is not given or is ``None`` (e.g., - ``Timeout()``), then the timeout will never expire and never raise - *exception*. This is convenient for creating functions which take - an optional timeout parameter of their own. (Note that this is **not** - the same thing as a *seconds* value of ``0``.) - - :: - - def function(args, timeout=None): - "A function with an optional timeout." - timer = Timeout(timeout) - with timer: - ... - - .. caution:: - - A *seconds* value less than ``0.0`` (e.g., ``-1``) is poorly defined. In the future, - support for negative values is likely to do the same thing as a value - of ``None`` or ``0`` - - A *seconds* value of ``0`` requests that the event loop spin and poll for I/O; - it will immediately expire as soon as control returns to the event loop. - - .. rubric:: Use As A Context Manager - - To simplify starting and canceling timeouts, the ``with`` - statement can be used:: - - with gevent.Timeout(seconds, exception) as timeout: - pass # ... code block ... - - This is equivalent to the try/finally block above with one - additional feature: if *exception* is the literal ``False``, the - timeout is still raised, but the context manager suppresses it, so - the code outside the with-block won't see it. - - This is handy for adding a timeout to the functions that don't - support a *timeout* parameter themselves:: - - data = None - with gevent.Timeout(5, False): - data = mysock.makefile().readline() - if data is None: - ... # 5 seconds passed without reading a line - else: - ... # a line was read within 5 seconds - - .. caution:: - - If ``readline()`` above catches and doesn't re-raise - :exc:`BaseException` (for example, with a bare ``except:``), then - your timeout will fail to function and control won't be returned - to you when you expect. - - .. rubric:: Catching Timeouts - - When catching timeouts, keep in mind that the one you catch may - not be the one you have set (a calling function may have set its - own timeout); if you are going to silence a timeout, always check that - it's the instance you need:: - - timeout = Timeout(1) - timeout.start() - try: - ... - except Timeout as t: - if t is not timeout: - raise # not my timeout - finally: - timeout.close() - - - .. versionchanged:: 1.1b2 - - If *seconds* is not given or is ``None``, no longer allocate a - native timer object that will never be started. - - .. versionchanged:: 1.1 - - Add warning about negative *seconds* values. - - .. versionchanged:: 1.3a1 - - Timeout objects now have a :meth:`close` - method that *must* be called when the timeout will no longer be - used to properly clean up native resources. - The ``with`` statement does this automatically. - - .. versionchanged:: 24.10.1 - - Timeout values can be compared to be less than an integer value, - or to be less than other timeouts, e.g., ``Timeout(0) < 1`` is true. - Timeouts are not absolutely ordered and support no other comparisons; this - is purely for convenience and may be removed or altered in the future. - - """ - - # We inherit a __dict__ from BaseException, so __slots__ actually - # makes us larger. - - def __init__(self, seconds=None, exception=None, ref=True, priority=-1, - _one_shot=False): - BaseException.__init__(self) - self.seconds = seconds - self.exception = exception - self._one_shot = _one_shot - if seconds is None: - # Avoid going through the timer codepath if no timeout is - # desired; this avoids some CFFI interactions on PyPy that can lead to a - # RuntimeError if this implementation is used during an `import` statement. See - # https://bitbucket.org/pypy/pypy/issues/2089/crash-in-pypy-260-linux64-with-gevent-11b1 - # and https://github.com/gevent/gevent/issues/618. - # Plus, in general, it should be more efficient - - self.timer = _FakeTimer - else: - # XXX: A timer <= 0 could cause libuv to block the loop; we catch - # that case in libuv/loop.py - self.timer = get_hub().loop.timer(seconds or 0.0, ref=ref, priority=priority) - - def start(self): - """Schedule the timeout.""" - if self.pending: - raise AssertionError('%r is already started; to restart it, cancel it first' % self) - - if self.seconds is None: - # "fake" timeout (never expires) - return - - if self.exception is None or self.exception is False or isinstance(self.exception, string_types): - # timeout that raises self - throws = self - else: - # regular timeout with user-provided exception - throws = self.exception - - # Make sure the timer updates the current time so that we don't - # expire prematurely. - self.timer.start(self._on_expiration, getcurrent(), throws, update=True) - - def _on_expiration(self, prev_greenlet, ex): - # Hook for subclasses. - prev_greenlet.throw(ex) - - @classmethod - def start_new(cls, timeout=None, exception=None, ref=True, _one_shot=False): - """Create a started :class:`Timeout`. - - This is a shortcut, the exact action depends on *timeout*'s type: - - * If *timeout* is a :class:`Timeout`, then call its :meth:`start` method - if it's not already begun. - * Otherwise, create a new :class:`Timeout` instance, passing (*timeout*, *exception*) as - arguments, then call its :meth:`start` method. - - Returns the :class:`Timeout` instance. - """ - if isinstance(timeout, Timeout): - if not timeout.pending: - timeout.start() - return timeout - timeout = cls(timeout, exception, ref=ref, _one_shot=_one_shot) - timeout.start() - return timeout - - @staticmethod - def _start_new_or_dummy(timeout, exception=None, ref=True): - # Internal use only in 1.1 - # Return an object with a 'cancel' method; if timeout is None, - # this will be a shared instance object that does nothing. Otherwise, - # return an actual Timeout. A 0 value is allowed and creates a real Timeout. - - # Because negative values are hard to reason about, - # and are often used as sentinels in Python APIs, in the future it's likely - # that a negative timeout will also return the shared instance. - # This saves the previously common idiom of - # 'timer = Timeout.start_new(t) if t is not None else None' - # followed by 'if timer is not None: timer.cancel()'. - # That idiom was used to avoid any object allocations. - - # A staticmethod is slightly faster under CPython, compared to a classmethod; - # under PyPy in synthetic benchmarks it makes no difference. - if timeout is None: - return _FakeTimer - return Timeout.start_new(timeout, exception, ref, _one_shot=True) - - @property - def pending(self): - """True if the timeout is scheduled to be raised.""" - return self.timer.pending or self.timer.active - - def cancel(self): - """ - If the timeout is pending, cancel it. Otherwise, do nothing. - - The timeout object can be :meth:`started ` again. If - you will not start the timeout again, you should use - :meth:`close` instead. - """ - self.timer.stop() - if self._one_shot: - self.close() - - def close(self): - """ - Close the timeout and free resources. The timer cannot be started again - after this method has been used. - """ - self.timer.stop() - self.timer.close() - self.timer = _FakeTimer - - def __repr__(self): - classname = type(self).__name__ - if self.pending: - pending = ' pending' - else: - pending = '' - if self.exception is None: - exception = '' - else: - exception = ' exception=%r' % self.exception - return '<%s at %s seconds=%s%s%s>' % (classname, hex(id(self)), self.seconds, exception, pending) - - def __str__(self): - """ - >>> raise Timeout #doctest: +IGNORE_EXCEPTION_DETAIL - Traceback (most recent call last): - ... - Timeout - """ - if self.seconds is None: - return '' - - suffix = '' if self.seconds == 1 else 's' - - if self.exception is None: - return '%s second%s' % (self.seconds, suffix) - if self.exception is False: - return '%s second%s (silent)' % (self.seconds, suffix) - return '%s second%s: %s' % (self.seconds, suffix, self.exception) - - def __enter__(self): - """ - Start and return the timer. If the timer is already started, just return it. - """ - if not self.pending: - self.start() - return self - - def __exit__(self, typ, value, tb): - """ - Stop the timer. - - .. versionchanged:: 1.3a1 - The underlying native timer is also stopped. This object cannot be - used again. - """ - self.close() - if value is self and self.exception is False: - return True # Suppress the exception - - def __lt__(self, other): - """ - For convenience, timeouts can be compared to integers (numbers) - based on their seconds value. - """ - try: - return self.seconds < other.seconds - except AttributeError: - try: - return self.seconds < other - except TypeError: - return NotImplemented - -def with_timeout(seconds, function, *args, **kwds): - """Wrap a call to *function* with a timeout; if the called - function fails to return before the timeout, cancel it and return a - flag value, provided by *timeout_value* keyword argument. - - If timeout expires but *timeout_value* is not provided, raise :class:`Timeout`. - - Keyword argument *timeout_value* is not passed to *function*. - """ - timeout_value = kwds.pop("timeout_value", _NONE) - timeout = Timeout.start_new(seconds, _one_shot=True) - try: - try: - return function(*args, **kwds) - except Timeout as ex: - if ex is timeout and timeout_value is not _NONE: - return timeout_value - raise - finally: - timeout.cancel() diff --git a/venv/lib/python3.9/site-packages/gevent/util.py b/venv/lib/python3.9/site-packages/gevent/util.py deleted file mode 100644 index 8744846..0000000 --- a/venv/lib/python3.9/site-packages/gevent/util.py +++ /dev/null @@ -1,667 +0,0 @@ -# Copyright (c) 2009 Denis Bilenko. See LICENSE for details. -""" -Low-level utilities. -""" - -from __future__ import absolute_import, print_function, division - -import functools -import pprint -import sys -import traceback - -from greenlet import getcurrent - -from gevent._compat import perf_counter -from gevent._compat import PYPY -from gevent._compat import thread_mod_name -from gevent._util import _NONE - -__all__ = [ - 'format_run_info', - 'print_run_info', - 'GreenletTree', - 'wrap_errors', - 'assert_switches', -] - -# PyPy is very slow at formatting stacks -# for some reason. -_STACK_LIMIT = 20 if PYPY else None - - -def _noop(): - return None - -def _ready(): - return False - -class wrap_errors(object): - """ - Helper to make function return an exception, rather than raise it. - - Because every exception that is unhandled by greenlet will be logged, - it is desirable to prevent non-error exceptions from leaving a greenlet. - This can done with a simple ``try/except`` construct:: - - def wrapped_func(*args, **kwargs): - try: - return func(*args, **kwargs) - except (TypeError, ValueError, AttributeError) as ex: - return ex - - This class provides a shortcut to write that in one line:: - - wrapped_func = wrap_errors((TypeError, ValueError, AttributeError), func) - - It also preserves ``__str__`` and ``__repr__`` of the original function. - """ - # QQQ could also support using wrap_errors as a decorator - - def __init__(self, errors, func): - """ - Calling this makes a new function from *func*, such that it catches *errors* (an - :exc:`BaseException` subclass, or a tuple of :exc:`BaseException` subclasses) and - return it as a value. - """ - self.__errors = errors - self.__func = func - # Set __doc__, __wrapped__, etc, especially useful on Python 3. - functools.update_wrapper(self, func) - - def __call__(self, *args, **kwargs): - func = self.__func - try: - return func(*args, **kwargs) - except self.__errors as ex: - return ex - - def __str__(self): - return str(self.__func) - - def __repr__(self): - return repr(self.__func) - - def __getattr__(self, name): - return getattr(self.__func, name) - - -def print_run_info(thread_stacks=True, greenlet_stacks=True, limit=_NONE, file=None): - """ - Call `format_run_info` and print the results to *file*. - - If *file* is not given, `sys.stderr` will be used. - - .. versionadded:: 1.3b1 - """ - lines = format_run_info(thread_stacks=thread_stacks, - greenlet_stacks=greenlet_stacks, - limit=limit) - file = sys.stderr if file is None else file - for l in lines: - print(l, file=file) - - -def format_run_info(thread_stacks=True, - greenlet_stacks=True, - limit=_NONE, - current_thread_ident=None): - """ - format_run_info(thread_stacks=True, greenlet_stacks=True, limit=None) -> [str] - - Request information about the running threads of the current process. - - This is a debugging utility. Its output has no guarantees other than being - intended for human consumption. - - :keyword bool thread_stacks: If true, then include the stacks for - running threads. - :keyword bool greenlet_stacks: If true, then include the stacks for - running greenlets. (Spawning stacks will always be printed.) - Setting this to False can reduce the output volume considerably - without reducing the overall information if *thread_stacks* is true - and you can associate a greenlet to a thread (using ``thread_ident`` - printed values). - :keyword int limit: If given, passed directly to `traceback.format_stack`. - If not given, this defaults to the whole stack under CPython, and a - smaller stack under PyPy. - - :return: A sequence of text lines detailing the stacks of running - threads and greenlets. (One greenlet will duplicate one thread, - the current thread and greenlet. If there are multiple running threads, - the stack for the current greenlet may be incorrectly duplicated in multiple - greenlets.) - Extra information about - :class:`gevent.Greenlet` object will also be returned. - - .. versionadded:: 1.3a1 - .. versionchanged:: 1.3a2 - Renamed from ``dump_stacks`` to reflect the fact that this - prints additional information about greenlets, including their - spawning stack, parent, locals, and any spawn tree locals. - .. versionchanged:: 1.3b1 - Added the *thread_stacks*, *greenlet_stacks*, and *limit* params. - """ - if current_thread_ident is None: - from gevent import monkey - current_thread_ident = monkey.get_original(thread_mod_name, 'get_ident')() - - lines = [] - - limit = _STACK_LIMIT if limit is _NONE else limit - _format_thread_info(lines, thread_stacks, limit, current_thread_ident) - _format_greenlet_info(lines, greenlet_stacks, limit) - return lines - - -def is_idle_threadpool_worker(frame): - return frame.f_locals and frame.f_locals.get('gevent_threadpool_worker_idle') - - -def _format_thread_info(lines, thread_stacks, limit, current_thread_ident): - import threading - - threads = {th.ident: th for th in threading.enumerate()} - lines.append('*' * 80) - lines.append('* Threads') - - thread = None - frame = None - for thread_ident, frame in sys._current_frames().items(): - do_stacks = thread_stacks - lines.append("*" * 80) - thread = threads.get(thread_ident) - name = None - if not thread: - # Is it an idle threadpool thread? thread pool threads - # don't have a Thread object, they're low-level - if is_idle_threadpool_worker(frame): - name = 'idle threadpool worker' - do_stacks = False - else: - name = thread.name - if getattr(thread, 'gevent_monitoring_thread', None): - name = repr(thread.gevent_monitoring_thread()) - if current_thread_ident == thread_ident: - name = '%s) (CURRENT' % (name,) - lines.append('Thread 0x%x (%s)\n' % (thread_ident, name)) - if do_stacks: - lines.append(''.join(traceback.format_stack(frame, limit))) - elif not thread_stacks: - lines.append('\t...stack elided...') - - # We may have captured our own frame, creating a reference - # cycle, so clear it out. - del thread - del frame - del lines - del threads - -def _format_greenlet_info(lines, greenlet_stacks, limit): - # Use the gc module to inspect all objects to find the greenlets - # since there isn't a global registry - lines.append('*' * 80) - lines.append('* Greenlets') - lines.append('*' * 80) - for tree in sorted(GreenletTree.forest(), - key=lambda t: '' if t.is_current_tree else repr(t.greenlet)): - lines.append("---- Thread boundary") - lines.extend(tree.format_lines(details={ - # greenlets from other threads tend to have their current - # frame just match our current frame, which is not helpful, - # so don't render their stack. - 'running_stacks': greenlet_stacks if tree.is_current_tree else False, - 'running_stack_limit': limit, - })) - - del lines - -dump_stacks = format_run_info - -def _line(f): - @functools.wraps(f) - def w(self, *args, **kwargs): - r = f(self, *args, **kwargs) - self.lines.append(r) - - return w - -class _TreeFormatter(object): - UP_AND_RIGHT = '+' - HORIZONTAL = '-' - VERTICAL = '|' - VERTICAL_AND_RIGHT = '+' - DATA = ':' - - label_space = 1 - horiz_width = 3 - indent = 1 - - def __init__(self, details, depth=0): - self.lines = [] - self.depth = depth - self.details = details - if not details: - self.child_data = lambda *args, **kwargs: None - - def deeper(self): - return type(self)(self.details, self.depth + 1) - - @_line - def node_label(self, text): - return text - - @_line - def child_head(self, label, right=VERTICAL_AND_RIGHT): - return ( - ' ' * self.indent - + right - + self.HORIZONTAL * self.horiz_width - + ' ' * self.label_space - + label - ) - - def last_child_head(self, label): - return self.child_head(label, self.UP_AND_RIGHT) - - @_line - def child_tail(self, line, vertical=VERTICAL): - return ( - ' ' * self.indent - + vertical - + ' ' * self.horiz_width - + line - ) - - def last_child_tail(self, line): - return self.child_tail(line, vertical=' ' * len(self.VERTICAL)) - - @_line - def child_data(self, data, data_marker=DATA): # pylint:disable=method-hidden - return (( - ' ' * self.indent - + (data_marker if not self.depth else ' ') - + ' ' * self.horiz_width - + ' ' * self.label_space - + data - ),) - - def last_child_data(self, data): - return self.child_data(data, ' ') - - def child_multidata(self, data): - # Remove embedded newlines - for l in data.splitlines(): - self.child_data(l) - - -class GreenletTree(object): - """ - Represents a tree of greenlets. - - In gevent, the *parent* of a greenlet is usually the hub, so this - tree is primarily arganized along the *spawning_greenlet* dimension. - - This object has a small str form showing this hierarchy. The `format` - method can output more details. The exact output is unspecified but is - intended to be human readable. - - Use the `forest` method to get the root greenlet trees for - all threads, and the `current_tree` to get the root greenlet tree for - the current thread. - """ - - #: The greenlet this tree represents. - greenlet = None - - #: Is this tree the root for the current thread? - is_current_tree = False - - def __init__(self, greenlet): - self.greenlet = greenlet - self.child_trees = [] - - def add_child(self, tree): - if tree is self: - return - self.child_trees.append(tree) - - @property - def root(self): - return self.greenlet.parent is None - - def __getattr__(self, name): - return getattr(self.greenlet, name) - - DEFAULT_DETAILS = { - 'running_stacks': True, - 'running_stack_limit': _STACK_LIMIT, - 'spawning_stacks': True, - 'locals': True, - } - - def format_lines(self, details=True): - """ - Return a sequence of lines for the greenlet tree. - - :keyword bool details: If true (the default), - then include more informative details in the output. - """ - if not isinstance(details, dict): - if not details: - details = {} - else: - details = self.DEFAULT_DETAILS.copy() - else: - params = details - details = self.DEFAULT_DETAILS.copy() - details.update(params) - tree = _TreeFormatter(details, depth=0) - lines = [l[0] if isinstance(l, tuple) else l - for l in self._render(tree)] - return lines - - def format(self, details=True): - """ - Like `format_lines` but returns a string. - """ - lines = self.format_lines(details) - return '\n'.join(lines) - - def __str__(self): - return self.format(False) - - # Prior to greenlet 3.0rc1, getting tracebacks of inactive - # greenlets could crash on Python 3.12. So we added a - # version-based setting here to disable it. That's fixed in the - # 3.0 final releases, but appears to be back with Python 3.12.1; - # this is likely related to https://github.com/python-greenlet/greenlet/issues/388 - #_SUPPORTS_TRACEBACK = sys.version_info[:3] < (3, 12, 1) - _SUPPORTS_TRACEBACK = True - - @classmethod - def __render_tb(cls, tree, label, frame, limit): - tree.child_data(label) - - if cls._SUPPORTS_TRACEBACK: - tb = ''.join(traceback.format_stack(frame, limit)) - else: - tb = '' - tree.child_multidata(tb) - - @staticmethod - def __spawning_parent(greenlet): - return (getattr(greenlet, 'spawning_greenlet', None) or _noop)() - - def __render_locals(self, tree): - # Defer the import to avoid cycles - from gevent.local import all_local_dicts_for_greenlet - - gr_locals = all_local_dicts_for_greenlet(self.greenlet) - if gr_locals: - tree.child_data("Greenlet Locals:") - for (kind, idl), vals in gr_locals: - if not vals: - continue # not set in this greenlet; ignore it. - tree.child_data(" Local %s at %s" % (kind, hex(idl))) - tree.child_multidata(" " + pprint.pformat(vals)) - - def _render(self, tree): - label = repr(self.greenlet) - if not self.greenlet: # Not running or dead - # raw greenlets do not have ready - if getattr(self.greenlet, 'ready', _ready)(): - label += '; finished' - if self.greenlet.value is not None: - label += ' with value ' + repr(self.greenlet.value)[:30] - elif getattr(self.greenlet, 'exception', None) is not None: - label += ' with exception ' + repr(self.greenlet.exception) - else: - label += '; not running' - tree.node_label(label) - - tree.child_data('Parent: ' + repr(self.greenlet.parent)) - - if getattr(self.greenlet, 'gevent_monitoring_thread', None) is not None: - tree.child_data('Monitoring Thread:' + repr(self.greenlet.gevent_monitoring_thread())) - - if self.greenlet and tree.details and tree.details['running_stacks']: - self.__render_tb(tree, 'Running:', self.greenlet.gr_frame, - tree.details['running_stack_limit']) - - - spawning_stack = getattr(self.greenlet, 'spawning_stack', None) - if spawning_stack and tree.details and tree.details['spawning_stacks']: - # We already placed a limit on the spawning stack when we captured it. - self.__render_tb(tree, 'Spawned at:', spawning_stack, None) - - spawning_parent = self.__spawning_parent(self.greenlet) - tree_locals = getattr(self.greenlet, 'spawn_tree_locals', None) - if tree_locals and tree_locals is not getattr(spawning_parent, 'spawn_tree_locals', None): - tree.child_data('Spawn Tree Locals') - tree.child_multidata(pprint.pformat(tree_locals)) - - self.__render_locals(tree) - try: - self.__render_children(tree) - except RuntimeError: # pragma: no cover - # If the tree is exceptionally deep, we can hit the recursion error. - # Usually it's several levels down so we can make a print call. - # This came up in test__semaphore before TestSemaphoreFair - # was fixed. - print("When rendering children", *sys.exc_info()) - return tree.lines - - def __render_children(self, tree): - children = sorted(self.child_trees, - key=lambda c: ( - # raw greenlets first. Note that we could be accessing - # minimal_ident for a hub from a different thread, which isn't - # technically thread safe. - getattr(c, 'minimal_ident', -1), - # running greenlets next - getattr(c, 'ready', _ready)(), - id(c.parent))) - for n, child in enumerate(children): - child_tree = child._render(tree.deeper()) - - head = tree.child_head - tail = tree.child_tail - data = tree.child_data - - if n == len(children) - 1: - # last child does not get the line drawn - head = tree.last_child_head - tail = tree.last_child_tail - data = tree.last_child_data - - head(child_tree.pop(0)) - for child_data in child_tree: - if isinstance(child_data, tuple): - data(child_data[0]) - else: - tail(child_data) - - return tree.lines - - - @staticmethod - def _root_greenlet(greenlet): - while greenlet.parent is not None and not getattr(greenlet, 'greenlet_tree_is_root', False): - greenlet = greenlet.parent - return greenlet - - @classmethod - def _forest(cls): - from gevent._greenlet_primitives import get_reachable_greenlets - main_greenlet = cls._root_greenlet(getcurrent()) - - trees = {} # greenlet -> GreenletTree - roots = {} # root greenlet -> GreenletTree - current_tree = roots[main_greenlet] = trees[main_greenlet] = cls(main_greenlet) - current_tree.is_current_tree = True - - root_greenlet = cls._root_greenlet - glets = get_reachable_greenlets() - - for ob in glets: - spawn_parent = cls.__spawning_parent(ob) - - if spawn_parent is None: - # spawn parent is dead, or raw greenlet. - # reparent under the root. - spawn_parent = root_greenlet(ob) - - if spawn_parent is root_greenlet(spawn_parent) and spawn_parent not in roots: - assert spawn_parent not in trees - trees[spawn_parent] = roots[spawn_parent] = cls(spawn_parent) - - - try: - parent_tree = trees[spawn_parent] - except KeyError: # pragma: no cover - parent_tree = trees[spawn_parent] = cls(spawn_parent) - - try: - # If the child also happened to be a spawning parent, - # we could have seen it before; the reachable greenlets - # are in no particular order. - child_tree = trees[ob] - except KeyError: - trees[ob] = child_tree = cls(ob) - parent_tree.add_child(child_tree) - - return roots, current_tree - - @classmethod - def forest(cls): - """ - forest() -> sequence - - Return a sequence of `GreenletTree`, one for each running - native thread. - """ - - return list(cls._forest()[0].values()) - - @classmethod - def current_tree(cls): - """ - current_tree() -> GreenletTree - - Returns the `GreenletTree` for the current thread. - """ - return cls._forest()[1] - -class _FailedToSwitch(AssertionError): - pass - -class assert_switches(object): - """ - A context manager for ensuring a block of code switches greenlets. - - This performs a similar function as the :doc:`monitoring thread - `, but the scope is limited to the body of the with - statement. If the code within the body doesn't yield to the hub - (and doesn't raise an exception), then upon exiting the - context manager an :exc:`AssertionError` will be raised. - - This is useful in unit tests and for debugging purposes. - - :keyword float max_blocking_time: If given, the body is allowed - to block for up to this many fractional seconds before - an error is raised. - :keyword bool hub_only: If True, then *max_blocking_time* only - refers to the amount of time spent between switches into the - hub. If False, then it refers to the maximum time between - *any* switches. If *max_blocking_time* is not given, has no - effect. - - Example:: - - # This will always raise an exception: nothing switched - with assert_switches(): - pass - - # This will never raise an exception; nothing switched, - # but it happened very fast - with assert_switches(max_blocking_time=1.0): - pass - - .. versionadded:: 1.3 - - .. versionchanged:: 1.4 - If an exception is raised, it now includes information about - the duration of blocking and the parameters of this object. - """ - - hub = None - tracer = None - _entered = None - - - def __init__(self, max_blocking_time=None, hub_only=False): - self.max_blocking_time = max_blocking_time - self.hub_only = hub_only - - def __enter__(self): - from gevent import get_hub - from gevent import _tracer - - self.hub = hub = get_hub() - - # TODO: We could optimize this to use the GreenletTracer - # installed by the monitoring thread, if there is one. - # As it is, we will chain trace calls back to it. - if not self.max_blocking_time: - self.tracer = _tracer.GreenletTracer() - elif self.hub_only: - self.tracer = _tracer.HubSwitchTracer(hub, self.max_blocking_time) - else: - self.tracer = _tracer.MaxSwitchTracer(hub, self.max_blocking_time) - - self._entered = perf_counter() - self.tracer.monitor_current_greenlet_blocking() - return self - - def __exit__(self, t, v, tb): - self.tracer.kill() - hub = self.hub; self.hub = None - tracer = self.tracer; self.tracer = None - - # Only check if there was no exception raised, we - # don't want to hide anything - if t is not None: - return - - - did_block = tracer.did_block_hub(hub) - if did_block: - execution_time_s = perf_counter() - self._entered - active_greenlet = did_block[1] - report_lines = tracer.did_block_hub_report(hub, active_greenlet, {}) - - message = 'To the hub' if self.hub_only else 'To any greenlet' - message += ' in %.4f seconds' % (execution_time_s,) - max_block = self.max_blocking_time - message += ' (max allowed %.4f seconds)' % (max_block,) if max_block else '' - message += '\n' - message += '\n'.join(report_lines) - raise _FailedToSwitch(message) - - -def clear_stack_frames(frame): - """Do our best to clear local variables in all frames in a stack.""" - # On Python 3, frames have a .clear() method that can raise a RuntimeError. - while frame is not None: - try: - frame.clear() - except (RuntimeError, AttributeError): - pass - try: - frame.f_locals.clear() - except AttributeError: - # Python 3.13 removed clear(); - # f_locals is now a FrameLocalsProxy. - pass - frame = frame.f_back diff --git a/venv/lib/python3.9/site-packages/gevent/win32util.py b/venv/lib/python3.9/site-packages/gevent/win32util.py deleted file mode 100644 index 7158d69..0000000 --- a/venv/lib/python3.9/site-packages/gevent/win32util.py +++ /dev/null @@ -1,98 +0,0 @@ -# Copyright (c) 2001-2007 Twisted Matrix Laboratories. -# Permission is hereby granted, free of charge, to any person obtaining -# a copy of this software and associated documentation files (the -# "Software"), to deal in the Software without restriction, including -# without limitation the rights to use, copy, modify, merge, publish, -# distribute, sublicense, and/or sell copies of the Software, and to -# permit persons to whom the Software is furnished to do so, subject to -# the following conditions: -# -# The above copyright notice and this permission notice shall be -# included in all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - -"""Error formatting function for Windows. - -The code is taken from twisted.python.win32 module. -""" - -from __future__ import absolute_import -import os - - -__all__ = ['formatError'] - - -class _ErrorFormatter(object): - """ - Formatter for Windows error messages. - - @ivar winError: A callable which takes one integer error number argument - and returns an L{exceptions.WindowsError} instance for that error (like - L{ctypes.WinError}). - - @ivar formatMessage: A callable which takes one integer error number - argument and returns a C{str} giving the message for that error (like - L{win32api.FormatMessage}). - - @ivar errorTab: A mapping from integer error numbers to C{str} messages - which correspond to those errors (like L{socket.errorTab}). - """ - def __init__(self, WinError, FormatMessage, errorTab): - self.winError = WinError - self.formatMessage = FormatMessage - self.errorTab = errorTab - - @classmethod - def fromEnvironment(cls): - """ - Get as many of the platform-specific error translation objects as - possible and return an instance of C{cls} created with them. - """ - try: - from ctypes import WinError - except ImportError: - WinError = None - try: - from win32api import FormatMessage - except ImportError: - FormatMessage = None - try: - from socket import errorTab - except ImportError: - errorTab = None - return cls(WinError, FormatMessage, errorTab) - - def formatError(self, errorcode): - """ - Returns the string associated with a Windows error message, such as the - ones found in socket.error. - - Attempts direct lookup against the win32 API via ctypes and then - pywin32 if available), then in the error table in the socket module, - then finally defaulting to C{os.strerror}. - - @param errorcode: the Windows error code - @type errorcode: C{int} - - @return: The error message string - @rtype: C{str} - """ - if self.winError is not None: - return str(self.winError(errorcode)) - if self.formatMessage is not None: - return self.formatMessage(errorcode) - if self.errorTab is not None: - result = self.errorTab.get(errorcode) - if result is not None: - return result - return os.strerror(errorcode) - -formatError = _ErrorFormatter.fromEnvironment().formatError diff --git a/venv/lib/python3.9/site-packages/gevent_websocket-0.10.1.dist-info/DESCRIPTION.rst b/venv/lib/python3.9/site-packages/gevent_websocket-0.10.1.dist-info/DESCRIPTION.rst deleted file mode 100644 index 07d4f63..0000000 --- a/venv/lib/python3.9/site-packages/gevent_websocket-0.10.1.dist-info/DESCRIPTION.rst +++ /dev/null @@ -1,125 +0,0 @@ - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - -Download-URL: https://www.gitlab.com/noppo/gevent-websocket -Description: ================ - gevent-websocket - ================ - - `gevent-websocket`_ is a WebSocket library for the gevent_ networking library. - - Features include: - - - Integration on both socket level or using an abstract interface. - - RPC and PubSub framework using `WAMP`_ (WebSocket Application - Messaging Protocol). - - Easily extendible using a simple WebSocket protocol plugin API - - - :: - - from geventwebsocket import WebSocketServer, WebSocketApplication, Resource - - class EchoApplication(WebSocketApplication): - def on_open(self): - print "Connection opened" - - def on_message(self, message): - self.ws.send(message) - - def on_close(self, reason): - print reason - - WebSocketServer( - ('', 8000), - Resource({'/': EchoApplication}) - ).serve_forever() - - or a low level implementation:: - - from gevent import pywsgi - from geventwebsocket.handler import WebSocketHandler - - def websocket_app(environ, start_response): - if environ["PATH_INFO"] == '/echo': - ws = environ["wsgi.websocket"] - message = ws.receive() - ws.send(message) - - server = pywsgi.WSGIServer(("", 8000), websocket_app, - handler_class=WebSocketHandler) - server.serve_forever() - - More examples can be found in the ``examples`` directory. Hopefully more - documentation will be available soon. - - Installation - ------------ - - The easiest way to install gevent-websocket is directly from PyPi_ using pip or - setuptools by running the commands below:: - - $ pip install gevent-websocket - - - Gunicorn Worker - ^^^^^^^^^^^^^^^ - - Using Gunicorn it is even more easy to start a server. Only the - `websocket_app` from the previous example is required to start the server. - Start Gunicorn using the following command and worker class to enable WebSocket - funtionality for the application. - - :: - - gunicorn -k "geventwebsocket.gunicorn.workers.GeventWebSocketWorker" wsgi:websocket_app - - Performance - ^^^^^^^^^^^ - - `gevent-websocket`_ is pretty fast, but can be accelerated further by - installing `wsaccel `_ and `ujson` or `simplejson`:: - - $ pip install wsaccel ujson - - `gevent-websocket`_ automatically detects ``wsaccell`` and uses the Cython - implementation for UTF8 validation and later also frame masking and - demasking. - - Get in touch - ^^^^^^^^^^^^ - - Get in touch on IRC #gevent on Freenode or on the Gevent `mailinglist - `_. Issues can be created - on `Bitbucket `_. - - .. _WAMP: http://www.wamp.ws - .. _gevent-websocket: http://www.bitbucket.org/Jeffrey/gevent-websocket/ - .. _gevent: http://www.gevent.org/ - .. _Jeffrey Gelens: http://www.gelens.org/ - .. _PyPi: http://pypi.python.org/pypi/gevent-websocket/ - .. _repository: http://www.bitbucket.org/Jeffrey/gevent-websocket/ - .. _RFC6455: http://datatracker.ietf.org/doc/rfc6455/?include_text=1 - -Platform: UNKNOWN -Classifier: Environment :: Web Environment -Classifier: Intended Audience :: Developers -Classifier: License :: OSI Approved :: Apache Software License -Classifier: Operating System :: MacOS :: MacOS X -Classifier: Operating System :: POSIX -Classifier: Programming Language :: Python -Classifier: Programming Language :: Python :: 2 -Classifier: Programming Language :: Python :: 2.7 -Classifier: Programming Language :: Python :: 3 -Classifier: Programming Language :: Python :: 3.5 -Classifier: Topic :: Internet -Classifier: Topic :: Software Development :: Libraries :: Python Modules diff --git a/venv/lib/python3.9/site-packages/gevent_websocket-0.10.1.dist-info/INSTALLER b/venv/lib/python3.9/site-packages/gevent_websocket-0.10.1.dist-info/INSTALLER deleted file mode 100644 index a1b589e..0000000 --- a/venv/lib/python3.9/site-packages/gevent_websocket-0.10.1.dist-info/INSTALLER +++ /dev/null @@ -1 +0,0 @@ -pip diff --git a/venv/lib/python3.9/site-packages/gevent_websocket-0.10.1.dist-info/METADATA b/venv/lib/python3.9/site-packages/gevent_websocket-0.10.1.dist-info/METADATA deleted file mode 100644 index 6c86010..0000000 --- a/venv/lib/python3.9/site-packages/gevent_websocket-0.10.1.dist-info/METADATA +++ /dev/null @@ -1,135 +0,0 @@ -Metadata-Version: 2.0 -Name: gevent-websocket -Version: 0.10.1 -Summary: Websocket handler for the gevent pywsgi server, a Python network library -Home-page: https://www.gitlab.com/noppo/gevent-websocket -Author: Jeffrey Gelens -Author-email: jeffrey@noppo.pro -License: Copyright 2011-2017 Jeffrey Gelens -Requires-Dist: gevent - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - -Download-URL: https://www.gitlab.com/noppo/gevent-websocket -Description: ================ - gevent-websocket - ================ - - `gevent-websocket`_ is a WebSocket library for the gevent_ networking library. - - Features include: - - - Integration on both socket level or using an abstract interface. - - RPC and PubSub framework using `WAMP`_ (WebSocket Application - Messaging Protocol). - - Easily extendible using a simple WebSocket protocol plugin API - - - :: - - from geventwebsocket import WebSocketServer, WebSocketApplication, Resource - - class EchoApplication(WebSocketApplication): - def on_open(self): - print "Connection opened" - - def on_message(self, message): - self.ws.send(message) - - def on_close(self, reason): - print reason - - WebSocketServer( - ('', 8000), - Resource({'/': EchoApplication}) - ).serve_forever() - - or a low level implementation:: - - from gevent import pywsgi - from geventwebsocket.handler import WebSocketHandler - - def websocket_app(environ, start_response): - if environ["PATH_INFO"] == '/echo': - ws = environ["wsgi.websocket"] - message = ws.receive() - ws.send(message) - - server = pywsgi.WSGIServer(("", 8000), websocket_app, - handler_class=WebSocketHandler) - server.serve_forever() - - More examples can be found in the ``examples`` directory. Hopefully more - documentation will be available soon. - - Installation - ------------ - - The easiest way to install gevent-websocket is directly from PyPi_ using pip or - setuptools by running the commands below:: - - $ pip install gevent-websocket - - - Gunicorn Worker - ^^^^^^^^^^^^^^^ - - Using Gunicorn it is even more easy to start a server. Only the - `websocket_app` from the previous example is required to start the server. - Start Gunicorn using the following command and worker class to enable WebSocket - funtionality for the application. - - :: - - gunicorn -k "geventwebsocket.gunicorn.workers.GeventWebSocketWorker" wsgi:websocket_app - - Performance - ^^^^^^^^^^^ - - `gevent-websocket`_ is pretty fast, but can be accelerated further by - installing `wsaccel `_ and `ujson` or `simplejson`:: - - $ pip install wsaccel ujson - - `gevent-websocket`_ automatically detects ``wsaccell`` and uses the Cython - implementation for UTF8 validation and later also frame masking and - demasking. - - Get in touch - ^^^^^^^^^^^^ - - Get in touch on IRC #gevent on Freenode or on the Gevent `mailinglist - `_. Issues can be created - on `Bitbucket `_. - - .. _WAMP: http://www.wamp.ws - .. _gevent-websocket: http://www.bitbucket.org/Jeffrey/gevent-websocket/ - .. _gevent: http://www.gevent.org/ - .. _Jeffrey Gelens: http://www.gelens.org/ - .. _PyPi: http://pypi.python.org/pypi/gevent-websocket/ - .. _repository: http://www.bitbucket.org/Jeffrey/gevent-websocket/ - .. _RFC6455: http://datatracker.ietf.org/doc/rfc6455/?include_text=1 - -Platform: UNKNOWN -Classifier: Environment :: Web Environment -Classifier: Intended Audience :: Developers -Classifier: License :: OSI Approved :: Apache Software License -Classifier: Operating System :: MacOS :: MacOS X -Classifier: Operating System :: POSIX -Classifier: Programming Language :: Python -Classifier: Programming Language :: Python :: 2 -Classifier: Programming Language :: Python :: 2.7 -Classifier: Programming Language :: Python :: 3 -Classifier: Programming Language :: Python :: 3.5 -Classifier: Topic :: Internet -Classifier: Topic :: Software Development :: Libraries :: Python Modules diff --git a/venv/lib/python3.9/site-packages/gevent_websocket-0.10.1.dist-info/RECORD b/venv/lib/python3.9/site-packages/gevent_websocket-0.10.1.dist-info/RECORD deleted file mode 100644 index f6175a0..0000000 --- a/venv/lib/python3.9/site-packages/gevent_websocket-0.10.1.dist-info/RECORD +++ /dev/null @@ -1,38 +0,0 @@ -gevent_websocket-0.10.1.dist-info/DESCRIPTION.rst,sha256=nQ4OV8W81ymEywPv_TiZa9VGAdZdAwjEd7Uoco4Zp7Y,4962 -gevent_websocket-0.10.1.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 -gevent_websocket-0.10.1.dist-info/METADATA,sha256=t93dKgVFczXCm7oEg4rL1-cnOITw74qtUdUjoa1j0OM,5304 -gevent_websocket-0.10.1.dist-info/RECORD,, -gevent_websocket-0.10.1.dist-info/REQUESTED,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 -gevent_websocket-0.10.1.dist-info/WHEEL,sha256=rNo05PbNqwnXiIHFsYm0m22u4Zm6YJtugFG2THx4w3g,92 -gevent_websocket-0.10.1.dist-info/metadata.json,sha256=XExyO_kAjuQqtilP6BOWLJPaezTVODL9OIwVIqrfQiM,582 -gevent_websocket-0.10.1.dist-info/top_level.txt,sha256=WTgLQQOgA-8n5eqLKVfJHX0yjqCBUtmq8kJYjB3ppXQ,16 -geventwebsocket/__init__.py,sha256=_HoAl2Lk6JpYlYQerqITTmtJW4PEb5Gc_LDWGT07R8s,441 -geventwebsocket/__pycache__/__init__.cpython-39.pyc,, -geventwebsocket/__pycache__/_compat.cpython-39.pyc,, -geventwebsocket/__pycache__/exceptions.cpython-39.pyc,, -geventwebsocket/__pycache__/handler.cpython-39.pyc,, -geventwebsocket/__pycache__/logging.cpython-39.pyc,, -geventwebsocket/__pycache__/resource.cpython-39.pyc,, -geventwebsocket/__pycache__/server.cpython-39.pyc,, -geventwebsocket/__pycache__/utf8validator.cpython-39.pyc,, -geventwebsocket/__pycache__/utils.cpython-39.pyc,, -geventwebsocket/__pycache__/websocket.cpython-39.pyc,, -geventwebsocket/_compat.py,sha256=cR7TQxMR4C62dQG4bZm7yoq3Yh55Z3Bwp50WyITifEk,484 -geventwebsocket/exceptions.py,sha256=3ed_NuUWYQcFENkoPMLLKnSiEf7VSfOt6NHpp8QfHxo,378 -geventwebsocket/gunicorn/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 -geventwebsocket/gunicorn/__pycache__/__init__.cpython-39.pyc,, -geventwebsocket/gunicorn/__pycache__/workers.cpython-39.pyc,, -geventwebsocket/gunicorn/workers.py,sha256=wRH20VBU_lU6wpEW3jCzbuj0RItvVyQIugjxVAdDW-c,196 -geventwebsocket/handler.py,sha256=rpzl4PMHJemjWXmtIca99GZI1oRi0uok64qQe4cTKvs,9579 -geventwebsocket/logging.py,sha256=txUUovb6xlxBgEihgFzxJw7X9WG3BNiQ1Do-8N6itCI,875 -geventwebsocket/protocols/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 -geventwebsocket/protocols/__pycache__/__init__.cpython-39.pyc,, -geventwebsocket/protocols/__pycache__/base.cpython-39.pyc,, -geventwebsocket/protocols/__pycache__/wamp.cpython-39.pyc,, -geventwebsocket/protocols/base.py,sha256=bqLQ8QJRm09royTznjau1ZC70swCoGnDtdrFr8poBNg,736 -geventwebsocket/protocols/wamp.py,sha256=3VIuxoXNTvZ4TeSwmRwPzmxiMx2LEdq0tW8vU3THIC4,6745 -geventwebsocket/resource.py,sha256=ySZXPNhtIzDZOUF8kC961FaVoYbcKipumGTYIuj_BYY,3077 -geventwebsocket/server.py,sha256=_Tu3cZh4W_PxOWF0wlYXmOOVmJ-_eyu6FaLJv_PEh6o,950 -geventwebsocket/utf8validator.py,sha256=BIBKbKaRso_Lo2-bVIE83GUfn6sfYqCV7lOicX1kq_U,10060 -geventwebsocket/utils.py,sha256=VYbrpapmq9B79kagK_tgTmLjV3U-Axwiu_dT0-6M14o,1185 -geventwebsocket/websocket.py,sha256=6-J2rhxGqVyF3dxweDkw8WPqyLfpicsulh0JqWDa6rI,16046 diff --git a/venv/lib/python3.9/site-packages/gevent_websocket-0.10.1.dist-info/REQUESTED b/venv/lib/python3.9/site-packages/gevent_websocket-0.10.1.dist-info/REQUESTED deleted file mode 100644 index e69de29..0000000 diff --git a/venv/lib/python3.9/site-packages/gevent_websocket-0.10.1.dist-info/WHEEL b/venv/lib/python3.9/site-packages/gevent_websocket-0.10.1.dist-info/WHEEL deleted file mode 100644 index bb7f7db..0000000 --- a/venv/lib/python3.9/site-packages/gevent_websocket-0.10.1.dist-info/WHEEL +++ /dev/null @@ -1,5 +0,0 @@ -Wheel-Version: 1.0 -Generator: bdist_wheel (0.29.0) -Root-Is-Purelib: true -Tag: py3-none-any - diff --git a/venv/lib/python3.9/site-packages/gevent_websocket-0.10.1.dist-info/metadata.json b/venv/lib/python3.9/site-packages/gevent_websocket-0.10.1.dist-info/metadata.json deleted file mode 100644 index ac6d51f..0000000 --- a/venv/lib/python3.9/site-packages/gevent_websocket-0.10.1.dist-info/metadata.json +++ /dev/null @@ -1 +0,0 @@ -{"extensions": {"python.details": {"contacts": [{"email": "jeffrey@noppo.pro", "name": "Jeffrey Gelens", "role": "author"}], "document_names": {"description": "DESCRIPTION.rst"}, "project_urls": {"Home": "https://www.gitlab.com/noppo/gevent-websocket"}}}, "extras": [], "generator": "bdist_wheel (0.29.0)", "license": "Copyright 2011-2017 Jeffrey Gelens ", "metadata_version": "2.0", "name": "gevent-websocket", "run_requires": [{"requires": ["gevent"]}], "summary": "Websocket handler for the gevent pywsgi server, a Python network library", "version": "0.10.1"} \ No newline at end of file diff --git a/venv/lib/python3.9/site-packages/gevent_websocket-0.10.1.dist-info/top_level.txt b/venv/lib/python3.9/site-packages/gevent_websocket-0.10.1.dist-info/top_level.txt deleted file mode 100644 index 4d11e1c..0000000 --- a/venv/lib/python3.9/site-packages/gevent_websocket-0.10.1.dist-info/top_level.txt +++ /dev/null @@ -1 +0,0 @@ -geventwebsocket diff --git a/venv/lib/python3.9/site-packages/geventwebsocket/__init__.py b/venv/lib/python3.9/site-packages/geventwebsocket/__init__.py deleted file mode 100644 index 5ee3f96..0000000 --- a/venv/lib/python3.9/site-packages/geventwebsocket/__init__.py +++ /dev/null @@ -1,21 +0,0 @@ -VERSION = (0, 10, 1, 'final', 0) - -__all__ = [ - 'WebSocketApplication', - 'Resource', - 'WebSocketServer', - 'WebSocketError', - 'get_version' -] - - -def get_version(*args, **kwargs): - from .utils import get_version - return get_version(*args, **kwargs) - -try: - from .resource import WebSocketApplication, Resource - from .server import WebSocketServer - from .exceptions import WebSocketError -except ImportError: - pass diff --git a/venv/lib/python3.9/site-packages/geventwebsocket/_compat.py b/venv/lib/python3.9/site-packages/geventwebsocket/_compat.py deleted file mode 100644 index 7035413..0000000 --- a/venv/lib/python3.9/site-packages/geventwebsocket/_compat.py +++ /dev/null @@ -1,23 +0,0 @@ -from __future__ import absolute_import, division, print_function - -import sys -import codecs - - -PY3 = sys.version_info[0] == 3 -PY2 = sys.version_info[0] == 2 - - -if PY2: - bytes = str - text_type = unicode - string_types = basestring - range_type = xrange - iteritems = lambda x: x.iteritems() - # b = lambda x: x -else: - text_type = str - string_types = str, - range_type = range - iteritems = lambda x: iter(x.items()) - # b = lambda x: codecs.latin_1_encode(x)[0] diff --git a/venv/lib/python3.9/site-packages/geventwebsocket/exceptions.py b/venv/lib/python3.9/site-packages/geventwebsocket/exceptions.py deleted file mode 100644 index e066727..0000000 --- a/venv/lib/python3.9/site-packages/geventwebsocket/exceptions.py +++ /dev/null @@ -1,19 +0,0 @@ -from socket import error as socket_error - - -class WebSocketError(socket_error): - """ - Base class for all websocket errors. - """ - - -class ProtocolError(WebSocketError): - """ - Raised if an error occurs when de/encoding the websocket protocol. - """ - - -class FrameTooLargeException(ProtocolError): - """ - Raised if a frame is received that is too large. - """ diff --git a/venv/lib/python3.9/site-packages/geventwebsocket/gunicorn/__init__.py b/venv/lib/python3.9/site-packages/geventwebsocket/gunicorn/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/venv/lib/python3.9/site-packages/geventwebsocket/gunicorn/workers.py b/venv/lib/python3.9/site-packages/geventwebsocket/gunicorn/workers.py deleted file mode 100644 index d0aa136..0000000 --- a/venv/lib/python3.9/site-packages/geventwebsocket/gunicorn/workers.py +++ /dev/null @@ -1,6 +0,0 @@ -from geventwebsocket.handler import WebSocketHandler -from gunicorn.workers.ggevent import GeventPyWSGIWorker - - -class GeventWebSocketWorker(GeventPyWSGIWorker): - wsgi_handler = WebSocketHandler diff --git a/venv/lib/python3.9/site-packages/geventwebsocket/handler.py b/venv/lib/python3.9/site-packages/geventwebsocket/handler.py deleted file mode 100644 index 8aec77c..0000000 --- a/venv/lib/python3.9/site-packages/geventwebsocket/handler.py +++ /dev/null @@ -1,283 +0,0 @@ -import base64 -import hashlib - -from gevent.pywsgi import WSGIHandler -from ._compat import PY3 -from .websocket import WebSocket, Stream -from .logging import create_logger - - -class Client(object): - def __init__(self, address, ws): - self.address = address - self.ws = ws - - -class WebSocketHandler(WSGIHandler): - """ - Automatically upgrades the connection to a websocket. - - To prevent the WebSocketHandler to call the underlying WSGI application, - but only setup the WebSocket negotiations, do: - - mywebsockethandler.prevent_wsgi_call = True - - before calling run_application(). This is useful if you want to do more - things before calling the app, and want to off-load the WebSocket - negotiations to this library. Socket.IO needs this for example, to send - the 'ack' before yielding the control to your WSGI app. - """ - - SUPPORTED_VERSIONS = ('13', '8', '7') - GUID = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11" - - def run_websocket(self): - """ - Called when a websocket has been created successfully. - """ - - if getattr(self, 'prevent_wsgi_call', False): - return - - # In case WebSocketServer is not used - if not hasattr(self.server, 'clients'): - self.server.clients = {} - - # Since we're now a websocket connection, we don't care what the - # application actually responds with for the http response - - try: - self.server.clients[self.client_address] = Client( - self.client_address, self.websocket) - list(self.application(self.environ, lambda s, h, e=None: [])) - finally: - del self.server.clients[self.client_address] - if not self.websocket.closed: - self.websocket.close() - self.environ.update({ - 'wsgi.websocket': None - }) - self.websocket = None - - def run_application(self): - if (hasattr(self.server, 'pre_start_hook') and self.server.pre_start_hook): - self.logger.debug("Calling pre-start hook") - if self.server.pre_start_hook(self): - return super(WebSocketHandler, self).run_application() - - self.logger.debug("Initializing WebSocket") - self.result = self.upgrade_websocket() - - if hasattr(self, 'websocket'): - if self.status and not self.headers_sent: - self.write('') - - self.run_websocket() - else: - if self.status: - # A status was set, likely an error so just send the response - if not self.result: - self.result = [] - - self.process_result() - return - - # This handler did not handle the request, so defer it to the - # underlying application object - return super(WebSocketHandler, self).run_application() - - def upgrade_websocket(self): - """ - Attempt to upgrade the current environ into a websocket enabled - connection. If successful, the environ dict with be updated with two - new entries, `wsgi.websocket` and `wsgi.websocket_version`. - - :returns: Whether the upgrade was successful. - """ - - # Some basic sanity checks first - - self.logger.debug("Validating WebSocket request") - - if self.environ.get('REQUEST_METHOD', '') != 'GET': - # This is not a websocket request, so we must not handle it - self.logger.debug('Can only upgrade connection if using GET method.') - return - - upgrade = self.environ.get('HTTP_UPGRADE', '').lower() - - if upgrade == 'websocket': - connection = self.environ.get('HTTP_CONNECTION', '').lower() - - if 'upgrade' not in connection: - # This is not a websocket request, so we must not handle it - self.logger.warning("Client didn't ask for a connection " - "upgrade") - return - else: - # This is not a websocket request, so we must not handle it - return - - if self.request_version != 'HTTP/1.1': - self.start_response('402 Bad Request', []) - self.logger.warning("Bad server protocol in headers") - - return ['Bad protocol version'] - - if self.environ.get('HTTP_SEC_WEBSOCKET_VERSION'): - return self.upgrade_connection() - else: - self.logger.warning("No protocol defined") - self.start_response('426 Upgrade Required', [ - ('Sec-WebSocket-Version', ', '.join(self.SUPPORTED_VERSIONS))]) - - return ['No Websocket protocol version defined'] - - def upgrade_connection(self): - """ - Validate and 'upgrade' the HTTP request to a WebSocket request. - - If an upgrade succeeded then then handler will have `start_response` - with a status of `101`, the environ will also be updated with - `wsgi.websocket` and `wsgi.websocket_version` keys. - - :param environ: The WSGI environ dict. - :param start_response: The callable used to start the response. - :param stream: File like object that will be read from/written to by - the underlying WebSocket object, if created. - :return: The WSGI response iterator is something went awry. - """ - - self.logger.debug("Attempting to upgrade connection") - - version = self.environ.get("HTTP_SEC_WEBSOCKET_VERSION") - - if version not in self.SUPPORTED_VERSIONS: - msg = "Unsupported WebSocket Version: {0}".format(version) - - self.logger.warning(msg) - self.start_response('400 Bad Request', [ - ('Sec-WebSocket-Version', ', '.join(self.SUPPORTED_VERSIONS)) - ]) - - return [msg] - - key = self.environ.get("HTTP_SEC_WEBSOCKET_KEY", '').strip() - - if not key: - # 5.2.1 (3) - msg = "Sec-WebSocket-Key header is missing/empty" - - self.logger.warning(msg) - self.start_response('400 Bad Request', []) - - return [msg] - - try: - key_len = len(base64.b64decode(key)) - except TypeError: - msg = "Invalid key: {0}".format(key) - - self.logger.warning(msg) - self.start_response('400 Bad Request', []) - - return [msg] - - if key_len != 16: - # 5.2.1 (3) - msg = "Invalid key: {0}".format(key) - - self.logger.warning(msg) - self.start_response('400 Bad Request', []) - - return [msg] - - # Check for WebSocket Protocols - requested_protocols = self.environ.get( - 'HTTP_SEC_WEBSOCKET_PROTOCOL', '') - protocol = None - - if hasattr(self.application, 'app_protocol'): - allowed_protocol = self.application.app_protocol( - self.environ['PATH_INFO']) - - if allowed_protocol and allowed_protocol in requested_protocols: - protocol = allowed_protocol - self.logger.debug("Protocol allowed: {0}".format(protocol)) - - self.websocket = WebSocket(self.environ, Stream(self), self) - self.environ.update({ - 'wsgi.websocket_version': version, - 'wsgi.websocket': self.websocket - }) - - if PY3: - accept = base64.b64encode( - hashlib.sha1((key + self.GUID).encode("latin-1")).digest() - ).decode("latin-1") - else: - accept = base64.b64encode(hashlib.sha1(key + self.GUID).digest()) - - headers = [ - ("Upgrade", "websocket"), - ("Connection", "Upgrade"), - ("Sec-WebSocket-Accept", accept) - ] - - if protocol: - headers.append(("Sec-WebSocket-Protocol", protocol)) - - self.logger.debug("WebSocket request accepted, switching protocols") - self.start_response("101 Switching Protocols", headers) - - @property - def logger(self): - if not hasattr(self.server, 'logger'): - self.server.logger = create_logger(__name__) - - return self.server.logger - - def log_request(self): - if '101' not in str(self.status): - self.logger.info(self.format_request()) - - @property - def active_client(self): - return self.server.clients[self.client_address] - - def start_response(self, status, headers, exc_info=None): - """ - Called when the handler is ready to send a response back to the remote - endpoint. A websocket connection may have not been created. - """ - writer = super(WebSocketHandler, self).start_response( - status, headers, exc_info=exc_info) - - self._prepare_response() - - return writer - - def _prepare_response(self): - """ - Sets up the ``pywsgi.Handler`` to work with a websocket response. - - This is used by other projects that need to support WebSocket - connections as part of a larger effort. - """ - assert not self.headers_sent - - if not self.environ.get('wsgi.websocket'): - # a WebSocket connection is not established, do nothing - return - - # So that `finalize_headers` doesn't write a Content-Length header - self.provided_content_length = False - - # The websocket is now controlling the response - self.response_use_chunked = False - - # Once the request is over, the connection must be closed - self.close_connection = True - - # Prevents the Date header from being written - self.provided_date = True diff --git a/venv/lib/python3.9/site-packages/geventwebsocket/logging.py b/venv/lib/python3.9/site-packages/geventwebsocket/logging.py deleted file mode 100644 index 554ca02..0000000 --- a/venv/lib/python3.9/site-packages/geventwebsocket/logging.py +++ /dev/null @@ -1,31 +0,0 @@ -from __future__ import absolute_import - -from logging import getLogger, StreamHandler, getLoggerClass, Formatter, DEBUG - - -def create_logger(name, debug=False, format=None): - Logger = getLoggerClass() - - class DebugLogger(Logger): - def getEffectiveLevel(x): - if x.level == 0 and debug: - return DEBUG - else: - return Logger.getEffectiveLevel(x) - - class DebugHandler(StreamHandler): - def emit(x, record): - StreamHandler.emit(x, record) if debug else None - - handler = DebugHandler() - handler.setLevel(DEBUG) - - if format: - handler.setFormatter(Formatter(format)) - - logger = getLogger(name) - del logger.handlers[:] - logger.__class__ = DebugLogger - logger.addHandler(handler) - - return logger diff --git a/venv/lib/python3.9/site-packages/geventwebsocket/protocols/__init__.py b/venv/lib/python3.9/site-packages/geventwebsocket/protocols/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/venv/lib/python3.9/site-packages/geventwebsocket/protocols/base.py b/venv/lib/python3.9/site-packages/geventwebsocket/protocols/base.py deleted file mode 100644 index 1c05ab6..0000000 --- a/venv/lib/python3.9/site-packages/geventwebsocket/protocols/base.py +++ /dev/null @@ -1,35 +0,0 @@ -class BaseProtocol(object): - PROTOCOL_NAME = '' - - def __init__(self, app): - self._app = app - - def on_open(self): - self.app.on_open() - - def on_message(self, message): - self.app.on_message(message) - - def on_close(self, reason=None): - self.app.on_close(reason) - - @property - def app(self): - if self._app: - return self._app - else: - raise Exception("No application coupled") - - @property - def server(self): - if not hasattr(self.app, 'ws'): - return None - - return self.app.ws.handler.server - - @property - def handler(self): - if not hasattr(self.app, 'ws'): - return None - - return self.app.ws.handler diff --git a/venv/lib/python3.9/site-packages/geventwebsocket/protocols/wamp.py b/venv/lib/python3.9/site-packages/geventwebsocket/protocols/wamp.py deleted file mode 100644 index c89775b..0000000 --- a/venv/lib/python3.9/site-packages/geventwebsocket/protocols/wamp.py +++ /dev/null @@ -1,235 +0,0 @@ -import inspect -import random -import string -import types - -try: - import ujson as json -except ImportError: - try: - import simplejson as json - except ImportError: - import json - -from .._compat import range_type, string_types -from ..exceptions import WebSocketError -from .base import BaseProtocol - - -def export_rpc(arg=None): - if isinstance(arg, types.FunctionType): - arg._rpc = arg.__name__ - return arg - - -def serialize(data): - return json.dumps(data) - - -class Prefixes(object): - def __init__(self): - self.prefixes = {} - - def add(self, prefix, uri): - self.prefixes[prefix] = uri - - def resolve(self, curie_or_uri): - if "http://" in curie_or_uri: - return curie_or_uri - elif ':' in curie_or_uri: - prefix, proc = curie_or_uri.split(':', 1) - return self.prefixes[prefix] + proc - else: - raise Exception(curie_or_uri) - - -class RemoteProcedures(object): - def __init__(self): - self.calls = {} - - def register_procedure(self, uri, proc): - self.calls[uri] = proc - - def register_object(self, uri, obj): - for k in inspect.getmembers(obj, inspect.ismethod): - if '_rpc' in k[1].__dict__: - proc_uri = uri + k[1]._rpc - self.calls[proc_uri] = (obj, k[1]) - - def call(self, uri, args): - if uri in self.calls: - proc = self.calls[uri] - - # Do the correct call whether it's a function or instance method. - if isinstance(proc, tuple): - if proc[1].__self__ is None: - # Create instance of object and call method - return proc[1](proc[0](), *args) - else: - # Call bound method on instance - return proc[1](*args) - else: - return self.calls[uri](*args) - else: - raise Exception("no such uri '{}'".format(uri)) - - -class Channels(object): - def __init__(self): - self.channels = {} - - def create(self, uri, prefix_matching=False): - if uri not in self.channels: - self.channels[uri] = [] - - # TODO: implement prefix matching - - def subscribe(self, uri, client): - if uri in self.channels: - self.channels[uri].append(client) - - def unsubscribe(self, uri, client): - if uri not in self.channels: - return - - client_index = self.channels[uri].index(client) - self.channels[uri].pop(client_index) - - if len(self.channels[uri]) == 0: - del self.channels[uri] - - def publish(self, uri, event, exclude=None, eligible=None): - if uri not in self.channels: - return - - # TODO: exclude & eligible - - msg = [WampProtocol.MSG_EVENT, uri, event] - - for client in self.channels[uri]: - try: - client.ws.send(serialize(msg)) - except WebSocketError: - # Seems someone didn't unsubscribe before disconnecting - self.channels[uri].remove(client) - - -class WampProtocol(BaseProtocol): - MSG_WELCOME = 0 - MSG_PREFIX = 1 - MSG_CALL = 2 - MSG_CALL_RESULT = 3 - MSG_CALL_ERROR = 4 - MSG_SUBSCRIBE = 5 - MSG_UNSUBSCRIBE = 6 - MSG_PUBLISH = 7 - MSG_EVENT = 8 - - PROTOCOL_NAME = "wamp" - - def __init__(self, *args, **kwargs): - self.procedures = RemoteProcedures() - self.prefixes = Prefixes() - self.session_id = ''.join( - [random.choice(string.digits + string.letters) - for i in range_type(16)]) - - super(WampProtocol, self).__init__(*args, **kwargs) - - def register_procedure(self, *args, **kwargs): - self.procedures.register_procedure(*args, **kwargs) - - def register_object(self, *args, **kwargs): - self.procedures.register_object(*args, **kwargs) - - def register_pubsub(self, *args, **kwargs): - if not hasattr(self.server, 'channels'): - self.server.channels = Channels() - - self.server.channels.create(*args, **kwargs) - - def do_handshake(self): - from geventwebsocket import get_version - - welcome = [ - self.MSG_WELCOME, - self.session_id, - 1, - 'gevent-websocket/' + get_version() - ] - self.app.ws.send(serialize(welcome)) - - def _get_exception_info(self, e): - uri = 'http://TODO#generic' - desc = str(type(e)) - details = str(e) - return [uri, desc, details] - - def rpc_call(self, data): - call_id, curie_or_uri = data[1:3] - args = data[3:] - - if not isinstance(call_id, string_types): - raise Exception() - if not isinstance(curie_or_uri, string_types): - raise Exception() - - uri = self.prefixes.resolve(curie_or_uri) - - try: - result = self.procedures.call(uri, args) - result_msg = [self.MSG_CALL_RESULT, call_id, result] - except Exception as e: - result_msg = [self.MSG_CALL_ERROR, - call_id] + self._get_exception_info(e) - - self.app.on_message(serialize(result_msg)) - - def pubsub_action(self, data): - action = data[0] - curie_or_uri = data[1] - - if not isinstance(action, int): - raise Exception() - if not isinstance(curie_or_uri, string_types): - raise Exception() - - uri = self.prefixes.resolve(curie_or_uri) - - if action == self.MSG_SUBSCRIBE and len(data) == 2: - self.server.channels.subscribe(data[1], self.handler.active_client) - - elif action == self.MSG_UNSUBSCRIBE and len(data) == 2: - self.server.channels.unsubscribe( - data[1], self.handler.active_client) - - elif action == self.MSG_PUBLISH and len(data) >= 3: - payload = data[2] if len(data) >= 3 else None - exclude = data[3] if len(data) >= 4 else None - eligible = data[4] if len(data) >= 5 else None - - self.server.channels.publish(uri, payload, exclude, eligible) - - def on_open(self): - self.app.on_open() - self.do_handshake() - - def on_message(self, message): - data = json.loads(message) - - if not isinstance(data, list): - raise Exception('incoming data is no list') - - if data[0] == self.MSG_PREFIX and len(data) == 3: - prefix, uri = data[1:3] - self.prefixes.add(prefix, uri) - - elif data[0] == self.MSG_CALL and len(data) >= 3: - return self.rpc_call(data) - - elif data[0] in (self.MSG_SUBSCRIBE, self.MSG_UNSUBSCRIBE, - self.MSG_PUBLISH): - return self.pubsub_action(data) - else: - raise Exception("Unknown call") - diff --git a/venv/lib/python3.9/site-packages/geventwebsocket/resource.py b/venv/lib/python3.9/site-packages/geventwebsocket/resource.py deleted file mode 100644 index 549f0d3..0000000 --- a/venv/lib/python3.9/site-packages/geventwebsocket/resource.py +++ /dev/null @@ -1,100 +0,0 @@ -import re -import warnings - -from .protocols.base import BaseProtocol -from .exceptions import WebSocketError - -try: - from collections import OrderedDict -except ImportError: - class OrderedDict: - pass - - -class WebSocketApplication(object): - protocol_class = BaseProtocol - - def __init__(self, ws): - self.protocol = self.protocol_class(self) - self.ws = ws - - def handle(self): - self.protocol.on_open() - - while True: - try: - message = self.ws.receive() - except WebSocketError: - self.protocol.on_close() - break - - self.protocol.on_message(message) - - def on_open(self, *args, **kwargs): - pass - - def on_close(self, *args, **kwargs): - pass - - def on_message(self, message, *args, **kwargs): - self.ws.send(message, **kwargs) - - @classmethod - def protocol_name(cls): - return cls.protocol_class.PROTOCOL_NAME - - -class Resource(object): - def __init__(self, apps=None): - self.apps = apps if apps else [] - - if isinstance(apps, dict): - if not isinstance(apps, OrderedDict): - warnings.warn("Using an unordered dictionary for the " - "app list is discouraged and may lead to " - "undefined behavior.", UserWarning) - - self.apps = apps.items() - - # An app can either be a standard WSGI application (an object we call with - # __call__(self, environ, start_response)) or a class we instantiate - # (and which can handle websockets). This function tells them apart. - # Override this if you have apps that can handle websockets but don't - # fulfill these criteria. - def _is_websocket_app(self, app): - return isinstance(app, type) and issubclass(app, WebSocketApplication) - - def _app_by_path(self, environ_path, is_websocket_request): - # Which app matched the current path? - for path, app in self.apps: - if re.match(path, environ_path): - if is_websocket_request == self._is_websocket_app(app): - return app - return None - - def app_protocol(self, path): - # app_protocol will only be called for websocket apps - app = self._app_by_path(path, True) - - if hasattr(app, 'protocol_name'): - return app.protocol_name() - else: - return '' - - def __call__(self, environ, start_response): - environ = environ - is_websocket_call = 'wsgi.websocket' in environ - current_app = self._app_by_path(environ['PATH_INFO'], is_websocket_call) - - if current_app is None: - raise Exception("No apps defined") - - if is_websocket_call: - ws = environ['wsgi.websocket'] - current_app = current_app(ws) - current_app.ws = ws # TODO: needed? - current_app.handle() - # Always return something, calling WSGI middleware may rely on it - return [] - else: - return current_app(environ, start_response) diff --git a/venv/lib/python3.9/site-packages/geventwebsocket/server.py b/venv/lib/python3.9/site-packages/geventwebsocket/server.py deleted file mode 100644 index e939bd1..0000000 --- a/venv/lib/python3.9/site-packages/geventwebsocket/server.py +++ /dev/null @@ -1,34 +0,0 @@ -from gevent.pywsgi import WSGIServer - -from .handler import WebSocketHandler -from .logging import create_logger - - -class WebSocketServer(WSGIServer): - handler_class = WebSocketHandler - debug_log_format = ( - '-' * 80 + '\n' + - '%(levelname)s in %(module)s [%(pathname)s:%(lineno)d]:\n' + - '%(message)s\n' + - '-' * 80 - ) - - def __init__(self, *args, **kwargs): - self.debug = kwargs.pop('debug', False) - self.pre_start_hook = kwargs.pop('pre_start_hook', None) - self._logger = None - self.clients = {} - - super(WebSocketServer, self).__init__(*args, **kwargs) - - def handle(self, socket, address): - handler = self.handler_class(socket, address, self) - handler.handle() - - @property - def logger(self): - if not self._logger: - self._logger = create_logger( - __name__, self.debug, self.debug_log_format) - - return self._logger diff --git a/venv/lib/python3.9/site-packages/geventwebsocket/utf8validator.py b/venv/lib/python3.9/site-packages/geventwebsocket/utf8validator.py deleted file mode 100644 index d604f96..0000000 --- a/venv/lib/python3.9/site-packages/geventwebsocket/utf8validator.py +++ /dev/null @@ -1,224 +0,0 @@ -from ._compat import PY3 - -############################################################################### -# -# The MIT License (MIT) -# -# Copyright (c) Crossbar.io Technologies GmbH -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. -# -############################################################################### - -# Note: This code is a Python implementation of the algorithm -# "Flexible and Economical UTF-8 Decoder" by Bjoern Hoehrmann -# bjoern@hoehrmann.de, http://bjoern.hoehrmann.de/utf-8/decoder/dfa/ - -__all__ = ("Utf8Validator",) - - -# DFA transitions -UTF8VALIDATOR_DFA = ( - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, # 00..1f - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, # 20..3f - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, # 40..5f - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, # 60..7f - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, # 80..9f - 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, # a0..bf - 8, 8, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, # c0..df - 0xa, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x4, 0x3, 0x3, # e0..ef - 0xb, 0x6, 0x6, 0x6, 0x5, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, # f0..ff - 0x0, 0x1, 0x2, 0x3, 0x5, 0x8, 0x7, 0x1, 0x1, 0x1, 0x4, 0x6, 0x1, 0x1, 0x1, 0x1, # s0..s0 - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, # s1..s2 - 1, 2, 1, 1, 1, 1, 1, 2, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, # s3..s4 - 1, 2, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 1, 3, 1, 1, 1, 1, 1, 1, # s5..s6 - 1, 3, 1, 1, 1, 1, 1, 3, 1, 3, 1, 1, 1, 1, 1, 1, 1, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, # s7..s8 -) - -UTF8_ACCEPT = 0 -UTF8_REJECT = 1 - - -# use Cython implementation of UTF8 validator if available -# -try: - from wsaccel.utf8validator import Utf8Validator - -except ImportError: - # - # Fallback to pure Python implementation - also for PyPy. - # - # Do NOT touch this code unless you know what you are doing! - # https://github.com/oberstet/scratchbox/tree/master/python/utf8 - # - - if PY3: - - # Python 3 and above - - # convert DFA table to bytes (performance) - UTF8VALIDATOR_DFA_S = bytes(UTF8VALIDATOR_DFA) - - class Utf8Validator(object): - """ - Incremental UTF-8 validator with constant memory consumption (minimal state). - - Implements the algorithm "Flexible and Economical UTF-8 Decoder" by - Bjoern Hoehrmann (http://bjoern.hoehrmann.de/utf-8/decoder/dfa/). - """ - - def __init__(self): - self.reset() - - def decode(self, b): - """ - Eat one UTF-8 octet, and validate on the fly. - - Returns ``UTF8_ACCEPT`` when enough octets have been consumed, in which case - ``self.codepoint`` contains the decoded Unicode code point. - - Returns ``UTF8_REJECT`` when invalid UTF-8 was encountered. - - Returns some other positive integer when more octets need to be eaten. - """ - tt = UTF8VALIDATOR_DFA_S[b] - if self.state != UTF8_ACCEPT: - self.codepoint = (b & 0x3f) | (self.codepoint << 6) - else: - self.codepoint = (0xff >> tt) & b - self.state = UTF8VALIDATOR_DFA_S[256 + self.state * 16 + tt] - return self.state - - def reset(self): - """ - Reset validator to start new incremental UTF-8 decode/validation. - """ - self.state = UTF8_ACCEPT # the empty string is valid UTF8 - self.codepoint = 0 - self.i = 0 - - def validate(self, ba): - """ - Incrementally validate a chunk of bytes provided as string. - - Will return a quad ``(valid?, endsOnCodePoint?, currentIndex, totalIndex)``. - - As soon as an octet is encountered which renders the octet sequence - invalid, a quad with ``valid? == False`` is returned. ``currentIndex`` returns - the index within the currently consumed chunk, and ``totalIndex`` the - index within the total consumed sequence that was the point of bail out. - When ``valid? == True``, currentIndex will be ``len(ba)`` and ``totalIndex`` the - total amount of consumed bytes. - """ - # - # The code here is written for optimal JITting in PyPy, not for best - # readability by your grandma or particular elegance. Do NOT touch! - # - l = len(ba) - i = 0 - state = self.state - while i < l: - # optimized version of decode(), since we are not interested in actual code points - state = UTF8VALIDATOR_DFA_S[256 + (state << 4) + UTF8VALIDATOR_DFA_S[ba[i]]] - if state == UTF8_REJECT: - self.state = state - self.i += i - return False, False, i, self.i - i += 1 - self.state = state - self.i += l - return True, state == UTF8_ACCEPT, l, self.i - - else: - - # convert DFA table to string (performance) - UTF8VALIDATOR_DFA_S = ''.join([chr(c) for c in UTF8VALIDATOR_DFA]) - - class Utf8Validator(object): - """ - Incremental UTF-8 validator with constant memory consumption (minimal state). - - Implements the algorithm "Flexible and Economical UTF-8 Decoder" by - Bjoern Hoehrmann (http://bjoern.hoehrmann.de/utf-8/decoder/dfa/). - """ - - def __init__(self): - self.reset() - - def decode(self, b): - """ - Eat one UTF-8 octet, and validate on the fly. - - Returns ``UTF8_ACCEPT`` when enough octets have been consumed, in which case - ``self.codepoint`` contains the decoded Unicode code point. - - Returns ``UTF8_REJECT`` when invalid UTF-8 was encountered. - - Returns some other positive integer when more octets need to be eaten. - """ - tt = ord(UTF8VALIDATOR_DFA_S[b]) - if self.state != UTF8_ACCEPT: - self.codepoint = (b & 0x3f) | (self.codepoint << 6) - else: - self.codepoint = (0xff >> tt) & b - self.state = ord(UTF8VALIDATOR_DFA_S[256 + self.state * 16 + tt]) - return self.state - - def reset(self): - """ - Reset validator to start new incremental UTF-8 decode/validation. - """ - self.state = UTF8_ACCEPT # the empty string is valid UTF8 - self.codepoint = 0 - self.i = 0 - - def validate(self, ba): - """ - Incrementally validate a chunk of bytes provided as string. - - Will return a quad ``(valid?, endsOnCodePoint?, currentIndex, totalIndex)``. - - As soon as an octet is encountered which renders the octet sequence - invalid, a quad with ``valid? == False`` is returned. ``currentIndex`` returns - the index within the currently consumed chunk, and ``totalIndex`` the - index within the total consumed sequence that was the point of bail out. - When ``valid? == True``, currentIndex will be ``len(ba)`` and ``totalIndex`` the - total amount of consumed bytes. - """ - # - # The code here is written for optimal JITting in PyPy, not for best - # readability by your grandma or particular elegance. Do NOT touch! - # - l = len(ba) - i = 0 - state = self.state - while i < l: - # optimized version of decode(), since we are not interested in actual code points - try: - state = ord(UTF8VALIDATOR_DFA_S[256 + (state << 4) + ord(UTF8VALIDATOR_DFA_S[ba[i]])]) - except: - import ipdb; ipdb.set_trace() - if state == UTF8_REJECT: - self.state = state - self.i += i - return False, False, i, self.i - i += 1 - self.state = state - self.i += l - return True, state == UTF8_ACCEPT, l, self.i diff --git a/venv/lib/python3.9/site-packages/geventwebsocket/utils.py b/venv/lib/python3.9/site-packages/geventwebsocket/utils.py deleted file mode 100644 index 2e5bc3b..0000000 --- a/venv/lib/python3.9/site-packages/geventwebsocket/utils.py +++ /dev/null @@ -1,45 +0,0 @@ -import subprocess - - -def get_version(version=None): - "Returns a PEP 386-compliant version number from VERSION." - - if version is None: - from geventwebsocket import VERSION as version - else: - assert len(version) == 5 - assert version[3] in ('alpha', 'beta', 'rc', 'final') - - # Now build the two parts of the version number: - # main = X.Y[.Z] - # sub = .devN - for pre-alpha releases - # | {a|b|c}N - for alpha, beta and rc releases - - parts = 2 if version[2] == 0 else 3 - main = '.'.join(str(x) for x in version[:parts]) - - sub = '' - if version[3] == 'alpha' and version[4] == 0: - hg_changeset = get_hg_changeset() - if hg_changeset: - sub = '.dev{0}'.format(hg_changeset) - - elif version[3] != 'final': - mapping = {'alpha': 'a', 'beta': 'b', 'rc': 'c'} - sub = mapping[version[3]] + str(version[4]) - - return str(main + sub) - - -def get_hg_changeset(): - rev, err = subprocess.Popen( - 'hg id -i', - shell=True, - stdout=subprocess.PIPE, - stderr=subprocess.PIPE - ).communicate() - - if err: - return None - else: - return rev.strip().replace('+', '') diff --git a/venv/lib/python3.9/site-packages/geventwebsocket/websocket.py b/venv/lib/python3.9/site-packages/geventwebsocket/websocket.py deleted file mode 100644 index 4557926..0000000 --- a/venv/lib/python3.9/site-packages/geventwebsocket/websocket.py +++ /dev/null @@ -1,565 +0,0 @@ -import struct - -from socket import error - -from ._compat import string_types, range_type, text_type -from .exceptions import ProtocolError -from .exceptions import WebSocketError -from .exceptions import FrameTooLargeException -from .utf8validator import Utf8Validator - - -MSG_SOCKET_DEAD = "Socket is dead" -MSG_ALREADY_CLOSED = "Connection is already closed" -MSG_CLOSED = "Connection closed" - - -class WebSocket(object): - """ - Base class for supporting websocket operations. - - :ivar environ: The http environment referenced by this connection. - :ivar closed: Whether this connection is closed/closing. - :ivar stream: The underlying file like object that will be read from / - written to by this WebSocket object. - """ - - __slots__ = ('utf8validator', 'utf8validate_last', 'environ', 'closed', - 'stream', 'raw_write', 'raw_read', 'handler') - - OPCODE_CONTINUATION = 0x00 - OPCODE_TEXT = 0x01 - OPCODE_BINARY = 0x02 - OPCODE_CLOSE = 0x08 - OPCODE_PING = 0x09 - OPCODE_PONG = 0x0a - - def __init__(self, environ, stream, handler): - self.environ = environ - self.closed = False - - self.stream = stream - - self.raw_write = stream.write - self.raw_read = stream.read - - self.utf8validator = Utf8Validator() - self.handler = handler - - def __del__(self): - try: - self.close() - except: - # close() may fail if __init__ didn't complete - pass - - def _decode_bytes(self, bytestring): - """ - Internal method used to convert the utf-8 encoded bytestring into - unicode. - - If the conversion fails, the socket will be closed. - """ - - if not bytestring: - return '' - - try: - return bytestring.decode('utf-8') - except UnicodeDecodeError: - self.close(1007) - - raise - - def _encode_bytes(self, text): - """ - :returns: The utf-8 byte string equivalent of `text`. - """ - - if not isinstance(text, str): - text = text_type(text or '') - - return text.encode("utf-8") - - def _is_valid_close_code(self, code): - """ - :returns: Whether the returned close code is a valid hybi return code. - """ - if code < 1000: - return False - - if 1004 <= code <= 1006: - return False - - if 1012 <= code <= 1016: - return False - - if code == 1100: - # not sure about this one but the autobahn fuzzer requires it. - return False - - if 2000 <= code <= 2999: - return False - - return True - - @property - def current_app(self): - if hasattr(self.handler.server.application, 'current_app'): - return self.handler.server.application.current_app - else: - # For backwards compatibility reasons - class MockApp(): - def on_close(self, *args): - pass - - return MockApp() - - @property - def origin(self): - if not self.environ: - return - - return self.environ.get('HTTP_ORIGIN') - - @property - def protocol(self): - if not self.environ: - return - - return self.environ.get('HTTP_SEC_WEBSOCKET_PROTOCOL') - - @property - def version(self): - if not self.environ: - return - - return self.environ.get('HTTP_SEC_WEBSOCKET_VERSION') - - @property - def path(self): - if not self.environ: - return - - return self.environ.get('PATH_INFO') - - @property - def logger(self): - return self.handler.logger - - def handle_close(self, header, payload): - """ - Called when a close frame has been decoded from the stream. - - :param header: The decoded `Header`. - :param payload: The bytestring payload associated with the close frame. - """ - if not payload: - self.close(1000, None) - - return - - if len(payload) < 2: - raise ProtocolError('Invalid close frame: {0} {1}'.format( - header, payload)) - - code = struct.unpack('!H', payload[:2])[0] - payload = payload[2:] - - if payload: - validator = Utf8Validator() - val = validator.validate(payload) - - if not val[0]: - raise UnicodeError - - if not self._is_valid_close_code(code): - raise ProtocolError('Invalid close code {0}'.format(code)) - - self.close(code, payload) - - def handle_ping(self, header, payload): - self.send_frame(payload, self.OPCODE_PONG) - - def handle_pong(self, header, payload): - pass - - def read_frame(self): - """ - Block until a full frame has been read from the socket. - - This is an internal method as calling this will not cleanup correctly - if an exception is called. Use `receive` instead. - - :return: The header and payload as a tuple. - """ - - header = Header.decode_header(self.stream) - - if header.flags: - raise ProtocolError - - if not header.length: - return header, b'' - - try: - payload = self.raw_read(header.length) - except error: - payload = b'' - except Exception: - # TODO log out this exception - payload = b'' - - if len(payload) != header.length: - raise WebSocketError('Unexpected EOF reading frame payload') - - if header.mask: - payload = header.unmask_payload(payload) - - return header, payload - - def validate_utf8(self, payload): - # Make sure the frames are decodable independently - self.utf8validate_last = self.utf8validator.validate(payload) - - if not self.utf8validate_last[0]: - raise UnicodeError("Encountered invalid UTF-8 while processing " - "text message at payload octet index " - "{0:d}".format(self.utf8validate_last[3])) - - def read_message(self): - """ - Return the next text or binary message from the socket. - - This is an internal method as calling this will not cleanup correctly - if an exception is called. Use `receive` instead. - """ - opcode = None - message = bytearray() - - while True: - header, payload = self.read_frame() - f_opcode = header.opcode - - if f_opcode in (self.OPCODE_TEXT, self.OPCODE_BINARY): - # a new frame - if opcode: - raise ProtocolError("The opcode in non-fin frame is " - "expected to be zero, got " - "{0!r}".format(f_opcode)) - - # Start reading a new message, reset the validator - self.utf8validator.reset() - self.utf8validate_last = (True, True, 0, 0) - - opcode = f_opcode - - elif f_opcode == self.OPCODE_CONTINUATION: - if not opcode: - raise ProtocolError("Unexpected frame with opcode=0") - - elif f_opcode == self.OPCODE_PING: - self.handle_ping(header, payload) - continue - - elif f_opcode == self.OPCODE_PONG: - self.handle_pong(header, payload) - continue - - elif f_opcode == self.OPCODE_CLOSE: - self.handle_close(header, payload) - return - - else: - raise ProtocolError("Unexpected opcode={0!r}".format(f_opcode)) - - if opcode == self.OPCODE_TEXT: - self.validate_utf8(payload) - - message += payload - - if header.fin: - break - - if opcode == self.OPCODE_TEXT: - self.validate_utf8(message) - return self._decode_bytes(message) - else: - return message - - def receive(self): - """ - Read and return a message from the stream. If `None` is returned, then - the socket is considered closed/errored. - """ - - if self.closed: - self.current_app.on_close(MSG_ALREADY_CLOSED) - raise WebSocketError(MSG_ALREADY_CLOSED) - - try: - return self.read_message() - except UnicodeError: - self.close(1007) - except ProtocolError: - self.close(1002) - except error: - self.close() - self.current_app.on_close(MSG_CLOSED) - - return None - - def send_frame(self, message, opcode): - """ - Send a frame over the websocket with message as its payload - """ - if self.closed: - self.current_app.on_close(MSG_ALREADY_CLOSED) - raise WebSocketError(MSG_ALREADY_CLOSED) - - if opcode in (self.OPCODE_TEXT, self.OPCODE_PING): - message = self._encode_bytes(message) - elif opcode == self.OPCODE_BINARY: - message = bytes(message) - - header = Header.encode_header(True, opcode, b'', len(message), 0) - - try: - self.raw_write(header + message) - except error: - raise WebSocketError(MSG_SOCKET_DEAD) - except: - raise - - def send(self, message, binary=None): - """ - Send a frame over the websocket with message as its payload - """ - if binary is None: - binary = not isinstance(message, string_types) - - opcode = self.OPCODE_BINARY if binary else self.OPCODE_TEXT - - try: - self.send_frame(message, opcode) - except WebSocketError: - self.current_app.on_close(MSG_SOCKET_DEAD) - raise WebSocketError(MSG_SOCKET_DEAD) - - def close(self, code=1000, message=b''): - """ - Close the websocket and connection, sending the specified code and - message. The underlying socket object is _not_ closed, that is the - responsibility of the initiator. - """ - - if self.closed: - self.current_app.on_close(MSG_ALREADY_CLOSED) - - try: - message = self._encode_bytes(message) - - self.send_frame(message, opcode=self.OPCODE_CLOSE) - except WebSocketError: - # Failed to write the closing frame but it's ok because we're - # closing the socket anyway. - self.logger.debug("Failed to write closing frame -> closing socket") - finally: - self.logger.debug("Closed WebSocket") - self.closed = True - - self.stream = None - self.raw_write = None - self.raw_read = None - - self.environ = None - - #self.current_app.on_close(MSG_ALREADY_CLOSED) - - -class Stream(object): - """ - Wraps the handler's socket/rfile attributes and makes it in to a file like - object that can be read from/written to by the lower level websocket api. - """ - - __slots__ = ('handler', 'read', 'write') - - def __init__(self, handler): - self.handler = handler - self.read = handler.rfile.read - self.write = handler.socket.sendall - - -class Header(object): - __slots__ = ('fin', 'mask', 'opcode', 'flags', 'length') - - FIN_MASK = 0x80 - OPCODE_MASK = 0x0f - MASK_MASK = 0x80 - LENGTH_MASK = 0x7f - - RSV0_MASK = 0x40 - RSV1_MASK = 0x20 - RSV2_MASK = 0x10 - - # bitwise mask that will determine the reserved bits for a frame header - HEADER_FLAG_MASK = RSV0_MASK | RSV1_MASK | RSV2_MASK - - def __init__(self, fin=0, opcode=0, flags=0, length=0): - self.mask = '' - self.fin = fin - self.opcode = opcode - self.flags = flags - self.length = length - - def mask_payload(self, payload): - payload = bytearray(payload) - mask = bytearray(self.mask) - - for i in range_type(self.length): - payload[i] ^= mask[i % 4] - - return payload - - # it's the same operation - unmask_payload = mask_payload - - def __repr__(self): - opcodes = { - 0: 'continuation(0)', - 1: 'text(1)', - 2: 'binary(2)', - 8: 'close(8)', - 9: 'ping(9)', - 10: 'pong(10)' - } - flags = { - 0x40: 'RSV1 MASK', - 0x20: 'RSV2 MASK', - 0x10: 'RSV3 MASK' - } - - return ("
    ").format( - self.fin, - opcodes.get(self.opcode, 'reserved({})'.format(self.opcode)), - self.length, - flags.get(self.flags, 'reserved({})'.format(self.flags)), - self.mask, id(self) - ) - - @classmethod - def decode_header(cls, stream): - """ - Decode a WebSocket header. - - :param stream: A file like object that can be 'read' from. - :returns: A `Header` instance. - """ - read = stream.read - data = read(2) - - if len(data) != 2: - raise WebSocketError("Unexpected EOF while decoding header") - - first_byte, second_byte = struct.unpack('!BB', data) - - header = cls( - fin=first_byte & cls.FIN_MASK == cls.FIN_MASK, - opcode=first_byte & cls.OPCODE_MASK, - flags=first_byte & cls.HEADER_FLAG_MASK, - length=second_byte & cls.LENGTH_MASK) - - has_mask = second_byte & cls.MASK_MASK == cls.MASK_MASK - - if header.opcode > 0x07: - if not header.fin: - raise ProtocolError( - "Received fragmented control frame: {0!r}".format(data)) - - # Control frames MUST have a payload length of 125 bytes or less - if header.length > 125: - raise FrameTooLargeException( - "Control frame cannot be larger than 125 bytes: " - "{0!r}".format(data)) - - if header.length == 126: - # 16 bit length - data = read(2) - - if len(data) != 2: - raise WebSocketError('Unexpected EOF while decoding header') - - header.length = struct.unpack('!H', data)[0] - elif header.length == 127: - # 64 bit length - data = read(8) - - if len(data) != 8: - raise WebSocketError('Unexpected EOF while decoding header') - - header.length = struct.unpack('!Q', data)[0] - - if has_mask: - mask = read(4) - - if len(mask) != 4: - raise WebSocketError('Unexpected EOF while decoding header') - - header.mask = mask - - return header - - @classmethod - def encode_header(cls, fin, opcode, mask, length, flags): - """ - Encodes a WebSocket header. - - :param fin: Whether this is the final frame for this opcode. - :param opcode: The opcode of the payload, see `OPCODE_*` - :param mask: Whether the payload is masked. - :param length: The length of the frame. - :param flags: The RSV* flags. - :return: A bytestring encoded header. - """ - first_byte = opcode - second_byte = 0 - extra = b"" - result = bytearray() - - if fin: - first_byte |= cls.FIN_MASK - - if flags & cls.RSV0_MASK: - first_byte |= cls.RSV0_MASK - - if flags & cls.RSV1_MASK: - first_byte |= cls.RSV1_MASK - - if flags & cls.RSV2_MASK: - first_byte |= cls.RSV2_MASK - - # now deal with length complexities - if length < 126: - second_byte += length - elif length <= 0xffff: - second_byte += 126 - extra = struct.pack('!H', length) - elif length <= 0xffffffffffffffff: - second_byte += 127 - extra = struct.pack('!Q', length) - else: - raise FrameTooLargeException - - if mask: - second_byte |= cls.MASK_MASK - - result.append(first_byte) - result.append(second_byte) - result.extend(extra) - - if mask: - result.extend(mask) - - return result diff --git a/venv/lib/python3.9/site-packages/greenlet-3.2.5.dist-info/INSTALLER b/venv/lib/python3.9/site-packages/greenlet-3.2.5.dist-info/INSTALLER deleted file mode 100644 index a1b589e..0000000 --- a/venv/lib/python3.9/site-packages/greenlet-3.2.5.dist-info/INSTALLER +++ /dev/null @@ -1 +0,0 @@ -pip diff --git a/venv/lib/python3.9/site-packages/greenlet-3.2.5.dist-info/METADATA b/venv/lib/python3.9/site-packages/greenlet-3.2.5.dist-info/METADATA deleted file mode 100644 index c11625b..0000000 --- a/venv/lib/python3.9/site-packages/greenlet-3.2.5.dist-info/METADATA +++ /dev/null @@ -1,117 +0,0 @@ -Metadata-Version: 2.4 -Name: greenlet -Version: 3.2.5 -Summary: Lightweight in-process concurrent programming -Home-page: https://greenlet.readthedocs.io/ -Author: Alexey Borzenkov -Author-email: snaury@gmail.com -Maintainer: Jason Madden -Maintainer-email: jason@seecoresoftware.com -License: MIT AND Python-2.0 -Project-URL: Bug Tracker, https://github.com/python-greenlet/greenlet/issues -Project-URL: Source Code, https://github.com/python-greenlet/greenlet/ -Project-URL: Documentation, https://greenlet.readthedocs.io/ -Project-URL: Changes, https://greenlet.readthedocs.io/en/latest/changes.html -Keywords: greenlet coroutine concurrency threads cooperative -Platform: any -Classifier: Development Status :: 5 - Production/Stable -Classifier: Intended Audience :: Developers -Classifier: Natural Language :: English -Classifier: Programming Language :: C -Classifier: Programming Language :: Python -Classifier: Programming Language :: Python :: 3 -Classifier: Programming Language :: Python :: 3 :: Only -Classifier: Programming Language :: Python :: 3.9 -Classifier: Programming Language :: Python :: 3.10 -Classifier: Programming Language :: Python :: 3.11 -Classifier: Programming Language :: Python :: 3.12 -Classifier: Programming Language :: Python :: 3.13 -Classifier: Operating System :: OS Independent -Classifier: Topic :: Software Development :: Libraries :: Python Modules -Requires-Python: >=3.9 -Description-Content-Type: text/x-rst -License-File: LICENSE -License-File: LICENSE.PSF -Provides-Extra: docs -Requires-Dist: Sphinx; extra == "docs" -Requires-Dist: furo; extra == "docs" -Provides-Extra: test -Requires-Dist: objgraph; extra == "test" -Requires-Dist: psutil; extra == "test" -Requires-Dist: setuptools; extra == "test" -Dynamic: author -Dynamic: author-email -Dynamic: classifier -Dynamic: description -Dynamic: description-content-type -Dynamic: home-page -Dynamic: keywords -Dynamic: license -Dynamic: license-file -Dynamic: maintainer -Dynamic: maintainer-email -Dynamic: platform -Dynamic: project-url -Dynamic: provides-extra -Dynamic: requires-python -Dynamic: summary - -.. This file is included into docs/history.rst - - -Greenlets are lightweight coroutines for in-process concurrent -programming. - -The "greenlet" package is a spin-off of `Stackless`_, a version of -CPython that supports micro-threads called "tasklets". Tasklets run -pseudo-concurrently (typically in a single or a few OS-level threads) -and are synchronized with data exchanges on "channels". - -A "greenlet", on the other hand, is a still more primitive notion of -micro-thread with no implicit scheduling; coroutines, in other words. -This is useful when you want to control exactly when your code runs. -You can build custom scheduled micro-threads on top of greenlet; -however, it seems that greenlets are useful on their own as a way to -make advanced control flow structures. For example, we can recreate -generators; the difference with Python's own generators is that our -generators can call nested functions and the nested functions can -yield values too. (Additionally, you don't need a "yield" keyword. See -the example in `test_generator.py -`_). - -Greenlets are provided as a C extension module for the regular unmodified -interpreter. - -.. _`Stackless`: http://www.stackless.com - - -Who is using Greenlet? -====================== - -There are several libraries that use Greenlet as a more flexible -alternative to Python's built in coroutine support: - - - `Concurrence`_ - - `Eventlet`_ - - `Gevent`_ - -.. _Concurrence: http://opensource.hyves.org/concurrence/ -.. _Eventlet: http://eventlet.net/ -.. _Gevent: http://www.gevent.org/ - -Getting Greenlet -================ - -The easiest way to get Greenlet is to install it with pip:: - - pip install greenlet - - -Source code archives and binary distributions are available on the -python package index at https://pypi.org/project/greenlet - -The source code repository is hosted on github: -https://github.com/python-greenlet/greenlet - -Documentation is available on readthedocs.org: -https://greenlet.readthedocs.io diff --git a/venv/lib/python3.9/site-packages/greenlet-3.2.5.dist-info/RECORD b/venv/lib/python3.9/site-packages/greenlet-3.2.5.dist-info/RECORD deleted file mode 100644 index d0ae76b..0000000 --- a/venv/lib/python3.9/site-packages/greenlet-3.2.5.dist-info/RECORD +++ /dev/null @@ -1,123 +0,0 @@ -../../../include/site/python3.9/greenlet/greenlet.h,sha256=sz5pYRSQqedgOt2AMgxLZdTjO-qcr_JMvgiEJR9IAJ8,4755 -greenlet-3.2.5.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 -greenlet-3.2.5.dist-info/METADATA,sha256=85RqHYxp-mlJwHcegPGsIrs2x-4nhmMYpr5jABqfoGk,4120 -greenlet-3.2.5.dist-info/RECORD,, -greenlet-3.2.5.dist-info/WHEEL,sha256=7JuDrj50iGL-3oIho5nqlmsUvW9aQ3YDEW80mDiB_Rk,148 -greenlet-3.2.5.dist-info/licenses/LICENSE,sha256=dpgx1uXfrywggC-sz_H6-0wgJd2PYlPfpH_K1Z1NCXk,1434 -greenlet-3.2.5.dist-info/licenses/LICENSE.PSF,sha256=5f88I8EQ5JTNfXNsEP2W1GJFe6_soxCEDbZScpjH1Gs,2424 -greenlet-3.2.5.dist-info/top_level.txt,sha256=YSnRsCRoO61JGlP57o8iKL6rdLWDWuiyKD8ekpWUsDc,9 -greenlet/CObjects.cpp,sha256=OPej1bWBgc4sRrTRQ2aFFML9pzDYKlKhlJSjsI0X_eU,3508 -greenlet/PyGreenlet.cpp,sha256=4hcUjgCDkPnQopwdk3aENUIA6AKWMpvFR2A1RU36WYE,25196 -greenlet/PyGreenlet.hpp,sha256=2ZQlOxYNoy7QwD7mppFoOXe_At56NIsJ0eNsE_hoSsw,1463 -greenlet/PyGreenletUnswitchable.cpp,sha256=PQE0fSZa_IOyUM44IESHkJoD2KtGW3dkhkmZSYY3WHs,4375 -greenlet/PyModule.cpp,sha256=J2TH06dGcNEarioS6NbWXkdME8hJY05XVbdqLrfO5w4,8587 -greenlet/TBrokenGreenlet.cpp,sha256=smN26uC7ahAbNYiS10rtWPjCeTG4jevM8siA2sjJiXg,1021 -greenlet/TExceptionState.cpp,sha256=U7Ctw9fBdNraS0d174MoQW7bN-ae209Ta0JuiKpcpVI,1359 -greenlet/TGreenlet.cpp,sha256=IM4cHsv1drEl35d7n8YOA_wR-R7oRvx5XhOJOK2PBB8,25732 -greenlet/TGreenlet.hpp,sha256=DoN795i3vofgll-20GA-ylg3qCNw-nKprLA6r7CK5HY,28522 -greenlet/TGreenletGlobals.cpp,sha256=YyEmDjKf1g32bsL-unIUScFLnnA1fzLWf2gOMd-D0Zw,3264 -greenlet/TMainGreenlet.cpp,sha256=fvgb8HHB-FVTPEKjR1s_ifCZSpp5D5YQByik0CnIABg,3276 -greenlet/TPythonState.cpp,sha256=b12U09sNjQvKG0_agROFHuJkDDa7HDccWaFW55XViQA,15975 -greenlet/TStackState.cpp,sha256=V444I8Jj9DhQz-9leVW_9dtiSRjaE1NMlgDG02Xxq-Y,7381 -greenlet/TThreadState.hpp,sha256=Pthmiz7YnWPyUvSMRDSGLW3Tkrpdblku0aVpzl6GFSQ,19934 -greenlet/TThreadStateCreator.hpp,sha256=uYTexDWooXSSgUc5uh-Mhm5BQi3-kR6CqpizvNynBFQ,2610 -greenlet/TThreadStateDestroy.cpp,sha256=36yBCAMq3beXTZd-XnFA7DwaHVSOx2vc28-nf0spysU,8169 -greenlet/TUserGreenlet.cpp,sha256=uemg0lwKXtYB0yzmvyYdIIAsKnNkifXM1OJ2OlrFP1A,23553 -greenlet/__init__.py,sha256=2xFOMAMtTyRy8SORU281wEQrCbWqBMb1nuoa-EAEu5I,1723 -greenlet/__pycache__/__init__.cpython-39.pyc,, -greenlet/_greenlet.cpython-39-x86_64-linux-gnu.so,sha256=6JlxfgNnbzfcasveWLyAd1lm3_JpXHMHqV2nyx79_ho,1360632 -greenlet/greenlet.cpp,sha256=WdItb1yWL9WNsTqJNf0Iw8ZwDHD49pkDP0rIRGBg2pw,10996 -greenlet/greenlet.h,sha256=sz5pYRSQqedgOt2AMgxLZdTjO-qcr_JMvgiEJR9IAJ8,4755 -greenlet/greenlet_allocator.hpp,sha256=eC0S1AQuep1vnVRsag-r83xgfAtbpn0qQZ-oXzQXaso,2607 -greenlet/greenlet_compiler_compat.hpp,sha256=nRxpLN9iNbnLVyFDeVmOwyeeNm6scQrOed1l7JQYMCM,4346 -greenlet/greenlet_cpython_compat.hpp,sha256=kJG6d_yDwwl3bSZOOFqM3ks1UzVIGcwbsTM2s8C6VYE,4149 -greenlet/greenlet_exceptions.hpp,sha256=06Bx81DtVaJTa6RtiMcV141b-XHv4ppEgVItkblcLWY,4503 -greenlet/greenlet_internal.hpp,sha256=Ajc-_09W4xWzm9XfyXHAeQAFUgKGKsnJwYsTCoNy3ns,2709 -greenlet/greenlet_msvc_compat.hpp,sha256=0MyaiyoCE_A6UROXZlMQRxRS17gfyh0d7NUppU3EVFc,2978 -greenlet/greenlet_refs.hpp,sha256=OnbA91yZf3QHH6-eJccvoNDAaN-pQBMMrclFU1Ot3J4,34436 -greenlet/greenlet_slp_switch.hpp,sha256=kM1QHA2iV-gH4cFyN6lfIagHQxvJZjWOVJdIxRE3TlQ,3198 -greenlet/greenlet_thread_support.hpp,sha256=XUJ6ljWjf9OYyuOILiz8e_yHvT3fbaUiHdhiPNQUV4s,867 -greenlet/platform/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 -greenlet/platform/__pycache__/__init__.cpython-39.pyc,, -greenlet/platform/setup_switch_x64_masm.cmd,sha256=ZpClUJeU0ujEPSTWNSepP0W2f9XiYQKA8QKSoVou8EU,143 -greenlet/platform/switch_aarch64_gcc.h,sha256=GKC0yWNXnbK2X--X6aguRCMj2Tg7hDU1Zkl3RljDvC8,4307 -greenlet/platform/switch_alpha_unix.h,sha256=Z-SvF8JQV3oxWT8JRbL9RFu4gRFxPdJ7cviM8YayMmw,671 -greenlet/platform/switch_amd64_unix.h,sha256=EcSFCBlodEBhqhKjcJqY_5Dn_jn7pKpkJlOvp7gFXLI,2748 -greenlet/platform/switch_arm32_gcc.h,sha256=Z3KkHszdgq6uU4YN3BxvKMG2AdDnovwCCNrqGWZ1Lyo,2479 -greenlet/platform/switch_arm32_ios.h,sha256=mm5_R9aXB92hyxzFRwB71M60H6AlvHjrpTrc72Pz3l8,1892 -greenlet/platform/switch_arm64_masm.asm,sha256=4kpTtfy7rfcr8j1CpJLAK21EtZpGDAJXWRU68HEy5A8,1245 -greenlet/platform/switch_arm64_masm.obj,sha256=DmLnIB_icoEHAz1naue_pJPTZgR9ElM7-Nmztr-o9_U,746 -greenlet/platform/switch_arm64_msvc.h,sha256=RqK5MHLmXI3Q-FQ7tm32KWnbDNZKnkJdq8CR89cz640,398 -greenlet/platform/switch_csky_gcc.h,sha256=kDikyiPpewP71KoBZQO_MukDTXTXBiC7x-hF0_2DL0w,1331 -greenlet/platform/switch_loongarch64_linux.h,sha256=7M-Dhc4Q8tRbJCJhalDLwU6S9Mx8MjmN1RbTDgIvQTM,779 -greenlet/platform/switch_m68k_gcc.h,sha256=VSa6NpZhvyyvF-Q58CTIWSpEDo4FKygOyTz00whctlw,928 -greenlet/platform/switch_mips_unix.h,sha256=E0tYsqc5anDY1BhenU1l8DW-nVHC_BElzLgJw3TGtPk,1426 -greenlet/platform/switch_ppc64_aix.h,sha256=_BL0iyRr3ZA5iPlr3uk9SJ5sNRWGYLrXcZ5z-CE9anE,3860 -greenlet/platform/switch_ppc64_linux.h,sha256=0rriT5XyxPb0GqsSSn_bP9iQsnjsPbBmu0yqo5goSyQ,3815 -greenlet/platform/switch_ppc_aix.h,sha256=pHA4slEjUFP3J3SYm1TAlNPhgb2G_PAtax5cO8BEe1A,2941 -greenlet/platform/switch_ppc_linux.h,sha256=YwrlKUzxlXuiKMQqr6MFAV1bPzWnmvk6X1AqJZEpOWU,2759 -greenlet/platform/switch_ppc_macosx.h,sha256=Z6KN_ud0n6nC3ltJrNz2qtvER6vnRAVRNH9mdIDpMxY,2624 -greenlet/platform/switch_ppc_unix.h,sha256=-ZG7MSSPEA5N4qO9PQChtyEJ-Fm6qInhyZm_ZBHTtMg,2652 -greenlet/platform/switch_riscv_unix.h,sha256=606V6ACDf79Fz_WGItnkgbjIJ0pGg_sHmPyDxQYKK58,949 -greenlet/platform/switch_s390_unix.h,sha256=RRlGu957ybmq95qNNY4Qw1mcaoT3eBnW5KbVwu48KX8,2763 -greenlet/platform/switch_sh_gcc.h,sha256=mcRJBTu-2UBf4kZtX601qofwuDuy-Y-hnxJtrcaB7do,901 -greenlet/platform/switch_sparc_sun_gcc.h,sha256=xZish9GsMHBienUbUMsX1-ZZ-as7hs36sVhYIE3ew8Y,2797 -greenlet/platform/switch_x32_unix.h,sha256=nM98PKtzTWc1lcM7TRMUZJzskVdR1C69U1UqZRWX0GE,1509 -greenlet/platform/switch_x64_masm.asm,sha256=nu6n2sWyXuXfpPx40d9YmLfHXUc1sHgeTvX1kUzuvEM,1841 -greenlet/platform/switch_x64_masm.obj,sha256=GNtTNxYdo7idFUYsQv-mrXWgyT5EJ93-9q90lN6svtQ,1078 -greenlet/platform/switch_x64_msvc.h,sha256=LIeasyKo_vHzspdMzMHbosRhrBfKI4BkQOh4qcTHyJw,1805 -greenlet/platform/switch_x86_msvc.h,sha256=TtGOwinbFfnn6clxMNkCz8i6OmgB6kVRrShoF5iT9to,12838 -greenlet/platform/switch_x86_unix.h,sha256=VplW9H0FF0cZHw1DhJdIUs5q6YLS4cwb2nYwjF83R1s,3059 -greenlet/slp_platformselect.h,sha256=hTb3GFdcPUYJTuu1MY93js7MZEax1_e5E-gflpi0RzI,3959 -greenlet/tests/__init__.py,sha256=EtTtQfpRDde0MhsdAM5Cm7LYIfS_HKUIFwquiH4Q7ac,9736 -greenlet/tests/__pycache__/__init__.cpython-39.pyc,, -greenlet/tests/__pycache__/fail_clearing_run_switches.cpython-39.pyc,, -greenlet/tests/__pycache__/fail_cpp_exception.cpython-39.pyc,, -greenlet/tests/__pycache__/fail_initialstub_already_started.cpython-39.pyc,, -greenlet/tests/__pycache__/fail_slp_switch.cpython-39.pyc,, -greenlet/tests/__pycache__/fail_switch_three_greenlets.cpython-39.pyc,, -greenlet/tests/__pycache__/fail_switch_three_greenlets2.cpython-39.pyc,, -greenlet/tests/__pycache__/fail_switch_two_greenlets.cpython-39.pyc,, -greenlet/tests/__pycache__/leakcheck.cpython-39.pyc,, -greenlet/tests/__pycache__/test_contextvars.cpython-39.pyc,, -greenlet/tests/__pycache__/test_cpp.cpython-39.pyc,, -greenlet/tests/__pycache__/test_extension_interface.cpython-39.pyc,, -greenlet/tests/__pycache__/test_gc.cpython-39.pyc,, -greenlet/tests/__pycache__/test_generator.cpython-39.pyc,, -greenlet/tests/__pycache__/test_generator_nested.cpython-39.pyc,, -greenlet/tests/__pycache__/test_greenlet.cpython-39.pyc,, -greenlet/tests/__pycache__/test_greenlet_trash.cpython-39.pyc,, -greenlet/tests/__pycache__/test_interpreter_shutdown.cpython-39.pyc,, -greenlet/tests/__pycache__/test_leaks.cpython-39.pyc,, -greenlet/tests/__pycache__/test_stack_saved.cpython-39.pyc,, -greenlet/tests/__pycache__/test_throw.cpython-39.pyc,, -greenlet/tests/__pycache__/test_tracing.cpython-39.pyc,, -greenlet/tests/__pycache__/test_version.cpython-39.pyc,, -greenlet/tests/__pycache__/test_weakref.cpython-39.pyc,, -greenlet/tests/_test_extension.c,sha256=vkeGA-6oeJcGILsD7oIrT1qZop2GaTOHXiNT7mcSl-0,5773 -greenlet/tests/_test_extension.cpython-39-x86_64-linux-gnu.so,sha256=KLoaMrq4Pfsuq-p4xF_sHIKzpLdAJpQVNfyqDuTGT7g,17256 -greenlet/tests/_test_extension_cpp.cpp,sha256=e0kVnaB8CCaEhE9yHtNyfqTjevsPDKKx-zgxk7PPK48,6565 -greenlet/tests/_test_extension_cpp.cpython-39-x86_64-linux-gnu.so,sha256=2iu0w5qyVh7zE3d3cTd7mYJS_ZlX7I6Tw8dpULad3Fo,57520 -greenlet/tests/fail_clearing_run_switches.py,sha256=o433oA_nUCtOPaMEGc8VEhZIKa71imVHXFw7TsXaP8M,1263 -greenlet/tests/fail_cpp_exception.py,sha256=o_ZbipWikok8Bjc-vjiQvcb5FHh2nVW-McGKMLcMzh0,985 -greenlet/tests/fail_initialstub_already_started.py,sha256=txENn5IyzGx2p-XR1XB7qXmC8JX_4mKDEA8kYBXUQKc,1961 -greenlet/tests/fail_slp_switch.py,sha256=rJBZcZfTWR3e2ERQtPAud6YKShiDsP84PmwOJbp4ey0,524 -greenlet/tests/fail_switch_three_greenlets.py,sha256=zSitV7rkNnaoHYVzAGGLnxz-yPtohXJJzaE8ehFDQ0M,956 -greenlet/tests/fail_switch_three_greenlets2.py,sha256=FPJensn2EJxoropl03JSTVP3kgP33k04h6aDWWozrOk,1285 -greenlet/tests/fail_switch_two_greenlets.py,sha256=1CaI8s3504VbbF1vj1uBYuy-zxBHVzHPIAd1LIc8ONg,817 -greenlet/tests/leakcheck.py,sha256=f28zZf0MlMgcybbm_5YyIOR6HcDqP2f2k6LX-FxFGqA,12652 -greenlet/tests/test_contextvars.py,sha256=xutO-qZgKTwKsA9lAqTjIcTBEiQV4RpNKM-vO2_YCVU,10541 -greenlet/tests/test_cpp.py,sha256=hpxhFAdKJTpAVZP8CBGs1ZcrKdscI9BaDZk4btkI5d4,2736 -greenlet/tests/test_extension_interface.py,sha256=eJ3cwLacdK2WbsrC-4DgeyHdwLRcG4zx7rrkRtqSzC4,3829 -greenlet/tests/test_gc.py,sha256=PCOaRpIyjNnNlDogGL3FZU_lrdXuM-pv1rxeE5TP5mc,2923 -greenlet/tests/test_generator.py,sha256=tONXiTf98VGm347o1b-810daPiwdla5cbpFg6QI1R1g,1240 -greenlet/tests/test_generator_nested.py,sha256=7v4HOYrf1XZP39dk5IUMubdZ8yc3ynwZcqj9GUJyMSA,3718 -greenlet/tests/test_greenlet.py,sha256=gSG6hOjKYyRRe5ZzNUpskrUcMnBT3WU4yITTzaZfLH4,47995 -greenlet/tests/test_greenlet_trash.py,sha256=n2dBlQfOoEO1ODatFi8QdhboH3fB86YtqzcYMYOXxbw,7947 -greenlet/tests/test_interpreter_shutdown.py,sha256=1chlkvgUD5g0y3lsFHm7SjHT3hJPTJwpL1LmR4r62pY,11949 -greenlet/tests/test_leaks.py,sha256=OFSE870Zyql85HukfC_XYa2c4gDQBU889RV1AlLum74,18076 -greenlet/tests/test_stack_saved.py,sha256=eyzqNY2VCGuGlxhT_In6TvZ6Okb0AXFZVyBEnK1jDwA,446 -greenlet/tests/test_throw.py,sha256=u2TQ_WvvCd6N6JdXWIxVEcXkKu5fepDlz9dktYdmtng,3712 -greenlet/tests/test_tracing.py,sha256=NFD6Vcww8grBnFQFhCNdswwGetjLeLQ7vL2Qqw3LWBM,8591 -greenlet/tests/test_version.py,sha256=O9DpAITsOFgiRcjd4odQ7ejmwx_N9Q1zQENVcbtFHIc,1339 -greenlet/tests/test_weakref.py,sha256=F8M23btEF87bIbpptLNBORosbQqNZGiYeKMqYjWrsak,883 diff --git a/venv/lib/python3.9/site-packages/greenlet-3.2.5.dist-info/WHEEL b/venv/lib/python3.9/site-packages/greenlet-3.2.5.dist-info/WHEEL deleted file mode 100644 index c341d7f..0000000 --- a/venv/lib/python3.9/site-packages/greenlet-3.2.5.dist-info/WHEEL +++ /dev/null @@ -1,6 +0,0 @@ -Wheel-Version: 1.0 -Generator: setuptools (82.0.0) -Root-Is-Purelib: false -Tag: cp39-cp39-manylinux_2_24_x86_64 -Tag: cp39-cp39-manylinux_2_28_x86_64 - diff --git a/venv/lib/python3.9/site-packages/greenlet-3.2.5.dist-info/licenses/LICENSE b/venv/lib/python3.9/site-packages/greenlet-3.2.5.dist-info/licenses/LICENSE deleted file mode 100644 index b73a4a1..0000000 --- a/venv/lib/python3.9/site-packages/greenlet-3.2.5.dist-info/licenses/LICENSE +++ /dev/null @@ -1,30 +0,0 @@ -The following files are derived from Stackless Python and are subject to the -same license as Stackless Python: - - src/greenlet/slp_platformselect.h - files in src/greenlet/platform/ directory - -See LICENSE.PSF and http://www.stackless.com/ for details. - -Unless otherwise noted, the files in greenlet have been released under the -following MIT license: - -Copyright (c) Armin Rigo, Christian Tismer and contributors - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. diff --git a/venv/lib/python3.9/site-packages/greenlet-3.2.5.dist-info/licenses/LICENSE.PSF b/venv/lib/python3.9/site-packages/greenlet-3.2.5.dist-info/licenses/LICENSE.PSF deleted file mode 100644 index d3b509a..0000000 --- a/venv/lib/python3.9/site-packages/greenlet-3.2.5.dist-info/licenses/LICENSE.PSF +++ /dev/null @@ -1,47 +0,0 @@ -PYTHON SOFTWARE FOUNDATION LICENSE VERSION 2 --------------------------------------------- - -1. This LICENSE AGREEMENT is between the Python Software Foundation -("PSF"), and the Individual or Organization ("Licensee") accessing and -otherwise using this software ("Python") in source or binary form and -its associated documentation. - -2. Subject to the terms and conditions of this License Agreement, PSF hereby -grants Licensee a nonexclusive, royalty-free, world-wide license to reproduce, -analyze, test, perform and/or display publicly, prepare derivative works, -distribute, and otherwise use Python alone or in any derivative version, -provided, however, that PSF's License Agreement and PSF's notice of copyright, -i.e., "Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, -2011 Python Software Foundation; All Rights Reserved" are retained in Python -alone or in any derivative version prepared by Licensee. - -3. In the event Licensee prepares a derivative work that is based on -or incorporates Python or any part thereof, and wants to make -the derivative work available to others as provided herein, then -Licensee hereby agrees to include in any such work a brief summary of -the changes made to Python. - -4. PSF is making Python available to Licensee on an "AS IS" -basis. PSF MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR -IMPLIED. BY WAY OF EXAMPLE, BUT NOT LIMITATION, PSF MAKES NO AND -DISCLAIMS ANY REPRESENTATION OR WARRANTY OF MERCHANTABILITY OR FITNESS -FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF PYTHON WILL NOT -INFRINGE ANY THIRD PARTY RIGHTS. - -5. PSF SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF PYTHON -FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS AS -A RESULT OF MODIFYING, DISTRIBUTING, OR OTHERWISE USING PYTHON, -OR ANY DERIVATIVE THEREOF, EVEN IF ADVISED OF THE POSSIBILITY THEREOF. - -6. This License Agreement will automatically terminate upon a material -breach of its terms and conditions. - -7. Nothing in this License Agreement shall be deemed to create any -relationship of agency, partnership, or joint venture between PSF and -Licensee. This License Agreement does not grant permission to use PSF -trademarks or trade name in a trademark sense to endorse or promote -products or services of Licensee, or any third party. - -8. By copying, installing or otherwise using Python, Licensee -agrees to be bound by the terms and conditions of this License -Agreement. diff --git a/venv/lib/python3.9/site-packages/greenlet-3.2.5.dist-info/top_level.txt b/venv/lib/python3.9/site-packages/greenlet-3.2.5.dist-info/top_level.txt deleted file mode 100644 index 46725be..0000000 --- a/venv/lib/python3.9/site-packages/greenlet-3.2.5.dist-info/top_level.txt +++ /dev/null @@ -1 +0,0 @@ -greenlet diff --git a/venv/lib/python3.9/site-packages/greenlet/CObjects.cpp b/venv/lib/python3.9/site-packages/greenlet/CObjects.cpp deleted file mode 100644 index c135995..0000000 --- a/venv/lib/python3.9/site-packages/greenlet/CObjects.cpp +++ /dev/null @@ -1,157 +0,0 @@ -#ifndef COBJECTS_CPP -#define COBJECTS_CPP -/***************************************************************************** - * C interface - * - * These are exported using the CObject API - */ -#ifdef __clang__ -# pragma clang diagnostic push -# pragma clang diagnostic ignored "-Wunused-function" -#endif - -#include "greenlet_exceptions.hpp" - -#include "greenlet_internal.hpp" -#include "greenlet_refs.hpp" - - -#include "TThreadStateDestroy.cpp" - -#include "PyGreenlet.hpp" - -using greenlet::PyErrOccurred; -using greenlet::Require; - - - -extern "C" { -static PyGreenlet* -PyGreenlet_GetCurrent(void) -{ - return GET_THREAD_STATE().state().get_current().relinquish_ownership(); -} - -static int -PyGreenlet_SetParent(PyGreenlet* g, PyGreenlet* nparent) -{ - return green_setparent((PyGreenlet*)g, (PyObject*)nparent, NULL); -} - -static PyGreenlet* -PyGreenlet_New(PyObject* run, PyGreenlet* parent) -{ - using greenlet::refs::NewDictReference; - // In the past, we didn't use green_new and green_init, but that - // was a maintenance issue because we duplicated code. This way is - // much safer, but slightly slower. If that's a problem, we could - // refactor green_init to separate argument parsing from initialization. - OwnedGreenlet g = OwnedGreenlet::consuming(green_new(&PyGreenlet_Type, nullptr, nullptr)); - if (!g) { - return NULL; - } - - try { - NewDictReference kwargs; - if (run) { - kwargs.SetItem(mod_globs->str_run, run); - } - if (parent) { - kwargs.SetItem("parent", (PyObject*)parent); - } - - Require(green_init(g.borrow(), mod_globs->empty_tuple, kwargs.borrow())); - } - catch (const PyErrOccurred&) { - return nullptr; - } - - return g.relinquish_ownership(); -} - -static PyObject* -PyGreenlet_Switch(PyGreenlet* self, PyObject* args, PyObject* kwargs) -{ - if (!PyGreenlet_Check(self)) { - PyErr_BadArgument(); - return NULL; - } - - if (args == NULL) { - args = mod_globs->empty_tuple; - } - - if (kwargs == NULL || !PyDict_Check(kwargs)) { - kwargs = NULL; - } - - return green_switch(self, args, kwargs); -} - -static PyObject* -PyGreenlet_Throw(PyGreenlet* self, PyObject* typ, PyObject* val, PyObject* tb) -{ - if (!PyGreenlet_Check(self)) { - PyErr_BadArgument(); - return nullptr; - } - try { - PyErrPieces err_pieces(typ, val, tb); - return internal_green_throw(self, err_pieces).relinquish_ownership(); - } - catch (const PyErrOccurred&) { - return nullptr; - } -} - - - -static int -Extern_PyGreenlet_MAIN(PyGreenlet* self) -{ - if (!PyGreenlet_Check(self)) { - PyErr_BadArgument(); - return -1; - } - return self->pimpl->main(); -} - -static int -Extern_PyGreenlet_ACTIVE(PyGreenlet* self) -{ - if (!PyGreenlet_Check(self)) { - PyErr_BadArgument(); - return -1; - } - return self->pimpl->active(); -} - -static int -Extern_PyGreenlet_STARTED(PyGreenlet* self) -{ - if (!PyGreenlet_Check(self)) { - PyErr_BadArgument(); - return -1; - } - return self->pimpl->started(); -} - -static PyGreenlet* -Extern_PyGreenlet_GET_PARENT(PyGreenlet* self) -{ - if (!PyGreenlet_Check(self)) { - PyErr_BadArgument(); - return NULL; - } - // This can return NULL even if there is no exception - return self->pimpl->parent().acquire(); -} -} // extern C. - -/** End C API ****************************************************************/ -#ifdef __clang__ -# pragma clang diagnostic pop -#endif - - -#endif diff --git a/venv/lib/python3.9/site-packages/greenlet/PyGreenlet.cpp b/venv/lib/python3.9/site-packages/greenlet/PyGreenlet.cpp deleted file mode 100644 index 64589de..0000000 --- a/venv/lib/python3.9/site-packages/greenlet/PyGreenlet.cpp +++ /dev/null @@ -1,772 +0,0 @@ -/* -*- indent-tabs-mode: nil; tab-width: 4; -*- */ -#ifndef PYGREENLET_CPP -#define PYGREENLET_CPP -/***************** -The Python slot functions for TGreenlet. - */ - - -#define PY_SSIZE_T_CLEAN -#include -#include "structmember.h" // PyMemberDef - -#include "greenlet_internal.hpp" -#include "TThreadStateDestroy.cpp" -#include "TGreenlet.hpp" -// #include "TUserGreenlet.cpp" -// #include "TMainGreenlet.cpp" -// #include "TBrokenGreenlet.cpp" - - -#include "greenlet_refs.hpp" -#include "greenlet_slp_switch.hpp" - -#include "greenlet_thread_support.hpp" -#include "TGreenlet.hpp" - -#include "TGreenletGlobals.cpp" -#include "TThreadStateDestroy.cpp" -#include "PyGreenlet.hpp" -// #include "TGreenlet.cpp" - -// #include "TExceptionState.cpp" -// #include "TPythonState.cpp" -// #include "TStackState.cpp" - -using greenlet::LockGuard; -using greenlet::LockInitError; -using greenlet::PyErrOccurred; -using greenlet::Require; - -using greenlet::g_handle_exit; -using greenlet::single_result; - -using greenlet::Greenlet; -using greenlet::UserGreenlet; -using greenlet::MainGreenlet; -using greenlet::BrokenGreenlet; -using greenlet::ThreadState; -using greenlet::PythonState; - - - -static PyGreenlet* -green_new(PyTypeObject* type, PyObject* UNUSED(args), PyObject* UNUSED(kwds)) -{ - PyGreenlet* o = - (PyGreenlet*)PyBaseObject_Type.tp_new(type, mod_globs->empty_tuple, mod_globs->empty_dict); - if (o) { - // Recall: borrowing or getting the current greenlet - // causes the "deleteme list" to get cleared. So constructing a greenlet - // can do things like cause other greenlets to get finalized. - UserGreenlet* c = new UserGreenlet(o, GET_THREAD_STATE().state().borrow_current()); - assert(Py_REFCNT(o) == 1); - // Also: This looks like a memory leak, but isn't. Constructing the - // C++ object assigns it to the pimpl pointer of the Python object (o); - // we'll need that later. - assert(c == o->pimpl); - } - return o; -} - - -// green_init is used in the tp_init slot. So it's important that -// it can be called directly from CPython. Thus, we don't use -// BorrowedGreenlet and BorrowedObject --- although in theory -// these should be binary layout compatible, that may not be -// guaranteed to be the case (32-bit linux ppc possibly). -static int -green_init(PyGreenlet* self, PyObject* args, PyObject* kwargs) -{ - PyArgParseParam run; - PyArgParseParam nparent; - static const char* kwlist[] = { - "run", - "parent", - NULL - }; - - // recall: The O specifier does NOT increase the reference count. - if (!PyArg_ParseTupleAndKeywords( - args, kwargs, "|OO:green", (char**)kwlist, &run, &nparent)) { - return -1; - } - - if (run) { - if (green_setrun(self, run, NULL)) { - return -1; - } - } - if (nparent && !nparent.is_None()) { - return green_setparent(self, nparent, NULL); - } - return 0; -} - - - -static int -green_traverse(PyGreenlet* self, visitproc visit, void* arg) -{ - // We must only visit referenced objects, i.e. only objects - // Py_INCREF'ed by this greenlet (directly or indirectly): - // - // - stack_prev is not visited: holds previous stack pointer, but it's not - // referenced - // - frames are not visited as we don't strongly reference them; - // alive greenlets are not garbage collected - // anyway. This can be a problem, however, if this greenlet is - // never allowed to finish, and is referenced from the frame: we - // have an uncollectible cycle in that case. Note that the - // frame object itself is also frequently not even tracked by the GC - // starting with Python 3.7 (frames are allocated by the - // interpreter untracked, and only become tracked when their - // evaluation is finished if they have a refcount > 1). All of - // this is to say that we should probably strongly reference - // the frame object. Doing so, while always allowing GC on a - // greenlet, solves several leaks for us. - - Py_VISIT(self->dict); - if (!self->pimpl) { - // Hmm. I have seen this at interpreter shutdown time, - // I think. That's very odd because this doesn't go away until - // we're ``green_dealloc()``, at which point we shouldn't be - // traversed anymore. - return 0; - } - - return self->pimpl->tp_traverse(visit, arg); -} - -static int -green_is_gc(PyObject* _self) -{ - BorrowedGreenlet self(_self); - int result = 0; - /* Main greenlet can be garbage collected since it can only - become unreachable if the underlying thread exited. - Active greenlets --- including those that are suspended --- - cannot be garbage collected, however. - */ - if (self->main() || !self->active()) { - result = 1; - } - // The main greenlet pointer will eventually go away after the thread dies. - if (self->was_running_in_dead_thread()) { - // Our thread is dead! We can never run again. Might as well - // GC us. Note that if a tuple containing only us and other - // immutable objects had been scanned before this, when we - // would have returned 0, the tuple will take itself out of GC - // tracking and never be investigated again. So that could - // result in both us and the tuple leaking due to an - // unreachable/uncollectible reference. The same goes for - // dictionaries. - // - // It's not a great idea to be changing our GC state on the - // fly. - result = 1; - } - return result; -} - - -static int -green_clear(PyGreenlet* self) -{ - /* Greenlet is only cleared if it is about to be collected. - Since active greenlets are not garbage collectable, we can - be sure that, even if they are deallocated during clear, - nothing they reference is in unreachable or finalizers, - so even if it switches we are relatively safe. */ - // XXX: Are we responsible for clearing weakrefs here? - Py_CLEAR(self->dict); - return self->pimpl->tp_clear(); -} - -/** - * Returns 0 on failure (the object was resurrected) or 1 on success. - **/ -static int -_green_dealloc_kill_started_non_main_greenlet(BorrowedGreenlet self) -{ - // During interpreter finalization, we cannot safely throw GreenletExit - // into the greenlet. Doing so calls g_switch(), which performs a stack - // switch and runs Python code via _PyEval_EvalFrameDefault. On Python - // < 3.11, executing Python code in a partially-torn-down interpreter - // leads to SIGSEGV (greenlet 3.x) or SIGABRT (greenlet 2.x). - // - // Python 3.11+ restructured interpreter finalization internals (frame - // representation, data stack management, recursion tracking) so that - // g_switch() during finalization is safe. On older Pythons, we simply - // mark the greenlet dead without throwing, which avoids the crash at - // the cost of not running any cleanup code inside the greenlet. - // - // See: https://github.com/python-greenlet/greenlet/issues/411 - // https://github.com/python-greenlet/greenlet/issues/351 -#if !GREENLET_PY311 - if (_Py_IsFinalizing()) { - self->murder_in_place(); - return 1; - } -#endif - - /* Hacks hacks hacks copied from instance_dealloc() */ - /* Temporarily resurrect the greenlet. */ - assert(self.REFCNT() == 0); - Py_SET_REFCNT(self.borrow(), 1); - /* Save the current exception, if any. */ - PyErrPieces saved_err; - try { - // BY THE TIME WE GET HERE, the state may actually be going - // away - // if we're shutting down the interpreter and freeing thread - // entries, - // this could result in freeing greenlets that were leaked. So - // we can't try to read the state. - self->deallocing_greenlet_in_thread( - self->thread_state() - ? static_cast(GET_THREAD_STATE()) - : nullptr); - } - catch (const PyErrOccurred&) { - PyErr_WriteUnraisable(self.borrow_o()); - /* XXX what else should we do? */ - } - /* Check for no resurrection must be done while we keep - * our internal reference, otherwise PyFile_WriteObject - * causes recursion if using Py_INCREF/Py_DECREF - */ - if (self.REFCNT() == 1 && self->active()) { - /* Not resurrected, but still not dead! - XXX what else should we do? we complain. */ - PyObject* f = PySys_GetObject("stderr"); - Py_INCREF(self.borrow_o()); /* leak! */ - if (f != NULL) { - PyFile_WriteString("GreenletExit did not kill ", f); - PyFile_WriteObject(self.borrow_o(), f, 0); - PyFile_WriteString("\n", f); - } - } - /* Restore the saved exception. */ - saved_err.PyErrRestore(); - /* Undo the temporary resurrection; can't use DECREF here, - * it would cause a recursive call. - */ - assert(self.REFCNT() > 0); - - Py_ssize_t refcnt = self.REFCNT() - 1; - Py_SET_REFCNT(self.borrow_o(), refcnt); - if (refcnt != 0) { - /* Resurrected! */ - _Py_NewReference(self.borrow_o()); - Py_SET_REFCNT(self.borrow_o(), refcnt); - /* Better to use tp_finalizer slot (PEP 442) - * and call ``PyObject_CallFinalizerFromDealloc``, - * but that's only supported in Python 3.4+; see - * Modules/_io/iobase.c for an example. - * TODO: We no longer run on anything that old, switch to finalizers. - * - * The following approach is copied from iobase.c in CPython 2.7. - * (along with much of this function in general). Here's their - * comment: - * - * When called from a heap type's dealloc, the type will be - * decref'ed on return (see e.g. subtype_dealloc in typeobject.c). - * - * On free-threaded builds of CPython, the type is meant to be immortal - * so we probably shouldn't mess with this? See - * test_issue_245_reference_counting_subclass_no_threads - */ - if (PyType_HasFeature(self.TYPE(), Py_TPFLAGS_HEAPTYPE)) { - Py_INCREF(self.TYPE()); - } - - PyObject_GC_Track((PyObject*)self); - - GREENLET_Py_DEC_REFTOTAL; -#ifdef COUNT_ALLOCS - --Py_TYPE(self)->tp_frees; - --Py_TYPE(self)->tp_allocs; -#endif /* COUNT_ALLOCS */ - return 0; - } - return 1; -} - - -static void -green_dealloc(PyGreenlet* self) -{ - PyObject_GC_UnTrack(self); - BorrowedGreenlet me(self); - if (me->active() - && me->started() - && !me->main()) { - if (!_green_dealloc_kill_started_non_main_greenlet(me)) { - return; - } - } - - if (self->weakreflist != NULL) { - PyObject_ClearWeakRefs((PyObject*)self); - } - Py_CLEAR(self->dict); - - if (self->pimpl) { - // In case deleting this, which frees some memory, - // somehow winds up calling back into us. That's usually a - //bug in our code. - Greenlet* p = self->pimpl; - self->pimpl = nullptr; - delete p; - } - // and finally we're done. self is now invalid. - Py_TYPE(self)->tp_free((PyObject*)self); -} - - - -static OwnedObject -internal_green_throw(BorrowedGreenlet self, PyErrPieces& err_pieces) -{ - PyObject* result = nullptr; - err_pieces.PyErrRestore(); - assert(PyErr_Occurred()); - if (self->started() && !self->active()) { - /* dead greenlet: turn GreenletExit into a regular return */ - result = g_handle_exit(OwnedObject()).relinquish_ownership(); - } - self->args() <<= result; - - return single_result(self->g_switch()); -} - - - -PyDoc_STRVAR( - green_switch_doc, - "switch(*args, **kwargs)\n" - "\n" - "Switch execution to this greenlet.\n" - "\n" - "If this greenlet has never been run, then this greenlet\n" - "will be switched to using the body of ``self.run(*args, **kwargs)``.\n" - "\n" - "If the greenlet is active (has been run, but was switch()'ed\n" - "out before leaving its run function), then this greenlet will\n" - "be resumed and the return value to its switch call will be\n" - "None if no arguments are given, the given argument if one\n" - "argument is given, or the args tuple and keyword args dict if\n" - "multiple arguments are given.\n" - "\n" - "If the greenlet is dead, or is the current greenlet then this\n" - "function will simply return the arguments using the same rules as\n" - "above.\n"); - -static PyObject* -green_switch(PyGreenlet* self, PyObject* args, PyObject* kwargs) -{ - using greenlet::SwitchingArgs; - SwitchingArgs switch_args(OwnedObject::owning(args), OwnedObject::owning(kwargs)); - self->pimpl->may_switch_away(); - self->pimpl->args() <<= switch_args; - - // If we're switching out of a greenlet, and that switch is the - // last thing the greenlet does, the greenlet ought to be able to - // go ahead and die at that point. Currently, someone else must - // manually switch back to the greenlet so that we "fall off the - // end" and can perform cleanup. You'd think we'd be able to - // figure out that this is happening using the frame's ``f_lasti`` - // member, which is supposed to be an index into - // ``frame->f_code->co_code``, the bytecode string. However, in - // recent interpreters, ``f_lasti`` tends not to be updated thanks - // to things like the PREDICT() macros in ceval.c. So it doesn't - // really work to do that in many cases. For example, the Python - // code: - // def run(): - // greenlet.getcurrent().parent.switch() - // produces bytecode of len 16, with the actual call to switch() - // being at index 10 (in Python 3.10). However, the reported - // ``f_lasti`` we actually see is...5! (Which happens to be the - // second byte of the CALL_METHOD op for ``getcurrent()``). - - try { - //OwnedObject result = single_result(self->pimpl->g_switch()); - OwnedObject result(single_result(self->pimpl->g_switch())); -#ifndef NDEBUG - // Note that the current greenlet isn't necessarily self. If self - // finished, we went to one of its parents. - assert(!self->pimpl->args()); - - const BorrowedGreenlet& current = GET_THREAD_STATE().state().borrow_current(); - // It's possible it's never been switched to. - assert(!current->args()); -#endif - PyObject* p = result.relinquish_ownership(); - - if (!p && !PyErr_Occurred()) { - // This shouldn't be happening anymore, so the asserts - // are there for debug builds. Non-debug builds - // crash "gracefully" in this case, although there is an - // argument to be made for killing the process in all - // cases --- for this to be the case, our switches - // probably nested in an incorrect way, so the state is - // suspicious. Nothing should be corrupt though, just - // confused at the Python level. Letting this propagate is - // probably good enough. - assert(p || PyErr_Occurred()); - throw PyErrOccurred( - mod_globs->PyExc_GreenletError, - "Greenlet.switch() returned NULL without an exception set." - ); - } - return p; - } - catch(const PyErrOccurred&) { - return nullptr; - } -} - -PyDoc_STRVAR( - green_throw_doc, - "Switches execution to this greenlet, but immediately raises the\n" - "given exception in this greenlet. If no argument is provided, the " - "exception\n" - "defaults to `greenlet.GreenletExit`. The normal exception\n" - "propagation rules apply, as described for `switch`. Note that calling " - "this\n" - "method is almost equivalent to the following::\n" - "\n" - " def raiser():\n" - " raise typ, val, tb\n" - " g_raiser = greenlet(raiser, parent=g)\n" - " g_raiser.switch()\n" - "\n" - "except that this trick does not work for the\n" - "`greenlet.GreenletExit` exception, which would not propagate\n" - "from ``g_raiser`` to ``g``.\n"); - -static PyObject* -green_throw(PyGreenlet* self, PyObject* args) -{ - PyArgParseParam typ(mod_globs->PyExc_GreenletExit); - PyArgParseParam val; - PyArgParseParam tb; - - if (!PyArg_ParseTuple(args, "|OOO:throw", &typ, &val, &tb)) { - return nullptr; - } - - assert(typ.borrow() || val.borrow()); - - self->pimpl->may_switch_away(); - try { - // Both normalizing the error and the actual throw_greenlet - // could throw PyErrOccurred. - PyErrPieces err_pieces(typ.borrow(), val.borrow(), tb.borrow()); - - return internal_green_throw(self, err_pieces).relinquish_ownership(); - } - catch (const PyErrOccurred&) { - return nullptr; - } -} - -static int -green_bool(PyGreenlet* self) -{ - return self->pimpl->active(); -} - -/** - * CAUTION: Allocates memory, may run GC and arbitrary Python code. - */ -static PyObject* -green_getdict(PyGreenlet* self, void* UNUSED(context)) -{ - if (self->dict == NULL) { - self->dict = PyDict_New(); - if (self->dict == NULL) { - return NULL; - } - } - Py_INCREF(self->dict); - return self->dict; -} - -static int -green_setdict(PyGreenlet* self, PyObject* val, void* UNUSED(context)) -{ - PyObject* tmp; - - if (val == NULL) { - PyErr_SetString(PyExc_TypeError, "__dict__ may not be deleted"); - return -1; - } - if (!PyDict_Check(val)) { - PyErr_SetString(PyExc_TypeError, "__dict__ must be a dictionary"); - return -1; - } - tmp = self->dict; - Py_INCREF(val); - self->dict = val; - Py_XDECREF(tmp); - return 0; -} - -static bool -_green_not_dead(BorrowedGreenlet self) -{ - // XXX: Where else should we do this? - // Probably on entry to most Python-facing functions? - if (self->was_running_in_dead_thread()) { - self->deactivate_and_free(); - return false; - } - return self->active() || !self->started(); -} - - -static PyObject* -green_getdead(PyGreenlet* self, void* UNUSED(context)) -{ - if (_green_not_dead(self)) { - Py_RETURN_FALSE; - } - else { - Py_RETURN_TRUE; - } -} - -static PyObject* -green_get_stack_saved(PyGreenlet* self, void* UNUSED(context)) -{ - return PyLong_FromSsize_t(self->pimpl->stack_saved()); -} - - -static PyObject* -green_getrun(PyGreenlet* self, void* UNUSED(context)) -{ - try { - OwnedObject result(BorrowedGreenlet(self)->run()); - return result.relinquish_ownership(); - } - catch(const PyErrOccurred&) { - return nullptr; - } -} - - -static int -green_setrun(PyGreenlet* self, PyObject* nrun, void* UNUSED(context)) -{ - try { - BorrowedGreenlet(self)->run(nrun); - return 0; - } - catch(const PyErrOccurred&) { - return -1; - } -} - -static PyObject* -green_getparent(PyGreenlet* self, void* UNUSED(context)) -{ - return BorrowedGreenlet(self)->parent().acquire_or_None(); -} - - -static int -green_setparent(PyGreenlet* self, PyObject* nparent, void* UNUSED(context)) -{ - try { - BorrowedGreenlet(self)->parent(nparent); - } - catch(const PyErrOccurred&) { - return -1; - } - return 0; -} - - -static PyObject* -green_getcontext(const PyGreenlet* self, void* UNUSED(context)) -{ - const Greenlet *const g = self->pimpl; - try { - OwnedObject result(g->context()); - return result.relinquish_ownership(); - } - catch(const PyErrOccurred&) { - return nullptr; - } -} - -static int -green_setcontext(PyGreenlet* self, PyObject* nctx, void* UNUSED(context)) -{ - try { - BorrowedGreenlet(self)->context(nctx); - return 0; - } - catch(const PyErrOccurred&) { - return -1; - } -} - - -static PyObject* -green_getframe(PyGreenlet* self, void* UNUSED(context)) -{ - const PythonState::OwnedFrame& top_frame = BorrowedGreenlet(self)->top_frame(); - return top_frame.acquire_or_None(); -} - - -static PyObject* -green_getstate(PyGreenlet* self) -{ - PyErr_Format(PyExc_TypeError, - "cannot serialize '%s' object", - Py_TYPE(self)->tp_name); - return nullptr; -} - -static PyObject* -green_repr(PyGreenlet* _self) -{ - BorrowedGreenlet self(_self); - /* - Return a string like - - - The handling of greenlets across threads is not super good. - We mostly use the internal definitions of these terms, but they - generally should make sense to users as well. - */ - PyObject* result; - int never_started = !self->started() && !self->active(); - - const char* const tp_name = Py_TYPE(self)->tp_name; - - if (_green_not_dead(self)) { - /* XXX: The otid= is almost useless because you can't correlate it to - any thread identifier exposed to Python. We could use - PyThreadState_GET()->thread_id, but we'd need to save that in the - greenlet, or save the whole PyThreadState object itself. - - As it stands, its only useful for identifying greenlets from the same thread. - */ - const char* state_in_thread; - if (self->was_running_in_dead_thread()) { - // The thread it was running in is dead! - // This can happen, especially at interpreter shut down. - // It complicates debugging output because it may be - // impossible to access the current thread state at that - // time. Thus, don't access the current thread state. - state_in_thread = " (thread exited)"; - } - else { - state_in_thread = GET_THREAD_STATE().state().is_current(self) - ? " current" - : (self->started() ? " suspended" : ""); - } - result = PyUnicode_FromFormat( - "<%s object at %p (otid=%p)%s%s%s%s>", - tp_name, - self.borrow_o(), - self->thread_state(), - state_in_thread, - self->active() ? " active" : "", - never_started ? " pending" : " started", - self->main() ? " main" : "" - ); - } - else { - result = PyUnicode_FromFormat( - "<%s object at %p (otid=%p) %sdead>", - tp_name, - self.borrow_o(), - self->thread_state(), - self->was_running_in_dead_thread() - ? "(thread exited) " - : "" - ); - } - - return result; -} - - -static PyMethodDef green_methods[] = { - { - .ml_name="switch", - .ml_meth=reinterpret_cast(green_switch), - .ml_flags=METH_VARARGS | METH_KEYWORDS, - .ml_doc=green_switch_doc - }, - {.ml_name="throw", .ml_meth=(PyCFunction)green_throw, .ml_flags=METH_VARARGS, .ml_doc=green_throw_doc}, - {.ml_name="__getstate__", .ml_meth=(PyCFunction)green_getstate, .ml_flags=METH_NOARGS, .ml_doc=NULL}, - {.ml_name=NULL, .ml_meth=NULL} /* sentinel */ -}; - -static PyGetSetDef green_getsets[] = { - /* name, getter, setter, doc, context pointer */ - {.name="__dict__", .get=(getter)green_getdict, .set=(setter)green_setdict}, - {.name="run", .get=(getter)green_getrun, .set=(setter)green_setrun}, - {.name="parent", .get=(getter)green_getparent, .set=(setter)green_setparent}, - {.name="gr_frame", .get=(getter)green_getframe }, - { - .name="gr_context", - .get=(getter)green_getcontext, - .set=(setter)green_setcontext - }, - {.name="dead", .get=(getter)green_getdead}, - {.name="_stack_saved", .get=(getter)green_get_stack_saved}, - {.name=NULL} -}; - -static PyMemberDef green_members[] = { - {.name=NULL} -}; - -static PyNumberMethods green_as_number = { - .nb_bool=(inquiry)green_bool, -}; - - -PyTypeObject PyGreenlet_Type = { - .ob_base=PyVarObject_HEAD_INIT(NULL, 0) - .tp_name="greenlet.greenlet", /* tp_name */ - .tp_basicsize=sizeof(PyGreenlet), /* tp_basicsize */ - /* methods */ - .tp_dealloc=(destructor)green_dealloc, /* tp_dealloc */ - .tp_repr=(reprfunc)green_repr, /* tp_repr */ - .tp_as_number=&green_as_number, /* tp_as _number*/ - .tp_flags=G_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */ - .tp_doc="greenlet(run=None, parent=None) -> greenlet\n\n" - "Creates a new greenlet object (without running it).\n\n" - " - *run* -- The callable to invoke.\n" - " - *parent* -- The parent greenlet. The default is the current " - "greenlet.", /* tp_doc */ - .tp_traverse=(traverseproc)green_traverse, /* tp_traverse */ - .tp_clear=(inquiry)green_clear, /* tp_clear */ - .tp_weaklistoffset=offsetof(PyGreenlet, weakreflist), /* tp_weaklistoffset */ - - .tp_methods=green_methods, /* tp_methods */ - .tp_members=green_members, /* tp_members */ - .tp_getset=green_getsets, /* tp_getset */ - .tp_dictoffset=offsetof(PyGreenlet, dict), /* tp_dictoffset */ - .tp_init=(initproc)green_init, /* tp_init */ - .tp_alloc=PyType_GenericAlloc, /* tp_alloc */ - .tp_new=(newfunc)green_new, /* tp_new */ - .tp_free=PyObject_GC_Del, /* tp_free */ - .tp_is_gc=(inquiry)green_is_gc, /* tp_is_gc */ -}; - -#endif - -// Local Variables: -// flycheck-clang-include-path: ("/opt/local/Library/Frameworks/Python.framework/Versions/3.8/include/python3.8") -// End: diff --git a/venv/lib/python3.9/site-packages/greenlet/PyGreenlet.hpp b/venv/lib/python3.9/site-packages/greenlet/PyGreenlet.hpp deleted file mode 100644 index df6cd80..0000000 --- a/venv/lib/python3.9/site-packages/greenlet/PyGreenlet.hpp +++ /dev/null @@ -1,35 +0,0 @@ -#ifndef PYGREENLET_HPP -#define PYGREENLET_HPP - - -#include "greenlet.h" -#include "greenlet_compiler_compat.hpp" -#include "greenlet_refs.hpp" - - -using greenlet::refs::OwnedGreenlet; -using greenlet::refs::BorrowedGreenlet; -using greenlet::refs::BorrowedObject;; -using greenlet::refs::OwnedObject; -using greenlet::refs::PyErrPieces; - - -// XXX: These doesn't really belong here, it's not a Python slot. -static OwnedObject internal_green_throw(BorrowedGreenlet self, PyErrPieces& err_pieces); - -static PyGreenlet* green_new(PyTypeObject* type, PyObject* UNUSED(args), PyObject* UNUSED(kwds)); -static int green_clear(PyGreenlet* self); -static int green_init(PyGreenlet* self, PyObject* args, PyObject* kwargs); -static int green_setparent(PyGreenlet* self, PyObject* nparent, void* UNUSED(context)); -static int green_setrun(PyGreenlet* self, PyObject* nrun, void* UNUSED(context)); -static int green_traverse(PyGreenlet* self, visitproc visit, void* arg); -static void green_dealloc(PyGreenlet* self); -static PyObject* green_getparent(PyGreenlet* self, void* UNUSED(context)); - -static int green_is_gc(PyObject* self); -static PyObject* green_getdead(PyGreenlet* self, void* UNUSED(context)); -static PyObject* green_getrun(PyGreenlet* self, void* UNUSED(context)); -static int green_setcontext(PyGreenlet* self, PyObject* nctx, void* UNUSED(context)); -static PyObject* green_getframe(PyGreenlet* self, void* UNUSED(context)); -static PyObject* green_repr(PyGreenlet* self); -#endif diff --git a/venv/lib/python3.9/site-packages/greenlet/PyGreenletUnswitchable.cpp b/venv/lib/python3.9/site-packages/greenlet/PyGreenletUnswitchable.cpp deleted file mode 100644 index 1b768ee..0000000 --- a/venv/lib/python3.9/site-packages/greenlet/PyGreenletUnswitchable.cpp +++ /dev/null @@ -1,147 +0,0 @@ -/* -*- indent-tabs-mode: nil; tab-width: 4; -*- */ -/** - Implementation of the Python slots for PyGreenletUnswitchable_Type -*/ -#ifndef PY_GREENLET_UNSWITCHABLE_CPP -#define PY_GREENLET_UNSWITCHABLE_CPP - - - -#define PY_SSIZE_T_CLEAN -#include -#include "structmember.h" // PyMemberDef - -#include "greenlet_internal.hpp" -// Code after this point can assume access to things declared in stdint.h, -// including the fixed-width types. This goes for the platform-specific switch functions -// as well. -#include "greenlet_refs.hpp" -#include "greenlet_slp_switch.hpp" - -#include "greenlet_thread_support.hpp" -#include "TGreenlet.hpp" - -#include "TGreenlet.cpp" -#include "TGreenletGlobals.cpp" -#include "TThreadStateDestroy.cpp" - - -using greenlet::LockGuard; -using greenlet::LockInitError; -using greenlet::PyErrOccurred; -using greenlet::Require; - -using greenlet::g_handle_exit; -using greenlet::single_result; - -using greenlet::Greenlet; -using greenlet::UserGreenlet; -using greenlet::MainGreenlet; -using greenlet::BrokenGreenlet; -using greenlet::ThreadState; -using greenlet::PythonState; - - -#include "PyGreenlet.hpp" - -static PyGreenlet* -green_unswitchable_new(PyTypeObject* type, PyObject* UNUSED(args), PyObject* UNUSED(kwds)) -{ - PyGreenlet* o = - (PyGreenlet*)PyBaseObject_Type.tp_new(type, mod_globs->empty_tuple, mod_globs->empty_dict); - if (o) { - new BrokenGreenlet(o, GET_THREAD_STATE().state().borrow_current()); - assert(Py_REFCNT(o) == 1); - } - return o; -} - -static PyObject* -green_unswitchable_getforce(PyGreenlet* self, void* UNUSED(context)) -{ - BrokenGreenlet* broken = dynamic_cast(self->pimpl); - return PyBool_FromLong(broken->_force_switch_error); -} - -static int -green_unswitchable_setforce(PyGreenlet* self, PyObject* nforce, void* UNUSED(context)) -{ - if (!nforce) { - PyErr_SetString( - PyExc_AttributeError, - "Cannot delete force_switch_error" - ); - return -1; - } - BrokenGreenlet* broken = dynamic_cast(self->pimpl); - int is_true = PyObject_IsTrue(nforce); - if (is_true == -1) { - return -1; - } - broken->_force_switch_error = is_true; - return 0; -} - -static PyObject* -green_unswitchable_getforceslp(PyGreenlet* self, void* UNUSED(context)) -{ - BrokenGreenlet* broken = dynamic_cast(self->pimpl); - return PyBool_FromLong(broken->_force_slp_switch_error); -} - -static int -green_unswitchable_setforceslp(PyGreenlet* self, PyObject* nforce, void* UNUSED(context)) -{ - if (!nforce) { - PyErr_SetString( - PyExc_AttributeError, - "Cannot delete force_slp_switch_error" - ); - return -1; - } - BrokenGreenlet* broken = dynamic_cast(self->pimpl); - int is_true = PyObject_IsTrue(nforce); - if (is_true == -1) { - return -1; - } - broken->_force_slp_switch_error = is_true; - return 0; -} - -static PyGetSetDef green_unswitchable_getsets[] = { - /* name, getter, setter, doc, closure (context pointer) */ - { - .name="force_switch_error", - .get=(getter)green_unswitchable_getforce, - .set=(setter)green_unswitchable_setforce, - .doc=NULL - }, - { - .name="force_slp_switch_error", - .get=(getter)green_unswitchable_getforceslp, - .set=(setter)green_unswitchable_setforceslp, - .doc=nullptr - }, - {.name=nullptr} -}; - -PyTypeObject PyGreenletUnswitchable_Type = { - .ob_base=PyVarObject_HEAD_INIT(NULL, 0) - .tp_name="greenlet._greenlet.UnswitchableGreenlet", - .tp_dealloc= (destructor)green_dealloc, /* tp_dealloc */ - .tp_flags=G_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */ - .tp_doc="Undocumented internal class", /* tp_doc */ - .tp_traverse=(traverseproc)green_traverse, /* tp_traverse */ - .tp_clear=(inquiry)green_clear, /* tp_clear */ - - .tp_getset=green_unswitchable_getsets, /* tp_getset */ - .tp_base=&PyGreenlet_Type, /* tp_base */ - .tp_init=(initproc)green_init, /* tp_init */ - .tp_alloc=PyType_GenericAlloc, /* tp_alloc */ - .tp_new=(newfunc)green_unswitchable_new, /* tp_new */ - .tp_free=PyObject_GC_Del, /* tp_free */ - .tp_is_gc=(inquiry)green_is_gc, /* tp_is_gc */ -}; - - -#endif diff --git a/venv/lib/python3.9/site-packages/greenlet/PyModule.cpp b/venv/lib/python3.9/site-packages/greenlet/PyModule.cpp deleted file mode 100644 index 6adcb5c..0000000 --- a/venv/lib/python3.9/site-packages/greenlet/PyModule.cpp +++ /dev/null @@ -1,292 +0,0 @@ -#ifndef PY_MODULE_CPP -#define PY_MODULE_CPP - -#include "greenlet_internal.hpp" - - -#include "TGreenletGlobals.cpp" -#include "TMainGreenlet.cpp" -#include "TThreadStateDestroy.cpp" - -using greenlet::LockGuard; -using greenlet::ThreadState; - -#ifdef __clang__ -# pragma clang diagnostic push -# pragma clang diagnostic ignored "-Wunused-function" -# pragma clang diagnostic ignored "-Wunused-variable" -#endif - -PyDoc_STRVAR(mod_getcurrent_doc, - "getcurrent() -> greenlet\n" - "\n" - "Returns the current greenlet (i.e. the one which called this " - "function).\n"); - -static PyObject* -mod_getcurrent(PyObject* UNUSED(module)) -{ - return GET_THREAD_STATE().state().get_current().relinquish_ownership_o(); -} - -PyDoc_STRVAR(mod_settrace_doc, - "settrace(callback) -> object\n" - "\n" - "Sets a new tracing function and returns the previous one.\n"); -static PyObject* -mod_settrace(PyObject* UNUSED(module), PyObject* args) -{ - PyArgParseParam tracefunc; - if (!PyArg_ParseTuple(args, "O", &tracefunc)) { - return NULL; - } - ThreadState& state = GET_THREAD_STATE(); - OwnedObject previous = state.get_tracefunc(); - if (!previous) { - previous = Py_None; - } - - state.set_tracefunc(tracefunc); - - return previous.relinquish_ownership(); -} - -PyDoc_STRVAR(mod_gettrace_doc, - "gettrace() -> object\n" - "\n" - "Returns the currently set tracing function, or None.\n"); - -static PyObject* -mod_gettrace(PyObject* UNUSED(module)) -{ - OwnedObject tracefunc = GET_THREAD_STATE().state().get_tracefunc(); - if (!tracefunc) { - tracefunc = Py_None; - } - return tracefunc.relinquish_ownership(); -} - - - -PyDoc_STRVAR(mod_set_thread_local_doc, - "set_thread_local(key, value) -> None\n" - "\n" - "Set a value in the current thread-local dictionary. Debugging only.\n"); - -static PyObject* -mod_set_thread_local(PyObject* UNUSED(module), PyObject* args) -{ - PyArgParseParam key; - PyArgParseParam value; - PyObject* result = NULL; - - if (PyArg_UnpackTuple(args, "set_thread_local", 2, 2, &key, &value)) { - if(PyDict_SetItem( - PyThreadState_GetDict(), // borrow - key, - value) == 0 ) { - // success - Py_INCREF(Py_None); - result = Py_None; - } - } - return result; -} - -PyDoc_STRVAR(mod_get_pending_cleanup_count_doc, - "get_pending_cleanup_count() -> Integer\n" - "\n" - "Get the number of greenlet cleanup operations pending. Testing only.\n"); - - -static PyObject* -mod_get_pending_cleanup_count(PyObject* UNUSED(module)) -{ - LockGuard cleanup_lock(*mod_globs->thread_states_to_destroy_lock); - return PyLong_FromSize_t(mod_globs->thread_states_to_destroy.size()); -} - -PyDoc_STRVAR(mod_get_total_main_greenlets_doc, - "get_total_main_greenlets() -> Integer\n" - "\n" - "Quickly return the number of main greenlets that exist. Testing only.\n"); - -static PyObject* -mod_get_total_main_greenlets(PyObject* UNUSED(module)) -{ - return PyLong_FromSize_t(G_TOTAL_MAIN_GREENLETS); -} - - - -PyDoc_STRVAR(mod_get_clocks_used_doing_optional_cleanup_doc, - "get_clocks_used_doing_optional_cleanup() -> Integer\n" - "\n" - "Get the number of clock ticks the program has used doing optional " - "greenlet cleanup.\n" - "Beginning in greenlet 2.0, greenlet tries to find and dispose of greenlets\n" - "that leaked after a thread exited. This requires invoking Python's garbage collector,\n" - "which may have a performance cost proportional to the number of live objects.\n" - "This function returns the amount of processor time\n" - "greenlet has used to do this. In programs that run with very large amounts of live\n" - "objects, this metric can be used to decide whether the cost of doing this cleanup\n" - "is worth the memory leak being corrected. If not, you can disable the cleanup\n" - "using ``enable_optional_cleanup(False)``.\n" - "The units are arbitrary and can only be compared to themselves (similarly to ``time.clock()``);\n" - "for example, to see how it scales with your heap. You can attempt to convert them into seconds\n" - "by dividing by the value of CLOCKS_PER_SEC." - "If cleanup has been disabled, returns None." - "\n" - "This is an implementation specific, provisional API. It may be changed or removed\n" - "in the future.\n" - ".. versionadded:: 2.0" - ); -static PyObject* -mod_get_clocks_used_doing_optional_cleanup(PyObject* UNUSED(module)) -{ - std::clock_t& clocks = ThreadState::clocks_used_doing_gc(); - - if (clocks == std::clock_t(-1)) { - Py_RETURN_NONE; - } - // This might not actually work on some implementations; clock_t - // is an opaque type. - return PyLong_FromSsize_t(clocks); -} - -PyDoc_STRVAR(mod_enable_optional_cleanup_doc, - "mod_enable_optional_cleanup(bool) -> None\n" - "\n" - "Enable or disable optional cleanup operations.\n" - "See ``get_clocks_used_doing_optional_cleanup()`` for details.\n" - ); -static PyObject* -mod_enable_optional_cleanup(PyObject* UNUSED(module), PyObject* flag) -{ - int is_true = PyObject_IsTrue(flag); - if (is_true == -1) { - return nullptr; - } - - std::clock_t& clocks = ThreadState::clocks_used_doing_gc(); - if (is_true) { - // If we already have a value, we don't want to lose it. - if (clocks == std::clock_t(-1)) { - clocks = 0; - } - } - else { - clocks = std::clock_t(-1); - } - Py_RETURN_NONE; -} - - - - -#if !GREENLET_PY313 -PyDoc_STRVAR(mod_get_tstate_trash_delete_nesting_doc, - "get_tstate_trash_delete_nesting() -> Integer\n" - "\n" - "Return the 'trash can' nesting level. Testing only.\n"); -static PyObject* -mod_get_tstate_trash_delete_nesting(PyObject* UNUSED(module)) -{ - PyThreadState* tstate = PyThreadState_GET(); - -#if GREENLET_PY312 - return PyLong_FromLong(tstate->trash.delete_nesting); -#else - return PyLong_FromLong(tstate->trash_delete_nesting); -#endif -} -#endif - - - - -static PyMethodDef GreenMethods[] = { - { - .ml_name="getcurrent", - .ml_meth=(PyCFunction)mod_getcurrent, - .ml_flags=METH_NOARGS, - .ml_doc=mod_getcurrent_doc - }, - { - .ml_name="settrace", - .ml_meth=(PyCFunction)mod_settrace, - .ml_flags=METH_VARARGS, - .ml_doc=mod_settrace_doc - }, - { - .ml_name="gettrace", - .ml_meth=(PyCFunction)mod_gettrace, - .ml_flags=METH_NOARGS, - .ml_doc=mod_gettrace_doc - }, - { - .ml_name="set_thread_local", - .ml_meth=(PyCFunction)mod_set_thread_local, - .ml_flags=METH_VARARGS, - .ml_doc=mod_set_thread_local_doc - }, - { - .ml_name="get_pending_cleanup_count", - .ml_meth=(PyCFunction)mod_get_pending_cleanup_count, - .ml_flags=METH_NOARGS, - .ml_doc=mod_get_pending_cleanup_count_doc - }, - { - .ml_name="get_total_main_greenlets", - .ml_meth=(PyCFunction)mod_get_total_main_greenlets, - .ml_flags=METH_NOARGS, - .ml_doc=mod_get_total_main_greenlets_doc - }, - { - .ml_name="get_clocks_used_doing_optional_cleanup", - .ml_meth=(PyCFunction)mod_get_clocks_used_doing_optional_cleanup, - .ml_flags=METH_NOARGS, - .ml_doc=mod_get_clocks_used_doing_optional_cleanup_doc - }, - { - .ml_name="enable_optional_cleanup", - .ml_meth=(PyCFunction)mod_enable_optional_cleanup, - .ml_flags=METH_O, - .ml_doc=mod_enable_optional_cleanup_doc - }, -#if !GREENLET_PY313 - { - .ml_name="get_tstate_trash_delete_nesting", - .ml_meth=(PyCFunction)mod_get_tstate_trash_delete_nesting, - .ml_flags=METH_NOARGS, - .ml_doc=mod_get_tstate_trash_delete_nesting_doc - }, -#endif - {.ml_name=NULL, .ml_meth=NULL} /* Sentinel */ -}; - -static const char* const copy_on_greentype[] = { - "getcurrent", - "error", - "GreenletExit", - "settrace", - "gettrace", - NULL -}; - -static struct PyModuleDef greenlet_module_def = { - .m_base=PyModuleDef_HEAD_INIT, - .m_name="greenlet._greenlet", - .m_doc=NULL, - .m_size=-1, - .m_methods=GreenMethods, -}; - - -#endif - -#ifdef __clang__ -# pragma clang diagnostic pop -#elif defined(__GNUC__) -# pragma GCC diagnostic pop -#endif diff --git a/venv/lib/python3.9/site-packages/greenlet/TBrokenGreenlet.cpp b/venv/lib/python3.9/site-packages/greenlet/TBrokenGreenlet.cpp deleted file mode 100644 index 7e9ab5b..0000000 --- a/venv/lib/python3.9/site-packages/greenlet/TBrokenGreenlet.cpp +++ /dev/null @@ -1,45 +0,0 @@ -/* -*- indent-tabs-mode: nil; tab-width: 4; -*- */ -/** - * Implementation of greenlet::UserGreenlet. - * - * Format with: - * clang-format -i --style=file src/greenlet/greenlet.c - * - * - * Fix missing braces with: - * clang-tidy src/greenlet/greenlet.c -fix -checks="readability-braces-around-statements" -*/ - -#include "TGreenlet.hpp" - -namespace greenlet { - -void* BrokenGreenlet::operator new(size_t UNUSED(count)) -{ - return allocator.allocate(1); -} - - -void BrokenGreenlet::operator delete(void* ptr) -{ - return allocator.deallocate(static_cast(ptr), - 1); -} - -greenlet::PythonAllocator greenlet::BrokenGreenlet::allocator; - -bool -BrokenGreenlet::force_slp_switch_error() const noexcept -{ - return this->_force_slp_switch_error; -} - -UserGreenlet::switchstack_result_t BrokenGreenlet::g_switchstack(void) -{ - if (this->_force_switch_error) { - return switchstack_result_t(-1); - } - return UserGreenlet::g_switchstack(); -} - -}; //namespace greenlet diff --git a/venv/lib/python3.9/site-packages/greenlet/TExceptionState.cpp b/venv/lib/python3.9/site-packages/greenlet/TExceptionState.cpp deleted file mode 100644 index 08a94ae..0000000 --- a/venv/lib/python3.9/site-packages/greenlet/TExceptionState.cpp +++ /dev/null @@ -1,62 +0,0 @@ -#ifndef GREENLET_EXCEPTION_STATE_CPP -#define GREENLET_EXCEPTION_STATE_CPP - -#include -#include "TGreenlet.hpp" - -namespace greenlet { - - -ExceptionState::ExceptionState() -{ - this->clear(); -} - -void ExceptionState::operator<<(const PyThreadState *const tstate) noexcept -{ - this->exc_info = tstate->exc_info; - this->exc_state = tstate->exc_state; -} - -void ExceptionState::operator>>(PyThreadState *const tstate) noexcept -{ - tstate->exc_state = this->exc_state; - tstate->exc_info = - this->exc_info ? this->exc_info : &tstate->exc_state; - this->clear(); -} - -void ExceptionState::clear() noexcept -{ - this->exc_info = nullptr; - this->exc_state.exc_value = nullptr; -#if !GREENLET_PY311 - this->exc_state.exc_type = nullptr; - this->exc_state.exc_traceback = nullptr; -#endif - this->exc_state.previous_item = nullptr; -} - -int ExceptionState::tp_traverse(visitproc visit, void* arg) noexcept -{ - Py_VISIT(this->exc_state.exc_value); -#if !GREENLET_PY311 - Py_VISIT(this->exc_state.exc_type); - Py_VISIT(this->exc_state.exc_traceback); -#endif - return 0; -} - -void ExceptionState::tp_clear() noexcept -{ - Py_CLEAR(this->exc_state.exc_value); -#if !GREENLET_PY311 - Py_CLEAR(this->exc_state.exc_type); - Py_CLEAR(this->exc_state.exc_traceback); -#endif -} - - -}; // namespace greenlet - -#endif // GREENLET_EXCEPTION_STATE_CPP diff --git a/venv/lib/python3.9/site-packages/greenlet/TGreenlet.cpp b/venv/lib/python3.9/site-packages/greenlet/TGreenlet.cpp deleted file mode 100644 index d12722b..0000000 --- a/venv/lib/python3.9/site-packages/greenlet/TGreenlet.cpp +++ /dev/null @@ -1,719 +0,0 @@ -/* -*- indent-tabs-mode: nil; tab-width: 4; -*- */ -/** - * Implementation of greenlet::Greenlet. - * - * Format with: - * clang-format -i --style=file src/greenlet/greenlet.c - * - * - * Fix missing braces with: - * clang-tidy src/greenlet/greenlet.c -fix -checks="readability-braces-around-statements" -*/ -#ifndef TGREENLET_CPP -#define TGREENLET_CPP -#include "greenlet_internal.hpp" -#include "TGreenlet.hpp" - - -#include "TGreenletGlobals.cpp" -#include "TThreadStateDestroy.cpp" - -namespace greenlet { - -Greenlet::Greenlet(PyGreenlet* p) - : Greenlet(p, StackState()) -{ -} - -Greenlet::Greenlet(PyGreenlet* p, const StackState& initial_stack) - : _self(p), stack_state(initial_stack) -{ - assert(p->pimpl == nullptr); - p->pimpl = this; -} - -Greenlet::~Greenlet() -{ - // XXX: Can't do this. tp_clear is a virtual function, and by the - // time we're here, we've sliced off our child classes. - //this->tp_clear(); - this->_self->pimpl = nullptr; -} - -bool -Greenlet::force_slp_switch_error() const noexcept -{ - return false; -} - -void -Greenlet::release_args() -{ - this->switch_args.CLEAR(); -} - -/** - * CAUTION: This will allocate memory and may trigger garbage - * collection and arbitrary Python code. - */ -OwnedObject -Greenlet::throw_GreenletExit_during_dealloc(const ThreadState& UNUSED(current_thread_state)) -{ - // If we're killed because we lost all references in the - // middle of a switch, that's ok. Don't reset the args/kwargs, - // we still want to pass them to the parent. - PyErr_SetString(mod_globs->PyExc_GreenletExit, - "Killing the greenlet because all references have vanished."); - // To get here it had to have run before - return this->g_switch(); -} - -inline void -Greenlet::slp_restore_state() noexcept -{ -#ifdef SLP_BEFORE_RESTORE_STATE - SLP_BEFORE_RESTORE_STATE(); -#endif - this->stack_state.copy_heap_to_stack( - this->thread_state()->borrow_current()->stack_state); -} - - -inline int -Greenlet::slp_save_state(char *const stackref) noexcept -{ - // XXX: This used to happen in the middle, before saving, but - // after finding the next owner. Does that matter? This is - // only defined for Sparc/GCC where it flushes register - // windows to the stack (I think) -#ifdef SLP_BEFORE_SAVE_STATE - SLP_BEFORE_SAVE_STATE(); -#endif - return this->stack_state.copy_stack_to_heap(stackref, - this->thread_state()->borrow_current()->stack_state); -} - -/** - * CAUTION: This will allocate memory and may trigger garbage - * collection and arbitrary Python code. - */ -OwnedObject -Greenlet::on_switchstack_or_initialstub_failure( - Greenlet* target, - const Greenlet::switchstack_result_t& err, - const bool target_was_me, - const bool was_initial_stub) -{ - // If we get here, either g_initialstub() - // failed, or g_switchstack() failed. Either one of those - // cases SHOULD leave us in the original greenlet with a valid stack. - if (!PyErr_Occurred()) { - PyErr_SetString( - PyExc_SystemError, - was_initial_stub - ? "Failed to switch stacks into a greenlet for the first time." - : "Failed to switch stacks into a running greenlet."); - } - this->release_args(); - - if (target && !target_was_me) { - target->murder_in_place(); - } - - assert(!err.the_new_current_greenlet); - assert(!err.origin_greenlet); - return OwnedObject(); - -} - -OwnedGreenlet -Greenlet::g_switchstack_success() noexcept -{ - PyThreadState* tstate = PyThreadState_GET(); - // restore the saved state - this->python_state >> tstate; - this->exception_state >> tstate; - - // The thread state hasn't been changed yet. - ThreadState* thread_state = this->thread_state(); - OwnedGreenlet result(thread_state->get_current()); - thread_state->set_current(this->self()); - //assert(thread_state->borrow_current().borrow() == this->_self); - return result; -} - -Greenlet::switchstack_result_t -Greenlet::g_switchstack(void) -{ - // if any of these assertions fail, it's likely because we - // switched away and tried to switch back to us. Early stages of - // switching are not reentrant because we re-use ``this->args()``. - // Switching away would happen if we trigger a garbage collection - // (by just using some Python APIs that happen to allocate Python - // objects) and some garbage had weakref callbacks or __del__ that - // switches (people don't write code like that by hand, but with - // gevent it's possible without realizing it) - assert(this->args() || PyErr_Occurred()); - { /* save state */ - if (this->thread_state()->is_current(this->self())) { - // Hmm, nothing to do. - // TODO: Does this bypass trace events that are - // important? - return switchstack_result_t(0, - this, this->thread_state()->borrow_current()); - } - BorrowedGreenlet current = this->thread_state()->borrow_current(); - PyThreadState* tstate = PyThreadState_GET(); - - current->python_state << tstate; - current->exception_state << tstate; - this->python_state.will_switch_from(tstate); - switching_thread_state = this; - current->expose_frames(); - } - assert(this->args() || PyErr_Occurred()); - // If this is the first switch into a greenlet, this will - // return twice, once with 1 in the new greenlet, once with 0 - // in the origin. - int err; - if (this->force_slp_switch_error()) { - err = -1; - } - else { - err = slp_switch(); - } - - if (err < 0) { /* error */ - // Tested by - // test_greenlet.TestBrokenGreenlets.test_failed_to_slp_switch_into_running - // - // It's not clear if it's worth trying to clean up and - // continue here. Failing to switch stacks is a big deal which - // may not be recoverable (who knows what state the stack is in). - // Also, we've stolen references in preparation for calling - // ``g_switchstack_success()`` and we don't have a clean - // mechanism for backing that all out. - Py_FatalError("greenlet: Failed low-level slp_switch(). The stack is probably corrupt."); - } - - // No stack-based variables are valid anymore. - - // But the global is volatile so we can reload it without the - // compiler caching it from earlier. - Greenlet* greenlet_that_switched_in = switching_thread_state; // aka this - switching_thread_state = nullptr; - // except that no stack variables are valid, we would: - // assert(this == greenlet_that_switched_in); - - // switchstack success is where we restore the exception state, - // etc. It returns the origin greenlet because its convenient. - - OwnedGreenlet origin = greenlet_that_switched_in->g_switchstack_success(); - assert(greenlet_that_switched_in->args() || PyErr_Occurred()); - return switchstack_result_t(err, greenlet_that_switched_in, origin); -} - - -inline void -Greenlet::check_switch_allowed() const -{ - // TODO: Make this take a parameter of the current greenlet, - // or current main greenlet, to make the check for - // cross-thread switching cheaper. Surely somewhere up the - // call stack we've already accessed the thread local variable. - - // We expect to always have a main greenlet now; accessing the thread state - // created it. However, if we get here and cleanup has already - // begun because we're a greenlet that was running in a - // (now dead) thread, these invariants will not hold true. In - // fact, accessing `this->thread_state` may not even be possible. - - // If the thread this greenlet was running in is dead, - // we'll still have a reference to a main greenlet, but the - // thread state pointer we have is bogus. - // TODO: Give the objects an API to determine if they belong - // to a dead thread. - - const BorrowedMainGreenlet main_greenlet = this->find_main_greenlet_in_lineage(); - - if (!main_greenlet) { - throw PyErrOccurred(mod_globs->PyExc_GreenletError, - "cannot switch to a garbage collected greenlet"); - } - - if (!main_greenlet->thread_state()) { - throw PyErrOccurred(mod_globs->PyExc_GreenletError, - "cannot switch to a different thread (which happens to have exited)"); - } - - // The main greenlet we found was from the .parent lineage. - // That may or may not have any relationship to the main - // greenlet of the running thread. We can't actually access - // our this->thread_state members to try to check that, - // because it could be in the process of getting destroyed, - // but setting the main_greenlet->thread_state member to NULL - // may not be visible yet. So we need to check against the - // current thread state (once the cheaper checks are out of - // the way) - const BorrowedMainGreenlet current_main_greenlet = GET_THREAD_STATE().state().borrow_main_greenlet(); - if ( - // lineage main greenlet is not this thread's greenlet - current_main_greenlet != main_greenlet - || ( - // atteched to some thread - this->main_greenlet() - // XXX: Same condition as above. Was this supposed to be - // this->main_greenlet()? - && current_main_greenlet != main_greenlet) - // switching into a known dead thread (XXX: which, if we get here, - // is bad, because we just accessed the thread state, which is - // gone!) - || (!current_main_greenlet->thread_state())) { - // CAUTION: This may trigger memory allocations, gc, and - // arbitrary Python code. - throw PyErrOccurred( - mod_globs->PyExc_GreenletError, - "Cannot switch to a different thread\n\tCurrent: %R\n\tExpected: %R", - current_main_greenlet, main_greenlet); - } -} - -const OwnedObject -Greenlet::context() const -{ - using greenlet::PythonStateContext; - OwnedObject result; - - if (this->is_currently_running_in_some_thread()) { - /* Currently running greenlet: context is stored in the thread state, - not the greenlet object. */ - if (GET_THREAD_STATE().state().is_current(this->self())) { - result = PythonStateContext::context(PyThreadState_GET()); - } - else { - throw ValueError( - "cannot get context of a " - "greenlet that is running in a different thread"); - } - } - else { - /* Greenlet is not running: just return context. */ - result = this->python_state.context(); - } - if (!result) { - result = OwnedObject::None(); - } - return result; -} - - -void -Greenlet::context(BorrowedObject given) -{ - using greenlet::PythonStateContext; - if (!given) { - throw AttributeError("can't delete context attribute"); - } - if (given.is_None()) { - /* "Empty context" is stored as NULL, not None. */ - given = nullptr; - } - - //checks type, incrs refcnt - greenlet::refs::OwnedContext context(given); - PyThreadState* tstate = PyThreadState_GET(); - - if (this->is_currently_running_in_some_thread()) { - if (!GET_THREAD_STATE().state().is_current(this->self())) { - throw ValueError("cannot set context of a greenlet" - " that is running in a different thread"); - } - - /* Currently running greenlet: context is stored in the thread state, - not the greenlet object. */ - OwnedObject octx = OwnedObject::consuming(PythonStateContext::context(tstate)); - PythonStateContext::context(tstate, context.relinquish_ownership()); - } - else { - /* Greenlet is not running: just set context. Note that the - greenlet may be dead.*/ - this->python_state.context() = context; - } -} - -/** - * CAUTION: May invoke arbitrary Python code. - * - * Figure out what the result of ``greenlet.switch(arg, kwargs)`` - * should be and transfers ownership of it to the left-hand-side. - * - * If switch() was just passed an arg tuple, then we'll just return that. - * If only keyword arguments were passed, then we'll pass the keyword - * argument dict. Otherwise, we'll create a tuple of (args, kwargs) and - * return both. - * - * CAUTION: This may allocate a new tuple object, which may - * cause the Python garbage collector to run, which in turn may - * run arbitrary Python code that switches. - */ -OwnedObject& operator<<=(OwnedObject& lhs, greenlet::SwitchingArgs& rhs) noexcept -{ - // Because this may invoke arbitrary Python code, which could - // result in switching back to us, we need to get the - // arguments locally on the stack. - assert(rhs); - OwnedObject args = rhs.args(); - OwnedObject kwargs = rhs.kwargs(); - rhs.CLEAR(); - // We shouldn't be called twice for the same switch. - assert(args || kwargs); - assert(!rhs); - - if (!kwargs) { - lhs = args; - } - else if (!PyDict_Size(kwargs.borrow())) { - lhs = args; - } - else if (!PySequence_Length(args.borrow())) { - lhs = kwargs; - } - else { - // PyTuple_Pack allocates memory, may GC, may run arbitrary - // Python code. - lhs = OwnedObject::consuming(PyTuple_Pack(2, args.borrow(), kwargs.borrow())); - } - return lhs; -} - -static OwnedObject -g_handle_exit(const OwnedObject& greenlet_result) -{ - if (!greenlet_result && mod_globs->PyExc_GreenletExit.PyExceptionMatches()) { - /* catch and ignore GreenletExit */ - PyErrFetchParam val; - PyErr_Fetch(PyErrFetchParam(), val, PyErrFetchParam()); - if (!val) { - return OwnedObject::None(); - } - return OwnedObject(val); - } - - if (greenlet_result) { - // package the result into a 1-tuple - // PyTuple_Pack increments the reference of its arguments, - // so we always need to decref the greenlet result; - // the owner will do that. - return OwnedObject::consuming(PyTuple_Pack(1, greenlet_result.borrow())); - } - - return OwnedObject(); -} - - - -/** - * May run arbitrary Python code. - */ -OwnedObject -Greenlet::g_switch_finish(const switchstack_result_t& err) -{ - assert(err.the_new_current_greenlet == this); - - ThreadState& state = *this->thread_state(); - // Because calling the trace function could do arbitrary things, - // including switching away from this greenlet and then maybe - // switching back, we need to capture the arguments now so that - // they don't change. - OwnedObject result; - if (this->args()) { - result <<= this->args(); - } - else { - assert(PyErr_Occurred()); - } - assert(!this->args()); - try { - // Our only caller handles the bad error case - assert(err.status >= 0); - assert(state.borrow_current() == this->self()); - if (OwnedObject tracefunc = state.get_tracefunc()) { - assert(result || PyErr_Occurred()); - g_calltrace(tracefunc, - result ? mod_globs->event_switch : mod_globs->event_throw, - err.origin_greenlet, - this->self()); - } - // The above could have invoked arbitrary Python code, but - // it couldn't switch back to this object and *also* - // throw an exception, so the args won't have changed. - - if (PyErr_Occurred()) { - // We get here if we fell of the end of the run() function - // raising an exception. The switch itself was - // successful, but the function raised. - // valgrind reports that memory allocated here can still - // be reached after a test run. - throw PyErrOccurred::from_current(); - } - return result; - } - catch (const PyErrOccurred&) { - /* Turn switch errors into switch throws */ - /* Turn trace errors into switch throws */ - this->release_args(); - throw; - } -} - -void -Greenlet::g_calltrace(const OwnedObject& tracefunc, - const greenlet::refs::ImmortalEventName& event, - const BorrowedGreenlet& origin, - const BorrowedGreenlet& target) -{ - PyErrPieces saved_exc; - try { - TracingGuard tracing_guard; - // TODO: We have saved the active exception (if any) that's - // about to be raised. In the 'throw' case, we could provide - // the exception to the tracefunction, which seems very helpful. - tracing_guard.CallTraceFunction(tracefunc, event, origin, target); - } - catch (const PyErrOccurred&) { - // In case of exceptions trace function is removed, - // and any existing exception is replaced with the tracing - // exception. - GET_THREAD_STATE().state().set_tracefunc(Py_None); - throw; - } - - saved_exc.PyErrRestore(); - assert( - (event == mod_globs->event_throw && PyErr_Occurred()) - || (event == mod_globs->event_switch && !PyErr_Occurred()) - ); -} - -void -Greenlet::murder_in_place() -{ - if (this->active()) { - assert(!this->is_currently_running_in_some_thread()); - this->deactivate_and_free(); - } -} - -inline void -Greenlet::deactivate_and_free() -{ - if (!this->active()) { - return; - } - // Throw away any saved stack. - this->stack_state = StackState(); - assert(!this->stack_state.active()); - // Throw away any Python references. - // We're holding a borrowed reference to the last - // frame we executed. Since we borrowed it, the - // normal traversal, clear, and dealloc functions - // ignore it, meaning it leaks. (The thread state - // object can't find it to clear it when that's - // deallocated either, because by definition if we - // got an object on this list, it wasn't - // running and the thread state doesn't have - // this frame.) - // So here, we *do* clear it. - this->python_state.tp_clear(true); -} - -bool -Greenlet::belongs_to_thread(const ThreadState* thread_state) const -{ - if (!this->thread_state() // not running anywhere, or thread - // exited - || !thread_state) { // same, or there is no thread state. - return false; - } - return true; -} - - -void -Greenlet::deallocing_greenlet_in_thread(const ThreadState* current_thread_state) -{ - /* Cannot raise an exception to kill the greenlet if - it is not running in the same thread! */ - if (this->belongs_to_thread(current_thread_state)) { - assert(current_thread_state); - // To get here it had to have run before - /* Send the greenlet a GreenletExit exception. */ - - // We don't care about the return value, only whether an - // exception happened. - this->throw_GreenletExit_during_dealloc(*current_thread_state); - return; - } - - // Not the same thread! Temporarily save the greenlet - // into its thread's deleteme list, *if* it exists. - // If that thread has already exited, and processed its pending - // cleanup, we'll never be able to clean everything up: we won't - // be able to raise an exception. - // That's mostly OK! Since we can't add it to a list, our refcount - // won't increase, and we'll go ahead with the DECREFs later. - - ThreadState *const thread_state = this->thread_state(); - if (thread_state) { - thread_state->delete_when_thread_running(this->self()); - } - else { - // The thread is dead, we can't raise an exception. - // We need to make it look non-active, though, so that dealloc - // finishes killing it. - this->deactivate_and_free(); - } - return; -} - - -int -Greenlet::tp_traverse(visitproc visit, void* arg) -{ - - int result; - if ((result = this->exception_state.tp_traverse(visit, arg)) != 0) { - return result; - } - //XXX: This is ugly. But so is handling everything having to do - //with the top frame. - bool visit_top_frame = this->was_running_in_dead_thread(); - // When true, the thread is dead. Our implicit weak reference to the - // frame is now all that's left; we consider ourselves to - // strongly own it now. - if ((result = this->python_state.tp_traverse(visit, arg, visit_top_frame)) != 0) { - return result; - } - return 0; -} - -int -Greenlet::tp_clear() -{ - bool own_top_frame = this->was_running_in_dead_thread(); - this->exception_state.tp_clear(); - this->python_state.tp_clear(own_top_frame); - return 0; -} - -bool Greenlet::is_currently_running_in_some_thread() const -{ - return this->stack_state.active() && !this->python_state.top_frame(); -} - -#if GREENLET_PY312 -void GREENLET_NOINLINE(Greenlet::expose_frames)() -{ - if (!this->python_state.top_frame()) { - return; - } - - _PyInterpreterFrame* last_complete_iframe = nullptr; - _PyInterpreterFrame* iframe = this->python_state.top_frame()->f_frame; - while (iframe) { - // We must make a copy before looking at the iframe contents, - // since iframe might point to a portion of the greenlet's C stack - // that was spilled when switching greenlets. - _PyInterpreterFrame iframe_copy; - this->stack_state.copy_from_stack(&iframe_copy, iframe, sizeof(*iframe)); - if (!_PyFrame_IsIncomplete(&iframe_copy)) { - // If the iframe were OWNED_BY_CSTACK then it would always be - // incomplete. Since it's not incomplete, it's not on the C stack - // and we can access it through the original `iframe` pointer - // directly. This is important since GetFrameObject might - // lazily _create_ the frame object and we don't want the - // interpreter to lose track of it. - assert(iframe_copy.owner != FRAME_OWNED_BY_CSTACK); - - // We really want to just write: - // PyFrameObject* frame = _PyFrame_GetFrameObject(iframe); - // but _PyFrame_GetFrameObject calls _PyFrame_MakeAndSetFrameObject - // which is not a visible symbol in libpython. The easiest - // way to get a public function to call it is using - // PyFrame_GetBack, which is defined as follows: - // assert(frame != NULL); - // assert(!_PyFrame_IsIncomplete(frame->f_frame)); - // PyFrameObject *back = frame->f_back; - // if (back == NULL) { - // _PyInterpreterFrame *prev = frame->f_frame->previous; - // prev = _PyFrame_GetFirstComplete(prev); - // if (prev) { - // back = _PyFrame_GetFrameObject(prev); - // } - // } - // return (PyFrameObject*)Py_XNewRef(back); - if (!iframe->frame_obj) { - PyFrameObject dummy_frame; - _PyInterpreterFrame dummy_iframe; - dummy_frame.f_back = nullptr; - dummy_frame.f_frame = &dummy_iframe; - // force the iframe to be considered complete without - // needing to check its code object: - dummy_iframe.owner = FRAME_OWNED_BY_GENERATOR; - dummy_iframe.previous = iframe; - assert(!_PyFrame_IsIncomplete(&dummy_iframe)); - // Drop the returned reference immediately; the iframe - // continues to hold a strong reference - Py_XDECREF(PyFrame_GetBack(&dummy_frame)); - assert(iframe->frame_obj); - } - - // This is a complete frame, so make the last one of those we saw - // point at it, bypassing any incomplete frames (which may have - // been on the C stack) in between the two. We're overwriting - // last_complete_iframe->previous and need that to be reversible, - // so we store the original previous ptr in the frame object - // (which we must have created on a previous iteration through - // this loop). The frame object has a bunch of storage that is - // only used when its iframe is OWNED_BY_FRAME_OBJECT, which only - // occurs when the frame object outlives the frame's execution, - // which can't have happened yet because the frame is currently - // executing as far as the interpreter is concerned. So, we can - // reuse it for our own purposes. - assert(iframe->owner == FRAME_OWNED_BY_THREAD - || iframe->owner == FRAME_OWNED_BY_GENERATOR); - if (last_complete_iframe) { - assert(last_complete_iframe->frame_obj); - memcpy(&last_complete_iframe->frame_obj->_f_frame_data[0], - &last_complete_iframe->previous, sizeof(void *)); - last_complete_iframe->previous = iframe; - } - last_complete_iframe = iframe; - } - // Frames that are OWNED_BY_FRAME_OBJECT are linked via the - // frame's f_back while all others are linked via the iframe's - // previous ptr. Since all the frames we traverse are running - // as far as the interpreter is concerned, we don't have to - // worry about the OWNED_BY_FRAME_OBJECT case. - iframe = iframe_copy.previous; - } - - // Give the outermost complete iframe a null previous pointer to - // account for any potential incomplete/C-stack iframes between it - // and the actual top-of-stack - if (last_complete_iframe) { - assert(last_complete_iframe->frame_obj); - memcpy(&last_complete_iframe->frame_obj->_f_frame_data[0], - &last_complete_iframe->previous, sizeof(void *)); - last_complete_iframe->previous = nullptr; - } -} -#else -void Greenlet::expose_frames() -{ - -} -#endif - -}; // namespace greenlet -#endif diff --git a/venv/lib/python3.9/site-packages/greenlet/TGreenlet.hpp b/venv/lib/python3.9/site-packages/greenlet/TGreenlet.hpp deleted file mode 100644 index e152353..0000000 --- a/venv/lib/python3.9/site-packages/greenlet/TGreenlet.hpp +++ /dev/null @@ -1,830 +0,0 @@ -#ifndef GREENLET_GREENLET_HPP -#define GREENLET_GREENLET_HPP -/* - * Declarations of the core data structures. -*/ - -#define PY_SSIZE_T_CLEAN -#include - -#include "greenlet_compiler_compat.hpp" -#include "greenlet_refs.hpp" -#include "greenlet_cpython_compat.hpp" -#include "greenlet_allocator.hpp" - -using greenlet::refs::OwnedObject; -using greenlet::refs::OwnedGreenlet; -using greenlet::refs::OwnedMainGreenlet; -using greenlet::refs::BorrowedGreenlet; - -#if PY_VERSION_HEX < 0x30B00A6 -# define _PyCFrame CFrame -# define _PyInterpreterFrame _interpreter_frame -#endif - -#if GREENLET_PY312 -# define Py_BUILD_CORE -# include "internal/pycore_frame.h" -#endif - -#if GREENLET_PY314 -# include "internal/pycore_interpframe_structs.h" -#if defined(_MSC_VER) || defined(__MINGW64__) -# include "greenlet_msvc_compat.hpp" -#else -# include "internal/pycore_interpframe.h" -#endif -#endif - -// XXX: TODO: Work to remove all virtual functions -// for speed of calling and size of objects (no vtable). -// One pattern is the Curiously Recurring Template -namespace greenlet -{ - class ExceptionState - { - private: - G_NO_COPIES_OF_CLS(ExceptionState); - - // Even though these are borrowed objects, we actually own - // them, when they're not null. - // XXX: Express that in the API. - private: - _PyErr_StackItem* exc_info; - _PyErr_StackItem exc_state; - public: - ExceptionState(); - void operator<<(const PyThreadState *const tstate) noexcept; - void operator>>(PyThreadState* tstate) noexcept; - void clear() noexcept; - - int tp_traverse(visitproc visit, void* arg) noexcept; - void tp_clear() noexcept; - }; - - template - void operator<<(const PyThreadState *const tstate, T& exc); - - class PythonStateContext - { - protected: - greenlet::refs::OwnedContext _context; - public: - inline const greenlet::refs::OwnedContext& context() const - { - return this->_context; - } - inline greenlet::refs::OwnedContext& context() - { - return this->_context; - } - - inline void tp_clear() - { - this->_context.CLEAR(); - } - - template - inline static PyObject* context(T* tstate) - { - return tstate->context; - } - - template - inline static void context(T* tstate, PyObject* new_context) - { - tstate->context = new_context; - tstate->context_ver++; - } - }; - class SwitchingArgs; - class PythonState : public PythonStateContext - { - public: - typedef greenlet::refs::OwnedReference OwnedFrame; - private: - G_NO_COPIES_OF_CLS(PythonState); - // We own this if we're suspended (although currently we don't - // tp_traverse into it; that's a TODO). If we're running, it's - // empty. If we get deallocated and *still* have a frame, it - // won't be reachable from the place that normally decref's - // it, so we need to do it (hence owning it). - OwnedFrame _top_frame; -#if GREENLET_USE_CFRAME - _PyCFrame* cframe; - int use_tracing; -#endif -#if GREENLET_PY314 - int py_recursion_depth; - // I think this is only used by the JIT. At least, - // we only got errors not switching it when the JIT was enabled. - // Python/generated_cases.c.h:12469: _PyEval_EvalFrameDefault: - // Assertion `tstate->current_executor == NULL' failed. - // see https://github.com/python-greenlet/greenlet/issues/460 - PyObject* current_executor; -#elif GREENLET_PY312 - int py_recursion_depth; - int c_recursion_depth; -#else - int recursion_depth; -#endif -#if GREENLET_PY313 - PyObject *delete_later; -#else - int trash_delete_nesting; -#endif -#if GREENLET_PY311 - _PyInterpreterFrame* current_frame; - _PyStackChunk* datastack_chunk; - PyObject** datastack_top; - PyObject** datastack_limit; -#endif - // The PyInterpreterFrame list on 3.12+ contains some entries that are - // on the C stack, which can't be directly accessed while a greenlet is - // suspended. In order to keep greenlet gr_frame introspection working, - // we adjust stack switching to rewrite the interpreter frame list - // to skip these C-stack frames; we call this "exposing" the greenlet's - // frames because it makes them valid to work with in Python. Then when - // the greenlet is resumed we need to remember to reverse the operation - // we did. The C-stack frames are "entry frames" which are a low-level - // interpreter detail; they're not needed for introspection, but do - // need to be present for the eval loop to work. - void unexpose_frames(); - - public: - - PythonState(); - // You can use this for testing whether we have a frame - // or not. It returns const so they can't modify it. - const OwnedFrame& top_frame() const noexcept; - - inline void operator<<(const PyThreadState *const tstate) noexcept; - inline void operator>>(PyThreadState* tstate) noexcept; - void clear() noexcept; - - int tp_traverse(visitproc visit, void* arg, bool visit_top_frame) noexcept; - void tp_clear(bool own_top_frame) noexcept; - void set_initial_state(const PyThreadState* const tstate) noexcept; -#if GREENLET_USE_CFRAME - void set_new_cframe(_PyCFrame& frame) noexcept; -#endif - - void may_switch_away() noexcept; - inline void will_switch_from(PyThreadState *const origin_tstate) noexcept; - void did_finish(PyThreadState* tstate) noexcept; - }; - - class StackState - { - // By having only plain C (POD) members, no virtual functions - // or bases, we get a trivial assignment operator generated - // for us. However, that's not safe since we do manage memory. - // So we declare an assignment operator that only works if we - // don't have any memory allocated. (We don't use - // std::shared_ptr for reference counting just to keep this - // object small) - private: - char* _stack_start; - char* stack_stop; - char* stack_copy; - intptr_t _stack_saved; - StackState* stack_prev; - inline int copy_stack_to_heap_up_to(const char* const stop) noexcept; - inline void free_stack_copy() noexcept; - - public: - /** - * Creates a started, but inactive, state, using *current* - * as the previous. - */ - StackState(void* mark, StackState& current); - /** - * Creates an inactive, unstarted, state. - */ - StackState(); - ~StackState(); - StackState(const StackState& other); - StackState& operator=(const StackState& other); - inline void copy_heap_to_stack(const StackState& current) noexcept; - inline int copy_stack_to_heap(char* const stackref, const StackState& current) noexcept; - inline bool started() const noexcept; - inline bool main() const noexcept; - inline bool active() const noexcept; - inline void set_active() noexcept; - inline void set_inactive() noexcept; - inline intptr_t stack_saved() const noexcept; - inline char* stack_start() const noexcept; - static inline StackState make_main() noexcept; -#ifdef GREENLET_USE_STDIO - friend std::ostream& operator<<(std::ostream& os, const StackState& s); -#endif - - // Fill in [dest, dest + n) with the values that would be at - // [src, src + n) while this greenlet is running. This is like memcpy - // except that if the greenlet is suspended it accounts for the portion - // of the greenlet's stack that was spilled to the heap. `src` may - // be on this greenlet's stack, or on the heap, but not on a different - // greenlet's stack. - void copy_from_stack(void* dest, const void* src, size_t n) const; - }; -#ifdef GREENLET_USE_STDIO - std::ostream& operator<<(std::ostream& os, const StackState& s); -#endif - - class SwitchingArgs - { - private: - G_NO_ASSIGNMENT_OF_CLS(SwitchingArgs); - // If args and kwargs are both false (NULL), this is a *throw*, not a - // switch. PyErr_... must have been called already. - OwnedObject _args; - OwnedObject _kwargs; - public: - - SwitchingArgs() - {} - - SwitchingArgs(const OwnedObject& args, const OwnedObject& kwargs) - : _args(args), - _kwargs(kwargs) - {} - - SwitchingArgs(const SwitchingArgs& other) - : _args(other._args), - _kwargs(other._kwargs) - {} - - const OwnedObject& args() - { - return this->_args; - } - - const OwnedObject& kwargs() - { - return this->_kwargs; - } - - /** - * Moves ownership from the argument to this object. - */ - SwitchingArgs& operator<<=(SwitchingArgs& other) - { - if (this != &other) { - this->_args = other._args; - this->_kwargs = other._kwargs; - other.CLEAR(); - } - return *this; - } - - /** - * Acquires ownership of the argument (consumes the reference). - */ - SwitchingArgs& operator<<=(PyObject* args) - { - this->_args = OwnedObject::consuming(args); - this->_kwargs.CLEAR(); - return *this; - } - - /** - * Acquires ownership of the argument. - * - * Sets the args to be the given value; clears the kwargs. - */ - SwitchingArgs& operator<<=(OwnedObject& args) - { - assert(&args != &this->_args); - this->_args = args; - this->_kwargs.CLEAR(); - args.CLEAR(); - - return *this; - } - - explicit operator bool() const noexcept - { - return this->_args || this->_kwargs; - } - - inline void CLEAR() - { - this->_args.CLEAR(); - this->_kwargs.CLEAR(); - } - - const std::string as_str() const noexcept - { - return PyUnicode_AsUTF8( - OwnedObject::consuming( - PyUnicode_FromFormat( - "SwitchingArgs(args=%R, kwargs=%R)", - this->_args.borrow(), - this->_kwargs.borrow() - ) - ).borrow() - ); - } - }; - - class ThreadState; - - class UserGreenlet; - class MainGreenlet; - - class Greenlet - { - private: - G_NO_COPIES_OF_CLS(Greenlet); - PyGreenlet* const _self; - private: - // XXX: Work to remove these. - friend class ThreadState; - friend class UserGreenlet; - friend class MainGreenlet; - protected: - ExceptionState exception_state; - SwitchingArgs switch_args; - StackState stack_state; - PythonState python_state; - Greenlet(PyGreenlet* p, const StackState& initial_state); - public: - // This constructor takes ownership of the PyGreenlet, by - // setting ``p->pimpl = this;``. - Greenlet(PyGreenlet* p); - virtual ~Greenlet(); - - const OwnedObject context() const; - - // You MUST call this _very_ early in the switching process to - // prepare anything that may need prepared. This might perform - // garbage collections or otherwise run arbitrary Python code. - // - // One specific use of it is for Python 3.11+, preventing - // running arbitrary code at unsafe times. See - // PythonState::may_switch_away(). - inline void may_switch_away() - { - this->python_state.may_switch_away(); - } - - inline void context(refs::BorrowedObject new_context); - - inline SwitchingArgs& args() - { - return this->switch_args; - } - - virtual const refs::BorrowedMainGreenlet main_greenlet() const = 0; - - inline intptr_t stack_saved() const noexcept - { - return this->stack_state.stack_saved(); - } - - // This is used by the macro SLP_SAVE_STATE to compute the - // difference in stack sizes. It might be nice to handle the - // computation ourself, but the type of the result - // varies by platform, so doing it in the macro is the - // simplest way. - inline const char* stack_start() const noexcept - { - return this->stack_state.stack_start(); - } - - virtual OwnedObject throw_GreenletExit_during_dealloc(const ThreadState& current_thread_state); - virtual OwnedObject g_switch() = 0; - /** - * Force the greenlet to appear dead. Used when it's not - * possible to throw an exception into a greenlet anymore. - * - * This losses access to the thread state and the main greenlet. - */ - virtual void murder_in_place(); - - /** - * Called when somebody notices we were running in a dead - * thread to allow cleaning up resources (because we can't - * raise GreenletExit into it anymore). - * This is very similar to ``murder_in_place()``, except that - * it DOES NOT lose the main greenlet or thread state. - */ - inline void deactivate_and_free(); - - - // Called when some thread wants to deallocate a greenlet - // object. - // The thread may or may not be the same thread the greenlet - // was running in. - // The thread state will be null if the thread the greenlet - // was running in was known to have exited. - void deallocing_greenlet_in_thread(const ThreadState* current_state); - - // Must be called on 3.12+ before exposing a suspended greenlet's - // frames to user code. This rewrites the linked list of interpreter - // frames to skip the ones that are being stored on the C stack (which - // can't be safely accessed while the greenlet is suspended because - // that stack space might be hosting a different greenlet), and - // sets PythonState::frames_were_exposed so we remember to restore - // the original list before resuming the greenlet. The C-stack frames - // are a low-level interpreter implementation detail; while they're - // important to the bytecode eval loop, they're superfluous for - // introspection purposes. - void expose_frames(); - - - // TODO: Figure out how to make these non-public. - inline void slp_restore_state() noexcept; - inline int slp_save_state(char *const stackref) noexcept; - - inline bool is_currently_running_in_some_thread() const; - virtual bool belongs_to_thread(const ThreadState* state) const; - - inline bool started() const - { - return this->stack_state.started(); - } - inline bool active() const - { - return this->stack_state.active(); - } - inline bool main() const - { - return this->stack_state.main(); - } - virtual refs::BorrowedMainGreenlet find_main_greenlet_in_lineage() const = 0; - - virtual const OwnedGreenlet parent() const = 0; - virtual void parent(const refs::BorrowedObject new_parent) = 0; - - inline const PythonState::OwnedFrame& top_frame() - { - return this->python_state.top_frame(); - } - - virtual const OwnedObject& run() const = 0; - virtual void run(const refs::BorrowedObject nrun) = 0; - - - virtual int tp_traverse(visitproc visit, void* arg); - virtual int tp_clear(); - - - // Return the thread state that the greenlet is running in, or - // null if the greenlet is not running or the thread is known - // to have exited. - virtual ThreadState* thread_state() const noexcept = 0; - - // Return true if the greenlet is known to have been running - // (active) in a thread that has now exited. - virtual bool was_running_in_dead_thread() const noexcept = 0; - - // Return a borrowed greenlet that is the Python object - // this object represents. - inline BorrowedGreenlet self() const noexcept - { - return BorrowedGreenlet(this->_self); - } - - // For testing. If this returns true, we should pretend that - // slp_switch() failed. - virtual bool force_slp_switch_error() const noexcept; - - protected: - inline void release_args(); - - // The functions that must not be inlined are declared virtual. - // We also mark them as protected, not private, so that the - // compiler is forced to call them through a function pointer. - // (A sufficiently smart compiler could directly call a private - // virtual function since it can never be overridden in a - // subclass). - - // Also TODO: Switch away from integer error codes and to enums, - // or throw exceptions when possible. - struct switchstack_result_t - { - int status; - Greenlet* the_new_current_greenlet; - OwnedGreenlet origin_greenlet; - - switchstack_result_t() - : status(0), - the_new_current_greenlet(nullptr) - {} - - switchstack_result_t(int err) - : status(err), - the_new_current_greenlet(nullptr) - {} - - switchstack_result_t(int err, Greenlet* state, OwnedGreenlet& origin) - : status(err), - the_new_current_greenlet(state), - origin_greenlet(origin) - { - } - - switchstack_result_t(int err, Greenlet* state, const BorrowedGreenlet& origin) - : status(err), - the_new_current_greenlet(state), - origin_greenlet(origin) - { - } - - switchstack_result_t(const switchstack_result_t& other) - : status(other.status), - the_new_current_greenlet(other.the_new_current_greenlet), - origin_greenlet(other.origin_greenlet) - {} - - switchstack_result_t& operator=(const switchstack_result_t& other) - { - this->status = other.status; - this->the_new_current_greenlet = other.the_new_current_greenlet; - this->origin_greenlet = other.origin_greenlet; - return *this; - } - }; - - OwnedObject on_switchstack_or_initialstub_failure( - Greenlet* target, - const switchstack_result_t& err, - const bool target_was_me=false, - const bool was_initial_stub=false); - - // Returns the previous greenlet we just switched away from. - virtual OwnedGreenlet g_switchstack_success() noexcept; - - - // Check the preconditions for switching to this greenlet; if they - // aren't met, throws PyErrOccurred. Most callers will want to - // catch this and clear the arguments - inline void check_switch_allowed() const; - class GreenletStartedWhileInPython : public std::runtime_error - { - public: - GreenletStartedWhileInPython() : std::runtime_error("") - {} - }; - - protected: - - - /** - Perform a stack switch into this greenlet. - - This temporarily sets the global variable - ``switching_thread_state`` to this greenlet; as soon as the - call to ``slp_switch`` completes, this is reset to NULL. - Consequently, this depends on the GIL. - - TODO: Adopt the stackman model and pass ``slp_switch`` a - callback function and context pointer; this eliminates the - need for global variables altogether. - - Because the stack switch happens in this function, this - function can't use its own stack (local) variables, set - before the switch, and then accessed after the switch. - - Further, you con't even access ``g_thread_state_global`` - before and after the switch from the global variable. - Because it is thread local some compilers cache it in a - register/on the stack, notably new versions of MSVC; this - breaks with strange crashes sometime later, because writing - to anything in ``g_thread_state_global`` after the switch - is actually writing to random memory. For this reason, we - call a non-inlined function to finish the operation. (XXX: - The ``/GT`` MSVC compiler argument probably fixes that.) - - It is very important that stack switch is 'atomic', i.e. no - calls into other Python code allowed (except very few that - are safe), because global variables are very fragile. (This - should no longer be the case with thread-local variables.) - - */ - // Made virtual to facilitate subclassing UserGreenlet for testing. - virtual switchstack_result_t g_switchstack(void); - -class TracingGuard -{ -private: - PyThreadState* tstate; -public: - TracingGuard() - : tstate(PyThreadState_GET()) - { - PyThreadState_EnterTracing(this->tstate); - } - - ~TracingGuard() - { - PyThreadState_LeaveTracing(this->tstate); - this->tstate = nullptr; - } - - inline void CallTraceFunction(const OwnedObject& tracefunc, - const greenlet::refs::ImmortalEventName& event, - const BorrowedGreenlet& origin, - const BorrowedGreenlet& target) - { - // TODO: This calls tracefunc(event, (origin, target)). Add a shortcut - // function for that that's specialized to avoid the Py_BuildValue - // string parsing, or start with just using "ON" format with PyTuple_Pack(2, - // origin, target). That seems like what the N format is meant - // for. - // XXX: Why does event not automatically cast back to a PyObject? - // It tries to call the "deleted constructor ImmortalEventName - // const" instead. - assert(tracefunc); - assert(event); - assert(origin); - assert(target); - greenlet::refs::NewReference retval( - PyObject_CallFunction( - tracefunc.borrow(), - "O(OO)", - event.borrow(), - origin.borrow(), - target.borrow() - )); - if (!retval) { - throw PyErrOccurred::from_current(); - } - } -}; - - static void - g_calltrace(const OwnedObject& tracefunc, - const greenlet::refs::ImmortalEventName& event, - const greenlet::refs::BorrowedGreenlet& origin, - const BorrowedGreenlet& target); - private: - OwnedObject g_switch_finish(const switchstack_result_t& err); - - }; - - class UserGreenlet : public Greenlet - { - private: - static greenlet::PythonAllocator allocator; - OwnedMainGreenlet _main_greenlet; - OwnedObject _run_callable; - OwnedGreenlet _parent; - public: - static void* operator new(size_t UNUSED(count)); - static void operator delete(void* ptr); - - UserGreenlet(PyGreenlet* p, BorrowedGreenlet the_parent); - virtual ~UserGreenlet(); - - virtual refs::BorrowedMainGreenlet find_main_greenlet_in_lineage() const; - virtual bool was_running_in_dead_thread() const noexcept; - virtual ThreadState* thread_state() const noexcept; - virtual OwnedObject g_switch(); - virtual const OwnedObject& run() const - { - if (this->started() || !this->_run_callable) { - throw AttributeError("run"); - } - return this->_run_callable; - } - virtual void run(const refs::BorrowedObject nrun); - - virtual const OwnedGreenlet parent() const; - virtual void parent(const refs::BorrowedObject new_parent); - - virtual const refs::BorrowedMainGreenlet main_greenlet() const; - - virtual void murder_in_place(); - virtual bool belongs_to_thread(const ThreadState* state) const; - virtual int tp_traverse(visitproc visit, void* arg); - virtual int tp_clear(); - class ParentIsCurrentGuard - { - private: - OwnedGreenlet oldparent; - UserGreenlet* greenlet; - G_NO_COPIES_OF_CLS(ParentIsCurrentGuard); - public: - ParentIsCurrentGuard(UserGreenlet* p, const ThreadState& thread_state); - ~ParentIsCurrentGuard(); - }; - virtual OwnedObject throw_GreenletExit_during_dealloc(const ThreadState& current_thread_state); - protected: - virtual switchstack_result_t g_initialstub(void* mark); - private: - // This function isn't meant to return. - // This accepts raw pointers and the ownership of them at the - // same time. The caller should use ``inner_bootstrap(origin.relinquish_ownership())``. - void inner_bootstrap(PyGreenlet* origin_greenlet, PyObject* run); - }; - - class BrokenGreenlet : public UserGreenlet - { - private: - static greenlet::PythonAllocator allocator; - public: - bool _force_switch_error = false; - bool _force_slp_switch_error = false; - - static void* operator new(size_t UNUSED(count)); - static void operator delete(void* ptr); - BrokenGreenlet(PyGreenlet* p, BorrowedGreenlet the_parent) - : UserGreenlet(p, the_parent) - {} - virtual ~BrokenGreenlet() - {} - - virtual switchstack_result_t g_switchstack(void); - virtual bool force_slp_switch_error() const noexcept; - - }; - - class MainGreenlet : public Greenlet - { - private: - static greenlet::PythonAllocator allocator; - refs::BorrowedMainGreenlet _self; - ThreadState* _thread_state; - G_NO_COPIES_OF_CLS(MainGreenlet); - public: - static void* operator new(size_t UNUSED(count)); - static void operator delete(void* ptr); - - MainGreenlet(refs::BorrowedMainGreenlet::PyType*, ThreadState*); - virtual ~MainGreenlet(); - - - virtual const OwnedObject& run() const; - virtual void run(const refs::BorrowedObject nrun); - - virtual const OwnedGreenlet parent() const; - virtual void parent(const refs::BorrowedObject new_parent); - - virtual const refs::BorrowedMainGreenlet main_greenlet() const; - - virtual refs::BorrowedMainGreenlet find_main_greenlet_in_lineage() const; - virtual bool was_running_in_dead_thread() const noexcept; - virtual ThreadState* thread_state() const noexcept; - void thread_state(ThreadState*) noexcept; - virtual OwnedObject g_switch(); - virtual int tp_traverse(visitproc visit, void* arg); - }; - - // Instantiate one on the stack to save the GC state, - // and then disable GC. When it goes out of scope, GC will be - // restored to its original state. Sadly, these APIs are only - // available on 3.10+; luckily, we only need them on 3.11+. -#if GREENLET_PY310 - class GCDisabledGuard - { - private: - int was_enabled = 0; - public: - GCDisabledGuard() - : was_enabled(PyGC_IsEnabled()) - { - PyGC_Disable(); - } - - ~GCDisabledGuard() - { - if (this->was_enabled) { - PyGC_Enable(); - } - } - }; -#endif - - OwnedObject& operator<<=(OwnedObject& lhs, greenlet::SwitchingArgs& rhs) noexcept; - - //TODO: Greenlet::g_switch() should call this automatically on its - //return value. As it is, the module code is calling it. - static inline OwnedObject - single_result(const OwnedObject& results) - { - if (results - && PyTuple_Check(results.borrow()) - && PyTuple_GET_SIZE(results.borrow()) == 1) { - PyObject* result = PyTuple_GET_ITEM(results.borrow(), 0); - assert(result); - return OwnedObject::owning(result); - } - return results; - } - - - static OwnedObject - g_handle_exit(const OwnedObject& greenlet_result); - - - template - void operator<<(const PyThreadState *const lhs, T& rhs) - { - rhs.operator<<(lhs); - } - -} // namespace greenlet ; - -#endif diff --git a/venv/lib/python3.9/site-packages/greenlet/TGreenletGlobals.cpp b/venv/lib/python3.9/site-packages/greenlet/TGreenletGlobals.cpp deleted file mode 100644 index 0087d2f..0000000 --- a/venv/lib/python3.9/site-packages/greenlet/TGreenletGlobals.cpp +++ /dev/null @@ -1,94 +0,0 @@ -/* -*- indent-tabs-mode: nil; tab-width: 4; -*- */ -/** - * Implementation of GreenletGlobals. - * - * Format with: - * clang-format -i --style=file src/greenlet/greenlet.c - * - * - * Fix missing braces with: - * clang-tidy src/greenlet/greenlet.c -fix -checks="readability-braces-around-statements" -*/ -#ifndef T_GREENLET_GLOBALS -#define T_GREENLET_GLOBALS - -#include "greenlet_refs.hpp" -#include "greenlet_exceptions.hpp" -#include "greenlet_thread_support.hpp" -#include "greenlet_internal.hpp" - -namespace greenlet { - -// This encapsulates what were previously module global "constants" -// established at init time. -// This is a step towards Python3 style module state that allows -// reloading. -// -// In an earlier iteration of this code, we used placement new to be -// able to allocate this object statically still, so that references -// to its members don't incur an extra pointer indirection. -// But under some scenarios, that could result in crashes at -// shutdown because apparently the destructor was getting run twice? -class GreenletGlobals -{ - -public: - const greenlet::refs::ImmortalEventName event_switch; - const greenlet::refs::ImmortalEventName event_throw; - const greenlet::refs::ImmortalException PyExc_GreenletError; - const greenlet::refs::ImmortalException PyExc_GreenletExit; - const greenlet::refs::ImmortalObject empty_tuple; - const greenlet::refs::ImmortalObject empty_dict; - const greenlet::refs::ImmortalString str_run; - Mutex* const thread_states_to_destroy_lock; - greenlet::cleanup_queue_t thread_states_to_destroy; - - GreenletGlobals() : - event_switch("switch"), - event_throw("throw"), - PyExc_GreenletError("greenlet.error"), - PyExc_GreenletExit("greenlet.GreenletExit", PyExc_BaseException), - empty_tuple(Require(PyTuple_New(0))), - empty_dict(Require(PyDict_New())), - str_run("run"), - thread_states_to_destroy_lock(new Mutex()) - {} - - ~GreenletGlobals() - { - // This object is (currently) effectively immortal, and not - // just because of those placement new tricks; if we try to - // deallocate the static object we allocated, and overwrote, - // we would be doing so at C++ teardown time, which is after - // the final Python GIL is released, and we can't use the API - // then. - // (The members will still be destructed, but they also don't - // do any deallocation.) - } - - void queue_to_destroy(ThreadState* ts) const - { - // we're currently accessed through a static const object, - // implicitly marking our members as const, so code can't just - // call push_back (or pop_back) without casting away the - // const. - // - // Do that for callers. - greenlet::cleanup_queue_t& q = const_cast(this->thread_states_to_destroy); - q.push_back(ts); - } - - ThreadState* take_next_to_destroy() const - { - greenlet::cleanup_queue_t& q = const_cast(this->thread_states_to_destroy); - ThreadState* result = q.back(); - q.pop_back(); - return result; - } -}; - -}; // namespace greenlet - -static const greenlet::GreenletGlobals* mod_globs; - -#endif // T_GREENLET_GLOBALS diff --git a/venv/lib/python3.9/site-packages/greenlet/TMainGreenlet.cpp b/venv/lib/python3.9/site-packages/greenlet/TMainGreenlet.cpp deleted file mode 100644 index a2a9cfe..0000000 --- a/venv/lib/python3.9/site-packages/greenlet/TMainGreenlet.cpp +++ /dev/null @@ -1,153 +0,0 @@ -/* -*- indent-tabs-mode: nil; tab-width: 4; -*- */ -/** - * Implementation of greenlet::MainGreenlet. - * - * Format with: - * clang-format -i --style=file src/greenlet/greenlet.c - * - * - * Fix missing braces with: - * clang-tidy src/greenlet/greenlet.c -fix -checks="readability-braces-around-statements" -*/ -#ifndef T_MAIN_GREENLET_CPP -#define T_MAIN_GREENLET_CPP - -#include "TGreenlet.hpp" - - - -// Protected by the GIL. Incremented when we create a main greenlet, -// in a new thread, decremented when it is destroyed. -static Py_ssize_t G_TOTAL_MAIN_GREENLETS; - -namespace greenlet { -greenlet::PythonAllocator MainGreenlet::allocator; - -void* MainGreenlet::operator new(size_t UNUSED(count)) -{ - return allocator.allocate(1); -} - - -void MainGreenlet::operator delete(void* ptr) -{ - return allocator.deallocate(static_cast(ptr), - 1); -} - - -MainGreenlet::MainGreenlet(PyGreenlet* p, ThreadState* state) - : Greenlet(p, StackState::make_main()), - _self(p), - _thread_state(state) -{ - G_TOTAL_MAIN_GREENLETS++; -} - -MainGreenlet::~MainGreenlet() -{ - G_TOTAL_MAIN_GREENLETS--; - this->tp_clear(); -} - -ThreadState* -MainGreenlet::thread_state() const noexcept -{ - return this->_thread_state; -} - -void -MainGreenlet::thread_state(ThreadState* t) noexcept -{ - assert(!t); - this->_thread_state = t; -} - - -const BorrowedMainGreenlet -MainGreenlet::main_greenlet() const -{ - return this->_self; -} - -BorrowedMainGreenlet -MainGreenlet::find_main_greenlet_in_lineage() const -{ - return BorrowedMainGreenlet(this->_self); -} - -bool -MainGreenlet::was_running_in_dead_thread() const noexcept -{ - return !this->_thread_state; -} - -OwnedObject -MainGreenlet::g_switch() -{ - try { - this->check_switch_allowed(); - } - catch (const PyErrOccurred&) { - this->release_args(); - throw; - } - - switchstack_result_t err = this->g_switchstack(); - if (err.status < 0) { - // XXX: This code path is untested, but it is shared - // with the UserGreenlet path that is tested. - return this->on_switchstack_or_initialstub_failure( - this, - err, - true, // target was me - false // was initial stub - ); - } - - return err.the_new_current_greenlet->g_switch_finish(err); -} - -int -MainGreenlet::tp_traverse(visitproc visit, void* arg) -{ - if (this->_thread_state) { - // we've already traversed main, (self), don't do it again. - int result = this->_thread_state->tp_traverse(visit, arg, false); - if (result) { - return result; - } - } - return Greenlet::tp_traverse(visit, arg); -} - -const OwnedObject& -MainGreenlet::run() const -{ - throw AttributeError("Main greenlets do not have a run attribute."); -} - -void -MainGreenlet::run(const BorrowedObject UNUSED(nrun)) -{ - throw AttributeError("Main greenlets do not have a run attribute."); -} - -void -MainGreenlet::parent(const BorrowedObject raw_new_parent) -{ - if (!raw_new_parent) { - throw AttributeError("can't delete attribute"); - } - throw AttributeError("cannot set the parent of a main greenlet"); -} - -const OwnedGreenlet -MainGreenlet::parent() const -{ - return OwnedGreenlet(); // null becomes None -} - -}; // namespace greenlet - -#endif diff --git a/venv/lib/python3.9/site-packages/greenlet/TPythonState.cpp b/venv/lib/python3.9/site-packages/greenlet/TPythonState.cpp deleted file mode 100644 index 8833a80..0000000 --- a/venv/lib/python3.9/site-packages/greenlet/TPythonState.cpp +++ /dev/null @@ -1,406 +0,0 @@ -#ifndef GREENLET_PYTHON_STATE_CPP -#define GREENLET_PYTHON_STATE_CPP - -#include -#include "TGreenlet.hpp" - -namespace greenlet { - -PythonState::PythonState() - : _top_frame() -#if GREENLET_USE_CFRAME - ,cframe(nullptr) - ,use_tracing(0) -#endif -#if GREENLET_PY314 - ,py_recursion_depth(0) - ,current_executor(nullptr) -#elif GREENLET_PY312 - ,py_recursion_depth(0) - ,c_recursion_depth(0) -#else - ,recursion_depth(0) -#endif -#if GREENLET_PY313 - ,delete_later(nullptr) -#else - ,trash_delete_nesting(0) -#endif -#if GREENLET_PY311 - ,current_frame(nullptr) - ,datastack_chunk(nullptr) - ,datastack_top(nullptr) - ,datastack_limit(nullptr) -#endif -{ -#if GREENLET_USE_CFRAME - /* - The PyThreadState->cframe pointer usually points to memory on - the stack, alloceted in a call into PyEval_EvalFrameDefault. - - Initially, before any evaluation begins, it points to the - initial PyThreadState object's ``root_cframe`` object, which is - statically allocated for the lifetime of the thread. - - A greenlet can last for longer than a call to - PyEval_EvalFrameDefault, so we can't set its ``cframe`` pointer - to be the current ``PyThreadState->cframe``; nor could we use - one from the greenlet parent for the same reason. Yet a further - no: we can't allocate one scoped to the greenlet and then - destroy it when the greenlet is deallocated, because inside the - interpreter the _PyCFrame objects form a linked list, and that too - can result in accessing memory beyond its dynamic lifetime (if - the greenlet doesn't actually finish before it dies, its entry - could still be in the list). - - Using the ``root_cframe`` is problematic, though, because its - members are never modified by the interpreter and are set to 0, - meaning that its ``use_tracing`` flag is never updated. We don't - want to modify that value in the ``root_cframe`` ourself: it - *shouldn't* matter much because we should probably never get - back to the point where that's the only cframe on the stack; - even if it did matter, the major consequence of an incorrect - value for ``use_tracing`` is that if its true the interpreter - does some extra work --- however, it's just good code hygiene. - - Our solution: before a greenlet runs, after its initial - creation, it uses the ``root_cframe`` just to have something to - put there. However, once the greenlet is actually switched to - for the first time, ``g_initialstub`` (which doesn't actually - "return" while the greenlet is running) stores a new _PyCFrame on - its local stack, and copies the appropriate values from the - currently running _PyCFrame; this is then made the _PyCFrame for the - newly-minted greenlet. ``g_initialstub`` then proceeds to call - ``glet.run()``, which results in ``PyEval_...`` adding the - _PyCFrame to the list. Switches continue as normal. Finally, when - the greenlet finishes, the call to ``glet.run()`` returns and - the _PyCFrame is taken out of the linked list and the stack value - is now unused and free to expire. - - XXX: I think we can do better. If we're deallocing in the same - thread, can't we traverse the list and unlink our frame? - Can we just keep a reference to the thread state in case we - dealloc in another thread? (Is that even possible if we're still - running and haven't returned from g_initialstub?) - */ - this->cframe = &PyThreadState_GET()->root_cframe; -#endif -} - - -inline void PythonState::may_switch_away() noexcept -{ -#if GREENLET_PY311 - // PyThreadState_GetFrame is probably going to have to allocate a - // new frame object. That may trigger garbage collection. Because - // we call this during the early phases of a switch (it doesn't - // matter to which greenlet, as this has a global effect), if a GC - // triggers a switch away, two things can happen, both bad: - // - We might not get switched back to, halting forward progress. - // this is pathological, but possible. - // - We might get switched back to with a different set of - // arguments or a throw instead of a switch. That would corrupt - // our state (specifically, PyErr_Occurred() and this->args() - // would no longer agree). - // - // Thus, when we call this API, we need to have GC disabled. - // This method serves as a bottleneck we call when maybe beginning - // a switch. In this way, it is always safe -- no risk of GC -- to - // use ``_GetFrame()`` whenever we need to, just as it was in - // <=3.10 (because subsequent calls will be cached and not - // allocate memory). - - GCDisabledGuard no_gc; - Py_XDECREF(PyThreadState_GetFrame(PyThreadState_GET())); -#endif -} - -void PythonState::operator<<(const PyThreadState *const tstate) noexcept -{ - this->_context.steal(tstate->context); -#if GREENLET_USE_CFRAME - /* - IMPORTANT: ``cframe`` is a pointer into the STACK. Thus, because - the call to ``slp_switch()`` changes the contents of the stack, - you cannot read from ``ts_current->cframe`` after that call and - necessarily get the same values you get from reading it here. - Anything you need to restore from now to then must be saved in a - global/threadlocal variable (because we can't use stack - variables here either). For things that need to persist across - the switch, use `will_switch_from`. - */ - this->cframe = tstate->cframe; - #if !GREENLET_PY312 - this->use_tracing = tstate->cframe->use_tracing; - #endif -#endif // GREENLET_USE_CFRAME -#if GREENLET_PY311 - #if GREENLET_PY314 - this->py_recursion_depth = tstate->py_recursion_limit - tstate->py_recursion_remaining; - this->current_executor = tstate->current_executor; - #elif GREENLET_PY312 - this->py_recursion_depth = tstate->py_recursion_limit - tstate->py_recursion_remaining; - this->c_recursion_depth = Py_C_RECURSION_LIMIT - tstate->c_recursion_remaining; - #else // not 312 - this->recursion_depth = tstate->recursion_limit - tstate->recursion_remaining; - #endif // GREENLET_PY312 - #if GREENLET_PY313 - this->current_frame = tstate->current_frame; - #elif GREENLET_USE_CFRAME - this->current_frame = tstate->cframe->current_frame; - #endif - this->datastack_chunk = tstate->datastack_chunk; - this->datastack_top = tstate->datastack_top; - this->datastack_limit = tstate->datastack_limit; - - PyFrameObject *frame = PyThreadState_GetFrame((PyThreadState *)tstate); - Py_XDECREF(frame); // PyThreadState_GetFrame gives us a new - // reference. - this->_top_frame.steal(frame); - #if GREENLET_PY313 - this->delete_later = Py_XNewRef(tstate->delete_later); - #elif GREENLET_PY312 - this->trash_delete_nesting = tstate->trash.delete_nesting; - #else // not 312 - this->trash_delete_nesting = tstate->trash_delete_nesting; - #endif // GREENLET_PY312 -#else // Not 311 - this->recursion_depth = tstate->recursion_depth; - this->_top_frame.steal(tstate->frame); - this->trash_delete_nesting = tstate->trash_delete_nesting; -#endif // GREENLET_PY311 -} - -#if GREENLET_PY312 -void GREENLET_NOINLINE(PythonState::unexpose_frames)() -{ - if (!this->top_frame()) { - return; - } - - // See GreenletState::expose_frames() and the comment on frames_were_exposed - // for more information about this logic. - _PyInterpreterFrame *iframe = this->_top_frame->f_frame; - while (iframe != nullptr) { - _PyInterpreterFrame *prev_exposed = iframe->previous; - assert(iframe->frame_obj); - memcpy(&iframe->previous, &iframe->frame_obj->_f_frame_data[0], - sizeof(void *)); - iframe = prev_exposed; - } -} -#else -void PythonState::unexpose_frames() -{} -#endif - -void PythonState::operator>>(PyThreadState *const tstate) noexcept -{ - tstate->context = this->_context.relinquish_ownership(); - /* Incrementing this value invalidates the contextvars cache, - which would otherwise remain valid across switches */ - tstate->context_ver++; -#if GREENLET_USE_CFRAME - tstate->cframe = this->cframe; - /* - If we were tracing, we need to keep tracing. - There should never be the possibility of hitting the - root_cframe here. See note above about why we can't - just copy this from ``origin->cframe->use_tracing``. - */ - #if !GREENLET_PY312 - tstate->cframe->use_tracing = this->use_tracing; - #endif -#endif // GREENLET_USE_CFRAME -#if GREENLET_PY311 - #if GREENLET_PY314 - tstate->py_recursion_remaining = tstate->py_recursion_limit - this->py_recursion_depth; - tstate->current_executor = this->current_executor; - this->unexpose_frames(); - #elif GREENLET_PY312 - tstate->py_recursion_remaining = tstate->py_recursion_limit - this->py_recursion_depth; - tstate->c_recursion_remaining = Py_C_RECURSION_LIMIT - this->c_recursion_depth; - this->unexpose_frames(); - #else // \/ 3.11 - tstate->recursion_remaining = tstate->recursion_limit - this->recursion_depth; - #endif // GREENLET_PY312 - #if GREENLET_PY313 - tstate->current_frame = this->current_frame; - #elif GREENLET_USE_CFRAME - tstate->cframe->current_frame = this->current_frame; - #endif - tstate->datastack_chunk = this->datastack_chunk; - tstate->datastack_top = this->datastack_top; - tstate->datastack_limit = this->datastack_limit; - this->_top_frame.relinquish_ownership(); - #if GREENLET_PY313 - Py_XDECREF(tstate->delete_later); - tstate->delete_later = this->delete_later; - Py_CLEAR(this->delete_later); - #elif GREENLET_PY312 - tstate->trash.delete_nesting = this->trash_delete_nesting; - #else // not 3.12 - tstate->trash_delete_nesting = this->trash_delete_nesting; - #endif // GREENLET_PY312 -#else // not 3.11 - tstate->frame = this->_top_frame.relinquish_ownership(); - tstate->recursion_depth = this->recursion_depth; - tstate->trash_delete_nesting = this->trash_delete_nesting; -#endif // GREENLET_PY311 -} - -inline void PythonState::will_switch_from(PyThreadState *const origin_tstate) noexcept -{ -#if GREENLET_USE_CFRAME && !GREENLET_PY312 - // The weird thing is, we don't actually save this for an - // effect on the current greenlet, it's saved for an - // effect on the target greenlet. That is, we want - // continuity of this setting across the greenlet switch. - this->use_tracing = origin_tstate->cframe->use_tracing; -#endif -} - -void PythonState::set_initial_state(const PyThreadState* const tstate) noexcept -{ - this->_top_frame = nullptr; -#if GREENLET_PY314 - this->py_recursion_depth = tstate->py_recursion_limit - tstate->py_recursion_remaining; - this->current_executor = tstate->current_executor; -#elif GREENLET_PY312 - this->py_recursion_depth = tstate->py_recursion_limit - tstate->py_recursion_remaining; - // XXX: TODO: Comment from a reviewer: - // Should this be ``Py_C_RECURSION_LIMIT - tstate->c_recursion_remaining``? - // But to me it looks more like that might not be the right - // initialization either? - this->c_recursion_depth = tstate->py_recursion_limit - tstate->py_recursion_remaining; -#elif GREENLET_PY311 - this->recursion_depth = tstate->recursion_limit - tstate->recursion_remaining; -#else - this->recursion_depth = tstate->recursion_depth; -#endif -} -// TODO: Better state management about when we own the top frame. -int PythonState::tp_traverse(visitproc visit, void* arg, bool own_top_frame) noexcept -{ - Py_VISIT(this->_context.borrow()); - if (own_top_frame) { - Py_VISIT(this->_top_frame.borrow()); - } - return 0; -} - -void PythonState::tp_clear(bool own_top_frame) noexcept -{ - PythonStateContext::tp_clear(); - // If we get here owning a frame, - // we got dealloc'd without being finished. We may or may not be - // in the same thread. - if (own_top_frame) { - this->_top_frame.CLEAR(); - } -} - -#if GREENLET_USE_CFRAME -void PythonState::set_new_cframe(_PyCFrame& frame) noexcept -{ - frame = *PyThreadState_GET()->cframe; - /* Make the target greenlet refer to the stack value. */ - this->cframe = &frame; - /* - And restore the link to the previous frame so this one gets - unliked appropriately. - */ - this->cframe->previous = &PyThreadState_GET()->root_cframe; -} -#endif - -const PythonState::OwnedFrame& PythonState::top_frame() const noexcept -{ - return this->_top_frame; -} - -void PythonState::did_finish(PyThreadState* tstate) noexcept -{ -#if GREENLET_PY311 - // See https://github.com/gevent/gevent/issues/1924 and - // https://github.com/python-greenlet/greenlet/issues/328. In - // short, Python 3.11 allocates memory for frames as a sort of - // linked list that's kept as part of PyThreadState in the - // ``datastack_chunk`` member and friends. These are saved and - // restored as part of switching greenlets. - // - // When we initially switch to a greenlet, we set those to NULL. - // That causes the frame management code to treat this like a - // brand new thread and start a fresh list of chunks, beginning - // with a new "root" chunk. As we make calls in this greenlet, - // those chunks get added, and as calls return, they get popped. - // But the frame code (pystate.c) is careful to make sure that the - // root chunk never gets popped. - // - // Thus, when a greenlet exits for the last time, there will be at - // least a single root chunk that we must be responsible for - // deallocating. - // - // The complex part is that these chunks are allocated and freed - // using ``_PyObject_VirtualAlloc``/``Free``. Those aren't public - // functions, and they aren't exported for linking. It so happens - // that we know they are just thin wrappers around the Arena - // allocator, so we can use that directly to deallocate in a - // compatible way. - // - // CAUTION: Check this implementation detail on every major version. - // - // It might be nice to be able to do this in our destructor, but - // can we be sure that no one else is using that memory? Plus, as - // described below, our pointers may not even be valid anymore. As - // a special case, there is one time that we know we can do this, - // and that's from the destructor of the associated UserGreenlet - // (NOT main greenlet) - PyObjectArenaAllocator alloc; - _PyStackChunk* chunk = nullptr; - if (tstate) { - // We really did finish, we can never be switched to again. - chunk = tstate->datastack_chunk; - // Unfortunately, we can't do much sanity checking. Our - // this->datastack_chunk pointer is out of date (evaluation may - // have popped down through it already) so we can't verify that - // we deallocate it. I don't think we can even check datastack_top - // for the same reason. - - PyObject_GetArenaAllocator(&alloc); - tstate->datastack_chunk = nullptr; - tstate->datastack_limit = nullptr; - tstate->datastack_top = nullptr; - - } - else if (this->datastack_chunk) { - // The UserGreenlet (NOT the main greenlet!) is being deallocated. If we're - // still holding a stack chunk, it's garbage because we know - // we can never switch back to let cPython clean it up. - // Because the last time we got switched away from, and we - // haven't run since then, we know our chain is valid and can - // be dealloced. - chunk = this->datastack_chunk; - PyObject_GetArenaAllocator(&alloc); - } - - if (alloc.free && chunk) { - // In case the arena mechanism has been torn down already. - while (chunk) { - _PyStackChunk *prev = chunk->previous; - chunk->previous = nullptr; - alloc.free(alloc.ctx, chunk, chunk->size); - chunk = prev; - } - } - - this->datastack_chunk = nullptr; - this->datastack_limit = nullptr; - this->datastack_top = nullptr; -#endif -} - - -}; // namespace greenlet - -#endif // GREENLET_PYTHON_STATE_CPP diff --git a/venv/lib/python3.9/site-packages/greenlet/TStackState.cpp b/venv/lib/python3.9/site-packages/greenlet/TStackState.cpp deleted file mode 100644 index 9743ab5..0000000 --- a/venv/lib/python3.9/site-packages/greenlet/TStackState.cpp +++ /dev/null @@ -1,265 +0,0 @@ -#ifndef GREENLET_STACK_STATE_CPP -#define GREENLET_STACK_STATE_CPP - -#include "TGreenlet.hpp" - -namespace greenlet { - -#ifdef GREENLET_USE_STDIO -#include -using std::cerr; -using std::endl; - -std::ostream& operator<<(std::ostream& os, const StackState& s) -{ - os << "StackState(stack_start=" << (void*)s._stack_start - << ", stack_stop=" << (void*)s.stack_stop - << ", stack_copy=" << (void*)s.stack_copy - << ", stack_saved=" << s._stack_saved - << ", stack_prev=" << s.stack_prev - << ", addr=" << &s - << ")"; - return os; -} -#endif - -StackState::StackState(void* mark, StackState& current) - : _stack_start(nullptr), - stack_stop((char*)mark), - stack_copy(nullptr), - _stack_saved(0), - /* Skip a dying greenlet */ - stack_prev(current._stack_start - ? ¤t - : current.stack_prev) -{ -} - -StackState::StackState() - : _stack_start(nullptr), - stack_stop(nullptr), - stack_copy(nullptr), - _stack_saved(0), - stack_prev(nullptr) -{ -} - -StackState::StackState(const StackState& other) -// can't use a delegating constructor because of -// MSVC for Python 2.7 - : _stack_start(nullptr), - stack_stop(nullptr), - stack_copy(nullptr), - _stack_saved(0), - stack_prev(nullptr) -{ - this->operator=(other); -} - -StackState& StackState::operator=(const StackState& other) -{ - if (&other == this) { - return *this; - } - if (other._stack_saved) { - throw std::runtime_error("Refusing to steal memory."); - } - - //If we have memory allocated, dispose of it - this->free_stack_copy(); - - this->_stack_start = other._stack_start; - this->stack_stop = other.stack_stop; - this->stack_copy = other.stack_copy; - this->_stack_saved = other._stack_saved; - this->stack_prev = other.stack_prev; - return *this; -} - -inline void StackState::free_stack_copy() noexcept -{ - PyMem_Free(this->stack_copy); - this->stack_copy = nullptr; - this->_stack_saved = 0; -} - -inline void StackState::copy_heap_to_stack(const StackState& current) noexcept -{ - - /* Restore the heap copy back into the C stack */ - if (this->_stack_saved != 0) { - memcpy(this->_stack_start, this->stack_copy, this->_stack_saved); - this->free_stack_copy(); - } - StackState* owner = const_cast(¤t); - if (!owner->_stack_start) { - owner = owner->stack_prev; /* greenlet is dying, skip it */ - } - while (owner && owner->stack_stop <= this->stack_stop) { - // cerr << "\tOwner: " << owner << endl; - owner = owner->stack_prev; /* find greenlet with more stack */ - } - this->stack_prev = owner; - // cerr << "\tFinished with: " << *this << endl; -} - -inline int StackState::copy_stack_to_heap_up_to(const char* const stop) noexcept -{ - /* Save more of g's stack into the heap -- at least up to 'stop' - g->stack_stop |________| - | | - | __ stop . . . . . - | | ==> . . - |________| _______ - | | | | - | | | | - g->stack_start | | |_______| g->stack_copy - */ - intptr_t sz1 = this->_stack_saved; - intptr_t sz2 = stop - this->_stack_start; - assert(this->_stack_start); - if (sz2 > sz1) { - char* c = (char*)PyMem_Realloc(this->stack_copy, sz2); - if (!c) { - PyErr_NoMemory(); - return -1; - } - memcpy(c + sz1, this->_stack_start + sz1, sz2 - sz1); - this->stack_copy = c; - this->_stack_saved = sz2; - } - return 0; -} - -inline int StackState::copy_stack_to_heap(char* const stackref, - const StackState& current) noexcept -{ - /* must free all the C stack up to target_stop */ - const char* const target_stop = this->stack_stop; - - StackState* owner = const_cast(¤t); - assert(owner->_stack_saved == 0); // everything is present on the stack - if (!owner->_stack_start) { - owner = owner->stack_prev; /* not saved if dying */ - } - else { - owner->_stack_start = stackref; - } - - while (owner->stack_stop < target_stop) { - /* ts_current is entierely within the area to free */ - if (owner->copy_stack_to_heap_up_to(owner->stack_stop)) { - return -1; /* XXX */ - } - owner = owner->stack_prev; - } - if (owner != this) { - if (owner->copy_stack_to_heap_up_to(target_stop)) { - return -1; /* XXX */ - } - } - return 0; -} - -inline bool StackState::started() const noexcept -{ - return this->stack_stop != nullptr; -} - -inline bool StackState::main() const noexcept -{ - return this->stack_stop == (char*)-1; -} - -inline bool StackState::active() const noexcept -{ - return this->_stack_start != nullptr; -} - -inline void StackState::set_active() noexcept -{ - assert(this->_stack_start == nullptr); - this->_stack_start = (char*)1; -} - -inline void StackState::set_inactive() noexcept -{ - this->_stack_start = nullptr; - // XXX: What if we still have memory out there? - // That case is actually triggered by - // test_issue251_issue252_explicit_reference_not_collectable (greenlet.tests.test_leaks.TestLeaks) - // and - // test_issue251_issue252_need_to_collect_in_background - // (greenlet.tests.test_leaks.TestLeaks) - // - // Those objects never get deallocated, so the destructor never - // runs. - // It *seems* safe to clean up the memory here? - if (this->_stack_saved) { - this->free_stack_copy(); - } -} - -inline intptr_t StackState::stack_saved() const noexcept -{ - return this->_stack_saved; -} - -inline char* StackState::stack_start() const noexcept -{ - return this->_stack_start; -} - - -inline StackState StackState::make_main() noexcept -{ - StackState s; - s._stack_start = (char*)1; - s.stack_stop = (char*)-1; - return s; -} - -StackState::~StackState() -{ - if (this->_stack_saved != 0) { - this->free_stack_copy(); - } -} - -void StackState::copy_from_stack(void* vdest, const void* vsrc, size_t n) const -{ - char* dest = static_cast(vdest); - const char* src = static_cast(vsrc); - if (src + n <= this->_stack_start - || src >= this->_stack_start + this->_stack_saved - || this->_stack_saved == 0) { - // Nothing we're copying was spilled from the stack - memcpy(dest, src, n); - return; - } - - if (src < this->_stack_start) { - // Copy the part before the saved stack. - // We know src + n > _stack_start due to the test above. - const size_t nbefore = this->_stack_start - src; - memcpy(dest, src, nbefore); - dest += nbefore; - src += nbefore; - n -= nbefore; - } - // We know src >= _stack_start after the before-copy, and - // src < _stack_start + _stack_saved due to the first if condition - size_t nspilled = std::min(n, this->_stack_start + this->_stack_saved - src); - memcpy(dest, this->stack_copy + (src - this->_stack_start), nspilled); - dest += nspilled; - src += nspilled; - n -= nspilled; - if (n > 0) { - // Copy the part after the saved stack - memcpy(dest, src, n); - } -} - -}; // namespace greenlet - -#endif // GREENLET_STACK_STATE_CPP diff --git a/venv/lib/python3.9/site-packages/greenlet/TThreadState.hpp b/venv/lib/python3.9/site-packages/greenlet/TThreadState.hpp deleted file mode 100644 index cd97c84..0000000 --- a/venv/lib/python3.9/site-packages/greenlet/TThreadState.hpp +++ /dev/null @@ -1,517 +0,0 @@ -#ifndef GREENLET_THREAD_STATE_HPP -#define GREENLET_THREAD_STATE_HPP - -#include -#include - -#include "greenlet_internal.hpp" -#include "greenlet_refs.hpp" -#include "greenlet_thread_support.hpp" - -using greenlet::refs::BorrowedObject; -using greenlet::refs::BorrowedGreenlet; -using greenlet::refs::BorrowedMainGreenlet; -using greenlet::refs::OwnedMainGreenlet; -using greenlet::refs::OwnedObject; -using greenlet::refs::OwnedGreenlet; -using greenlet::refs::OwnedList; -using greenlet::refs::PyErrFetchParam; -using greenlet::refs::PyArgParseParam; -using greenlet::refs::ImmortalString; -using greenlet::refs::CreatedModule; -using greenlet::refs::PyErrPieces; -using greenlet::refs::NewReference; - -namespace greenlet { -/** - * Thread-local state of greenlets. - * - * Each native thread will get exactly one of these objects, - * automatically accessed through the best available thread-local - * mechanism the compiler supports (``thread_local`` for C++11 - * compilers or ``__thread``/``declspec(thread)`` for older GCC/clang - * or MSVC, respectively.) - * - * Previously, we kept thread-local state mostly in a bunch of - * ``static volatile`` variables in the main greenlet file.. This had - * the problem of requiring extra checks, loops, and great care - * accessing these variables if we potentially invoked any Python code - * that could release the GIL, because the state could change out from - * under us. Making the variables thread-local solves this problem. - * - * When we detected that a greenlet API accessing the current greenlet - * was invoked from a different thread than the greenlet belonged to, - * we stored a reference to the greenlet in the Python thread - * dictionary for the thread the greenlet belonged to. This could lead - * to memory leaks if the thread then exited (because of a reference - * cycle, as greenlets referred to the thread dictionary, and deleting - * non-current greenlets leaked their frame plus perhaps arguments on - * the C stack). If a thread exited while still having running - * greenlet objects (perhaps that had just switched back to the main - * greenlet), and did not invoke one of the greenlet APIs *in that - * thread, immediately before it exited, without some other thread - * then being invoked*, such a leak was guaranteed. - * - * This can be partly solved by using compiler thread-local variables - * instead of the Python thread dictionary, thus avoiding a cycle. - * - * To fully solve this problem, we need a reliable way to know that a - * thread is done and we should clean up the main greenlet. On POSIX, - * we can use the destructor function of ``pthread_key_create``, but - * there's nothing similar on Windows; a C++11 thread local object - * reliably invokes its destructor when the thread it belongs to exits - * (non-C++11 compilers offer ``__thread`` or ``declspec(thread)`` to - * create thread-local variables, but they can't hold C++ objects that - * invoke destructors; the C++11 version is the most portable solution - * I found). When the thread exits, we can drop references and - * otherwise manipulate greenlets and frames that we know can no - * longer be switched to. For compilers that don't support C++11 - * thread locals, we have a solution that uses the python thread - * dictionary, though it may not collect everything as promptly as - * other compilers do, if some other library is using the thread - * dictionary and has a cycle or extra reference. - * - * There are two small wrinkles. The first is that when the thread - * exits, it is too late to actually invoke Python APIs: the Python - * thread state is gone, and the GIL is released. To solve *this* - * problem, our destructor uses ``Py_AddPendingCall`` to transfer the - * destruction work to the main thread. (This is not an issue for the - * dictionary solution.) - * - * The second is that once the thread exits, the thread local object - * is invalid and we can't even access a pointer to it, so we can't - * pass it to ``Py_AddPendingCall``. This is handled by actually using - * a second object that's thread local (ThreadStateCreator) and having - * it dynamically allocate this object so it can live until the - * pending call runs. - */ - - - -class ThreadState { -private: - // As of commit 08ad1dd7012b101db953f492e0021fb08634afad - // this class needed 56 bytes in o Py_DEBUG build - // on 64-bit macOS 11. - // Adding the vector takes us up to 80 bytes () - - /* Strong reference to the main greenlet */ - OwnedMainGreenlet main_greenlet; - - /* Strong reference to the current greenlet. */ - OwnedGreenlet current_greenlet; - - /* Strong reference to the trace function, if any. */ - OwnedObject tracefunc; - - typedef std::vector > deleteme_t; - /* A vector of raw PyGreenlet pointers representing things that need - deleted when this thread is running. The vector owns the - references, but you need to manually INCREF/DECREF as you use - them. We don't use a vector because we - make copy of this vector, and that would become O(n) as all the - refcounts are incremented in the copy. - */ - deleteme_t deleteme; - -#ifdef GREENLET_NEEDS_EXCEPTION_STATE_SAVED - void* exception_state; -#endif - - static std::clock_t _clocks_used_doing_gc; - static ImmortalString get_referrers_name; - static PythonAllocator allocator; - - G_NO_COPIES_OF_CLS(ThreadState); - - - // Allocates a main greenlet for the thread state. If this fails, - // exits the process. Called only during constructing a ThreadState. - MainGreenlet* alloc_main() - { - PyGreenlet* gmain; - - /* create the main greenlet for this thread */ - gmain = reinterpret_cast(PyType_GenericAlloc(&PyGreenlet_Type, 0)); - if (gmain == NULL) { - throw PyFatalError("alloc_main failed to alloc"); //exits the process - } - - MainGreenlet* const main = new MainGreenlet(gmain, this); - - assert(Py_REFCNT(gmain) == 1); - assert(gmain->pimpl == main); - return main; - } - - -public: - static void* operator new(size_t UNUSED(count)) - { - return ThreadState::allocator.allocate(1); - } - - static void operator delete(void* ptr) - { - return ThreadState::allocator.deallocate(static_cast(ptr), - 1); - } - - static void init() - { - ThreadState::get_referrers_name = "get_referrers"; - ThreadState::_clocks_used_doing_gc = 0; - } - - ThreadState() - { - -#ifdef GREENLET_NEEDS_EXCEPTION_STATE_SAVED - this->exception_state = slp_get_exception_state(); -#endif - - // XXX: Potentially dangerous, exposing a not fully - // constructed object. - MainGreenlet* const main = this->alloc_main(); - this->main_greenlet = OwnedMainGreenlet::consuming( - main->self() - ); - assert(this->main_greenlet); - this->current_greenlet = main->self(); - // The main greenlet starts with 1 refs: The returned one. We - // then copied it to the current greenlet. - assert(this->main_greenlet.REFCNT() == 2); - } - - inline void restore_exception_state() - { -#ifdef GREENLET_NEEDS_EXCEPTION_STATE_SAVED - // It's probably important this be inlined and only call C - // functions to avoid adding an SEH frame. - slp_set_exception_state(this->exception_state); -#endif - } - - inline bool has_main_greenlet() const noexcept - { - return bool(this->main_greenlet); - } - - // Called from the ThreadStateCreator when we're in non-standard - // threading mode. In that case, there is an object in the Python - // thread state dictionary that points to us. The main greenlet - // also traverses into us, in which case it's crucial not to - // traverse back into the main greenlet. - int tp_traverse(visitproc visit, void* arg, bool traverse_main=true) - { - if (traverse_main) { - Py_VISIT(main_greenlet.borrow_o()); - } - if (traverse_main || current_greenlet != main_greenlet) { - Py_VISIT(current_greenlet.borrow_o()); - } - Py_VISIT(tracefunc.borrow()); - return 0; - } - - inline BorrowedMainGreenlet borrow_main_greenlet() const noexcept - { - assert(this->main_greenlet); - assert(this->main_greenlet.REFCNT() >= 2); - return this->main_greenlet; - }; - - inline OwnedMainGreenlet get_main_greenlet() const noexcept - { - return this->main_greenlet; - } - - /** - * In addition to returning a new reference to the currunt - * greenlet, this performs any maintenance needed. - */ - inline OwnedGreenlet get_current() - { - /* green_dealloc() cannot delete greenlets from other threads, so - it stores them in the thread dict; delete them now. */ - this->clear_deleteme_list(); - //assert(this->current_greenlet->main_greenlet == this->main_greenlet); - //assert(this->main_greenlet->main_greenlet == this->main_greenlet); - return this->current_greenlet; - } - - /** - * As for non-const get_current(); - */ - inline BorrowedGreenlet borrow_current() - { - this->clear_deleteme_list(); - return this->current_greenlet; - } - - /** - * Does no maintenance. - */ - inline OwnedGreenlet get_current() const - { - return this->current_greenlet; - } - - template - inline bool is_current(const refs::PyObjectPointer& obj) const - { - return this->current_greenlet.borrow_o() == obj.borrow_o(); - } - - inline void set_current(const OwnedGreenlet& target) - { - this->current_greenlet = target; - } - -private: - /** - * Deref and remove the greenlets from the deleteme list. Must be - * holding the GIL. - * - * If *murder* is true, then we must be called from a different - * thread than the one that these greenlets were running in. - * In that case, if the greenlet was actually running, we destroy - * the frame reference and otherwise make it appear dead before - * proceeding; otherwise, we would try (and fail) to raise an - * exception in it and wind up right back in this list. - */ - inline void clear_deleteme_list(const bool murder=false) - { - if (!this->deleteme.empty()) { - // It's possible we could add items to this list while - // running Python code if there's a thread switch, so we - // need to defensively copy it before that can happen. - deleteme_t copy = this->deleteme; - this->deleteme.clear(); // in case things come back on the list - for(deleteme_t::iterator it = copy.begin(), end = copy.end(); - it != end; - ++it ) { - PyGreenlet* to_del = *it; - if (murder) { - // Force each greenlet to appear dead; we can't raise an - // exception into it anymore anyway. - to_del->pimpl->murder_in_place(); - } - - // The only reference to these greenlets should be in - // this list, decreffing them should let them be - // deleted again, triggering calls to green_dealloc() - // in the correct thread (if we're not murdering). - // This may run arbitrary Python code and switch - // threads or greenlets! - Py_DECREF(to_del); - if (PyErr_Occurred()) { - PyErr_WriteUnraisable(nullptr); - PyErr_Clear(); - } - } - } - } - -public: - - /** - * Returns a new reference, or a false object. - */ - inline OwnedObject get_tracefunc() const - { - return tracefunc; - }; - - - inline void set_tracefunc(BorrowedObject tracefunc) - { - assert(tracefunc); - if (tracefunc == BorrowedObject(Py_None)) { - this->tracefunc.CLEAR(); - } - else { - this->tracefunc = tracefunc; - } - } - - /** - * Given a reference to a greenlet that some other thread - * attempted to delete (has a refcount of 0) store it for later - * deletion when the thread this state belongs to is current. - */ - inline void delete_when_thread_running(PyGreenlet* to_del) - { - Py_INCREF(to_del); - this->deleteme.push_back(to_del); - } - - /** - * Set to std::clock_t(-1) to disable. - */ - inline static std::clock_t& clocks_used_doing_gc() - { - return ThreadState::_clocks_used_doing_gc; - } - - ~ThreadState() - { - if (!PyInterpreterState_Head()) { - // We shouldn't get here (our callers protect us) - // but if we do, all we can do is bail early. - return; - } - - // During interpreter finalization, Python APIs like - // PyImport_ImportModule are unsafe (the import machinery may - // be partially torn down). On Python < 3.11, perform only the - // minimal cleanup that is safe: clear our strong references so - // we don't leak, but skip the GC-based leak detection. - // - // Python 3.11+ restructured interpreter finalization so that - // these APIs remain safe during shutdown. -#if !GREENLET_PY311 - if (_Py_IsFinalizing()) { - this->tracefunc.CLEAR(); - if (this->current_greenlet) { - this->current_greenlet->murder_in_place(); - this->current_greenlet.CLEAR(); - } - this->main_greenlet.CLEAR(); - return; - } -#endif - - // We should not have an "origin" greenlet; that only exists - // for the temporary time during a switch, which should not - // be in progress as the thread dies. - //assert(!this->switching_state.origin); - - this->tracefunc.CLEAR(); - - // Forcibly GC as much as we can. - this->clear_deleteme_list(true); - - // The pending call did this. - assert(this->main_greenlet->thread_state() == nullptr); - - // If the main greenlet is the current greenlet, - // then we "fell off the end" and the thread died. - // It's possible that there is some other greenlet that - // switched to us, leaving a reference to the main greenlet - // on the stack, somewhere uncollectible. Try to detect that. - if (this->current_greenlet == this->main_greenlet && this->current_greenlet) { - assert(this->current_greenlet->is_currently_running_in_some_thread()); - // Drop one reference we hold. - this->current_greenlet.CLEAR(); - assert(!this->current_greenlet); - // Only our reference to the main greenlet should be left, - // But hold onto the pointer in case we need to do extra cleanup. - PyGreenlet* old_main_greenlet = this->main_greenlet.borrow(); - Py_ssize_t cnt = this->main_greenlet.REFCNT(); - this->main_greenlet.CLEAR(); - if (ThreadState::_clocks_used_doing_gc != std::clock_t(-1) - && cnt == 2 && Py_REFCNT(old_main_greenlet) == 1) { - // Highly likely that the reference is somewhere on - // the stack, not reachable by GC. Verify. - // XXX: This is O(n) in the total number of objects. - // TODO: Add a way to disable this at runtime, and - // another way to report on it. - std::clock_t begin = std::clock(); - NewReference gc(PyImport_ImportModule("gc")); - if (gc) { - OwnedObject get_referrers = gc.PyRequireAttr(ThreadState::get_referrers_name); - OwnedList refs(get_referrers.PyCall(old_main_greenlet)); - if (refs && refs.empty()) { - assert(refs.REFCNT() == 1); - // We found nothing! So we left a dangling - // reference: Probably the last thing some - // other greenlet did was call - // 'getcurrent().parent.switch()' to switch - // back to us. Clean it up. This will be the - // case on CPython 3.7 and newer, as they use - // an internal calling conversion that avoids - // creating method objects and storing them on - // the stack. - Py_DECREF(old_main_greenlet); - } - else if (refs - && refs.size() == 1 - && PyCFunction_Check(refs.at(0)) - && Py_REFCNT(refs.at(0)) == 2) { - assert(refs.REFCNT() == 1); - // Ok, we found a C method that refers to the - // main greenlet, and its only referenced - // twice, once in the list we just created, - // once from...somewhere else. If we can't - // find where else, then this is a leak. - // This happens in older versions of CPython - // that create a bound method object somewhere - // on the stack that we'll never get back to. - if (PyCFunction_GetFunction(refs.at(0).borrow()) == (PyCFunction)green_switch) { - BorrowedObject function_w = refs.at(0); - refs.clear(); // destroy the reference - // from the list. - // back to one reference. Can *it* be - // found? - assert(function_w.REFCNT() == 1); - refs = get_referrers.PyCall(function_w); - if (refs && refs.empty()) { - // Nope, it can't be found so it won't - // ever be GC'd. Drop it. - Py_CLEAR(function_w); - } - } - } - std::clock_t end = std::clock(); - ThreadState::_clocks_used_doing_gc += (end - begin); - } - } - } - - // We need to make sure this greenlet appears to be dead, - // because otherwise deallocing it would fail to raise an - // exception in it (the thread is dead) and put it back in our - // deleteme list. - if (this->current_greenlet) { - this->current_greenlet->murder_in_place(); - this->current_greenlet.CLEAR(); - } - - if (this->main_greenlet) { - // Couldn't have been the main greenlet that was running - // when the thread exited (because we already cleared this - // pointer if it was). This shouldn't be possible? - - // If the main greenlet was current when the thread died (it - // should be, right?) then we cleared its self pointer above - // when we cleared the current greenlet's main greenlet pointer. - // assert(this->main_greenlet->main_greenlet == this->main_greenlet - // || !this->main_greenlet->main_greenlet); - // // self reference, probably gone - // this->main_greenlet->main_greenlet.CLEAR(); - - // This will actually go away when the ivar is destructed. - this->main_greenlet.CLEAR(); - } - - if (PyErr_Occurred()) { - PyErr_WriteUnraisable(NULL); - PyErr_Clear(); - } - - } - -}; - -ImmortalString ThreadState::get_referrers_name(nullptr); -PythonAllocator ThreadState::allocator; -std::clock_t ThreadState::_clocks_used_doing_gc(0); - - - - - -}; // namespace greenlet - -#endif diff --git a/venv/lib/python3.9/site-packages/greenlet/TThreadStateCreator.hpp b/venv/lib/python3.9/site-packages/greenlet/TThreadStateCreator.hpp deleted file mode 100644 index 2ec7ab5..0000000 --- a/venv/lib/python3.9/site-packages/greenlet/TThreadStateCreator.hpp +++ /dev/null @@ -1,102 +0,0 @@ -#ifndef GREENLET_THREAD_STATE_CREATOR_HPP -#define GREENLET_THREAD_STATE_CREATOR_HPP - -#include -#include - -#include "greenlet_internal.hpp" -#include "greenlet_refs.hpp" -#include "greenlet_thread_support.hpp" - -#include "TThreadState.hpp" - -namespace greenlet { - - -typedef void (*ThreadStateDestructor)(ThreadState* const); - -template -class ThreadStateCreator -{ -private: - // Initialized to 1, and, if still 1, created on access. - // Set to 0 on destruction. - ThreadState* _state; - G_NO_COPIES_OF_CLS(ThreadStateCreator); - - inline bool has_initialized_state() const noexcept - { - return this->_state != (ThreadState*)1; - } - - inline bool has_state() const noexcept - { - return this->has_initialized_state() && this->_state != nullptr; - } - -public: - - // Only one of these, auto created per thread. - // Constructing the state constructs the MainGreenlet. - ThreadStateCreator() : - _state((ThreadState*)1) - { - } - - ~ThreadStateCreator() - { - if (this->has_state()) { - Destructor(this->_state); - } - - this->_state = nullptr; - } - - inline ThreadState& state() - { - // The main greenlet will own this pointer when it is created, - // which will be right after this. The plan is to give every - // greenlet a pointer to the main greenlet for the thread it - // runs in; if we are doing something cross-thread, we need to - // access the pointer from the main greenlet. Deleting the - // thread, and hence the thread-local storage, will delete the - // state pointer in the main greenlet. - if (!this->has_initialized_state()) { - // XXX: Assuming allocation never fails - this->_state = new ThreadState; - // For non-standard threading, we need to store an object - // in the Python thread state dictionary so that it can be - // DECREF'd when the thread ends (ideally; the dict could - // last longer) and clean this object up. - } - if (!this->_state) { - throw std::runtime_error("Accessing state after destruction."); - } - return *this->_state; - } - - operator ThreadState&() - { - return this->state(); - } - - operator ThreadState*() - { - return &this->state(); - } - - inline int tp_traverse(visitproc visit, void* arg) - { - if (this->has_state()) { - return this->_state->tp_traverse(visit, arg); - } - return 0; - } - -}; - - - -}; // namespace greenlet - -#endif diff --git a/venv/lib/python3.9/site-packages/greenlet/TThreadStateDestroy.cpp b/venv/lib/python3.9/site-packages/greenlet/TThreadStateDestroy.cpp deleted file mode 100644 index 449b788..0000000 --- a/venv/lib/python3.9/site-packages/greenlet/TThreadStateDestroy.cpp +++ /dev/null @@ -1,217 +0,0 @@ -/* -*- indent-tabs-mode: nil; tab-width: 4; -*- */ -/** - * Implementation of the ThreadState destructors. - * - * Format with: - * clang-format -i --style=file src/greenlet/greenlet.c - * - * - * Fix missing braces with: - * clang-tidy src/greenlet/greenlet.c -fix -checks="readability-braces-around-statements" -*/ -#ifndef T_THREADSTATE_DESTROY -#define T_THREADSTATE_DESTROY - -#include "TGreenlet.hpp" - -#include "greenlet_thread_support.hpp" -#include "greenlet_compiler_compat.hpp" -#include "TGreenletGlobals.cpp" -#include "TThreadState.hpp" -#include "TThreadStateCreator.hpp" - -namespace greenlet { - -extern "C" { - -struct ThreadState_DestroyNoGIL -{ - /** - This function uses the same lock that the PendingCallback does - */ - static void - MarkGreenletDeadAndQueueCleanup(ThreadState* const state) - { -#if GREENLET_BROKEN_THREAD_LOCAL_CLEANUP_JUST_LEAK - return; -#endif - // We are *NOT* holding the GIL. Our thread is in the middle - // of its death throes and the Python thread state is already - // gone so we can't use most Python APIs. One that is safe is - // ``Py_AddPendingCall``, unless the interpreter itself has - // been torn down. There is a limited number of calls that can - // be queued: 32 (NPENDINGCALLS) in CPython 3.10, so we - // coalesce these calls using our own queue. - - if (!MarkGreenletDeadIfNeeded(state)) { - // No state, or no greenlet - return; - } - - // XXX: Because we don't have the GIL, this is a race condition. - if (!PyInterpreterState_Head()) { - // We have to leak the thread state, if the - // interpreter has shut down when we're getting - // deallocated, we can't run the cleanup code that - // deleting it would imply. - return; - } - - AddToCleanupQueue(state); - - } - -private: - - // If the state has an allocated main greenlet: - // - mark the greenlet as dead by disassociating it from the state; - // - return 1 - // Otherwise, return 0. - static bool - MarkGreenletDeadIfNeeded(ThreadState* const state) - { - if (state && state->has_main_greenlet()) { - // mark the thread as dead ASAP. - // this is racy! If we try to throw or switch to a - // greenlet from this thread from some other thread before - // we clear the state pointer, it won't realize the state - // is dead which can crash the process. - PyGreenlet* p(state->borrow_main_greenlet().borrow()); - assert(p->pimpl->thread_state() == state || p->pimpl->thread_state() == nullptr); - dynamic_cast(p->pimpl)->thread_state(nullptr); - return true; - } - return false; - } - - static void - AddToCleanupQueue(ThreadState* const state) - { - assert(state && state->has_main_greenlet()); - - // NOTE: Because we're not holding the GIL here, some other - // Python thread could run and call ``os.fork()``, which would - // be bad if that happened while we are holding the cleanup - // lock (it wouldn't function in the child process). - // Make a best effort to try to keep the duration we hold the - // lock short. - // TODO: On platforms that support it, use ``pthread_atfork`` to - // drop this lock. - LockGuard cleanup_lock(*mod_globs->thread_states_to_destroy_lock); - - mod_globs->queue_to_destroy(state); - if (mod_globs->thread_states_to_destroy.size() == 1) { - // We added the first item to the queue. We need to schedule - // the cleanup. - - // A size greater than 1 means that we have already added the pending call, - // and in fact, it may be executing now. - // If it is executing, our lock makes sure that it will see the item we just added - // to the queue on its next iteration (after we release the lock) - // - // A size of 1 means there is no pending call, OR the pending call is - // currently executing, has dropped the lock, and is deleting the last item - // from the queue; its next iteration will go ahead and delete the item we just added. - // And the pending call we schedule here will have no work to do. - int result = AddPendingCall( - PendingCallback_DestroyQueueWithGIL, - nullptr); - if (result < 0) { - // Hmm, what can we do here? - fprintf(stderr, - "greenlet: WARNING: failed in call to Py_AddPendingCall; " - "expect a memory leak.\n"); - } - } - } - - static int - PendingCallback_DestroyQueueWithGIL(void* UNUSED(arg)) - { - // We're holding the GIL here, so no Python code should be able to - // run to call ``os.fork()``. - while (1) { - ThreadState* to_destroy; - { - LockGuard cleanup_lock(*mod_globs->thread_states_to_destroy_lock); - if (mod_globs->thread_states_to_destroy.empty()) { - break; - } - to_destroy = mod_globs->take_next_to_destroy(); - } - assert(to_destroy); - assert(to_destroy->has_main_greenlet()); - // Drop the lock while we do the actual deletion. - // This allows other calls to MarkGreenletDeadAndQueueCleanup - // to enter and add to our queue. - DestroyOneWithGIL(to_destroy); - } - return 0; - } - - static void - DestroyOneWithGIL(const ThreadState* const state) - { - // Holding the GIL. - // Passed a non-shared pointer to the actual thread state. - // state -> main greenlet - assert(state->has_main_greenlet()); - PyGreenlet* main(state->borrow_main_greenlet()); - // When we need to do cross-thread operations, we check this. - // A NULL value means the thread died some time ago. - // We do this here, rather than in a Python dealloc function - // for the greenlet, in case there's still a reference out - // there. - dynamic_cast(main->pimpl)->thread_state(nullptr); - - delete state; // Deleting this runs the destructor, DECREFs the main greenlet. - } - - - static int AddPendingCall(int (*func)(void*), void* arg) - { - // If the interpreter is in the middle of finalizing, we can't add a - // pending call. Trying to do so will end up in a SIGSEGV, as - // Py_AddPendingCall will not be able to get the interpreter and will - // try to dereference a NULL pointer. It's possible this can still - // segfault if we happen to get context switched, and maybe we should - // just always implement our own AddPendingCall, but I'd like to see if - // this works first -#if GREENLET_PY313 - if (Py_IsFinalizing()) { -#else - if (_Py_IsFinalizing()) { -#endif -#ifdef GREENLET_DEBUG - // No need to log in the general case. Yes, we'll leak, - // but we're shutting down so it should be ok. - fprintf(stderr, - "greenlet: WARNING: Interpreter is finalizing. Ignoring " - "call to Py_AddPendingCall; \n"); -#endif - return 0; - } - return Py_AddPendingCall(func, arg); - } - - - - - -}; -}; - -}; // namespace greenlet - -// The intent when GET_THREAD_STATE() is needed multiple times in a -// function is to take a reference to its return value in a local -// variable, to avoid the thread-local indirection. On some platforms -// (macOS), accessing a thread-local involves a function call (plus an -// initial function call in each function that uses a thread local); -// in contrast, static volatile variables are at some pre-computed -// offset. -typedef greenlet::ThreadStateCreator ThreadStateCreator; -static thread_local ThreadStateCreator g_thread_state_global; -#define GET_THREAD_STATE() g_thread_state_global - -#endif //T_THREADSTATE_DESTROY diff --git a/venv/lib/python3.9/site-packages/greenlet/TUserGreenlet.cpp b/venv/lib/python3.9/site-packages/greenlet/TUserGreenlet.cpp deleted file mode 100644 index 73a8133..0000000 --- a/venv/lib/python3.9/site-packages/greenlet/TUserGreenlet.cpp +++ /dev/null @@ -1,662 +0,0 @@ -/* -*- indent-tabs-mode: nil; tab-width: 4; -*- */ -/** - * Implementation of greenlet::UserGreenlet. - * - * Format with: - * clang-format -i --style=file src/greenlet/greenlet.c - * - * - * Fix missing braces with: - * clang-tidy src/greenlet/greenlet.c -fix -checks="readability-braces-around-statements" -*/ -#ifndef T_USER_GREENLET_CPP -#define T_USER_GREENLET_CPP - -#include "greenlet_internal.hpp" -#include "TGreenlet.hpp" - -#include "TThreadStateDestroy.cpp" - - -namespace greenlet { -using greenlet::refs::BorrowedMainGreenlet; -greenlet::PythonAllocator UserGreenlet::allocator; - -void* UserGreenlet::operator new(size_t UNUSED(count)) -{ - return allocator.allocate(1); -} - - -void UserGreenlet::operator delete(void* ptr) -{ - return allocator.deallocate(static_cast(ptr), - 1); -} - - -UserGreenlet::UserGreenlet(PyGreenlet* p, BorrowedGreenlet the_parent) - : Greenlet(p), _parent(the_parent) -{ -} - -UserGreenlet::~UserGreenlet() -{ - // Python 3.11: If we don't clear out the raw frame datastack - // when deleting an unfinished greenlet, - // TestLeaks.test_untracked_memory_doesnt_increase_unfinished_thread_dealloc_in_main fails. - this->python_state.did_finish(nullptr); - this->tp_clear(); -} - - -const BorrowedMainGreenlet -UserGreenlet::main_greenlet() const -{ - return this->_main_greenlet; -} - - -BorrowedMainGreenlet -UserGreenlet::find_main_greenlet_in_lineage() const -{ - if (this->started()) { - assert(this->_main_greenlet); - return BorrowedMainGreenlet(this->_main_greenlet); - } - - if (!this->_parent) { - /* garbage collected greenlet in chain */ - // XXX: WHAT? - return BorrowedMainGreenlet(nullptr); - } - - return this->_parent->find_main_greenlet_in_lineage(); -} - - -/** - * CAUTION: This will allocate memory and may trigger garbage - * collection and arbitrary Python code. - */ -OwnedObject -UserGreenlet::throw_GreenletExit_during_dealloc(const ThreadState& current_thread_state) -{ - /* The dying greenlet cannot be a parent of ts_current - because the 'parent' field chain would hold a - reference */ - UserGreenlet::ParentIsCurrentGuard with_current_parent(this, current_thread_state); - - // We don't care about the return value, only whether an - // exception happened. Whether or not an exception happens, - // we need to restore the parent in case the greenlet gets - // resurrected. - return Greenlet::throw_GreenletExit_during_dealloc(current_thread_state); -} - -ThreadState* -UserGreenlet::thread_state() const noexcept -{ - // TODO: maybe make this throw, if the thread state isn't there? - // if (!this->main_greenlet) { - // throw std::runtime_error("No thread state"); // TODO: Better exception - // } - if (!this->_main_greenlet) { - return nullptr; - } - return this->_main_greenlet->thread_state(); -} - - -bool -UserGreenlet::was_running_in_dead_thread() const noexcept -{ - return this->_main_greenlet && !this->thread_state(); -} - -OwnedObject -UserGreenlet::g_switch() -{ - assert(this->args() || PyErr_Occurred()); - - try { - this->check_switch_allowed(); - } - catch (const PyErrOccurred&) { - this->release_args(); - throw; - } - - // Switching greenlets used to attempt to clean out ones that need - // deleted *if* we detected a thread switch. Should it still do - // that? - // An issue is that if we delete a greenlet from another thread, - // it gets queued to this thread, and ``kill_greenlet()`` switches - // back into the greenlet - - /* find the real target by ignoring dead greenlets, - and if necessary starting a greenlet. */ - switchstack_result_t err; - Greenlet* target = this; - // TODO: probably cleaner to handle the case where we do - // switch to ourself separately from the other cases. - // This can probably even further be simplified if we keep - // track of the switching_state we're going for and just call - // into g_switch() if it's not ourself. The main problem with that - // is that we would be using more stack space. - bool target_was_me = true; - bool was_initial_stub = false; - while (target) { - if (target->active()) { - if (!target_was_me) { - target->args() <<= this->args(); - assert(!this->args()); - } - err = target->g_switchstack(); - break; - } - if (!target->started()) { - // We never encounter a main greenlet that's not started. - assert(!target->main()); - UserGreenlet* real_target = static_cast(target); - assert(real_target); - void* dummymarker; - was_initial_stub = true; - if (!target_was_me) { - target->args() <<= this->args(); - assert(!this->args()); - } - try { - // This can only throw back to us while we're - // still in this greenlet. Once the new greenlet - // is bootstrapped, it has its own exception state. - err = real_target->g_initialstub(&dummymarker); - } - catch (const PyErrOccurred&) { - this->release_args(); - throw; - } - catch (const GreenletStartedWhileInPython&) { - // The greenlet was started sometime before this - // greenlet actually switched to it, i.e., - // "concurrent" calls to switch() or throw(). - // We need to retry the switch. - // Note that the current greenlet has been reset - // to this one (or we wouldn't be running!) - continue; - } - break; - } - - target = target->parent(); - target_was_me = false; - } - // The ``this`` pointer and all other stack or register based - // variables are invalid now, at least where things succeed - // above. - // But this one, probably not so much? It's not clear if it's - // safe to throw an exception at this point. - - if (err.status < 0) { - // If we get here, either g_initialstub() - // failed, or g_switchstack() failed. Either one of those - // cases SHOULD leave us in the original greenlet with a valid - // stack. - return this->on_switchstack_or_initialstub_failure(target, err, target_was_me, was_initial_stub); - } - - // err.the_new_current_greenlet would be the same as ``target``, - // if target wasn't probably corrupt. - return err.the_new_current_greenlet->g_switch_finish(err); -} - - - -Greenlet::switchstack_result_t -UserGreenlet::g_initialstub(void* mark) -{ - OwnedObject run; - - // We need to grab a reference to the current switch arguments - // in case we're entered concurrently during the call to - // GetAttr() and have to try again. - // We'll restore them when we return in that case. - // Scope them tightly to avoid ref leaks. - { - SwitchingArgs args(this->args()); - - /* save exception in case getattr clears it */ - PyErrPieces saved; - - /* - self.run is the object to call in the new greenlet. - This could run arbitrary python code and switch greenlets! - */ - run = this->self().PyRequireAttr(mod_globs->str_run); - /* restore saved exception */ - saved.PyErrRestore(); - - - /* recheck that it's safe to switch in case greenlet reparented anywhere above */ - this->check_switch_allowed(); - - /* by the time we got here another start could happen elsewhere, - * that means it should now be a regular switch. - * This can happen if the Python code is a subclass that implements - * __getattribute__ or __getattr__, or makes ``run`` a descriptor; - * all of those can run arbitrary code that switches back into - * this greenlet. - */ - if (this->stack_state.started()) { - // the successful switch cleared these out, we need to - // restore our version. They will be copied on up to the - // next target. - assert(!this->args()); - this->args() <<= args; - throw GreenletStartedWhileInPython(); - } - } - - // Sweet, if we got here, we have the go-ahead and will switch - // greenlets. - // Nothing we do from here on out should allow for a thread or - // greenlet switch: No arbitrary calls to Python, including - // decref'ing - -#if GREENLET_USE_CFRAME - /* OK, we need it, we're about to switch greenlets, save the state. */ - /* - See green_new(). This is a stack-allocated variable used - while *self* is in PyObject_Call(). - We want to defer copying the state info until we're sure - we need it and are in a stable place to do so. - */ - _PyCFrame trace_info; - - this->python_state.set_new_cframe(trace_info); -#endif - /* start the greenlet */ - ThreadState& thread_state = GET_THREAD_STATE().state(); - this->stack_state = StackState(mark, - thread_state.borrow_current()->stack_state); - this->python_state.set_initial_state(PyThreadState_GET()); - this->exception_state.clear(); - this->_main_greenlet = thread_state.get_main_greenlet(); - - /* perform the initial switch */ - switchstack_result_t err = this->g_switchstack(); - /* returns twice! - The 1st time with ``err == 1``: we are in the new greenlet. - This one owns a greenlet that used to be current. - The 2nd time with ``err <= 0``: back in the caller's - greenlet; this happens if the child finishes or switches - explicitly to us. Either way, the ``err`` variable is - created twice at the same memory location, but possibly - having different ``origin`` values. Note that it's not - constructed for the second time until the switch actually happens. - */ - if (err.status == 1) { - // In the new greenlet. - - // This never returns! Calling inner_bootstrap steals - // the contents of our run object within this stack frame, so - // it is not valid to do anything with it. - try { - this->inner_bootstrap(err.origin_greenlet.relinquish_ownership(), - run.relinquish_ownership()); - } - // Getting a C++ exception here isn't good. It's probably a - // bug in the underlying greenlet, meaning it's probably a - // C++ extension. We're going to abort anyway, but try to - // display some nice information *if* possible. Some obscure - // platforms don't properly support this (old 32-bit Arm, see see - // https://github.com/python-greenlet/greenlet/issues/385); that's not - // great, but should usually be OK because, as mentioned above, we're - // terminating anyway. - // - // The catching is tested by - // ``test_cpp.CPPTests.test_unhandled_exception_in_greenlet_aborts``. - // - // PyErrOccurred can theoretically be thrown by - // inner_bootstrap() -> g_switch_finish(), but that should - // never make it back to here. It is a std::exception and - // would be caught if it is. - catch (const std::exception& e) { - std::string base = "greenlet: Unhandled C++ exception: "; - base += e.what(); - Py_FatalError(base.c_str()); - } - catch (...) { - // Some compilers/runtimes use exceptions internally. - // It appears that GCC on Linux with libstdc++ throws an - // exception internally at process shutdown time to unwind - // stacks and clean up resources. Depending on exactly - // where we are when the process exits, that could result - // in an unknown exception getting here. If we - // Py_FatalError() or abort() here, we interfere with - // orderly process shutdown. Throwing the exception on up - // is the right thing to do. - // - // gevent's ``examples/dns_mass_resolve.py`` demonstrates this. -#ifndef NDEBUG - fprintf(stderr, - "greenlet: inner_bootstrap threw unknown exception; " - "is the process terminating?\n"); -#endif - throw; - } - Py_FatalError("greenlet: inner_bootstrap returned with no exception.\n"); - } - - - // In contrast, notice that we're keeping the origin greenlet - // around as an owned reference; we need it to call the trace - // function for the switch back into the parent. It was only - // captured at the time the switch actually happened, though, - // so we haven't been keeping an extra reference around this - // whole time. - - /* back in the parent */ - if (err.status < 0) { - /* start failed badly, restore greenlet state */ - this->stack_state = StackState(); - this->_main_greenlet.CLEAR(); - // CAUTION: This may run arbitrary Python code. - run.CLEAR(); // inner_bootstrap didn't run, we own the reference. - } - - // In the success case, the spawned code (inner_bootstrap) will - // take care of decrefing this, so we relinquish ownership so as - // to not double-decref. - - run.relinquish_ownership(); - - return err; -} - - -void -UserGreenlet::inner_bootstrap(PyGreenlet* origin_greenlet, PyObject* run) -{ - // The arguments here would be another great place for move. - // As it is, we take them as a reference so that when we clear - // them we clear what's on the stack above us. Do that NOW, and - // without using a C++ RAII object, - // so there's no way that exiting the parent frame can clear it, - // or we clear it unexpectedly. This arises in the context of the - // interpreter shutting down. See https://github.com/python-greenlet/greenlet/issues/325 - //PyObject* run = _run.relinquish_ownership(); - - /* in the new greenlet */ - assert(this->thread_state()->borrow_current() == BorrowedGreenlet(this->_self)); - // C++ exceptions cannot propagate to the parent greenlet from - // here. (TODO: Do we need a catch(...) clause, perhaps on the - // function itself? ALl we could do is terminate the program.) - // NOTE: On 32-bit Windows, the call chain is extremely - // important here in ways that are subtle, having to do with - // the depth of the SEH list. The call to restore it MUST NOT - // add a new SEH handler to the list, or we'll restore it to - // the wrong thing. - this->thread_state()->restore_exception_state(); - /* stack variables from above are no good and also will not unwind! */ - // EXCEPT: That can't be true, we access run, among others, here. - - this->stack_state.set_active(); /* running */ - - // We're about to possibly run Python code again, which - // could switch back/away to/from us, so we need to grab the - // arguments locally. - SwitchingArgs args; - args <<= this->args(); - assert(!this->args()); - - // XXX: We could clear this much earlier, right? - // Or would that introduce the possibility of running Python - // code when we don't want to? - // CAUTION: This may run arbitrary Python code. - this->_run_callable.CLEAR(); - - - // The first switch we need to manually call the trace - // function here instead of in g_switch_finish, because we - // never return there. - if (OwnedObject tracefunc = this->thread_state()->get_tracefunc()) { - OwnedGreenlet trace_origin; - trace_origin = origin_greenlet; - try { - g_calltrace(tracefunc, - args ? mod_globs->event_switch : mod_globs->event_throw, - trace_origin, - this->_self); - } - catch (const PyErrOccurred&) { - /* Turn trace errors into switch throws */ - args.CLEAR(); - } - } - - // We no longer need the origin, it was only here for - // tracing. - // We may never actually exit this stack frame so we need - // to explicitly clear it. - // This could run Python code and switch. - Py_CLEAR(origin_greenlet); - - OwnedObject result; - if (!args) { - /* pending exception */ - result = NULL; - } - else { - /* call g.run(*args, **kwargs) */ - // This could result in further switches - try { - //result = run.PyCall(args.args(), args.kwargs()); - // CAUTION: Just invoking this, before the function even - // runs, may cause memory allocations, which may trigger - // GC, which may run arbitrary Python code. - result = OwnedObject::consuming(PyObject_Call(run, args.args().borrow(), args.kwargs().borrow())); - } - catch (...) { - // Unhandled C++ exception! - - // If we declare ourselves as noexcept, if we don't catch - // this here, most platforms will just abort() the - // process. But on 64-bit Windows with older versions of - // the C runtime, this can actually corrupt memory and - // just return. We see this when compiling with the - // Windows 7.0 SDK targeting Windows Server 2008, but not - // when using the Appveyor Visual Studio 2019 image. So - // this currently only affects Python 2.7 on Windows 64. - // That is, the tests pass and the runtime aborts - // everywhere else. - // - // However, if we catch it and try to continue with a - // Python error, then all Windows 64 bit platforms corrupt - // memory. So all we can do is manually abort, hopefully - // with a good error message. (Note that the above was - // tested WITHOUT the `/EHr` switch being used at compile - // time, so MSVC may have "optimized" out important - // checking. Using that switch, we may be in a better - // place in terms of memory corruption.) But sometimes it - // can't be caught here at all, which is confusing but not - // terribly surprising; so again, the G_NOEXCEPT_WIN32 - // plus "/EHr". - // - // Hopefully the basic C stdlib is still functional enough - // for us to at least print an error. - // - // It gets more complicated than that, though, on some - // platforms, specifically at least Linux/gcc/libstdc++. They use - // an exception to unwind the stack when a background - // thread exits. (See comments about noexcept.) So this - // may not actually represent anything untoward. On those - // platforms we allow throws of this to propagate, or - // attempt to anyway. -# if defined(WIN32) || defined(_WIN32) - Py_FatalError( - "greenlet: Unhandled C++ exception from a greenlet run function. " - "Because memory is likely corrupted, terminating process."); - std::abort(); -#else - throw; -#endif - } - } - // These lines may run arbitrary code - args.CLEAR(); - Py_CLEAR(run); - - if (!result - && mod_globs->PyExc_GreenletExit.PyExceptionMatches() - && (this->args())) { - // This can happen, for example, if our only reference - // goes away after we switch back to the parent. - // See test_dealloc_switch_args_not_lost - PyErrPieces clear_error; - result <<= this->args(); - result = single_result(result); - } - this->release_args(); - this->python_state.did_finish(PyThreadState_GET()); - - result = g_handle_exit(result); - assert(this->thread_state()->borrow_current() == this->_self); - - /* jump back to parent */ - this->stack_state.set_inactive(); /* dead */ - - - // TODO: Can we decref some things here? Release our main greenlet - // and maybe parent? - for (Greenlet* parent = this->_parent; - parent; - parent = parent->parent()) { - // We need to somewhere consume a reference to - // the result; in most cases we'll never have control - // back in this stack frame again. Calling - // green_switch actually adds another reference! - // This would probably be clearer with a specific API - // to hand results to the parent. - parent->args() <<= result; - assert(!result); - // The parent greenlet now owns the result; in the - // typical case we'll never get back here to assign to - // result and thus release the reference. - try { - result = parent->g_switch(); - } - catch (const PyErrOccurred&) { - // Ignore, keep passing the error on up. - } - - /* Return here means switch to parent failed, - * in which case we throw *current* exception - * to the next parent in chain. - */ - assert(!result); - } - /* We ran out of parents, cannot continue */ - PyErr_WriteUnraisable(this->self().borrow_o()); - Py_FatalError("greenlet: ran out of parent greenlets while propagating exception; " - "cannot continue"); - std::abort(); -} - -void -UserGreenlet::run(const BorrowedObject nrun) -{ - if (this->started()) { - throw AttributeError( - "run cannot be set " - "after the start of the greenlet"); - } - this->_run_callable = nrun; -} - -const OwnedGreenlet -UserGreenlet::parent() const -{ - return this->_parent; -} - -void -UserGreenlet::parent(const BorrowedObject raw_new_parent) -{ - if (!raw_new_parent) { - throw AttributeError("can't delete attribute"); - } - - BorrowedMainGreenlet main_greenlet_of_new_parent; - BorrowedGreenlet new_parent(raw_new_parent.borrow()); // could - // throw - // TypeError! - for (BorrowedGreenlet p = new_parent; p; p = p->parent()) { - if (p == this->self()) { - throw ValueError("cyclic parent chain"); - } - main_greenlet_of_new_parent = p->main_greenlet(); - } - - if (!main_greenlet_of_new_parent) { - throw ValueError("parent must not be garbage collected"); - } - - if (this->started() - && this->_main_greenlet != main_greenlet_of_new_parent) { - throw ValueError("parent cannot be on a different thread"); - } - - this->_parent = new_parent; -} - -void -UserGreenlet::murder_in_place() -{ - this->_main_greenlet.CLEAR(); - Greenlet::murder_in_place(); -} - -bool -UserGreenlet::belongs_to_thread(const ThreadState* thread_state) const -{ - return Greenlet::belongs_to_thread(thread_state) && this->_main_greenlet == thread_state->borrow_main_greenlet(); -} - - -int -UserGreenlet::tp_traverse(visitproc visit, void* arg) -{ - Py_VISIT(this->_parent.borrow_o()); - Py_VISIT(this->_main_greenlet.borrow_o()); - Py_VISIT(this->_run_callable.borrow_o()); - - return Greenlet::tp_traverse(visit, arg); -} - -int -UserGreenlet::tp_clear() -{ - Greenlet::tp_clear(); - this->_parent.CLEAR(); - this->_main_greenlet.CLEAR(); - this->_run_callable.CLEAR(); - return 0; -} - -UserGreenlet::ParentIsCurrentGuard::ParentIsCurrentGuard(UserGreenlet* p, - const ThreadState& thread_state) - : oldparent(p->_parent), - greenlet(p) -{ - p->_parent = thread_state.get_current(); -} - -UserGreenlet::ParentIsCurrentGuard::~ParentIsCurrentGuard() -{ - this->greenlet->_parent = oldparent; - oldparent.CLEAR(); -} - -}; //namespace greenlet -#endif diff --git a/venv/lib/python3.9/site-packages/greenlet/__init__.py b/venv/lib/python3.9/site-packages/greenlet/__init__.py deleted file mode 100644 index f07e5e0..0000000 --- a/venv/lib/python3.9/site-packages/greenlet/__init__.py +++ /dev/null @@ -1,71 +0,0 @@ -# -*- coding: utf-8 -*- -""" -The root of the greenlet package. -""" -from __future__ import absolute_import -from __future__ import division -from __future__ import print_function - -__all__ = [ - '__version__', - '_C_API', - - 'GreenletExit', - 'error', - - 'getcurrent', - 'greenlet', - - 'gettrace', - 'settrace', -] - -# pylint:disable=no-name-in-module - -### -# Metadata -### -__version__ = '3.2.5' -from ._greenlet import _C_API # pylint:disable=no-name-in-module - -### -# Exceptions -### -from ._greenlet import GreenletExit -from ._greenlet import error - -### -# greenlets -### -from ._greenlet import getcurrent -from ._greenlet import greenlet - -### -# tracing -### -try: - from ._greenlet import gettrace - from ._greenlet import settrace -except ImportError: - # Tracing wasn't supported. - # XXX: The option to disable it was removed in 1.0, - # so this branch should be dead code. - pass - -### -# Constants -# These constants aren't documented and aren't recommended. -# In 1.0, USE_GC and USE_TRACING are always true, and USE_CONTEXT_VARS -# is the same as ``sys.version_info[:2] >= 3.7`` -### -from ._greenlet import GREENLET_USE_CONTEXT_VARS # pylint:disable=unused-import -from ._greenlet import GREENLET_USE_GC # pylint:disable=unused-import -from ._greenlet import GREENLET_USE_TRACING # pylint:disable=unused-import - -# Controlling the use of the gc module. Provisional API for this greenlet -# implementation in 2.0. -from ._greenlet import CLOCKS_PER_SEC # pylint:disable=unused-import -from ._greenlet import enable_optional_cleanup # pylint:disable=unused-import -from ._greenlet import get_clocks_used_doing_optional_cleanup # pylint:disable=unused-import - -# Other APIS in the _greenlet module are for test support. diff --git a/venv/lib/python3.9/site-packages/greenlet/_greenlet.cpython-39-x86_64-linux-gnu.so b/venv/lib/python3.9/site-packages/greenlet/_greenlet.cpython-39-x86_64-linux-gnu.so deleted file mode 100755 index a2eb761..0000000 Binary files a/venv/lib/python3.9/site-packages/greenlet/_greenlet.cpython-39-x86_64-linux-gnu.so and /dev/null differ diff --git a/venv/lib/python3.9/site-packages/greenlet/greenlet.cpp b/venv/lib/python3.9/site-packages/greenlet/greenlet.cpp deleted file mode 100644 index e8d92a0..0000000 --- a/venv/lib/python3.9/site-packages/greenlet/greenlet.cpp +++ /dev/null @@ -1,320 +0,0 @@ -/* -*- indent-tabs-mode: nil; tab-width: 4; -*- */ -/* Format with: - * clang-format -i --style=file src/greenlet/greenlet.c - * - * - * Fix missing braces with: - * clang-tidy src/greenlet/greenlet.c -fix -checks="readability-braces-around-statements" -*/ -#include -#include -#include -#include - - -#define PY_SSIZE_T_CLEAN -#include -#include "structmember.h" // PyMemberDef - -#include "greenlet_internal.hpp" -// Code after this point can assume access to things declared in stdint.h, -// including the fixed-width types. This goes for the platform-specific switch functions -// as well. -#include "greenlet_refs.hpp" -#include "greenlet_slp_switch.hpp" - -#include "greenlet_thread_support.hpp" -#include "TGreenlet.hpp" - -#include "TGreenletGlobals.cpp" - -#include "TGreenlet.cpp" -#include "TMainGreenlet.cpp" -#include "TUserGreenlet.cpp" -#include "TBrokenGreenlet.cpp" -#include "TExceptionState.cpp" -#include "TPythonState.cpp" -#include "TStackState.cpp" - -#include "TThreadState.hpp" -#include "TThreadStateCreator.hpp" -#include "TThreadStateDestroy.cpp" - -#include "PyGreenlet.cpp" -#include "PyGreenletUnswitchable.cpp" -#include "CObjects.cpp" - -using greenlet::LockGuard; -using greenlet::LockInitError; -using greenlet::PyErrOccurred; -using greenlet::Require; - -using greenlet::g_handle_exit; -using greenlet::single_result; - -using greenlet::Greenlet; -using greenlet::UserGreenlet; -using greenlet::MainGreenlet; -using greenlet::BrokenGreenlet; -using greenlet::ThreadState; -using greenlet::PythonState; - - - -// ******* Implementation of things from included files -template -greenlet::refs::_BorrowedGreenlet& greenlet::refs::_BorrowedGreenlet::operator=(const greenlet::refs::BorrowedObject& other) -{ - this->_set_raw_pointer(static_cast(other)); - return *this; -} - -template -inline greenlet::refs::_BorrowedGreenlet::operator Greenlet*() const noexcept -{ - if (!this->p) { - return nullptr; - } - return reinterpret_cast(this->p)->pimpl; -} - -template -greenlet::refs::_BorrowedGreenlet::_BorrowedGreenlet(const BorrowedObject& p) - : BorrowedReference(nullptr) -{ - - this->_set_raw_pointer(p.borrow()); -} - -template -inline greenlet::refs::_OwnedGreenlet::operator Greenlet*() const noexcept -{ - if (!this->p) { - return nullptr; - } - return reinterpret_cast(this->p)->pimpl; -} - - - -#ifdef __clang__ -# pragma clang diagnostic push -# pragma clang diagnostic ignored "-Wmissing-field-initializers" -# pragma clang diagnostic ignored "-Wwritable-strings" -#elif defined(__GNUC__) -# pragma GCC diagnostic push -// warning: ISO C++ forbids converting a string constant to ‘char*’ -// (The python APIs aren't const correct and accept writable char*) -# pragma GCC diagnostic ignored "-Wwrite-strings" -#endif - - -/*********************************************************** - -A PyGreenlet is a range of C stack addresses that must be -saved and restored in such a way that the full range of the -stack contains valid data when we switch to it. - -Stack layout for a greenlet: - - | ^^^ | - | older data | - | | - stack_stop . |_______________| - . | | - . | greenlet data | - . | in stack | - . * |_______________| . . _____________ stack_copy + stack_saved - . | | | | - . | data | |greenlet data| - . | unrelated | | saved | - . | to | | in heap | - stack_start . | this | . . |_____________| stack_copy - | greenlet | - | | - | newer data | - | vvv | - - -Note that a greenlet's stack data is typically partly at its correct -place in the stack, and partly saved away in the heap, but always in -the above configuration: two blocks, the more recent one in the heap -and the older one still in the stack (either block may be empty). - -Greenlets are chained: each points to the previous greenlet, which is -the one that owns the data currently in the C stack above my -stack_stop. The currently running greenlet is the first element of -this chain. The main (initial) greenlet is the last one. Greenlets -whose stack is entirely in the heap can be skipped from the chain. - -The chain is not related to execution order, but only to the order -in which bits of C stack happen to belong to greenlets at a particular -point in time. - -The main greenlet doesn't have a stack_stop: it is responsible for the -complete rest of the C stack, and we don't know where it begins. We -use (char*) -1, the largest possible address. - -States: - stack_stop == NULL && stack_start == NULL: did not start yet - stack_stop != NULL && stack_start == NULL: already finished - stack_stop != NULL && stack_start != NULL: active - -The running greenlet's stack_start is undefined but not NULL. - - ***********************************************************/ - - - - -/***********************************************************/ - -/* Some functions must not be inlined: - * slp_restore_state, when inlined into slp_switch might cause - it to restore stack over its own local variables - * slp_save_state, when inlined would add its own local - variables to the saved stack, wasting space - * slp_switch, cannot be inlined for obvious reasons - * g_initialstub, when inlined would receive a pointer into its - own stack frame, leading to incomplete stack save/restore - -g_initialstub is a member function and declared virtual so that the -compiler always calls it through a vtable. - -slp_save_state and slp_restore_state are also member functions. They -are called from trampoline functions that themselves are declared as -not eligible for inlining. -*/ - -extern "C" { -static int GREENLET_NOINLINE(slp_save_state_trampoline)(char* stackref) -{ - return switching_thread_state->slp_save_state(stackref); -} -static void GREENLET_NOINLINE(slp_restore_state_trampoline)() -{ - switching_thread_state->slp_restore_state(); -} -} - - -/***********************************************************/ - - -#include "PyModule.cpp" - - - -static PyObject* -greenlet_internal_mod_init() noexcept -{ - static void* _PyGreenlet_API[PyGreenlet_API_pointers]; - - try { - CreatedModule m(greenlet_module_def); - - Require(PyType_Ready(&PyGreenlet_Type)); - Require(PyType_Ready(&PyGreenletUnswitchable_Type)); - - mod_globs = new greenlet::GreenletGlobals; - ThreadState::init(); - - m.PyAddObject("greenlet", PyGreenlet_Type); - m.PyAddObject("UnswitchableGreenlet", PyGreenletUnswitchable_Type); - m.PyAddObject("error", mod_globs->PyExc_GreenletError); - m.PyAddObject("GreenletExit", mod_globs->PyExc_GreenletExit); - - m.PyAddObject("GREENLET_USE_GC", 1); - m.PyAddObject("GREENLET_USE_TRACING", 1); - m.PyAddObject("GREENLET_USE_CONTEXT_VARS", 1L); - m.PyAddObject("GREENLET_USE_STANDARD_THREADING", 1L); - - OwnedObject clocks_per_sec = OwnedObject::consuming(PyLong_FromSsize_t(CLOCKS_PER_SEC)); - m.PyAddObject("CLOCKS_PER_SEC", clocks_per_sec); - - /* also publish module-level data as attributes of the greentype. */ - // XXX: This is weird, and enables a strange pattern of - // confusing the class greenlet with the module greenlet; with - // the exception of (possibly) ``getcurrent()``, this - // shouldn't be encouraged so don't add new items here. - for (const char* const* p = copy_on_greentype; *p; p++) { - OwnedObject o = m.PyRequireAttr(*p); - PyDict_SetItemString(PyGreenlet_Type.tp_dict, *p, o.borrow()); - } - - /* - * Expose C API - */ - - /* types */ - _PyGreenlet_API[PyGreenlet_Type_NUM] = (void*)&PyGreenlet_Type; - - /* exceptions */ - _PyGreenlet_API[PyExc_GreenletError_NUM] = (void*)mod_globs->PyExc_GreenletError; - _PyGreenlet_API[PyExc_GreenletExit_NUM] = (void*)mod_globs->PyExc_GreenletExit; - - /* methods */ - _PyGreenlet_API[PyGreenlet_New_NUM] = (void*)PyGreenlet_New; - _PyGreenlet_API[PyGreenlet_GetCurrent_NUM] = (void*)PyGreenlet_GetCurrent; - _PyGreenlet_API[PyGreenlet_Throw_NUM] = (void*)PyGreenlet_Throw; - _PyGreenlet_API[PyGreenlet_Switch_NUM] = (void*)PyGreenlet_Switch; - _PyGreenlet_API[PyGreenlet_SetParent_NUM] = (void*)PyGreenlet_SetParent; - - /* Previously macros, but now need to be functions externally. */ - _PyGreenlet_API[PyGreenlet_MAIN_NUM] = (void*)Extern_PyGreenlet_MAIN; - _PyGreenlet_API[PyGreenlet_STARTED_NUM] = (void*)Extern_PyGreenlet_STARTED; - _PyGreenlet_API[PyGreenlet_ACTIVE_NUM] = (void*)Extern_PyGreenlet_ACTIVE; - _PyGreenlet_API[PyGreenlet_GET_PARENT_NUM] = (void*)Extern_PyGreenlet_GET_PARENT; - - /* XXX: Note that our module name is ``greenlet._greenlet``, but for - backwards compatibility with existing C code, we need the _C_API to - be directly in greenlet. - */ - const NewReference c_api_object(Require( - PyCapsule_New( - (void*)_PyGreenlet_API, - "greenlet._C_API", - NULL))); - m.PyAddObject("_C_API", c_api_object); - assert(c_api_object.REFCNT() == 2); - - // cerr << "Sizes:" - // << "\n\tGreenlet : " << sizeof(Greenlet) - // << "\n\tUserGreenlet : " << sizeof(UserGreenlet) - // << "\n\tMainGreenlet : " << sizeof(MainGreenlet) - // << "\n\tExceptionState : " << sizeof(greenlet::ExceptionState) - // << "\n\tPythonState : " << sizeof(greenlet::PythonState) - // << "\n\tStackState : " << sizeof(greenlet::StackState) - // << "\n\tSwitchingArgs : " << sizeof(greenlet::SwitchingArgs) - // << "\n\tOwnedObject : " << sizeof(greenlet::refs::OwnedObject) - // << "\n\tBorrowedObject : " << sizeof(greenlet::refs::BorrowedObject) - // << "\n\tPyGreenlet : " << sizeof(PyGreenlet) - // << endl; - - return m.borrow(); // But really it's the main reference. - } - catch (const LockInitError& e) { - PyErr_SetString(PyExc_MemoryError, e.what()); - return NULL; - } - catch (const PyErrOccurred&) { - return NULL; - } - -} - -extern "C" { - -PyMODINIT_FUNC -PyInit__greenlet(void) -{ - return greenlet_internal_mod_init(); -} - -}; // extern C - -#ifdef __clang__ -# pragma clang diagnostic pop -#elif defined(__GNUC__) -# pragma GCC diagnostic pop -#endif diff --git a/venv/lib/python3.9/site-packages/greenlet/greenlet.h b/venv/lib/python3.9/site-packages/greenlet/greenlet.h deleted file mode 100644 index d02a16e..0000000 --- a/venv/lib/python3.9/site-packages/greenlet/greenlet.h +++ /dev/null @@ -1,164 +0,0 @@ -/* -*- indent-tabs-mode: nil; tab-width: 4; -*- */ - -/* Greenlet object interface */ - -#ifndef Py_GREENLETOBJECT_H -#define Py_GREENLETOBJECT_H - - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/* This is deprecated and undocumented. It does not change. */ -#define GREENLET_VERSION "1.0.0" - -#ifndef GREENLET_MODULE -#define implementation_ptr_t void* -#endif - -typedef struct _greenlet { - PyObject_HEAD - PyObject* weakreflist; - PyObject* dict; - implementation_ptr_t pimpl; -} PyGreenlet; - -#define PyGreenlet_Check(op) (op && PyObject_TypeCheck(op, &PyGreenlet_Type)) - - -/* C API functions */ - -/* Total number of symbols that are exported */ -#define PyGreenlet_API_pointers 12 - -#define PyGreenlet_Type_NUM 0 -#define PyExc_GreenletError_NUM 1 -#define PyExc_GreenletExit_NUM 2 - -#define PyGreenlet_New_NUM 3 -#define PyGreenlet_GetCurrent_NUM 4 -#define PyGreenlet_Throw_NUM 5 -#define PyGreenlet_Switch_NUM 6 -#define PyGreenlet_SetParent_NUM 7 - -#define PyGreenlet_MAIN_NUM 8 -#define PyGreenlet_STARTED_NUM 9 -#define PyGreenlet_ACTIVE_NUM 10 -#define PyGreenlet_GET_PARENT_NUM 11 - -#ifndef GREENLET_MODULE -/* This section is used by modules that uses the greenlet C API */ -static void** _PyGreenlet_API = NULL; - -# define PyGreenlet_Type \ - (*(PyTypeObject*)_PyGreenlet_API[PyGreenlet_Type_NUM]) - -# define PyExc_GreenletError \ - ((PyObject*)_PyGreenlet_API[PyExc_GreenletError_NUM]) - -# define PyExc_GreenletExit \ - ((PyObject*)_PyGreenlet_API[PyExc_GreenletExit_NUM]) - -/* - * PyGreenlet_New(PyObject *args) - * - * greenlet.greenlet(run, parent=None) - */ -# define PyGreenlet_New \ - (*(PyGreenlet * (*)(PyObject * run, PyGreenlet * parent)) \ - _PyGreenlet_API[PyGreenlet_New_NUM]) - -/* - * PyGreenlet_GetCurrent(void) - * - * greenlet.getcurrent() - */ -# define PyGreenlet_GetCurrent \ - (*(PyGreenlet * (*)(void)) _PyGreenlet_API[PyGreenlet_GetCurrent_NUM]) - -/* - * PyGreenlet_Throw( - * PyGreenlet *greenlet, - * PyObject *typ, - * PyObject *val, - * PyObject *tb) - * - * g.throw(...) - */ -# define PyGreenlet_Throw \ - (*(PyObject * (*)(PyGreenlet * self, \ - PyObject * typ, \ - PyObject * val, \ - PyObject * tb)) \ - _PyGreenlet_API[PyGreenlet_Throw_NUM]) - -/* - * PyGreenlet_Switch(PyGreenlet *greenlet, PyObject *args) - * - * g.switch(*args, **kwargs) - */ -# define PyGreenlet_Switch \ - (*(PyObject * \ - (*)(PyGreenlet * greenlet, PyObject * args, PyObject * kwargs)) \ - _PyGreenlet_API[PyGreenlet_Switch_NUM]) - -/* - * PyGreenlet_SetParent(PyObject *greenlet, PyObject *new_parent) - * - * g.parent = new_parent - */ -# define PyGreenlet_SetParent \ - (*(int (*)(PyGreenlet * greenlet, PyGreenlet * nparent)) \ - _PyGreenlet_API[PyGreenlet_SetParent_NUM]) - -/* - * PyGreenlet_GetParent(PyObject* greenlet) - * - * return greenlet.parent; - * - * This could return NULL even if there is no exception active. - * If it does not return NULL, you are responsible for decrementing the - * reference count. - */ -# define PyGreenlet_GetParent \ - (*(PyGreenlet* (*)(PyGreenlet*)) \ - _PyGreenlet_API[PyGreenlet_GET_PARENT_NUM]) - -/* - * deprecated, undocumented alias. - */ -# define PyGreenlet_GET_PARENT PyGreenlet_GetParent - -# define PyGreenlet_MAIN \ - (*(int (*)(PyGreenlet*)) \ - _PyGreenlet_API[PyGreenlet_MAIN_NUM]) - -# define PyGreenlet_STARTED \ - (*(int (*)(PyGreenlet*)) \ - _PyGreenlet_API[PyGreenlet_STARTED_NUM]) - -# define PyGreenlet_ACTIVE \ - (*(int (*)(PyGreenlet*)) \ - _PyGreenlet_API[PyGreenlet_ACTIVE_NUM]) - - - - -/* Macro that imports greenlet and initializes C API */ -/* NOTE: This has actually moved to ``greenlet._greenlet._C_API``, but we - keep the older definition to be sure older code that might have a copy of - the header still works. */ -# define PyGreenlet_Import() \ - { \ - _PyGreenlet_API = (void**)PyCapsule_Import("greenlet._C_API", 0); \ - } - -#endif /* GREENLET_MODULE */ - -#ifdef __cplusplus -} -#endif -#endif /* !Py_GREENLETOBJECT_H */ diff --git a/venv/lib/python3.9/site-packages/greenlet/greenlet_allocator.hpp b/venv/lib/python3.9/site-packages/greenlet/greenlet_allocator.hpp deleted file mode 100644 index dc2b969..0000000 --- a/venv/lib/python3.9/site-packages/greenlet/greenlet_allocator.hpp +++ /dev/null @@ -1,89 +0,0 @@ -#ifndef GREENLET_ALLOCATOR_HPP -#define GREENLET_ALLOCATOR_HPP - -#define PY_SSIZE_T_CLEAN -#include -#include -#include "greenlet_compiler_compat.hpp" -#include "greenlet_cpython_compat.hpp" - - -namespace greenlet -{ -#if defined(Py_GIL_DISABLED) -// Python on free threaded builds says this -// (https://docs.python.org/3/howto/free-threading-extensions.html#memory-allocation-apis): -// -// For thread-safety, the free-threaded build requires that only -// Python objects are allocated using the object domain, and that all -// Python object are allocated using that domain. -// -// This turns out to be important because the GC implementation on -// free threaded Python uses internal mimalloc APIs to find allocated -// objects. If we allocate non-PyObject objects using that API, then -// Bad Things could happen, including crashes and improper results. -// So in that case, we revert to standard C++ allocation. - - template - struct PythonAllocator : public std::allocator { - // This member is deprecated in C++17 and removed in C++20 - template< class U > - struct rebind { - typedef PythonAllocator other; - }; - }; - -#else - // This allocator is stateless; all instances are identical. - // It can *ONLY* be used when we're sure we're holding the GIL - // (Python's allocators require the GIL). - template - struct PythonAllocator : public std::allocator { - - PythonAllocator(const PythonAllocator& UNUSED(other)) - : std::allocator() - { - } - - PythonAllocator(const std::allocator other) - : std::allocator(other) - {} - - template - PythonAllocator(const std::allocator& other) - : std::allocator(other) - { - } - - PythonAllocator() : std::allocator() {} - - T* allocate(size_t number_objects, const void* UNUSED(hint)=0) - { - void* p; - if (number_objects == 1) - p = PyObject_Malloc(sizeof(T)); - else - p = PyMem_Malloc(sizeof(T) * number_objects); - return static_cast(p); - } - - void deallocate(T* t, size_t n) - { - void* p = t; - if (n == 1) { - PyObject_Free(p); - } - else - PyMem_Free(p); - } - // This member is deprecated in C++17 and removed in C++20 - template< class U > - struct rebind { - typedef PythonAllocator other; - }; - - }; -#endif // allocator type -} - -#endif diff --git a/venv/lib/python3.9/site-packages/greenlet/greenlet_compiler_compat.hpp b/venv/lib/python3.9/site-packages/greenlet/greenlet_compiler_compat.hpp deleted file mode 100644 index af24bd8..0000000 --- a/venv/lib/python3.9/site-packages/greenlet/greenlet_compiler_compat.hpp +++ /dev/null @@ -1,98 +0,0 @@ -/* -*- indent-tabs-mode: nil; tab-width: 4; -*- */ -#ifndef GREENLET_COMPILER_COMPAT_HPP -#define GREENLET_COMPILER_COMPAT_HPP - -/** - * Definitions to aid with compatibility with different compilers. - * - * .. caution:: Use extreme care with noexcept. - * Some compilers and runtimes, specifically gcc/libgcc/libstdc++ on - * Linux, implement stack unwinding by throwing an uncatchable - * exception, one that specifically does not appear to be an active - * exception to the rest of the runtime. If this happens while we're in a noexcept function, - * we have violated our dynamic exception contract, and so the runtime - * will call std::terminate(), which kills the process with the - * unhelpful message "terminate called without an active exception". - * - * This has happened in this scenario: A background thread is running - * a greenlet that has made a native call and released the GIL. - * Meanwhile, the main thread finishes and starts shutting down the - * interpreter. When the background thread is scheduled again and - * attempts to obtain the GIL, it notices that the interpreter is - * exiting and calls ``pthread_exit()``. This in turn starts to unwind - * the stack by throwing that exception. But we had the ``PyCall`` - * functions annotated as noexcept, so the runtime terminated us. - * - * #2 0x00007fab26fec2b7 in std::terminate() () from /lib/x86_64-linux-gnu/libstdc++.so.6 - * #3 0x00007fab26febb3c in __gxx_personality_v0 () from /lib/x86_64-linux-gnu/libstdc++.so.6 - * #4 0x00007fab26f34de6 in ?? () from /lib/x86_64-linux-gnu/libgcc_s.so.1 - * #6 0x00007fab276a34c6 in __GI___pthread_unwind at ./nptl/unwind.c:130 - * #7 0x00007fab2769bd3a in __do_cancel () at ../sysdeps/nptl/pthreadP.h:280 - * #8 __GI___pthread_exit (value=value@entry=0x0) at ./nptl/pthread_exit.c:36 - * #9 0x000000000052e567 in PyThread_exit_thread () at ../Python/thread_pthread.h:370 - * #10 0x00000000004d60b5 in take_gil at ../Python/ceval_gil.h:224 - * #11 0x00000000004d65f9 in PyEval_RestoreThread at ../Python/ceval.c:467 - * #12 0x000000000060cce3 in setipaddr at ../Modules/socketmodule.c:1203 - * #13 0x00000000006101cd in socket_gethostbyname - */ - -#include - -# define G_NO_COPIES_OF_CLS(Cls) private: \ - Cls(const Cls& other) = delete; \ - Cls& operator=(const Cls& other) = delete - -# define G_NO_ASSIGNMENT_OF_CLS(Cls) private: \ - Cls& operator=(const Cls& other) = delete - -# define G_NO_COPY_CONSTRUCTOR_OF_CLS(Cls) private: \ - Cls(const Cls& other) = delete; - - -// CAUTION: MSVC is stupidly picky: -// -// "The compiler ignores, without warning, any __declspec keywords -// placed after * or & and in front of the variable identifier in a -// declaration." -// (https://docs.microsoft.com/en-us/cpp/cpp/declspec?view=msvc-160) -// -// So pointer return types must be handled differently (because of the -// trailing *), or you get inscrutable compiler warnings like "error -// C2059: syntax error: ''" -// -// In C++ 11, there is a standard syntax for attributes, and -// GCC defines an attribute to use with this: [[gnu:noinline]]. -// In the future, this is expected to become standard. - -#if defined(__GNUC__) || defined(__clang__) -/* We used to check for GCC 4+ or 3.4+, but those compilers are - laughably out of date. Just assume they support it. */ -# define GREENLET_NOINLINE(name) __attribute__((noinline)) name -# define GREENLET_NOINLINE_P(rtype, name) rtype __attribute__((noinline)) name -# define UNUSED(x) UNUSED_ ## x __attribute__((__unused__)) -#elif defined(_MSC_VER) -/* We used to check for && (_MSC_VER >= 1300) but that's also out of date. */ -# define GREENLET_NOINLINE(name) __declspec(noinline) name -# define GREENLET_NOINLINE_P(rtype, name) __declspec(noinline) rtype name -# define UNUSED(x) UNUSED_ ## x -#endif - -#if defined(_MSC_VER) -# define G_NOEXCEPT_WIN32 noexcept -#else -# define G_NOEXCEPT_WIN32 -#endif - -#if defined(__GNUC__) && defined(__POWERPC__) && defined(__APPLE__) -// 32-bit PPC/MacOSX. Only known to be tested on unreleased versions -// of macOS 10.6 using a macports build gcc 14. It appears that -// running C++ destructors of thread-local variables is broken. - -// See https://github.com/python-greenlet/greenlet/pull/419 -# define GREENLET_BROKEN_THREAD_LOCAL_CLEANUP_JUST_LEAK 1 -#else -# define GREENLET_BROKEN_THREAD_LOCAL_CLEANUP_JUST_LEAK 0 -#endif - - -#endif diff --git a/venv/lib/python3.9/site-packages/greenlet/greenlet_cpython_compat.hpp b/venv/lib/python3.9/site-packages/greenlet/greenlet_cpython_compat.hpp deleted file mode 100644 index a3b3850..0000000 --- a/venv/lib/python3.9/site-packages/greenlet/greenlet_cpython_compat.hpp +++ /dev/null @@ -1,150 +0,0 @@ -/* -*- indent-tabs-mode: nil; tab-width: 4; -*- */ -#ifndef GREENLET_CPYTHON_COMPAT_H -#define GREENLET_CPYTHON_COMPAT_H - -/** - * Helpers for compatibility with multiple versions of CPython. - */ - -#define PY_SSIZE_T_CLEAN -#include "Python.h" - - -#if PY_VERSION_HEX >= 0x30A00B1 -# define GREENLET_PY310 1 -#else -# define GREENLET_PY310 0 -#endif - -/* -Python 3.10 beta 1 changed tstate->use_tracing to a nested cframe member. -See https://github.com/python/cpython/pull/25276 -We have to save and restore this as well. - -Python 3.13 removed PyThreadState.cframe (GH-108035). -*/ -#if GREENLET_PY310 && PY_VERSION_HEX < 0x30D0000 -# define GREENLET_USE_CFRAME 1 -#else -# define GREENLET_USE_CFRAME 0 -#endif - - -#if PY_VERSION_HEX >= 0x30B00A4 -/* -Greenlet won't compile on anything older than Python 3.11 alpha 4 (see -https://bugs.python.org/issue46090). Summary of breaking internal changes: -- Python 3.11 alpha 1 changed how frame objects are represented internally. - - https://github.com/python/cpython/pull/30122 -- Python 3.11 alpha 3 changed how recursion limits are stored. - - https://github.com/python/cpython/pull/29524 -- Python 3.11 alpha 4 changed how exception state is stored. It also includes a - change to help greenlet save and restore the interpreter frame "data stack". - - https://github.com/python/cpython/pull/30122 - - https://github.com/python/cpython/pull/30234 -*/ -# define GREENLET_PY311 1 -#else -# define GREENLET_PY311 0 -#endif - - -#if PY_VERSION_HEX >= 0x30C0000 -# define GREENLET_PY312 1 -#else -# define GREENLET_PY312 0 -#endif - -#if PY_VERSION_HEX >= 0x30D0000 -# define GREENLET_PY313 1 -#else -# define GREENLET_PY313 0 -#endif - -#if PY_VERSION_HEX >= 0x30E0000 -# define GREENLET_PY314 1 -#else -# define GREENLET_PY314 0 -#endif - -#ifndef Py_SET_REFCNT -/* Py_REFCNT and Py_SIZE macros are converted to functions -https://bugs.python.org/issue39573 */ -# define Py_SET_REFCNT(obj, refcnt) Py_REFCNT(obj) = (refcnt) -#endif - -#ifdef _Py_DEC_REFTOTAL -# define GREENLET_Py_DEC_REFTOTAL _Py_DEC_REFTOTAL -#else -/* _Py_DEC_REFTOTAL macro has been removed from Python 3.9 by: - https://github.com/python/cpython/commit/49932fec62c616ec88da52642339d83ae719e924 - - The symbol we use to replace it was removed by at least 3.12. -*/ -# ifdef Py_REF_DEBUG -# if GREENLET_PY312 -# define GREENLET_Py_DEC_REFTOTAL -# else -# define GREENLET_Py_DEC_REFTOTAL _Py_RefTotal-- -# endif -# else -# define GREENLET_Py_DEC_REFTOTAL -# endif -#endif -// Define these flags like Cython does if we're on an old version. -#ifndef Py_TPFLAGS_CHECKTYPES - #define Py_TPFLAGS_CHECKTYPES 0 -#endif -#ifndef Py_TPFLAGS_HAVE_INDEX - #define Py_TPFLAGS_HAVE_INDEX 0 -#endif -#ifndef Py_TPFLAGS_HAVE_NEWBUFFER - #define Py_TPFLAGS_HAVE_NEWBUFFER 0 -#endif - -#ifndef Py_TPFLAGS_HAVE_VERSION_TAG - #define Py_TPFLAGS_HAVE_VERSION_TAG 0 -#endif - -#define G_TPFLAGS_DEFAULT Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_VERSION_TAG | Py_TPFLAGS_CHECKTYPES | Py_TPFLAGS_HAVE_NEWBUFFER | Py_TPFLAGS_HAVE_GC - - -#if PY_VERSION_HEX < 0x03090000 -// The official version only became available in 3.9 -# define PyObject_GC_IsTracked(o) _PyObject_GC_IS_TRACKED(o) -#endif - - -// bpo-43760 added PyThreadState_EnterTracing() to Python 3.11.0a2 -#if PY_VERSION_HEX < 0x030B00A2 && !defined(PYPY_VERSION) -static inline void PyThreadState_EnterTracing(PyThreadState *tstate) -{ - tstate->tracing++; -#if PY_VERSION_HEX >= 0x030A00A1 - tstate->cframe->use_tracing = 0; -#else - tstate->use_tracing = 0; -#endif -} -#endif - -// bpo-43760 added PyThreadState_LeaveTracing() to Python 3.11.0a2 -#if PY_VERSION_HEX < 0x030B00A2 && !defined(PYPY_VERSION) -static inline void PyThreadState_LeaveTracing(PyThreadState *tstate) -{ - tstate->tracing--; - int use_tracing = (tstate->c_tracefunc != NULL - || tstate->c_profilefunc != NULL); -#if PY_VERSION_HEX >= 0x030A00A1 - tstate->cframe->use_tracing = use_tracing; -#else - tstate->use_tracing = use_tracing; -#endif -} -#endif - -#if !defined(Py_C_RECURSION_LIMIT) && defined(C_RECURSION_LIMIT) -# define Py_C_RECURSION_LIMIT C_RECURSION_LIMIT -#endif - -#endif /* GREENLET_CPYTHON_COMPAT_H */ diff --git a/venv/lib/python3.9/site-packages/greenlet/greenlet_exceptions.hpp b/venv/lib/python3.9/site-packages/greenlet/greenlet_exceptions.hpp deleted file mode 100644 index 617f07c..0000000 --- a/venv/lib/python3.9/site-packages/greenlet/greenlet_exceptions.hpp +++ /dev/null @@ -1,171 +0,0 @@ -#ifndef GREENLET_EXCEPTIONS_HPP -#define GREENLET_EXCEPTIONS_HPP - -#define PY_SSIZE_T_CLEAN -#include -#include -#include - -#ifdef __clang__ -# pragma clang diagnostic push -# pragma clang diagnostic ignored "-Wunused-function" -#endif - -namespace greenlet { - - class PyErrOccurred : public std::runtime_error - { - public: - - // CAUTION: In debug builds, may run arbitrary Python code. - static const PyErrOccurred - from_current() - { - assert(PyErr_Occurred()); -#ifndef NDEBUG - // This is not exception safe, and - // not necessarily safe in general (what if it switches?) - // But we only do this in debug mode, where we are in - // tight control of what exceptions are getting raised and - // can prevent those issues. - - // You can't call PyObject_Str with a pending exception. - PyObject* typ; - PyObject* val; - PyObject* tb; - - PyErr_Fetch(&typ, &val, &tb); - PyObject* typs = PyObject_Str(typ); - PyObject* vals = PyObject_Str(val ? val : typ); - const char* typ_msg = PyUnicode_AsUTF8(typs); - const char* val_msg = PyUnicode_AsUTF8(vals); - PyErr_Restore(typ, val, tb); - - std::string msg(typ_msg); - msg += ": "; - msg += val_msg; - PyErrOccurred ex(msg); - Py_XDECREF(typs); - Py_XDECREF(vals); - - return ex; -#else - return PyErrOccurred(); -#endif - } - - PyErrOccurred() : std::runtime_error("") - { - assert(PyErr_Occurred()); - } - - PyErrOccurred(const std::string& msg) : std::runtime_error(msg) - { - assert(PyErr_Occurred()); - } - - PyErrOccurred(PyObject* exc_kind, const char* const msg) - : std::runtime_error(msg) - { - PyErr_SetString(exc_kind, msg); - } - - PyErrOccurred(PyObject* exc_kind, const std::string msg) - : std::runtime_error(msg) - { - // This copies the c_str, so we don't have any lifetime - // issues to worry about. - PyErr_SetString(exc_kind, msg.c_str()); - } - - PyErrOccurred(PyObject* exc_kind, - const std::string msg, //This is the format - //string; that's not - //usually safe! - - PyObject* borrowed_obj_one, PyObject* borrowed_obj_two) - : std::runtime_error(msg) - { - - //This is designed specifically for the - //``check_switch_allowed`` function. - - // PyObject_Str and PyObject_Repr are safe to call with - // NULL pointers; they return the string "" in that - // case. - // This function always returns null. - PyErr_Format(exc_kind, - msg.c_str(), - borrowed_obj_one, borrowed_obj_two); - } - }; - - class TypeError : public PyErrOccurred - { - public: - TypeError(const char* const what) - : PyErrOccurred(PyExc_TypeError, what) - { - } - TypeError(const std::string what) - : PyErrOccurred(PyExc_TypeError, what) - { - } - }; - - class ValueError : public PyErrOccurred - { - public: - ValueError(const char* const what) - : PyErrOccurred(PyExc_ValueError, what) - { - } - }; - - class AttributeError : public PyErrOccurred - { - public: - AttributeError(const char* const what) - : PyErrOccurred(PyExc_AttributeError, what) - { - } - }; - - /** - * Calls `Py_FatalError` when constructed, so you can't actually - * throw this. It just makes static analysis easier. - */ - class PyFatalError : public std::runtime_error - { - public: - PyFatalError(const char* const msg) - : std::runtime_error(msg) - { - Py_FatalError(msg); - } - }; - - static inline PyObject* - Require(PyObject* p, const std::string& msg="") - { - if (!p) { - throw PyErrOccurred(msg); - } - return p; - }; - - static inline void - Require(const int retval) - { - if (retval < 0) { - throw PyErrOccurred(); - } - }; - - -}; -#ifdef __clang__ -# pragma clang diagnostic pop -#endif - -#endif diff --git a/venv/lib/python3.9/site-packages/greenlet/greenlet_internal.hpp b/venv/lib/python3.9/site-packages/greenlet/greenlet_internal.hpp deleted file mode 100644 index f2b15d5..0000000 --- a/venv/lib/python3.9/site-packages/greenlet/greenlet_internal.hpp +++ /dev/null @@ -1,107 +0,0 @@ -/* -*- indent-tabs-mode: nil; tab-width: 4; -*- */ -#ifndef GREENLET_INTERNAL_H -#define GREENLET_INTERNAL_H -#ifdef __clang__ -# pragma clang diagnostic push -# pragma clang diagnostic ignored "-Wunused-function" -#endif - -/** - * Implementation helpers. - * - * C++ templates and inline functions should go here. - */ -#define PY_SSIZE_T_CLEAN -#include "greenlet_compiler_compat.hpp" -#include "greenlet_cpython_compat.hpp" -#include "greenlet_exceptions.hpp" -#include "TGreenlet.hpp" -#include "greenlet_allocator.hpp" - -#include -#include - -#define GREENLET_MODULE -struct _greenlet; -typedef struct _greenlet PyGreenlet; -namespace greenlet { - - class ThreadState; - // We can't use the PythonAllocator for this, because we push to it - // from the thread state destructor, which doesn't have the GIL, - // and Python's allocators can only be called with the GIL. - typedef std::vector cleanup_queue_t; - -}; - - -#define implementation_ptr_t greenlet::Greenlet* - - -#include "greenlet.h" - -void -greenlet::refs::MainGreenletExactChecker(void *p) -{ - if (!p) { - return; - } - // We control the class of the main greenlet exactly. - if (Py_TYPE(p) != &PyGreenlet_Type) { - std::string err("MainGreenlet: Expected exactly a greenlet, not a "); - err += Py_TYPE(p)->tp_name; - throw greenlet::TypeError(err); - } - - // Greenlets from dead threads no longer respond to main() with a - // true value; so in that case we need to perform an additional - // check. - Greenlet* g = static_cast(p)->pimpl; - if (g->main()) { - return; - } - if (!dynamic_cast(g)) { - std::string err("MainGreenlet: Expected exactly a main greenlet, not a "); - err += Py_TYPE(p)->tp_name; - throw greenlet::TypeError(err); - } -} - - - -template -inline greenlet::Greenlet* greenlet::refs::_OwnedGreenlet::operator->() const noexcept -{ - return reinterpret_cast(this->p)->pimpl; -} - -template -inline greenlet::Greenlet* greenlet::refs::_BorrowedGreenlet::operator->() const noexcept -{ - return reinterpret_cast(this->p)->pimpl; -} - -#include -#include - - -extern PyTypeObject PyGreenlet_Type; - - - -/** - * Forward declarations needed in multiple files. - */ -static PyObject* green_switch(PyGreenlet* self, PyObject* args, PyObject* kwargs); - - -#ifdef __clang__ -# pragma clang diagnostic pop -#endif - - -#endif - -// Local Variables: -// flycheck-clang-include-path: ("../../include" "/opt/local/Library/Frameworks/Python.framework/Versions/3.10/include/python3.10") -// End: diff --git a/venv/lib/python3.9/site-packages/greenlet/greenlet_msvc_compat.hpp b/venv/lib/python3.9/site-packages/greenlet/greenlet_msvc_compat.hpp deleted file mode 100644 index c00245b..0000000 --- a/venv/lib/python3.9/site-packages/greenlet/greenlet_msvc_compat.hpp +++ /dev/null @@ -1,91 +0,0 @@ -#ifndef GREENLET_MSVC_COMPAT_HPP -#define GREENLET_MSVC_COMPAT_HPP -/* - * Support for MSVC on Windows. - * - * Beginning with Python 3.14, some of the internal - * include files we need are not compatible with MSVC - * in C++ mode: - * - * internal\pycore_stackref.h(253): error C4576: a parenthesized type - * followed by an initializer list is a non-standard explicit type conversion syntax - * - * This file is included from ``internal/pycore_interpframe.h``, which - * we need for the ``_PyFrame_IsIncomplete`` API. - * - * Unfortunately, that API is a ``static inline`` function, as are a - * bunch of the functions it calls. The only solution seems to be to - * copy those definitions and the supporting inline functions here. - * - * Now, this makes us VERY fragile to changes in those functions. Because - * they're internal and static, the CPython devs might feel free to change - * them in even minor versions, meaning that we could runtime link and load, - * but still crash. We have that problem on all platforms though. It's just worse - * here because we have to keep copying the updated definitions. - */ -#include -#include "greenlet_cpython_compat.hpp" - -// This file is only included on 3.14+ - -extern "C" { - -// pycore_code.h ---------------- -#define _PyCode_CODE(CO) _Py_RVALUE((_Py_CODEUNIT *)(CO)->co_code_adaptive) -// End pycore_code.h ---------- - -// pycore_interpframe.h ---------- -#if !defined(Py_GIL_DISABLED) && defined(Py_STACKREF_DEBUG) - -#define Py_TAG_BITS 0 -#else -#define Py_TAG_BITS ((uintptr_t)1) -#define Py_TAG_DEFERRED (1) -#endif - - -static const _PyStackRef PyStackRef_NULL = { .bits = Py_TAG_DEFERRED}; -#define PyStackRef_IsNull(stackref) ((stackref).bits == PyStackRef_NULL.bits) - -static inline PyObject * -PyStackRef_AsPyObjectBorrow(_PyStackRef stackref) -{ - PyObject *cleared = ((PyObject *)((stackref).bits & (~Py_TAG_BITS))); - return cleared; -} - -static inline PyCodeObject *_PyFrame_GetCode(_PyInterpreterFrame *f) { - assert(!PyStackRef_IsNull(f->f_executable)); - PyObject *executable = PyStackRef_AsPyObjectBorrow(f->f_executable); - assert(PyCode_Check(executable)); - return (PyCodeObject *)executable; -} - - -static inline _Py_CODEUNIT * -_PyFrame_GetBytecode(_PyInterpreterFrame *f) -{ -#ifdef Py_GIL_DISABLED - PyCodeObject *co = _PyFrame_GetCode(f); - _PyCodeArray *tlbc = _PyCode_GetTLBCArray(co); - assert(f->tlbc_index >= 0 && f->tlbc_index < tlbc->size); - return (_Py_CODEUNIT *)tlbc->entries[f->tlbc_index]; -#else - return _PyCode_CODE(_PyFrame_GetCode(f)); -#endif -} - -static inline bool //_Py_NO_SANITIZE_THREAD -_PyFrame_IsIncomplete(_PyInterpreterFrame *frame) -{ - if (frame->owner >= FRAME_OWNED_BY_INTERPRETER) { - return true; - } - return frame->owner != FRAME_OWNED_BY_GENERATOR && - frame->instr_ptr < _PyFrame_GetBytecode(frame) + - _PyFrame_GetCode(frame)->_co_firsttraceable; -} -// pycore_interpframe.h ---------- - -} -#endif // GREENLET_MSVC_COMPAT_HPP diff --git a/venv/lib/python3.9/site-packages/greenlet/greenlet_refs.hpp b/venv/lib/python3.9/site-packages/greenlet/greenlet_refs.hpp deleted file mode 100644 index b7e5e3f..0000000 --- a/venv/lib/python3.9/site-packages/greenlet/greenlet_refs.hpp +++ /dev/null @@ -1,1118 +0,0 @@ -#ifndef GREENLET_REFS_HPP -#define GREENLET_REFS_HPP - -#define PY_SSIZE_T_CLEAN -#include - -#include - -//#include "greenlet_internal.hpp" -#include "greenlet_compiler_compat.hpp" -#include "greenlet_cpython_compat.hpp" -#include "greenlet_exceptions.hpp" - -struct _greenlet; -struct _PyMainGreenlet; - -typedef struct _greenlet PyGreenlet; -extern PyTypeObject PyGreenlet_Type; - - -#ifdef GREENLET_USE_STDIO -#include -using std::cerr; -using std::endl; -#endif - -namespace greenlet -{ - class Greenlet; - - namespace refs - { - // Type checkers throw a TypeError if the argument is not - // null, and isn't of the required Python type. - // (We can't use most of the defined type checkers - // like PyList_Check, etc, directly, because they are - // implemented as macros.) - typedef void (*TypeChecker)(void*); - - void - NoOpChecker(void*) - { - return; - } - - void - GreenletChecker(void *p) - { - if (!p) { - return; - } - - PyTypeObject* typ = Py_TYPE(p); - // fast, common path. (PyObject_TypeCheck is a macro or - // static inline function, and it also does a - // direct comparison of the type pointers, but its fast - // path only handles one type) - if (typ == &PyGreenlet_Type) { - return; - } - - if (!PyObject_TypeCheck(p, &PyGreenlet_Type)) { - std::string err("GreenletChecker: Expected any type of greenlet, not "); - err += Py_TYPE(p)->tp_name; - throw TypeError(err); - } - } - - void - MainGreenletExactChecker(void *p); - - template - class PyObjectPointer; - - template - class OwnedReference; - - - template - class BorrowedReference; - - typedef BorrowedReference BorrowedObject; - typedef OwnedReference OwnedObject; - - class ImmortalObject; - class ImmortalString; - - template - class _OwnedGreenlet; - - typedef _OwnedGreenlet OwnedGreenlet; - typedef _OwnedGreenlet OwnedMainGreenlet; - - template - class _BorrowedGreenlet; - - typedef _BorrowedGreenlet BorrowedGreenlet; - - void - ContextExactChecker(void *p) - { - if (!p) { - return; - } - if (!PyContext_CheckExact(p)) { - throw TypeError( - "greenlet context must be a contextvars.Context or None" - ); - } - } - - typedef OwnedReference OwnedContext; - } -} - -namespace greenlet { - - - namespace refs { - // A set of classes to make reference counting rules in python - // code explicit. - // - // Rules of use: - // (1) Functions returning a new reference that the caller of the - // function is expected to dispose of should return a - // ``OwnedObject`` object. This object automatically releases its - // reference when it goes out of scope. It works like a ``std::shared_ptr`` - // and can be copied or used as a function parameter (but don't do - // that). Note that constructing a ``OwnedObject`` from a - // PyObject* steals the reference. - // (2) Parameters to functions should be either a - // ``OwnedObject&``, or, more generally, a ``PyObjectPointer&``. - // If the function needs to create its own new reference, it can - // do so by copying to a local ``OwnedObject``. - // (3) Functions returning an existing pointer that is NOT - // incref'd, and which the caller MUST NOT decref, - // should return a ``BorrowedObject``. - - // XXX: The following two paragraphs do not hold for all platforms. - // Notably, 32-bit PPC Linux passes structs by reference, not by - // value, so this actually doesn't work. (Although that's the only - // platform that doesn't work on.) DO NOT ATTEMPT IT. The - // unfortunate consequence of that is that the slots which we - // *know* are already type safe will wind up calling the type - // checker function (when we had the slots accepting - // BorrowedGreenlet, this was bypassed), so this slows us down. - // TODO: Optimize this again. - - // For a class with a single pointer member, whose constructor - // does nothing but copy a pointer parameter into the member, and - // which can then be converted back to the pointer type, compilers - // generate code that's the same as just passing the pointer. - // That is, func(BorrowedObject x) called like ``PyObject* p = - // ...; f(p)`` has 0 overhead. Similarly, they "unpack" to the - // pointer type with 0 overhead. - // - // If there are no virtual functions, no complex inheritance (maybe?) and - // no destructor, these can be directly used as parameters in - // Python callbacks like tp_init: the layout is the same as a - // single pointer. Only subclasses with trivial constructors that - // do nothing but set the single pointer member are safe to use - // that way. - - - // This is the base class for things that can be done with a - // PyObject pointer. It assumes nothing about memory management. - // NOTE: Nothing is virtual, so subclasses shouldn't add new - // storage fields or try to override these methods. - template - class PyObjectPointer - { - public: - typedef T PyType; - protected: - T* p; - public: - PyObjectPointer(T* it=nullptr) : p(it) - { - TC(p); - } - - // We don't allow automatic casting to PyObject* at this - // level, because then we could be passed to Py_DECREF/INCREF, - // but we want nothing to do with memory management. If you - // know better, then you can use the get() method, like on a - // std::shared_ptr. Except we name it borrow() to clarify that - // if this is a reference-tracked object, the pointer you get - // back will go away when the object does. - // TODO: This should probably not exist here, but be moved - // down to relevant sub-types. - - T* borrow() const noexcept - { - return this->p; - } - - PyObject* borrow_o() const noexcept - { - return reinterpret_cast(this->p); - } - - T* operator->() const noexcept - { - return this->p; - } - - bool is_None() const noexcept - { - return this->p == Py_None; - } - - PyObject* acquire_or_None() const noexcept - { - PyObject* result = this->p ? reinterpret_cast(this->p) : Py_None; - Py_INCREF(result); - return result; - } - - explicit operator bool() const noexcept - { - return this->p != nullptr; - } - - bool operator!() const noexcept - { - return this->p == nullptr; - } - - Py_ssize_t REFCNT() const noexcept - { - return p ? Py_REFCNT(p) : -42; - } - - PyTypeObject* TYPE() const noexcept - { - return p ? Py_TYPE(p) : nullptr; - } - - inline OwnedObject PyStr() const noexcept; - inline const std::string as_str() const noexcept; - inline OwnedObject PyGetAttr(const ImmortalObject& name) const noexcept; - inline OwnedObject PyRequireAttr(const char* const name) const; - inline OwnedObject PyRequireAttr(const ImmortalString& name) const; - inline OwnedObject PyCall(const BorrowedObject& arg) const; - inline OwnedObject PyCall(PyGreenlet* arg) const ; - inline OwnedObject PyCall(PyObject* arg) const ; - // PyObject_Call(this, args, kwargs); - inline OwnedObject PyCall(const BorrowedObject args, - const BorrowedObject kwargs) const; - inline OwnedObject PyCall(const OwnedObject& args, - const OwnedObject& kwargs) const; - - protected: - void _set_raw_pointer(void* t) - { - TC(t); - p = reinterpret_cast(t); - } - void* _get_raw_pointer() const - { - return p; - } - }; - -#ifdef GREENLET_USE_STDIO - template - std::ostream& operator<<(std::ostream& os, const PyObjectPointer& s) - { - const std::type_info& t = typeid(s); - os << t.name() - << "(addr=" << s.borrow() - << ", refcnt=" << s.REFCNT() - << ", value=" << s.as_str() - << ")"; - - return os; - } -#endif - - template - inline bool operator==(const PyObjectPointer& lhs, const PyObject* const rhs) noexcept - { - return static_cast(lhs.borrow_o()) == static_cast(rhs); - } - - template - inline bool operator==(const PyObjectPointer& lhs, const PyObjectPointer& rhs) noexcept - { - return lhs.borrow_o() == rhs.borrow_o(); - } - - template - inline bool operator!=(const PyObjectPointer& lhs, - const PyObjectPointer& rhs) noexcept - { - return lhs.borrow_o() != rhs.borrow_o(); - } - - template - class OwnedReference : public PyObjectPointer - { - private: - friend class OwnedList; - - protected: - explicit OwnedReference(T* it) : PyObjectPointer(it) - { - } - - public: - - // Constructors - - static OwnedReference consuming(PyObject* p) - { - return OwnedReference(reinterpret_cast(p)); - } - - static OwnedReference owning(T* p) - { - OwnedReference result(p); - Py_XINCREF(result.p); - return result; - } - - OwnedReference() : PyObjectPointer(nullptr) - {} - - explicit OwnedReference(const PyObjectPointer<>& other) - : PyObjectPointer(nullptr) - { - T* op = other.borrow(); - TC(op); - this->p = other.borrow(); - Py_XINCREF(this->p); - } - - // It would be good to make use of the C++11 distinction - // between move and copy operations, e.g., constructing from a - // pointer should be a move operation. - // In the common case of ``OwnedObject x = Py_SomeFunction()``, - // the call to the copy constructor will be elided completely. - OwnedReference(const OwnedReference& other) - : PyObjectPointer(other.p) - { - Py_XINCREF(this->p); - } - - static OwnedReference None() - { - Py_INCREF(Py_None); - return OwnedReference(Py_None); - } - - // We can assign from exactly our type without any extra checking - OwnedReference& operator=(const OwnedReference& other) - { - Py_XINCREF(other.p); - const T* tmp = this->p; - this->p = other.p; - Py_XDECREF(tmp); - return *this; - } - - OwnedReference& operator=(const BorrowedReference other) - { - return this->operator=(other.borrow()); - } - - OwnedReference& operator=(T* const other) - { - TC(other); - Py_XINCREF(other); - T* tmp = this->p; - this->p = other; - Py_XDECREF(tmp); - return *this; - } - - // We can assign from an arbitrary reference type - // if it passes our check. - template - OwnedReference& operator=(const OwnedReference& other) - { - X* op = other.borrow(); - TC(op); - return this->operator=(reinterpret_cast(op)); - } - - inline void steal(T* other) - { - assert(this->p == nullptr); - TC(other); - this->p = other; - } - - T* relinquish_ownership() - { - T* result = this->p; - this->p = nullptr; - return result; - } - - T* acquire() const - { - // Return a new reference. - // TODO: This may go away when we have reference objects - // throughout the code. - Py_XINCREF(this->p); - return this->p; - } - - // Nothing else declares a destructor, we're the leaf, so we - // should be able to get away without virtual. - ~OwnedReference() - { - Py_CLEAR(this->p); - } - - void CLEAR() - { - Py_CLEAR(this->p); - assert(this->p == nullptr); - } - }; - - static inline - void operator<<=(PyObject*& target, OwnedObject& o) - { - target = o.relinquish_ownership(); - } - - - class NewReference : public OwnedObject - { - private: - G_NO_COPIES_OF_CLS(NewReference); - public: - // Consumes the reference. Only use this - // for API return values. - NewReference(PyObject* it) : OwnedObject(it) - { - } - }; - - class NewDictReference : public NewReference - { - private: - G_NO_COPIES_OF_CLS(NewDictReference); - public: - NewDictReference() : NewReference(PyDict_New()) - { - if (!this->p) { - throw PyErrOccurred(); - } - } - - void SetItem(const char* const key, PyObject* value) - { - Require(PyDict_SetItemString(this->p, key, value)); - } - - void SetItem(const PyObjectPointer<>& key, PyObject* value) - { - Require(PyDict_SetItem(this->p, key.borrow_o(), value)); - } - }; - - template - class _OwnedGreenlet: public OwnedReference - { - private: - protected: - _OwnedGreenlet(T* it) : OwnedReference(it) - {} - - public: - _OwnedGreenlet() : OwnedReference() - {} - - _OwnedGreenlet(const _OwnedGreenlet& other) : OwnedReference(other) - { - } - _OwnedGreenlet(OwnedMainGreenlet& other) : - OwnedReference(reinterpret_cast(other.acquire())) - { - } - _OwnedGreenlet(const BorrowedGreenlet& other); - // Steals a reference. - static _OwnedGreenlet consuming(PyGreenlet* it) - { - return _OwnedGreenlet(reinterpret_cast(it)); - } - - inline _OwnedGreenlet& operator=(const OwnedGreenlet& other) - { - return this->operator=(other.borrow()); - } - - inline _OwnedGreenlet& operator=(const BorrowedGreenlet& other); - - _OwnedGreenlet& operator=(const OwnedMainGreenlet& other) - { - PyGreenlet* owned = other.acquire(); - Py_XDECREF(this->p); - this->p = reinterpret_cast(owned); - return *this; - } - - _OwnedGreenlet& operator=(T* const other) - { - OwnedReference::operator=(other); - return *this; - } - - T* relinquish_ownership() - { - T* result = this->p; - this->p = nullptr; - return result; - } - - PyObject* relinquish_ownership_o() - { - return reinterpret_cast(relinquish_ownership()); - } - - inline Greenlet* operator->() const noexcept; - inline operator Greenlet*() const noexcept; - }; - - template - class BorrowedReference : public PyObjectPointer - { - public: - // Allow implicit creation from PyObject* pointers as we - // transition to using these classes. Also allow automatic - // conversion to PyObject* for passing to C API calls and even - // for Py_INCREF/DECREF, because we ourselves do no memory management. - BorrowedReference(T* it) : PyObjectPointer(it) - {} - - BorrowedReference(const PyObjectPointer& ref) : PyObjectPointer(ref.borrow()) - {} - - BorrowedReference() : PyObjectPointer(nullptr) - {} - - operator T*() const - { - return this->p; - } - }; - - typedef BorrowedReference BorrowedObject; - //typedef BorrowedReference BorrowedGreenlet; - - template - class _BorrowedGreenlet : public BorrowedReference - { - public: - _BorrowedGreenlet() : - BorrowedReference(nullptr) - {} - - _BorrowedGreenlet(T* it) : - BorrowedReference(it) - {} - - _BorrowedGreenlet(const BorrowedObject& it); - - _BorrowedGreenlet(const OwnedGreenlet& it) : - BorrowedReference(it.borrow()) - {} - - _BorrowedGreenlet& operator=(const BorrowedObject& other); - - // We get one of these for PyGreenlet, but one for PyObject - // is handy as well - operator PyObject*() const - { - return reinterpret_cast(this->p); - } - Greenlet* operator->() const noexcept; - operator Greenlet*() const noexcept; - }; - - typedef _BorrowedGreenlet BorrowedGreenlet; - - template - _OwnedGreenlet::_OwnedGreenlet(const BorrowedGreenlet& other) - : OwnedReference(reinterpret_cast(other.borrow())) - { - Py_XINCREF(this->p); - } - - - class BorrowedMainGreenlet - : public _BorrowedGreenlet - { - public: - BorrowedMainGreenlet(const OwnedMainGreenlet& it) : - _BorrowedGreenlet(it.borrow()) - {} - BorrowedMainGreenlet(PyGreenlet* it=nullptr) - : _BorrowedGreenlet(it) - {} - }; - - template - _OwnedGreenlet& _OwnedGreenlet::operator=(const BorrowedGreenlet& other) - { - return this->operator=(other.borrow()); - } - - - class ImmortalObject : public PyObjectPointer<> - { - private: - G_NO_ASSIGNMENT_OF_CLS(ImmortalObject); - public: - explicit ImmortalObject(PyObject* it) : PyObjectPointer<>(it) - { - } - - ImmortalObject(const ImmortalObject& other) - : PyObjectPointer<>(other.p) - { - - } - - /** - * Become the new owner of the object. Does not change the - * reference count. - */ - ImmortalObject& operator=(PyObject* it) - { - assert(this->p == nullptr); - this->p = it; - return *this; - } - - static ImmortalObject consuming(PyObject* it) - { - return ImmortalObject(it); - } - - inline operator PyObject*() const - { - return this->p; - } - }; - - class ImmortalString : public ImmortalObject - { - private: - G_NO_COPIES_OF_CLS(ImmortalString); - const char* str; - public: - ImmortalString(const char* const str) : - ImmortalObject(str ? Require(PyUnicode_InternFromString(str)) : nullptr) - { - this->str = str; - } - - inline ImmortalString& operator=(const char* const str) - { - if (!this->p) { - this->p = Require(PyUnicode_InternFromString(str)); - this->str = str; - } - else { - assert(this->str == str); - } - return *this; - } - - inline operator std::string() const - { - return this->str; - } - - }; - - class ImmortalEventName : public ImmortalString - { - private: - G_NO_COPIES_OF_CLS(ImmortalEventName); - public: - ImmortalEventName(const char* const str) : ImmortalString(str) - {} - }; - - class ImmortalException : public ImmortalObject - { - private: - G_NO_COPIES_OF_CLS(ImmortalException); - public: - ImmortalException(const char* const name, PyObject* base=nullptr) : - ImmortalObject(name - // Python 2.7 isn't const correct - ? Require(PyErr_NewException((char*)name, base, nullptr)) - : nullptr) - {} - - inline bool PyExceptionMatches() const - { - return PyErr_ExceptionMatches(this->p) > 0; - } - - }; - - template - inline OwnedObject PyObjectPointer::PyStr() const noexcept - { - if (!this->p) { - return OwnedObject(); - } - return OwnedObject::consuming(PyObject_Str(reinterpret_cast(this->p))); - } - - template - inline const std::string PyObjectPointer::as_str() const noexcept - { - // NOTE: This is not Python exception safe. - if (this->p) { - // The Python APIs return a cached char* value that's only valid - // as long as the original object stays around, and we're - // about to (probably) toss it. Hence the copy to std::string. - OwnedObject py_str = this->PyStr(); - if (!py_str) { - return "(nil)"; - } - return PyUnicode_AsUTF8(py_str.borrow()); - } - return "(nil)"; - } - - template - inline OwnedObject PyObjectPointer::PyGetAttr(const ImmortalObject& name) const noexcept - { - assert(this->p); - return OwnedObject::consuming(PyObject_GetAttr(reinterpret_cast(this->p), name)); - } - - template - inline OwnedObject PyObjectPointer::PyRequireAttr(const char* const name) const - { - assert(this->p); - return OwnedObject::consuming(Require(PyObject_GetAttrString(this->p, name), name)); - } - - template - inline OwnedObject PyObjectPointer::PyRequireAttr(const ImmortalString& name) const - { - assert(this->p); - return OwnedObject::consuming(Require( - PyObject_GetAttr( - reinterpret_cast(this->p), - name - ), - name - )); - } - - template - inline OwnedObject PyObjectPointer::PyCall(const BorrowedObject& arg) const - { - return this->PyCall(arg.borrow()); - } - - template - inline OwnedObject PyObjectPointer::PyCall(PyGreenlet* arg) const - { - return this->PyCall(reinterpret_cast(arg)); - } - - template - inline OwnedObject PyObjectPointer::PyCall(PyObject* arg) const - { - assert(this->p); - return OwnedObject::consuming(PyObject_CallFunctionObjArgs(this->p, arg, NULL)); - } - - template - inline OwnedObject PyObjectPointer::PyCall(const BorrowedObject args, - const BorrowedObject kwargs) const - { - assert(this->p); - return OwnedObject::consuming(PyObject_Call(this->p, args, kwargs)); - } - - template - inline OwnedObject PyObjectPointer::PyCall(const OwnedObject& args, - const OwnedObject& kwargs) const - { - assert(this->p); - return OwnedObject::consuming(PyObject_Call(this->p, args.borrow(), kwargs.borrow())); - } - - inline void - ListChecker(void * p) - { - if (!p) { - return; - } - if (!PyList_Check(p)) { - throw TypeError("Expected a list"); - } - } - - class OwnedList : public OwnedReference - { - private: - G_NO_ASSIGNMENT_OF_CLS(OwnedList); - public: - // TODO: Would like to use move. - explicit OwnedList(const OwnedObject& other) - : OwnedReference(other) - { - } - - OwnedList& operator=(const OwnedObject& other) - { - if (other && PyList_Check(other.p)) { - // Valid list. Own a new reference to it, discard the - // reference to what we did own. - PyObject* new_ptr = other.p; - Py_INCREF(new_ptr); - Py_XDECREF(this->p); - this->p = new_ptr; - } - else { - // Either the other object was NULL (an error) or it - // wasn't a list. Either way, we're now invalidated. - Py_XDECREF(this->p); - this->p = nullptr; - } - return *this; - } - - inline bool empty() const - { - return PyList_GET_SIZE(p) == 0; - } - - inline Py_ssize_t size() const - { - return PyList_GET_SIZE(p); - } - - inline BorrowedObject at(const Py_ssize_t index) const - { - return PyList_GET_ITEM(p, index); - } - - inline void clear() - { - PyList_SetSlice(p, 0, PyList_GET_SIZE(p), NULL); - } - }; - - // Use this to represent the module object used at module init - // time. - // This could either be a borrowed (Py2) or new (Py3) reference; - // either way, we don't want to do any memory management - // on it here, Python itself will handle that. - // XXX: Actually, that's not quite right. On Python 3, if an - // exception occurs before we return to the interpreter, this will - // leak; but all previous versions also had that problem. - class CreatedModule : public PyObjectPointer<> - { - private: - G_NO_COPIES_OF_CLS(CreatedModule); - public: - CreatedModule(PyModuleDef& mod_def) : PyObjectPointer<>( - Require(PyModule_Create(&mod_def))) - { - } - - // PyAddObject(): Add a reference to the object to the module. - // On return, the reference count of the object is unchanged. - // - // The docs warn that PyModule_AddObject only steals the - // reference on success, so if it fails after we've incref'd - // or allocated, we're responsible for the decref. - void PyAddObject(const char* name, const long new_bool) - { - OwnedObject p = OwnedObject::consuming(Require(PyBool_FromLong(new_bool))); - this->PyAddObject(name, p); - } - - void PyAddObject(const char* name, const OwnedObject& new_object) - { - // The caller already owns a reference they will decref - // when their variable goes out of scope, we still need to - // incref/decref. - this->PyAddObject(name, new_object.borrow()); - } - - void PyAddObject(const char* name, const ImmortalObject& new_object) - { - this->PyAddObject(name, new_object.borrow()); - } - - void PyAddObject(const char* name, PyTypeObject& type) - { - this->PyAddObject(name, reinterpret_cast(&type)); - } - - void PyAddObject(const char* name, PyObject* new_object) - { - Py_INCREF(new_object); - try { - Require(PyModule_AddObject(this->p, name, new_object)); - } - catch (const PyErrOccurred&) { - Py_DECREF(p); - throw; - } - } - }; - - class PyErrFetchParam : public PyObjectPointer<> - { - // Not an owned object, because we can't be initialized with - // one, and we only sometimes acquire ownership. - private: - G_NO_COPIES_OF_CLS(PyErrFetchParam); - public: - // To allow declaring these and passing them to - // PyErr_Fetch we implement the empty constructor, - // and the address operator. - PyErrFetchParam() : PyObjectPointer<>(nullptr) - { - } - - PyObject** operator&() - { - return &this->p; - } - - // This allows us to pass one directly without the &, - // BUT it has higher precedence than the bool operator - // if it's not explicit. - operator PyObject**() - { - return &this->p; - } - - // We don't want to be able to pass these to Py_DECREF and - // such so we don't have the implicit PyObject* conversion. - - inline PyObject* relinquish_ownership() - { - PyObject* result = this->p; - this->p = nullptr; - return result; - } - - ~PyErrFetchParam() - { - Py_XDECREF(p); - } - }; - - class OwnedErrPiece : public OwnedObject - { - private: - - public: - // Unlike OwnedObject, this increments the refcount. - OwnedErrPiece(PyObject* p=nullptr) : OwnedObject(p) - { - this->acquire(); - } - - PyObject** operator&() - { - return &this->p; - } - - inline operator PyObject*() const - { - return this->p; - } - - operator PyTypeObject*() const - { - return reinterpret_cast(this->p); - } - }; - - class PyErrPieces - { - private: - OwnedErrPiece type; - OwnedErrPiece instance; - OwnedErrPiece traceback; - bool restored; - public: - // Takes new references; if we're destroyed before - // restoring the error, we drop the references. - PyErrPieces(PyObject* t, PyObject* v, PyObject* tb) : - type(t), - instance(v), - traceback(tb), - restored(0) - { - this->normalize(); - } - - PyErrPieces() : - restored(0) - { - // PyErr_Fetch transfers ownership to us, so - // we don't actually need to INCREF; but we *do* - // need to DECREF if we're not restored. - PyErrFetchParam t, v, tb; - PyErr_Fetch(&t, &v, &tb); - type.steal(t.relinquish_ownership()); - instance.steal(v.relinquish_ownership()); - traceback.steal(tb.relinquish_ownership()); - } - - void PyErrRestore() - { - // can only do this once - assert(!this->restored); - this->restored = true; - PyErr_Restore( - this->type.relinquish_ownership(), - this->instance.relinquish_ownership(), - this->traceback.relinquish_ownership()); - assert(!this->type && !this->instance && !this->traceback); - } - - private: - void normalize() - { - // First, check the traceback argument, replacing None, - // with NULL - if (traceback.is_None()) { - traceback = nullptr; - } - - if (traceback && !PyTraceBack_Check(traceback.borrow())) { - throw PyErrOccurred(PyExc_TypeError, - "throw() third argument must be a traceback object"); - } - - if (PyExceptionClass_Check(type)) { - // If we just had a type, we'll now have a type and - // instance. - // The type's refcount will have gone up by one - // because of the instance and the instance will have - // a refcount of one. Either way, we owned, and still - // do own, exactly one reference. - PyErr_NormalizeException(&type, &instance, &traceback); - - } - else if (PyExceptionInstance_Check(type)) { - /* Raising an instance --- usually that means an - object that is a subclass of BaseException, but on - Python 2, that can also mean an arbitrary old-style - object. The value should be a dummy. */ - if (instance && !instance.is_None()) { - throw PyErrOccurred( - PyExc_TypeError, - "instance exception may not have a separate value"); - } - /* Normalize to raise , */ - this->instance = this->type; - this->type = PyExceptionInstance_Class(instance.borrow()); - - /* - It would be tempting to do this: - - Py_ssize_t type_count = Py_REFCNT(Py_TYPE(instance.borrow())); - this->type = PyExceptionInstance_Class(instance.borrow()); - assert(this->type.REFCNT() == type_count + 1); - - But that doesn't work on Python 2 in the case of - old-style instances: The result of Py_TYPE is going to - be the global shared that all - old-style classes have, while the return of Instance_Class() - will be the Python-level class object. The two are unrelated. - */ - } - else { - /* Not something you can raise. throw() fails. */ - PyErr_Format(PyExc_TypeError, - "exceptions must be classes, or instances, not %s", - Py_TYPE(type.borrow())->tp_name); - throw PyErrOccurred(); - } - } - }; - - // PyArg_Parse's O argument returns a borrowed reference. - class PyArgParseParam : public BorrowedObject - { - private: - G_NO_COPIES_OF_CLS(PyArgParseParam); - public: - explicit PyArgParseParam(PyObject* p=nullptr) : BorrowedObject(p) - { - } - - inline PyObject** operator&() - { - return &this->p; - } - }; - -};}; - -#endif diff --git a/venv/lib/python3.9/site-packages/greenlet/greenlet_slp_switch.hpp b/venv/lib/python3.9/site-packages/greenlet/greenlet_slp_switch.hpp deleted file mode 100644 index bd4b7ae..0000000 --- a/venv/lib/python3.9/site-packages/greenlet/greenlet_slp_switch.hpp +++ /dev/null @@ -1,99 +0,0 @@ -#ifndef GREENLET_SLP_SWITCH_HPP -#define GREENLET_SLP_SWITCH_HPP - -#include "greenlet_compiler_compat.hpp" -#include "greenlet_refs.hpp" - -/* - * the following macros are spliced into the OS/compiler - * specific code, in order to simplify maintenance. - */ -// We can save about 10% of the time it takes to switch greenlets if -// we thread the thread state through the slp_save_state() and the -// following slp_restore_state() calls from -// slp_switch()->g_switchstack() (which already needs to access it). -// -// However: -// -// that requires changing the prototypes and implementations of the -// switching functions. If we just change the prototype of -// slp_switch() to accept the argument and update the macros, without -// changing the implementation of slp_switch(), we get crashes on -// 64-bit Linux and 32-bit x86 (for reasons that aren't 100% clear); -// on the other hand, 64-bit macOS seems to be fine. Also, 64-bit -// windows is an issue because slp_switch is written fully in assembly -// and currently ignores its argument so some code would have to be -// adjusted there to pass the argument on to the -// ``slp_save_state_asm()`` function (but interestingly, because of -// the calling convention, the extra argument is just ignored and -// things function fine, albeit slower, if we just modify -// ``slp_save_state_asm`()` to fetch the pointer to pass to the -// macro.) -// -// Our compromise is to use a *glabal*, untracked, weak, pointer -// to the necessary thread state during the process of switching only. -// This is safe because we're protected by the GIL, and if we're -// running this code, the thread isn't exiting. This also nets us a -// 10-12% speed improvement. - -static greenlet::Greenlet* volatile switching_thread_state = nullptr; - - -extern "C" { -static int GREENLET_NOINLINE(slp_save_state_trampoline)(char* stackref); -static void GREENLET_NOINLINE(slp_restore_state_trampoline)(); -} - - -#define SLP_SAVE_STATE(stackref, stsizediff) \ -do { \ - assert(switching_thread_state); \ - stackref += STACK_MAGIC; \ - if (slp_save_state_trampoline((char*)stackref)) \ - return -1; \ - if (!switching_thread_state->active()) \ - return 1; \ - stsizediff = switching_thread_state->stack_start() - (char*)stackref; \ -} while (0) - -#define SLP_RESTORE_STATE() slp_restore_state_trampoline() - -#define SLP_EVAL -extern "C" { -#define slp_switch GREENLET_NOINLINE(slp_switch) -#include "slp_platformselect.h" -} -#undef slp_switch - -#ifndef STACK_MAGIC -# error \ - "greenlet needs to be ported to this platform, or taught how to detect your compiler properly." -#endif /* !STACK_MAGIC */ - - - -#ifdef EXTERNAL_ASM -/* CCP addition: Make these functions, to be called from assembler. - * The token include file for the given platform should enable the - * EXTERNAL_ASM define so that this is included. - */ -extern "C" { -intptr_t -slp_save_state_asm(intptr_t* ref) -{ - intptr_t diff; - SLP_SAVE_STATE(ref, diff); - return diff; -} - -void -slp_restore_state_asm(void) -{ - SLP_RESTORE_STATE(); -} - -extern int slp_switch(void); -}; -#endif - -#endif diff --git a/venv/lib/python3.9/site-packages/greenlet/greenlet_thread_support.hpp b/venv/lib/python3.9/site-packages/greenlet/greenlet_thread_support.hpp deleted file mode 100644 index 3ded7d2..0000000 --- a/venv/lib/python3.9/site-packages/greenlet/greenlet_thread_support.hpp +++ /dev/null @@ -1,31 +0,0 @@ -#ifndef GREENLET_THREAD_SUPPORT_HPP -#define GREENLET_THREAD_SUPPORT_HPP - -/** - * Defines various utility functions to help greenlet integrate well - * with threads. This used to be needed when we supported Python - * 2.7 on Windows, which used a very old compiler. We wrote an - * alternative implementation using Python APIs and POSIX or Windows - * APIs, but that's no longer needed. So this file is a shadow of its - * former self --- but may be needed in the future. - */ - -#include -#include -#include - -#include "greenlet_compiler_compat.hpp" - -namespace greenlet { - typedef std::mutex Mutex; - typedef std::lock_guard LockGuard; - class LockInitError : public std::runtime_error - { - public: - LockInitError(const char* what) : std::runtime_error(what) - {}; - }; -}; - - -#endif /* GREENLET_THREAD_SUPPORT_HPP */ diff --git a/venv/lib/python3.9/site-packages/greenlet/platform/__init__.py b/venv/lib/python3.9/site-packages/greenlet/platform/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/venv/lib/python3.9/site-packages/greenlet/platform/setup_switch_x64_masm.cmd b/venv/lib/python3.9/site-packages/greenlet/platform/setup_switch_x64_masm.cmd deleted file mode 100644 index 0928595..0000000 --- a/venv/lib/python3.9/site-packages/greenlet/platform/setup_switch_x64_masm.cmd +++ /dev/null @@ -1,2 +0,0 @@ -call "C:\Program Files (x86)\Microsoft Visual Studio 9.0\VC\vcvarsall.bat" amd64 -ml64 /nologo /c /Fo switch_x64_masm.obj switch_x64_masm.asm diff --git a/venv/lib/python3.9/site-packages/greenlet/platform/switch_aarch64_gcc.h b/venv/lib/python3.9/site-packages/greenlet/platform/switch_aarch64_gcc.h deleted file mode 100644 index 058617c..0000000 --- a/venv/lib/python3.9/site-packages/greenlet/platform/switch_aarch64_gcc.h +++ /dev/null @@ -1,124 +0,0 @@ -/* - * this is the internal transfer function. - * - * HISTORY - * 07-Sep-16 Add clang support using x register naming. Fredrik Fornwall - * 13-Apr-13 Add support for strange GCC caller-save decisions - * 08-Apr-13 File creation. Michael Matz - * - * NOTES - * - * Simply save all callee saved registers - * - */ - -#define STACK_REFPLUS 1 - -#ifdef SLP_EVAL -#define STACK_MAGIC 0 -#define REGS_TO_SAVE "x19", "x20", "x21", "x22", "x23", "x24", "x25", "x26", \ - "x27", "x28", "x30" /* aka lr */, \ - "v8", "v9", "v10", "v11", \ - "v12", "v13", "v14", "v15" - -/* - * Recall: - asm asm-qualifiers ( AssemblerTemplate - : OutputOperands - [ : InputOperands - [ : Clobbers ] ]) - - or (if asm-qualifiers contains 'goto') - - asm asm-qualifiers ( AssemblerTemplate - : OutputOperands - : InputOperands - : Clobbers - : GotoLabels) - - and OutputOperands are - - [ [asmSymbolicName] ] constraint (cvariablename) - - When a name is given, refer to it as ``%[the name]``. - When not given, ``%i`` where ``i`` is the zero-based index. - - constraints starting with ``=`` means only writing; ``+`` means - reading and writing. - - This is followed by ``r`` (must be register) or ``m`` (must be memory) - and these can be combined. - - The ``cvariablename`` is actually an lvalue expression. - - In AArch65, 31 general purpose registers. If named X0... they are - 64-bit. If named W0... they are the bottom 32 bits of the - corresponding 64 bit register. - - XZR and WZR are hardcoded to 0, and ignore writes. - - Arguments are in X0..X7. C++ uses X0 for ``this``. X0 holds simple return - values (?) - - Whenever a W register is written, the top half of the X register is zeroed. - */ - -static int -slp_switch(void) -{ - int err; - void *fp; - /* Windowz uses a 32-bit long on a 64-bit platform, unlike the rest of - the world, and in theory we can be compiled with GCC/llvm on 64-bit - windows. So we need a fixed-width type. - */ - int64_t *stackref, stsizediff; - __asm__ volatile ("" : : : REGS_TO_SAVE); - __asm__ volatile ("str x29, %0" : "=m"(fp) : : ); - __asm__ ("mov %0, sp" : "=r" (stackref)); - { - SLP_SAVE_STATE(stackref, stsizediff); - __asm__ volatile ( - "add sp,sp,%0\n" - "add x29,x29,%0\n" - : - : "r" (stsizediff) - ); - SLP_RESTORE_STATE(); - /* SLP_SAVE_STATE macro contains some return statements - (of -1 and 1). It falls through only when - the return value of slp_save_state() is zero, which - is placed in x0. - In that case we (slp_switch) also want to return zero - (also in x0 of course). - Now, some GCC versions (seen with 4.8) think it's a - good idea to save/restore x0 around the call to - slp_restore_state(), instead of simply zeroing it - at the return below. But slp_restore_state - writes random values to the stack slot used for this - save/restore (from when it once was saved above in - SLP_SAVE_STATE, when it was still uninitialized), so - "restoring" that precious zero actually makes us - return random values. There are some ways to make - GCC not use that zero value in the normal return path - (e.g. making err volatile, but that costs a little - stack space), and the simplest is to call a function - that returns an unknown value (which happens to be zero), - so the saved/restored value is unused. - - Thus, this line stores a 0 into the ``err`` variable - (which must be held in a register for this instruction, - of course). The ``w`` qualifier causes the instruction - to use W0 instead of X0, otherwise we get a warning - about a value size mismatch (because err is an int, - and aarch64 platforms are LP64: 32-bit int, 64 bit long - and pointer). - */ - __asm__ volatile ("mov %w0, #0" : "=r" (err)); - } - __asm__ volatile ("ldr x29, %0" : : "m" (fp) :); - __asm__ volatile ("" : : : REGS_TO_SAVE); - return err; -} - -#endif diff --git a/venv/lib/python3.9/site-packages/greenlet/platform/switch_alpha_unix.h b/venv/lib/python3.9/site-packages/greenlet/platform/switch_alpha_unix.h deleted file mode 100644 index 7e07abf..0000000 --- a/venv/lib/python3.9/site-packages/greenlet/platform/switch_alpha_unix.h +++ /dev/null @@ -1,30 +0,0 @@ -#define STACK_REFPLUS 1 - -#ifdef SLP_EVAL -#define STACK_MAGIC 0 - -#define REGS_TO_SAVE "$9", "$10", "$11", "$12", "$13", "$14", "$15", \ - "$f2", "$f3", "$f4", "$f5", "$f6", "$f7", "$f8", "$f9" - -static int -slp_switch(void) -{ - int ret; - long *stackref, stsizediff; - __asm__ volatile ("" : : : REGS_TO_SAVE); - __asm__ volatile ("mov $30, %0" : "=r" (stackref) : ); - { - SLP_SAVE_STATE(stackref, stsizediff); - __asm__ volatile ( - "addq $30, %0, $30\n\t" - : /* no outputs */ - : "r" (stsizediff) - ); - SLP_RESTORE_STATE(); - } - __asm__ volatile ("" : : : REGS_TO_SAVE); - __asm__ volatile ("mov $31, %0" : "=r" (ret) : ); - return ret; -} - -#endif diff --git a/venv/lib/python3.9/site-packages/greenlet/platform/switch_amd64_unix.h b/venv/lib/python3.9/site-packages/greenlet/platform/switch_amd64_unix.h deleted file mode 100644 index d470110..0000000 --- a/venv/lib/python3.9/site-packages/greenlet/platform/switch_amd64_unix.h +++ /dev/null @@ -1,87 +0,0 @@ -/* - * this is the internal transfer function. - * - * HISTORY - * 3-May-13 Ralf Schmitt - * Add support for strange GCC caller-save decisions - * (ported from switch_aarch64_gcc.h) - * 18-Aug-11 Alexey Borzenkov - * Correctly save rbp, csr and cw - * 01-Apr-04 Hye-Shik Chang - * Ported from i386 to amd64. - * 24-Nov-02 Christian Tismer - * needed to add another magic constant to insure - * that f in slp_eval_frame(PyFrameObject *f) - * STACK_REFPLUS will probably be 1 in most cases. - * gets included into the saved stack area. - * 17-Sep-02 Christian Tismer - * after virtualizing stack save/restore, the - * stack size shrunk a bit. Needed to introduce - * an adjustment STACK_MAGIC per platform. - * 15-Sep-02 Gerd Woetzel - * slightly changed framework for spark - * 31-Avr-02 Armin Rigo - * Added ebx, esi and edi register-saves. - * 01-Mar-02 Samual M. Rushing - * Ported from i386. - */ - -#define STACK_REFPLUS 1 - -#ifdef SLP_EVAL - -/* #define STACK_MAGIC 3 */ -/* the above works fine with gcc 2.96, but 2.95.3 wants this */ -#define STACK_MAGIC 0 - -#define REGS_TO_SAVE "r12", "r13", "r14", "r15" - -static int -slp_switch(void) -{ - int err; - void* rbp; - void* rbx; - unsigned int csr; - unsigned short cw; - /* This used to be declared 'register', but that does nothing in - modern compilers and is explicitly forbidden in some new - standards. */ - long *stackref, stsizediff; - __asm__ volatile ("" : : : REGS_TO_SAVE); - __asm__ volatile ("fstcw %0" : "=m" (cw)); - __asm__ volatile ("stmxcsr %0" : "=m" (csr)); - __asm__ volatile ("movq %%rbp, %0" : "=m" (rbp)); - __asm__ volatile ("movq %%rbx, %0" : "=m" (rbx)); - __asm__ ("movq %%rsp, %0" : "=g" (stackref)); - { - SLP_SAVE_STATE(stackref, stsizediff); - __asm__ volatile ( - "addq %0, %%rsp\n" - "addq %0, %%rbp\n" - : - : "r" (stsizediff) - ); - SLP_RESTORE_STATE(); - __asm__ volatile ("xorq %%rax, %%rax" : "=a" (err)); - } - __asm__ volatile ("movq %0, %%rbx" : : "m" (rbx)); - __asm__ volatile ("movq %0, %%rbp" : : "m" (rbp)); - __asm__ volatile ("ldmxcsr %0" : : "m" (csr)); - __asm__ volatile ("fldcw %0" : : "m" (cw)); - __asm__ volatile ("" : : : REGS_TO_SAVE); - return err; -} - -#endif - -/* - * further self-processing support - */ - -/* - * if you want to add self-inspection tools, place them - * here. See the x86_msvc for the necessary defines. - * These features are highly experimental und not - * essential yet. - */ diff --git a/venv/lib/python3.9/site-packages/greenlet/platform/switch_arm32_gcc.h b/venv/lib/python3.9/site-packages/greenlet/platform/switch_arm32_gcc.h deleted file mode 100644 index 655003a..0000000 --- a/venv/lib/python3.9/site-packages/greenlet/platform/switch_arm32_gcc.h +++ /dev/null @@ -1,79 +0,0 @@ -/* - * this is the internal transfer function. - * - * HISTORY - * 14-Aug-06 File creation. Ported from Arm Thumb. Sylvain Baro - * 3-Sep-06 Commented out saving of r1-r3 (r4 already commented out) as I - * read that these do not need to be saved. Also added notes and - * errors related to the frame pointer. Richard Tew. - * - * NOTES - * - * It is not possible to detect if fp is used or not, so the supplied - * switch function needs to support it, so that you can remove it if - * it does not apply to you. - * - * POSSIBLE ERRORS - * - * "fp cannot be used in asm here" - * - * - Try commenting out "fp" in REGS_TO_SAVE. - * - */ - -#define STACK_REFPLUS 1 - -#ifdef SLP_EVAL -#define STACK_MAGIC 0 -#define REG_SP "sp" -#define REG_SPSP "sp,sp" -#ifdef __thumb__ -#define REG_FP "r7" -#define REG_FPFP "r7,r7" -#define REGS_TO_SAVE_GENERAL "r4", "r5", "r6", "r8", "r9", "r10", "r11", "lr" -#else -#define REG_FP "fp" -#define REG_FPFP "fp,fp" -#define REGS_TO_SAVE_GENERAL "r4", "r5", "r6", "r7", "r8", "r9", "r10", "lr" -#endif -#if defined(__SOFTFP__) -#define REGS_TO_SAVE REGS_TO_SAVE_GENERAL -#elif defined(__VFP_FP__) -#define REGS_TO_SAVE REGS_TO_SAVE_GENERAL, "d8", "d9", "d10", "d11", \ - "d12", "d13", "d14", "d15" -#elif defined(__MAVERICK__) -#define REGS_TO_SAVE REGS_TO_SAVE_GENERAL, "mvf4", "mvf5", "mvf6", "mvf7", \ - "mvf8", "mvf9", "mvf10", "mvf11", \ - "mvf12", "mvf13", "mvf14", "mvf15" -#else -#define REGS_TO_SAVE REGS_TO_SAVE_GENERAL, "f4", "f5", "f6", "f7" -#endif - -static int -#ifdef __GNUC__ -__attribute__((optimize("no-omit-frame-pointer"))) -#endif -slp_switch(void) -{ - void *fp; - int *stackref, stsizediff; - int result; - __asm__ volatile ("" : : : REGS_TO_SAVE); - __asm__ volatile ("mov r0," REG_FP "\n\tstr r0,%0" : "=m" (fp) : : "r0"); - __asm__ ("mov %0," REG_SP : "=r" (stackref)); - { - SLP_SAVE_STATE(stackref, stsizediff); - __asm__ volatile ( - "add " REG_SPSP ",%0\n" - "add " REG_FPFP ",%0\n" - : - : "r" (stsizediff) - ); - SLP_RESTORE_STATE(); - } - __asm__ volatile ("ldr r0,%1\n\tmov " REG_FP ",r0\n\tmov %0, #0" : "=r" (result) : "m" (fp) : "r0"); - __asm__ volatile ("" : : : REGS_TO_SAVE); - return result; -} - -#endif diff --git a/venv/lib/python3.9/site-packages/greenlet/platform/switch_arm32_ios.h b/venv/lib/python3.9/site-packages/greenlet/platform/switch_arm32_ios.h deleted file mode 100644 index 9e640e1..0000000 --- a/venv/lib/python3.9/site-packages/greenlet/platform/switch_arm32_ios.h +++ /dev/null @@ -1,67 +0,0 @@ -/* - * this is the internal transfer function. - * - * HISTORY - * 31-May-15 iOS support. Ported from arm32. Proton - * - * NOTES - * - * It is not possible to detect if fp is used or not, so the supplied - * switch function needs to support it, so that you can remove it if - * it does not apply to you. - * - * POSSIBLE ERRORS - * - * "fp cannot be used in asm here" - * - * - Try commenting out "fp" in REGS_TO_SAVE. - * - */ - -#define STACK_REFPLUS 1 - -#ifdef SLP_EVAL - -#define STACK_MAGIC 0 -#define REG_SP "sp" -#define REG_SPSP "sp,sp" -#define REG_FP "r7" -#define REG_FPFP "r7,r7" -#define REGS_TO_SAVE_GENERAL "r4", "r5", "r6", "r8", "r10", "r11", "lr" -#define REGS_TO_SAVE REGS_TO_SAVE_GENERAL, "d8", "d9", "d10", "d11", \ - "d12", "d13", "d14", "d15" - -static int -#ifdef __GNUC__ -__attribute__((optimize("no-omit-frame-pointer"))) -#endif -slp_switch(void) -{ - void *fp; - int *stackref, stsizediff, result; - __asm__ volatile ("" : : : REGS_TO_SAVE); - __asm__ volatile ("str " REG_FP ",%0" : "=m" (fp)); - __asm__ ("mov %0," REG_SP : "=r" (stackref)); - { - SLP_SAVE_STATE(stackref, stsizediff); - __asm__ volatile ( - "add " REG_SPSP ",%0\n" - "add " REG_FPFP ",%0\n" - : - : "r" (stsizediff) - : REGS_TO_SAVE /* Clobber registers, force compiler to - * recalculate address of void *fp from REG_SP or REG_FP */ - ); - SLP_RESTORE_STATE(); - } - __asm__ volatile ( - "ldr " REG_FP ", %1\n\t" - "mov %0, #0" - : "=r" (result) - : "m" (fp) - : REGS_TO_SAVE /* Force compiler to restore saved registers after this */ - ); - return result; -} - -#endif diff --git a/venv/lib/python3.9/site-packages/greenlet/platform/switch_arm64_masm.asm b/venv/lib/python3.9/site-packages/greenlet/platform/switch_arm64_masm.asm deleted file mode 100644 index 29f9c22..0000000 --- a/venv/lib/python3.9/site-packages/greenlet/platform/switch_arm64_masm.asm +++ /dev/null @@ -1,53 +0,0 @@ - AREA switch_arm64_masm, CODE, READONLY; - GLOBAL slp_switch [FUNC] - EXTERN slp_save_state_asm - EXTERN slp_restore_state_asm - -slp_switch - ; push callee saved registers to stack - stp x19, x20, [sp, #-16]! - stp x21, x22, [sp, #-16]! - stp x23, x24, [sp, #-16]! - stp x25, x26, [sp, #-16]! - stp x27, x28, [sp, #-16]! - stp x29, x30, [sp, #-16]! - stp d8, d9, [sp, #-16]! - stp d10, d11, [sp, #-16]! - stp d12, d13, [sp, #-16]! - stp d14, d15, [sp, #-16]! - - ; call slp_save_state_asm with stack pointer - mov x0, sp - bl slp_save_state_asm - - ; early return for return value of 1 and -1 - cmp x0, #-1 - b.eq RETURN - cmp x0, #1 - b.eq RETURN - - ; increment stack and frame pointer - add sp, sp, x0 - add x29, x29, x0 - - bl slp_restore_state_asm - - ; store return value for successful completion of routine - mov x0, #0 - -RETURN - ; pop registers from stack - ldp d14, d15, [sp], #16 - ldp d12, d13, [sp], #16 - ldp d10, d11, [sp], #16 - ldp d8, d9, [sp], #16 - ldp x29, x30, [sp], #16 - ldp x27, x28, [sp], #16 - ldp x25, x26, [sp], #16 - ldp x23, x24, [sp], #16 - ldp x21, x22, [sp], #16 - ldp x19, x20, [sp], #16 - - ret - - END diff --git a/venv/lib/python3.9/site-packages/greenlet/platform/switch_arm64_masm.obj b/venv/lib/python3.9/site-packages/greenlet/platform/switch_arm64_masm.obj deleted file mode 100644 index f6f220e..0000000 Binary files a/venv/lib/python3.9/site-packages/greenlet/platform/switch_arm64_masm.obj and /dev/null differ diff --git a/venv/lib/python3.9/site-packages/greenlet/platform/switch_arm64_msvc.h b/venv/lib/python3.9/site-packages/greenlet/platform/switch_arm64_msvc.h deleted file mode 100644 index 7ab7f45..0000000 --- a/venv/lib/python3.9/site-packages/greenlet/platform/switch_arm64_msvc.h +++ /dev/null @@ -1,17 +0,0 @@ -/* - * this is the internal transfer function. - * - * HISTORY - * 21-Oct-21 Niyas Sait - * First version to enable win/arm64 support. - */ - -#define STACK_REFPLUS 1 -#define STACK_MAGIC 0 - -/* Use the generic support for an external assembly language slp_switch function. */ -#define EXTERNAL_ASM - -#ifdef SLP_EVAL -/* This always uses the external masm assembly file. */ -#endif \ No newline at end of file diff --git a/venv/lib/python3.9/site-packages/greenlet/platform/switch_csky_gcc.h b/venv/lib/python3.9/site-packages/greenlet/platform/switch_csky_gcc.h deleted file mode 100644 index ac469d3..0000000 --- a/venv/lib/python3.9/site-packages/greenlet/platform/switch_csky_gcc.h +++ /dev/null @@ -1,48 +0,0 @@ -#ifdef SLP_EVAL -#define STACK_MAGIC 0 -#define REG_FP "r8" -#ifdef __CSKYABIV2__ -#define REGS_TO_SAVE_GENERAL "r4", "r5", "r6", "r7", "r9", "r10", "r11", "r15",\ - "r16", "r17", "r18", "r19", "r20", "r21", "r22",\ - "r23", "r24", "r25" - -#if defined (__CSKY_HARD_FLOAT__) || (__CSKY_VDSP__) -#define REGS_TO_SAVE REGS_TO_SAVE_GENERAL, "vr8", "vr9", "vr10", "vr11", "vr12",\ - "vr13", "vr14", "vr15" -#else -#define REGS_TO_SAVE REGS_TO_SAVE_GENERAL -#endif -#else -#define REGS_TO_SAVE "r9", "r10", "r11", "r12", "r13", "r15" -#endif - - -static int -#ifdef __GNUC__ -__attribute__((optimize("no-omit-frame-pointer"))) -#endif -slp_switch(void) -{ - int *stackref, stsizediff; - int result; - - __asm__ volatile ("" : : : REGS_TO_SAVE); - __asm__ ("mov %0, sp" : "=r" (stackref)); - { - SLP_SAVE_STATE(stackref, stsizediff); - __asm__ volatile ( - "addu sp,%0\n" - "addu "REG_FP",%0\n" - : - : "r" (stsizediff) - ); - - SLP_RESTORE_STATE(); - } - __asm__ volatile ("movi %0, 0" : "=r" (result)); - __asm__ volatile ("" : : : REGS_TO_SAVE); - - return result; -} - -#endif diff --git a/venv/lib/python3.9/site-packages/greenlet/platform/switch_loongarch64_linux.h b/venv/lib/python3.9/site-packages/greenlet/platform/switch_loongarch64_linux.h deleted file mode 100644 index 9eaf34e..0000000 --- a/venv/lib/python3.9/site-packages/greenlet/platform/switch_loongarch64_linux.h +++ /dev/null @@ -1,31 +0,0 @@ -#define STACK_REFPLUS 1 - -#ifdef SLP_EVAL -#define STACK_MAGIC 0 - -#define REGS_TO_SAVE "s0", "s1", "s2", "s3", "s4", "s5", \ - "s6", "s7", "s8", "fp", \ - "f24", "f25", "f26", "f27", "f28", "f29", "f30", "f31" - -static int -slp_switch(void) -{ - int ret; - long *stackref, stsizediff; - __asm__ volatile ("" : : : REGS_TO_SAVE); - __asm__ volatile ("move %0, $sp" : "=r" (stackref) : ); - { - SLP_SAVE_STATE(stackref, stsizediff); - __asm__ volatile ( - "add.d $sp, $sp, %0\n\t" - : /* no outputs */ - : "r" (stsizediff) - ); - SLP_RESTORE_STATE(); - } - __asm__ volatile ("" : : : REGS_TO_SAVE); - __asm__ volatile ("move %0, $zero" : "=r" (ret) : ); - return ret; -} - -#endif diff --git a/venv/lib/python3.9/site-packages/greenlet/platform/switch_m68k_gcc.h b/venv/lib/python3.9/site-packages/greenlet/platform/switch_m68k_gcc.h deleted file mode 100644 index da761c2..0000000 --- a/venv/lib/python3.9/site-packages/greenlet/platform/switch_m68k_gcc.h +++ /dev/null @@ -1,38 +0,0 @@ -/* - * this is the internal transfer function. - * - * HISTORY - * 2014-01-06 Andreas Schwab - * File created. - */ - -#ifdef SLP_EVAL - -#define STACK_MAGIC 0 - -#define REGS_TO_SAVE "%d2", "%d3", "%d4", "%d5", "%d6", "%d7", \ - "%a2", "%a3", "%a4" - -static int -slp_switch(void) -{ - int err; - int *stackref, stsizediff; - void *fp, *a5; - __asm__ volatile ("" : : : REGS_TO_SAVE); - __asm__ volatile ("move.l %%fp, %0" : "=m"(fp)); - __asm__ volatile ("move.l %%a5, %0" : "=m"(a5)); - __asm__ ("move.l %%sp, %0" : "=r"(stackref)); - { - SLP_SAVE_STATE(stackref, stsizediff); - __asm__ volatile ("add.l %0, %%sp; add.l %0, %%fp" : : "r"(stsizediff)); - SLP_RESTORE_STATE(); - __asm__ volatile ("clr.l %0" : "=g" (err)); - } - __asm__ volatile ("move.l %0, %%a5" : : "m"(a5)); - __asm__ volatile ("move.l %0, %%fp" : : "m"(fp)); - __asm__ volatile ("" : : : REGS_TO_SAVE); - return err; -} - -#endif diff --git a/venv/lib/python3.9/site-packages/greenlet/platform/switch_mips_unix.h b/venv/lib/python3.9/site-packages/greenlet/platform/switch_mips_unix.h deleted file mode 100644 index b9003e9..0000000 --- a/venv/lib/python3.9/site-packages/greenlet/platform/switch_mips_unix.h +++ /dev/null @@ -1,64 +0,0 @@ -/* - * this is the internal transfer function. - * - * HISTORY - * 20-Sep-14 Matt Madison - * Re-code the saving of the gp register for MIPS64. - * 05-Jan-08 Thiemo Seufer - * Ported from ppc. - */ - -#define STACK_REFPLUS 1 - -#ifdef SLP_EVAL - -#define STACK_MAGIC 0 - -#define REGS_TO_SAVE "$16", "$17", "$18", "$19", "$20", "$21", "$22", \ - "$23", "$30" -static int -slp_switch(void) -{ - int err; - int *stackref, stsizediff; -#ifdef __mips64 - uint64_t gpsave; -#endif - __asm__ __volatile__ ("" : : : REGS_TO_SAVE); -#ifdef __mips64 - __asm__ __volatile__ ("sd $28,%0" : "=m" (gpsave) : : ); -#endif - __asm__ ("move %0, $29" : "=r" (stackref) : ); - { - SLP_SAVE_STATE(stackref, stsizediff); - __asm__ __volatile__ ( -#ifdef __mips64 - "daddu $29, %0\n" -#else - "addu $29, %0\n" -#endif - : /* no outputs */ - : "r" (stsizediff) - ); - SLP_RESTORE_STATE(); - } -#ifdef __mips64 - __asm__ __volatile__ ("ld $28,%0" : : "m" (gpsave) : ); -#endif - __asm__ __volatile__ ("" : : : REGS_TO_SAVE); - __asm__ __volatile__ ("move %0, $0" : "=r" (err)); - return err; -} - -#endif - -/* - * further self-processing support - */ - -/* - * if you want to add self-inspection tools, place them - * here. See the x86_msvc for the necessary defines. - * These features are highly experimental und not - * essential yet. - */ diff --git a/venv/lib/python3.9/site-packages/greenlet/platform/switch_ppc64_aix.h b/venv/lib/python3.9/site-packages/greenlet/platform/switch_ppc64_aix.h deleted file mode 100644 index e7e0b87..0000000 --- a/venv/lib/python3.9/site-packages/greenlet/platform/switch_ppc64_aix.h +++ /dev/null @@ -1,103 +0,0 @@ -/* - * this is the internal transfer function. - * - * HISTORY - * 16-Oct-20 Jesse Gorzinski - * Copied from Linux PPC64 implementation - * 04-Sep-18 Alexey Borzenkov - * Workaround a gcc bug using manual save/restore of r30 - * 21-Mar-18 Tulio Magno Quites Machado Filho - * Added r30 to the list of saved registers in order to fully comply with - * both ppc64 ELFv1 ABI and the ppc64le ELFv2 ABI, that classify this - * register as a nonvolatile register used for local variables. - * 21-Mar-18 Laszlo Boszormenyi - * Save r2 (TOC pointer) manually. - * 10-Dec-13 Ulrich Weigand - * Support ELFv2 ABI. Save float/vector registers. - * 09-Mar-12 Michael Ellerman - * 64-bit implementation, copied from 32-bit. - * 07-Sep-05 (py-dev mailing list discussion) - * removed 'r31' from the register-saved. !!!! WARNING !!!! - * It means that this file can no longer be compiled statically! - * It is now only suitable as part of a dynamic library! - * 14-Jan-04 Bob Ippolito - * added cr2-cr4 to the registers to be saved. - * Open questions: Should we save FP registers? - * What about vector registers? - * Differences between darwin and unix? - * 24-Nov-02 Christian Tismer - * needed to add another magic constant to insure - * that f in slp_eval_frame(PyFrameObject *f) - * STACK_REFPLUS will probably be 1 in most cases. - * gets included into the saved stack area. - * 04-Oct-02 Gustavo Niemeyer - * Ported from MacOS version. - * 17-Sep-02 Christian Tismer - * after virtualizing stack save/restore, the - * stack size shrunk a bit. Needed to introduce - * an adjustment STACK_MAGIC per platform. - * 15-Sep-02 Gerd Woetzel - * slightly changed framework for sparc - * 29-Jun-02 Christian Tismer - * Added register 13-29, 31 saves. The same way as - * Armin Rigo did for the x86_unix version. - * This seems to be now fully functional! - * 04-Mar-02 Hye-Shik Chang - * Ported from i386. - * 31-Jul-12 Trevor Bowen - * Changed memory constraints to register only. - */ - -#define STACK_REFPLUS 1 - -#ifdef SLP_EVAL - -#define STACK_MAGIC 6 - -#if defined(__ALTIVEC__) -#define ALTIVEC_REGS \ - "v20", "v21", "v22", "v23", "v24", "v25", "v26", "v27", \ - "v28", "v29", "v30", "v31", -#else -#define ALTIVEC_REGS -#endif - -#define REGS_TO_SAVE "r14", "r15", "r16", "r17", "r18", "r19", "r20", \ - "r21", "r22", "r23", "r24", "r25", "r26", "r27", "r28", "r29", \ - "r31", \ - "fr14", "fr15", "fr16", "fr17", "fr18", "fr19", "fr20", "fr21", \ - "fr22", "fr23", "fr24", "fr25", "fr26", "fr27", "fr28", "fr29", \ - "fr30", "fr31", \ - ALTIVEC_REGS \ - "cr2", "cr3", "cr4" - -static int -slp_switch(void) -{ - int err; - long *stackref, stsizediff; - void * toc; - void * r30; - __asm__ volatile ("" : : : REGS_TO_SAVE); - __asm__ volatile ("std 2, %0" : "=m" (toc)); - __asm__ volatile ("std 30, %0" : "=m" (r30)); - __asm__ ("mr %0, 1" : "=r" (stackref) : ); - { - SLP_SAVE_STATE(stackref, stsizediff); - __asm__ volatile ( - "mr 11, %0\n" - "add 1, 1, 11\n" - : /* no outputs */ - : "r" (stsizediff) - : "11" - ); - SLP_RESTORE_STATE(); - } - __asm__ volatile ("ld 30, %0" : : "m" (r30)); - __asm__ volatile ("ld 2, %0" : : "m" (toc)); - __asm__ volatile ("" : : : REGS_TO_SAVE); - __asm__ volatile ("li %0, 0" : "=r" (err)); - return err; -} - -#endif diff --git a/venv/lib/python3.9/site-packages/greenlet/platform/switch_ppc64_linux.h b/venv/lib/python3.9/site-packages/greenlet/platform/switch_ppc64_linux.h deleted file mode 100644 index 3c324d0..0000000 --- a/venv/lib/python3.9/site-packages/greenlet/platform/switch_ppc64_linux.h +++ /dev/null @@ -1,105 +0,0 @@ -/* - * this is the internal transfer function. - * - * HISTORY - * 04-Sep-18 Alexey Borzenkov - * Workaround a gcc bug using manual save/restore of r30 - * 21-Mar-18 Tulio Magno Quites Machado Filho - * Added r30 to the list of saved registers in order to fully comply with - * both ppc64 ELFv1 ABI and the ppc64le ELFv2 ABI, that classify this - * register as a nonvolatile register used for local variables. - * 21-Mar-18 Laszlo Boszormenyi - * Save r2 (TOC pointer) manually. - * 10-Dec-13 Ulrich Weigand - * Support ELFv2 ABI. Save float/vector registers. - * 09-Mar-12 Michael Ellerman - * 64-bit implementation, copied from 32-bit. - * 07-Sep-05 (py-dev mailing list discussion) - * removed 'r31' from the register-saved. !!!! WARNING !!!! - * It means that this file can no longer be compiled statically! - * It is now only suitable as part of a dynamic library! - * 14-Jan-04 Bob Ippolito - * added cr2-cr4 to the registers to be saved. - * Open questions: Should we save FP registers? - * What about vector registers? - * Differences between darwin and unix? - * 24-Nov-02 Christian Tismer - * needed to add another magic constant to insure - * that f in slp_eval_frame(PyFrameObject *f) - * STACK_REFPLUS will probably be 1 in most cases. - * gets included into the saved stack area. - * 04-Oct-02 Gustavo Niemeyer - * Ported from MacOS version. - * 17-Sep-02 Christian Tismer - * after virtualizing stack save/restore, the - * stack size shrunk a bit. Needed to introduce - * an adjustment STACK_MAGIC per platform. - * 15-Sep-02 Gerd Woetzel - * slightly changed framework for sparc - * 29-Jun-02 Christian Tismer - * Added register 13-29, 31 saves. The same way as - * Armin Rigo did for the x86_unix version. - * This seems to be now fully functional! - * 04-Mar-02 Hye-Shik Chang - * Ported from i386. - * 31-Jul-12 Trevor Bowen - * Changed memory constraints to register only. - */ - -#define STACK_REFPLUS 1 - -#ifdef SLP_EVAL - -#if _CALL_ELF == 2 -#define STACK_MAGIC 4 -#else -#define STACK_MAGIC 6 -#endif - -#if defined(__ALTIVEC__) -#define ALTIVEC_REGS \ - "v20", "v21", "v22", "v23", "v24", "v25", "v26", "v27", \ - "v28", "v29", "v30", "v31", -#else -#define ALTIVEC_REGS -#endif - -#define REGS_TO_SAVE "r14", "r15", "r16", "r17", "r18", "r19", "r20", \ - "r21", "r22", "r23", "r24", "r25", "r26", "r27", "r28", "r29", \ - "r31", \ - "fr14", "fr15", "fr16", "fr17", "fr18", "fr19", "fr20", "fr21", \ - "fr22", "fr23", "fr24", "fr25", "fr26", "fr27", "fr28", "fr29", \ - "fr30", "fr31", \ - ALTIVEC_REGS \ - "cr2", "cr3", "cr4" - -static int -slp_switch(void) -{ - int err; - long *stackref, stsizediff; - void * toc; - void * r30; - __asm__ volatile ("" : : : REGS_TO_SAVE); - __asm__ volatile ("std 2, %0" : "=m" (toc)); - __asm__ volatile ("std 30, %0" : "=m" (r30)); - __asm__ ("mr %0, 1" : "=r" (stackref) : ); - { - SLP_SAVE_STATE(stackref, stsizediff); - __asm__ volatile ( - "mr 11, %0\n" - "add 1, 1, 11\n" - : /* no outputs */ - : "r" (stsizediff) - : "11" - ); - SLP_RESTORE_STATE(); - } - __asm__ volatile ("ld 30, %0" : : "m" (r30)); - __asm__ volatile ("ld 2, %0" : : "m" (toc)); - __asm__ volatile ("" : : : REGS_TO_SAVE); - __asm__ volatile ("li %0, 0" : "=r" (err)); - return err; -} - -#endif diff --git a/venv/lib/python3.9/site-packages/greenlet/platform/switch_ppc_aix.h b/venv/lib/python3.9/site-packages/greenlet/platform/switch_ppc_aix.h deleted file mode 100644 index 6d93c13..0000000 --- a/venv/lib/python3.9/site-packages/greenlet/platform/switch_ppc_aix.h +++ /dev/null @@ -1,87 +0,0 @@ -/* - * this is the internal transfer function. - * - * HISTORY - * 07-Mar-11 Floris Bruynooghe - * Do not add stsizediff to general purpose - * register (GPR) 30 as this is a non-volatile and - * unused by the PowerOpen Environment, therefore - * this was modifying a user register instead of the - * frame pointer (which does not seem to exist). - * 07-Sep-05 (py-dev mailing list discussion) - * removed 'r31' from the register-saved. !!!! WARNING !!!! - * It means that this file can no longer be compiled statically! - * It is now only suitable as part of a dynamic library! - * 14-Jan-04 Bob Ippolito - * added cr2-cr4 to the registers to be saved. - * Open questions: Should we save FP registers? - * What about vector registers? - * Differences between darwin and unix? - * 24-Nov-02 Christian Tismer - * needed to add another magic constant to insure - * that f in slp_eval_frame(PyFrameObject *f) - * STACK_REFPLUS will probably be 1 in most cases. - * gets included into the saved stack area. - * 04-Oct-02 Gustavo Niemeyer - * Ported from MacOS version. - * 17-Sep-02 Christian Tismer - * after virtualizing stack save/restore, the - * stack size shrunk a bit. Needed to introduce - * an adjustment STACK_MAGIC per platform. - * 15-Sep-02 Gerd Woetzel - * slightly changed framework for sparc - * 29-Jun-02 Christian Tismer - * Added register 13-29, 31 saves. The same way as - * Armin Rigo did for the x86_unix version. - * This seems to be now fully functional! - * 04-Mar-02 Hye-Shik Chang - * Ported from i386. - */ - -#define STACK_REFPLUS 1 - -#ifdef SLP_EVAL - -#define STACK_MAGIC 3 - -/* !!!!WARNING!!!! need to add "r31" in the next line if this header file - * is meant to be compiled non-dynamically! - */ -#define REGS_TO_SAVE "r13", "r14", "r15", "r16", "r17", "r18", "r19", "r20", \ - "r21", "r22", "r23", "r24", "r25", "r26", "r27", "r28", "r29", \ - "cr2", "cr3", "cr4" -static int -slp_switch(void) -{ - int err; - int *stackref, stsizediff; - __asm__ volatile ("" : : : REGS_TO_SAVE); - __asm__ ("mr %0, 1" : "=r" (stackref) : ); - { - SLP_SAVE_STATE(stackref, stsizediff); - __asm__ volatile ( - "mr 11, %0\n" - "add 1, 1, 11\n" - : /* no outputs */ - : "r" (stsizediff) - : "11" - ); - SLP_RESTORE_STATE(); - } - __asm__ volatile ("" : : : REGS_TO_SAVE); - __asm__ volatile ("li %0, 0" : "=r" (err)); - return err; -} - -#endif - -/* - * further self-processing support - */ - -/* - * if you want to add self-inspection tools, place them - * here. See the x86_msvc for the necessary defines. - * These features are highly experimental und not - * essential yet. - */ diff --git a/venv/lib/python3.9/site-packages/greenlet/platform/switch_ppc_linux.h b/venv/lib/python3.9/site-packages/greenlet/platform/switch_ppc_linux.h deleted file mode 100644 index e83ad70..0000000 --- a/venv/lib/python3.9/site-packages/greenlet/platform/switch_ppc_linux.h +++ /dev/null @@ -1,84 +0,0 @@ -/* - * this is the internal transfer function. - * - * HISTORY - * 07-Sep-05 (py-dev mailing list discussion) - * removed 'r31' from the register-saved. !!!! WARNING !!!! - * It means that this file can no longer be compiled statically! - * It is now only suitable as part of a dynamic library! - * 14-Jan-04 Bob Ippolito - * added cr2-cr4 to the registers to be saved. - * Open questions: Should we save FP registers? - * What about vector registers? - * Differences between darwin and unix? - * 24-Nov-02 Christian Tismer - * needed to add another magic constant to insure - * that f in slp_eval_frame(PyFrameObject *f) - * STACK_REFPLUS will probably be 1 in most cases. - * gets included into the saved stack area. - * 04-Oct-02 Gustavo Niemeyer - * Ported from MacOS version. - * 17-Sep-02 Christian Tismer - * after virtualizing stack save/restore, the - * stack size shrunk a bit. Needed to introduce - * an adjustment STACK_MAGIC per platform. - * 15-Sep-02 Gerd Woetzel - * slightly changed framework for sparc - * 29-Jun-02 Christian Tismer - * Added register 13-29, 31 saves. The same way as - * Armin Rigo did for the x86_unix version. - * This seems to be now fully functional! - * 04-Mar-02 Hye-Shik Chang - * Ported from i386. - * 31-Jul-12 Trevor Bowen - * Changed memory constraints to register only. - */ - -#define STACK_REFPLUS 1 - -#ifdef SLP_EVAL - -#define STACK_MAGIC 3 - -/* !!!!WARNING!!!! need to add "r31" in the next line if this header file - * is meant to be compiled non-dynamically! - */ -#define REGS_TO_SAVE "r13", "r14", "r15", "r16", "r17", "r18", "r19", "r20", \ - "r21", "r22", "r23", "r24", "r25", "r26", "r27", "r28", "r29", \ - "cr2", "cr3", "cr4" -static int -slp_switch(void) -{ - int err; - int *stackref, stsizediff; - __asm__ volatile ("" : : : REGS_TO_SAVE); - __asm__ ("mr %0, 1" : "=r" (stackref) : ); - { - SLP_SAVE_STATE(stackref, stsizediff); - __asm__ volatile ( - "mr 11, %0\n" - "add 1, 1, 11\n" - "add 30, 30, 11\n" - : /* no outputs */ - : "r" (stsizediff) - : "11" - ); - SLP_RESTORE_STATE(); - } - __asm__ volatile ("" : : : REGS_TO_SAVE); - __asm__ volatile ("li %0, 0" : "=r" (err)); - return err; -} - -#endif - -/* - * further self-processing support - */ - -/* - * if you want to add self-inspection tools, place them - * here. See the x86_msvc for the necessary defines. - * These features are highly experimental und not - * essential yet. - */ diff --git a/venv/lib/python3.9/site-packages/greenlet/platform/switch_ppc_macosx.h b/venv/lib/python3.9/site-packages/greenlet/platform/switch_ppc_macosx.h deleted file mode 100644 index bd414c6..0000000 --- a/venv/lib/python3.9/site-packages/greenlet/platform/switch_ppc_macosx.h +++ /dev/null @@ -1,82 +0,0 @@ -/* - * this is the internal transfer function. - * - * HISTORY - * 07-Sep-05 (py-dev mailing list discussion) - * removed 'r31' from the register-saved. !!!! WARNING !!!! - * It means that this file can no longer be compiled statically! - * It is now only suitable as part of a dynamic library! - * 14-Jan-04 Bob Ippolito - * added cr2-cr4 to the registers to be saved. - * Open questions: Should we save FP registers? - * What about vector registers? - * Differences between darwin and unix? - * 24-Nov-02 Christian Tismer - * needed to add another magic constant to insure - * that f in slp_eval_frame(PyFrameObject *f) - * STACK_REFPLUS will probably be 1 in most cases. - * gets included into the saved stack area. - * 17-Sep-02 Christian Tismer - * after virtualizing stack save/restore, the - * stack size shrunk a bit. Needed to introduce - * an adjustment STACK_MAGIC per platform. - * 15-Sep-02 Gerd Woetzel - * slightly changed framework for sparc - * 29-Jun-02 Christian Tismer - * Added register 13-29, 31 saves. The same way as - * Armin Rigo did for the x86_unix version. - * This seems to be now fully functional! - * 04-Mar-02 Hye-Shik Chang - * Ported from i386. - */ - -#define STACK_REFPLUS 1 - -#ifdef SLP_EVAL - -#define STACK_MAGIC 3 - -/* !!!!WARNING!!!! need to add "r31" in the next line if this header file - * is meant to be compiled non-dynamically! - */ -#define REGS_TO_SAVE "r13", "r14", "r15", "r16", "r17", "r18", "r19", "r20", \ - "r21", "r22", "r23", "r24", "r25", "r26", "r27", "r28", "r29", \ - "cr2", "cr3", "cr4" - -static int -slp_switch(void) -{ - int err; - int *stackref, stsizediff; - __asm__ volatile ("" : : : REGS_TO_SAVE); - __asm__ ("; asm block 2\n\tmr %0, r1" : "=r" (stackref) : ); - { - SLP_SAVE_STATE(stackref, stsizediff); - __asm__ volatile ( - "; asm block 3\n" - "\tmr r11, %0\n" - "\tadd r1, r1, r11\n" - "\tadd r30, r30, r11\n" - : /* no outputs */ - : "r" (stsizediff) - : "r11" - ); - SLP_RESTORE_STATE(); - } - __asm__ volatile ("" : : : REGS_TO_SAVE); - __asm__ volatile ("li %0, 0" : "=r" (err)); - return err; -} - -#endif - -/* - * further self-processing support - */ - -/* - * if you want to add self-inspection tools, place them - * here. See the x86_msvc for the necessary defines. - * These features are highly experimental und not - * essential yet. - */ diff --git a/venv/lib/python3.9/site-packages/greenlet/platform/switch_ppc_unix.h b/venv/lib/python3.9/site-packages/greenlet/platform/switch_ppc_unix.h deleted file mode 100644 index bb18808..0000000 --- a/venv/lib/python3.9/site-packages/greenlet/platform/switch_ppc_unix.h +++ /dev/null @@ -1,82 +0,0 @@ -/* - * this is the internal transfer function. - * - * HISTORY - * 07-Sep-05 (py-dev mailing list discussion) - * removed 'r31' from the register-saved. !!!! WARNING !!!! - * It means that this file can no longer be compiled statically! - * It is now only suitable as part of a dynamic library! - * 14-Jan-04 Bob Ippolito - * added cr2-cr4 to the registers to be saved. - * Open questions: Should we save FP registers? - * What about vector registers? - * Differences between darwin and unix? - * 24-Nov-02 Christian Tismer - * needed to add another magic constant to insure - * that f in slp_eval_frame(PyFrameObject *f) - * STACK_REFPLUS will probably be 1 in most cases. - * gets included into the saved stack area. - * 04-Oct-02 Gustavo Niemeyer - * Ported from MacOS version. - * 17-Sep-02 Christian Tismer - * after virtualizing stack save/restore, the - * stack size shrunk a bit. Needed to introduce - * an adjustment STACK_MAGIC per platform. - * 15-Sep-02 Gerd Woetzel - * slightly changed framework for sparc - * 29-Jun-02 Christian Tismer - * Added register 13-29, 31 saves. The same way as - * Armin Rigo did for the x86_unix version. - * This seems to be now fully functional! - * 04-Mar-02 Hye-Shik Chang - * Ported from i386. - */ - -#define STACK_REFPLUS 1 - -#ifdef SLP_EVAL - -#define STACK_MAGIC 3 - -/* !!!!WARNING!!!! need to add "r31" in the next line if this header file - * is meant to be compiled non-dynamically! - */ -#define REGS_TO_SAVE "r13", "r14", "r15", "r16", "r17", "r18", "r19", "r20", \ - "r21", "r22", "r23", "r24", "r25", "r26", "r27", "r28", "r29", \ - "cr2", "cr3", "cr4" -static int -slp_switch(void) -{ - int err; - int *stackref, stsizediff; - __asm__ volatile ("" : : : REGS_TO_SAVE); - __asm__ ("mr %0, 1" : "=r" (stackref) : ); - { - SLP_SAVE_STATE(stackref, stsizediff); - __asm__ volatile ( - "mr 11, %0\n" - "add 1, 1, 11\n" - "add 30, 30, 11\n" - : /* no outputs */ - : "r" (stsizediff) - : "11" - ); - SLP_RESTORE_STATE(); - } - __asm__ volatile ("" : : : REGS_TO_SAVE); - __asm__ volatile ("li %0, 0" : "=r" (err)); - return err; -} - -#endif - -/* - * further self-processing support - */ - -/* - * if you want to add self-inspection tools, place them - * here. See the x86_msvc for the necessary defines. - * These features are highly experimental und not - * essential yet. - */ diff --git a/venv/lib/python3.9/site-packages/greenlet/platform/switch_riscv_unix.h b/venv/lib/python3.9/site-packages/greenlet/platform/switch_riscv_unix.h deleted file mode 100644 index 8761122..0000000 --- a/venv/lib/python3.9/site-packages/greenlet/platform/switch_riscv_unix.h +++ /dev/null @@ -1,41 +0,0 @@ -#define STACK_REFPLUS 1 - -#ifdef SLP_EVAL -#define STACK_MAGIC 0 - -#define REGS_TO_SAVE "s1", "s2", "s3", "s4", "s5", \ - "s6", "s7", "s8", "s9", "s10", "s11", "fs0", "fs1", \ - "fs2", "fs3", "fs4", "fs5", "fs6", "fs7", "fs8", "fs9", \ - "fs10", "fs11" - -static int -slp_switch(void) -{ - int ret; - long fp; - long *stackref, stsizediff; - - __asm__ volatile ("" : : : REGS_TO_SAVE); - __asm__ volatile ("mv %0, fp" : "=r" (fp) : ); - __asm__ volatile ("mv %0, sp" : "=r" (stackref) : ); - { - SLP_SAVE_STATE(stackref, stsizediff); - __asm__ volatile ( - "add sp, sp, %0\n\t" - "add fp, fp, %0\n\t" - : /* no outputs */ - : "r" (stsizediff) - ); - SLP_RESTORE_STATE(); - } - __asm__ volatile ("" : : : REGS_TO_SAVE); -#if __riscv_xlen == 32 - __asm__ volatile ("lw fp, %0" : : "m" (fp)); -#else - __asm__ volatile ("ld fp, %0" : : "m" (fp)); -#endif - __asm__ volatile ("mv %0, zero" : "=r" (ret) : ); - return ret; -} - -#endif diff --git a/venv/lib/python3.9/site-packages/greenlet/platform/switch_s390_unix.h b/venv/lib/python3.9/site-packages/greenlet/platform/switch_s390_unix.h deleted file mode 100644 index 9199367..0000000 --- a/venv/lib/python3.9/site-packages/greenlet/platform/switch_s390_unix.h +++ /dev/null @@ -1,87 +0,0 @@ -/* - * this is the internal transfer function. - * - * HISTORY - * 25-Jan-12 Alexey Borzenkov - * Fixed Linux/S390 port to work correctly with - * different optimization options both on 31-bit - * and 64-bit. Thanks to Stefan Raabe for lots - * of testing. - * 24-Nov-02 Christian Tismer - * needed to add another magic constant to insure - * that f in slp_eval_frame(PyFrameObject *f) - * STACK_REFPLUS will probably be 1 in most cases. - * gets included into the saved stack area. - * 06-Oct-02 Gustavo Niemeyer - * Ported to Linux/S390. - */ - -#define STACK_REFPLUS 1 - -#ifdef SLP_EVAL - -#ifdef __s390x__ -#define STACK_MAGIC 20 /* 20 * 8 = 160 bytes of function call area */ -#else -#define STACK_MAGIC 24 /* 24 * 4 = 96 bytes of function call area */ -#endif - -/* Technically, r11-r13 also need saving, but function prolog starts - with stm(g) and since there are so many saved registers already - it won't be optimized, resulting in all r6-r15 being saved */ -#define REGS_TO_SAVE "r6", "r7", "r8", "r9", "r10", "r14", \ - "f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7", \ - "f8", "f9", "f10", "f11", "f12", "f13", "f14", "f15" - -static int -slp_switch(void) -{ - int ret; - long *stackref, stsizediff; - __asm__ volatile ("" : : : REGS_TO_SAVE); -#ifdef __s390x__ - __asm__ volatile ("lgr %0, 15" : "=r" (stackref) : ); -#else - __asm__ volatile ("lr %0, 15" : "=r" (stackref) : ); -#endif - { - SLP_SAVE_STATE(stackref, stsizediff); -/* N.B. - r11 may be used as the frame pointer, and in that case it cannot be - clobbered and needs offsetting just like the stack pointer (but in cases - where frame pointer isn't used we might clobber it accidentally). What's - scary is that r11 is 2nd (and even 1st when GOT is used) callee saved - register that gcc would chose for surviving function calls. However, - since r6-r10 are clobbered above, their cost for reuse is reduced, so - gcc IRA will chose them over r11 (not seeing r11 is implicitly saved), - making it relatively safe to offset in all cases. :) */ - __asm__ volatile ( -#ifdef __s390x__ - "agr 15, %0\n\t" - "agr 11, %0" -#else - "ar 15, %0\n\t" - "ar 11, %0" -#endif - : /* no outputs */ - : "r" (stsizediff) - ); - SLP_RESTORE_STATE(); - } - __asm__ volatile ("" : : : REGS_TO_SAVE); - __asm__ volatile ("lhi %0, 0" : "=r" (ret) : ); - return ret; -} - -#endif - -/* - * further self-processing support - */ - -/* - * if you want to add self-inspection tools, place them - * here. See the x86_msvc for the necessary defines. - * These features are highly experimental und not - * essential yet. - */ diff --git a/venv/lib/python3.9/site-packages/greenlet/platform/switch_sh_gcc.h b/venv/lib/python3.9/site-packages/greenlet/platform/switch_sh_gcc.h deleted file mode 100644 index 5ecc3b3..0000000 --- a/venv/lib/python3.9/site-packages/greenlet/platform/switch_sh_gcc.h +++ /dev/null @@ -1,36 +0,0 @@ -#define STACK_REFPLUS 1 - -#ifdef SLP_EVAL -#define STACK_MAGIC 0 -#define REGS_TO_SAVE "r8", "r9", "r10", "r11", "r13", \ - "fr12", "fr13", "fr14", "fr15" - -// r12 Global context pointer, GP -// r14 Frame pointer, FP -// r15 Stack pointer, SP - -static int -slp_switch(void) -{ - int err; - void* fp; - int *stackref, stsizediff; - __asm__ volatile("" : : : REGS_TO_SAVE); - __asm__ volatile("mov.l r14, %0" : "=m"(fp) : :); - __asm__("mov r15, %0" : "=r"(stackref)); - { - SLP_SAVE_STATE(stackref, stsizediff); - __asm__ volatile( - "add %0, r15\n" - "add %0, r14\n" - : /* no outputs */ - : "r"(stsizediff)); - SLP_RESTORE_STATE(); - __asm__ volatile("mov r0, %0" : "=r"(err) : :); - } - __asm__ volatile("mov.l %0, r14" : : "m"(fp) :); - __asm__ volatile("" : : : REGS_TO_SAVE); - return err; -} - -#endif diff --git a/venv/lib/python3.9/site-packages/greenlet/platform/switch_sparc_sun_gcc.h b/venv/lib/python3.9/site-packages/greenlet/platform/switch_sparc_sun_gcc.h deleted file mode 100644 index 96990c3..0000000 --- a/venv/lib/python3.9/site-packages/greenlet/platform/switch_sparc_sun_gcc.h +++ /dev/null @@ -1,92 +0,0 @@ -/* - * this is the internal transfer function. - * - * HISTORY - * 16-May-15 Alexey Borzenkov - * Move stack spilling code inside save/restore functions - * 30-Aug-13 Floris Bruynooghe - Clean the register windows again before returning. - This does not clobber the PIC register as it leaves - the current window intact and is required for multi- - threaded code to work correctly. - * 08-Mar-11 Floris Bruynooghe - * No need to set return value register explicitly - * before the stack and framepointer are adjusted - * as none of the other registers are influenced by - * this. Also don't needlessly clean the windows - * ('ta %0" :: "i" (ST_CLEAN_WINDOWS)') as that - * clobbers the gcc PIC register (%l7). - * 24-Nov-02 Christian Tismer - * needed to add another magic constant to insure - * that f in slp_eval_frame(PyFrameObject *f) - * STACK_REFPLUS will probably be 1 in most cases. - * gets included into the saved stack area. - * 17-Sep-02 Christian Tismer - * after virtualizing stack save/restore, the - * stack size shrunk a bit. Needed to introduce - * an adjustment STACK_MAGIC per platform. - * 15-Sep-02 Gerd Woetzel - * added support for SunOS sparc with gcc - */ - -#define STACK_REFPLUS 1 - -#ifdef SLP_EVAL - - -#define STACK_MAGIC 0 - - -#if defined(__sparcv9) -#define SLP_FLUSHW __asm__ volatile ("flushw") -#else -#define SLP_FLUSHW __asm__ volatile ("ta 3") /* ST_FLUSH_WINDOWS */ -#endif - -/* On sparc we need to spill register windows inside save/restore functions */ -#define SLP_BEFORE_SAVE_STATE() SLP_FLUSHW -#define SLP_BEFORE_RESTORE_STATE() SLP_FLUSHW - - -static int -slp_switch(void) -{ - int err; - int *stackref, stsizediff; - - /* Put current stack pointer into stackref. - * Register spilling is done in save/restore. - */ - __asm__ volatile ("mov %%sp, %0" : "=r" (stackref)); - - { - /* Thou shalt put SLP_SAVE_STATE into a local block */ - /* Copy the current stack onto the heap */ - SLP_SAVE_STATE(stackref, stsizediff); - - /* Increment stack and frame pointer by stsizediff */ - __asm__ volatile ( - "add %0, %%sp, %%sp\n\t" - "add %0, %%fp, %%fp" - : : "r" (stsizediff)); - - /* Copy new stack from it's save store on the heap */ - SLP_RESTORE_STATE(); - - __asm__ volatile ("mov %1, %0" : "=r" (err) : "i" (0)); - return err; - } -} - -#endif - -/* - * further self-processing support - */ - -/* - * if you want to add self-inspection tools, place them - * here. See the x86_msvc for the necessary defines. - * These features are highly experimental und not - * essential yet. - */ diff --git a/venv/lib/python3.9/site-packages/greenlet/platform/switch_x32_unix.h b/venv/lib/python3.9/site-packages/greenlet/platform/switch_x32_unix.h deleted file mode 100644 index 893369c..0000000 --- a/venv/lib/python3.9/site-packages/greenlet/platform/switch_x32_unix.h +++ /dev/null @@ -1,63 +0,0 @@ -/* - * this is the internal transfer function. - * - * HISTORY - * 17-Aug-12 Fantix King - * Ported from amd64. - */ - -#define STACK_REFPLUS 1 - -#ifdef SLP_EVAL - -#define STACK_MAGIC 0 - -#define REGS_TO_SAVE "r12", "r13", "r14", "r15" - - -static int -slp_switch(void) -{ - void* ebp; - void* ebx; - unsigned int csr; - unsigned short cw; - int err; - int *stackref, stsizediff; - __asm__ volatile ("" : : : REGS_TO_SAVE); - __asm__ volatile ("fstcw %0" : "=m" (cw)); - __asm__ volatile ("stmxcsr %0" : "=m" (csr)); - __asm__ volatile ("movl %%ebp, %0" : "=m" (ebp)); - __asm__ volatile ("movl %%ebx, %0" : "=m" (ebx)); - __asm__ ("movl %%esp, %0" : "=g" (stackref)); - { - SLP_SAVE_STATE(stackref, stsizediff); - __asm__ volatile ( - "addl %0, %%esp\n" - "addl %0, %%ebp\n" - : - : "r" (stsizediff) - ); - SLP_RESTORE_STATE(); - } - __asm__ volatile ("movl %0, %%ebx" : : "m" (ebx)); - __asm__ volatile ("movl %0, %%ebp" : : "m" (ebp)); - __asm__ volatile ("ldmxcsr %0" : : "m" (csr)); - __asm__ volatile ("fldcw %0" : : "m" (cw)); - __asm__ volatile ("" : : : REGS_TO_SAVE); - __asm__ volatile ("xorl %%eax, %%eax" : "=a" (err)); - return err; -} - -#endif - -/* - * further self-processing support - */ - -/* - * if you want to add self-inspection tools, place them - * here. See the x86_msvc for the necessary defines. - * These features are highly experimental und not - * essential yet. - */ diff --git a/venv/lib/python3.9/site-packages/greenlet/platform/switch_x64_masm.asm b/venv/lib/python3.9/site-packages/greenlet/platform/switch_x64_masm.asm deleted file mode 100644 index f5c72a2..0000000 --- a/venv/lib/python3.9/site-packages/greenlet/platform/switch_x64_masm.asm +++ /dev/null @@ -1,111 +0,0 @@ -; -; stack switching code for MASM on x641 -; Kristjan Valur Jonsson, sept 2005 -; - - -;prototypes for our calls -slp_save_state_asm PROTO -slp_restore_state_asm PROTO - - -pushxmm MACRO reg - sub rsp, 16 - .allocstack 16 - movaps [rsp], reg ; faster than movups, but we must be aligned - ; .savexmm128 reg, offset (don't know what offset is, no documentation) -ENDM -popxmm MACRO reg - movaps reg, [rsp] ; faster than movups, but we must be aligned - add rsp, 16 -ENDM - -pushreg MACRO reg - push reg - .pushreg reg -ENDM -popreg MACRO reg - pop reg -ENDM - - -.code -slp_switch PROC FRAME - ;realign stack to 16 bytes after return address push, makes the following faster - sub rsp,8 - .allocstack 8 - - pushxmm xmm15 - pushxmm xmm14 - pushxmm xmm13 - pushxmm xmm12 - pushxmm xmm11 - pushxmm xmm10 - pushxmm xmm9 - pushxmm xmm8 - pushxmm xmm7 - pushxmm xmm6 - - pushreg r15 - pushreg r14 - pushreg r13 - pushreg r12 - - pushreg rbp - pushreg rbx - pushreg rdi - pushreg rsi - - sub rsp, 10h ;allocate the singlefunction argument (must be multiple of 16) - .allocstack 10h -.endprolog - - lea rcx, [rsp+10h] ;load stack base that we are saving - call slp_save_state_asm ;pass stackpointer, return offset in eax - cmp rax, 1 - je EXIT1 - cmp rax, -1 - je EXIT2 - ;actual stack switch: - add rsp, rax - call slp_restore_state_asm - xor rax, rax ;return 0 - -EXIT: - - add rsp, 10h - popreg rsi - popreg rdi - popreg rbx - popreg rbp - - popreg r12 - popreg r13 - popreg r14 - popreg r15 - - popxmm xmm6 - popxmm xmm7 - popxmm xmm8 - popxmm xmm9 - popxmm xmm10 - popxmm xmm11 - popxmm xmm12 - popxmm xmm13 - popxmm xmm14 - popxmm xmm15 - - add rsp, 8 - ret - -EXIT1: - mov rax, 1 - jmp EXIT - -EXIT2: - sar rax, 1 - jmp EXIT - -slp_switch ENDP - -END \ No newline at end of file diff --git a/venv/lib/python3.9/site-packages/greenlet/platform/switch_x64_masm.obj b/venv/lib/python3.9/site-packages/greenlet/platform/switch_x64_masm.obj deleted file mode 100644 index 64e3e6b..0000000 Binary files a/venv/lib/python3.9/site-packages/greenlet/platform/switch_x64_masm.obj and /dev/null differ diff --git a/venv/lib/python3.9/site-packages/greenlet/platform/switch_x64_msvc.h b/venv/lib/python3.9/site-packages/greenlet/platform/switch_x64_msvc.h deleted file mode 100644 index 601ea56..0000000 --- a/venv/lib/python3.9/site-packages/greenlet/platform/switch_x64_msvc.h +++ /dev/null @@ -1,60 +0,0 @@ -/* - * this is the internal transfer function. - * - * HISTORY - * 24-Nov-02 Christian Tismer - * needed to add another magic constant to insure - * that f in slp_eval_frame(PyFrameObject *f) - * STACK_REFPLUS will probably be 1 in most cases. - * gets included into the saved stack area. - * 26-Sep-02 Christian Tismer - * again as a result of virtualized stack access, - * the compiler used less registers. Needed to - * explicit mention registers in order to get them saved. - * Thanks to Jeff Senn for pointing this out and help. - * 17-Sep-02 Christian Tismer - * after virtualizing stack save/restore, the - * stack size shrunk a bit. Needed to introduce - * an adjustment STACK_MAGIC per platform. - * 15-Sep-02 Gerd Woetzel - * slightly changed framework for sparc - * 01-Mar-02 Christian Tismer - * Initial final version after lots of iterations for i386. - */ - -/* Avoid alloca redefined warning on mingw64 */ -#ifndef alloca -#define alloca _alloca -#endif - -#define STACK_REFPLUS 1 -#define STACK_MAGIC 0 - -/* Use the generic support for an external assembly language slp_switch function. */ -#define EXTERNAL_ASM - -#ifdef SLP_EVAL -/* This always uses the external masm assembly file. */ -#endif - -/* - * further self-processing support - */ - -/* we have IsBadReadPtr available, so we can peek at objects */ -/* -#define STACKLESS_SPY - -#ifdef IMPLEMENT_STACKLESSMODULE -#include "Windows.h" -#define CANNOT_READ_MEM(p, bytes) IsBadReadPtr(p, bytes) - -static int IS_ON_STACK(void*p) -{ - int stackref; - intptr_t stackbase = ((intptr_t)&stackref) & 0xfffff000; - return (intptr_t)p >= stackbase && (intptr_t)p < stackbase + 0x00100000; -} - -#endif -*/ \ No newline at end of file diff --git a/venv/lib/python3.9/site-packages/greenlet/platform/switch_x86_msvc.h b/venv/lib/python3.9/site-packages/greenlet/platform/switch_x86_msvc.h deleted file mode 100644 index 0f3a59f..0000000 --- a/venv/lib/python3.9/site-packages/greenlet/platform/switch_x86_msvc.h +++ /dev/null @@ -1,326 +0,0 @@ -/* - * this is the internal transfer function. - * - * HISTORY - * 24-Nov-02 Christian Tismer - * needed to add another magic constant to insure - * that f in slp_eval_frame(PyFrameObject *f) - * STACK_REFPLUS will probably be 1 in most cases. - * gets included into the saved stack area. - * 26-Sep-02 Christian Tismer - * again as a result of virtualized stack access, - * the compiler used less registers. Needed to - * explicit mention registers in order to get them saved. - * Thanks to Jeff Senn for pointing this out and help. - * 17-Sep-02 Christian Tismer - * after virtualizing stack save/restore, the - * stack size shrunk a bit. Needed to introduce - * an adjustment STACK_MAGIC per platform. - * 15-Sep-02 Gerd Woetzel - * slightly changed framework for sparc - * 01-Mar-02 Christian Tismer - * Initial final version after lots of iterations for i386. - */ - -#define alloca _alloca - -#define STACK_REFPLUS 1 - -#ifdef SLP_EVAL - -#define STACK_MAGIC 0 - -/* Some magic to quell warnings and keep slp_switch() from crashing when built - with VC90. Disable global optimizations, and the warning: frame pointer - register 'ebp' modified by inline assembly code. - - We used to just disable global optimizations ("g") but upstream stackless - Python, as well as stackman, turn off all optimizations. - -References: -https://github.com/stackless-dev/stackman/blob/dbc72fe5207a2055e658c819fdeab9731dee78b9/stackman/platforms/switch_x86_msvc.h -https://github.com/stackless-dev/stackless/blob/main-slp/Stackless/platf/switch_x86_msvc.h -*/ -#define WIN32_LEAN_AND_MEAN -#include - -#pragma optimize("", off) /* so that autos are stored on the stack */ -#pragma warning(disable:4731) -#pragma warning(disable:4733) /* disable warning about modifying FS[0] */ - -/** - * Most modern compilers and environments handle C++ exceptions without any - * special help from us. MSVC on 32-bit windows is an exception. There, C++ - * exceptions are dealt with using Windows' Structured Exception Handling - * (SEH). - * - * SEH is implemented as a singly linked list of nodes. The - * head of this list is stored in the Thread Information Block, which itself - * is pointed to from the FS register. It's the first field in the structure, - * or offset 0, so we can access it using assembly FS:[0], or the compiler - * intrinsics and field offset information from the headers (as we do below). - * Somewhat unusually, the tail of the list doesn't have prev == NULL, it has - * prev == 0xFFFFFFFF. - * - * SEH was designed for C, and traditionally uses the MSVC compiler - * intrinsincs __try{}/__except{}. It is also utilized for C++ exceptions by - * MSVC; there, every throw of a C++ exception raises a SEH error with the - * ExceptionCode 0xE06D7363; the SEH handler list is then traversed to - * deal with the exception. - * - * If the SEH list is corrupt, then when a C++ exception is thrown the program - * will abruptly exit with exit code 1. This does not use std::terminate(), so - * std::set_terminate() is useless to debug this. - * - * The SEH list is closely tied to the call stack; entering a function that - * uses __try{} or most C++ functions will push a new handler onto the front - * of the list. Returning from the function will remove the handler. Saving - * and restoring the head node of the SEH list (FS:[0]) per-greenlet is NOT - * ENOUGH to make SEH or exceptions work. - * - * Stack switching breaks SEH because the call stack no longer necessarily - * matches the SEH list. For example, given greenlet A that switches to - * greenlet B, at the moment of entering greenlet B, we will have any SEH - * handlers from greenlet A on the SEH list; greenlet B can then add its own - * handlers to the SEH list. When greenlet B switches back to greenlet A, - * greenlet B's handlers would still be on the SEH stack, but when switch() - * returns control to greenlet A, we have replaced the contents of the stack - * in memory, so all the address that greenlet B added to the SEH list are now - * invalid: part of the call stack has been unwound, but the SEH list was out - * of sync with the call stack. The net effect is that exception handling - * stops working. - * - * Thus, when switching greenlets, we need to be sure that the SEH list - * matches the effective call stack, "cutting out" any handlers that were - * pushed by the greenlet that switched out and which are no longer valid. - * - * The easiest way to do this is to capture the SEH list at the time the main - * greenlet for a thread is created, and, when initially starting a greenlet, - * start a new SEH list for it, which contains nothing but the handler - * established for the new greenlet itself, with the tail being the handlers - * for the main greenlet. If we then save and restore the SEH per-greenlet, - * they won't interfere with each others SEH lists. (No greenlet can unwind - * the call stack past the handlers established by the main greenlet). - * - * By observation, a new thread starts with three SEH handlers on the list. By - * the time we get around to creating the main greenlet, though, there can be - * many more, established by transient calls that lead to the creation of the - * main greenlet. Therefore, 3 is a magic constant telling us when to perform - * the initial slice. - * - * All of this can be debugged using a vectored exception handler, which - * operates independently of the SEH handler list, and is called first. - * Walking the SEH list at key points can also be helpful. - * - * References: - * https://en.wikipedia.org/wiki/Win32_Thread_Information_Block - * https://devblogs.microsoft.com/oldnewthing/20100730-00/?p=13273 - * https://docs.microsoft.com/en-us/cpp/cpp/try-except-statement?view=msvc-160 - * https://docs.microsoft.com/en-us/cpp/cpp/structured-exception-handling-c-cpp?view=msvc-160 - * https://docs.microsoft.com/en-us/windows/win32/debug/structured-exception-handling - * https://docs.microsoft.com/en-us/windows/win32/debug/using-a-vectored-exception-handler - * https://bytepointer.com/resources/pietrek_crash_course_depths_of_win32_seh.htm - */ -#define GREENLET_NEEDS_EXCEPTION_STATE_SAVED - - -typedef struct _GExceptionRegistration { - struct _GExceptionRegistration* prev; - void* handler_f; -} GExceptionRegistration; - -static void -slp_set_exception_state(const void *const seh_state) -{ - // Because the stack from from which we do this is ALSO a handler, and - // that one we want to keep, we need to relink the current SEH handler - // frame to point to this one, cutting out the middle men, as it were. - // - // Entering a try block doesn't change the SEH frame, but entering a - // function containing a try block does. - GExceptionRegistration* current_seh_state = (GExceptionRegistration*)__readfsdword(FIELD_OFFSET(NT_TIB, ExceptionList)); - current_seh_state->prev = (GExceptionRegistration*)seh_state; -} - - -static GExceptionRegistration* -x86_slp_get_third_oldest_handler() -{ - GExceptionRegistration* a = NULL; /* Closest to the top */ - GExceptionRegistration* b = NULL; /* second */ - GExceptionRegistration* c = NULL; - GExceptionRegistration* seh_state = (GExceptionRegistration*)__readfsdword(FIELD_OFFSET(NT_TIB, ExceptionList)); - a = b = c = seh_state; - - while (seh_state && seh_state != (GExceptionRegistration*)0xFFFFFFFF) { - if ((void*)seh_state->prev < (void*)100) { - fprintf(stderr, "\tERROR: Broken SEH chain.\n"); - return NULL; - } - a = b; - b = c; - c = seh_state; - - seh_state = seh_state->prev; - } - return a ? a : (b ? b : c); -} - - -static void* -slp_get_exception_state() -{ - // XXX: There appear to be three SEH handlers on the stack already at the - // start of the thread. Is that a guarantee? Almost certainly not. Yet in - // all observed cases it has been three. This is consistent with - // faulthandler off or on, and optimizations off or on. It may not be - // consistent with other operating system versions, though: we only have - // CI on one or two versions (don't ask what there are). - // In theory we could capture the number of handlers on the chain when - // PyInit__greenlet is called: there are probably only the default - // handlers at that point (unless we're embedded and people have used - // __try/__except or a C++ handler)? - return x86_slp_get_third_oldest_handler(); -} - -static int -slp_switch(void) -{ - /* MASM syntax is typically reversed from other assemblers. - It is usually - */ - int *stackref, stsizediff; - /* store the structured exception state for this stack */ - DWORD seh_state = __readfsdword(FIELD_OFFSET(NT_TIB, ExceptionList)); - __asm mov stackref, esp; - /* modify EBX, ESI and EDI in order to get them preserved */ - __asm mov ebx, ebx; - __asm xchg esi, edi; - { - SLP_SAVE_STATE(stackref, stsizediff); - __asm { - mov eax, stsizediff - add esp, eax - add ebp, eax - } - SLP_RESTORE_STATE(); - } - __writefsdword(FIELD_OFFSET(NT_TIB, ExceptionList), seh_state); - return 0; -} - -/* re-enable ebp warning and global optimizations. */ -#pragma optimize("", on) -#pragma warning(default:4731) -#pragma warning(default:4733) /* disable warning about modifying FS[0] */ - - -#endif - -/* - * further self-processing support - */ - -/* we have IsBadReadPtr available, so we can peek at objects */ -#define STACKLESS_SPY - -#ifdef GREENLET_DEBUG - -#define CANNOT_READ_MEM(p, bytes) IsBadReadPtr(p, bytes) - -static int IS_ON_STACK(void*p) -{ - int stackref; - int stackbase = ((int)&stackref) & 0xfffff000; - return (int)p >= stackbase && (int)p < stackbase + 0x00100000; -} - -static void -x86_slp_show_seh_chain() -{ - GExceptionRegistration* seh_state = (GExceptionRegistration*)__readfsdword(FIELD_OFFSET(NT_TIB, ExceptionList)); - fprintf(stderr, "====== SEH Chain ======\n"); - while (seh_state && seh_state != (GExceptionRegistration*)0xFFFFFFFF) { - fprintf(stderr, "\tSEH_chain addr: %p handler: %p prev: %p\n", - seh_state, - seh_state->handler_f, seh_state->prev); - if ((void*)seh_state->prev < (void*)100) { - fprintf(stderr, "\tERROR: Broken chain.\n"); - break; - } - seh_state = seh_state->prev; - } - fprintf(stderr, "====== End SEH Chain ======\n"); - fflush(NULL); - return; -} - -//addVectoredExceptionHandler constants: -//CALL_FIRST means call this exception handler first; -//CALL_LAST means call this exception handler last -#define CALL_FIRST 1 -#define CALL_LAST 0 - -LONG WINAPI -GreenletVectorHandler(PEXCEPTION_POINTERS ExceptionInfo) -{ - // We get one of these for every C++ exception, with code - // E06D7363 - // This is a special value that means "C++ exception from MSVC" - // https://devblogs.microsoft.com/oldnewthing/20100730-00/?p=13273 - // - // Install in the module init function with: - // AddVectoredExceptionHandler(CALL_FIRST, GreenletVectorHandler); - PEXCEPTION_RECORD ExceptionRecord = ExceptionInfo->ExceptionRecord; - - fprintf(stderr, - "GOT VECTORED EXCEPTION:\n" - "\tExceptionCode : %p\n" - "\tExceptionFlags : %p\n" - "\tExceptionAddr : %p\n" - "\tNumberparams : %ld\n", - ExceptionRecord->ExceptionCode, - ExceptionRecord->ExceptionFlags, - ExceptionRecord->ExceptionAddress, - ExceptionRecord->NumberParameters - ); - if (ExceptionRecord->ExceptionFlags & 1) { - fprintf(stderr, "\t\tEH_NONCONTINUABLE\n" ); - } - if (ExceptionRecord->ExceptionFlags & 2) { - fprintf(stderr, "\t\tEH_UNWINDING\n" ); - } - if (ExceptionRecord->ExceptionFlags & 4) { - fprintf(stderr, "\t\tEH_EXIT_UNWIND\n" ); - } - if (ExceptionRecord->ExceptionFlags & 8) { - fprintf(stderr, "\t\tEH_STACK_INVALID\n" ); - } - if (ExceptionRecord->ExceptionFlags & 0x10) { - fprintf(stderr, "\t\tEH_NESTED_CALL\n" ); - } - if (ExceptionRecord->ExceptionFlags & 0x20) { - fprintf(stderr, "\t\tEH_TARGET_UNWIND\n" ); - } - if (ExceptionRecord->ExceptionFlags & 0x40) { - fprintf(stderr, "\t\tEH_COLLIDED_UNWIND\n" ); - } - fprintf(stderr, "\n"); - fflush(NULL); - for(DWORD i = 0; i < ExceptionRecord->NumberParameters; i++) { - fprintf(stderr, "\t\t\tParam %ld: %lX\n", i, ExceptionRecord->ExceptionInformation[i]); - } - - if (ExceptionRecord->NumberParameters == 3) { - fprintf(stderr, "\tAbout to traverse SEH chain\n"); - // C++ Exception records have 3 params. - x86_slp_show_seh_chain(); - } - - return EXCEPTION_CONTINUE_SEARCH; -} - - - - -#endif diff --git a/venv/lib/python3.9/site-packages/greenlet/platform/switch_x86_unix.h b/venv/lib/python3.9/site-packages/greenlet/platform/switch_x86_unix.h deleted file mode 100644 index 493fa6b..0000000 --- a/venv/lib/python3.9/site-packages/greenlet/platform/switch_x86_unix.h +++ /dev/null @@ -1,105 +0,0 @@ -/* - * this is the internal transfer function. - * - * HISTORY - * 3-May-13 Ralf Schmitt - * Add support for strange GCC caller-save decisions - * (ported from switch_aarch64_gcc.h) - * 19-Aug-11 Alexey Borzenkov - * Correctly save ebp, ebx and cw - * 07-Sep-05 (py-dev mailing list discussion) - * removed 'ebx' from the register-saved. !!!! WARNING !!!! - * It means that this file can no longer be compiled statically! - * It is now only suitable as part of a dynamic library! - * 24-Nov-02 Christian Tismer - * needed to add another magic constant to insure - * that f in slp_eval_frame(PyFrameObject *f) - * STACK_REFPLUS will probably be 1 in most cases. - * gets included into the saved stack area. - * 17-Sep-02 Christian Tismer - * after virtualizing stack save/restore, the - * stack size shrunk a bit. Needed to introduce - * an adjustment STACK_MAGIC per platform. - * 15-Sep-02 Gerd Woetzel - * slightly changed framework for spark - * 31-Avr-02 Armin Rigo - * Added ebx, esi and edi register-saves. - * 01-Mar-02 Samual M. Rushing - * Ported from i386. - */ - -#define STACK_REFPLUS 1 - -#ifdef SLP_EVAL - -/* #define STACK_MAGIC 3 */ -/* the above works fine with gcc 2.96, but 2.95.3 wants this */ -#define STACK_MAGIC 0 - -#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 5) -# define ATTR_NOCLONE __attribute__((noclone)) -#else -# define ATTR_NOCLONE -#endif - -static int -slp_switch(void) -{ - int err; -#ifdef _WIN32 - void *seh; -#endif - void *ebp, *ebx; - unsigned short cw; - int *stackref, stsizediff; - __asm__ volatile ("" : : : "esi", "edi"); - __asm__ volatile ("fstcw %0" : "=m" (cw)); - __asm__ volatile ("movl %%ebp, %0" : "=m" (ebp)); - __asm__ volatile ("movl %%ebx, %0" : "=m" (ebx)); -#ifdef _WIN32 - __asm__ volatile ( - "movl %%fs:0x0, %%eax\n" - "movl %%eax, %0\n" - : "=m" (seh) - : - : "eax"); -#endif - __asm__ ("movl %%esp, %0" : "=g" (stackref)); - { - SLP_SAVE_STATE(stackref, stsizediff); - __asm__ volatile ( - "addl %0, %%esp\n" - "addl %0, %%ebp\n" - : - : "r" (stsizediff) - ); - SLP_RESTORE_STATE(); - __asm__ volatile ("xorl %%eax, %%eax" : "=a" (err)); - } -#ifdef _WIN32 - __asm__ volatile ( - "movl %0, %%eax\n" - "movl %%eax, %%fs:0x0\n" - : - : "m" (seh) - : "eax"); -#endif - __asm__ volatile ("movl %0, %%ebx" : : "m" (ebx)); - __asm__ volatile ("movl %0, %%ebp" : : "m" (ebp)); - __asm__ volatile ("fldcw %0" : : "m" (cw)); - __asm__ volatile ("" : : : "esi", "edi"); - return err; -} - -#endif - -/* - * further self-processing support - */ - -/* - * if you want to add self-inspection tools, place them - * here. See the x86_msvc for the necessary defines. - * These features are highly experimental und not - * essential yet. - */ diff --git a/venv/lib/python3.9/site-packages/greenlet/slp_platformselect.h b/venv/lib/python3.9/site-packages/greenlet/slp_platformselect.h deleted file mode 100644 index d9b7d0a..0000000 --- a/venv/lib/python3.9/site-packages/greenlet/slp_platformselect.h +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Platform Selection for Stackless Python - */ -#ifdef __cplusplus -extern "C" { -#endif - -#if defined(MS_WIN32) && !defined(MS_WIN64) && defined(_M_IX86) && defined(_MSC_VER) -# include "platform/switch_x86_msvc.h" /* MS Visual Studio on X86 */ -#elif defined(MS_WIN64) && defined(_M_X64) && defined(_MSC_VER) || defined(__MINGW64__) -# include "platform/switch_x64_msvc.h" /* MS Visual Studio on X64 */ -#elif defined(MS_WIN64) && defined(_M_ARM64) -# include "platform/switch_arm64_msvc.h" /* MS Visual Studio on ARM64 */ -#elif defined(__GNUC__) && defined(__amd64__) && defined(__ILP32__) -# include "platform/switch_x32_unix.h" /* gcc on amd64 with x32 ABI */ -#elif defined(__GNUC__) && defined(__amd64__) -# include "platform/switch_amd64_unix.h" /* gcc on amd64 */ -#elif defined(__GNUC__) && defined(__i386__) -# include "platform/switch_x86_unix.h" /* gcc on X86 */ -#elif defined(__GNUC__) && defined(__powerpc64__) && (defined(__linux__) || defined(__FreeBSD__)) -# include "platform/switch_ppc64_linux.h" /* gcc on PowerPC 64-bit */ -#elif defined(__GNUC__) && defined(__PPC__) && (defined(__linux__) || defined(__FreeBSD__)) -# include "platform/switch_ppc_linux.h" /* gcc on PowerPC */ -#elif defined(__GNUC__) && defined(__POWERPC__) && defined(__APPLE__) -# include "platform/switch_ppc_macosx.h" /* Apple MacOS X on 32-bit PowerPC */ -#elif defined(__GNUC__) && defined(__powerpc64__) && defined(_AIX) -# include "platform/switch_ppc64_aix.h" /* gcc on AIX/PowerPC 64-bit */ -#elif defined(__GNUC__) && defined(_ARCH_PPC) && defined(_AIX) -# include "platform/switch_ppc_aix.h" /* gcc on AIX/PowerPC */ -#elif defined(__GNUC__) && defined(__powerpc__) && defined(__NetBSD__) -#include "platform/switch_ppc_unix.h" /* gcc on NetBSD/powerpc */ -#elif defined(__GNUC__) && defined(sparc) -# include "platform/switch_sparc_sun_gcc.h" /* SunOS sparc with gcc */ -#elif defined(__GNUC__) && defined(__sparc__) -# include "platform/switch_sparc_sun_gcc.h" /* NetBSD sparc with gcc */ -#elif defined(__SUNPRO_C) && defined(sparc) && defined(sun) -# include "platform/switch_sparc_sun_gcc.h" /* SunStudio on amd64 */ -#elif defined(__SUNPRO_C) && defined(__amd64__) && defined(sun) -# include "platform/switch_amd64_unix.h" /* SunStudio on amd64 */ -#elif defined(__SUNPRO_C) && defined(__i386__) && defined(sun) -# include "platform/switch_x86_unix.h" /* SunStudio on x86 */ -#elif defined(__GNUC__) && defined(__s390__) && defined(__linux__) -# include "platform/switch_s390_unix.h" /* Linux/S390 */ -#elif defined(__GNUC__) && defined(__s390x__) && defined(__linux__) -# include "platform/switch_s390_unix.h" /* Linux/S390 zSeries (64-bit) */ -#elif defined(__GNUC__) && defined(__arm__) -# ifdef __APPLE__ -# include -# endif -# if TARGET_OS_IPHONE -# include "platform/switch_arm32_ios.h" /* iPhone OS on arm32 */ -# else -# include "platform/switch_arm32_gcc.h" /* gcc using arm32 */ -# endif -#elif defined(__GNUC__) && defined(__mips__) && defined(__linux__) -# include "platform/switch_mips_unix.h" /* Linux/MIPS */ -#elif defined(__GNUC__) && defined(__aarch64__) -# include "platform/switch_aarch64_gcc.h" /* Aarch64 ABI */ -#elif defined(__GNUC__) && defined(__mc68000__) -# include "platform/switch_m68k_gcc.h" /* gcc on m68k */ -#elif defined(__GNUC__) && defined(__csky__) -#include "platform/switch_csky_gcc.h" /* gcc on csky */ -# elif defined(__GNUC__) && defined(__riscv) -# include "platform/switch_riscv_unix.h" /* gcc on RISC-V */ -#elif defined(__GNUC__) && defined(__alpha__) -# include "platform/switch_alpha_unix.h" /* gcc on DEC Alpha */ -#elif defined(MS_WIN32) && defined(__llvm__) && defined(__aarch64__) -# include "platform/switch_aarch64_gcc.h" /* LLVM Aarch64 ABI for Windows */ -#elif defined(__GNUC__) && defined(__loongarch64) && defined(__linux__) -# include "platform/switch_loongarch64_linux.h" /* LoongArch64 */ -#elif defined(__GNUC__) && defined(__sh__) -# include "platform/switch_sh_gcc.h" /* SuperH */ -#endif - -#ifdef __cplusplus -}; -#endif diff --git a/venv/lib/python3.9/site-packages/greenlet/tests/__init__.py b/venv/lib/python3.9/site-packages/greenlet/tests/__init__.py deleted file mode 100644 index 1861360..0000000 --- a/venv/lib/python3.9/site-packages/greenlet/tests/__init__.py +++ /dev/null @@ -1,248 +0,0 @@ -# -*- coding: utf-8 -*- -""" -Tests for greenlet. - -""" -import os -import sys -import sysconfig -import unittest - -from gc import collect -from gc import get_objects -from threading import active_count as active_thread_count -from time import sleep -from time import time - -import psutil - -from greenlet import greenlet as RawGreenlet -from greenlet import getcurrent - -from greenlet._greenlet import get_pending_cleanup_count -from greenlet._greenlet import get_total_main_greenlets - -from . import leakcheck - -PY312 = sys.version_info[:2] >= (3, 12) -PY313 = sys.version_info[:2] >= (3, 13) -# XXX: First tested on 3.14a7. Revisit all uses of this on later versions to ensure they -# are still valid. -PY314 = sys.version_info[:2] >= (3, 14) - -WIN = sys.platform.startswith("win") -RUNNING_ON_GITHUB_ACTIONS = os.environ.get('GITHUB_ACTIONS') -RUNNING_ON_TRAVIS = os.environ.get('TRAVIS') or RUNNING_ON_GITHUB_ACTIONS -RUNNING_ON_APPVEYOR = os.environ.get('APPVEYOR') -RUNNING_ON_CI = RUNNING_ON_TRAVIS or RUNNING_ON_APPVEYOR -RUNNING_ON_MANYLINUX = os.environ.get('GREENLET_MANYLINUX') - -# Is the current interpreter free-threaded?) Note that this -# isn't the same as whether the GIL is enabled, this is the build-time -# value. Certain CPython details, like the garbage collector, -# work very differently on potentially-free-threaded builds than -# standard builds. -RUNNING_ON_FREETHREAD_BUILD = bool(sysconfig.get_config_var("Py_GIL_DISABLED")) - -class TestCaseMetaClass(type): - # wrap each test method with - # a) leak checks - def __new__(cls, classname, bases, classDict): - # pylint and pep8 fight over what this should be called (mcs or cls). - # pylint gets it right, but we can't scope disable pep8, so we go with - # its convention. - # pylint: disable=bad-mcs-classmethod-argument - check_totalrefcount = True - - # Python 3: must copy, we mutate the classDict. Interestingly enough, - # it doesn't actually error out, but under 3.6 we wind up wrapping - # and re-wrapping the same items over and over and over. - for key, value in list(classDict.items()): - if key.startswith('test') and callable(value): - classDict.pop(key) - if check_totalrefcount: - value = leakcheck.wrap_refcount(value) - classDict[key] = value - return type.__new__(cls, classname, bases, classDict) - - -class TestCase(unittest.TestCase, metaclass=TestCaseMetaClass): - - cleanup_attempt_sleep_duration = 0.001 - cleanup_max_sleep_seconds = 1 - - def wait_for_pending_cleanups(self, - initial_active_threads=None, - initial_main_greenlets=None): - initial_active_threads = initial_active_threads or self.threads_before_test - initial_main_greenlets = initial_main_greenlets or self.main_greenlets_before_test - sleep_time = self.cleanup_attempt_sleep_duration - # NOTE: This is racy! A Python-level thread object may be dead - # and gone, but the C thread may not yet have fired its - # destructors and added to the queue. There's no particular - # way to know that's about to happen. We try to watch the - # Python threads to make sure they, at least, have gone away. - # Counting the main greenlets, which we can easily do deterministically, - # also helps. - - # Always sleep at least once to let other threads run - sleep(sleep_time) - quit_after = time() + self.cleanup_max_sleep_seconds - # TODO: We could add an API that calls us back when a particular main greenlet is deleted? - # It would have to drop the GIL - while ( - get_pending_cleanup_count() - or active_thread_count() > initial_active_threads - or (not self.expect_greenlet_leak - and get_total_main_greenlets() > initial_main_greenlets)): - sleep(sleep_time) - if time() > quit_after: - print("Time limit exceeded.") - print("Threads: Waiting for only", initial_active_threads, - "-->", active_thread_count()) - print("MGlets : Waiting for only", initial_main_greenlets, - "-->", get_total_main_greenlets()) - break - collect() - - def count_objects(self, kind=list, exact_kind=True): - # pylint:disable=unidiomatic-typecheck - # Collect the garbage. - for _ in range(3): - collect() - if exact_kind: - return sum( - 1 - for x in get_objects() - if type(x) is kind - ) - # instances - return sum( - 1 - for x in get_objects() - if isinstance(x, kind) - ) - - greenlets_before_test = 0 - threads_before_test = 0 - main_greenlets_before_test = 0 - expect_greenlet_leak = False - - def count_greenlets(self): - """ - Find all the greenlets and subclasses tracked by the GC. - """ - return self.count_objects(RawGreenlet, False) - - def setUp(self): - # Ensure the main greenlet exists, otherwise the first test - # gets a false positive leak - super().setUp() - getcurrent() - self.threads_before_test = active_thread_count() - self.main_greenlets_before_test = get_total_main_greenlets() - self.wait_for_pending_cleanups(self.threads_before_test, self.main_greenlets_before_test) - self.greenlets_before_test = self.count_greenlets() - - def tearDown(self): - if getattr(self, 'skipTearDown', False): - return - - self.wait_for_pending_cleanups(self.threads_before_test, self.main_greenlets_before_test) - super().tearDown() - - def get_expected_returncodes_for_aborted_process(self): - import signal - # The child should be aborted in an unusual way. On POSIX - # platforms, this is done with abort() and signal.SIGABRT, - # which is reflected in a negative return value; however, on - # Windows, even though we observe the child print "Fatal - # Python error: Aborted" and in older versions of the C - # runtime "This application has requested the Runtime to - # terminate it in an unusual way," it always has an exit code - # of 3. This is interesting because 3 is the error code for - # ERROR_PATH_NOT_FOUND; BUT: the C runtime abort() function - # also uses this code. - # - # If we link to the static C library on Windows, the error - # code changes to '0xc0000409' (hex(3221226505)), which - # apparently is STATUS_STACK_BUFFER_OVERRUN; but "What this - # means is that nowadays when you get a - # STATUS_STACK_BUFFER_OVERRUN, it doesn’t actually mean that - # there is a stack buffer overrun. It just means that the - # application decided to terminate itself with great haste." - # - # - # On windows, we've also seen '0xc0000005' (hex(3221225477)). - # That's "Access Violation" - # - # See - # https://devblogs.microsoft.com/oldnewthing/20110519-00/?p=10623 - # and - # https://docs.microsoft.com/en-us/previous-versions/k089yyh0(v=vs.140)?redirectedfrom=MSDN - # and - # https://devblogs.microsoft.com/oldnewthing/20190108-00/?p=100655 - expected_exit = ( - -signal.SIGABRT, - # But beginning on Python 3.11, the faulthandler - # that prints the C backtraces sometimes segfaults after - # reporting the exception but before printing the stack. - # This has only been seen on linux/gcc. - -signal.SIGSEGV, - ) if not WIN else ( - 3, - 0xc0000409, - 0xc0000005, - ) - return expected_exit - - def get_process_uss(self): - """ - Return the current process's USS in bytes. - - uss is available on Linux, macOS, Windows. Also known as - "Unique Set Size", this is the memory which is unique to a - process and which would be freed if the process was terminated - right now. - - If this is not supported by ``psutil``, this raises the - :exc:`unittest.SkipTest` exception. - """ - try: - return psutil.Process().memory_full_info().uss - except AttributeError as e: - raise unittest.SkipTest("uss not supported") from e - - def run_script(self, script_name, show_output=True): - import subprocess - script = os.path.join( - os.path.dirname(__file__), - script_name, - ) - - try: - return subprocess.check_output([sys.executable, script], - encoding='utf-8', - stderr=subprocess.STDOUT) - except subprocess.CalledProcessError as ex: - if show_output: - print('-----') - print('Failed to run script', script) - print('~~~~~') - print(ex.output) - print('------') - raise - - - def assertScriptRaises(self, script_name, exitcodes=None): - import subprocess - with self.assertRaises(subprocess.CalledProcessError) as exc: - output = self.run_script(script_name, show_output=False) - __traceback_info__ = output - # We're going to fail the assertion if we get here, at least - # preserve the output in the traceback. - - if exitcodes is None: - exitcodes = self.get_expected_returncodes_for_aborted_process() - self.assertIn(exc.exception.returncode, exitcodes) - return exc.exception diff --git a/venv/lib/python3.9/site-packages/greenlet/tests/_test_extension.c b/venv/lib/python3.9/site-packages/greenlet/tests/_test_extension.c deleted file mode 100644 index 05e81c0..0000000 --- a/venv/lib/python3.9/site-packages/greenlet/tests/_test_extension.c +++ /dev/null @@ -1,231 +0,0 @@ -/* This is a set of functions used by test_extension_interface.py to test the - * Greenlet C API. - */ - -#include "../greenlet.h" - -#ifndef Py_RETURN_NONE -# define Py_RETURN_NONE return Py_INCREF(Py_None), Py_None -#endif - -#define TEST_MODULE_NAME "_test_extension" - -static PyObject* -test_switch(PyObject* self, PyObject* greenlet) -{ - PyObject* result = NULL; - - if (greenlet == NULL || !PyGreenlet_Check(greenlet)) { - PyErr_BadArgument(); - return NULL; - } - - result = PyGreenlet_Switch((PyGreenlet*)greenlet, NULL, NULL); - if (result == NULL) { - if (!PyErr_Occurred()) { - PyErr_SetString(PyExc_AssertionError, - "greenlet.switch() failed for some reason."); - } - return NULL; - } - Py_INCREF(result); - return result; -} - -static PyObject* -test_switch_kwargs(PyObject* self, PyObject* args, PyObject* kwargs) -{ - PyGreenlet* g = NULL; - PyObject* result = NULL; - - PyArg_ParseTuple(args, "O!", &PyGreenlet_Type, &g); - - if (g == NULL || !PyGreenlet_Check(g)) { - PyErr_BadArgument(); - return NULL; - } - - result = PyGreenlet_Switch(g, NULL, kwargs); - if (result == NULL) { - if (!PyErr_Occurred()) { - PyErr_SetString(PyExc_AssertionError, - "greenlet.switch() failed for some reason."); - } - return NULL; - } - Py_XINCREF(result); - return result; -} - -static PyObject* -test_getcurrent(PyObject* self) -{ - PyGreenlet* g = PyGreenlet_GetCurrent(); - if (g == NULL || !PyGreenlet_Check(g) || !PyGreenlet_ACTIVE(g)) { - PyErr_SetString(PyExc_AssertionError, - "getcurrent() returned an invalid greenlet"); - Py_XDECREF(g); - return NULL; - } - Py_DECREF(g); - Py_RETURN_NONE; -} - -static PyObject* -test_setparent(PyObject* self, PyObject* arg) -{ - PyGreenlet* current; - PyGreenlet* greenlet = NULL; - - if (arg == NULL || !PyGreenlet_Check(arg)) { - PyErr_BadArgument(); - return NULL; - } - if ((current = PyGreenlet_GetCurrent()) == NULL) { - return NULL; - } - greenlet = (PyGreenlet*)arg; - if (PyGreenlet_SetParent(greenlet, current)) { - Py_DECREF(current); - return NULL; - } - Py_DECREF(current); - if (PyGreenlet_Switch(greenlet, NULL, NULL) == NULL) { - return NULL; - } - Py_RETURN_NONE; -} - -static PyObject* -test_new_greenlet(PyObject* self, PyObject* callable) -{ - PyObject* result = NULL; - PyGreenlet* greenlet = PyGreenlet_New(callable, NULL); - - if (!greenlet) { - return NULL; - } - - result = PyGreenlet_Switch(greenlet, NULL, NULL); - Py_CLEAR(greenlet); - if (result == NULL) { - return NULL; - } - - Py_INCREF(result); - return result; -} - -static PyObject* -test_raise_dead_greenlet(PyObject* self) -{ - PyErr_SetString(PyExc_GreenletExit, "test GreenletExit exception."); - return NULL; -} - -static PyObject* -test_raise_greenlet_error(PyObject* self) -{ - PyErr_SetString(PyExc_GreenletError, "test greenlet.error exception"); - return NULL; -} - -static PyObject* -test_throw(PyObject* self, PyGreenlet* g) -{ - const char msg[] = "take that sucka!"; - PyObject* msg_obj = Py_BuildValue("s", msg); - PyGreenlet_Throw(g, PyExc_ValueError, msg_obj, NULL); - Py_DECREF(msg_obj); - if (PyErr_Occurred()) { - return NULL; - } - Py_RETURN_NONE; -} - -static PyObject* -test_throw_exact(PyObject* self, PyObject* args) -{ - PyGreenlet* g = NULL; - PyObject* typ = NULL; - PyObject* val = NULL; - PyObject* tb = NULL; - - if (!PyArg_ParseTuple(args, "OOOO:throw", &g, &typ, &val, &tb)) { - return NULL; - } - - PyGreenlet_Throw(g, typ, val, tb); - if (PyErr_Occurred()) { - return NULL; - } - Py_RETURN_NONE; -} - -static PyMethodDef test_methods[] = { - {"test_switch", - (PyCFunction)test_switch, - METH_O, - "Switch to the provided greenlet sending provided arguments, and \n" - "return the results."}, - {"test_switch_kwargs", - (PyCFunction)test_switch_kwargs, - METH_VARARGS | METH_KEYWORDS, - "Switch to the provided greenlet sending the provided keyword args."}, - {"test_getcurrent", - (PyCFunction)test_getcurrent, - METH_NOARGS, - "Test PyGreenlet_GetCurrent()"}, - {"test_setparent", - (PyCFunction)test_setparent, - METH_O, - "Se the parent of the provided greenlet and switch to it."}, - {"test_new_greenlet", - (PyCFunction)test_new_greenlet, - METH_O, - "Test PyGreenlet_New()"}, - {"test_raise_dead_greenlet", - (PyCFunction)test_raise_dead_greenlet, - METH_NOARGS, - "Just raise greenlet.GreenletExit"}, - {"test_raise_greenlet_error", - (PyCFunction)test_raise_greenlet_error, - METH_NOARGS, - "Just raise greenlet.error"}, - {"test_throw", - (PyCFunction)test_throw, - METH_O, - "Throw a ValueError at the provided greenlet"}, - {"test_throw_exact", - (PyCFunction)test_throw_exact, - METH_VARARGS, - "Throw exactly the arguments given at the provided greenlet"}, - {NULL, NULL, 0, NULL} -}; - - -#define INITERROR return NULL - -static struct PyModuleDef moduledef = {PyModuleDef_HEAD_INIT, - TEST_MODULE_NAME, - NULL, - 0, - test_methods, - NULL, - NULL, - NULL, - NULL}; - -PyMODINIT_FUNC -PyInit__test_extension(void) -{ - PyObject* module = NULL; - module = PyModule_Create(&moduledef); - - if (module == NULL) { - return NULL; - } - - PyGreenlet_Import(); - return module; -} diff --git a/venv/lib/python3.9/site-packages/greenlet/tests/_test_extension.cpython-39-x86_64-linux-gnu.so b/venv/lib/python3.9/site-packages/greenlet/tests/_test_extension.cpython-39-x86_64-linux-gnu.so deleted file mode 100755 index b7e0a51..0000000 Binary files a/venv/lib/python3.9/site-packages/greenlet/tests/_test_extension.cpython-39-x86_64-linux-gnu.so and /dev/null differ diff --git a/venv/lib/python3.9/site-packages/greenlet/tests/_test_extension_cpp.cpp b/venv/lib/python3.9/site-packages/greenlet/tests/_test_extension_cpp.cpp deleted file mode 100644 index 5cbe6a7..0000000 --- a/venv/lib/python3.9/site-packages/greenlet/tests/_test_extension_cpp.cpp +++ /dev/null @@ -1,226 +0,0 @@ -/* This is a set of functions used to test C++ exceptions are not - * broken during greenlet switches - */ - -#include "../greenlet.h" -#include "../greenlet_compiler_compat.hpp" -#include -#include - -struct exception_t { - int depth; - exception_t(int depth) : depth(depth) {} -}; - -/* Functions are called via pointers to prevent inlining */ -static void (*p_test_exception_throw_nonstd)(int depth); -static void (*p_test_exception_throw_std)(); -static PyObject* (*p_test_exception_switch_recurse)(int depth, int left); - -static void -test_exception_throw_nonstd(int depth) -{ - throw exception_t(depth); -} - -static void -test_exception_throw_std() -{ - throw std::runtime_error("Thrown from an extension."); -} - -static PyObject* -test_exception_switch_recurse(int depth, int left) -{ - if (left > 0) { - return p_test_exception_switch_recurse(depth, left - 1); - } - - PyObject* result = NULL; - PyGreenlet* self = PyGreenlet_GetCurrent(); - if (self == NULL) - return NULL; - - try { - if (PyGreenlet_Switch(PyGreenlet_GET_PARENT(self), NULL, NULL) == NULL) { - Py_DECREF(self); - return NULL; - } - p_test_exception_throw_nonstd(depth); - PyErr_SetString(PyExc_RuntimeError, - "throwing C++ exception didn't work"); - } - catch (const exception_t& e) { - if (e.depth != depth) - PyErr_SetString(PyExc_AssertionError, "depth mismatch"); - else - result = PyLong_FromLong(depth); - } - catch (...) { - PyErr_SetString(PyExc_RuntimeError, "unexpected C++ exception"); - } - - Py_DECREF(self); - return result; -} - -/* test_exception_switch(int depth) - * - recurses depth times - * - switches to parent inside try/catch block - * - throws an exception that (expected to be caught in the same function) - * - verifies depth matches (exceptions shouldn't be caught in other greenlets) - */ -static PyObject* -test_exception_switch(PyObject* UNUSED(self), PyObject* args) -{ - int depth; - if (!PyArg_ParseTuple(args, "i", &depth)) - return NULL; - return p_test_exception_switch_recurse(depth, depth); -} - - -static PyObject* -py_test_exception_throw_nonstd(PyObject* self, PyObject* args) -{ - if (!PyArg_ParseTuple(args, "")) - return NULL; - p_test_exception_throw_nonstd(0); - PyErr_SetString(PyExc_AssertionError, "unreachable code running after throw"); - return NULL; -} - -static PyObject* -py_test_exception_throw_std(PyObject* self, PyObject* args) -{ - if (!PyArg_ParseTuple(args, "")) - return NULL; - p_test_exception_throw_std(); - PyErr_SetString(PyExc_AssertionError, "unreachable code running after throw"); - return NULL; -} - -static PyObject* -py_test_call(PyObject* self, PyObject* arg) -{ - PyObject* noargs = PyTuple_New(0); - PyObject* ret = PyObject_Call(arg, noargs, nullptr); - Py_DECREF(noargs); - return ret; -} - - - -/* test_exception_switch_and_do_in_g2(g2func) - * - creates new greenlet g2 to run g2func - * - switches to g2 inside try/catch block - * - verifies that no exception has been caught - * - * it is used together with test_exception_throw to verify that unhandled - * exceptions thrown in one greenlet do not propagate to other greenlet nor - * segfault the process. - */ -static PyObject* -test_exception_switch_and_do_in_g2(PyObject* self, PyObject* args) -{ - PyObject* g2func = NULL; - PyObject* result = NULL; - - if (!PyArg_ParseTuple(args, "O", &g2func)) - return NULL; - PyGreenlet* g2 = PyGreenlet_New(g2func, NULL); - if (!g2) { - return NULL; - } - - try { - result = PyGreenlet_Switch(g2, NULL, NULL); - if (!result) { - return NULL; - } - } - catch (const exception_t& e) { - /* if we are here the memory can be already corrupted and the program - * might crash before below py-level exception might become printed. - * -> print something to stderr to make it clear that we had entered - * this catch block. - * See comments in inner_bootstrap() - */ -#if defined(WIN32) || defined(_WIN32) - fprintf(stderr, "C++ exception unexpectedly caught in g1\n"); - PyErr_SetString(PyExc_AssertionError, "C++ exception unexpectedly caught in g1"); - Py_XDECREF(result); - return NULL; -#else - throw; -#endif - } - - Py_XDECREF(result); - Py_RETURN_NONE; -} - -static PyMethodDef test_methods[] = { - {"test_exception_switch", - (PyCFunction)&test_exception_switch, - METH_VARARGS, - "Switches to parent twice, to test exception handling and greenlet " - "switching."}, - {"test_exception_switch_and_do_in_g2", - (PyCFunction)&test_exception_switch_and_do_in_g2, - METH_VARARGS, - "Creates new greenlet g2 to run g2func and switches to it inside try/catch " - "block. Used together with test_exception_throw to verify that unhandled " - "C++ exceptions thrown in a greenlet doe not corrupt memory."}, - {"test_exception_throw_nonstd", - (PyCFunction)&py_test_exception_throw_nonstd, - METH_VARARGS, - "Throws non-standard C++ exception. Calling this function directly should abort the process." - }, - {"test_exception_throw_std", - (PyCFunction)&py_test_exception_throw_std, - METH_VARARGS, - "Throws standard C++ exception. Calling this function directly should abort the process." - }, - {"test_call", - (PyCFunction)&py_test_call, - METH_O, - "Call the given callable. Unlike calling it directly, this creates a " - "new C-level stack frame, which may be helpful in testing." - }, - {NULL, NULL, 0, NULL} -}; - - -static struct PyModuleDef moduledef = {PyModuleDef_HEAD_INIT, - "greenlet.tests._test_extension_cpp", - NULL, - 0, - test_methods, - NULL, - NULL, - NULL, - NULL}; - -PyMODINIT_FUNC -PyInit__test_extension_cpp(void) -{ - PyObject* module = NULL; - - module = PyModule_Create(&moduledef); - - if (module == NULL) { - return NULL; - } - - PyGreenlet_Import(); - if (_PyGreenlet_API == NULL) { - return NULL; - } - - p_test_exception_throw_nonstd = test_exception_throw_nonstd; - p_test_exception_throw_std = test_exception_throw_std; - p_test_exception_switch_recurse = test_exception_switch_recurse; - - return module; -} diff --git a/venv/lib/python3.9/site-packages/greenlet/tests/_test_extension_cpp.cpython-39-x86_64-linux-gnu.so b/venv/lib/python3.9/site-packages/greenlet/tests/_test_extension_cpp.cpython-39-x86_64-linux-gnu.so deleted file mode 100755 index 49eca52..0000000 Binary files a/venv/lib/python3.9/site-packages/greenlet/tests/_test_extension_cpp.cpython-39-x86_64-linux-gnu.so and /dev/null differ diff --git a/venv/lib/python3.9/site-packages/greenlet/tests/fail_clearing_run_switches.py b/venv/lib/python3.9/site-packages/greenlet/tests/fail_clearing_run_switches.py deleted file mode 100644 index 6dd1492..0000000 --- a/venv/lib/python3.9/site-packages/greenlet/tests/fail_clearing_run_switches.py +++ /dev/null @@ -1,47 +0,0 @@ -# -*- coding: utf-8 -*- -""" -If we have a run callable passed to the constructor or set as an -attribute, but we don't actually use that (because ``__getattribute__`` -or the like interferes), then when we clear callable before beginning -to run, there's an opportunity for Python code to run. - -""" -import greenlet - -g = None -main = greenlet.getcurrent() - -results = [] - -class RunCallable: - - def __del__(self): - results.append(('RunCallable', '__del__')) - main.switch('from RunCallable') - - -class G(greenlet.greenlet): - - def __getattribute__(self, name): - if name == 'run': - results.append(('G.__getattribute__', 'run')) - return run_func - return object.__getattribute__(self, name) - - -def run_func(): - results.append(('run_func', 'enter')) - - -g = G(RunCallable()) -# Try to start G. It will get to the point where it deletes -# its run callable C++ variable in inner_bootstrap. That triggers -# the __del__ method, which switches back to main before g -# actually even starts running. -x = g.switch() -results.append(('main: g.switch()', x)) -# In the C++ code, this results in g->g_switch() appearing to return, even though -# it has yet to run. -print('In main with', x, flush=True) -g.switch() -print('RESULTS', results) diff --git a/venv/lib/python3.9/site-packages/greenlet/tests/fail_cpp_exception.py b/venv/lib/python3.9/site-packages/greenlet/tests/fail_cpp_exception.py deleted file mode 100644 index fa4dc2e..0000000 --- a/venv/lib/python3.9/site-packages/greenlet/tests/fail_cpp_exception.py +++ /dev/null @@ -1,33 +0,0 @@ -# -*- coding: utf-8 -*- -""" -Helper for testing a C++ exception throw aborts the process. - -Takes one argument, the name of the function in :mod:`_test_extension_cpp` to call. -""" -import sys -import greenlet -from greenlet.tests import _test_extension_cpp -print('fail_cpp_exception is running') - -def run_unhandled_exception_in_greenlet_aborts(): - def _(): - _test_extension_cpp.test_exception_switch_and_do_in_g2( - _test_extension_cpp.test_exception_throw_nonstd - ) - g1 = greenlet.greenlet(_) - g1.switch() - - -func_name = sys.argv[1] -try: - func = getattr(_test_extension_cpp, func_name) -except AttributeError: - if func_name == run_unhandled_exception_in_greenlet_aborts.__name__: - func = run_unhandled_exception_in_greenlet_aborts - elif func_name == 'run_as_greenlet_target': - g = greenlet.greenlet(_test_extension_cpp.test_exception_throw_std) - func = g.switch - else: - raise -print('raising', func, flush=True) -func() diff --git a/venv/lib/python3.9/site-packages/greenlet/tests/fail_initialstub_already_started.py b/venv/lib/python3.9/site-packages/greenlet/tests/fail_initialstub_already_started.py deleted file mode 100644 index c1a44ef..0000000 --- a/venv/lib/python3.9/site-packages/greenlet/tests/fail_initialstub_already_started.py +++ /dev/null @@ -1,78 +0,0 @@ -""" -Testing initialstub throwing an already started exception. -""" - -import greenlet - -a = None -b = None -c = None -main = greenlet.getcurrent() - -# If we switch into a dead greenlet, -# we go looking for its parents. -# if a parent is not yet started, we start it. - -results = [] - -def a_run(*args): - #results.append('A') - results.append(('Begin A', args)) - - -def c_run(): - results.append('Begin C') - b.switch('From C') - results.append('C done') - -class A(greenlet.greenlet): pass - -class B(greenlet.greenlet): - doing_it = False - def __getattribute__(self, name): - if name == 'run' and not self.doing_it: - assert greenlet.getcurrent() is c - self.doing_it = True - results.append('Switch to b from B.__getattribute__ in ' - + type(greenlet.getcurrent()).__name__) - b.switch() - results.append('B.__getattribute__ back from main in ' - + type(greenlet.getcurrent()).__name__) - if name == 'run': - name = '_B_run' - return object.__getattribute__(self, name) - - def _B_run(self, *arg): - results.append(('Begin B', arg)) - results.append('_B_run switching to main') - main.switch('From B') - -class C(greenlet.greenlet): - pass -a = A(a_run) -b = B(parent=a) -c = C(c_run, b) - -# Start a child; while running, it will start B, -# but starting B will ALSO start B. -result = c.switch() -results.append(('main from c', result)) - -# Switch back to C, which was in the middle of switching -# already. This will throw the ``GreenletStartedWhileInPython`` -# exception, which results in parent A getting started (B is finished) -c.switch() - -results.append(('A dead?', a.dead, 'B dead?', b.dead, 'C dead?', c.dead)) - -# A and B should both be dead now. -assert a.dead -assert b.dead -assert not c.dead - -result = c.switch() -results.append(('main from c.2', result)) -# Now C is dead -assert c.dead - -print("RESULTS:", results) diff --git a/venv/lib/python3.9/site-packages/greenlet/tests/fail_slp_switch.py b/venv/lib/python3.9/site-packages/greenlet/tests/fail_slp_switch.py deleted file mode 100644 index 0990526..0000000 --- a/venv/lib/python3.9/site-packages/greenlet/tests/fail_slp_switch.py +++ /dev/null @@ -1,29 +0,0 @@ -# -*- coding: utf-8 -*- -""" -A test helper for seeing what happens when slp_switch() -fails. -""" -# pragma: no cover - -import greenlet - - -print('fail_slp_switch is running', flush=True) - -runs = [] -def func(): - runs.append(1) - greenlet.getcurrent().parent.switch() - runs.append(2) - greenlet.getcurrent().parent.switch() - runs.append(3) - -g = greenlet._greenlet.UnswitchableGreenlet(func) -g.switch() -assert runs == [1] -g.switch() -assert runs == [1, 2] -g.force_slp_switch_error = True - -# This should crash. -g.switch() diff --git a/venv/lib/python3.9/site-packages/greenlet/tests/fail_switch_three_greenlets.py b/venv/lib/python3.9/site-packages/greenlet/tests/fail_switch_three_greenlets.py deleted file mode 100644 index e151b19..0000000 --- a/venv/lib/python3.9/site-packages/greenlet/tests/fail_switch_three_greenlets.py +++ /dev/null @@ -1,44 +0,0 @@ -""" -Uses a trace function to switch greenlets at unexpected times. - -In the trace function, we switch from the current greenlet to another -greenlet, which switches -""" -import greenlet - -g1 = None -g2 = None - -switch_to_g2 = False - -def tracefunc(*args): - print('TRACE', *args) - global switch_to_g2 - if switch_to_g2: - switch_to_g2 = False - g2.switch() - print('\tLEAVE TRACE', *args) - -def g1_run(): - print('In g1_run') - global switch_to_g2 - switch_to_g2 = True - from_parent = greenlet.getcurrent().parent.switch() - print('Return to g1_run') - print('From parent', from_parent) - -def g2_run(): - #g1.switch() - greenlet.getcurrent().parent.switch() - -greenlet.settrace(tracefunc) - -g1 = greenlet.greenlet(g1_run) -g2 = greenlet.greenlet(g2_run) - -# This switch didn't actually finish! -# And if it did, it would raise TypeError -# because g1_run() doesn't take any arguments. -g1.switch(1) -print('Back in main') -g1.switch(2) diff --git a/venv/lib/python3.9/site-packages/greenlet/tests/fail_switch_three_greenlets2.py b/venv/lib/python3.9/site-packages/greenlet/tests/fail_switch_three_greenlets2.py deleted file mode 100644 index 1f6b66b..0000000 --- a/venv/lib/python3.9/site-packages/greenlet/tests/fail_switch_three_greenlets2.py +++ /dev/null @@ -1,55 +0,0 @@ -""" -Like fail_switch_three_greenlets, but the call into g1_run would actually be -valid. -""" -import greenlet - -g1 = None -g2 = None - -switch_to_g2 = True - -results = [] - -def tracefunc(*args): - results.append(('trace', args[0])) - print('TRACE', *args) - global switch_to_g2 - if switch_to_g2: - switch_to_g2 = False - g2.switch('g2 from tracefunc') - print('\tLEAVE TRACE', *args) - -def g1_run(arg): - results.append(('g1 arg', arg)) - print('In g1_run') - from_parent = greenlet.getcurrent().parent.switch('from g1_run') - results.append(('g1 from parent', from_parent)) - return 'g1 done' - -def g2_run(arg): - #g1.switch() - results.append(('g2 arg', arg)) - parent = greenlet.getcurrent().parent.switch('from g2_run') - global switch_to_g2 - switch_to_g2 = False - results.append(('g2 from parent', parent)) - return 'g2 done' - - -greenlet.settrace(tracefunc) - -g1 = greenlet.greenlet(g1_run) -g2 = greenlet.greenlet(g2_run) - -x = g1.switch('g1 from main') -results.append(('main g1', x)) -print('Back in main', x) -x = g1.switch('g2 from main') -results.append(('main g2', x)) -print('back in amain again', x) -x = g1.switch('g1 from main 2') -results.append(('main g1.2', x)) -x = g2.switch() -results.append(('main g2.2', x)) -print("RESULTS:", results) diff --git a/venv/lib/python3.9/site-packages/greenlet/tests/fail_switch_two_greenlets.py b/venv/lib/python3.9/site-packages/greenlet/tests/fail_switch_two_greenlets.py deleted file mode 100644 index 3e52345..0000000 --- a/venv/lib/python3.9/site-packages/greenlet/tests/fail_switch_two_greenlets.py +++ /dev/null @@ -1,41 +0,0 @@ -""" -Uses a trace function to switch greenlets at unexpected times. - -In the trace function, we switch from the current greenlet to another -greenlet, which switches -""" -import greenlet - -g1 = None -g2 = None - -switch_to_g2 = False - -def tracefunc(*args): - print('TRACE', *args) - global switch_to_g2 - if switch_to_g2: - switch_to_g2 = False - g2.switch() - print('\tLEAVE TRACE', *args) - -def g1_run(): - print('In g1_run') - global switch_to_g2 - switch_to_g2 = True - greenlet.getcurrent().parent.switch() - print('Return to g1_run') - print('Falling off end of g1_run') - -def g2_run(): - g1.switch() - print('Falling off end of g2') - -greenlet.settrace(tracefunc) - -g1 = greenlet.greenlet(g1_run) -g2 = greenlet.greenlet(g2_run) - -g1.switch() -print('Falling off end of main') -g2.switch() diff --git a/venv/lib/python3.9/site-packages/greenlet/tests/leakcheck.py b/venv/lib/python3.9/site-packages/greenlet/tests/leakcheck.py deleted file mode 100644 index f45361e..0000000 --- a/venv/lib/python3.9/site-packages/greenlet/tests/leakcheck.py +++ /dev/null @@ -1,336 +0,0 @@ -# Copyright (c) 2018 gevent community -# Copyright (c) 2021 greenlet community -# -# This was originally part of gevent's test suite. The main author -# (Jason Madden) vendored a copy of it into greenlet. -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. -from __future__ import print_function - -import os -import sys -import gc - -from functools import wraps -import unittest - - -import objgraph - -# graphviz 0.18 (Nov 7 2021), available only on Python 3.6 and newer, -# has added type hints (sigh). It wants to use ``typing.Literal`` for -# some stuff, but that's only available on Python 3.9+. If that's not -# found, it creates a ``unittest.mock.MagicMock`` object and annotates -# with that. These are GC'able objects, and doing almost *anything* -# with them results in an explosion of objects. For example, trying to -# compare them for equality creates new objects. This causes our -# leakchecks to fail, with reports like: -# -# greenlet.tests.leakcheck.LeakCheckError: refcount increased by [337, 1333, 343, 430, 530, 643, 769] -# _Call 1820 +546 -# dict 4094 +76 -# MagicProxy 585 +73 -# tuple 2693 +66 -# _CallList 24 +3 -# weakref 1441 +1 -# function 5996 +1 -# type 736 +1 -# cell 592 +1 -# MagicMock 8 +1 -# -# To avoid this, we *could* filter this type of object out early. In -# principle it could leak, but we don't use mocks in greenlet, so it -# doesn't leak from us. However, a further issue is that ``MagicMock`` -# objects have subobjects that are also GC'able, like ``_Call``, and -# those create new mocks of their own too. So we'd have to filter them -# as well, and they're not public. That's OK, we can workaround the -# problem by being very careful to never compare by equality or other -# user-defined operators, only using object identity or other builtin -# functions. - -RUNNING_ON_GITHUB_ACTIONS = os.environ.get('GITHUB_ACTIONS') -RUNNING_ON_TRAVIS = os.environ.get('TRAVIS') or RUNNING_ON_GITHUB_ACTIONS -RUNNING_ON_APPVEYOR = os.environ.get('APPVEYOR') -RUNNING_ON_CI = RUNNING_ON_TRAVIS or RUNNING_ON_APPVEYOR -RUNNING_ON_MANYLINUX = os.environ.get('GREENLET_MANYLINUX') -SKIP_LEAKCHECKS = RUNNING_ON_MANYLINUX or os.environ.get('GREENLET_SKIP_LEAKCHECKS') -SKIP_FAILING_LEAKCHECKS = os.environ.get('GREENLET_SKIP_FAILING_LEAKCHECKS') -ONLY_FAILING_LEAKCHECKS = os.environ.get('GREENLET_ONLY_FAILING_LEAKCHECKS') - -def ignores_leakcheck(func): - """ - Ignore the given object during leakchecks. - - Can be applied to a method, in which case the method will run, but - will not be subject to leak checks. - - If applied to a class, the entire class will be skipped during leakchecks. This - is intended to be used for classes that are very slow and cause problems such as - test timeouts; typically it will be used for classes that are subclasses of a base - class and specify variants of behaviour (such as pool sizes). - """ - func.ignore_leakcheck = True - return func - -def fails_leakcheck(func): - """ - Mark that the function is known to leak. - """ - func.fails_leakcheck = True - if SKIP_FAILING_LEAKCHECKS: - func = unittest.skip("Skipping known failures")(func) - return func - -class LeakCheckError(AssertionError): - pass - -if hasattr(sys, 'getobjects'): - # In a Python build with ``--with-trace-refs``, make objgraph - # trace *all* the objects, not just those that are tracked by the - # GC - class _MockGC(object): - def get_objects(self): - return sys.getobjects(0) # pylint:disable=no-member - def __getattr__(self, name): - return getattr(gc, name) - objgraph.gc = _MockGC() - fails_strict_leakcheck = fails_leakcheck -else: - def fails_strict_leakcheck(func): - """ - Decorator for a function that is known to fail when running - strict (``sys.getobjects()``) leakchecks. - - This type of leakcheck finds all objects, even those, such as - strings, which are not tracked by the garbage collector. - """ - return func - -class ignores_types_in_strict_leakcheck(object): - def __init__(self, types): - self.types = types - def __call__(self, func): - func.leakcheck_ignore_types = self.types - return func - -class _RefCountChecker(object): - - # Some builtin things that we ignore - # XXX: Those things were ignored by gevent, but they're important here, - # presumably. - IGNORED_TYPES = () #(tuple, dict, types.FrameType, types.TracebackType) - - # Names of types that should be ignored. Use this when we cannot - # or don't want to import the class directly. - IGNORED_TYPE_NAMES = ( - # This appears in Python3.14 with the JIT enabled. It - # doesn't seem to be directly exposed to Python; the only way to get - # one is to cause code to get jitted and then look for all objects - # and find one with this name. But they multiply as code - # executes and gets jitted, in ways we don't want to rely on. - # So just ignore it. - 'uop_executor', - ) - - def __init__(self, testcase, function): - self.testcase = testcase - self.function = function - self.deltas = [] - self.peak_stats = {} - self.ignored_types = () - - # The very first time we are called, we have already been - # self.setUp() by the test runner, so we don't need to do it again. - self.needs_setUp = False - - def _include_object_p(self, obj): - # pylint:disable=too-many-return-statements - # - # See the comment block at the top. We must be careful to - # avoid invoking user-defined operations. - if obj is self: - return False - kind = type(obj) - # ``self._include_object_p == obj`` returns NotImplemented - # for non-function objects, which causes the interpreter - # to try to reverse the order of arguments...which leads - # to the explosion of mock objects. We don't want that, so we implement - # the check manually. - if kind == type(self._include_object_p): # pylint: disable=unidiomatic-typecheck - try: - # pylint:disable=not-callable - exact_method_equals = self._include_object_p.__eq__(obj) - except AttributeError: - # Python 2.7 methods may only have __cmp__, and that raises a - # TypeError for non-method arguments - # pylint:disable=no-member - exact_method_equals = self._include_object_p.__cmp__(obj) == 0 - - if exact_method_equals is not NotImplemented and exact_method_equals: - return False - - # Similarly, we need to check identity in our __dict__ to avoid mock explosions. - for x in self.__dict__.values(): - if obj is x: - return False - - - if ( - kind in self.ignored_types - or kind in self.IGNORED_TYPES - or kind.__name__ in self.IGNORED_TYPE_NAMES - ): - return False - - - return True - - def _growth(self): - return objgraph.growth(limit=None, peak_stats=self.peak_stats, - filter=self._include_object_p) - - def _report_diff(self, growth): - if not growth: - return "" - - lines = [] - width = max(len(name) for name, _, _ in growth) - for name, count, delta in growth: - lines.append('%-*s%9d %+9d' % (width, name, count, delta)) - - diff = '\n'.join(lines) - return diff - - - def _run_test(self, args, kwargs): - gc_enabled = gc.isenabled() - gc.disable() - - if self.needs_setUp: - self.testcase.setUp() - self.testcase.skipTearDown = False - try: - self.function(self.testcase, *args, **kwargs) - finally: - self.testcase.tearDown() - self.testcase.doCleanups() - self.testcase.skipTearDown = True - self.needs_setUp = True - if gc_enabled: - gc.enable() - - def _growth_after(self): - # Grab post snapshot - # pylint:disable=no-member - if 'urlparse' in sys.modules: - sys.modules['urlparse'].clear_cache() - if 'urllib.parse' in sys.modules: - sys.modules['urllib.parse'].clear_cache() - - return self._growth() - - def _check_deltas(self, growth): - # Return false when we have decided there is no leak, - # true if we should keep looping, raises an assertion - # if we have decided there is a leak. - - deltas = self.deltas - if not deltas: - # We haven't run yet, no data, keep looping - return True - - if gc.garbage: - raise LeakCheckError("Generated uncollectable garbage %r" % (gc.garbage,)) - - - # the following configurations are classified as "no leak" - # [0, 0] - # [x, 0, 0] - # [... a, b, c, d] where a+b+c+d = 0 - # - # the following configurations are classified as "leak" - # [... z, z, z] where z > 0 - - if deltas[-2:] == [0, 0] and len(deltas) in (2, 3): - return False - - if deltas[-3:] == [0, 0, 0]: - return False - - if len(deltas) >= 4 and sum(deltas[-4:]) == 0: - return False - - if len(deltas) >= 3 and deltas[-1] > 0 and deltas[-1] == deltas[-2] and deltas[-2] == deltas[-3]: - diff = self._report_diff(growth) - raise LeakCheckError('refcount increased by %r\n%s' % (deltas, diff)) - - # OK, we don't know for sure yet. Let's search for more - if sum(deltas[-3:]) <= 0 or sum(deltas[-4:]) <= 0 or deltas[-4:].count(0) >= 2: - # this is suspicious, so give a few more runs - limit = 11 - else: - limit = 7 - if len(deltas) >= limit: - raise LeakCheckError('refcount increased by %r\n%s' - % (deltas, - self._report_diff(growth))) - - # We couldn't decide yet, keep going - return True - - def __call__(self, args, kwargs): - for _ in range(3): - gc.collect() - - expect_failure = getattr(self.function, 'fails_leakcheck', False) - if expect_failure: - self.testcase.expect_greenlet_leak = True - self.ignored_types = getattr(self.function, "leakcheck_ignore_types", ()) - - # Capture state before; the incremental will be - # updated by each call to _growth_after - growth = self._growth() - - try: - while self._check_deltas(growth): - self._run_test(args, kwargs) - - growth = self._growth_after() - - self.deltas.append(sum((stat[2] for stat in growth))) - except LeakCheckError: - if not expect_failure: - raise - else: - if expect_failure: - raise LeakCheckError("Expected %s to leak but it did not." % (self.function,)) - -def wrap_refcount(method): - if getattr(method, 'ignore_leakcheck', False) or SKIP_LEAKCHECKS: - return method - - @wraps(method) - def wrapper(self, *args, **kwargs): # pylint:disable=too-many-branches - if getattr(self, 'ignore_leakcheck', False): - raise unittest.SkipTest("This class ignored during leakchecks") - if ONLY_FAILING_LEAKCHECKS and not getattr(method, 'fails_leakcheck', False): - raise unittest.SkipTest("Only running tests that fail leakchecks.") - return _RefCountChecker(self, method)(args, kwargs) - - return wrapper diff --git a/venv/lib/python3.9/site-packages/greenlet/tests/test_contextvars.py b/venv/lib/python3.9/site-packages/greenlet/tests/test_contextvars.py deleted file mode 100644 index b0d1ccf..0000000 --- a/venv/lib/python3.9/site-packages/greenlet/tests/test_contextvars.py +++ /dev/null @@ -1,312 +0,0 @@ -from __future__ import print_function - -import gc -import sys -import unittest - -from functools import partial -from unittest import skipUnless -from unittest import skipIf - -from greenlet import greenlet -from greenlet import getcurrent -from . import TestCase -from . import PY314 - -try: - from contextvars import Context - from contextvars import ContextVar - from contextvars import copy_context - # From the documentation: - # - # Important: Context Variables should be created at the top module - # level and never in closures. Context objects hold strong - # references to context variables which prevents context variables - # from being properly garbage collected. - ID_VAR = ContextVar("id", default=None) - VAR_VAR = ContextVar("var", default=None) - ContextVar = None -except ImportError: - Context = ContextVar = copy_context = None - -# We don't support testing if greenlet's built-in context var support is disabled. -@skipUnless(Context is not None, "ContextVar not supported") -class ContextVarsTests(TestCase): - def _new_ctx_run(self, *args, **kwargs): - return copy_context().run(*args, **kwargs) - - def _increment(self, greenlet_id, callback, counts, expect): - ctx_var = ID_VAR - if expect is None: - self.assertIsNone(ctx_var.get()) - else: - self.assertEqual(ctx_var.get(), expect) - ctx_var.set(greenlet_id) - for _ in range(2): - counts[ctx_var.get()] += 1 - callback() - - def _test_context(self, propagate_by): - # pylint:disable=too-many-branches - ID_VAR.set(0) - - callback = getcurrent().switch - counts = dict((i, 0) for i in range(5)) - - lets = [ - greenlet(partial( - partial( - copy_context().run, - self._increment - ) if propagate_by == "run" else self._increment, - greenlet_id=i, - callback=callback, - counts=counts, - expect=( - i - 1 if propagate_by == "share" else - 0 if propagate_by in ("set", "run") else None - ) - )) - for i in range(1, 5) - ] - - for let in lets: - if propagate_by == "set": - let.gr_context = copy_context() - elif propagate_by == "share": - let.gr_context = getcurrent().gr_context - - for i in range(2): - counts[ID_VAR.get()] += 1 - for let in lets: - let.switch() - - if propagate_by == "run": - # Must leave each context.run() in reverse order of entry - for let in reversed(lets): - let.switch() - else: - # No context.run(), so fine to exit in any order. - for let in lets: - let.switch() - - for let in lets: - self.assertTrue(let.dead) - # When using run(), we leave the run() as the greenlet dies, - # and there's no context "underneath". When not using run(), - # gr_context still reflects the context the greenlet was - # running in. - if propagate_by == 'run': - self.assertIsNone(let.gr_context) - else: - self.assertIsNotNone(let.gr_context) - - - if propagate_by == "share": - self.assertEqual(counts, {0: 1, 1: 1, 2: 1, 3: 1, 4: 6}) - else: - self.assertEqual(set(counts.values()), set([2])) - - def test_context_propagated_by_context_run(self): - self._new_ctx_run(self._test_context, "run") - - def test_context_propagated_by_setting_attribute(self): - self._new_ctx_run(self._test_context, "set") - - def test_context_not_propagated(self): - self._new_ctx_run(self._test_context, None) - - def test_context_shared(self): - self._new_ctx_run(self._test_context, "share") - - def test_break_ctxvars(self): - let1 = greenlet(copy_context().run) - let2 = greenlet(copy_context().run) - let1.switch(getcurrent().switch) - let2.switch(getcurrent().switch) - # Since let2 entered the current context and let1 exits its own, the - # interpreter emits: - # RuntimeError: cannot exit context: thread state references a different context object - let1.switch() - - def test_not_broken_if_using_attribute_instead_of_context_run(self): - let1 = greenlet(getcurrent().switch) - let2 = greenlet(getcurrent().switch) - let1.gr_context = copy_context() - let2.gr_context = copy_context() - let1.switch() - let2.switch() - let1.switch() - let2.switch() - - def test_context_assignment_while_running(self): - # pylint:disable=too-many-statements - ID_VAR.set(None) - - def target(): - self.assertIsNone(ID_VAR.get()) - self.assertIsNone(gr.gr_context) - - # Context is created on first use - ID_VAR.set(1) - self.assertIsInstance(gr.gr_context, Context) - self.assertEqual(ID_VAR.get(), 1) - self.assertEqual(gr.gr_context[ID_VAR], 1) - - # Clearing the context makes it get re-created as another - # empty context when next used - old_context = gr.gr_context - gr.gr_context = None # assign None while running - self.assertIsNone(ID_VAR.get()) - self.assertIsNone(gr.gr_context) - ID_VAR.set(2) - self.assertIsInstance(gr.gr_context, Context) - self.assertEqual(ID_VAR.get(), 2) - self.assertEqual(gr.gr_context[ID_VAR], 2) - - new_context = gr.gr_context - getcurrent().parent.switch((old_context, new_context)) - # parent switches us back to old_context - - self.assertEqual(ID_VAR.get(), 1) - gr.gr_context = new_context # assign non-None while running - self.assertEqual(ID_VAR.get(), 2) - - getcurrent().parent.switch() - # parent switches us back to no context - self.assertIsNone(ID_VAR.get()) - self.assertIsNone(gr.gr_context) - gr.gr_context = old_context - self.assertEqual(ID_VAR.get(), 1) - - getcurrent().parent.switch() - # parent switches us back to no context - self.assertIsNone(ID_VAR.get()) - self.assertIsNone(gr.gr_context) - - gr = greenlet(target) - - with self.assertRaisesRegex(AttributeError, "can't delete context attribute"): - del gr.gr_context - - self.assertIsNone(gr.gr_context) - old_context, new_context = gr.switch() - self.assertIs(new_context, gr.gr_context) - self.assertEqual(old_context[ID_VAR], 1) - self.assertEqual(new_context[ID_VAR], 2) - self.assertEqual(new_context.run(ID_VAR.get), 2) - gr.gr_context = old_context # assign non-None while suspended - gr.switch() - self.assertIs(gr.gr_context, new_context) - gr.gr_context = None # assign None while suspended - gr.switch() - self.assertIs(gr.gr_context, old_context) - gr.gr_context = None - gr.switch() - self.assertIsNone(gr.gr_context) - - # Make sure there are no reference leaks - gr = None - gc.collect() - # Python 3.14 elides reference counting operations - # in some cases. See https://github.com/python/cpython/pull/130708 - self.assertEqual(sys.getrefcount(old_context), 2 if not PY314 else 1) - self.assertEqual(sys.getrefcount(new_context), 2 if not PY314 else 1) - - def test_context_assignment_different_thread(self): - import threading - VAR_VAR.set(None) - ctx = Context() - - is_running = threading.Event() - should_suspend = threading.Event() - did_suspend = threading.Event() - should_exit = threading.Event() - holder = [] - - def greenlet_in_thread_fn(): - VAR_VAR.set(1) - is_running.set() - should_suspend.wait(10) - VAR_VAR.set(2) - getcurrent().parent.switch() - holder.append(VAR_VAR.get()) - - def thread_fn(): - gr = greenlet(greenlet_in_thread_fn) - gr.gr_context = ctx - holder.append(gr) - gr.switch() - did_suspend.set() - should_exit.wait(10) - gr.switch() - del gr - greenlet() # trigger cleanup - - thread = threading.Thread(target=thread_fn, daemon=True) - thread.start() - is_running.wait(10) - gr = holder[0] - - # Can't access or modify context if the greenlet is running - # in a different thread - with self.assertRaisesRegex(ValueError, "running in a different"): - getattr(gr, 'gr_context') - with self.assertRaisesRegex(ValueError, "running in a different"): - gr.gr_context = None - - should_suspend.set() - did_suspend.wait(10) - - # OK to access and modify context if greenlet is suspended - self.assertIs(gr.gr_context, ctx) - self.assertEqual(gr.gr_context[VAR_VAR], 2) - gr.gr_context = None - - should_exit.set() - thread.join(10) - - self.assertEqual(holder, [gr, None]) - - # Context can still be accessed/modified when greenlet is dead: - self.assertIsNone(gr.gr_context) - gr.gr_context = ctx - self.assertIs(gr.gr_context, ctx) - - # Otherwise we leak greenlets on some platforms. - # XXX: Should be able to do this automatically - del holder[:] - gr = None - thread = None - - def test_context_assignment_wrong_type(self): - g = greenlet() - with self.assertRaisesRegex(TypeError, - "greenlet context must be a contextvars.Context or None"): - g.gr_context = self - - -@skipIf(Context is not None, "ContextVar supported") -class NoContextVarsTests(TestCase): - def test_contextvars_errors(self): - let1 = greenlet(getcurrent().switch) - self.assertFalse(hasattr(let1, 'gr_context')) - with self.assertRaises(AttributeError): - getattr(let1, 'gr_context') - - with self.assertRaises(AttributeError): - let1.gr_context = None - - let1.switch() - - with self.assertRaises(AttributeError): - getattr(let1, 'gr_context') - - with self.assertRaises(AttributeError): - let1.gr_context = None - - del let1 - - -if __name__ == '__main__': - unittest.main() diff --git a/venv/lib/python3.9/site-packages/greenlet/tests/test_cpp.py b/venv/lib/python3.9/site-packages/greenlet/tests/test_cpp.py deleted file mode 100644 index 2d0cc9c..0000000 --- a/venv/lib/python3.9/site-packages/greenlet/tests/test_cpp.py +++ /dev/null @@ -1,73 +0,0 @@ -from __future__ import print_function -from __future__ import absolute_import - -import subprocess -import unittest - -import greenlet -from . import _test_extension_cpp -from . import TestCase -from . import WIN - -class CPPTests(TestCase): - def test_exception_switch(self): - greenlets = [] - for i in range(4): - g = greenlet.greenlet(_test_extension_cpp.test_exception_switch) - g.switch(i) - greenlets.append(g) - for i, g in enumerate(greenlets): - self.assertEqual(g.switch(), i) - - def _do_test_unhandled_exception(self, target): - import os - import sys - script = os.path.join( - os.path.dirname(__file__), - 'fail_cpp_exception.py', - ) - args = [sys.executable, script, target.__name__ if not isinstance(target, str) else target] - __traceback_info__ = args - with self.assertRaises(subprocess.CalledProcessError) as exc: - subprocess.check_output( - args, - encoding='utf-8', - stderr=subprocess.STDOUT - ) - - ex = exc.exception - expected_exit = self.get_expected_returncodes_for_aborted_process() - self.assertIn(ex.returncode, expected_exit) - self.assertIn('fail_cpp_exception is running', ex.output) - return ex.output - - - def test_unhandled_nonstd_exception_aborts(self): - # verify that plain unhandled throw aborts - self._do_test_unhandled_exception(_test_extension_cpp.test_exception_throw_nonstd) - - def test_unhandled_std_exception_aborts(self): - # verify that plain unhandled throw aborts - self._do_test_unhandled_exception(_test_extension_cpp.test_exception_throw_std) - - @unittest.skipIf(WIN, "XXX: This does not crash on Windows") - # Meaning the exception is getting lost somewhere... - def test_unhandled_std_exception_as_greenlet_function_aborts(self): - # verify that plain unhandled throw aborts - output = self._do_test_unhandled_exception('run_as_greenlet_target') - self.assertIn( - # We really expect this to be prefixed with "greenlet: Unhandled C++ exception:" - # as added by our handler for std::exception (see TUserGreenlet.cpp), but - # that's not correct everywhere --- our handler never runs before std::terminate - # gets called (for example, on arm32). - 'Thrown from an extension.', - output - ) - - def test_unhandled_exception_in_greenlet_aborts(self): - # verify that unhandled throw called in greenlet aborts too - self._do_test_unhandled_exception('run_unhandled_exception_in_greenlet_aborts') - - -if __name__ == '__main__': - unittest.main() diff --git a/venv/lib/python3.9/site-packages/greenlet/tests/test_extension_interface.py b/venv/lib/python3.9/site-packages/greenlet/tests/test_extension_interface.py deleted file mode 100644 index 34b6656..0000000 --- a/venv/lib/python3.9/site-packages/greenlet/tests/test_extension_interface.py +++ /dev/null @@ -1,115 +0,0 @@ -from __future__ import print_function -from __future__ import absolute_import - -import sys - -import greenlet -from . import _test_extension -from . import TestCase - -# pylint:disable=c-extension-no-member - -class CAPITests(TestCase): - def test_switch(self): - self.assertEqual( - 50, _test_extension.test_switch(greenlet.greenlet(lambda: 50))) - - def test_switch_kwargs(self): - def adder(x, y): - return x * y - g = greenlet.greenlet(adder) - self.assertEqual(6, _test_extension.test_switch_kwargs(g, x=3, y=2)) - - def test_setparent(self): - # pylint:disable=disallowed-name - def foo(): - def bar(): - greenlet.getcurrent().parent.switch() - - # This final switch should go back to the main greenlet, since - # the test_setparent() function in the C extension should have - # reparented this greenlet. - greenlet.getcurrent().parent.switch() - raise AssertionError("Should never have reached this code") - child = greenlet.greenlet(bar) - child.switch() - greenlet.getcurrent().parent.switch(child) - greenlet.getcurrent().parent.throw( - AssertionError("Should never reach this code")) - foo_child = greenlet.greenlet(foo).switch() - self.assertEqual(None, _test_extension.test_setparent(foo_child)) - - def test_getcurrent(self): - _test_extension.test_getcurrent() - - def test_new_greenlet(self): - self.assertEqual(-15, _test_extension.test_new_greenlet(lambda: -15)) - - def test_raise_greenlet_dead(self): - self.assertRaises( - greenlet.GreenletExit, _test_extension.test_raise_dead_greenlet) - - def test_raise_greenlet_error(self): - self.assertRaises( - greenlet.error, _test_extension.test_raise_greenlet_error) - - def test_throw(self): - seen = [] - - def foo(): # pylint:disable=disallowed-name - try: - greenlet.getcurrent().parent.switch() - except ValueError: - seen.append(sys.exc_info()[1]) - except greenlet.GreenletExit: - raise AssertionError - g = greenlet.greenlet(foo) - g.switch() - _test_extension.test_throw(g) - self.assertEqual(len(seen), 1) - self.assertTrue( - isinstance(seen[0], ValueError), - "ValueError was not raised in foo()") - self.assertEqual( - str(seen[0]), - 'take that sucka!', - "message doesn't match") - - def test_non_traceback_param(self): - with self.assertRaises(TypeError) as exc: - _test_extension.test_throw_exact( - greenlet.getcurrent(), - Exception, - Exception(), - self - ) - self.assertEqual(str(exc.exception), - "throw() third argument must be a traceback object") - - def test_instance_of_wrong_type(self): - with self.assertRaises(TypeError) as exc: - _test_extension.test_throw_exact( - greenlet.getcurrent(), - Exception(), - BaseException(), - None, - ) - - self.assertEqual(str(exc.exception), - "instance exception may not have a separate value") - - def test_not_throwable(self): - with self.assertRaises(TypeError) as exc: - _test_extension.test_throw_exact( - greenlet.getcurrent(), - "abc", - None, - None, - ) - self.assertEqual(str(exc.exception), - "exceptions must be classes, or instances, not str") - - -if __name__ == '__main__': - import unittest - unittest.main() diff --git a/venv/lib/python3.9/site-packages/greenlet/tests/test_gc.py b/venv/lib/python3.9/site-packages/greenlet/tests/test_gc.py deleted file mode 100644 index 994addb..0000000 --- a/venv/lib/python3.9/site-packages/greenlet/tests/test_gc.py +++ /dev/null @@ -1,86 +0,0 @@ -import gc - -import weakref - -import greenlet - - -from . import TestCase -from .leakcheck import fails_leakcheck -# These only work with greenlet gc support -# which is no longer optional. -assert greenlet.GREENLET_USE_GC - -class GCTests(TestCase): - def test_dead_circular_ref(self): - o = weakref.ref(greenlet.greenlet(greenlet.getcurrent).switch()) - gc.collect() - if o() is not None: - import sys - print("O IS NOT NONE.", sys.getrefcount(o())) - self.assertIsNone(o()) - self.assertFalse(gc.garbage, gc.garbage) - - def test_circular_greenlet(self): - class circular_greenlet(greenlet.greenlet): - self = None - o = circular_greenlet() - o.self = o - o = weakref.ref(o) - gc.collect() - self.assertIsNone(o()) - self.assertFalse(gc.garbage, gc.garbage) - - def test_inactive_ref(self): - class inactive_greenlet(greenlet.greenlet): - def __init__(self): - greenlet.greenlet.__init__(self, run=self.run) - - def run(self): - pass - o = inactive_greenlet() - o = weakref.ref(o) - gc.collect() - self.assertIsNone(o()) - self.assertFalse(gc.garbage, gc.garbage) - - @fails_leakcheck - def test_finalizer_crash(self): - # This test is designed to crash when active greenlets - # are made garbage collectable, until the underlying - # problem is resolved. How does it work: - # - order of object creation is important - # - array is created first, so it is moved to unreachable first - # - we create a cycle between a greenlet and this array - # - we create an object that participates in gc, is only - # referenced by a greenlet, and would corrupt gc lists - # on destruction, the easiest is to use an object with - # a finalizer - # - because array is the first object in unreachable it is - # cleared first, which causes all references to greenlet - # to disappear and causes greenlet to be destroyed, but since - # it is still live it causes a switch during gc, which causes - # an object with finalizer to be destroyed, which causes stack - # corruption and then a crash - - class object_with_finalizer(object): - def __del__(self): - pass - array = [] - parent = greenlet.getcurrent() - def greenlet_body(): - greenlet.getcurrent().object = object_with_finalizer() - try: - parent.switch() - except greenlet.GreenletExit: - print("Got greenlet exit!") - finally: - del greenlet.getcurrent().object - g = greenlet.greenlet(greenlet_body) - g.array = array - array.append(g) - g.switch() - del array - del g - greenlet.getcurrent() - gc.collect() diff --git a/venv/lib/python3.9/site-packages/greenlet/tests/test_generator.py b/venv/lib/python3.9/site-packages/greenlet/tests/test_generator.py deleted file mode 100644 index ca4a644..0000000 --- a/venv/lib/python3.9/site-packages/greenlet/tests/test_generator.py +++ /dev/null @@ -1,59 +0,0 @@ - -from greenlet import greenlet - -from . import TestCase - -class genlet(greenlet): - parent = None - def __init__(self, *args, **kwds): - self.args = args - self.kwds = kwds - - def run(self): - fn, = self.fn - fn(*self.args, **self.kwds) - - def __iter__(self): - return self - - def __next__(self): - self.parent = greenlet.getcurrent() - result = self.switch() - if self: - return result - - raise StopIteration - - next = __next__ - - -def Yield(value): - g = greenlet.getcurrent() - while not isinstance(g, genlet): - if g is None: - raise RuntimeError('yield outside a genlet') - g = g.parent - g.parent.switch(value) - - -def generator(func): - class Generator(genlet): - fn = (func,) - return Generator - -# ____________________________________________________________ - - -class GeneratorTests(TestCase): - def test_generator(self): - seen = [] - - def g(n): - for i in range(n): - seen.append(i) - Yield(i) - g = generator(g) - for _ in range(3): - for j in g(5): - seen.append(j) - self.assertEqual(seen, 3 * [0, 0, 1, 1, 2, 2, 3, 3, 4, 4]) diff --git a/venv/lib/python3.9/site-packages/greenlet/tests/test_generator_nested.py b/venv/lib/python3.9/site-packages/greenlet/tests/test_generator_nested.py deleted file mode 100644 index 8d752a6..0000000 --- a/venv/lib/python3.9/site-packages/greenlet/tests/test_generator_nested.py +++ /dev/null @@ -1,168 +0,0 @@ - -from greenlet import greenlet -from . import TestCase -from .leakcheck import fails_leakcheck - -class genlet(greenlet): - parent = None - def __init__(self, *args, **kwds): - self.args = args - self.kwds = kwds - self.child = None - - def run(self): - # Note the function is packed in a tuple - # to avoid creating a bound method for it. - fn, = self.fn - fn(*self.args, **self.kwds) - - def __iter__(self): - return self - - def set_child(self, child): - self.child = child - - def __next__(self): - if self.child: - child = self.child - while child.child: - tmp = child - child = child.child - tmp.child = None - - result = child.switch() - else: - self.parent = greenlet.getcurrent() - result = self.switch() - - if self: - return result - - raise StopIteration - - next = __next__ - -def Yield(value, level=1): - g = greenlet.getcurrent() - - while level != 0: - if not isinstance(g, genlet): - raise RuntimeError('yield outside a genlet') - if level > 1: - g.parent.set_child(g) - g = g.parent - level -= 1 - - g.switch(value) - - -def Genlet(func): - class TheGenlet(genlet): - fn = (func,) - return TheGenlet - -# ____________________________________________________________ - - -def g1(n, seen): - for i in range(n): - seen.append(i + 1) - yield i - - -def g2(n, seen): - for i in range(n): - seen.append(i + 1) - Yield(i) - -g2 = Genlet(g2) - - -def nested(i): - Yield(i) - - -def g3(n, seen): - for i in range(n): - seen.append(i + 1) - nested(i) -g3 = Genlet(g3) - - -def a(n): - if n == 0: - return - for ii in ax(n - 1): - Yield(ii) - Yield(n) -ax = Genlet(a) - - -def perms(l): - if len(l) > 1: - for e in l: - # No syntactical sugar for generator expressions - x = [Yield([e] + p) for p in perms([x for x in l if x != e])] - assert x - else: - Yield(l) -perms = Genlet(perms) - - -def gr1(n): - for ii in range(1, n): - Yield(ii) - Yield(ii * ii, 2) - -gr1 = Genlet(gr1) - - -def gr2(n, seen): - for ii in gr1(n): - seen.append(ii) - -gr2 = Genlet(gr2) - - -class NestedGeneratorTests(TestCase): - def test_layered_genlets(self): - seen = [] - for ii in gr2(5, seen): - seen.append(ii) - self.assertEqual(seen, [1, 1, 2, 4, 3, 9, 4, 16]) - - @fails_leakcheck - def test_permutations(self): - gen_perms = perms(list(range(4))) - permutations = list(gen_perms) - self.assertEqual(len(permutations), 4 * 3 * 2 * 1) - self.assertIn([0, 1, 2, 3], permutations) - self.assertIn([3, 2, 1, 0], permutations) - res = [] - for ii in zip(perms(list(range(4))), perms(list(range(3)))): - res.append(ii) - self.assertEqual( - res, - [([0, 1, 2, 3], [0, 1, 2]), ([0, 1, 3, 2], [0, 2, 1]), - ([0, 2, 1, 3], [1, 0, 2]), ([0, 2, 3, 1], [1, 2, 0]), - ([0, 3, 1, 2], [2, 0, 1]), ([0, 3, 2, 1], [2, 1, 0])]) - # XXX Test to make sure we are working as a generator expression - - def test_genlet_simple(self): - for g in g1, g2, g3: - seen = [] - for _ in range(3): - for j in g(5, seen): - seen.append(j) - self.assertEqual(seen, 3 * [1, 0, 2, 1, 3, 2, 4, 3, 5, 4]) - - def test_genlet_bad(self): - try: - Yield(10) - except RuntimeError: - pass - - def test_nested_genlets(self): - seen = [] - for ii in ax(5): - seen.append(ii) diff --git a/venv/lib/python3.9/site-packages/greenlet/tests/test_greenlet.py b/venv/lib/python3.9/site-packages/greenlet/tests/test_greenlet.py deleted file mode 100644 index 1fa4bd1..0000000 --- a/venv/lib/python3.9/site-packages/greenlet/tests/test_greenlet.py +++ /dev/null @@ -1,1353 +0,0 @@ -import gc -import sys -import time -import threading -import unittest - -from abc import ABCMeta -from abc import abstractmethod - -import greenlet -from greenlet import greenlet as RawGreenlet -from . import TestCase -from . import RUNNING_ON_MANYLINUX -from . import PY313 -from . import PY314 -from . import RUNNING_ON_FREETHREAD_BUILD -from .leakcheck import fails_leakcheck - - -# We manually manage locks in many tests -# pylint:disable=consider-using-with -# pylint:disable=too-many-public-methods -# This module is quite large. -# TODO: Refactor into separate test files. For example, -# put all the regression tests that used to produce -# crashes in test_greenlet_no_crash; put tests that DO deliberately crash -# the interpreter into test_greenlet_crash. -# pylint:disable=too-many-lines - -class SomeError(Exception): - pass - - -def fmain(seen): - try: - greenlet.getcurrent().parent.switch() - except: - seen.append(sys.exc_info()[0]) - raise - raise SomeError - - -def send_exception(g, exc): - # note: send_exception(g, exc) can be now done with g.throw(exc). - # the purpose of this test is to explicitly check the propagation rules. - def crasher(exc): - raise exc - g1 = RawGreenlet(crasher, parent=g) - g1.switch(exc) - - -class TestGreenlet(TestCase): - - def _do_simple_test(self): - lst = [] - - def f(): - lst.append(1) - greenlet.getcurrent().parent.switch() - lst.append(3) - g = RawGreenlet(f) - lst.append(0) - g.switch() - lst.append(2) - g.switch() - lst.append(4) - self.assertEqual(lst, list(range(5))) - - def test_simple(self): - self._do_simple_test() - - def test_switch_no_run_raises_AttributeError(self): - g = RawGreenlet() - with self.assertRaises(AttributeError) as exc: - g.switch() - - self.assertIn("run", str(exc.exception)) - - def test_throw_no_run_raises_AttributeError(self): - g = RawGreenlet() - with self.assertRaises(AttributeError) as exc: - g.throw(SomeError) - - self.assertIn("run", str(exc.exception)) - - def test_parent_equals_None(self): - g = RawGreenlet(parent=None) - self.assertIsNotNone(g) - self.assertIs(g.parent, greenlet.getcurrent()) - - def test_run_equals_None(self): - g = RawGreenlet(run=None) - self.assertIsNotNone(g) - self.assertIsNone(g.run) - - def test_two_children(self): - lst = [] - - def f(): - lst.append(1) - greenlet.getcurrent().parent.switch() - lst.extend([1, 1]) - g = RawGreenlet(f) - h = RawGreenlet(f) - g.switch() - self.assertEqual(len(lst), 1) - h.switch() - self.assertEqual(len(lst), 2) - h.switch() - self.assertEqual(len(lst), 4) - self.assertEqual(h.dead, True) - g.switch() - self.assertEqual(len(lst), 6) - self.assertEqual(g.dead, True) - - def test_two_recursive_children(self): - lst = [] - - def f(): - lst.append('b') - greenlet.getcurrent().parent.switch() - - def g(): - lst.append('a') - g = RawGreenlet(f) - g.switch() - lst.append('c') - self.assertEqual(sys.getrefcount(g), 2 if not PY314 else 1) - g = RawGreenlet(g) - # Python 3.14 elides reference counting operations - # in some cases. See https://github.com/python/cpython/pull/130708 - self.assertEqual(sys.getrefcount(g), 2 if not PY314 else 1) - g.switch() - self.assertEqual(lst, ['a', 'b', 'c']) - # Just the one in this frame, plus the one on the stack we pass to the function - self.assertEqual(sys.getrefcount(g), 2 if not PY314 else 1) - - def test_threads(self): - success = [] - - def f(): - self._do_simple_test() - success.append(True) - ths = [threading.Thread(target=f) for i in range(10)] - for th in ths: - th.start() - for th in ths: - th.join(10) - self.assertEqual(len(success), len(ths)) - - def test_exception(self): - seen = [] - g1 = RawGreenlet(fmain) - g2 = RawGreenlet(fmain) - g1.switch(seen) - g2.switch(seen) - g2.parent = g1 - - self.assertEqual(seen, []) - #with self.assertRaises(SomeError): - # p("***Switching back") - # g2.switch() - # Creating this as a bound method can reveal bugs that - # are hidden on newer versions of Python that avoid creating - # bound methods for direct expressions; IOW, don't use the `with` - # form! - self.assertRaises(SomeError, g2.switch) - self.assertEqual(seen, [SomeError]) - - value = g2.switch() - self.assertEqual(value, ()) - self.assertEqual(seen, [SomeError]) - - value = g2.switch(25) - self.assertEqual(value, 25) - self.assertEqual(seen, [SomeError]) - - - def test_send_exception(self): - seen = [] - g1 = RawGreenlet(fmain) - g1.switch(seen) - self.assertRaises(KeyError, send_exception, g1, KeyError) - self.assertEqual(seen, [KeyError]) - - def test_dealloc(self): - seen = [] - g1 = RawGreenlet(fmain) - g2 = RawGreenlet(fmain) - g1.switch(seen) - g2.switch(seen) - self.assertEqual(seen, []) - del g1 - gc.collect() - self.assertEqual(seen, [greenlet.GreenletExit]) - del g2 - gc.collect() - self.assertEqual(seen, [greenlet.GreenletExit, greenlet.GreenletExit]) - - def test_dealloc_catches_GreenletExit_throws_other(self): - def run(): - try: - greenlet.getcurrent().parent.switch() - except greenlet.GreenletExit: - raise SomeError from None - - g = RawGreenlet(run) - g.switch() - # Destroying the only reference to the greenlet causes it - # to get GreenletExit; when it in turn raises, even though we're the parent - # we don't get the exception, it just gets printed. - # When we run on 3.8 only, we can use sys.unraisablehook - oldstderr = sys.stderr - from io import StringIO - stderr = sys.stderr = StringIO() - try: - del g - finally: - sys.stderr = oldstderr - - v = stderr.getvalue() - self.assertIn("Exception", v) - self.assertIn('ignored', v) - self.assertIn("SomeError", v) - - - @unittest.skipIf( - PY313 and RUNNING_ON_MANYLINUX, - "Sometimes flaky (getting one GreenletExit in the second list)" - # Probably due to funky timing interactions? - # TODO: FIXME Make that work. - ) - - def test_dealloc_other_thread(self): - seen = [] - someref = [] - - bg_glet_created_running_and_no_longer_ref_in_bg = threading.Event() - fg_ref_released = threading.Event() - bg_should_be_clear = threading.Event() - ok_to_exit_bg_thread = threading.Event() - - def f(): - g1 = RawGreenlet(fmain) - g1.switch(seen) - someref.append(g1) - del g1 - gc.collect() - bg_glet_created_running_and_no_longer_ref_in_bg.set() - fg_ref_released.wait(3) - - RawGreenlet() # trigger release - bg_should_be_clear.set() - ok_to_exit_bg_thread.wait(3) - RawGreenlet() # One more time - - t = threading.Thread(target=f) - t.start() - bg_glet_created_running_and_no_longer_ref_in_bg.wait(10) - - self.assertEqual(seen, []) - self.assertEqual(len(someref), 1) - del someref[:] - if not RUNNING_ON_FREETHREAD_BUILD: - # The free-threaded GC is very different. In 3.14rc1, - # the free-threaded GC traverses ``g1``, realizes it is - # not referenced from anywhere else IT cares about, - # calls ``tp_clear`` and then ``green_dealloc``. This causes - # the greenlet to lose its reference to the main greenlet and thread - # in which it was running, which means we can no longer throw an - # exception into it, preventing the rest of this test from working. - # Standard 3.14 traverses the object but doesn't ``tp_clear`` or - # ``green_dealloc`` it. - gc.collect() - # g1 is not released immediately because it's from another thread; - # switching back to that thread will allocate a greenlet and thus - # trigger deletion actions. - self.assertEqual(seen, []) - fg_ref_released.set() - bg_should_be_clear.wait(3) - try: - self.assertEqual(seen, [greenlet.GreenletExit]) - finally: - ok_to_exit_bg_thread.set() - t.join(10) - del seen[:] - del someref[:] - - def test_frame(self): - def f1(): - f = sys._getframe(0) # pylint:disable=protected-access - self.assertEqual(f.f_back, None) - greenlet.getcurrent().parent.switch(f) - return "meaning of life" - g = RawGreenlet(f1) - frame = g.switch() - self.assertTrue(frame is g.gr_frame) - self.assertTrue(g) - - from_g = g.switch() - self.assertFalse(g) - self.assertEqual(from_g, 'meaning of life') - self.assertEqual(g.gr_frame, None) - - def test_thread_bug(self): - def runner(x): - g = RawGreenlet(lambda: time.sleep(x)) - g.switch() - t1 = threading.Thread(target=runner, args=(0.2,)) - t2 = threading.Thread(target=runner, args=(0.3,)) - t1.start() - t2.start() - t1.join(10) - t2.join(10) - - def test_switch_kwargs(self): - def run(a, b): - self.assertEqual(a, 4) - self.assertEqual(b, 2) - return 42 - x = RawGreenlet(run).switch(a=4, b=2) - self.assertEqual(x, 42) - - def test_switch_kwargs_to_parent(self): - def run(x): - greenlet.getcurrent().parent.switch(x=x) - greenlet.getcurrent().parent.switch(2, x=3) - return x, x ** 2 - g = RawGreenlet(run) - self.assertEqual({'x': 3}, g.switch(3)) - self.assertEqual(((2,), {'x': 3}), g.switch()) - self.assertEqual((3, 9), g.switch()) - - def test_switch_to_another_thread(self): - data = {} - created_event = threading.Event() - done_event = threading.Event() - - def run(): - data['g'] = RawGreenlet(lambda: None) - created_event.set() - done_event.wait(10) - thread = threading.Thread(target=run) - thread.start() - created_event.wait(10) - with self.assertRaises(greenlet.error): - data['g'].switch() - done_event.set() - thread.join(10) - # XXX: Should handle this automatically - data.clear() - - def test_exc_state(self): - def f(): - try: - raise ValueError('fun') - except: # pylint:disable=bare-except - exc_info = sys.exc_info() - RawGreenlet(h).switch() - self.assertEqual(exc_info, sys.exc_info()) - - def h(): - self.assertEqual(sys.exc_info(), (None, None, None)) - - RawGreenlet(f).switch() - - def test_instance_dict(self): - def f(): - greenlet.getcurrent().test = 42 - def deldict(g): - del g.__dict__ - def setdict(g, value): - g.__dict__ = value - g = RawGreenlet(f) - self.assertEqual(g.__dict__, {}) - g.switch() - self.assertEqual(g.test, 42) - self.assertEqual(g.__dict__, {'test': 42}) - g.__dict__ = g.__dict__ - self.assertEqual(g.__dict__, {'test': 42}) - self.assertRaises(TypeError, deldict, g) - self.assertRaises(TypeError, setdict, g, 42) - - def test_running_greenlet_has_no_run(self): - has_run = [] - def func(): - has_run.append( - hasattr(greenlet.getcurrent(), 'run') - ) - - g = RawGreenlet(func) - g.switch() - self.assertEqual(has_run, [False]) - - def test_deepcopy(self): - import copy - self.assertRaises(TypeError, copy.copy, RawGreenlet()) - self.assertRaises(TypeError, copy.deepcopy, RawGreenlet()) - - def test_parent_restored_on_kill(self): - hub = RawGreenlet(lambda: None) - main = greenlet.getcurrent() - result = [] - def worker(): - try: - # Wait to be killed by going back to the test. - main.switch() - except greenlet.GreenletExit: - # Resurrect and switch to parent - result.append(greenlet.getcurrent().parent) - result.append(greenlet.getcurrent()) - hub.switch() - g = RawGreenlet(worker, parent=hub) - g.switch() - # delete the only reference, thereby raising GreenletExit - del g - self.assertTrue(result) - self.assertIs(result[0], main) - self.assertIs(result[1].parent, hub) - # Delete them, thereby breaking the cycle between the greenlet - # and the frame, which otherwise would never be collectable - # XXX: We should be able to automatically fix this. - del result[:] - hub = None - main = None - - def test_parent_return_failure(self): - # No run causes AttributeError on switch - g1 = RawGreenlet() - # Greenlet that implicitly switches to parent - g2 = RawGreenlet(lambda: None, parent=g1) - # AttributeError should propagate to us, no fatal errors - with self.assertRaises(AttributeError): - g2.switch() - - def test_throw_exception_not_lost(self): - class mygreenlet(RawGreenlet): - def __getattribute__(self, name): - try: - raise Exception # pylint:disable=broad-exception-raised - except: # pylint:disable=bare-except - pass - return RawGreenlet.__getattribute__(self, name) - g = mygreenlet(lambda: None) - self.assertRaises(SomeError, g.throw, SomeError()) - - @fails_leakcheck - def _do_test_throw_to_dead_thread_doesnt_crash(self, wait_for_cleanup=False): - result = [] - def worker(): - greenlet.getcurrent().parent.switch() - - def creator(): - g = RawGreenlet(worker) - g.switch() - result.append(g) - if wait_for_cleanup: - # Let this greenlet eventually be cleaned up. - g.switch() - greenlet.getcurrent() - t = threading.Thread(target=creator) - t.start() - t.join(10) - del t - # But, depending on the operating system, the thread - # deallocator may not actually have run yet! So we can't be - # sure about the error message unless we wait. - if wait_for_cleanup: - self.wait_for_pending_cleanups() - with self.assertRaises(greenlet.error) as exc: - result[0].throw(SomeError) - - if not wait_for_cleanup: - s = str(exc.exception) - self.assertTrue( - s == "cannot switch to a different thread (which happens to have exited)" - or 'Cannot switch' in s - ) - else: - self.assertEqual( - str(exc.exception), - "cannot switch to a different thread (which happens to have exited)", - ) - - if hasattr(result[0].gr_frame, 'clear'): - # The frame is actually executing (it thinks), we can't clear it. - with self.assertRaises(RuntimeError): - result[0].gr_frame.clear() - # Unfortunately, this doesn't actually clear the references, they're in the - # fast local array. - if not wait_for_cleanup: - # f_locals has no clear method in Python 3.13 - if hasattr(result[0].gr_frame.f_locals, 'clear'): - result[0].gr_frame.f_locals.clear() - else: - self.assertIsNone(result[0].gr_frame) - - del creator - worker = None - del result[:] - # XXX: we ought to be able to automatically fix this. - # See issue 252 - self.expect_greenlet_leak = True # direct us not to wait for it to go away - - @fails_leakcheck - def test_throw_to_dead_thread_doesnt_crash(self): - self._do_test_throw_to_dead_thread_doesnt_crash() - - def test_throw_to_dead_thread_doesnt_crash_wait(self): - self._do_test_throw_to_dead_thread_doesnt_crash(True) - - @fails_leakcheck - def test_recursive_startup(self): - class convoluted(RawGreenlet): - def __init__(self): - RawGreenlet.__init__(self) - self.count = 0 - def __getattribute__(self, name): - if name == 'run' and self.count == 0: - self.count = 1 - self.switch(43) - return RawGreenlet.__getattribute__(self, name) - def run(self, value): - while True: - self.parent.switch(value) - g = convoluted() - self.assertEqual(g.switch(42), 43) - # Exits the running greenlet, otherwise it leaks - # XXX: We should be able to automatically fix this - #g.throw(greenlet.GreenletExit) - #del g - self.expect_greenlet_leak = True - - def test_threaded_updatecurrent(self): - # released when main thread should execute - lock1 = threading.Lock() - lock1.acquire() - # released when another thread should execute - lock2 = threading.Lock() - lock2.acquire() - class finalized(object): - def __del__(self): - # happens while in green_updatecurrent() in main greenlet - # should be very careful not to accidentally call it again - # at the same time we must make sure another thread executes - lock2.release() - lock1.acquire() - # now ts_current belongs to another thread - def deallocator(): - greenlet.getcurrent().parent.switch() - def fthread(): - lock2.acquire() - greenlet.getcurrent() - del g[0] - lock1.release() - lock2.acquire() - greenlet.getcurrent() - lock1.release() - main = greenlet.getcurrent() - g = [RawGreenlet(deallocator)] - g[0].bomb = finalized() - g[0].switch() - t = threading.Thread(target=fthread) - t.start() - # let another thread grab ts_current and deallocate g[0] - lock2.release() - lock1.acquire() - # this is the corner stone - # getcurrent() will notice that ts_current belongs to another thread - # and start the update process, which would notice that g[0] should - # be deallocated, and that will execute an object's finalizer. Now, - # that object will let another thread run so it can grab ts_current - # again, which would likely crash the interpreter if there's no - # check for this case at the end of green_updatecurrent(). This test - # passes if getcurrent() returns correct result, but it's likely - # to randomly crash if it's not anyway. - self.assertEqual(greenlet.getcurrent(), main) - # wait for another thread to complete, just in case - t.join(10) - - def test_dealloc_switch_args_not_lost(self): - seen = [] - def worker(): - # wait for the value - value = greenlet.getcurrent().parent.switch() - # delete all references to ourself - del worker[0] - initiator.parent = greenlet.getcurrent().parent - # switch to main with the value, but because - # ts_current is the last reference to us we - # return here immediately, where we resurrect ourself. - try: - greenlet.getcurrent().parent.switch(value) - finally: - seen.append(greenlet.getcurrent()) - def initiator(): - return 42 # implicitly falls thru to parent - - worker = [RawGreenlet(worker)] - - worker[0].switch() # prime worker - initiator = RawGreenlet(initiator, worker[0]) - value = initiator.switch() - self.assertTrue(seen) - self.assertEqual(value, 42) - - def test_tuple_subclass(self): - # The point of this test is to see what happens when a custom - # tuple subclass is used as an object passed directly to the C - # function ``green_switch``; part of ``green_switch`` checks - # the ``len()`` of the ``args`` tuple, and that can call back - # into Python. Here, when it calls back into Python, we - # recursively enter ``green_switch`` again. - - # This test is really only relevant on Python 2. The builtin - # `apply` function directly passes the given args tuple object - # to the underlying function, whereas the Python 3 version - # unpacks and repacks into an actual tuple. This could still - # happen using the C API on Python 3 though. We should write a - # builtin version of apply() ourself. - def _apply(func, a, k): - func(*a, **k) - - class mytuple(tuple): - def __len__(self): - greenlet.getcurrent().switch() - return tuple.__len__(self) - args = mytuple() - kwargs = dict(a=42) - def switchapply(): - _apply(greenlet.getcurrent().parent.switch, args, kwargs) - g = RawGreenlet(switchapply) - self.assertEqual(g.switch(), kwargs) - - def test_abstract_subclasses(self): - AbstractSubclass = ABCMeta( - 'AbstractSubclass', - (RawGreenlet,), - {'run': abstractmethod(lambda self: None)}) - - class BadSubclass(AbstractSubclass): - pass - - class GoodSubclass(AbstractSubclass): - def run(self): - pass - - GoodSubclass() # should not raise - self.assertRaises(TypeError, BadSubclass) - - def test_implicit_parent_with_threads(self): - if not gc.isenabled(): - return # cannot test with disabled gc - N = gc.get_threshold()[0] - if N < 50: - return # cannot test with such a small N - def attempt(): - lock1 = threading.Lock() - lock1.acquire() - lock2 = threading.Lock() - lock2.acquire() - recycled = [False] - def another_thread(): - lock1.acquire() # wait for gc - greenlet.getcurrent() # update ts_current - lock2.release() # release gc - t = threading.Thread(target=another_thread) - t.start() - class gc_callback(object): - def __del__(self): - lock1.release() - lock2.acquire() - recycled[0] = True - class garbage(object): - def __init__(self): - self.cycle = self - self.callback = gc_callback() - l = [] - x = range(N*2) - current = greenlet.getcurrent() - g = garbage() - for _ in x: - g = None # lose reference to garbage - if recycled[0]: - # gc callback called prematurely - t.join(10) - return False - last = RawGreenlet() - if recycled[0]: - break # yes! gc called in green_new - l.append(last) # increase allocation counter - else: - # gc callback not called when expected - gc.collect() - if recycled[0]: - t.join(10) - return False - self.assertEqual(last.parent, current) - for g in l: - self.assertEqual(g.parent, current) - return True - for _ in range(5): - if attempt(): - break - - def test_issue_245_reference_counting_subclass_no_threads(self): - # https://github.com/python-greenlet/greenlet/issues/245 - # Before the fix, this crashed pretty reliably on - # Python 3.10, at least on macOS; but much less reliably on other - # interpreters (memory layout must have changed). - # The threaded test crashed more reliably on more interpreters. - from greenlet import getcurrent - from greenlet import GreenletExit - - class Greenlet(RawGreenlet): - pass - - initial_refs = sys.getrefcount(Greenlet) - # This has to be an instance variable because - # Python 2 raises a SyntaxError if we delete a local - # variable referenced in an inner scope. - self.glets = [] # pylint:disable=attribute-defined-outside-init - - def greenlet_main(): - try: - getcurrent().parent.switch() - except GreenletExit: - self.glets.append(getcurrent()) - - # Before the - for _ in range(10): - Greenlet(greenlet_main).switch() - - del self.glets - if RUNNING_ON_FREETHREAD_BUILD: - # Free-threaded builds make types immortal, which gives us - # weird numbers here, and we actually do APPEAR to end - # up with one more reference than we started with, at least on 3.14. - # If we change the code in green_dealloc to avoid increffing the type - # (which fixed this initial bug), then our leakchecks find other objects - # that have leaked, including a tuple, a dict, and a type. So that's not the - # right solution. Instead we change the test: - # XXX: FIXME: Is there a better way? - self.assertGreaterEqual(sys.getrefcount(Greenlet), initial_refs) - else: - self.assertEqual(sys.getrefcount(Greenlet), initial_refs) - - @unittest.skipIf( - PY313 and RUNNING_ON_MANYLINUX, - "The manylinux images appear to hang on this test on 3.13rc2" - # Or perhaps I just got tired of waiting for the 450s timeout. - # Still, it shouldn't take anywhere near that long. Does not reproduce in - # Ubuntu images, on macOS or Windows. - ) - def test_issue_245_reference_counting_subclass_threads(self): - # https://github.com/python-greenlet/greenlet/issues/245 - from threading import Thread - from threading import Event - - from greenlet import getcurrent - - class MyGreenlet(RawGreenlet): - pass - - glets = [] - ref_cleared = Event() - - def greenlet_main(): - getcurrent().parent.switch() - - def thread_main(greenlet_running_event): - mine = MyGreenlet(greenlet_main) - glets.append(mine) - # The greenlets being deleted must be active - mine.switch() - # Don't keep any reference to it in this thread - del mine - # Let main know we published our greenlet. - greenlet_running_event.set() - # Wait for main to let us know the references are - # gone and the greenlet objects no longer reachable - ref_cleared.wait(10) - # The creating thread must call getcurrent() (or a few other - # greenlet APIs) because that's when the thread-local list of dead - # greenlets gets cleared. - getcurrent() - - # We start with 3 references to the subclass: - # - This module - # - Its __mro__ - # - The __subclassess__ attribute of greenlet - # - (If we call gc.get_referents(), we find four entries, including - # some other tuple ``(greenlet)`` that I'm not sure about but must be part - # of the machinery.) - # - # On Python 3.10 it's often enough to just run 3 threads; on Python 2.7, - # more threads are needed, and the results are still - # non-deterministic. Presumably the memory layouts are different - initial_refs = sys.getrefcount(MyGreenlet) - thread_ready_events = [] - thread_count = initial_refs + 45 - if RUNNING_ON_FREETHREAD_BUILD: - # types are immortal, so this is a HUGE number most likely, - # and we can't create that many threads. - thread_count = 50 - for _ in range(thread_count): - event = Event() - thread = Thread(target=thread_main, args=(event,)) - thread_ready_events.append(event) - thread.start() - - - for done_event in thread_ready_events: - done_event.wait(10) - - - del glets[:] - ref_cleared.set() - # Let any other thread run; it will crash the interpreter - # if not fixed (or silently corrupt memory and we possibly crash - # later). - self.wait_for_pending_cleanups() - self.assertEqual(sys.getrefcount(MyGreenlet), initial_refs) - - def test_falling_off_end_switches_to_unstarted_parent_raises_error(self): - def no_args(): - return 13 - - parent_never_started = RawGreenlet(no_args) - - def leaf(): - return 42 - - child = RawGreenlet(leaf, parent_never_started) - - # Because the run function takes to arguments - with self.assertRaises(TypeError): - child.switch() - - def test_falling_off_end_switches_to_unstarted_parent_works(self): - def one_arg(x): - return (x, 24) - - parent_never_started = RawGreenlet(one_arg) - - def leaf(): - return 42 - - child = RawGreenlet(leaf, parent_never_started) - - result = child.switch() - self.assertEqual(result, (42, 24)) - - def test_switch_to_dead_greenlet_with_unstarted_perverse_parent(self): - class Parent(RawGreenlet): - def __getattribute__(self, name): - if name == 'run': - raise SomeError - - - parent_never_started = Parent() - seen = [] - child = RawGreenlet(lambda: seen.append(42), parent_never_started) - # Because we automatically start the parent when the child is - # finished - with self.assertRaises(SomeError): - child.switch() - - self.assertEqual(seen, [42]) - - with self.assertRaises(SomeError): - child.switch() - self.assertEqual(seen, [42]) - - def test_switch_to_dead_greenlet_reparent(self): - seen = [] - parent_never_started = RawGreenlet(lambda: seen.append(24)) - child = RawGreenlet(lambda: seen.append(42)) - - child.switch() - self.assertEqual(seen, [42]) - - child.parent = parent_never_started - # This actually is the same as switching to the parent. - result = child.switch() - self.assertIsNone(result) - self.assertEqual(seen, [42, 24]) - - def test_can_access_f_back_of_suspended_greenlet(self): - # This tests our frame rewriting to work around Python 3.12+ having - # some interpreter frames on the C stack. It will crash in the absence - # of that logic. - main = greenlet.getcurrent() - - def outer(): - inner() - - def inner(): - main.switch(sys._getframe(0)) - - hub = RawGreenlet(outer) - # start it - hub.switch() - - # start another greenlet to make sure we aren't relying on - # anything in `hub` still being on the C stack - unrelated = RawGreenlet(lambda: None) - unrelated.switch() - - # now it is suspended - self.assertIsNotNone(hub.gr_frame) - self.assertEqual(hub.gr_frame.f_code.co_name, "inner") - self.assertIsNotNone(hub.gr_frame.f_back) - self.assertEqual(hub.gr_frame.f_back.f_code.co_name, "outer") - # The next line is what would crash - self.assertIsNone(hub.gr_frame.f_back.f_back) - - def test_get_stack_with_nested_c_calls(self): - from functools import partial - from . import _test_extension_cpp - - def recurse(v): - if v > 0: - return v * _test_extension_cpp.test_call(partial(recurse, v - 1)) - return greenlet.getcurrent().parent.switch() - - gr = RawGreenlet(recurse) - gr.switch(5) - frame = gr.gr_frame - for i in range(5): - self.assertEqual(frame.f_locals["v"], i) - frame = frame.f_back - self.assertEqual(frame.f_locals["v"], 5) - self.assertIsNone(frame.f_back) - self.assertEqual(gr.switch(10), 1200) # 1200 = 5! * 10 - - def test_frames_always_exposed(self): - # On Python 3.12 this will crash if we don't set the - # gr_frames_always_exposed attribute. More background: - # https://github.com/python-greenlet/greenlet/issues/388 - main = greenlet.getcurrent() - - def outer(): - inner(sys._getframe(0)) - - def inner(frame): - main.switch(frame) - - gr = RawGreenlet(outer) - frame = gr.switch() - - # Do something else to clobber the part of the C stack used by `gr`, - # so we can't skate by on "it just happened to still be there" - unrelated = RawGreenlet(lambda: None) - unrelated.switch() - - self.assertEqual(frame.f_code.co_name, "outer") - # The next line crashes on 3.12 if we haven't exposed the frames. - self.assertIsNone(frame.f_back) - - -class TestGreenletSetParentErrors(TestCase): - def test_threaded_reparent(self): - data = {} - created_event = threading.Event() - done_event = threading.Event() - - def run(): - data['g'] = RawGreenlet(lambda: None) - created_event.set() - done_event.wait(10) - - def blank(): - greenlet.getcurrent().parent.switch() - - thread = threading.Thread(target=run) - thread.start() - created_event.wait(10) - g = RawGreenlet(blank) - g.switch() - with self.assertRaises(ValueError) as exc: - g.parent = data['g'] - done_event.set() - thread.join(10) - - self.assertEqual(str(exc.exception), "parent cannot be on a different thread") - - def test_unexpected_reparenting(self): - another = [] - def worker(): - g = RawGreenlet(lambda: None) - another.append(g) - g.switch() - t = threading.Thread(target=worker) - t.start() - t.join(10) - # The first time we switch (running g_initialstub(), which is - # when we look up the run attribute) we attempt to change the - # parent to one from another thread (which also happens to be - # dead). ``g_initialstub()`` should detect this and raise a - # greenlet error. - # - # EXCEPT: With the fix for #252, this is actually detected - # sooner, when setting the parent itself. Prior to that fix, - # the main greenlet from the background thread kept a valid - # value for ``run_info``, and appeared to be a valid parent - # until we actually started the greenlet. But now that it's - # cleared, this test is catching whether ``green_setparent`` - # can detect the dead thread. - # - # Further refactoring once again changes this back to a greenlet.error - # - # We need to wait for the cleanup to happen, but we're - # deliberately leaking a main greenlet here. - self.wait_for_pending_cleanups(initial_main_greenlets=self.main_greenlets_before_test + 1) - - class convoluted(RawGreenlet): - def __getattribute__(self, name): - if name == 'run': - self.parent = another[0] # pylint:disable=attribute-defined-outside-init - return RawGreenlet.__getattribute__(self, name) - g = convoluted(lambda: None) - with self.assertRaises(greenlet.error) as exc: - g.switch() - self.assertEqual(str(exc.exception), - "cannot switch to a different thread (which happens to have exited)") - del another[:] - - def test_unexpected_reparenting_thread_running(self): - # Like ``test_unexpected_reparenting``, except the background thread is - # actually still alive. - another = [] - switched_to_greenlet = threading.Event() - keep_main_alive = threading.Event() - def worker(): - g = RawGreenlet(lambda: None) - another.append(g) - g.switch() - switched_to_greenlet.set() - keep_main_alive.wait(10) - class convoluted(RawGreenlet): - def __getattribute__(self, name): - if name == 'run': - self.parent = another[0] # pylint:disable=attribute-defined-outside-init - return RawGreenlet.__getattribute__(self, name) - - t = threading.Thread(target=worker) - t.start() - - switched_to_greenlet.wait(10) - try: - g = convoluted(lambda: None) - - with self.assertRaises(greenlet.error) as exc: - g.switch() - self.assertIn("Cannot switch to a different thread", str(exc.exception)) - self.assertIn("Expected", str(exc.exception)) - self.assertIn("Current", str(exc.exception)) - finally: - keep_main_alive.set() - t.join(10) - # XXX: Should handle this automatically. - del another[:] - - def test_cannot_delete_parent(self): - worker = RawGreenlet(lambda: None) - self.assertIs(worker.parent, greenlet.getcurrent()) - - with self.assertRaises(AttributeError) as exc: - del worker.parent - self.assertEqual(str(exc.exception), "can't delete attribute") - - def test_cannot_delete_parent_of_main(self): - with self.assertRaises(AttributeError) as exc: - del greenlet.getcurrent().parent - self.assertEqual(str(exc.exception), "can't delete attribute") - - - def test_main_greenlet_parent_is_none(self): - # assuming we're in a main greenlet here. - self.assertIsNone(greenlet.getcurrent().parent) - - def test_set_parent_wrong_types(self): - def bg(): - # Go back to main. - greenlet.getcurrent().parent.switch() - - def check(glet): - for p in None, 1, self, "42": - with self.assertRaises(TypeError) as exc: - glet.parent = p - - self.assertEqual( - str(exc.exception), - "GreenletChecker: Expected any type of greenlet, not " + type(p).__name__) - - # First, not running - g = RawGreenlet(bg) - self.assertFalse(g) - check(g) - - # Then when running. - g.switch() - self.assertTrue(g) - check(g) - - # Let it finish - g.switch() - - - def test_trivial_cycle(self): - glet = RawGreenlet(lambda: None) - with self.assertRaises(ValueError) as exc: - glet.parent = glet - self.assertEqual(str(exc.exception), "cyclic parent chain") - - def test_trivial_cycle_main(self): - # This used to produce a ValueError, but we catch it earlier than that now. - with self.assertRaises(AttributeError) as exc: - greenlet.getcurrent().parent = greenlet.getcurrent() - self.assertEqual(str(exc.exception), "cannot set the parent of a main greenlet") - - def test_deeper_cycle(self): - g1 = RawGreenlet(lambda: None) - g2 = RawGreenlet(lambda: None) - g3 = RawGreenlet(lambda: None) - - g1.parent = g2 - g2.parent = g3 - with self.assertRaises(ValueError) as exc: - g3.parent = g1 - self.assertEqual(str(exc.exception), "cyclic parent chain") - - -class TestRepr(TestCase): - - def assertEndsWith(self, got, suffix): - self.assertTrue(got.endswith(suffix), (got, suffix)) - - def test_main_while_running(self): - r = repr(greenlet.getcurrent()) - self.assertEndsWith(r, " current active started main>") - - def test_main_in_background(self): - main = greenlet.getcurrent() - def run(): - return repr(main) - - g = RawGreenlet(run) - r = g.switch() - self.assertEndsWith(r, ' suspended active started main>') - - def test_initial(self): - r = repr(RawGreenlet()) - self.assertEndsWith(r, ' pending>') - - def test_main_from_other_thread(self): - main = greenlet.getcurrent() - - class T(threading.Thread): - original_main = thread_main = None - main_glet = None - def run(self): - self.original_main = repr(main) - self.main_glet = greenlet.getcurrent() - self.thread_main = repr(self.main_glet) - - t = T() - t.start() - t.join(10) - - self.assertEndsWith(t.original_main, ' suspended active started main>') - self.assertEndsWith(t.thread_main, ' current active started main>') - # give the machinery time to notice the death of the thread, - # and clean it up. Note that we don't use - # ``expect_greenlet_leak`` or wait_for_pending_cleanups, - # because at this point we know we have an extra greenlet - # still reachable. - for _ in range(3): - time.sleep(0.001) - - # In the past, main greenlets, even from dead threads, never - # really appear dead. We have fixed that, and we also report - # that the thread is dead in the repr. (Do this multiple times - # to make sure that we don't self-modify and forget our state - # in the C++ code). - for _ in range(3): - self.assertTrue(t.main_glet.dead) - r = repr(t.main_glet) - self.assertEndsWith(r, ' (thread exited) dead>') - - def test_dead(self): - g = RawGreenlet(lambda: None) - g.switch() - self.assertEndsWith(repr(g), ' dead>') - self.assertNotIn('suspended', repr(g)) - self.assertNotIn('started', repr(g)) - self.assertNotIn('active', repr(g)) - - def test_formatting_produces_native_str(self): - # https://github.com/python-greenlet/greenlet/issues/218 - # %s formatting on Python 2 was producing unicode, not str. - - g_dead = RawGreenlet(lambda: None) - g_not_started = RawGreenlet(lambda: None) - g_cur = greenlet.getcurrent() - - for g in g_dead, g_not_started, g_cur: - - self.assertIsInstance( - '%s' % (g,), - str - ) - self.assertIsInstance( - '%r' % (g,), - str, - ) - - -class TestMainGreenlet(TestCase): - # Tests some implementation details, and relies on some - # implementation details. - - def _check_current_is_main(self): - # implementation detail - assert 'main' in repr(greenlet.getcurrent()) - - t = type(greenlet.getcurrent()) - assert 'main' not in repr(t) - return t - - def test_main_greenlet_type_can_be_subclassed(self): - main_type = self._check_current_is_main() - subclass = type('subclass', (main_type,), {}) - self.assertIsNotNone(subclass) - - def test_main_greenlet_is_greenlet(self): - self._check_current_is_main() - self.assertIsInstance(greenlet.getcurrent(), RawGreenlet) - - - -class TestBrokenGreenlets(TestCase): - # Tests for things that used to, or still do, terminate the interpreter. - # This often means doing unsavory things. - - def test_failed_to_initialstub(self): - def func(): - raise AssertionError("Never get here") - - - g = greenlet._greenlet.UnswitchableGreenlet(func) - g.force_switch_error = True - - with self.assertRaisesRegex(SystemError, - "Failed to switch stacks into a greenlet for the first time."): - g.switch() - - def test_failed_to_switch_into_running(self): - runs = [] - def func(): - runs.append(1) - greenlet.getcurrent().parent.switch() - runs.append(2) - greenlet.getcurrent().parent.switch() - runs.append(3) # pragma: no cover - - g = greenlet._greenlet.UnswitchableGreenlet(func) - g.switch() - self.assertEqual(runs, [1]) - g.switch() - self.assertEqual(runs, [1, 2]) - g.force_switch_error = True - - with self.assertRaisesRegex(SystemError, - "Failed to switch stacks into a running greenlet."): - g.switch() - - # If we stopped here, we would fail the leakcheck, because we've left - # the ``inner_bootstrap()`` C frame and its descendents hanging around, - # which have a bunch of Python references. They'll never get cleaned up - # if we don't let the greenlet finish. - g.force_switch_error = False - g.switch() - self.assertEqual(runs, [1, 2, 3]) - - def test_failed_to_slp_switch_into_running(self): - ex = self.assertScriptRaises('fail_slp_switch.py') - - self.assertIn('fail_slp_switch is running', ex.output) - self.assertIn(ex.returncode, self.get_expected_returncodes_for_aborted_process()) - - def test_reentrant_switch_two_greenlets(self): - # Before we started capturing the arguments in g_switch_finish, this could crash. - output = self.run_script('fail_switch_two_greenlets.py') - self.assertIn('In g1_run', output) - self.assertIn('TRACE', output) - self.assertIn('LEAVE TRACE', output) - self.assertIn('Falling off end of main', output) - self.assertIn('Falling off end of g1_run', output) - self.assertIn('Falling off end of g2', output) - - def test_reentrant_switch_three_greenlets(self): - # On debug builds of greenlet, this used to crash with an assertion error; - # on non-debug versions, it ran fine (which it should not do!). - # Now it always crashes correctly with a TypeError - ex = self.assertScriptRaises('fail_switch_three_greenlets.py', exitcodes=(1,)) - - self.assertIn('TypeError', ex.output) - self.assertIn('positional arguments', ex.output) - - def test_reentrant_switch_three_greenlets2(self): - # This actually passed on debug and non-debug builds. It - # should probably have been triggering some debug assertions - # but it didn't. - # - # I think the fixes for the above test also kicked in here. - output = self.run_script('fail_switch_three_greenlets2.py') - self.assertIn( - "RESULTS: [('trace', 'switch'), " - "('trace', 'switch'), ('g2 arg', 'g2 from tracefunc'), " - "('trace', 'switch'), ('main g1', 'from g2_run'), ('trace', 'switch'), " - "('g1 arg', 'g1 from main'), ('trace', 'switch'), ('main g2', 'from g1_run'), " - "('trace', 'switch'), ('g1 from parent', 'g1 from main 2'), ('trace', 'switch'), " - "('main g1.2', 'g1 done'), ('trace', 'switch'), ('g2 from parent', ()), " - "('trace', 'switch'), ('main g2.2', 'g2 done')]", - output - ) - - def test_reentrant_switch_GreenletAlreadyStartedInPython(self): - output = self.run_script('fail_initialstub_already_started.py') - - self.assertIn( - "RESULTS: ['Begin C', 'Switch to b from B.__getattribute__ in C', " - "('Begin B', ()), '_B_run switching to main', ('main from c', 'From B'), " - "'B.__getattribute__ back from main in C', ('Begin A', (None,)), " - "('A dead?', True, 'B dead?', True, 'C dead?', False), " - "'C done', ('main from c.2', None)]", - output - ) - - def test_reentrant_switch_run_callable_has_del(self): - output = self.run_script('fail_clearing_run_switches.py') - self.assertIn( - "RESULTS [" - "('G.__getattribute__', 'run'), ('RunCallable', '__del__'), " - "('main: g.switch()', 'from RunCallable'), ('run_func', 'enter')" - "]", - output - ) - -if __name__ == '__main__': - unittest.main() diff --git a/venv/lib/python3.9/site-packages/greenlet/tests/test_greenlet_trash.py b/venv/lib/python3.9/site-packages/greenlet/tests/test_greenlet_trash.py deleted file mode 100644 index c1fc137..0000000 --- a/venv/lib/python3.9/site-packages/greenlet/tests/test_greenlet_trash.py +++ /dev/null @@ -1,187 +0,0 @@ -# -*- coding: utf-8 -*- -""" -Tests for greenlets interacting with the CPython trash can API. - -The CPython trash can API is not designed to be re-entered from a -single thread. But this can happen using greenlets, if something -during the object deallocation process switches greenlets, and this second -greenlet then causes the trash can to get entered again. Here, we do this -very explicitly, but in other cases (like gevent) it could be arbitrarily more -complicated: for example, a weakref callback might try to acquire a lock that's -already held by another greenlet; that would allow a greenlet switch to occur. - -See https://github.com/gevent/gevent/issues/1909 - -This test is fragile and relies on details of the CPython -implementation (like most of the rest of this package): - - - We enter the trashcan and deferred deallocation after - ``_PyTrash_UNWIND_LEVEL`` calls. This constant, defined in - CPython's object.c, is generally 50. That's basically how many objects are required to - get us into the deferred deallocation situation. - - - The test fails by hitting an ``assert()`` in object.c; if the - build didn't enable assert, then we don't catch this. - - - If the test fails in that way, the interpreter crashes. -""" -from __future__ import print_function, absolute_import, division - -import unittest - - -class TestTrashCanReEnter(unittest.TestCase): - - def test_it(self): - try: - # pylint:disable-next=no-name-in-module - from greenlet._greenlet import get_tstate_trash_delete_nesting # pylint:disable=unused-import - except ImportError: - import sys - # Python 3.13 has not "trash delete nesting" anymore (but "delete later") - assert sys.version_info[:2] >= (3, 13) - self.skipTest("get_tstate_trash_delete_nesting is not available.") - - # Try several times to trigger it, because it isn't 100% - # reliable. - for _ in range(10): - self.check_it() - - def check_it(self): # pylint:disable=too-many-statements - import greenlet - from greenlet._greenlet import get_tstate_trash_delete_nesting # pylint:disable=no-name-in-module - main = greenlet.getcurrent() - - assert get_tstate_trash_delete_nesting() == 0 - - # We expect to be in deferred deallocation after this many - # deallocations have occurred. TODO: I wish we had a better way to do - # this --- that was before get_tstate_trash_delete_nesting; perhaps - # we can use that API to do better? - TRASH_UNWIND_LEVEL = 50 - # How many objects to put in a container; it's the container that - # queues objects for deferred deallocation. - OBJECTS_PER_CONTAINER = 500 - - class Dealloc: # define the class here because we alter class variables each time we run. - """ - An object with a ``__del__`` method. When it starts getting deallocated - from a deferred trash can run, it switches greenlets, allocates more objects - which then also go in the trash can. If we don't save state appropriately, - nesting gets out of order and we can crash the interpreter. - """ - - #: Has our deallocation actually run and switched greenlets? - #: When it does, this will be set to the current greenlet. This should - #: be happening in the main greenlet, so we check that down below. - SPAWNED = False - - #: Has the background greenlet run? - BG_RAN = False - - BG_GLET = None - - #: How many of these things have ever been allocated. - CREATED = 0 - - #: How many of these things have ever been deallocated. - DESTROYED = 0 - - #: How many were destroyed not in the main greenlet. There should always - #: be some. - #: If the test is broken or things change in the trashcan implementation, - #: this may not be correct. - DESTROYED_BG = 0 - - def __init__(self, sequence_number): - """ - :param sequence_number: The ordinal of this object during - one particular creation run. This is used to detect (guess, really) - when we have entered the trash can's deferred deallocation. - """ - self.i = sequence_number - Dealloc.CREATED += 1 - - def __del__(self): - if self.i == TRASH_UNWIND_LEVEL and not self.SPAWNED: - Dealloc.SPAWNED = greenlet.getcurrent() - other = Dealloc.BG_GLET = greenlet.greenlet(background_greenlet) - x = other.switch() - assert x == 42 - # It's important that we don't switch back to the greenlet, - # we leave it hanging there in an incomplete state. But we don't let it - # get collected, either. If we complete it now, while we're still - # in the scope of the initial trash can, things work out and we - # don't see the problem. We need this greenlet to complete - # at some point in the future, after we've exited this trash can invocation. - del other - elif self.i == 40 and greenlet.getcurrent() is not main: - Dealloc.BG_RAN = True - try: - main.switch(42) - except greenlet.GreenletExit as ex: - # We expect this; all references to us go away - # while we're still running, and we need to finish deleting - # ourself. - Dealloc.BG_RAN = type(ex) - del ex - - # Record the fact that we're dead last of all. This ensures that - # we actually get returned too. - Dealloc.DESTROYED += 1 - if greenlet.getcurrent() is not main: - Dealloc.DESTROYED_BG += 1 - - - def background_greenlet(): - # We direct through a second function, instead of - # directly calling ``make_some()``, so that we have complete - # control over when these objects are destroyed: we need them - # to be destroyed in the context of the background greenlet - t = make_some() - del t # Triggere deletion. - - def make_some(): - t = () - i = OBJECTS_PER_CONTAINER - while i: - # Nest the tuples; it's the recursion that gets us - # into trash. - t = (Dealloc(i), t) - i -= 1 - return t - - - some = make_some() - self.assertEqual(Dealloc.CREATED, OBJECTS_PER_CONTAINER) - self.assertEqual(Dealloc.DESTROYED, 0) - - # If we're going to crash, it should be on the following line. - # We only crash if ``assert()`` is enabled, of course. - del some - - # For non-debug builds of CPython, we won't crash. The best we can do is check - # the nesting level explicitly. - self.assertEqual(0, get_tstate_trash_delete_nesting()) - - # Discard this, raising GreenletExit into where it is waiting. - Dealloc.BG_GLET = None - # The same nesting level maintains. - self.assertEqual(0, get_tstate_trash_delete_nesting()) - - # We definitely cleaned some up in the background - self.assertGreater(Dealloc.DESTROYED_BG, 0) - - # Make sure all the cleanups happened. - self.assertIs(Dealloc.SPAWNED, main) - self.assertTrue(Dealloc.BG_RAN) - self.assertEqual(Dealloc.BG_RAN, greenlet.GreenletExit) - self.assertEqual(Dealloc.CREATED, Dealloc.DESTROYED ) - self.assertEqual(Dealloc.CREATED, OBJECTS_PER_CONTAINER * 2) - - import gc - gc.collect() - - -if __name__ == '__main__': - unittest.main() diff --git a/venv/lib/python3.9/site-packages/greenlet/tests/test_interpreter_shutdown.py b/venv/lib/python3.9/site-packages/greenlet/tests/test_interpreter_shutdown.py deleted file mode 100644 index 37afc52..0000000 --- a/venv/lib/python3.9/site-packages/greenlet/tests/test_interpreter_shutdown.py +++ /dev/null @@ -1,320 +0,0 @@ -# -*- coding: utf-8 -*- -""" -Tests for greenlet behavior during interpreter shutdown (Py_FinalizeEx). - -Prior to the safe finalization fix, active greenlets being deallocated -during interpreter shutdown could trigger SIGSEGV or SIGABRT on Python -< 3.11, because green_dealloc attempted to throw GreenletExit via -g_switch() into a partially-torn-down interpreter. - -The fix adds _Py_IsFinalizing() guards (on Python < 3.11 only) that -call murder_in_place() instead of g_switch() when the interpreter is -shutting down, avoiding the crash at the cost of not running cleanup -code inside the greenlet. - -These tests verify: - 1. No crashes on ANY Python version (the core safety guarantee). - 2. GreenletExit cleanup code runs correctly during normal thread exit - (the standard production path, e.g. uWSGI worker threads). -""" -import sys -import subprocess -import unittest -import textwrap - -from greenlet.tests import TestCase - - -class TestInterpreterShutdown(TestCase): - - def _run_shutdown_script(self, script_body): - """ - Run a Python script in a subprocess that exercises greenlet - during interpreter shutdown. Returns (returncode, stdout, stderr). - """ - full_script = textwrap.dedent(script_body) - result = subprocess.run( - [sys.executable, '-c', full_script], - capture_output=True, - text=True, - timeout=30, - check=False, - ) - return result.returncode, result.stdout, result.stderr - - # ----------------------------------------------------------------- - # Core safety tests: no crashes on any Python version - # ----------------------------------------------------------------- - - def test_active_greenlet_at_shutdown_no_crash(self): - """ - An active (suspended) greenlet that is deallocated during - interpreter shutdown should not crash the process. - - Before the fix, this would SIGSEGV on Python < 3.11 because - _green_dealloc_kill_started_non_main_greenlet tried to call - g_switch() during Py_FinalizeEx. - """ - rc, stdout, stderr = self._run_shutdown_script("""\ - import greenlet - - def worker(): - greenlet.getcurrent().parent.switch("from worker") - return "done" - - g = greenlet.greenlet(worker) - result = g.switch() - assert result == "from worker", result - print("OK: exiting with active greenlet") - """) - self.assertEqual(rc, 0, f"Process crashed (rc={rc}):\n{stdout}{stderr}") - self.assertIn("OK: exiting with active greenlet", stdout) - - def test_multiple_active_greenlets_at_shutdown(self): - """ - Multiple suspended greenlets at shutdown should all be cleaned - up without crashing. - """ - rc, stdout, stderr = self._run_shutdown_script("""\ - import greenlet - - def worker(name): - greenlet.getcurrent().parent.switch(f"hello from {name}") - return "done" - - greenlets = [] - for i in range(10): - g = greenlet.greenlet(worker) - result = g.switch(f"g{i}") - greenlets.append(g) - - print(f"OK: {len(greenlets)} active greenlets at shutdown") - """) - self.assertEqual(rc, 0, f"Process crashed (rc={rc}):\n{stdout}{stderr}") - self.assertIn("OK: 10 active greenlets at shutdown", stdout) - - def test_nested_greenlets_at_shutdown(self): - """ - Nested (chained parent) greenlets at shutdown should not crash. - """ - rc, stdout, stderr = self._run_shutdown_script("""\ - import greenlet - - def inner(): - greenlet.getcurrent().parent.switch("inner done") - - def outer(): - g_inner = greenlet.greenlet(inner) - g_inner.switch() - greenlet.getcurrent().parent.switch("outer done") - - g = greenlet.greenlet(outer) - result = g.switch() - assert result == "outer done", result - print("OK: nested greenlets at shutdown") - """) - self.assertEqual(rc, 0, f"Process crashed (rc={rc}):\n{stdout}{stderr}") - self.assertIn("OK: nested greenlets at shutdown", stdout) - - def test_threaded_greenlets_at_shutdown(self): - """ - Greenlets in worker threads that are still referenced at - shutdown should not crash. - """ - rc, stdout, stderr = self._run_shutdown_script("""\ - import greenlet - import threading - - results = [] - - def thread_worker(): - def greenlet_func(): - greenlet.getcurrent().parent.switch("from thread greenlet") - return "done" - - g = greenlet.greenlet(greenlet_func) - val = g.switch() - results.append((g, val)) - - threads = [] - for _ in range(3): - t = threading.Thread(target=thread_worker) - t.start() - threads.append(t) - - for t in threads: - t.join() - - print(f"OK: {len(results)} threaded greenlets at shutdown") - """) - self.assertEqual(rc, 0, f"Process crashed (rc={rc}):\n{stdout}{stderr}") - self.assertIn("OK: 3 threaded greenlets at shutdown", stdout) - - # ----------------------------------------------------------------- - # Cleanup semantics tests - # ----------------------------------------------------------------- - # - # Note on behavioral testing during interpreter shutdown: - # - # During Py_FinalizeEx, sys.stdout is set to None early, making - # print() a no-op. More importantly, an active greenlet in the - # module-level scope interferes with module dict clearing — the - # greenlet's dealloc path (which temporarily resurrects the object - # and performs a stack switch via g_switch) prevents reliable - # observation of cleanup behavior. - # - # The production crash (SIGSEGV/SIGABRT) occurs during thread-state - # cleanup in Py_FinalizeEx, not during module dict clearing. Our - # _Py_IsFinalizing() guard in _green_dealloc_kill_started_non_main_ - # greenlet targets that path. The safety tests above verify that no - # crashes occur; the tests below verify that greenlet cleanup works - # correctly during normal thread exit (the most common code path). - - def test_greenlet_cleanup_during_thread_exit(self): - """ - When a thread exits normally while holding active greenlets, - GreenletExit IS thrown and cleanup code runs. This is the - standard cleanup path used in production (e.g. uWSGI worker - threads finishing a request). - """ - rc, stdout, stderr = self._run_shutdown_script("""\ - import os - import threading - import greenlet - - _write = os.write - - def thread_func(): - def worker(_w=_write, - _GreenletExit=greenlet.GreenletExit): - try: - greenlet.getcurrent().parent.switch("suspended") - except _GreenletExit: - _w(1, b"CLEANUP: GreenletExit caught\\n") - raise - - g = greenlet.greenlet(worker) - g.switch() - # Thread exits with active greenlet -> thread-state - # cleanup triggers GreenletExit - - t = threading.Thread(target=thread_func) - t.start() - t.join() - print("OK: thread cleanup done") - """) - self.assertEqual(rc, 0, f"Process crashed (rc={rc}):\n{stdout}{stderr}") - self.assertIn("OK: thread cleanup done", stdout) - self.assertIn("CLEANUP: GreenletExit caught", stdout) - - def test_finally_block_during_thread_exit(self): - """ - try/finally blocks in active greenlets run correctly when the - owning thread exits. - """ - rc, stdout, stderr = self._run_shutdown_script("""\ - import os - import threading - import greenlet - - _write = os.write - - def thread_func(): - def worker(_w=_write): - try: - greenlet.getcurrent().parent.switch("suspended") - finally: - _w(1, b"FINALLY: cleanup executed\\n") - - g = greenlet.greenlet(worker) - g.switch() - - t = threading.Thread(target=thread_func) - t.start() - t.join() - print("OK: thread cleanup done") - """) - self.assertEqual(rc, 0, f"Process crashed (rc={rc}):\n{stdout}{stderr}") - self.assertIn("OK: thread cleanup done", stdout) - self.assertIn("FINALLY: cleanup executed", stdout) - - def test_many_greenlets_with_cleanup_at_shutdown(self): - """ - Stress test: many active greenlets with cleanup code at shutdown. - Ensures no crashes regardless of deallocation order. - """ - rc, stdout, stderr = self._run_shutdown_script("""\ - import sys - import greenlet - - cleanup_count = 0 - - def worker(idx): - global cleanup_count - try: - greenlet.getcurrent().parent.switch(f"ready-{idx}") - except greenlet.GreenletExit: - cleanup_count += 1 - raise - - greenlets = [] - for i in range(50): - g = greenlet.greenlet(worker) - result = g.switch(i) - greenlets.append(g) - - print(f"OK: {len(greenlets)} greenlets about to shut down") - # Note: we can't easily print cleanup_count during shutdown - # since it happens after the main module's code runs. - """) - self.assertEqual(rc, 0, f"Process crashed (rc={rc}):\n{stdout}{stderr}") - self.assertIn("OK: 50 greenlets about to shut down", stdout) - - def test_deeply_nested_greenlets_at_shutdown(self): - """ - Deeply nested greenlet parent chains at shutdown. - Tests that the deallocation order doesn't cause issues. - """ - rc, stdout, stderr = self._run_shutdown_script("""\ - import greenlet - - def level(depth, max_depth): - if depth < max_depth: - g = greenlet.greenlet(level) - g.switch(depth + 1, max_depth) - greenlet.getcurrent().parent.switch(f"depth-{depth}") - - g = greenlet.greenlet(level) - result = g.switch(0, 10) - print(f"OK: nested to depth 10, got {result}") - """) - self.assertEqual(rc, 0, f"Process crashed (rc={rc}):\n{stdout}{stderr}") - self.assertIn("OK: nested to depth 10", stdout) - - def test_greenlet_with_traceback_at_shutdown(self): - """ - A greenlet that has an active exception context when it's - suspended should not crash during shutdown cleanup. - """ - rc, stdout, stderr = self._run_shutdown_script("""\ - import greenlet - - def worker(): - try: - raise ValueError("test error") - except ValueError: - # Suspend while an exception is active on the stack - greenlet.getcurrent().parent.switch("suspended with exc") - return "done" - - g = greenlet.greenlet(worker) - result = g.switch() - assert result == "suspended with exc" - print("OK: greenlet with active exception at shutdown") - """) - self.assertEqual(rc, 0, f"Process crashed (rc={rc}):\n{stdout}{stderr}") - self.assertIn("OK: greenlet with active exception at shutdown", stdout) - - -if __name__ == '__main__': - unittest.main() diff --git a/venv/lib/python3.9/site-packages/greenlet/tests/test_leaks.py b/venv/lib/python3.9/site-packages/greenlet/tests/test_leaks.py deleted file mode 100644 index e09da7d..0000000 --- a/venv/lib/python3.9/site-packages/greenlet/tests/test_leaks.py +++ /dev/null @@ -1,457 +0,0 @@ -# -*- coding: utf-8 -*- -""" -Testing scenarios that may have leaked. -""" -from __future__ import print_function, absolute_import, division - -import sys -import gc - -import time -import weakref -import threading - - -import greenlet -from . import TestCase -from . import PY314 -from . import RUNNING_ON_FREETHREAD_BUILD -from .leakcheck import fails_leakcheck -from .leakcheck import ignores_leakcheck -from .leakcheck import RUNNING_ON_MANYLINUX - - -# pylint:disable=protected-access - -assert greenlet.GREENLET_USE_GC # Option to disable this was removed in 1.0 - -class HasFinalizerTracksInstances(object): - EXTANT_INSTANCES = set() - def __init__(self, msg): - self.msg = sys.intern(msg) - self.EXTANT_INSTANCES.add(id(self)) - def __del__(self): - self.EXTANT_INSTANCES.remove(id(self)) - def __repr__(self): - return "" % ( - id(self), self.msg - ) - @classmethod - def reset(cls): - cls.EXTANT_INSTANCES.clear() - - -def fails_leakcheck_except_on_free_thraded(func): - if RUNNING_ON_FREETHREAD_BUILD: - # These all seem to pass on free threading because - # of the changes to the garbage collector - return func - return fails_leakcheck(func) - - -class TestLeaks(TestCase): - - def test_arg_refs(self): - args = ('a', 'b', 'c') - refcount_before = sys.getrefcount(args) - # pylint:disable=unnecessary-lambda - g = greenlet.greenlet( - lambda *args: greenlet.getcurrent().parent.switch(*args)) - for _ in range(100): - g.switch(*args) - self.assertEqual(sys.getrefcount(args), refcount_before) - - def test_kwarg_refs(self): - kwargs = {} - self.assertEqual(sys.getrefcount(kwargs), 2 if not PY314 else 1) - # pylint:disable=unnecessary-lambda - g = greenlet.greenlet( - lambda **gkwargs: greenlet.getcurrent().parent.switch(**gkwargs)) - for _ in range(100): - g.switch(**kwargs) - # Python 3.14 elides reference counting operations - # in some cases. See https://github.com/python/cpython/pull/130708 - self.assertEqual(sys.getrefcount(kwargs), 2 if not PY314 else 1) - - - @staticmethod - def __recycle_threads(): - # By introducing a thread that does sleep we allow other threads, - # that have triggered their __block condition, but did not have a - # chance to deallocate their thread state yet, to finally do so. - # The way it works is by requiring a GIL switch (different thread), - # which does a GIL release (sleep), which might do a GIL switch - # to finished threads and allow them to clean up. - def worker(): - time.sleep(0.001) - t = threading.Thread(target=worker) - t.start() - time.sleep(0.001) - t.join(10) - - def test_threaded_leak(self): - gg = [] - def worker(): - # only main greenlet present - gg.append(weakref.ref(greenlet.getcurrent())) - for _ in range(2): - t = threading.Thread(target=worker) - t.start() - t.join(10) - del t - greenlet.getcurrent() # update ts_current - self.__recycle_threads() - greenlet.getcurrent() # update ts_current - gc.collect() - greenlet.getcurrent() # update ts_current - for g in gg: - self.assertIsNone(g()) - - def test_threaded_adv_leak(self): - gg = [] - def worker(): - # main and additional *finished* greenlets - ll = greenlet.getcurrent().ll = [] - def additional(): - ll.append(greenlet.getcurrent()) - for _ in range(2): - greenlet.greenlet(additional).switch() - gg.append(weakref.ref(greenlet.getcurrent())) - for _ in range(2): - t = threading.Thread(target=worker) - t.start() - t.join(10) - del t - greenlet.getcurrent() # update ts_current - self.__recycle_threads() - greenlet.getcurrent() # update ts_current - gc.collect() - greenlet.getcurrent() # update ts_current - for g in gg: - self.assertIsNone(g()) - - def assertClocksUsed(self): - used = greenlet._greenlet.get_clocks_used_doing_optional_cleanup() - self.assertGreaterEqual(used, 0) - # we don't lose the value - greenlet._greenlet.enable_optional_cleanup(True) - used2 = greenlet._greenlet.get_clocks_used_doing_optional_cleanup() - self.assertEqual(used, used2) - self.assertGreater(greenlet._greenlet.CLOCKS_PER_SEC, 1) - - def _check_issue251(self, - manually_collect_background=True, - explicit_reference_to_switch=False): - # See https://github.com/python-greenlet/greenlet/issues/251 - # Killing a greenlet (probably not the main one) - # in one thread from another thread would - # result in leaking a list (the ts_delkey list). - # We no longer use lists to hold that stuff, though. - - # For the test to be valid, even empty lists have to be tracked by the - # GC - - assert gc.is_tracked([]) - HasFinalizerTracksInstances.reset() - greenlet.getcurrent() - greenlets_before = self.count_objects(greenlet.greenlet, exact_kind=False) - - background_glet_running = threading.Event() - background_glet_killed = threading.Event() - background_greenlets = [] - - # XXX: Switching this to a greenlet subclass that overrides - # run results in all callers failing the leaktest; that - # greenlet instance is leaked. There's a bound method for - # run() living on the stack of the greenlet in g_initialstub, - # and since we don't manually switch back to the background - # greenlet to let it "fall off the end" and exit the - # g_initialstub function, it never gets cleaned up. Making the - # garbage collector aware of this bound method (making it an - # attribute of the greenlet structure and traversing into it) - # doesn't help, for some reason. - def background_greenlet(): - # Throw control back to the main greenlet. - jd = HasFinalizerTracksInstances("DELETING STACK OBJECT") - greenlet._greenlet.set_thread_local( - 'test_leaks_key', - HasFinalizerTracksInstances("DELETING THREAD STATE")) - # Explicitly keeping 'switch' in a local variable - # breaks this test in all versions - if explicit_reference_to_switch: - s = greenlet.getcurrent().parent.switch - s([jd]) - else: - greenlet.getcurrent().parent.switch([jd]) - - bg_main_wrefs = [] - - def background_thread(): - glet = greenlet.greenlet(background_greenlet) - bg_main_wrefs.append(weakref.ref(glet.parent)) - - background_greenlets.append(glet) - glet.switch() # Be sure it's active. - # Control is ours again. - del glet # Delete one reference from the thread it runs in. - background_glet_running.set() - background_glet_killed.wait(10) - - # To trigger the background collection of the dead - # greenlet, thus clearing out the contents of the list, we - # need to run some APIs. See issue 252. - if manually_collect_background: - greenlet.getcurrent() - - - t = threading.Thread(target=background_thread) - t.start() - background_glet_running.wait(10) - greenlet.getcurrent() - lists_before = self.count_objects(list, exact_kind=True) - - assert len(background_greenlets) == 1 - self.assertFalse(background_greenlets[0].dead) - # Delete the last reference to the background greenlet - # from a different thread. This puts it in the background thread's - # ts_delkey list. - del background_greenlets[:] - background_glet_killed.set() - - # Now wait for the background thread to die. - t.join(10) - del t - # As part of the fix for 252, we need to cycle the ceval.c - # interpreter loop to be sure it has had a chance to process - # the pending call. - self.wait_for_pending_cleanups() - - lists_after = self.count_objects(list, exact_kind=True) - greenlets_after = self.count_objects(greenlet.greenlet, exact_kind=False) - - # On 2.7, we observe that lists_after is smaller than - # lists_before. No idea what lists got cleaned up. All the - # Python 3 versions match exactly. - self.assertLessEqual(lists_after, lists_before) - # On versions after 3.6, we've successfully cleaned up the - # greenlet references thanks to the internal "vectorcall" - # protocol; prior to that, there is a reference path through - # the ``greenlet.switch`` method still on the stack that we - # can't reach to clean up. The C code goes through terrific - # lengths to clean that up. - if not explicit_reference_to_switch \ - and greenlet._greenlet.get_clocks_used_doing_optional_cleanup() is not None: - # If cleanup was disabled, though, we may not find it. - self.assertEqual(greenlets_after, greenlets_before) - if manually_collect_background: - # TODO: Figure out how to make this work! - # The one on the stack is still leaking somehow - # in the non-manually-collect state. - self.assertEqual(HasFinalizerTracksInstances.EXTANT_INSTANCES, set()) - else: - # The explicit reference prevents us from collecting it - # and it isn't always found by the GC either for some - # reason. The entire frame is leaked somehow, on some - # platforms (e.g., MacPorts builds of Python (all - # versions!)), but not on other platforms (the linux and - # windows builds on GitHub actions and Appveyor). So we'd - # like to write a test that proves that the main greenlet - # sticks around, and we can on my machine (macOS 11.6, - # MacPorts builds of everything) but we can't write that - # same test on other platforms. However, hopefully iteration - # done by leakcheck will find it. - pass - - if greenlet._greenlet.get_clocks_used_doing_optional_cleanup() is not None: - self.assertClocksUsed() - - def test_issue251_killing_cross_thread_leaks_list(self): - self._check_issue251() - - def test_issue251_with_cleanup_disabled(self): - greenlet._greenlet.enable_optional_cleanup(False) - try: - self._check_issue251() - finally: - greenlet._greenlet.enable_optional_cleanup(True) - - @fails_leakcheck_except_on_free_thraded - def test_issue251_issue252_need_to_collect_in_background(self): - # Between greenlet 1.1.2 and the next version, this was still - # failing because the leak of the list still exists when we - # don't call a greenlet API before exiting the thread. The - # proximate cause is that neither of the two greenlets from - # the background thread are actually being destroyed, even - # though the GC is in fact visiting both objects. It's not - # clear where that leak is? For some reason the thread-local - # dict holding it isn't being cleaned up. - # - # The leak, I think, is in the CPYthon internal function that - # calls into green_switch(). The argument tuple is still on - # the C stack somewhere and can't be reached? That doesn't - # make sense, because the tuple should be collectable when - # this object goes away. - # - # Note that this test sometimes spuriously passes on Linux, - # for some reason, but I've never seen it pass on macOS. - self._check_issue251(manually_collect_background=False) - - @fails_leakcheck_except_on_free_thraded - def test_issue251_issue252_need_to_collect_in_background_cleanup_disabled(self): - self.expect_greenlet_leak = True - greenlet._greenlet.enable_optional_cleanup(False) - try: - self._check_issue251(manually_collect_background=False) - finally: - greenlet._greenlet.enable_optional_cleanup(True) - - @fails_leakcheck_except_on_free_thraded - def test_issue251_issue252_explicit_reference_not_collectable(self): - self._check_issue251( - manually_collect_background=False, - explicit_reference_to_switch=True) - - UNTRACK_ATTEMPTS = 100 - - def _only_test_some_versions(self): - # We're only looking for this problem specifically on 3.11, - # and this set of tests is relatively fragile, depending on - # OS and memory management details. So we want to run it on 3.11+ - # (obviously) but not every older 3.x version in order to reduce - # false negatives. At the moment, those false results seem to have - # resolved, so we are actually running this on 3.8+ - assert sys.version_info[0] >= 3 - if sys.version_info[:2] < (3, 8): - self.skipTest('Only observed on 3.11') - if RUNNING_ON_MANYLINUX: - self.skipTest("Slow and not worth repeating here") - - @ignores_leakcheck - # Because we're just trying to track raw memory, not objects, and running - # the leakcheck makes an already slow test slower. - def test_untracked_memory_doesnt_increase(self): - # See https://github.com/gevent/gevent/issues/1924 - # and https://github.com/python-greenlet/greenlet/issues/328 - self._only_test_some_versions() - def f(): - return 1 - - ITER = 10000 - def run_it(): - for _ in range(ITER): - greenlet.greenlet(f).switch() - - # Establish baseline - for _ in range(3): - run_it() - - # uss: (Linux, macOS, Windows): aka "Unique Set Size", this is - # the memory which is unique to a process and which would be - # freed if the process was terminated right now. - uss_before = self.get_process_uss() - - for count in range(self.UNTRACK_ATTEMPTS): - uss_before = max(uss_before, self.get_process_uss()) - run_it() - - uss_after = self.get_process_uss() - if uss_after <= uss_before and count > 1: - break - - self.assertLessEqual(uss_after, uss_before) - - def _check_untracked_memory_thread(self, deallocate_in_thread=True): - self._only_test_some_versions() - # Like the above test, but what if there are a bunch of - # unfinished greenlets in a thread that dies? - # Does it matter if we deallocate in the thread or not? - EXIT_COUNT = [0] - - def f(): - try: - greenlet.getcurrent().parent.switch() - except greenlet.GreenletExit: - EXIT_COUNT[0] += 1 - raise - return 1 - - ITER = 10000 - def run_it(): - glets = [] - for _ in range(ITER): - # Greenlet starts, switches back to us. - # We keep a strong reference to the greenlet though so it doesn't - # get a GreenletExit exception. - g = greenlet.greenlet(f) - glets.append(g) - g.switch() - - return glets - - test = self - - class ThreadFunc: - uss_before = uss_after = 0 - glets = () - ITER = 2 - def __call__(self): - self.uss_before = test.get_process_uss() - - for _ in range(self.ITER): - self.glets += tuple(run_it()) - - for g in self.glets: - test.assertIn('suspended active', str(g)) - # Drop them. - if deallocate_in_thread: - self.glets = () - self.uss_after = test.get_process_uss() - - # Establish baseline - uss_before = uss_after = None - for count in range(self.UNTRACK_ATTEMPTS): - EXIT_COUNT[0] = 0 - thread_func = ThreadFunc() - t = threading.Thread(target=thread_func) - t.start() - t.join(30) - self.assertFalse(t.is_alive()) - - if uss_before is None: - uss_before = thread_func.uss_before - - uss_before = max(uss_before, thread_func.uss_before) - if deallocate_in_thread: - self.assertEqual(thread_func.glets, ()) - self.assertEqual(EXIT_COUNT[0], ITER * thread_func.ITER) - - del thread_func # Deallocate the greenlets; but this won't raise into them - del t - if not deallocate_in_thread: - self.assertEqual(EXIT_COUNT[0], 0) - if deallocate_in_thread: - self.wait_for_pending_cleanups() - - uss_after = self.get_process_uss() - # See if we achieve a non-growth state at some point. Break when we do. - if uss_after <= uss_before and count > 1: - break - - self.wait_for_pending_cleanups() - uss_after = self.get_process_uss() - self.assertLessEqual(uss_after, uss_before, "after attempts %d" % (count,)) - - @ignores_leakcheck - # Because we're just trying to track raw memory, not objects, and running - # the leakcheck makes an already slow test slower. - def test_untracked_memory_doesnt_increase_unfinished_thread_dealloc_in_thread(self): - self._check_untracked_memory_thread(deallocate_in_thread=True) - - @ignores_leakcheck - # Because the main greenlets from the background threads do not exit in a timely fashion, - # we fail the object-based leakchecks. - def test_untracked_memory_doesnt_increase_unfinished_thread_dealloc_in_main(self): - self._check_untracked_memory_thread(deallocate_in_thread=False) - -if __name__ == '__main__': - __import__('unittest').main() diff --git a/venv/lib/python3.9/site-packages/greenlet/tests/test_stack_saved.py b/venv/lib/python3.9/site-packages/greenlet/tests/test_stack_saved.py deleted file mode 100644 index b362bf9..0000000 --- a/venv/lib/python3.9/site-packages/greenlet/tests/test_stack_saved.py +++ /dev/null @@ -1,19 +0,0 @@ -import greenlet -from . import TestCase - - -class Test(TestCase): - - def test_stack_saved(self): - main = greenlet.getcurrent() - self.assertEqual(main._stack_saved, 0) - - def func(): - main.switch(main._stack_saved) - - g = greenlet.greenlet(func) - x = g.switch() - self.assertGreater(x, 0) - self.assertGreater(g._stack_saved, 0) - g.switch() - self.assertEqual(g._stack_saved, 0) diff --git a/venv/lib/python3.9/site-packages/greenlet/tests/test_throw.py b/venv/lib/python3.9/site-packages/greenlet/tests/test_throw.py deleted file mode 100644 index f4f9a14..0000000 --- a/venv/lib/python3.9/site-packages/greenlet/tests/test_throw.py +++ /dev/null @@ -1,128 +0,0 @@ -import sys - - -from greenlet import greenlet -from . import TestCase - -def switch(*args): - return greenlet.getcurrent().parent.switch(*args) - - -class ThrowTests(TestCase): - def test_class(self): - def f(): - try: - switch("ok") - except RuntimeError: - switch("ok") - return - switch("fail") - g = greenlet(f) - res = g.switch() - self.assertEqual(res, "ok") - res = g.throw(RuntimeError) - self.assertEqual(res, "ok") - - def test_val(self): - def f(): - try: - switch("ok") - except RuntimeError: - val = sys.exc_info()[1] - if str(val) == "ciao": - switch("ok") - return - switch("fail") - - g = greenlet(f) - res = g.switch() - self.assertEqual(res, "ok") - res = g.throw(RuntimeError("ciao")) - self.assertEqual(res, "ok") - - g = greenlet(f) - res = g.switch() - self.assertEqual(res, "ok") - res = g.throw(RuntimeError, "ciao") - self.assertEqual(res, "ok") - - def test_kill(self): - def f(): - switch("ok") - switch("fail") - g = greenlet(f) - res = g.switch() - self.assertEqual(res, "ok") - res = g.throw() - self.assertTrue(isinstance(res, greenlet.GreenletExit)) - self.assertTrue(g.dead) - res = g.throw() # immediately eaten by the already-dead greenlet - self.assertTrue(isinstance(res, greenlet.GreenletExit)) - - def test_throw_goes_to_original_parent(self): - main = greenlet.getcurrent() - - def f1(): - try: - main.switch("f1 ready to catch") - except IndexError: - return "caught" - return "normal exit" - - def f2(): - main.switch("from f2") - - g1 = greenlet(f1) - g2 = greenlet(f2, parent=g1) - with self.assertRaises(IndexError): - g2.throw(IndexError) - self.assertTrue(g2.dead) - self.assertTrue(g1.dead) - - g1 = greenlet(f1) - g2 = greenlet(f2, parent=g1) - res = g1.switch() - self.assertEqual(res, "f1 ready to catch") - res = g2.throw(IndexError) - self.assertEqual(res, "caught") - self.assertTrue(g2.dead) - self.assertTrue(g1.dead) - - g1 = greenlet(f1) - g2 = greenlet(f2, parent=g1) - res = g1.switch() - self.assertEqual(res, "f1 ready to catch") - res = g2.switch() - self.assertEqual(res, "from f2") - res = g2.throw(IndexError) - self.assertEqual(res, "caught") - self.assertTrue(g2.dead) - self.assertTrue(g1.dead) - - def test_non_traceback_param(self): - with self.assertRaises(TypeError) as exc: - greenlet.getcurrent().throw( - Exception, - Exception(), - self - ) - self.assertEqual(str(exc.exception), - "throw() third argument must be a traceback object") - - def test_instance_of_wrong_type(self): - with self.assertRaises(TypeError) as exc: - greenlet.getcurrent().throw( - Exception(), - BaseException() - ) - - self.assertEqual(str(exc.exception), - "instance exception may not have a separate value") - - def test_not_throwable(self): - with self.assertRaises(TypeError) as exc: - greenlet.getcurrent().throw( - "abc" - ) - self.assertEqual(str(exc.exception), - "exceptions must be classes, or instances, not str") diff --git a/venv/lib/python3.9/site-packages/greenlet/tests/test_tracing.py b/venv/lib/python3.9/site-packages/greenlet/tests/test_tracing.py deleted file mode 100644 index 235fbcd..0000000 --- a/venv/lib/python3.9/site-packages/greenlet/tests/test_tracing.py +++ /dev/null @@ -1,299 +0,0 @@ -from __future__ import print_function -import sys -import sysconfig -import greenlet -import unittest - -from . import TestCase -from . import PY312 - -# https://discuss.python.org/t/cpython-3-12-greenlet-and-tracing-profiling-how-to-not-crash-and-get-correct-results/33144/2 -# When build variables are available, OPT is the best way of detecting -# the build with assertions enabled. Otherwise, fallback to detecting PyDEBUG -# build. -ASSERTION_BUILD_PY312 = ( - PY312 and ( - "-DNDEBUG" not in sysconfig.get_config_var("OPT").split() - if sysconfig.get_config_var("OPT") is not None - else hasattr(sys, 'gettotalrefcount') - ), - "Broken on assertion-enabled builds of Python 3.12" -) - -class SomeError(Exception): - pass - -class GreenletTracer(object): - oldtrace = None - - def __init__(self, error_on_trace=False): - self.actions = [] - self.error_on_trace = error_on_trace - - def __call__(self, *args): - self.actions.append(args) - if self.error_on_trace: - raise SomeError - - def __enter__(self): - self.oldtrace = greenlet.settrace(self) - return self.actions - - def __exit__(self, *args): - greenlet.settrace(self.oldtrace) - - -class TestGreenletTracing(TestCase): - """ - Tests of ``greenlet.settrace()`` - """ - - def test_a_greenlet_tracing(self): - main = greenlet.getcurrent() - def dummy(): - pass - def dummyexc(): - raise SomeError() - - with GreenletTracer() as actions: - g1 = greenlet.greenlet(dummy) - g1.switch() - g2 = greenlet.greenlet(dummyexc) - self.assertRaises(SomeError, g2.switch) - - self.assertEqual(actions, [ - ('switch', (main, g1)), - ('switch', (g1, main)), - ('switch', (main, g2)), - ('throw', (g2, main)), - ]) - - def test_b_exception_disables_tracing(self): - main = greenlet.getcurrent() - def dummy(): - main.switch() - g = greenlet.greenlet(dummy) - g.switch() - with GreenletTracer(error_on_trace=True) as actions: - self.assertRaises(SomeError, g.switch) - self.assertEqual(greenlet.gettrace(), None) - - self.assertEqual(actions, [ - ('switch', (main, g)), - ]) - - def test_set_same_tracer_twice(self): - # https://github.com/python-greenlet/greenlet/issues/332 - # Our logic in asserting that the tracefunction should - # gain a reference was incorrect if the same tracefunction was set - # twice. - tracer = GreenletTracer() - with tracer: - greenlet.settrace(tracer) - - -class PythonTracer(object): - oldtrace = None - - def __init__(self): - self.actions = [] - - def __call__(self, frame, event, arg): - # Record the co_name so we have an idea what function we're in. - self.actions.append((event, frame.f_code.co_name)) - - def __enter__(self): - self.oldtrace = sys.setprofile(self) - return self.actions - - def __exit__(self, *args): - sys.setprofile(self.oldtrace) - -def tpt_callback(): - return 42 - -class TestPythonTracing(TestCase): - """ - Tests of the interaction of ``sys.settrace()`` - with greenlet facilities. - - NOTE: Most of this is probably CPython specific. - """ - - maxDiff = None - - def test_trace_events_trivial(self): - with PythonTracer() as actions: - tpt_callback() - # If we use the sys.settrace instead of setprofile, we get - # this: - - # self.assertEqual(actions, [ - # ('call', 'tpt_callback'), - # ('call', '__exit__'), - # ]) - - self.assertEqual(actions, [ - ('return', '__enter__'), - ('call', 'tpt_callback'), - ('return', 'tpt_callback'), - ('call', '__exit__'), - ('c_call', '__exit__'), - ]) - - def _trace_switch(self, glet): - with PythonTracer() as actions: - glet.switch() - return actions - - def _check_trace_events_func_already_set(self, glet): - actions = self._trace_switch(glet) - self.assertEqual(actions, [ - ('return', '__enter__'), - ('c_call', '_trace_switch'), - ('call', 'run'), - ('call', 'tpt_callback'), - ('return', 'tpt_callback'), - ('return', 'run'), - ('c_return', '_trace_switch'), - ('call', '__exit__'), - ('c_call', '__exit__'), - ]) - - def test_trace_events_into_greenlet_func_already_set(self): - def run(): - return tpt_callback() - - self._check_trace_events_func_already_set(greenlet.greenlet(run)) - - def test_trace_events_into_greenlet_subclass_already_set(self): - class X(greenlet.greenlet): - def run(self): - return tpt_callback() - self._check_trace_events_func_already_set(X()) - - def _check_trace_events_from_greenlet_sets_profiler(self, g, tracer): - g.switch() - tpt_callback() - tracer.__exit__() - self.assertEqual(tracer.actions, [ - ('return', '__enter__'), - ('call', 'tpt_callback'), - ('return', 'tpt_callback'), - ('return', 'run'), - ('call', 'tpt_callback'), - ('return', 'tpt_callback'), - ('call', '__exit__'), - ('c_call', '__exit__'), - ]) - - - def test_trace_events_from_greenlet_func_sets_profiler(self): - tracer = PythonTracer() - def run(): - tracer.__enter__() - return tpt_callback() - - self._check_trace_events_from_greenlet_sets_profiler(greenlet.greenlet(run), - tracer) - - def test_trace_events_from_greenlet_subclass_sets_profiler(self): - tracer = PythonTracer() - class X(greenlet.greenlet): - def run(self): - tracer.__enter__() - return tpt_callback() - - self._check_trace_events_from_greenlet_sets_profiler(X(), tracer) - - @unittest.skipIf(*ASSERTION_BUILD_PY312) - def test_trace_events_multiple_greenlets_switching(self): - tracer = PythonTracer() - - g1 = None - g2 = None - - def g1_run(): - tracer.__enter__() - tpt_callback() - g2.switch() - tpt_callback() - return 42 - - def g2_run(): - tpt_callback() - tracer.__exit__() - tpt_callback() - g1.switch() - - g1 = greenlet.greenlet(g1_run) - g2 = greenlet.greenlet(g2_run) - - x = g1.switch() - self.assertEqual(x, 42) - tpt_callback() # ensure not in the trace - self.assertEqual(tracer.actions, [ - ('return', '__enter__'), - ('call', 'tpt_callback'), - ('return', 'tpt_callback'), - ('c_call', 'g1_run'), - ('call', 'g2_run'), - ('call', 'tpt_callback'), - ('return', 'tpt_callback'), - ('call', '__exit__'), - ('c_call', '__exit__'), - ]) - - @unittest.skipIf(*ASSERTION_BUILD_PY312) - def test_trace_events_multiple_greenlets_switching_siblings(self): - # Like the first version, but get both greenlets running first - # as "siblings" and then establish the tracing. - tracer = PythonTracer() - - g1 = None - g2 = None - - def g1_run(): - greenlet.getcurrent().parent.switch() - tracer.__enter__() - tpt_callback() - g2.switch() - tpt_callback() - return 42 - - def g2_run(): - greenlet.getcurrent().parent.switch() - - tpt_callback() - tracer.__exit__() - tpt_callback() - g1.switch() - - g1 = greenlet.greenlet(g1_run) - g2 = greenlet.greenlet(g2_run) - - # Start g1 - g1.switch() - # And it immediately returns control to us. - # Start g2 - g2.switch() - # Which also returns. Now kick of the real part of the - # test. - x = g1.switch() - self.assertEqual(x, 42) - - tpt_callback() # ensure not in the trace - self.assertEqual(tracer.actions, [ - ('return', '__enter__'), - ('call', 'tpt_callback'), - ('return', 'tpt_callback'), - ('c_call', 'g1_run'), - ('call', 'tpt_callback'), - ('return', 'tpt_callback'), - ('call', '__exit__'), - ('c_call', '__exit__'), - ]) - - -if __name__ == '__main__': - unittest.main() diff --git a/venv/lib/python3.9/site-packages/greenlet/tests/test_version.py b/venv/lib/python3.9/site-packages/greenlet/tests/test_version.py deleted file mode 100644 index 96c17cf..0000000 --- a/venv/lib/python3.9/site-packages/greenlet/tests/test_version.py +++ /dev/null @@ -1,41 +0,0 @@ -#! /usr/bin/env python -from __future__ import absolute_import -from __future__ import print_function - -import sys -import os -from unittest import TestCase as NonLeakingTestCase - -import greenlet - -# No reason to run this multiple times under leakchecks, -# it doesn't do anything. -class VersionTests(NonLeakingTestCase): - def test_version(self): - def find_dominating_file(name): - if os.path.exists(name): - return name - - tried = [] - here = os.path.abspath(os.path.dirname(__file__)) - for i in range(10): - up = ['..'] * i - path = [here] + up + [name] - fname = os.path.join(*path) - fname = os.path.abspath(fname) - tried.append(fname) - if os.path.exists(fname): - return fname - raise AssertionError("Could not find file " + name + "; checked " + str(tried)) - - try: - setup_py = find_dominating_file('setup.py') - except AssertionError as e: - self.skipTest("Unable to find setup.py; must be out of tree. " + str(e)) - - - invoke_setup = "%s %s --version" % (sys.executable, setup_py) - with os.popen(invoke_setup) as f: - sversion = f.read().strip() - - self.assertEqual(sversion, greenlet.__version__) diff --git a/venv/lib/python3.9/site-packages/greenlet/tests/test_weakref.py b/venv/lib/python3.9/site-packages/greenlet/tests/test_weakref.py deleted file mode 100644 index 05a38a7..0000000 --- a/venv/lib/python3.9/site-packages/greenlet/tests/test_weakref.py +++ /dev/null @@ -1,35 +0,0 @@ -import gc -import weakref - - -import greenlet -from . import TestCase - -class WeakRefTests(TestCase): - def test_dead_weakref(self): - def _dead_greenlet(): - g = greenlet.greenlet(lambda: None) - g.switch() - return g - o = weakref.ref(_dead_greenlet()) - gc.collect() - self.assertEqual(o(), None) - - def test_inactive_weakref(self): - o = weakref.ref(greenlet.greenlet()) - gc.collect() - self.assertEqual(o(), None) - - def test_dealloc_weakref(self): - seen = [] - def worker(): - try: - greenlet.getcurrent().parent.switch() - finally: - seen.append(g()) - g = greenlet.greenlet(worker) - g.switch() - g2 = greenlet.greenlet(lambda: None, g) - g = weakref.ref(g2) - g2 = None - self.assertEqual(seen, [None]) diff --git a/venv/lib/python3.9/site-packages/gunicorn-23.0.0.dist-info/INSTALLER b/venv/lib/python3.9/site-packages/gunicorn-23.0.0.dist-info/INSTALLER deleted file mode 100644 index a1b589e..0000000 --- a/venv/lib/python3.9/site-packages/gunicorn-23.0.0.dist-info/INSTALLER +++ /dev/null @@ -1 +0,0 @@ -pip diff --git a/venv/lib/python3.9/site-packages/gunicorn-23.0.0.dist-info/LICENSE b/venv/lib/python3.9/site-packages/gunicorn-23.0.0.dist-info/LICENSE deleted file mode 100644 index 0dca6e1..0000000 --- a/venv/lib/python3.9/site-packages/gunicorn-23.0.0.dist-info/LICENSE +++ /dev/null @@ -1,23 +0,0 @@ -2009-2024 (c) Benoît Chesneau -2009-2015 (c) Paul J. Davis - -Permission is hereby granted, free of charge, to any person -obtaining a copy of this software and associated documentation -files (the "Software"), to deal in the Software without -restriction, including without limitation the rights to use, -copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the -Software is furnished to do so, subject to the following -conditions: - -The above copyright notice and this permission notice shall be -included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES -OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT -HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, -WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR -OTHER DEALINGS IN THE SOFTWARE. diff --git a/venv/lib/python3.9/site-packages/gunicorn-23.0.0.dist-info/METADATA b/venv/lib/python3.9/site-packages/gunicorn-23.0.0.dist-info/METADATA deleted file mode 100644 index 550aef2..0000000 --- a/venv/lib/python3.9/site-packages/gunicorn-23.0.0.dist-info/METADATA +++ /dev/null @@ -1,130 +0,0 @@ -Metadata-Version: 2.1 -Name: gunicorn -Version: 23.0.0 -Summary: WSGI HTTP Server for UNIX -Author-email: Benoit Chesneau -License: MIT -Project-URL: Homepage, https://gunicorn.org -Project-URL: Documentation, https://docs.gunicorn.org -Project-URL: Issue tracker, https://github.com/benoitc/gunicorn/issues -Project-URL: Source code, https://github.com/benoitc/gunicorn -Project-URL: Changelog, https://docs.gunicorn.org/en/stable/news.html -Classifier: Development Status :: 5 - Production/Stable -Classifier: Environment :: Other Environment -Classifier: Intended Audience :: Developers -Classifier: License :: OSI Approved :: MIT License -Classifier: Operating System :: MacOS :: MacOS X -Classifier: Operating System :: POSIX -Classifier: Programming Language :: Python -Classifier: Programming Language :: Python :: 3 -Classifier: Programming Language :: Python :: 3.7 -Classifier: Programming Language :: Python :: 3.8 -Classifier: Programming Language :: Python :: 3.9 -Classifier: Programming Language :: Python :: 3.10 -Classifier: Programming Language :: Python :: 3.11 -Classifier: Programming Language :: Python :: 3.12 -Classifier: Programming Language :: Python :: 3 :: Only -Classifier: Programming Language :: Python :: Implementation :: CPython -Classifier: Programming Language :: Python :: Implementation :: PyPy -Classifier: Topic :: Internet -Classifier: Topic :: Utilities -Classifier: Topic :: Software Development :: Libraries :: Python Modules -Classifier: Topic :: Internet :: WWW/HTTP -Classifier: Topic :: Internet :: WWW/HTTP :: WSGI -Classifier: Topic :: Internet :: WWW/HTTP :: WSGI :: Server -Classifier: Topic :: Internet :: WWW/HTTP :: Dynamic Content -Requires-Python: >=3.7 -Description-Content-Type: text/x-rst -License-File: LICENSE -Requires-Dist: packaging -Requires-Dist: importlib-metadata ; python_version < "3.8" -Provides-Extra: eventlet -Requires-Dist: eventlet !=0.36.0,>=0.24.1 ; extra == 'eventlet' -Provides-Extra: gevent -Requires-Dist: gevent >=1.4.0 ; extra == 'gevent' -Provides-Extra: gthread -Provides-Extra: setproctitle -Requires-Dist: setproctitle ; extra == 'setproctitle' -Provides-Extra: testing -Requires-Dist: gevent ; extra == 'testing' -Requires-Dist: eventlet ; extra == 'testing' -Requires-Dist: coverage ; extra == 'testing' -Requires-Dist: pytest ; extra == 'testing' -Requires-Dist: pytest-cov ; extra == 'testing' -Provides-Extra: tornado -Requires-Dist: tornado >=0.2 ; extra == 'tornado' - -Gunicorn --------- - -.. image:: https://img.shields.io/pypi/v/gunicorn.svg?style=flat - :alt: PyPI version - :target: https://pypi.python.org/pypi/gunicorn - -.. image:: https://img.shields.io/pypi/pyversions/gunicorn.svg - :alt: Supported Python versions - :target: https://pypi.python.org/pypi/gunicorn - -.. image:: https://github.com/benoitc/gunicorn/actions/workflows/tox.yml/badge.svg - :alt: Build Status - :target: https://github.com/benoitc/gunicorn/actions/workflows/tox.yml - -.. image:: https://github.com/benoitc/gunicorn/actions/workflows/lint.yml/badge.svg - :alt: Lint Status - :target: https://github.com/benoitc/gunicorn/actions/workflows/lint.yml - -Gunicorn 'Green Unicorn' is a Python WSGI HTTP Server for UNIX. It's a pre-fork -worker model ported from Ruby's Unicorn_ project. The Gunicorn server is broadly -compatible with various web frameworks, simply implemented, light on server -resource usage, and fairly speedy. - -Feel free to join us in `#gunicorn`_ on `Libera.chat`_. - -Documentation -------------- - -The documentation is hosted at https://docs.gunicorn.org. - -Installation ------------- - -Gunicorn requires **Python 3.x >= 3.7**. - -Install from PyPI:: - - $ pip install gunicorn - - -Usage ------ - -Basic usage:: - - $ gunicorn [OPTIONS] APP_MODULE - -Where ``APP_MODULE`` is of the pattern ``$(MODULE_NAME):$(VARIABLE_NAME)``. The -module name can be a full dotted path. The variable name refers to a WSGI -callable that should be found in the specified module. - -Example with test app:: - - $ cd examples - $ gunicorn --workers=2 test:app - - -Contributing ------------- - -See `our complete contributor's guide `_ for more details. - - -License -------- - -Gunicorn is released under the MIT License. See the LICENSE_ file for more -details. - -.. _Unicorn: https://bogomips.org/unicorn/ -.. _`#gunicorn`: https://web.libera.chat/?channels=#gunicorn -.. _`Libera.chat`: https://libera.chat/ -.. _LICENSE: https://github.com/benoitc/gunicorn/blob/master/LICENSE diff --git a/venv/lib/python3.9/site-packages/gunicorn-23.0.0.dist-info/RECORD b/venv/lib/python3.9/site-packages/gunicorn-23.0.0.dist-info/RECORD deleted file mode 100644 index 5dd55f0..0000000 --- a/venv/lib/python3.9/site-packages/gunicorn-23.0.0.dist-info/RECORD +++ /dev/null @@ -1,77 +0,0 @@ -../../../bin/gunicorn,sha256=Y_Y_DHRcCqfGG6_8Q6u7Ac17AiEhpiMpIgn9ziO5GHw,191 -gunicorn-23.0.0.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 -gunicorn-23.0.0.dist-info/LICENSE,sha256=ZkbNu6LpnjQh3RjCIXNXmh_eNH6DHa5q3ugO7-Mx6VE,1136 -gunicorn-23.0.0.dist-info/METADATA,sha256=KhY-mRcAcWCLIbXIHihsUNKWB5fGDOrsbq-JKQTBHY4,4421 -gunicorn-23.0.0.dist-info/RECORD,, -gunicorn-23.0.0.dist-info/REQUESTED,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 -gunicorn-23.0.0.dist-info/WHEEL,sha256=R0nc6qTxuoLk7ShA2_Y-UWkN8ZdfDBG2B6Eqpz2WXbs,91 -gunicorn-23.0.0.dist-info/entry_points.txt,sha256=bF8VNiG4H8W83JfEBcqcPMydv9hl04CS4kwh1KOYrFY,113 -gunicorn-23.0.0.dist-info/top_level.txt,sha256=cdMaa2yhxb8do-WioY9qRHUCfwf55YztjwQCncaInoE,9 -gunicorn/__init__.py,sha256=NaLW_JTiKLgqMXipjqzxFn-1wdiptlO2WxOB_KKwx94,257 -gunicorn/__main__.py,sha256=tviepyuwKyB6SPV28t2eZy_5PcCpT56z7QZjzbMpkQw,338 -gunicorn/__pycache__/__init__.cpython-39.pyc,, -gunicorn/__pycache__/__main__.cpython-39.pyc,, -gunicorn/__pycache__/arbiter.cpython-39.pyc,, -gunicorn/__pycache__/config.cpython-39.pyc,, -gunicorn/__pycache__/debug.cpython-39.pyc,, -gunicorn/__pycache__/errors.cpython-39.pyc,, -gunicorn/__pycache__/glogging.cpython-39.pyc,, -gunicorn/__pycache__/pidfile.cpython-39.pyc,, -gunicorn/__pycache__/reloader.cpython-39.pyc,, -gunicorn/__pycache__/sock.cpython-39.pyc,, -gunicorn/__pycache__/systemd.cpython-39.pyc,, -gunicorn/__pycache__/util.cpython-39.pyc,, -gunicorn/app/__init__.py,sha256=8m9lIbhRssnbGuBeQUA-vNSNbMeNju9Q_PUnnNfqOYU,105 -gunicorn/app/__pycache__/__init__.cpython-39.pyc,, -gunicorn/app/__pycache__/base.cpython-39.pyc,, -gunicorn/app/__pycache__/pasterapp.cpython-39.pyc,, -gunicorn/app/__pycache__/wsgiapp.cpython-39.pyc,, -gunicorn/app/base.py,sha256=KV2aIO50JTlakHL82q9zu3LhCJrDmUmaViwSy14Gk6U,7370 -gunicorn/app/pasterapp.py,sha256=BIa0mz_J86NuObUw2UIyjLYKUm8V3b034pJrTkvF-sA,2016 -gunicorn/app/wsgiapp.py,sha256=gVBgUc_3uSK0QzXYQ1XbutacEGjf44CgxAaYkgwfucY,1924 -gunicorn/arbiter.py,sha256=xcHpv8bsrYpIpu9q7YK4ue11f9kmz80dr7BUwKX3oxk,21470 -gunicorn/config.py,sha256=t3BChwMoBZwfV05Iy_n3oh232xvi1SORkOJfHFL_c-8,70318 -gunicorn/debug.py,sha256=c8cQv_g3d22JE6A4hv7FNmMhm4wq6iB_E-toorpqJcw,2263 -gunicorn/errors.py,sha256=iLTJQC4SVSRoygIGGHXvEp0d8UdzpeqmMRqUcF0JI14,897 -gunicorn/glogging.py,sha256=76MlUUc82FqdeD3R4qC8NeUHt8vxa3IBSxmeBtbZKtE,15273 -gunicorn/http/__init__.py,sha256=1k_WWvjT9eDDRDOutzXCebvYKm_qzaQA3GuLk0VkbJI,255 -gunicorn/http/__pycache__/__init__.cpython-39.pyc,, -gunicorn/http/__pycache__/body.cpython-39.pyc,, -gunicorn/http/__pycache__/errors.cpython-39.pyc,, -gunicorn/http/__pycache__/message.cpython-39.pyc,, -gunicorn/http/__pycache__/parser.cpython-39.pyc,, -gunicorn/http/__pycache__/unreader.cpython-39.pyc,, -gunicorn/http/__pycache__/wsgi.cpython-39.pyc,, -gunicorn/http/body.py,sha256=sQgp_hJUjx8DK6LYzklMTl-xKcX8efsbreCKzowCGmo,7600 -gunicorn/http/errors.py,sha256=6tcG9pCvRiooXpfudQBILzUPx3ertuQ5utjZeUNMUqA,3437 -gunicorn/http/message.py,sha256=ok4xnqWhntIn21gcPa1KYZWRYTbwsECpot-Eac47qFs,17632 -gunicorn/http/parser.py,sha256=wayoAFjQYERSwE4YGwI2AYSNGZ2eTNbGUtoqqQFph5U,1334 -gunicorn/http/unreader.py,sha256=D7bluz62A1aLZQ9XbpX0-nDBal9KPtp_pjokk2YNY8E,1913 -gunicorn/http/wsgi.py,sha256=x-zTT7gvRF4wipmvoVePz1qO407JZCU_sNU8yjcl_R4,12811 -gunicorn/instrument/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 -gunicorn/instrument/__pycache__/__init__.cpython-39.pyc,, -gunicorn/instrument/__pycache__/statsd.cpython-39.pyc,, -gunicorn/instrument/statsd.py,sha256=ghmaniNEjMMLvvdQkDPpB_u9a8z4FBfWUE_C9O1KIYQ,4750 -gunicorn/pidfile.py,sha256=HntiveG8eJmwB8_D3o5cBXRuGKnC0cvWxg90MWh1hUc,2327 -gunicorn/reloader.py,sha256=oDuK2PWGyIMm0_vc1y196Z1EggOvBi-Iz_2UbRY7PsQ,3761 -gunicorn/sock.py,sha256=VVF2eeoxQEJ2OEoZoek3BFZTqj7wXvQql7jpdFAjVTI,6834 -gunicorn/systemd.py,sha256=DmWbcqeRyHdAIy70UCEg2J93v6PpESp3EFTNm0Djgyg,2498 -gunicorn/util.py,sha256=YqC4E3RxhFNH-W4LOqy1RtxcHRy9hRyYND92ZSNXEwc,19095 -gunicorn/workers/__init__.py,sha256=Y0Z6WhXKY6PuTbFkOkeEBzIfhDDg5FeqVg8aJp6lIZA,572 -gunicorn/workers/__pycache__/__init__.cpython-39.pyc,, -gunicorn/workers/__pycache__/base.cpython-39.pyc,, -gunicorn/workers/__pycache__/base_async.cpython-39.pyc,, -gunicorn/workers/__pycache__/geventlet.cpython-39.pyc,, -gunicorn/workers/__pycache__/ggevent.cpython-39.pyc,, -gunicorn/workers/__pycache__/gthread.cpython-39.pyc,, -gunicorn/workers/__pycache__/gtornado.cpython-39.pyc,, -gunicorn/workers/__pycache__/sync.cpython-39.pyc,, -gunicorn/workers/__pycache__/workertmp.cpython-39.pyc,, -gunicorn/workers/base.py,sha256=eM9MTLP9PdWL0Pm5V5byyBli-r8zF2MSEGjefr3y92M,9763 -gunicorn/workers/base_async.py,sha256=Oc-rSV81uHqvEqww2PM6tz75qNR07ChuqM6IkTOpzlk,5627 -gunicorn/workers/geventlet.py,sha256=s_I-gKYgDJnlAHdCxN_wfglODnDE1eJaZJZCJyNYg-4,6069 -gunicorn/workers/ggevent.py,sha256=OEhj-bFVBGQ-jbjr5S3gSvixJTa-YOQYht7fYTOCyt4,6030 -gunicorn/workers/gthread.py,sha256=moycCQoJS602u3U7gZEooYxqRP86Tq5bmQnipL4a4_c,12500 -gunicorn/workers/gtornado.py,sha256=zCHbxs5JeE9rtZa5mXlhftBlNlwp_tBWXuTQwqgv1so,5811 -gunicorn/workers/sync.py,sha256=mOY84VHbAx62lmo2DLuifkK9d6anEgvC7LAuYVJyRM4,7204 -gunicorn/workers/workertmp.py,sha256=bswGosCIDb_wBfdGaFqHopgxbmJ6rgVXYlVhJDWZKIc,1604 diff --git a/venv/lib/python3.9/site-packages/gunicorn-23.0.0.dist-info/REQUESTED b/venv/lib/python3.9/site-packages/gunicorn-23.0.0.dist-info/REQUESTED deleted file mode 100644 index e69de29..0000000 diff --git a/venv/lib/python3.9/site-packages/gunicorn-23.0.0.dist-info/WHEEL b/venv/lib/python3.9/site-packages/gunicorn-23.0.0.dist-info/WHEEL deleted file mode 100644 index 1a9c535..0000000 --- a/venv/lib/python3.9/site-packages/gunicorn-23.0.0.dist-info/WHEEL +++ /dev/null @@ -1,5 +0,0 @@ -Wheel-Version: 1.0 -Generator: setuptools (72.1.0) -Root-Is-Purelib: true -Tag: py3-none-any - diff --git a/venv/lib/python3.9/site-packages/gunicorn-23.0.0.dist-info/entry_points.txt b/venv/lib/python3.9/site-packages/gunicorn-23.0.0.dist-info/entry_points.txt deleted file mode 100644 index fd14749..0000000 --- a/venv/lib/python3.9/site-packages/gunicorn-23.0.0.dist-info/entry_points.txt +++ /dev/null @@ -1,5 +0,0 @@ -[console_scripts] -gunicorn = gunicorn.app.wsgiapp:run - -[paste.server_runner] -main = gunicorn.app.pasterapp:serve diff --git a/venv/lib/python3.9/site-packages/gunicorn-23.0.0.dist-info/top_level.txt b/venv/lib/python3.9/site-packages/gunicorn-23.0.0.dist-info/top_level.txt deleted file mode 100644 index 8f22dcc..0000000 --- a/venv/lib/python3.9/site-packages/gunicorn-23.0.0.dist-info/top_level.txt +++ /dev/null @@ -1 +0,0 @@ -gunicorn diff --git a/venv/lib/python3.9/site-packages/gunicorn/__init__.py b/venv/lib/python3.9/site-packages/gunicorn/__init__.py deleted file mode 100644 index cdcd135..0000000 --- a/venv/lib/python3.9/site-packages/gunicorn/__init__.py +++ /dev/null @@ -1,8 +0,0 @@ -# -# This file is part of gunicorn released under the MIT license. -# See the NOTICE for more information. - -version_info = (23, 0, 0) -__version__ = ".".join([str(v) for v in version_info]) -SERVER = "gunicorn" -SERVER_SOFTWARE = "%s/%s" % (SERVER, __version__) diff --git a/venv/lib/python3.9/site-packages/gunicorn/__main__.py b/venv/lib/python3.9/site-packages/gunicorn/__main__.py deleted file mode 100644 index ceb44d0..0000000 --- a/venv/lib/python3.9/site-packages/gunicorn/__main__.py +++ /dev/null @@ -1,10 +0,0 @@ -# -# This file is part of gunicorn released under the MIT license. -# See the NOTICE for more information. - -from gunicorn.app.wsgiapp import run - -if __name__ == "__main__": - # see config.py - argparse defaults to basename(argv[0]) == "__main__.py" - # todo: let runpy.run_module take care of argv[0] rewriting - run(prog="gunicorn") diff --git a/venv/lib/python3.9/site-packages/gunicorn/app/__init__.py b/venv/lib/python3.9/site-packages/gunicorn/app/__init__.py deleted file mode 100644 index 530e35c..0000000 --- a/venv/lib/python3.9/site-packages/gunicorn/app/__init__.py +++ /dev/null @@ -1,3 +0,0 @@ -# -# This file is part of gunicorn released under the MIT license. -# See the NOTICE for more information. diff --git a/venv/lib/python3.9/site-packages/gunicorn/app/base.py b/venv/lib/python3.9/site-packages/gunicorn/app/base.py deleted file mode 100644 index 9bf7a4f..0000000 --- a/venv/lib/python3.9/site-packages/gunicorn/app/base.py +++ /dev/null @@ -1,235 +0,0 @@ -# -# This file is part of gunicorn released under the MIT license. -# See the NOTICE for more information. -import importlib.util -import importlib.machinery -import os -import sys -import traceback - -from gunicorn import util -from gunicorn.arbiter import Arbiter -from gunicorn.config import Config, get_default_config_file -from gunicorn import debug - - -class BaseApplication: - """ - An application interface for configuring and loading - the various necessities for any given web framework. - """ - def __init__(self, usage=None, prog=None): - self.usage = usage - self.cfg = None - self.callable = None - self.prog = prog - self.logger = None - self.do_load_config() - - def do_load_config(self): - """ - Loads the configuration - """ - try: - self.load_default_config() - self.load_config() - except Exception as e: - print("\nError: %s" % str(e), file=sys.stderr) - sys.stderr.flush() - sys.exit(1) - - def load_default_config(self): - # init configuration - self.cfg = Config(self.usage, prog=self.prog) - - def init(self, parser, opts, args): - raise NotImplementedError - - def load(self): - raise NotImplementedError - - def load_config(self): - """ - This method is used to load the configuration from one or several input(s). - Custom Command line, configuration file. - You have to override this method in your class. - """ - raise NotImplementedError - - def reload(self): - self.do_load_config() - if self.cfg.spew: - debug.spew() - - def wsgi(self): - if self.callable is None: - self.callable = self.load() - return self.callable - - def run(self): - try: - Arbiter(self).run() - except RuntimeError as e: - print("\nError: %s\n" % e, file=sys.stderr) - sys.stderr.flush() - sys.exit(1) - - -class Application(BaseApplication): - - # 'init' and 'load' methods are implemented by WSGIApplication. - # pylint: disable=abstract-method - - def chdir(self): - # chdir to the configured path before loading, - # default is the current dir - os.chdir(self.cfg.chdir) - - # add the path to sys.path - if self.cfg.chdir not in sys.path: - sys.path.insert(0, self.cfg.chdir) - - def get_config_from_filename(self, filename): - - if not os.path.exists(filename): - raise RuntimeError("%r doesn't exist" % filename) - - ext = os.path.splitext(filename)[1] - - try: - module_name = '__config__' - if ext in [".py", ".pyc"]: - spec = importlib.util.spec_from_file_location(module_name, filename) - else: - msg = "configuration file should have a valid Python extension.\n" - util.warn(msg) - loader_ = importlib.machinery.SourceFileLoader(module_name, filename) - spec = importlib.util.spec_from_file_location(module_name, filename, loader=loader_) - mod = importlib.util.module_from_spec(spec) - sys.modules[module_name] = mod - spec.loader.exec_module(mod) - except Exception: - print("Failed to read config file: %s" % filename, file=sys.stderr) - traceback.print_exc() - sys.stderr.flush() - sys.exit(1) - - return vars(mod) - - def get_config_from_module_name(self, module_name): - return vars(importlib.import_module(module_name)) - - def load_config_from_module_name_or_filename(self, location): - """ - Loads the configuration file: the file is a python file, otherwise raise an RuntimeError - Exception or stop the process if the configuration file contains a syntax error. - """ - - if location.startswith("python:"): - module_name = location[len("python:"):] - cfg = self.get_config_from_module_name(module_name) - else: - if location.startswith("file:"): - filename = location[len("file:"):] - else: - filename = location - cfg = self.get_config_from_filename(filename) - - for k, v in cfg.items(): - # Ignore unknown names - if k not in self.cfg.settings: - continue - try: - self.cfg.set(k.lower(), v) - except Exception: - print("Invalid value for %s: %s\n" % (k, v), file=sys.stderr) - sys.stderr.flush() - raise - - return cfg - - def load_config_from_file(self, filename): - return self.load_config_from_module_name_or_filename(location=filename) - - def load_config(self): - # parse console args - parser = self.cfg.parser() - args = parser.parse_args() - - # optional settings from apps - cfg = self.init(parser, args, args.args) - - # set up import paths and follow symlinks - self.chdir() - - # Load up the any app specific configuration - if cfg: - for k, v in cfg.items(): - self.cfg.set(k.lower(), v) - - env_args = parser.parse_args(self.cfg.get_cmd_args_from_env()) - - if args.config: - self.load_config_from_file(args.config) - elif env_args.config: - self.load_config_from_file(env_args.config) - else: - default_config = get_default_config_file() - if default_config is not None: - self.load_config_from_file(default_config) - - # Load up environment configuration - for k, v in vars(env_args).items(): - if v is None: - continue - if k == "args": - continue - self.cfg.set(k.lower(), v) - - # Lastly, update the configuration with any command line settings. - for k, v in vars(args).items(): - if v is None: - continue - if k == "args": - continue - self.cfg.set(k.lower(), v) - - # current directory might be changed by the config now - # set up import paths and follow symlinks - self.chdir() - - def run(self): - if self.cfg.print_config: - print(self.cfg) - - if self.cfg.print_config or self.cfg.check_config: - try: - self.load() - except Exception: - msg = "\nError while loading the application:\n" - print(msg, file=sys.stderr) - traceback.print_exc() - sys.stderr.flush() - sys.exit(1) - sys.exit(0) - - if self.cfg.spew: - debug.spew() - - if self.cfg.daemon: - if os.environ.get('NOTIFY_SOCKET'): - msg = "Warning: you shouldn't specify `daemon = True`" \ - " when launching by systemd with `Type = notify`" - print(msg, file=sys.stderr, flush=True) - - util.daemonize(self.cfg.enable_stdio_inheritance) - - # set python paths - if self.cfg.pythonpath: - paths = self.cfg.pythonpath.split(",") - for path in paths: - pythonpath = os.path.abspath(path) - if pythonpath not in sys.path: - sys.path.insert(0, pythonpath) - - super().run() diff --git a/venv/lib/python3.9/site-packages/gunicorn/app/pasterapp.py b/venv/lib/python3.9/site-packages/gunicorn/app/pasterapp.py deleted file mode 100644 index b1738f2..0000000 --- a/venv/lib/python3.9/site-packages/gunicorn/app/pasterapp.py +++ /dev/null @@ -1,74 +0,0 @@ -# -# This file is part of gunicorn released under the MIT license. -# See the NOTICE for more information. - -import configparser -import os - -from paste.deploy import loadapp - -from gunicorn.app.wsgiapp import WSGIApplication -from gunicorn.config import get_default_config_file - - -def get_wsgi_app(config_uri, name=None, defaults=None): - if ':' not in config_uri: - config_uri = "config:%s" % config_uri - - return loadapp( - config_uri, - name=name, - relative_to=os.getcwd(), - global_conf=defaults, - ) - - -def has_logging_config(config_file): - parser = configparser.ConfigParser() - parser.read([config_file]) - return parser.has_section('loggers') - - -def serve(app, global_conf, **local_conf): - """\ - A Paste Deployment server runner. - - Example configuration: - - [server:main] - use = egg:gunicorn#main - host = 127.0.0.1 - port = 5000 - """ - config_file = global_conf['__file__'] - gunicorn_config_file = local_conf.pop('config', None) - - host = local_conf.pop('host', '') - port = local_conf.pop('port', '') - if host and port: - local_conf['bind'] = '%s:%s' % (host, port) - elif host: - local_conf['bind'] = host.split(',') - - class PasterServerApplication(WSGIApplication): - def load_config(self): - self.cfg.set("default_proc_name", config_file) - - if has_logging_config(config_file): - self.cfg.set("logconfig", config_file) - - if gunicorn_config_file: - self.load_config_from_file(gunicorn_config_file) - else: - default_gunicorn_config_file = get_default_config_file() - if default_gunicorn_config_file is not None: - self.load_config_from_file(default_gunicorn_config_file) - - for k, v in local_conf.items(): - if v is not None: - self.cfg.set(k.lower(), v) - - def load(self): - return app - - PasterServerApplication().run() diff --git a/venv/lib/python3.9/site-packages/gunicorn/app/wsgiapp.py b/venv/lib/python3.9/site-packages/gunicorn/app/wsgiapp.py deleted file mode 100644 index 1b0ba96..0000000 --- a/venv/lib/python3.9/site-packages/gunicorn/app/wsgiapp.py +++ /dev/null @@ -1,70 +0,0 @@ -# -# This file is part of gunicorn released under the MIT license. -# See the NOTICE for more information. - -import os - -from gunicorn.errors import ConfigError -from gunicorn.app.base import Application -from gunicorn import util - - -class WSGIApplication(Application): - def init(self, parser, opts, args): - self.app_uri = None - - if opts.paste: - from .pasterapp import has_logging_config - - config_uri = os.path.abspath(opts.paste) - config_file = config_uri.split('#')[0] - - if not os.path.exists(config_file): - raise ConfigError("%r not found" % config_file) - - self.cfg.set("default_proc_name", config_file) - self.app_uri = config_uri - - if has_logging_config(config_file): - self.cfg.set("logconfig", config_file) - - return - - if len(args) > 0: - self.cfg.set("default_proc_name", args[0]) - self.app_uri = args[0] - - def load_config(self): - super().load_config() - - if self.app_uri is None: - if self.cfg.wsgi_app is not None: - self.app_uri = self.cfg.wsgi_app - else: - raise ConfigError("No application module specified.") - - def load_wsgiapp(self): - return util.import_app(self.app_uri) - - def load_pasteapp(self): - from .pasterapp import get_wsgi_app - return get_wsgi_app(self.app_uri, defaults=self.cfg.paste_global_conf) - - def load(self): - if self.cfg.paste is not None: - return self.load_pasteapp() - else: - return self.load_wsgiapp() - - -def run(prog=None): - """\ - The ``gunicorn`` command line runner for launching Gunicorn with - generic WSGI applications. - """ - from gunicorn.app.wsgiapp import WSGIApplication - WSGIApplication("%(prog)s [OPTIONS] [APP_MODULE]", prog=prog).run() - - -if __name__ == '__main__': - run() diff --git a/venv/lib/python3.9/site-packages/gunicorn/arbiter.py b/venv/lib/python3.9/site-packages/gunicorn/arbiter.py deleted file mode 100644 index 1eaf453..0000000 --- a/venv/lib/python3.9/site-packages/gunicorn/arbiter.py +++ /dev/null @@ -1,671 +0,0 @@ -# -# This file is part of gunicorn released under the MIT license. -# See the NOTICE for more information. -import errno -import os -import random -import select -import signal -import sys -import time -import traceback - -from gunicorn.errors import HaltServer, AppImportError -from gunicorn.pidfile import Pidfile -from gunicorn import sock, systemd, util - -from gunicorn import __version__, SERVER_SOFTWARE - - -class Arbiter: - """ - Arbiter maintain the workers processes alive. It launches or - kills them if needed. It also manages application reloading - via SIGHUP/USR2. - """ - - # A flag indicating if a worker failed to - # to boot. If a worker process exist with - # this error code, the arbiter will terminate. - WORKER_BOOT_ERROR = 3 - - # A flag indicating if an application failed to be loaded - APP_LOAD_ERROR = 4 - - START_CTX = {} - - LISTENERS = [] - WORKERS = {} - PIPE = [] - - # I love dynamic languages - SIG_QUEUE = [] - SIGNALS = [getattr(signal, "SIG%s" % x) - for x in "HUP QUIT INT TERM TTIN TTOU USR1 USR2 WINCH".split()] - SIG_NAMES = dict( - (getattr(signal, name), name[3:].lower()) for name in dir(signal) - if name[:3] == "SIG" and name[3] != "_" - ) - - def __init__(self, app): - os.environ["SERVER_SOFTWARE"] = SERVER_SOFTWARE - - self._num_workers = None - self._last_logged_active_worker_count = None - self.log = None - - self.setup(app) - - self.pidfile = None - self.systemd = False - self.worker_age = 0 - self.reexec_pid = 0 - self.master_pid = 0 - self.master_name = "Master" - - cwd = util.getcwd() - - args = sys.argv[:] - args.insert(0, sys.executable) - - # init start context - self.START_CTX = { - "args": args, - "cwd": cwd, - 0: sys.executable - } - - def _get_num_workers(self): - return self._num_workers - - def _set_num_workers(self, value): - old_value = self._num_workers - self._num_workers = value - self.cfg.nworkers_changed(self, value, old_value) - num_workers = property(_get_num_workers, _set_num_workers) - - def setup(self, app): - self.app = app - self.cfg = app.cfg - - if self.log is None: - self.log = self.cfg.logger_class(app.cfg) - - # reopen files - if 'GUNICORN_PID' in os.environ: - self.log.reopen_files() - - self.worker_class = self.cfg.worker_class - self.address = self.cfg.address - self.num_workers = self.cfg.workers - self.timeout = self.cfg.timeout - self.proc_name = self.cfg.proc_name - - self.log.debug('Current configuration:\n{0}'.format( - '\n'.join( - ' {0}: {1}'.format(config, value.value) - for config, value - in sorted(self.cfg.settings.items(), - key=lambda setting: setting[1])))) - - # set environment' variables - if self.cfg.env: - for k, v in self.cfg.env.items(): - os.environ[k] = v - - if self.cfg.preload_app: - self.app.wsgi() - - def start(self): - """\ - Initialize the arbiter. Start listening and set pidfile if needed. - """ - self.log.info("Starting gunicorn %s", __version__) - - if 'GUNICORN_PID' in os.environ: - self.master_pid = int(os.environ.get('GUNICORN_PID')) - self.proc_name = self.proc_name + ".2" - self.master_name = "Master.2" - - self.pid = os.getpid() - if self.cfg.pidfile is not None: - pidname = self.cfg.pidfile - if self.master_pid != 0: - pidname += ".2" - self.pidfile = Pidfile(pidname) - self.pidfile.create(self.pid) - self.cfg.on_starting(self) - - self.init_signals() - - if not self.LISTENERS: - fds = None - listen_fds = systemd.listen_fds() - if listen_fds: - self.systemd = True - fds = range(systemd.SD_LISTEN_FDS_START, - systemd.SD_LISTEN_FDS_START + listen_fds) - - elif self.master_pid: - fds = [] - for fd in os.environ.pop('GUNICORN_FD').split(','): - fds.append(int(fd)) - - self.LISTENERS = sock.create_sockets(self.cfg, self.log, fds) - - listeners_str = ",".join([str(lnr) for lnr in self.LISTENERS]) - self.log.debug("Arbiter booted") - self.log.info("Listening at: %s (%s)", listeners_str, self.pid) - self.log.info("Using worker: %s", self.cfg.worker_class_str) - systemd.sd_notify("READY=1\nSTATUS=Gunicorn arbiter booted", self.log) - - # check worker class requirements - if hasattr(self.worker_class, "check_config"): - self.worker_class.check_config(self.cfg, self.log) - - self.cfg.when_ready(self) - - def init_signals(self): - """\ - Initialize master signal handling. Most of the signals - are queued. Child signals only wake up the master. - """ - # close old PIPE - for p in self.PIPE: - os.close(p) - - # initialize the pipe - self.PIPE = pair = os.pipe() - for p in pair: - util.set_non_blocking(p) - util.close_on_exec(p) - - self.log.close_on_exec() - - # initialize all signals - for s in self.SIGNALS: - signal.signal(s, self.signal) - signal.signal(signal.SIGCHLD, self.handle_chld) - - def signal(self, sig, frame): - if len(self.SIG_QUEUE) < 5: - self.SIG_QUEUE.append(sig) - self.wakeup() - - def run(self): - "Main master loop." - self.start() - util._setproctitle("master [%s]" % self.proc_name) - - try: - self.manage_workers() - - while True: - self.maybe_promote_master() - - sig = self.SIG_QUEUE.pop(0) if self.SIG_QUEUE else None - if sig is None: - self.sleep() - self.murder_workers() - self.manage_workers() - continue - - if sig not in self.SIG_NAMES: - self.log.info("Ignoring unknown signal: %s", sig) - continue - - signame = self.SIG_NAMES.get(sig) - handler = getattr(self, "handle_%s" % signame, None) - if not handler: - self.log.error("Unhandled signal: %s", signame) - continue - self.log.info("Handling signal: %s", signame) - handler() - self.wakeup() - except (StopIteration, KeyboardInterrupt): - self.halt() - except HaltServer as inst: - self.halt(reason=inst.reason, exit_status=inst.exit_status) - except SystemExit: - raise - except Exception: - self.log.error("Unhandled exception in main loop", - exc_info=True) - self.stop(False) - if self.pidfile is not None: - self.pidfile.unlink() - sys.exit(-1) - - def handle_chld(self, sig, frame): - "SIGCHLD handling" - self.reap_workers() - self.wakeup() - - def handle_hup(self): - """\ - HUP handling. - - Reload configuration - - Start the new worker processes with a new configuration - - Gracefully shutdown the old worker processes - """ - self.log.info("Hang up: %s", self.master_name) - self.reload() - - def handle_term(self): - "SIGTERM handling" - raise StopIteration - - def handle_int(self): - "SIGINT handling" - self.stop(False) - raise StopIteration - - def handle_quit(self): - "SIGQUIT handling" - self.stop(False) - raise StopIteration - - def handle_ttin(self): - """\ - SIGTTIN handling. - Increases the number of workers by one. - """ - self.num_workers += 1 - self.manage_workers() - - def handle_ttou(self): - """\ - SIGTTOU handling. - Decreases the number of workers by one. - """ - if self.num_workers <= 1: - return - self.num_workers -= 1 - self.manage_workers() - - def handle_usr1(self): - """\ - SIGUSR1 handling. - Kill all workers by sending them a SIGUSR1 - """ - self.log.reopen_files() - self.kill_workers(signal.SIGUSR1) - - def handle_usr2(self): - """\ - SIGUSR2 handling. - Creates a new arbiter/worker set as a fork of the current - arbiter without affecting old workers. Use this to do live - deployment with the ability to backout a change. - """ - self.reexec() - - def handle_winch(self): - """SIGWINCH handling""" - if self.cfg.daemon: - self.log.info("graceful stop of workers") - self.num_workers = 0 - self.kill_workers(signal.SIGTERM) - else: - self.log.debug("SIGWINCH ignored. Not daemonized") - - def maybe_promote_master(self): - if self.master_pid == 0: - return - - if self.master_pid != os.getppid(): - self.log.info("Master has been promoted.") - # reset master infos - self.master_name = "Master" - self.master_pid = 0 - self.proc_name = self.cfg.proc_name - del os.environ['GUNICORN_PID'] - # rename the pidfile - if self.pidfile is not None: - self.pidfile.rename(self.cfg.pidfile) - # reset proctitle - util._setproctitle("master [%s]" % self.proc_name) - - def wakeup(self): - """\ - Wake up the arbiter by writing to the PIPE - """ - try: - os.write(self.PIPE[1], b'.') - except OSError as e: - if e.errno not in [errno.EAGAIN, errno.EINTR]: - raise - - def halt(self, reason=None, exit_status=0): - """ halt arbiter """ - self.stop() - - log_func = self.log.info if exit_status == 0 else self.log.error - log_func("Shutting down: %s", self.master_name) - if reason is not None: - log_func("Reason: %s", reason) - - if self.pidfile is not None: - self.pidfile.unlink() - self.cfg.on_exit(self) - sys.exit(exit_status) - - def sleep(self): - """\ - Sleep until PIPE is readable or we timeout. - A readable PIPE means a signal occurred. - """ - try: - ready = select.select([self.PIPE[0]], [], [], 1.0) - if not ready[0]: - return - while os.read(self.PIPE[0], 1): - pass - except OSError as e: - # TODO: select.error is a subclass of OSError since Python 3.3. - error_number = getattr(e, 'errno', e.args[0]) - if error_number not in [errno.EAGAIN, errno.EINTR]: - raise - except KeyboardInterrupt: - sys.exit() - - def stop(self, graceful=True): - """\ - Stop workers - - :attr graceful: boolean, If True (the default) workers will be - killed gracefully (ie. trying to wait for the current connection) - """ - unlink = ( - self.reexec_pid == self.master_pid == 0 - and not self.systemd - and not self.cfg.reuse_port - ) - sock.close_sockets(self.LISTENERS, unlink) - - self.LISTENERS = [] - sig = signal.SIGTERM - if not graceful: - sig = signal.SIGQUIT - limit = time.time() + self.cfg.graceful_timeout - # instruct the workers to exit - self.kill_workers(sig) - # wait until the graceful timeout - while self.WORKERS and time.time() < limit: - time.sleep(0.1) - - self.kill_workers(signal.SIGKILL) - - def reexec(self): - """\ - Relaunch the master and workers. - """ - if self.reexec_pid != 0: - self.log.warning("USR2 signal ignored. Child exists.") - return - - if self.master_pid != 0: - self.log.warning("USR2 signal ignored. Parent exists.") - return - - master_pid = os.getpid() - self.reexec_pid = os.fork() - if self.reexec_pid != 0: - return - - self.cfg.pre_exec(self) - - environ = self.cfg.env_orig.copy() - environ['GUNICORN_PID'] = str(master_pid) - - if self.systemd: - environ['LISTEN_PID'] = str(os.getpid()) - environ['LISTEN_FDS'] = str(len(self.LISTENERS)) - else: - environ['GUNICORN_FD'] = ','.join( - str(lnr.fileno()) for lnr in self.LISTENERS) - - os.chdir(self.START_CTX['cwd']) - - # exec the process using the original environment - os.execvpe(self.START_CTX[0], self.START_CTX['args'], environ) - - def reload(self): - old_address = self.cfg.address - - # reset old environment - for k in self.cfg.env: - if k in self.cfg.env_orig: - # reset the key to the value it had before - # we launched gunicorn - os.environ[k] = self.cfg.env_orig[k] - else: - # delete the value set by gunicorn - try: - del os.environ[k] - except KeyError: - pass - - # reload conf - self.app.reload() - self.setup(self.app) - - # reopen log files - self.log.reopen_files() - - # do we need to change listener ? - if old_address != self.cfg.address: - # close all listeners - for lnr in self.LISTENERS: - lnr.close() - # init new listeners - self.LISTENERS = sock.create_sockets(self.cfg, self.log) - listeners_str = ",".join([str(lnr) for lnr in self.LISTENERS]) - self.log.info("Listening at: %s", listeners_str) - - # do some actions on reload - self.cfg.on_reload(self) - - # unlink pidfile - if self.pidfile is not None: - self.pidfile.unlink() - - # create new pidfile - if self.cfg.pidfile is not None: - self.pidfile = Pidfile(self.cfg.pidfile) - self.pidfile.create(self.pid) - - # set new proc_name - util._setproctitle("master [%s]" % self.proc_name) - - # spawn new workers - for _ in range(self.cfg.workers): - self.spawn_worker() - - # manage workers - self.manage_workers() - - def murder_workers(self): - """\ - Kill unused/idle workers - """ - if not self.timeout: - return - workers = list(self.WORKERS.items()) - for (pid, worker) in workers: - try: - if time.monotonic() - worker.tmp.last_update() <= self.timeout: - continue - except (OSError, ValueError): - continue - - if not worker.aborted: - self.log.critical("WORKER TIMEOUT (pid:%s)", pid) - worker.aborted = True - self.kill_worker(pid, signal.SIGABRT) - else: - self.kill_worker(pid, signal.SIGKILL) - - def reap_workers(self): - """\ - Reap workers to avoid zombie processes - """ - try: - while True: - wpid, status = os.waitpid(-1, os.WNOHANG) - if not wpid: - break - if self.reexec_pid == wpid: - self.reexec_pid = 0 - else: - # A worker was terminated. If the termination reason was - # that it could not boot, we'll shut it down to avoid - # infinite start/stop cycles. - exitcode = status >> 8 - if exitcode != 0: - self.log.error('Worker (pid:%s) exited with code %s', wpid, exitcode) - if exitcode == self.WORKER_BOOT_ERROR: - reason = "Worker failed to boot." - raise HaltServer(reason, self.WORKER_BOOT_ERROR) - if exitcode == self.APP_LOAD_ERROR: - reason = "App failed to load." - raise HaltServer(reason, self.APP_LOAD_ERROR) - - if exitcode > 0: - # If the exit code of the worker is greater than 0, - # let the user know. - self.log.error("Worker (pid:%s) exited with code %s.", - wpid, exitcode) - elif status > 0: - # If the exit code of the worker is 0 and the status - # is greater than 0, then it was most likely killed - # via a signal. - try: - sig_name = signal.Signals(status).name - except ValueError: - sig_name = "code {}".format(status) - msg = "Worker (pid:{}) was sent {}!".format( - wpid, sig_name) - - # Additional hint for SIGKILL - if status == signal.SIGKILL: - msg += " Perhaps out of memory?" - self.log.error(msg) - - worker = self.WORKERS.pop(wpid, None) - if not worker: - continue - worker.tmp.close() - self.cfg.child_exit(self, worker) - except OSError as e: - if e.errno != errno.ECHILD: - raise - - def manage_workers(self): - """\ - Maintain the number of workers by spawning or killing - as required. - """ - if len(self.WORKERS) < self.num_workers: - self.spawn_workers() - - workers = self.WORKERS.items() - workers = sorted(workers, key=lambda w: w[1].age) - while len(workers) > self.num_workers: - (pid, _) = workers.pop(0) - self.kill_worker(pid, signal.SIGTERM) - - active_worker_count = len(workers) - if self._last_logged_active_worker_count != active_worker_count: - self._last_logged_active_worker_count = active_worker_count - self.log.debug("{0} workers".format(active_worker_count), - extra={"metric": "gunicorn.workers", - "value": active_worker_count, - "mtype": "gauge"}) - - def spawn_worker(self): - self.worker_age += 1 - worker = self.worker_class(self.worker_age, self.pid, self.LISTENERS, - self.app, self.timeout / 2.0, - self.cfg, self.log) - self.cfg.pre_fork(self, worker) - pid = os.fork() - if pid != 0: - worker.pid = pid - self.WORKERS[pid] = worker - return pid - - # Do not inherit the temporary files of other workers - for sibling in self.WORKERS.values(): - sibling.tmp.close() - - # Process Child - worker.pid = os.getpid() - try: - util._setproctitle("worker [%s]" % self.proc_name) - self.log.info("Booting worker with pid: %s", worker.pid) - self.cfg.post_fork(self, worker) - worker.init_process() - sys.exit(0) - except SystemExit: - raise - except AppImportError as e: - self.log.debug("Exception while loading the application", - exc_info=True) - print("%s" % e, file=sys.stderr) - sys.stderr.flush() - sys.exit(self.APP_LOAD_ERROR) - except Exception: - self.log.exception("Exception in worker process") - if not worker.booted: - sys.exit(self.WORKER_BOOT_ERROR) - sys.exit(-1) - finally: - self.log.info("Worker exiting (pid: %s)", worker.pid) - try: - worker.tmp.close() - self.cfg.worker_exit(self, worker) - except Exception: - self.log.warning("Exception during worker exit:\n%s", - traceback.format_exc()) - - def spawn_workers(self): - """\ - Spawn new workers as needed. - - This is where a worker process leaves the main loop - of the master process. - """ - - for _ in range(self.num_workers - len(self.WORKERS)): - self.spawn_worker() - time.sleep(0.1 * random.random()) - - def kill_workers(self, sig): - """\ - Kill all workers with the signal `sig` - :attr sig: `signal.SIG*` value - """ - worker_pids = list(self.WORKERS.keys()) - for pid in worker_pids: - self.kill_worker(pid, sig) - - def kill_worker(self, pid, sig): - """\ - Kill a worker - - :attr pid: int, worker pid - :attr sig: `signal.SIG*` value - """ - try: - os.kill(pid, sig) - except OSError as e: - if e.errno == errno.ESRCH: - try: - worker = self.WORKERS.pop(pid) - worker.tmp.close() - self.cfg.worker_exit(self, worker) - return - except (KeyError, OSError): - return - raise diff --git a/venv/lib/python3.9/site-packages/gunicorn/config.py b/venv/lib/python3.9/site-packages/gunicorn/config.py deleted file mode 100644 index 402a26b..0000000 --- a/venv/lib/python3.9/site-packages/gunicorn/config.py +++ /dev/null @@ -1,2442 +0,0 @@ -# -# This file is part of gunicorn released under the MIT license. -# See the NOTICE for more information. - -# Please remember to run "make -C docs html" after update "desc" attributes. - -import argparse -import copy -import grp -import inspect -import ipaddress -import os -import pwd -import re -import shlex -import ssl -import sys -import textwrap - -from gunicorn import __version__, util -from gunicorn.errors import ConfigError -from gunicorn.reloader import reloader_engines - -KNOWN_SETTINGS = [] -PLATFORM = sys.platform - - -def make_settings(ignore=None): - settings = {} - ignore = ignore or () - for s in KNOWN_SETTINGS: - setting = s() - if setting.name in ignore: - continue - settings[setting.name] = setting.copy() - return settings - - -def auto_int(_, x): - # for compatible with octal numbers in python3 - if re.match(r'0(\d)', x, re.IGNORECASE): - x = x.replace('0', '0o', 1) - return int(x, 0) - - -class Config: - - def __init__(self, usage=None, prog=None): - self.settings = make_settings() - self.usage = usage - self.prog = prog or os.path.basename(sys.argv[0]) - self.env_orig = os.environ.copy() - - def __str__(self): - lines = [] - kmax = max(len(k) for k in self.settings) - for k in sorted(self.settings): - v = self.settings[k].value - if callable(v): - v = "<{}()>".format(v.__qualname__) - lines.append("{k:{kmax}} = {v}".format(k=k, v=v, kmax=kmax)) - return "\n".join(lines) - - def __getattr__(self, name): - if name not in self.settings: - raise AttributeError("No configuration setting for: %s" % name) - return self.settings[name].get() - - def __setattr__(self, name, value): - if name != "settings" and name in self.settings: - raise AttributeError("Invalid access!") - super().__setattr__(name, value) - - def set(self, name, value): - if name not in self.settings: - raise AttributeError("No configuration setting for: %s" % name) - self.settings[name].set(value) - - def get_cmd_args_from_env(self): - if 'GUNICORN_CMD_ARGS' in self.env_orig: - return shlex.split(self.env_orig['GUNICORN_CMD_ARGS']) - return [] - - def parser(self): - kwargs = { - "usage": self.usage, - "prog": self.prog - } - parser = argparse.ArgumentParser(**kwargs) - parser.add_argument("-v", "--version", - action="version", default=argparse.SUPPRESS, - version="%(prog)s (version " + __version__ + ")\n", - help="show program's version number and exit") - parser.add_argument("args", nargs="*", help=argparse.SUPPRESS) - - keys = sorted(self.settings, key=self.settings.__getitem__) - for k in keys: - self.settings[k].add_option(parser) - - return parser - - @property - def worker_class_str(self): - uri = self.settings['worker_class'].get() - - if isinstance(uri, str): - # are we using a threaded worker? - is_sync = uri.endswith('SyncWorker') or uri == 'sync' - if is_sync and self.threads > 1: - return "gthread" - return uri - return uri.__name__ - - @property - def worker_class(self): - uri = self.settings['worker_class'].get() - - # are we using a threaded worker? - is_sync = isinstance(uri, str) and (uri.endswith('SyncWorker') or uri == 'sync') - if is_sync and self.threads > 1: - uri = "gunicorn.workers.gthread.ThreadWorker" - - worker_class = util.load_class(uri) - if hasattr(worker_class, "setup"): - worker_class.setup() - return worker_class - - @property - def address(self): - s = self.settings['bind'].get() - return [util.parse_address(util.bytes_to_str(bind)) for bind in s] - - @property - def uid(self): - return self.settings['user'].get() - - @property - def gid(self): - return self.settings['group'].get() - - @property - def proc_name(self): - pn = self.settings['proc_name'].get() - if pn is not None: - return pn - else: - return self.settings['default_proc_name'].get() - - @property - def logger_class(self): - uri = self.settings['logger_class'].get() - if uri == "simple": - # support the default - uri = LoggerClass.default - - # if default logger is in use, and statsd is on, automagically switch - # to the statsd logger - if uri == LoggerClass.default: - if 'statsd_host' in self.settings and self.settings['statsd_host'].value is not None: - uri = "gunicorn.instrument.statsd.Statsd" - - logger_class = util.load_class( - uri, - default="gunicorn.glogging.Logger", - section="gunicorn.loggers") - - if hasattr(logger_class, "install"): - logger_class.install() - return logger_class - - @property - def is_ssl(self): - return self.certfile or self.keyfile - - @property - def ssl_options(self): - opts = {} - for name, value in self.settings.items(): - if value.section == 'SSL': - opts[name] = value.get() - return opts - - @property - def env(self): - raw_env = self.settings['raw_env'].get() - env = {} - - if not raw_env: - return env - - for e in raw_env: - s = util.bytes_to_str(e) - try: - k, v = s.split('=', 1) - except ValueError: - raise RuntimeError("environment setting %r invalid" % s) - - env[k] = v - - return env - - @property - def sendfile(self): - if self.settings['sendfile'].get() is not None: - return False - - if 'SENDFILE' in os.environ: - sendfile = os.environ['SENDFILE'].lower() - return sendfile in ['y', '1', 'yes', 'true'] - - return True - - @property - def reuse_port(self): - return self.settings['reuse_port'].get() - - @property - def paste_global_conf(self): - raw_global_conf = self.settings['raw_paste_global_conf'].get() - if raw_global_conf is None: - return None - - global_conf = {} - for e in raw_global_conf: - s = util.bytes_to_str(e) - try: - k, v = re.split(r'(?" % ( - self.__class__.__module__, - self.__class__.__name__, - id(self), - self.value, - ) - - -Setting = SettingMeta('Setting', (Setting,), {}) - - -def validate_bool(val): - if val is None: - return - - if isinstance(val, bool): - return val - if not isinstance(val, str): - raise TypeError("Invalid type for casting: %s" % val) - if val.lower().strip() == "true": - return True - elif val.lower().strip() == "false": - return False - else: - raise ValueError("Invalid boolean: %s" % val) - - -def validate_dict(val): - if not isinstance(val, dict): - raise TypeError("Value is not a dictionary: %s " % val) - return val - - -def validate_pos_int(val): - if not isinstance(val, int): - val = int(val, 0) - else: - # Booleans are ints! - val = int(val) - if val < 0: - raise ValueError("Value must be positive: %s" % val) - return val - - -def validate_ssl_version(val): - if val != SSLVersion.default: - sys.stderr.write("Warning: option `ssl_version` is deprecated and it is ignored. Use ssl_context instead.\n") - return val - - -def validate_string(val): - if val is None: - return None - if not isinstance(val, str): - raise TypeError("Not a string: %s" % val) - return val.strip() - - -def validate_file_exists(val): - if val is None: - return None - if not os.path.exists(val): - raise ValueError("File %s does not exists." % val) - return val - - -def validate_list_string(val): - if not val: - return [] - - # legacy syntax - if isinstance(val, str): - val = [val] - - return [validate_string(v) for v in val] - - -def validate_list_of_existing_files(val): - return [validate_file_exists(v) for v in validate_list_string(val)] - - -def validate_string_to_addr_list(val): - val = validate_string_to_list(val) - - for addr in val: - if addr == "*": - continue - _vaid_ip = ipaddress.ip_address(addr) - - return val - - -def validate_string_to_list(val): - val = validate_string(val) - - if not val: - return [] - - return [v.strip() for v in val.split(",") if v] - - -def validate_class(val): - if inspect.isfunction(val) or inspect.ismethod(val): - val = val() - if inspect.isclass(val): - return val - return validate_string(val) - - -def validate_callable(arity): - def _validate_callable(val): - if isinstance(val, str): - try: - mod_name, obj_name = val.rsplit(".", 1) - except ValueError: - raise TypeError("Value '%s' is not import string. " - "Format: module[.submodules...].object" % val) - try: - mod = __import__(mod_name, fromlist=[obj_name]) - val = getattr(mod, obj_name) - except ImportError as e: - raise TypeError(str(e)) - except AttributeError: - raise TypeError("Can not load '%s' from '%s'" - "" % (obj_name, mod_name)) - if not callable(val): - raise TypeError("Value is not callable: %s" % val) - if arity != -1 and arity != util.get_arity(val): - raise TypeError("Value must have an arity of: %s" % arity) - return val - return _validate_callable - - -def validate_user(val): - if val is None: - return os.geteuid() - if isinstance(val, int): - return val - elif val.isdigit(): - return int(val) - else: - try: - return pwd.getpwnam(val).pw_uid - except KeyError: - raise ConfigError("No such user: '%s'" % val) - - -def validate_group(val): - if val is None: - return os.getegid() - - if isinstance(val, int): - return val - elif val.isdigit(): - return int(val) - else: - try: - return grp.getgrnam(val).gr_gid - except KeyError: - raise ConfigError("No such group: '%s'" % val) - - -def validate_post_request(val): - val = validate_callable(-1)(val) - - largs = util.get_arity(val) - if largs == 4: - return val - elif largs == 3: - return lambda worker, req, env, _r: val(worker, req, env) - elif largs == 2: - return lambda worker, req, _e, _r: val(worker, req) - else: - raise TypeError("Value must have an arity of: 4") - - -def validate_chdir(val): - # valid if the value is a string - val = validate_string(val) - - # transform relative paths - path = os.path.abspath(os.path.normpath(os.path.join(util.getcwd(), val))) - - # test if the path exists - if not os.path.exists(path): - raise ConfigError("can't chdir to %r" % val) - - return path - - -def validate_statsd_address(val): - val = validate_string(val) - if val is None: - return None - - # As of major release 20, util.parse_address would recognize unix:PORT - # as a UDS address, breaking backwards compatibility. We defend against - # that regression here (this is also unit-tested). - # Feel free to remove in the next major release. - unix_hostname_regression = re.match(r'^unix:(\d+)$', val) - if unix_hostname_regression: - return ('unix', int(unix_hostname_regression.group(1))) - - try: - address = util.parse_address(val, default_port='8125') - except RuntimeError: - raise TypeError("Value must be one of ('host:port', 'unix://PATH')") - - return address - - -def validate_reload_engine(val): - if val not in reloader_engines: - raise ConfigError("Invalid reload_engine: %r" % val) - - return val - - -def get_default_config_file(): - config_path = os.path.join(os.path.abspath(os.getcwd()), - 'gunicorn.conf.py') - if os.path.exists(config_path): - return config_path - return None - - -class ConfigFile(Setting): - name = "config" - section = "Config File" - cli = ["-c", "--config"] - meta = "CONFIG" - validator = validate_string - default = "./gunicorn.conf.py" - desc = """\ - :ref:`The Gunicorn config file`. - - A string of the form ``PATH``, ``file:PATH``, or ``python:MODULE_NAME``. - - Only has an effect when specified on the command line or as part of an - application specific configuration. - - By default, a file named ``gunicorn.conf.py`` will be read from the same - directory where gunicorn is being run. - - .. versionchanged:: 19.4 - Loading the config from a Python module requires the ``python:`` - prefix. - """ - - -class WSGIApp(Setting): - name = "wsgi_app" - section = "Config File" - meta = "STRING" - validator = validate_string - default = None - desc = """\ - A WSGI application path in pattern ``$(MODULE_NAME):$(VARIABLE_NAME)``. - - .. versionadded:: 20.1.0 - """ - - -class Bind(Setting): - name = "bind" - action = "append" - section = "Server Socket" - cli = ["-b", "--bind"] - meta = "ADDRESS" - validator = validate_list_string - - if 'PORT' in os.environ: - default = ['0.0.0.0:{0}'.format(os.environ.get('PORT'))] - else: - default = ['127.0.0.1:8000'] - - desc = """\ - The socket to bind. - - A string of the form: ``HOST``, ``HOST:PORT``, ``unix:PATH``, - ``fd://FD``. An IP is a valid ``HOST``. - - .. versionchanged:: 20.0 - Support for ``fd://FD`` got added. - - Multiple addresses can be bound. ex.:: - - $ gunicorn -b 127.0.0.1:8000 -b [::1]:8000 test:app - - will bind the `test:app` application on localhost both on ipv6 - and ipv4 interfaces. - - If the ``PORT`` environment variable is defined, the default - is ``['0.0.0.0:$PORT']``. If it is not defined, the default - is ``['127.0.0.1:8000']``. - """ - - -class Backlog(Setting): - name = "backlog" - section = "Server Socket" - cli = ["--backlog"] - meta = "INT" - validator = validate_pos_int - type = int - default = 2048 - desc = """\ - The maximum number of pending connections. - - This refers to the number of clients that can be waiting to be served. - Exceeding this number results in the client getting an error when - attempting to connect. It should only affect servers under significant - load. - - Must be a positive integer. Generally set in the 64-2048 range. - """ - - -class Workers(Setting): - name = "workers" - section = "Worker Processes" - cli = ["-w", "--workers"] - meta = "INT" - validator = validate_pos_int - type = int - default = int(os.environ.get("WEB_CONCURRENCY", 1)) - desc = """\ - The number of worker processes for handling requests. - - A positive integer generally in the ``2-4 x $(NUM_CORES)`` range. - You'll want to vary this a bit to find the best for your particular - application's work load. - - By default, the value of the ``WEB_CONCURRENCY`` environment variable, - which is set by some Platform-as-a-Service providers such as Heroku. If - it is not defined, the default is ``1``. - """ - - -class WorkerClass(Setting): - name = "worker_class" - section = "Worker Processes" - cli = ["-k", "--worker-class"] - meta = "STRING" - validator = validate_class - default = "sync" - desc = """\ - The type of workers to use. - - The default class (``sync``) should handle most "normal" types of - workloads. You'll want to read :doc:`design` for information on when - you might want to choose one of the other worker classes. Required - libraries may be installed using setuptools' ``extras_require`` feature. - - A string referring to one of the following bundled classes: - - * ``sync`` - * ``eventlet`` - Requires eventlet >= 0.24.1 (or install it via - ``pip install gunicorn[eventlet]``) - * ``gevent`` - Requires gevent >= 1.4 (or install it via - ``pip install gunicorn[gevent]``) - * ``tornado`` - Requires tornado >= 0.2 (or install it via - ``pip install gunicorn[tornado]``) - * ``gthread`` - Python 2 requires the futures package to be installed - (or install it via ``pip install gunicorn[gthread]``) - - Optionally, you can provide your own worker by giving Gunicorn a - Python path to a subclass of ``gunicorn.workers.base.Worker``. - This alternative syntax will load the gevent class: - ``gunicorn.workers.ggevent.GeventWorker``. - """ - - -class WorkerThreads(Setting): - name = "threads" - section = "Worker Processes" - cli = ["--threads"] - meta = "INT" - validator = validate_pos_int - type = int - default = 1 - desc = """\ - The number of worker threads for handling requests. - - Run each worker with the specified number of threads. - - A positive integer generally in the ``2-4 x $(NUM_CORES)`` range. - You'll want to vary this a bit to find the best for your particular - application's work load. - - If it is not defined, the default is ``1``. - - This setting only affects the Gthread worker type. - - .. note:: - If you try to use the ``sync`` worker type and set the ``threads`` - setting to more than 1, the ``gthread`` worker type will be used - instead. - """ - - -class WorkerConnections(Setting): - name = "worker_connections" - section = "Worker Processes" - cli = ["--worker-connections"] - meta = "INT" - validator = validate_pos_int - type = int - default = 1000 - desc = """\ - The maximum number of simultaneous clients. - - This setting only affects the ``gthread``, ``eventlet`` and ``gevent`` worker types. - """ - - -class MaxRequests(Setting): - name = "max_requests" - section = "Worker Processes" - cli = ["--max-requests"] - meta = "INT" - validator = validate_pos_int - type = int - default = 0 - desc = """\ - The maximum number of requests a worker will process before restarting. - - Any value greater than zero will limit the number of requests a worker - will process before automatically restarting. This is a simple method - to help limit the damage of memory leaks. - - If this is set to zero (the default) then the automatic worker - restarts are disabled. - """ - - -class MaxRequestsJitter(Setting): - name = "max_requests_jitter" - section = "Worker Processes" - cli = ["--max-requests-jitter"] - meta = "INT" - validator = validate_pos_int - type = int - default = 0 - desc = """\ - The maximum jitter to add to the *max_requests* setting. - - The jitter causes the restart per worker to be randomized by - ``randint(0, max_requests_jitter)``. This is intended to stagger worker - restarts to avoid all workers restarting at the same time. - - .. versionadded:: 19.2 - """ - - -class Timeout(Setting): - name = "timeout" - section = "Worker Processes" - cli = ["-t", "--timeout"] - meta = "INT" - validator = validate_pos_int - type = int - default = 30 - desc = """\ - Workers silent for more than this many seconds are killed and restarted. - - Value is a positive number or 0. Setting it to 0 has the effect of - infinite timeouts by disabling timeouts for all workers entirely. - - Generally, the default of thirty seconds should suffice. Only set this - noticeably higher if you're sure of the repercussions for sync workers. - For the non sync workers it just means that the worker process is still - communicating and is not tied to the length of time required to handle a - single request. - """ - - -class GracefulTimeout(Setting): - name = "graceful_timeout" - section = "Worker Processes" - cli = ["--graceful-timeout"] - meta = "INT" - validator = validate_pos_int - type = int - default = 30 - desc = """\ - Timeout for graceful workers restart. - - After receiving a restart signal, workers have this much time to finish - serving requests. Workers still alive after the timeout (starting from - the receipt of the restart signal) are force killed. - """ - - -class Keepalive(Setting): - name = "keepalive" - section = "Worker Processes" - cli = ["--keep-alive"] - meta = "INT" - validator = validate_pos_int - type = int - default = 2 - desc = """\ - The number of seconds to wait for requests on a Keep-Alive connection. - - Generally set in the 1-5 seconds range for servers with direct connection - to the client (e.g. when you don't have separate load balancer). When - Gunicorn is deployed behind a load balancer, it often makes sense to - set this to a higher value. - - .. note:: - ``sync`` worker does not support persistent connections and will - ignore this option. - """ - - -class LimitRequestLine(Setting): - name = "limit_request_line" - section = "Security" - cli = ["--limit-request-line"] - meta = "INT" - validator = validate_pos_int - type = int - default = 4094 - desc = """\ - The maximum size of HTTP request line in bytes. - - This parameter is used to limit the allowed size of a client's - HTTP request-line. Since the request-line consists of the HTTP - method, URI, and protocol version, this directive places a - restriction on the length of a request-URI allowed for a request - on the server. A server needs this value to be large enough to - hold any of its resource names, including any information that - might be passed in the query part of a GET request. Value is a number - from 0 (unlimited) to 8190. - - This parameter can be used to prevent any DDOS attack. - """ - - -class LimitRequestFields(Setting): - name = "limit_request_fields" - section = "Security" - cli = ["--limit-request-fields"] - meta = "INT" - validator = validate_pos_int - type = int - default = 100 - desc = """\ - Limit the number of HTTP headers fields in a request. - - This parameter is used to limit the number of headers in a request to - prevent DDOS attack. Used with the *limit_request_field_size* it allows - more safety. By default this value is 100 and can't be larger than - 32768. - """ - - -class LimitRequestFieldSize(Setting): - name = "limit_request_field_size" - section = "Security" - cli = ["--limit-request-field_size"] - meta = "INT" - validator = validate_pos_int - type = int - default = 8190 - desc = """\ - Limit the allowed size of an HTTP request header field. - - Value is a positive number or 0. Setting it to 0 will allow unlimited - header field sizes. - - .. warning:: - Setting this parameter to a very high or unlimited value can open - up for DDOS attacks. - """ - - -class Reload(Setting): - name = "reload" - section = 'Debugging' - cli = ['--reload'] - validator = validate_bool - action = 'store_true' - default = False - - desc = '''\ - Restart workers when code changes. - - This setting is intended for development. It will cause workers to be - restarted whenever application code changes. - - The reloader is incompatible with application preloading. When using a - paste configuration be sure that the server block does not import any - application code or the reload will not work as designed. - - The default behavior is to attempt inotify with a fallback to file - system polling. Generally, inotify should be preferred if available - because it consumes less system resources. - - .. note:: - In order to use the inotify reloader, you must have the ``inotify`` - package installed. - ''' - - -class ReloadEngine(Setting): - name = "reload_engine" - section = "Debugging" - cli = ["--reload-engine"] - meta = "STRING" - validator = validate_reload_engine - default = "auto" - desc = """\ - The implementation that should be used to power :ref:`reload`. - - Valid engines are: - - * ``'auto'`` - * ``'poll'`` - * ``'inotify'`` (requires inotify) - - .. versionadded:: 19.7 - """ - - -class ReloadExtraFiles(Setting): - name = "reload_extra_files" - action = "append" - section = "Debugging" - cli = ["--reload-extra-file"] - meta = "FILES" - validator = validate_list_of_existing_files - default = [] - desc = """\ - Extends :ref:`reload` option to also watch and reload on additional files - (e.g., templates, configurations, specifications, etc.). - - .. versionadded:: 19.8 - """ - - -class Spew(Setting): - name = "spew" - section = "Debugging" - cli = ["--spew"] - validator = validate_bool - action = "store_true" - default = False - desc = """\ - Install a trace function that spews every line executed by the server. - - This is the nuclear option. - """ - - -class ConfigCheck(Setting): - name = "check_config" - section = "Debugging" - cli = ["--check-config"] - validator = validate_bool - action = "store_true" - default = False - desc = """\ - Check the configuration and exit. The exit status is 0 if the - configuration is correct, and 1 if the configuration is incorrect. - """ - - -class PrintConfig(Setting): - name = "print_config" - section = "Debugging" - cli = ["--print-config"] - validator = validate_bool - action = "store_true" - default = False - desc = """\ - Print the configuration settings as fully resolved. Implies :ref:`check-config`. - """ - - -class PreloadApp(Setting): - name = "preload_app" - section = "Server Mechanics" - cli = ["--preload"] - validator = validate_bool - action = "store_true" - default = False - desc = """\ - Load application code before the worker processes are forked. - - By preloading an application you can save some RAM resources as well as - speed up server boot times. Although, if you defer application loading - to each worker process, you can reload your application code easily by - restarting workers. - """ - - -class Sendfile(Setting): - name = "sendfile" - section = "Server Mechanics" - cli = ["--no-sendfile"] - validator = validate_bool - action = "store_const" - const = False - - desc = """\ - Disables the use of ``sendfile()``. - - If not set, the value of the ``SENDFILE`` environment variable is used - to enable or disable its usage. - - .. versionadded:: 19.2 - .. versionchanged:: 19.4 - Swapped ``--sendfile`` with ``--no-sendfile`` to actually allow - disabling. - .. versionchanged:: 19.6 - added support for the ``SENDFILE`` environment variable - """ - - -class ReusePort(Setting): - name = "reuse_port" - section = "Server Mechanics" - cli = ["--reuse-port"] - validator = validate_bool - action = "store_true" - default = False - - desc = """\ - Set the ``SO_REUSEPORT`` flag on the listening socket. - - .. versionadded:: 19.8 - """ - - -class Chdir(Setting): - name = "chdir" - section = "Server Mechanics" - cli = ["--chdir"] - validator = validate_chdir - default = util.getcwd() - default_doc = "``'.'``" - desc = """\ - Change directory to specified directory before loading apps. - """ - - -class Daemon(Setting): - name = "daemon" - section = "Server Mechanics" - cli = ["-D", "--daemon"] - validator = validate_bool - action = "store_true" - default = False - desc = """\ - Daemonize the Gunicorn process. - - Detaches the server from the controlling terminal and enters the - background. - """ - - -class Env(Setting): - name = "raw_env" - action = "append" - section = "Server Mechanics" - cli = ["-e", "--env"] - meta = "ENV" - validator = validate_list_string - default = [] - - desc = """\ - Set environment variables in the execution environment. - - Should be a list of strings in the ``key=value`` format. - - For example on the command line: - - .. code-block:: console - - $ gunicorn -b 127.0.0.1:8000 --env FOO=1 test:app - - Or in the configuration file: - - .. code-block:: python - - raw_env = ["FOO=1"] - """ - - -class Pidfile(Setting): - name = "pidfile" - section = "Server Mechanics" - cli = ["-p", "--pid"] - meta = "FILE" - validator = validate_string - default = None - desc = """\ - A filename to use for the PID file. - - If not set, no PID file will be written. - """ - - -class WorkerTmpDir(Setting): - name = "worker_tmp_dir" - section = "Server Mechanics" - cli = ["--worker-tmp-dir"] - meta = "DIR" - validator = validate_string - default = None - desc = """\ - A directory to use for the worker heartbeat temporary file. - - If not set, the default temporary directory will be used. - - .. note:: - The current heartbeat system involves calling ``os.fchmod`` on - temporary file handlers and may block a worker for arbitrary time - if the directory is on a disk-backed filesystem. - - See :ref:`blocking-os-fchmod` for more detailed information - and a solution for avoiding this problem. - """ - - -class User(Setting): - name = "user" - section = "Server Mechanics" - cli = ["-u", "--user"] - meta = "USER" - validator = validate_user - default = os.geteuid() - default_doc = "``os.geteuid()``" - desc = """\ - Switch worker processes to run as this user. - - A valid user id (as an integer) or the name of a user that can be - retrieved with a call to ``pwd.getpwnam(value)`` or ``None`` to not - change the worker process user. - """ - - -class Group(Setting): - name = "group" - section = "Server Mechanics" - cli = ["-g", "--group"] - meta = "GROUP" - validator = validate_group - default = os.getegid() - default_doc = "``os.getegid()``" - desc = """\ - Switch worker process to run as this group. - - A valid group id (as an integer) or the name of a user that can be - retrieved with a call to ``pwd.getgrnam(value)`` or ``None`` to not - change the worker processes group. - """ - - -class Umask(Setting): - name = "umask" - section = "Server Mechanics" - cli = ["-m", "--umask"] - meta = "INT" - validator = validate_pos_int - type = auto_int - default = 0 - desc = """\ - A bit mask for the file mode on files written by Gunicorn. - - Note that this affects unix socket permissions. - - A valid value for the ``os.umask(mode)`` call or a string compatible - with ``int(value, 0)`` (``0`` means Python guesses the base, so values - like ``0``, ``0xFF``, ``0022`` are valid for decimal, hex, and octal - representations) - """ - - -class Initgroups(Setting): - name = "initgroups" - section = "Server Mechanics" - cli = ["--initgroups"] - validator = validate_bool - action = 'store_true' - default = False - - desc = """\ - If true, set the worker process's group access list with all of the - groups of which the specified username is a member, plus the specified - group id. - - .. versionadded:: 19.7 - """ - - -class TmpUploadDir(Setting): - name = "tmp_upload_dir" - section = "Server Mechanics" - meta = "DIR" - validator = validate_string - default = None - desc = """\ - Directory to store temporary request data as they are read. - - This may disappear in the near future. - - This path should be writable by the process permissions set for Gunicorn - workers. If not specified, Gunicorn will choose a system generated - temporary directory. - """ - - -class SecureSchemeHeader(Setting): - name = "secure_scheme_headers" - section = "Server Mechanics" - validator = validate_dict - default = { - "X-FORWARDED-PROTOCOL": "ssl", - "X-FORWARDED-PROTO": "https", - "X-FORWARDED-SSL": "on" - } - desc = """\ - - A dictionary containing headers and values that the front-end proxy - uses to indicate HTTPS requests. If the source IP is permitted by - :ref:`forwarded-allow-ips` (below), *and* at least one request header matches - a key-value pair listed in this dictionary, then Gunicorn will set - ``wsgi.url_scheme`` to ``https``, so your application can tell that the - request is secure. - - If the other headers listed in this dictionary are not present in the request, they will be ignored, - but if the other headers are present and do not match the provided values, then - the request will fail to parse. See the note below for more detailed examples of this behaviour. - - The dictionary should map upper-case header names to exact string - values. The value comparisons are case-sensitive, unlike the header - names, so make sure they're exactly what your front-end proxy sends - when handling HTTPS requests. - - It is important that your front-end proxy configuration ensures that - the headers defined here can not be passed directly from the client. - """ - - -class ForwardedAllowIPS(Setting): - name = "forwarded_allow_ips" - section = "Server Mechanics" - cli = ["--forwarded-allow-ips"] - meta = "STRING" - validator = validate_string_to_addr_list - default = os.environ.get("FORWARDED_ALLOW_IPS", "127.0.0.1,::1") - desc = """\ - Front-end's IPs from which allowed to handle set secure headers. - (comma separated). - - Set to ``*`` to disable checking of front-end IPs. This is useful for setups - where you don't know in advance the IP address of front-end, but - instead have ensured via other means that only your - authorized front-ends can access Gunicorn. - - By default, the value of the ``FORWARDED_ALLOW_IPS`` environment - variable. If it is not defined, the default is ``"127.0.0.1,::1"``. - - .. note:: - - This option does not affect UNIX socket connections. Connections not associated with - an IP address are treated as allowed, unconditionally. - - .. note:: - - The interplay between the request headers, the value of ``forwarded_allow_ips``, and the value of - ``secure_scheme_headers`` is complex. Various scenarios are documented below to further elaborate. - In each case, we have a request from the remote address 134.213.44.18, and the default value of - ``secure_scheme_headers``: - - .. code:: - - secure_scheme_headers = { - 'X-FORWARDED-PROTOCOL': 'ssl', - 'X-FORWARDED-PROTO': 'https', - 'X-FORWARDED-SSL': 'on' - } - - - .. list-table:: - :header-rows: 1 - :align: center - :widths: auto - - * - ``forwarded-allow-ips`` - - Secure Request Headers - - Result - - Explanation - * - .. code:: - - ["127.0.0.1"] - - .. code:: - - X-Forwarded-Proto: https - - .. code:: - - wsgi.url_scheme = "http" - - IP address was not allowed - * - .. code:: - - "*" - - - - .. code:: - - wsgi.url_scheme = "http" - - IP address allowed, but no secure headers provided - * - .. code:: - - "*" - - .. code:: - - X-Forwarded-Proto: https - - .. code:: - - wsgi.url_scheme = "https" - - IP address allowed, one request header matched - * - .. code:: - - ["134.213.44.18"] - - .. code:: - - X-Forwarded-Ssl: on - X-Forwarded-Proto: http - - ``InvalidSchemeHeaders()`` raised - - IP address allowed, but the two secure headers disagreed on if HTTPS was used - - - """ - - -class AccessLog(Setting): - name = "accesslog" - section = "Logging" - cli = ["--access-logfile"] - meta = "FILE" - validator = validate_string - default = None - desc = """\ - The Access log file to write to. - - ``'-'`` means log to stdout. - """ - - -class DisableRedirectAccessToSyslog(Setting): - name = "disable_redirect_access_to_syslog" - section = "Logging" - cli = ["--disable-redirect-access-to-syslog"] - validator = validate_bool - action = 'store_true' - default = False - desc = """\ - Disable redirect access logs to syslog. - - .. versionadded:: 19.8 - """ - - -class AccessLogFormat(Setting): - name = "access_log_format" - section = "Logging" - cli = ["--access-logformat"] - meta = "STRING" - validator = validate_string - default = '%(h)s %(l)s %(u)s %(t)s "%(r)s" %(s)s %(b)s "%(f)s" "%(a)s"' - desc = """\ - The access log format. - - =========== =========== - Identifier Description - =========== =========== - h remote address - l ``'-'`` - u user name (if HTTP Basic auth used) - t date of the request - r status line (e.g. ``GET / HTTP/1.1``) - m request method - U URL path without query string - q query string - H protocol - s status - B response length - b response length or ``'-'`` (CLF format) - f referrer (note: header is ``referer``) - a user agent - T request time in seconds - M request time in milliseconds - D request time in microseconds - L request time in decimal seconds - p process ID - {header}i request header - {header}o response header - {variable}e environment variable - =========== =========== - - Use lowercase for header and environment variable names, and put - ``{...}x`` names inside ``%(...)s``. For example:: - - %({x-forwarded-for}i)s - """ - - -class ErrorLog(Setting): - name = "errorlog" - section = "Logging" - cli = ["--error-logfile", "--log-file"] - meta = "FILE" - validator = validate_string - default = '-' - desc = """\ - The Error log file to write to. - - Using ``'-'`` for FILE makes gunicorn log to stderr. - - .. versionchanged:: 19.2 - Log to stderr by default. - - """ - - -class Loglevel(Setting): - name = "loglevel" - section = "Logging" - cli = ["--log-level"] - meta = "LEVEL" - validator = validate_string - default = "info" - desc = """\ - The granularity of Error log outputs. - - Valid level names are: - - * ``'debug'`` - * ``'info'`` - * ``'warning'`` - * ``'error'`` - * ``'critical'`` - """ - - -class CaptureOutput(Setting): - name = "capture_output" - section = "Logging" - cli = ["--capture-output"] - validator = validate_bool - action = 'store_true' - default = False - desc = """\ - Redirect stdout/stderr to specified file in :ref:`errorlog`. - - .. versionadded:: 19.6 - """ - - -class LoggerClass(Setting): - name = "logger_class" - section = "Logging" - cli = ["--logger-class"] - meta = "STRING" - validator = validate_class - default = "gunicorn.glogging.Logger" - desc = """\ - The logger you want to use to log events in Gunicorn. - - The default class (``gunicorn.glogging.Logger``) handles most - normal usages in logging. It provides error and access logging. - - You can provide your own logger by giving Gunicorn a Python path to a - class that quacks like ``gunicorn.glogging.Logger``. - """ - - -class LogConfig(Setting): - name = "logconfig" - section = "Logging" - cli = ["--log-config"] - meta = "FILE" - validator = validate_string - default = None - desc = """\ - The log config file to use. - Gunicorn uses the standard Python logging module's Configuration - file format. - """ - - -class LogConfigDict(Setting): - name = "logconfig_dict" - section = "Logging" - validator = validate_dict - default = {} - desc = """\ - The log config dictionary to use, using the standard Python - logging module's dictionary configuration format. This option - takes precedence over the :ref:`logconfig` and :ref:`logconfig-json` options, - which uses the older file configuration format and JSON - respectively. - - Format: https://docs.python.org/3/library/logging.config.html#logging.config.dictConfig - - For more context you can look at the default configuration dictionary for logging, - which can be found at ``gunicorn.glogging.CONFIG_DEFAULTS``. - - .. versionadded:: 19.8 - """ - - -class LogConfigJson(Setting): - name = "logconfig_json" - section = "Logging" - cli = ["--log-config-json"] - meta = "FILE" - validator = validate_string - default = None - desc = """\ - The log config to read config from a JSON file - - Format: https://docs.python.org/3/library/logging.config.html#logging.config.jsonConfig - - .. versionadded:: 20.0 - """ - - -class SyslogTo(Setting): - name = "syslog_addr" - section = "Logging" - cli = ["--log-syslog-to"] - meta = "SYSLOG_ADDR" - validator = validate_string - - if PLATFORM == "darwin": - default = "unix:///var/run/syslog" - elif PLATFORM in ('freebsd', 'dragonfly', ): - default = "unix:///var/run/log" - elif PLATFORM == "openbsd": - default = "unix:///dev/log" - else: - default = "udp://localhost:514" - - desc = """\ - Address to send syslog messages. - - Address is a string of the form: - - * ``unix://PATH#TYPE`` : for unix domain socket. ``TYPE`` can be ``stream`` - for the stream driver or ``dgram`` for the dgram driver. - ``stream`` is the default. - * ``udp://HOST:PORT`` : for UDP sockets - * ``tcp://HOST:PORT`` : for TCP sockets - - """ - - -class Syslog(Setting): - name = "syslog" - section = "Logging" - cli = ["--log-syslog"] - validator = validate_bool - action = 'store_true' - default = False - desc = """\ - Send *Gunicorn* logs to syslog. - - .. versionchanged:: 19.8 - You can now disable sending access logs by using the - :ref:`disable-redirect-access-to-syslog` setting. - """ - - -class SyslogPrefix(Setting): - name = "syslog_prefix" - section = "Logging" - cli = ["--log-syslog-prefix"] - meta = "SYSLOG_PREFIX" - validator = validate_string - default = None - desc = """\ - Makes Gunicorn use the parameter as program-name in the syslog entries. - - All entries will be prefixed by ``gunicorn.``. By default the - program name is the name of the process. - """ - - -class SyslogFacility(Setting): - name = "syslog_facility" - section = "Logging" - cli = ["--log-syslog-facility"] - meta = "SYSLOG_FACILITY" - validator = validate_string - default = "user" - desc = """\ - Syslog facility name - """ - - -class EnableStdioInheritance(Setting): - name = "enable_stdio_inheritance" - section = "Logging" - cli = ["-R", "--enable-stdio-inheritance"] - validator = validate_bool - default = False - action = "store_true" - desc = """\ - Enable stdio inheritance. - - Enable inheritance for stdio file descriptors in daemon mode. - - Note: To disable the Python stdout buffering, you can to set the user - environment variable ``PYTHONUNBUFFERED`` . - """ - - -# statsD monitoring -class StatsdHost(Setting): - name = "statsd_host" - section = "Logging" - cli = ["--statsd-host"] - meta = "STATSD_ADDR" - default = None - validator = validate_statsd_address - desc = """\ - The address of the StatsD server to log to. - - Address is a string of the form: - - * ``unix://PATH`` : for a unix domain socket. - * ``HOST:PORT`` : for a network address - - .. versionadded:: 19.1 - """ - - -# Datadog Statsd (dogstatsd) tags. https://docs.datadoghq.com/developers/dogstatsd/ -class DogstatsdTags(Setting): - name = "dogstatsd_tags" - section = "Logging" - cli = ["--dogstatsd-tags"] - meta = "DOGSTATSD_TAGS" - default = "" - validator = validate_string - desc = """\ - A comma-delimited list of datadog statsd (dogstatsd) tags to append to - statsd metrics. - - .. versionadded:: 20 - """ - - -class StatsdPrefix(Setting): - name = "statsd_prefix" - section = "Logging" - cli = ["--statsd-prefix"] - meta = "STATSD_PREFIX" - default = "" - validator = validate_string - desc = """\ - Prefix to use when emitting statsd metrics (a trailing ``.`` is added, - if not provided). - - .. versionadded:: 19.2 - """ - - -class Procname(Setting): - name = "proc_name" - section = "Process Naming" - cli = ["-n", "--name"] - meta = "STRING" - validator = validate_string - default = None - desc = """\ - A base to use with setproctitle for process naming. - - This affects things like ``ps`` and ``top``. If you're going to be - running more than one instance of Gunicorn you'll probably want to set a - name to tell them apart. This requires that you install the setproctitle - module. - - If not set, the *default_proc_name* setting will be used. - """ - - -class DefaultProcName(Setting): - name = "default_proc_name" - section = "Process Naming" - validator = validate_string - default = "gunicorn" - desc = """\ - Internal setting that is adjusted for each type of application. - """ - - -class PythonPath(Setting): - name = "pythonpath" - section = "Server Mechanics" - cli = ["--pythonpath"] - meta = "STRING" - validator = validate_string - default = None - desc = """\ - A comma-separated list of directories to add to the Python path. - - e.g. - ``'/home/djangoprojects/myproject,/home/python/mylibrary'``. - """ - - -class Paste(Setting): - name = "paste" - section = "Server Mechanics" - cli = ["--paste", "--paster"] - meta = "STRING" - validator = validate_string - default = None - desc = """\ - Load a PasteDeploy config file. The argument may contain a ``#`` - symbol followed by the name of an app section from the config file, - e.g. ``production.ini#admin``. - - At this time, using alternate server blocks is not supported. Use the - command line arguments to control server configuration instead. - """ - - -class OnStarting(Setting): - name = "on_starting" - section = "Server Hooks" - validator = validate_callable(1) - type = callable - - def on_starting(server): - pass - default = staticmethod(on_starting) - desc = """\ - Called just before the master process is initialized. - - The callable needs to accept a single instance variable for the Arbiter. - """ - - -class OnReload(Setting): - name = "on_reload" - section = "Server Hooks" - validator = validate_callable(1) - type = callable - - def on_reload(server): - pass - default = staticmethod(on_reload) - desc = """\ - Called to recycle workers during a reload via SIGHUP. - - The callable needs to accept a single instance variable for the Arbiter. - """ - - -class WhenReady(Setting): - name = "when_ready" - section = "Server Hooks" - validator = validate_callable(1) - type = callable - - def when_ready(server): - pass - default = staticmethod(when_ready) - desc = """\ - Called just after the server is started. - - The callable needs to accept a single instance variable for the Arbiter. - """ - - -class Prefork(Setting): - name = "pre_fork" - section = "Server Hooks" - validator = validate_callable(2) - type = callable - - def pre_fork(server, worker): - pass - default = staticmethod(pre_fork) - desc = """\ - Called just before a worker is forked. - - The callable needs to accept two instance variables for the Arbiter and - new Worker. - """ - - -class Postfork(Setting): - name = "post_fork" - section = "Server Hooks" - validator = validate_callable(2) - type = callable - - def post_fork(server, worker): - pass - default = staticmethod(post_fork) - desc = """\ - Called just after a worker has been forked. - - The callable needs to accept two instance variables for the Arbiter and - new Worker. - """ - - -class PostWorkerInit(Setting): - name = "post_worker_init" - section = "Server Hooks" - validator = validate_callable(1) - type = callable - - def post_worker_init(worker): - pass - - default = staticmethod(post_worker_init) - desc = """\ - Called just after a worker has initialized the application. - - The callable needs to accept one instance variable for the initialized - Worker. - """ - - -class WorkerInt(Setting): - name = "worker_int" - section = "Server Hooks" - validator = validate_callable(1) - type = callable - - def worker_int(worker): - pass - - default = staticmethod(worker_int) - desc = """\ - Called just after a worker exited on SIGINT or SIGQUIT. - - The callable needs to accept one instance variable for the initialized - Worker. - """ - - -class WorkerAbort(Setting): - name = "worker_abort" - section = "Server Hooks" - validator = validate_callable(1) - type = callable - - def worker_abort(worker): - pass - - default = staticmethod(worker_abort) - desc = """\ - Called when a worker received the SIGABRT signal. - - This call generally happens on timeout. - - The callable needs to accept one instance variable for the initialized - Worker. - """ - - -class PreExec(Setting): - name = "pre_exec" - section = "Server Hooks" - validator = validate_callable(1) - type = callable - - def pre_exec(server): - pass - default = staticmethod(pre_exec) - desc = """\ - Called just before a new master process is forked. - - The callable needs to accept a single instance variable for the Arbiter. - """ - - -class PreRequest(Setting): - name = "pre_request" - section = "Server Hooks" - validator = validate_callable(2) - type = callable - - def pre_request(worker, req): - worker.log.debug("%s %s", req.method, req.path) - default = staticmethod(pre_request) - desc = """\ - Called just before a worker processes the request. - - The callable needs to accept two instance variables for the Worker and - the Request. - """ - - -class PostRequest(Setting): - name = "post_request" - section = "Server Hooks" - validator = validate_post_request - type = callable - - def post_request(worker, req, environ, resp): - pass - default = staticmethod(post_request) - desc = """\ - Called after a worker processes the request. - - The callable needs to accept two instance variables for the Worker and - the Request. - """ - - -class ChildExit(Setting): - name = "child_exit" - section = "Server Hooks" - validator = validate_callable(2) - type = callable - - def child_exit(server, worker): - pass - default = staticmethod(child_exit) - desc = """\ - Called just after a worker has been exited, in the master process. - - The callable needs to accept two instance variables for the Arbiter and - the just-exited Worker. - - .. versionadded:: 19.7 - """ - - -class WorkerExit(Setting): - name = "worker_exit" - section = "Server Hooks" - validator = validate_callable(2) - type = callable - - def worker_exit(server, worker): - pass - default = staticmethod(worker_exit) - desc = """\ - Called just after a worker has been exited, in the worker process. - - The callable needs to accept two instance variables for the Arbiter and - the just-exited Worker. - """ - - -class NumWorkersChanged(Setting): - name = "nworkers_changed" - section = "Server Hooks" - validator = validate_callable(3) - type = callable - - def nworkers_changed(server, new_value, old_value): - pass - default = staticmethod(nworkers_changed) - desc = """\ - Called just after *num_workers* has been changed. - - The callable needs to accept an instance variable of the Arbiter and - two integers of number of workers after and before change. - - If the number of workers is set for the first time, *old_value* would - be ``None``. - """ - - -class OnExit(Setting): - name = "on_exit" - section = "Server Hooks" - validator = validate_callable(1) - - def on_exit(server): - pass - - default = staticmethod(on_exit) - desc = """\ - Called just before exiting Gunicorn. - - The callable needs to accept a single instance variable for the Arbiter. - """ - - -class NewSSLContext(Setting): - name = "ssl_context" - section = "Server Hooks" - validator = validate_callable(2) - type = callable - - def ssl_context(config, default_ssl_context_factory): - return default_ssl_context_factory() - - default = staticmethod(ssl_context) - desc = """\ - Called when SSLContext is needed. - - Allows customizing SSL context. - - The callable needs to accept an instance variable for the Config and - a factory function that returns default SSLContext which is initialized - with certificates, private key, cert_reqs, and ciphers according to - config and can be further customized by the callable. - The callable needs to return SSLContext object. - - Following example shows a configuration file that sets the minimum TLS version to 1.3: - - .. code-block:: python - - def ssl_context(conf, default_ssl_context_factory): - import ssl - context = default_ssl_context_factory() - context.minimum_version = ssl.TLSVersion.TLSv1_3 - return context - - .. versionadded:: 21.0 - """ - - -class ProxyProtocol(Setting): - name = "proxy_protocol" - section = "Server Mechanics" - cli = ["--proxy-protocol"] - validator = validate_bool - default = False - action = "store_true" - desc = """\ - Enable detect PROXY protocol (PROXY mode). - - Allow using HTTP and Proxy together. It may be useful for work with - stunnel as HTTPS frontend and Gunicorn as HTTP server. - - PROXY protocol: http://haproxy.1wt.eu/download/1.5/doc/proxy-protocol.txt - - Example for stunnel config:: - - [https] - protocol = proxy - accept = 443 - connect = 80 - cert = /etc/ssl/certs/stunnel.pem - key = /etc/ssl/certs/stunnel.key - """ - - -class ProxyAllowFrom(Setting): - name = "proxy_allow_ips" - section = "Server Mechanics" - cli = ["--proxy-allow-from"] - validator = validate_string_to_addr_list - default = "127.0.0.1,::1" - desc = """\ - Front-end's IPs from which allowed accept proxy requests (comma separated). - - Set to ``*`` to disable checking of front-end IPs. This is useful for setups - where you don't know in advance the IP address of front-end, but - instead have ensured via other means that only your - authorized front-ends can access Gunicorn. - - .. note:: - - This option does not affect UNIX socket connections. Connections not associated with - an IP address are treated as allowed, unconditionally. - """ - - -class KeyFile(Setting): - name = "keyfile" - section = "SSL" - cli = ["--keyfile"] - meta = "FILE" - validator = validate_string - default = None - desc = """\ - SSL key file - """ - - -class CertFile(Setting): - name = "certfile" - section = "SSL" - cli = ["--certfile"] - meta = "FILE" - validator = validate_string - default = None - desc = """\ - SSL certificate file - """ - - -class SSLVersion(Setting): - name = "ssl_version" - section = "SSL" - cli = ["--ssl-version"] - validator = validate_ssl_version - - if hasattr(ssl, "PROTOCOL_TLS"): - default = ssl.PROTOCOL_TLS - else: - default = ssl.PROTOCOL_SSLv23 - - default = ssl.PROTOCOL_SSLv23 - desc = """\ - SSL version to use (see stdlib ssl module's). - - .. deprecated:: 21.0 - The option is deprecated and it is currently ignored. Use :ref:`ssl-context` instead. - - ============= ============ - --ssl-version Description - ============= ============ - SSLv3 SSLv3 is not-secure and is strongly discouraged. - SSLv23 Alias for TLS. Deprecated in Python 3.6, use TLS. - TLS Negotiate highest possible version between client/server. - Can yield SSL. (Python 3.6+) - TLSv1 TLS 1.0 - TLSv1_1 TLS 1.1 (Python 3.4+) - TLSv1_2 TLS 1.2 (Python 3.4+) - TLS_SERVER Auto-negotiate the highest protocol version like TLS, - but only support server-side SSLSocket connections. - (Python 3.6+) - ============= ============ - - .. versionchanged:: 19.7 - The default value has been changed from ``ssl.PROTOCOL_TLSv1`` to - ``ssl.PROTOCOL_SSLv23``. - .. versionchanged:: 20.0 - This setting now accepts string names based on ``ssl.PROTOCOL_`` - constants. - .. versionchanged:: 20.0.1 - The default value has been changed from ``ssl.PROTOCOL_SSLv23`` to - ``ssl.PROTOCOL_TLS`` when Python >= 3.6 . - """ - - -class CertReqs(Setting): - name = "cert_reqs" - section = "SSL" - cli = ["--cert-reqs"] - validator = validate_pos_int - default = ssl.CERT_NONE - desc = """\ - Whether client certificate is required (see stdlib ssl module's) - - =========== =========================== - --cert-reqs Description - =========== =========================== - `0` no client verification - `1` ssl.CERT_OPTIONAL - `2` ssl.CERT_REQUIRED - =========== =========================== - """ - - -class CACerts(Setting): - name = "ca_certs" - section = "SSL" - cli = ["--ca-certs"] - meta = "FILE" - validator = validate_string - default = None - desc = """\ - CA certificates file - """ - - -class SuppressRaggedEOFs(Setting): - name = "suppress_ragged_eofs" - section = "SSL" - cli = ["--suppress-ragged-eofs"] - action = "store_true" - default = True - validator = validate_bool - desc = """\ - Suppress ragged EOFs (see stdlib ssl module's) - """ - - -class DoHandshakeOnConnect(Setting): - name = "do_handshake_on_connect" - section = "SSL" - cli = ["--do-handshake-on-connect"] - validator = validate_bool - action = "store_true" - default = False - desc = """\ - Whether to perform SSL handshake on socket connect (see stdlib ssl module's) - """ - - -class Ciphers(Setting): - name = "ciphers" - section = "SSL" - cli = ["--ciphers"] - validator = validate_string - default = None - desc = """\ - SSL Cipher suite to use, in the format of an OpenSSL cipher list. - - By default we use the default cipher list from Python's ``ssl`` module, - which contains ciphers considered strong at the time of each Python - release. - - As a recommended alternative, the Open Web App Security Project (OWASP) - offers `a vetted set of strong cipher strings rated A+ to C- - `_. - OWASP provides details on user-agent compatibility at each security level. - - See the `OpenSSL Cipher List Format Documentation - `_ - for details on the format of an OpenSSL cipher list. - """ - - -class PasteGlobalConf(Setting): - name = "raw_paste_global_conf" - action = "append" - section = "Server Mechanics" - cli = ["--paste-global"] - meta = "CONF" - validator = validate_list_string - default = [] - - desc = """\ - Set a PasteDeploy global config variable in ``key=value`` form. - - The option can be specified multiple times. - - The variables are passed to the PasteDeploy entrypoint. Example:: - - $ gunicorn -b 127.0.0.1:8000 --paste development.ini --paste-global FOO=1 --paste-global BAR=2 - - .. versionadded:: 19.7 - """ - - -class PermitObsoleteFolding(Setting): - name = "permit_obsolete_folding" - section = "Server Mechanics" - cli = ["--permit-obsolete-folding"] - validator = validate_bool - action = "store_true" - default = False - desc = """\ - Permit requests employing obsolete HTTP line folding mechanism - - The folding mechanism was deprecated by rfc7230 Section 3.2.4 and will not be - employed in HTTP request headers from standards-compliant HTTP clients. - - This option is provided to diagnose backwards-incompatible changes. - Use with care and only if necessary. Temporary; the precise effect of this option may - change in a future version, or it may be removed altogether. - - .. versionadded:: 23.0.0 - """ - - -class StripHeaderSpaces(Setting): - name = "strip_header_spaces" - section = "Server Mechanics" - cli = ["--strip-header-spaces"] - validator = validate_bool - action = "store_true" - default = False - desc = """\ - Strip spaces present between the header name and the the ``:``. - - This is known to induce vulnerabilities and is not compliant with the HTTP/1.1 standard. - See https://portswigger.net/research/http-desync-attacks-request-smuggling-reborn. - - Use with care and only if necessary. Deprecated; scheduled for removal in 25.0.0 - - .. versionadded:: 20.0.1 - """ - - -class PermitUnconventionalHTTPMethod(Setting): - name = "permit_unconventional_http_method" - section = "Server Mechanics" - cli = ["--permit-unconventional-http-method"] - validator = validate_bool - action = "store_true" - default = False - desc = """\ - Permit HTTP methods not matching conventions, such as IANA registration guidelines - - This permits request methods of length less than 3 or more than 20, - methods with lowercase characters or methods containing the # character. - HTTP methods are case sensitive by definition, and merely uppercase by convention. - - If unset, Gunicorn will apply nonstandard restrictions and cause 400 response status - in cases where otherwise 501 status is expected. While this option does modify that - behaviour, it should not be depended upon to guarantee standards-compliant behaviour. - Rather, it is provided temporarily, to assist in diagnosing backwards-incompatible - changes around the incomplete application of those restrictions. - - Use with care and only if necessary. Temporary; scheduled for removal in 24.0.0 - - .. versionadded:: 22.0.0 - """ - - -class PermitUnconventionalHTTPVersion(Setting): - name = "permit_unconventional_http_version" - section = "Server Mechanics" - cli = ["--permit-unconventional-http-version"] - validator = validate_bool - action = "store_true" - default = False - desc = """\ - Permit HTTP version not matching conventions of 2023 - - This disables the refusal of likely malformed request lines. - It is unusual to specify HTTP 1 versions other than 1.0 and 1.1. - - This option is provided to diagnose backwards-incompatible changes. - Use with care and only if necessary. Temporary; the precise effect of this option may - change in a future version, or it may be removed altogether. - - .. versionadded:: 22.0.0 - """ - - -class CasefoldHTTPMethod(Setting): - name = "casefold_http_method" - section = "Server Mechanics" - cli = ["--casefold-http-method"] - validator = validate_bool - action = "store_true" - default = False - desc = """\ - Transform received HTTP methods to uppercase - - HTTP methods are case sensitive by definition, and merely uppercase by convention. - - This option is provided because previous versions of gunicorn defaulted to this behaviour. - - Use with care and only if necessary. Deprecated; scheduled for removal in 24.0.0 - - .. versionadded:: 22.0.0 - """ - - -def validate_header_map_behaviour(val): - # FIXME: refactor all of this subclassing stdlib argparse - - if val is None: - return - - if not isinstance(val, str): - raise TypeError("Invalid type for casting: %s" % val) - if val.lower().strip() == "drop": - return "drop" - elif val.lower().strip() == "refuse": - return "refuse" - elif val.lower().strip() == "dangerous": - return "dangerous" - else: - raise ValueError("Invalid header map behaviour: %s" % val) - - -class ForwarderHeaders(Setting): - name = "forwarder_headers" - section = "Server Mechanics" - cli = ["--forwarder-headers"] - validator = validate_string_to_list - default = "SCRIPT_NAME,PATH_INFO" - desc = """\ - - A list containing upper-case header field names that the front-end proxy - (see :ref:`forwarded-allow-ips`) sets, to be used in WSGI environment. - - This option has no effect for headers not present in the request. - - This option can be used to transfer ``SCRIPT_NAME``, ``PATH_INFO`` - and ``REMOTE_USER``. - - It is important that your front-end proxy configuration ensures that - the headers defined here can not be passed directly from the client. - """ - - -class HeaderMap(Setting): - name = "header_map" - section = "Server Mechanics" - cli = ["--header-map"] - validator = validate_header_map_behaviour - default = "drop" - desc = """\ - Configure how header field names are mapped into environ - - Headers containing underscores are permitted by RFC9110, - but gunicorn joining headers of different names into - the same environment variable will dangerously confuse applications as to which is which. - - The safe default ``drop`` is to silently drop headers that cannot be unambiguously mapped. - The value ``refuse`` will return an error if a request contains *any* such header. - The value ``dangerous`` matches the previous, not advisable, behaviour of mapping different - header field names into the same environ name. - - If the source is permitted as explained in :ref:`forwarded-allow-ips`, *and* the header name is - present in :ref:`forwarder-headers`, the header is mapped into environment regardless of - the state of this setting. - - Use with care and only if necessary and after considering if your problem could - instead be solved by specifically renaming or rewriting only the intended headers - on a proxy in front of Gunicorn. - - .. versionadded:: 22.0.0 - """ diff --git a/venv/lib/python3.9/site-packages/gunicorn/debug.py b/venv/lib/python3.9/site-packages/gunicorn/debug.py deleted file mode 100644 index 5fae0b4..0000000 --- a/venv/lib/python3.9/site-packages/gunicorn/debug.py +++ /dev/null @@ -1,68 +0,0 @@ -# -# This file is part of gunicorn released under the MIT license. -# See the NOTICE for more information. - -"""The debug module contains utilities and functions for better -debugging Gunicorn.""" - -import sys -import linecache -import re -import inspect - -__all__ = ['spew', 'unspew'] - -_token_spliter = re.compile(r'\W+') - - -class Spew: - - def __init__(self, trace_names=None, show_values=True): - self.trace_names = trace_names - self.show_values = show_values - - def __call__(self, frame, event, arg): - if event == 'line': - lineno = frame.f_lineno - if '__file__' in frame.f_globals: - filename = frame.f_globals['__file__'] - if (filename.endswith('.pyc') or - filename.endswith('.pyo')): - filename = filename[:-1] - name = frame.f_globals['__name__'] - line = linecache.getline(filename, lineno) - else: - name = '[unknown]' - try: - src = inspect.getsourcelines(frame) - line = src[lineno] - except OSError: - line = 'Unknown code named [%s]. VM instruction #%d' % ( - frame.f_code.co_name, frame.f_lasti) - if self.trace_names is None or name in self.trace_names: - print('%s:%s: %s' % (name, lineno, line.rstrip())) - if not self.show_values: - return self - details = [] - tokens = _token_spliter.split(line) - for tok in tokens: - if tok in frame.f_globals: - details.append('%s=%r' % (tok, frame.f_globals[tok])) - if tok in frame.f_locals: - details.append('%s=%r' % (tok, frame.f_locals[tok])) - if details: - print("\t%s" % ' '.join(details)) - return self - - -def spew(trace_names=None, show_values=False): - """Install a trace hook which writes incredibly detailed logs - about what code is being executed to stdout. - """ - sys.settrace(Spew(trace_names, show_values)) - - -def unspew(): - """Remove the trace hook installed by spew. - """ - sys.settrace(None) diff --git a/venv/lib/python3.9/site-packages/gunicorn/errors.py b/venv/lib/python3.9/site-packages/gunicorn/errors.py deleted file mode 100644 index 1128380..0000000 --- a/venv/lib/python3.9/site-packages/gunicorn/errors.py +++ /dev/null @@ -1,28 +0,0 @@ -# -# This file is part of gunicorn released under the MIT license. -# See the NOTICE for more information. - -# We don't need to call super() in __init__ methods of our -# BaseException and Exception classes because we also define -# our own __str__ methods so there is no need to pass 'message' -# to the base class to get a meaningful output from 'str(exc)'. -# pylint: disable=super-init-not-called - - -# we inherit from BaseException here to make sure to not be caught -# at application level -class HaltServer(BaseException): - def __init__(self, reason, exit_status=1): - self.reason = reason - self.exit_status = exit_status - - def __str__(self): - return "" % (self.reason, self.exit_status) - - -class ConfigError(Exception): - """ Exception raised on config error """ - - -class AppImportError(Exception): - """ Exception raised when loading an application """ diff --git a/venv/lib/python3.9/site-packages/gunicorn/glogging.py b/venv/lib/python3.9/site-packages/gunicorn/glogging.py deleted file mode 100644 index e34fcd5..0000000 --- a/venv/lib/python3.9/site-packages/gunicorn/glogging.py +++ /dev/null @@ -1,473 +0,0 @@ -# -# This file is part of gunicorn released under the MIT license. -# See the NOTICE for more information. - -import base64 -import binascii -import json -import time -import logging -logging.Logger.manager.emittedNoHandlerWarning = 1 # noqa -from logging.config import dictConfig -from logging.config import fileConfig -import os -import socket -import sys -import threading -import traceback - -from gunicorn import util - - -# syslog facility codes -SYSLOG_FACILITIES = { - "auth": 4, - "authpriv": 10, - "cron": 9, - "daemon": 3, - "ftp": 11, - "kern": 0, - "lpr": 6, - "mail": 2, - "news": 7, - "security": 4, # DEPRECATED - "syslog": 5, - "user": 1, - "uucp": 8, - "local0": 16, - "local1": 17, - "local2": 18, - "local3": 19, - "local4": 20, - "local5": 21, - "local6": 22, - "local7": 23 -} - -CONFIG_DEFAULTS = { - "version": 1, - "disable_existing_loggers": False, - "root": {"level": "INFO", "handlers": ["console"]}, - "loggers": { - "gunicorn.error": { - "level": "INFO", - "handlers": ["error_console"], - "propagate": True, - "qualname": "gunicorn.error" - }, - - "gunicorn.access": { - "level": "INFO", - "handlers": ["console"], - "propagate": True, - "qualname": "gunicorn.access" - } - }, - "handlers": { - "console": { - "class": "logging.StreamHandler", - "formatter": "generic", - "stream": "ext://sys.stdout" - }, - "error_console": { - "class": "logging.StreamHandler", - "formatter": "generic", - "stream": "ext://sys.stderr" - }, - }, - "formatters": { - "generic": { - "format": "%(asctime)s [%(process)d] [%(levelname)s] %(message)s", - "datefmt": "[%Y-%m-%d %H:%M:%S %z]", - "class": "logging.Formatter" - } - } -} - - -def loggers(): - """ get list of all loggers """ - root = logging.root - existing = list(root.manager.loggerDict.keys()) - return [logging.getLogger(name) for name in existing] - - -class SafeAtoms(dict): - - def __init__(self, atoms): - dict.__init__(self) - for key, value in atoms.items(): - if isinstance(value, str): - self[key] = value.replace('"', '\\"') - else: - self[key] = value - - def __getitem__(self, k): - if k.startswith("{"): - kl = k.lower() - if kl in self: - return super().__getitem__(kl) - else: - return "-" - if k in self: - return super().__getitem__(k) - else: - return '-' - - -def parse_syslog_address(addr): - - # unix domain socket type depends on backend - # SysLogHandler will try both when given None - if addr.startswith("unix://"): - sock_type = None - - # set socket type only if explicitly requested - parts = addr.split("#", 1) - if len(parts) == 2: - addr = parts[0] - if parts[1] == "dgram": - sock_type = socket.SOCK_DGRAM - - return (sock_type, addr.split("unix://")[1]) - - if addr.startswith("udp://"): - addr = addr.split("udp://")[1] - socktype = socket.SOCK_DGRAM - elif addr.startswith("tcp://"): - addr = addr.split("tcp://")[1] - socktype = socket.SOCK_STREAM - else: - raise RuntimeError("invalid syslog address") - - if '[' in addr and ']' in addr: - host = addr.split(']')[0][1:].lower() - elif ':' in addr: - host = addr.split(':')[0].lower() - elif addr == "": - host = "localhost" - else: - host = addr.lower() - - addr = addr.split(']')[-1] - if ":" in addr: - port = addr.split(':', 1)[1] - if not port.isdigit(): - raise RuntimeError("%r is not a valid port number." % port) - port = int(port) - else: - port = 514 - - return (socktype, (host, port)) - - -class Logger: - - LOG_LEVELS = { - "critical": logging.CRITICAL, - "error": logging.ERROR, - "warning": logging.WARNING, - "info": logging.INFO, - "debug": logging.DEBUG - } - loglevel = logging.INFO - - error_fmt = r"%(asctime)s [%(process)d] [%(levelname)s] %(message)s" - datefmt = r"[%Y-%m-%d %H:%M:%S %z]" - - access_fmt = "%(message)s" - syslog_fmt = "[%(process)d] %(message)s" - - atoms_wrapper_class = SafeAtoms - - def __init__(self, cfg): - self.error_log = logging.getLogger("gunicorn.error") - self.error_log.propagate = False - self.access_log = logging.getLogger("gunicorn.access") - self.access_log.propagate = False - self.error_handlers = [] - self.access_handlers = [] - self.logfile = None - self.lock = threading.Lock() - self.cfg = cfg - self.setup(cfg) - - def setup(self, cfg): - self.loglevel = self.LOG_LEVELS.get(cfg.loglevel.lower(), logging.INFO) - self.error_log.setLevel(self.loglevel) - self.access_log.setLevel(logging.INFO) - - # set gunicorn.error handler - if self.cfg.capture_output and cfg.errorlog != "-": - for stream in sys.stdout, sys.stderr: - stream.flush() - - self.logfile = open(cfg.errorlog, 'a+') - os.dup2(self.logfile.fileno(), sys.stdout.fileno()) - os.dup2(self.logfile.fileno(), sys.stderr.fileno()) - - self._set_handler(self.error_log, cfg.errorlog, - logging.Formatter(self.error_fmt, self.datefmt)) - - # set gunicorn.access handler - if cfg.accesslog is not None: - self._set_handler( - self.access_log, cfg.accesslog, - fmt=logging.Formatter(self.access_fmt), stream=sys.stdout - ) - - # set syslog handler - if cfg.syslog: - self._set_syslog_handler( - self.error_log, cfg, self.syslog_fmt, "error" - ) - if not cfg.disable_redirect_access_to_syslog: - self._set_syslog_handler( - self.access_log, cfg, self.syslog_fmt, "access" - ) - - if cfg.logconfig_dict: - config = CONFIG_DEFAULTS.copy() - config.update(cfg.logconfig_dict) - try: - dictConfig(config) - except ( - AttributeError, - ImportError, - ValueError, - TypeError - ) as exc: - raise RuntimeError(str(exc)) - elif cfg.logconfig_json: - config = CONFIG_DEFAULTS.copy() - if os.path.exists(cfg.logconfig_json): - try: - config_json = json.load(open(cfg.logconfig_json)) - config.update(config_json) - dictConfig(config) - except ( - json.JSONDecodeError, - AttributeError, - ImportError, - ValueError, - TypeError - ) as exc: - raise RuntimeError(str(exc)) - elif cfg.logconfig: - if os.path.exists(cfg.logconfig): - defaults = CONFIG_DEFAULTS.copy() - defaults['__file__'] = cfg.logconfig - defaults['here'] = os.path.dirname(cfg.logconfig) - fileConfig(cfg.logconfig, defaults=defaults, - disable_existing_loggers=False) - else: - msg = "Error: log config '%s' not found" - raise RuntimeError(msg % cfg.logconfig) - - def critical(self, msg, *args, **kwargs): - self.error_log.critical(msg, *args, **kwargs) - - def error(self, msg, *args, **kwargs): - self.error_log.error(msg, *args, **kwargs) - - def warning(self, msg, *args, **kwargs): - self.error_log.warning(msg, *args, **kwargs) - - def info(self, msg, *args, **kwargs): - self.error_log.info(msg, *args, **kwargs) - - def debug(self, msg, *args, **kwargs): - self.error_log.debug(msg, *args, **kwargs) - - def exception(self, msg, *args, **kwargs): - self.error_log.exception(msg, *args, **kwargs) - - def log(self, lvl, msg, *args, **kwargs): - if isinstance(lvl, str): - lvl = self.LOG_LEVELS.get(lvl.lower(), logging.INFO) - self.error_log.log(lvl, msg, *args, **kwargs) - - def atoms(self, resp, req, environ, request_time): - """ Gets atoms for log formatting. - """ - status = resp.status - if isinstance(status, str): - status = status.split(None, 1)[0] - atoms = { - 'h': environ.get('REMOTE_ADDR', '-'), - 'l': '-', - 'u': self._get_user(environ) or '-', - 't': self.now(), - 'r': "%s %s %s" % (environ['REQUEST_METHOD'], - environ['RAW_URI'], - environ["SERVER_PROTOCOL"]), - 's': status, - 'm': environ.get('REQUEST_METHOD'), - 'U': environ.get('PATH_INFO'), - 'q': environ.get('QUERY_STRING'), - 'H': environ.get('SERVER_PROTOCOL'), - 'b': getattr(resp, 'sent', None) is not None and str(resp.sent) or '-', - 'B': getattr(resp, 'sent', None), - 'f': environ.get('HTTP_REFERER', '-'), - 'a': environ.get('HTTP_USER_AGENT', '-'), - 'T': request_time.seconds, - 'D': (request_time.seconds * 1000000) + request_time.microseconds, - 'M': (request_time.seconds * 1000) + int(request_time.microseconds / 1000), - 'L': "%d.%06d" % (request_time.seconds, request_time.microseconds), - 'p': "<%s>" % os.getpid() - } - - # add request headers - if hasattr(req, 'headers'): - req_headers = req.headers - else: - req_headers = req - - if hasattr(req_headers, "items"): - req_headers = req_headers.items() - - atoms.update({"{%s}i" % k.lower(): v for k, v in req_headers}) - - resp_headers = resp.headers - if hasattr(resp_headers, "items"): - resp_headers = resp_headers.items() - - # add response headers - atoms.update({"{%s}o" % k.lower(): v for k, v in resp_headers}) - - # add environ variables - environ_variables = environ.items() - atoms.update({"{%s}e" % k.lower(): v for k, v in environ_variables}) - - return atoms - - def access(self, resp, req, environ, request_time): - """ See http://httpd.apache.org/docs/2.0/logs.html#combined - for format details - """ - - if not (self.cfg.accesslog or self.cfg.logconfig or - self.cfg.logconfig_dict or self.cfg.logconfig_json or - (self.cfg.syslog and not self.cfg.disable_redirect_access_to_syslog)): - return - - # wrap atoms: - # - make sure atoms will be test case insensitively - # - if atom doesn't exist replace it by '-' - safe_atoms = self.atoms_wrapper_class( - self.atoms(resp, req, environ, request_time) - ) - - try: - self.access_log.info(self.cfg.access_log_format, safe_atoms) - except Exception: - self.error(traceback.format_exc()) - - def now(self): - """ return date in Apache Common Log Format """ - return time.strftime('[%d/%b/%Y:%H:%M:%S %z]') - - def reopen_files(self): - if self.cfg.capture_output and self.cfg.errorlog != "-": - for stream in sys.stdout, sys.stderr: - stream.flush() - - with self.lock: - if self.logfile is not None: - self.logfile.close() - self.logfile = open(self.cfg.errorlog, 'a+') - os.dup2(self.logfile.fileno(), sys.stdout.fileno()) - os.dup2(self.logfile.fileno(), sys.stderr.fileno()) - - for log in loggers(): - for handler in log.handlers: - if isinstance(handler, logging.FileHandler): - handler.acquire() - try: - if handler.stream: - handler.close() - handler.stream = handler._open() - finally: - handler.release() - - def close_on_exec(self): - for log in loggers(): - for handler in log.handlers: - if isinstance(handler, logging.FileHandler): - handler.acquire() - try: - if handler.stream: - util.close_on_exec(handler.stream.fileno()) - finally: - handler.release() - - def _get_gunicorn_handler(self, log): - for h in log.handlers: - if getattr(h, "_gunicorn", False): - return h - - def _set_handler(self, log, output, fmt, stream=None): - # remove previous gunicorn log handler - h = self._get_gunicorn_handler(log) - if h: - log.handlers.remove(h) - - if output is not None: - if output == "-": - h = logging.StreamHandler(stream) - else: - util.check_is_writable(output) - h = logging.FileHandler(output) - # make sure the user can reopen the file - try: - os.chown(h.baseFilename, self.cfg.user, self.cfg.group) - except OSError: - # it's probably OK there, we assume the user has given - # /dev/null as a parameter. - pass - - h.setFormatter(fmt) - h._gunicorn = True - log.addHandler(h) - - def _set_syslog_handler(self, log, cfg, fmt, name): - # setup format - prefix = cfg.syslog_prefix or cfg.proc_name.replace(":", ".") - - prefix = "gunicorn.%s.%s" % (prefix, name) - - # set format - fmt = logging.Formatter(r"%s: %s" % (prefix, fmt)) - - # syslog facility - try: - facility = SYSLOG_FACILITIES[cfg.syslog_facility.lower()] - except KeyError: - raise RuntimeError("unknown facility name") - - # parse syslog address - socktype, addr = parse_syslog_address(cfg.syslog_addr) - - # finally setup the syslog handler - h = logging.handlers.SysLogHandler(address=addr, - facility=facility, socktype=socktype) - - h.setFormatter(fmt) - h._gunicorn = True - log.addHandler(h) - - def _get_user(self, environ): - user = None - http_auth = environ.get("HTTP_AUTHORIZATION") - if http_auth and http_auth.lower().startswith('basic'): - auth = http_auth.split(" ", 1) - if len(auth) == 2: - try: - # b64decode doesn't accept unicode in Python < 3.3 - # so we need to convert it to a byte string - auth = base64.b64decode(auth[1].strip().encode('utf-8')) - # b64decode returns a byte string - user = auth.split(b":", 1)[0].decode("UTF-8") - except (TypeError, binascii.Error, UnicodeDecodeError) as exc: - self.debug("Couldn't get username: %s", exc) - return user diff --git a/venv/lib/python3.9/site-packages/gunicorn/http/__init__.py b/venv/lib/python3.9/site-packages/gunicorn/http/__init__.py deleted file mode 100644 index 11473bb..0000000 --- a/venv/lib/python3.9/site-packages/gunicorn/http/__init__.py +++ /dev/null @@ -1,8 +0,0 @@ -# -# This file is part of gunicorn released under the MIT license. -# See the NOTICE for more information. - -from gunicorn.http.message import Message, Request -from gunicorn.http.parser import RequestParser - -__all__ = ['Message', 'Request', 'RequestParser'] diff --git a/venv/lib/python3.9/site-packages/gunicorn/http/body.py b/venv/lib/python3.9/site-packages/gunicorn/http/body.py deleted file mode 100644 index d7ee29e..0000000 --- a/venv/lib/python3.9/site-packages/gunicorn/http/body.py +++ /dev/null @@ -1,268 +0,0 @@ -# -# This file is part of gunicorn released under the MIT license. -# See the NOTICE for more information. - -import io -import sys - -from gunicorn.http.errors import (NoMoreData, ChunkMissingTerminator, - InvalidChunkSize) - - -class ChunkedReader: - def __init__(self, req, unreader): - self.req = req - self.parser = self.parse_chunked(unreader) - self.buf = io.BytesIO() - - def read(self, size): - if not isinstance(size, int): - raise TypeError("size must be an integer type") - if size < 0: - raise ValueError("Size must be positive.") - if size == 0: - return b"" - - if self.parser: - while self.buf.tell() < size: - try: - self.buf.write(next(self.parser)) - except StopIteration: - self.parser = None - break - - data = self.buf.getvalue() - ret, rest = data[:size], data[size:] - self.buf = io.BytesIO() - self.buf.write(rest) - return ret - - def parse_trailers(self, unreader, data): - buf = io.BytesIO() - buf.write(data) - - idx = buf.getvalue().find(b"\r\n\r\n") - done = buf.getvalue()[:2] == b"\r\n" - while idx < 0 and not done: - self.get_data(unreader, buf) - idx = buf.getvalue().find(b"\r\n\r\n") - done = buf.getvalue()[:2] == b"\r\n" - if done: - unreader.unread(buf.getvalue()[2:]) - return b"" - self.req.trailers = self.req.parse_headers(buf.getvalue()[:idx], from_trailer=True) - unreader.unread(buf.getvalue()[idx + 4:]) - - def parse_chunked(self, unreader): - (size, rest) = self.parse_chunk_size(unreader) - while size > 0: - while size > len(rest): - size -= len(rest) - yield rest - rest = unreader.read() - if not rest: - raise NoMoreData() - yield rest[:size] - # Remove \r\n after chunk - rest = rest[size:] - while len(rest) < 2: - new_data = unreader.read() - if not new_data: - break - rest += new_data - if rest[:2] != b'\r\n': - raise ChunkMissingTerminator(rest[:2]) - (size, rest) = self.parse_chunk_size(unreader, data=rest[2:]) - - def parse_chunk_size(self, unreader, data=None): - buf = io.BytesIO() - if data is not None: - buf.write(data) - - idx = buf.getvalue().find(b"\r\n") - while idx < 0: - self.get_data(unreader, buf) - idx = buf.getvalue().find(b"\r\n") - - data = buf.getvalue() - line, rest_chunk = data[:idx], data[idx + 2:] - - # RFC9112 7.1.1: BWS before chunk-ext - but ONLY then - chunk_size, *chunk_ext = line.split(b";", 1) - if chunk_ext: - chunk_size = chunk_size.rstrip(b" \t") - if any(n not in b"0123456789abcdefABCDEF" for n in chunk_size): - raise InvalidChunkSize(chunk_size) - if len(chunk_size) == 0: - raise InvalidChunkSize(chunk_size) - chunk_size = int(chunk_size, 16) - - if chunk_size == 0: - try: - self.parse_trailers(unreader, rest_chunk) - except NoMoreData: - pass - return (0, None) - return (chunk_size, rest_chunk) - - def get_data(self, unreader, buf): - data = unreader.read() - if not data: - raise NoMoreData() - buf.write(data) - - -class LengthReader: - def __init__(self, unreader, length): - self.unreader = unreader - self.length = length - - def read(self, size): - if not isinstance(size, int): - raise TypeError("size must be an integral type") - - size = min(self.length, size) - if size < 0: - raise ValueError("Size must be positive.") - if size == 0: - return b"" - - buf = io.BytesIO() - data = self.unreader.read() - while data: - buf.write(data) - if buf.tell() >= size: - break - data = self.unreader.read() - - buf = buf.getvalue() - ret, rest = buf[:size], buf[size:] - self.unreader.unread(rest) - self.length -= size - return ret - - -class EOFReader: - def __init__(self, unreader): - self.unreader = unreader - self.buf = io.BytesIO() - self.finished = False - - def read(self, size): - if not isinstance(size, int): - raise TypeError("size must be an integral type") - if size < 0: - raise ValueError("Size must be positive.") - if size == 0: - return b"" - - if self.finished: - data = self.buf.getvalue() - ret, rest = data[:size], data[size:] - self.buf = io.BytesIO() - self.buf.write(rest) - return ret - - data = self.unreader.read() - while data: - self.buf.write(data) - if self.buf.tell() > size: - break - data = self.unreader.read() - - if not data: - self.finished = True - - data = self.buf.getvalue() - ret, rest = data[:size], data[size:] - self.buf = io.BytesIO() - self.buf.write(rest) - return ret - - -class Body: - def __init__(self, reader): - self.reader = reader - self.buf = io.BytesIO() - - def __iter__(self): - return self - - def __next__(self): - ret = self.readline() - if not ret: - raise StopIteration() - return ret - - next = __next__ - - def getsize(self, size): - if size is None: - return sys.maxsize - elif not isinstance(size, int): - raise TypeError("size must be an integral type") - elif size < 0: - return sys.maxsize - return size - - def read(self, size=None): - size = self.getsize(size) - if size == 0: - return b"" - - if size < self.buf.tell(): - data = self.buf.getvalue() - ret, rest = data[:size], data[size:] - self.buf = io.BytesIO() - self.buf.write(rest) - return ret - - while size > self.buf.tell(): - data = self.reader.read(1024) - if not data: - break - self.buf.write(data) - - data = self.buf.getvalue() - ret, rest = data[:size], data[size:] - self.buf = io.BytesIO() - self.buf.write(rest) - return ret - - def readline(self, size=None): - size = self.getsize(size) - if size == 0: - return b"" - - data = self.buf.getvalue() - self.buf = io.BytesIO() - - ret = [] - while 1: - idx = data.find(b"\n", 0, size) - idx = idx + 1 if idx >= 0 else size if len(data) >= size else 0 - if idx: - ret.append(data[:idx]) - self.buf.write(data[idx:]) - break - - ret.append(data) - size -= len(data) - data = self.reader.read(min(1024, size)) - if not data: - break - - return b"".join(ret) - - def readlines(self, size=None): - ret = [] - data = self.read() - while data: - pos = data.find(b"\n") - if pos < 0: - ret.append(data) - data = b"" - else: - line, data = data[:pos + 1], data[pos + 1:] - ret.append(line) - return ret diff --git a/venv/lib/python3.9/site-packages/gunicorn/http/errors.py b/venv/lib/python3.9/site-packages/gunicorn/http/errors.py deleted file mode 100644 index bcb9700..0000000 --- a/venv/lib/python3.9/site-packages/gunicorn/http/errors.py +++ /dev/null @@ -1,145 +0,0 @@ -# -# This file is part of gunicorn released under the MIT license. -# See the NOTICE for more information. - -# We don't need to call super() in __init__ methods of our -# BaseException and Exception classes because we also define -# our own __str__ methods so there is no need to pass 'message' -# to the base class to get a meaningful output from 'str(exc)'. -# pylint: disable=super-init-not-called - - -class ParseException(Exception): - pass - - -class NoMoreData(IOError): - def __init__(self, buf=None): - self.buf = buf - - def __str__(self): - return "No more data after: %r" % self.buf - - -class ConfigurationProblem(ParseException): - def __init__(self, info): - self.info = info - self.code = 500 - - def __str__(self): - return "Configuration problem: %s" % self.info - - -class InvalidRequestLine(ParseException): - def __init__(self, req): - self.req = req - self.code = 400 - - def __str__(self): - return "Invalid HTTP request line: %r" % self.req - - -class InvalidRequestMethod(ParseException): - def __init__(self, method): - self.method = method - - def __str__(self): - return "Invalid HTTP method: %r" % self.method - - -class InvalidHTTPVersion(ParseException): - def __init__(self, version): - self.version = version - - def __str__(self): - return "Invalid HTTP Version: %r" % (self.version,) - - -class InvalidHeader(ParseException): - def __init__(self, hdr, req=None): - self.hdr = hdr - self.req = req - - def __str__(self): - return "Invalid HTTP Header: %r" % self.hdr - - -class ObsoleteFolding(ParseException): - def __init__(self, hdr): - self.hdr = hdr - - def __str__(self): - return "Obsolete line folding is unacceptable: %r" % (self.hdr, ) - - -class InvalidHeaderName(ParseException): - def __init__(self, hdr): - self.hdr = hdr - - def __str__(self): - return "Invalid HTTP header name: %r" % self.hdr - - -class UnsupportedTransferCoding(ParseException): - def __init__(self, hdr): - self.hdr = hdr - self.code = 501 - - def __str__(self): - return "Unsupported transfer coding: %r" % self.hdr - - -class InvalidChunkSize(IOError): - def __init__(self, data): - self.data = data - - def __str__(self): - return "Invalid chunk size: %r" % self.data - - -class ChunkMissingTerminator(IOError): - def __init__(self, term): - self.term = term - - def __str__(self): - return "Invalid chunk terminator is not '\\r\\n': %r" % self.term - - -class LimitRequestLine(ParseException): - def __init__(self, size, max_size): - self.size = size - self.max_size = max_size - - def __str__(self): - return "Request Line is too large (%s > %s)" % (self.size, self.max_size) - - -class LimitRequestHeaders(ParseException): - def __init__(self, msg): - self.msg = msg - - def __str__(self): - return self.msg - - -class InvalidProxyLine(ParseException): - def __init__(self, line): - self.line = line - self.code = 400 - - def __str__(self): - return "Invalid PROXY line: %r" % self.line - - -class ForbiddenProxyRequest(ParseException): - def __init__(self, host): - self.host = host - self.code = 403 - - def __str__(self): - return "Proxy request from %r not allowed" % self.host - - -class InvalidSchemeHeaders(ParseException): - def __str__(self): - return "Contradictory scheme headers" diff --git a/venv/lib/python3.9/site-packages/gunicorn/http/message.py b/venv/lib/python3.9/site-packages/gunicorn/http/message.py deleted file mode 100644 index 59ce0bf..0000000 --- a/venv/lib/python3.9/site-packages/gunicorn/http/message.py +++ /dev/null @@ -1,463 +0,0 @@ -# -# This file is part of gunicorn released under the MIT license. -# See the NOTICE for more information. - -import io -import re -import socket - -from gunicorn.http.body import ChunkedReader, LengthReader, EOFReader, Body -from gunicorn.http.errors import ( - InvalidHeader, InvalidHeaderName, NoMoreData, - InvalidRequestLine, InvalidRequestMethod, InvalidHTTPVersion, - LimitRequestLine, LimitRequestHeaders, - UnsupportedTransferCoding, ObsoleteFolding, -) -from gunicorn.http.errors import InvalidProxyLine, ForbiddenProxyRequest -from gunicorn.http.errors import InvalidSchemeHeaders -from gunicorn.util import bytes_to_str, split_request_uri - -MAX_REQUEST_LINE = 8190 -MAX_HEADERS = 32768 -DEFAULT_MAX_HEADERFIELD_SIZE = 8190 - -# verbosely on purpose, avoid backslash ambiguity -RFC9110_5_6_2_TOKEN_SPECIALS = r"!#$%&'*+-.^_`|~" -TOKEN_RE = re.compile(r"[%s0-9a-zA-Z]+" % (re.escape(RFC9110_5_6_2_TOKEN_SPECIALS))) -METHOD_BADCHAR_RE = re.compile("[a-z#]") -# usually 1.0 or 1.1 - RFC9112 permits restricting to single-digit versions -VERSION_RE = re.compile(r"HTTP/(\d)\.(\d)") -RFC9110_5_5_INVALID_AND_DANGEROUS = re.compile(r"[\0\r\n]") - - -class Message: - def __init__(self, cfg, unreader, peer_addr): - self.cfg = cfg - self.unreader = unreader - self.peer_addr = peer_addr - self.remote_addr = peer_addr - self.version = None - self.headers = [] - self.trailers = [] - self.body = None - self.scheme = "https" if cfg.is_ssl else "http" - self.must_close = False - - # set headers limits - self.limit_request_fields = cfg.limit_request_fields - if (self.limit_request_fields <= 0 - or self.limit_request_fields > MAX_HEADERS): - self.limit_request_fields = MAX_HEADERS - self.limit_request_field_size = cfg.limit_request_field_size - if self.limit_request_field_size < 0: - self.limit_request_field_size = DEFAULT_MAX_HEADERFIELD_SIZE - - # set max header buffer size - max_header_field_size = self.limit_request_field_size or DEFAULT_MAX_HEADERFIELD_SIZE - self.max_buffer_headers = self.limit_request_fields * \ - (max_header_field_size + 2) + 4 - - unused = self.parse(self.unreader) - self.unreader.unread(unused) - self.set_body_reader() - - def force_close(self): - self.must_close = True - - def parse(self, unreader): - raise NotImplementedError() - - def parse_headers(self, data, from_trailer=False): - cfg = self.cfg - headers = [] - - # Split lines on \r\n - lines = [bytes_to_str(line) for line in data.split(b"\r\n")] - - # handle scheme headers - scheme_header = False - secure_scheme_headers = {} - forwarder_headers = [] - if from_trailer: - # nonsense. either a request is https from the beginning - # .. or we are just behind a proxy who does not remove conflicting trailers - pass - elif ('*' in cfg.forwarded_allow_ips or - not isinstance(self.peer_addr, tuple) - or self.peer_addr[0] in cfg.forwarded_allow_ips): - secure_scheme_headers = cfg.secure_scheme_headers - forwarder_headers = cfg.forwarder_headers - - # Parse headers into key/value pairs paying attention - # to continuation lines. - while lines: - if len(headers) >= self.limit_request_fields: - raise LimitRequestHeaders("limit request headers fields") - - # Parse initial header name: value pair. - curr = lines.pop(0) - header_length = len(curr) + len("\r\n") - if curr.find(":") <= 0: - raise InvalidHeader(curr) - name, value = curr.split(":", 1) - if self.cfg.strip_header_spaces: - name = name.rstrip(" \t") - if not TOKEN_RE.fullmatch(name): - raise InvalidHeaderName(name) - - # this is still a dangerous place to do this - # but it is more correct than doing it before the pattern match: - # after we entered Unicode wonderland, 8bits could case-shift into ASCII: - # b"\xDF".decode("latin-1").upper().encode("ascii") == b"SS" - name = name.upper() - - value = [value.strip(" \t")] - - # Consume value continuation lines.. - while lines and lines[0].startswith((" ", "\t")): - # .. which is obsolete here, and no longer done by default - if not self.cfg.permit_obsolete_folding: - raise ObsoleteFolding(name) - curr = lines.pop(0) - header_length += len(curr) + len("\r\n") - if header_length > self.limit_request_field_size > 0: - raise LimitRequestHeaders("limit request headers " - "fields size") - value.append(curr.strip("\t ")) - value = " ".join(value) - - if RFC9110_5_5_INVALID_AND_DANGEROUS.search(value): - raise InvalidHeader(name) - - if header_length > self.limit_request_field_size > 0: - raise LimitRequestHeaders("limit request headers fields size") - - if name in secure_scheme_headers: - secure = value == secure_scheme_headers[name] - scheme = "https" if secure else "http" - if scheme_header: - if scheme != self.scheme: - raise InvalidSchemeHeaders() - else: - scheme_header = True - self.scheme = scheme - - # ambiguous mapping allows fooling downstream, e.g. merging non-identical headers: - # X-Forwarded-For: 2001:db8::ha:cc:ed - # X_Forwarded_For: 127.0.0.1,::1 - # HTTP_X_FORWARDED_FOR = 2001:db8::ha:cc:ed,127.0.0.1,::1 - # Only modify after fixing *ALL* header transformations; network to wsgi env - if "_" in name: - if name in forwarder_headers or "*" in forwarder_headers: - # This forwarder may override our environment - pass - elif self.cfg.header_map == "dangerous": - # as if we did not know we cannot safely map this - pass - elif self.cfg.header_map == "drop": - # almost as if it never had been there - # but still counts against resource limits - continue - else: - # fail-safe fallthrough: refuse - raise InvalidHeaderName(name) - - headers.append((name, value)) - - return headers - - def set_body_reader(self): - chunked = False - content_length = None - - for (name, value) in self.headers: - if name == "CONTENT-LENGTH": - if content_length is not None: - raise InvalidHeader("CONTENT-LENGTH", req=self) - content_length = value - elif name == "TRANSFER-ENCODING": - # T-E can be a list - # https://datatracker.ietf.org/doc/html/rfc9112#name-transfer-encoding - vals = [v.strip() for v in value.split(',')] - for val in vals: - if val.lower() == "chunked": - # DANGER: transfer codings stack, and stacked chunking is never intended - if chunked: - raise InvalidHeader("TRANSFER-ENCODING", req=self) - chunked = True - elif val.lower() == "identity": - # does not do much, could still plausibly desync from what the proxy does - # safe option: nuke it, its never needed - if chunked: - raise InvalidHeader("TRANSFER-ENCODING", req=self) - elif val.lower() in ('compress', 'deflate', 'gzip'): - # chunked should be the last one - if chunked: - raise InvalidHeader("TRANSFER-ENCODING", req=self) - self.force_close() - else: - raise UnsupportedTransferCoding(value) - - if chunked: - # two potentially dangerous cases: - # a) CL + TE (TE overrides CL.. only safe if the recipient sees it that way too) - # b) chunked HTTP/1.0 (always faulty) - if self.version < (1, 1): - # framing wonky, see RFC 9112 Section 6.1 - raise InvalidHeader("TRANSFER-ENCODING", req=self) - if content_length is not None: - # we cannot be certain the message framing we understood matches proxy intent - # -> whatever happens next, remaining input must not be trusted - raise InvalidHeader("CONTENT-LENGTH", req=self) - self.body = Body(ChunkedReader(self, self.unreader)) - elif content_length is not None: - try: - if str(content_length).isnumeric(): - content_length = int(content_length) - else: - raise InvalidHeader("CONTENT-LENGTH", req=self) - except ValueError: - raise InvalidHeader("CONTENT-LENGTH", req=self) - - if content_length < 0: - raise InvalidHeader("CONTENT-LENGTH", req=self) - - self.body = Body(LengthReader(self.unreader, content_length)) - else: - self.body = Body(EOFReader(self.unreader)) - - def should_close(self): - if self.must_close: - return True - for (h, v) in self.headers: - if h == "CONNECTION": - v = v.lower().strip(" \t") - if v == "close": - return True - elif v == "keep-alive": - return False - break - return self.version <= (1, 0) - - -class Request(Message): - def __init__(self, cfg, unreader, peer_addr, req_number=1): - self.method = None - self.uri = None - self.path = None - self.query = None - self.fragment = None - - # get max request line size - self.limit_request_line = cfg.limit_request_line - if (self.limit_request_line < 0 - or self.limit_request_line >= MAX_REQUEST_LINE): - self.limit_request_line = MAX_REQUEST_LINE - - self.req_number = req_number - self.proxy_protocol_info = None - super().__init__(cfg, unreader, peer_addr) - - def get_data(self, unreader, buf, stop=False): - data = unreader.read() - if not data: - if stop: - raise StopIteration() - raise NoMoreData(buf.getvalue()) - buf.write(data) - - def parse(self, unreader): - buf = io.BytesIO() - self.get_data(unreader, buf, stop=True) - - # get request line - line, rbuf = self.read_line(unreader, buf, self.limit_request_line) - - # proxy protocol - if self.proxy_protocol(bytes_to_str(line)): - # get next request line - buf = io.BytesIO() - buf.write(rbuf) - line, rbuf = self.read_line(unreader, buf, self.limit_request_line) - - self.parse_request_line(line) - buf = io.BytesIO() - buf.write(rbuf) - - # Headers - data = buf.getvalue() - idx = data.find(b"\r\n\r\n") - - done = data[:2] == b"\r\n" - while True: - idx = data.find(b"\r\n\r\n") - done = data[:2] == b"\r\n" - - if idx < 0 and not done: - self.get_data(unreader, buf) - data = buf.getvalue() - if len(data) > self.max_buffer_headers: - raise LimitRequestHeaders("max buffer headers") - else: - break - - if done: - self.unreader.unread(data[2:]) - return b"" - - self.headers = self.parse_headers(data[:idx], from_trailer=False) - - ret = data[idx + 4:] - buf = None - return ret - - def read_line(self, unreader, buf, limit=0): - data = buf.getvalue() - - while True: - idx = data.find(b"\r\n") - if idx >= 0: - # check if the request line is too large - if idx > limit > 0: - raise LimitRequestLine(idx, limit) - break - if len(data) - 2 > limit > 0: - raise LimitRequestLine(len(data), limit) - self.get_data(unreader, buf) - data = buf.getvalue() - - return (data[:idx], # request line, - data[idx + 2:]) # residue in the buffer, skip \r\n - - def proxy_protocol(self, line): - """\ - Detect, check and parse proxy protocol. - - :raises: ForbiddenProxyRequest, InvalidProxyLine. - :return: True for proxy protocol line else False - """ - if not self.cfg.proxy_protocol: - return False - - if self.req_number != 1: - return False - - if not line.startswith("PROXY"): - return False - - self.proxy_protocol_access_check() - self.parse_proxy_protocol(line) - - return True - - def proxy_protocol_access_check(self): - # check in allow list - if ("*" not in self.cfg.proxy_allow_ips and - isinstance(self.peer_addr, tuple) and - self.peer_addr[0] not in self.cfg.proxy_allow_ips): - raise ForbiddenProxyRequest(self.peer_addr[0]) - - def parse_proxy_protocol(self, line): - bits = line.split(" ") - - if len(bits) != 6: - raise InvalidProxyLine(line) - - # Extract data - proto = bits[1] - s_addr = bits[2] - d_addr = bits[3] - - # Validation - if proto not in ["TCP4", "TCP6"]: - raise InvalidProxyLine("protocol '%s' not supported" % proto) - if proto == "TCP4": - try: - socket.inet_pton(socket.AF_INET, s_addr) - socket.inet_pton(socket.AF_INET, d_addr) - except OSError: - raise InvalidProxyLine(line) - elif proto == "TCP6": - try: - socket.inet_pton(socket.AF_INET6, s_addr) - socket.inet_pton(socket.AF_INET6, d_addr) - except OSError: - raise InvalidProxyLine(line) - - try: - s_port = int(bits[4]) - d_port = int(bits[5]) - except ValueError: - raise InvalidProxyLine("invalid port %s" % line) - - if not ((0 <= s_port <= 65535) and (0 <= d_port <= 65535)): - raise InvalidProxyLine("invalid port %s" % line) - - # Set data - self.proxy_protocol_info = { - "proxy_protocol": proto, - "client_addr": s_addr, - "client_port": s_port, - "proxy_addr": d_addr, - "proxy_port": d_port - } - - def parse_request_line(self, line_bytes): - bits = [bytes_to_str(bit) for bit in line_bytes.split(b" ", 2)] - if len(bits) != 3: - raise InvalidRequestLine(bytes_to_str(line_bytes)) - - # Method: RFC9110 Section 9 - self.method = bits[0] - - # nonstandard restriction, suitable for all IANA registered methods - # partially enforced in previous gunicorn versions - if not self.cfg.permit_unconventional_http_method: - if METHOD_BADCHAR_RE.search(self.method): - raise InvalidRequestMethod(self.method) - if not 3 <= len(bits[0]) <= 20: - raise InvalidRequestMethod(self.method) - # standard restriction: RFC9110 token - if not TOKEN_RE.fullmatch(self.method): - raise InvalidRequestMethod(self.method) - # nonstandard and dangerous - # methods are merely uppercase by convention, no case-insensitive treatment is intended - if self.cfg.casefold_http_method: - self.method = self.method.upper() - - # URI - self.uri = bits[1] - - # Python stdlib explicitly tells us it will not perform validation. - # https://docs.python.org/3/library/urllib.parse.html#url-parsing-security - # There are *four* `request-target` forms in rfc9112, none of them can be empty: - # 1. origin-form, which starts with a slash - # 2. absolute-form, which starts with a non-empty scheme - # 3. authority-form, (for CONNECT) which contains a colon after the host - # 4. asterisk-form, which is an asterisk (`\x2A`) - # => manually reject one always invalid URI: empty - if len(self.uri) == 0: - raise InvalidRequestLine(bytes_to_str(line_bytes)) - - try: - parts = split_request_uri(self.uri) - except ValueError: - raise InvalidRequestLine(bytes_to_str(line_bytes)) - self.path = parts.path or "" - self.query = parts.query or "" - self.fragment = parts.fragment or "" - - # Version - match = VERSION_RE.fullmatch(bits[2]) - if match is None: - raise InvalidHTTPVersion(bits[2]) - self.version = (int(match.group(1)), int(match.group(2))) - if not (1, 0) <= self.version < (2, 0): - # if ever relaxing this, carefully review Content-Encoding processing - if not self.cfg.permit_unconventional_http_version: - raise InvalidHTTPVersion(self.version) - - def set_body_reader(self): - super().set_body_reader() - if isinstance(self.body.reader, EOFReader): - self.body = Body(LengthReader(self.unreader, 0)) diff --git a/venv/lib/python3.9/site-packages/gunicorn/http/parser.py b/venv/lib/python3.9/site-packages/gunicorn/http/parser.py deleted file mode 100644 index 88da17a..0000000 --- a/venv/lib/python3.9/site-packages/gunicorn/http/parser.py +++ /dev/null @@ -1,51 +0,0 @@ -# -# This file is part of gunicorn released under the MIT license. -# See the NOTICE for more information. - -from gunicorn.http.message import Request -from gunicorn.http.unreader import SocketUnreader, IterUnreader - - -class Parser: - - mesg_class = None - - def __init__(self, cfg, source, source_addr): - self.cfg = cfg - if hasattr(source, "recv"): - self.unreader = SocketUnreader(source) - else: - self.unreader = IterUnreader(source) - self.mesg = None - self.source_addr = source_addr - - # request counter (for keepalive connetions) - self.req_count = 0 - - def __iter__(self): - return self - - def __next__(self): - # Stop if HTTP dictates a stop. - if self.mesg and self.mesg.should_close(): - raise StopIteration() - - # Discard any unread body of the previous message - if self.mesg: - data = self.mesg.body.read(8192) - while data: - data = self.mesg.body.read(8192) - - # Parse the next request - self.req_count += 1 - self.mesg = self.mesg_class(self.cfg, self.unreader, self.source_addr, self.req_count) - if not self.mesg: - raise StopIteration() - return self.mesg - - next = __next__ - - -class RequestParser(Parser): - - mesg_class = Request diff --git a/venv/lib/python3.9/site-packages/gunicorn/http/unreader.py b/venv/lib/python3.9/site-packages/gunicorn/http/unreader.py deleted file mode 100644 index 9aadfbc..0000000 --- a/venv/lib/python3.9/site-packages/gunicorn/http/unreader.py +++ /dev/null @@ -1,78 +0,0 @@ -# -# This file is part of gunicorn released under the MIT license. -# See the NOTICE for more information. - -import io -import os - -# Classes that can undo reading data from -# a given type of data source. - - -class Unreader: - def __init__(self): - self.buf = io.BytesIO() - - def chunk(self): - raise NotImplementedError() - - def read(self, size=None): - if size is not None and not isinstance(size, int): - raise TypeError("size parameter must be an int or long.") - - if size is not None: - if size == 0: - return b"" - if size < 0: - size = None - - self.buf.seek(0, os.SEEK_END) - - if size is None and self.buf.tell(): - ret = self.buf.getvalue() - self.buf = io.BytesIO() - return ret - if size is None: - d = self.chunk() - return d - - while self.buf.tell() < size: - chunk = self.chunk() - if not chunk: - ret = self.buf.getvalue() - self.buf = io.BytesIO() - return ret - self.buf.write(chunk) - data = self.buf.getvalue() - self.buf = io.BytesIO() - self.buf.write(data[size:]) - return data[:size] - - def unread(self, data): - self.buf.seek(0, os.SEEK_END) - self.buf.write(data) - - -class SocketUnreader(Unreader): - def __init__(self, sock, max_chunk=8192): - super().__init__() - self.sock = sock - self.mxchunk = max_chunk - - def chunk(self): - return self.sock.recv(self.mxchunk) - - -class IterUnreader(Unreader): - def __init__(self, iterable): - super().__init__() - self.iter = iter(iterable) - - def chunk(self): - if not self.iter: - return b"" - try: - return next(self.iter) - except StopIteration: - self.iter = None - return b"" diff --git a/venv/lib/python3.9/site-packages/gunicorn/http/wsgi.py b/venv/lib/python3.9/site-packages/gunicorn/http/wsgi.py deleted file mode 100644 index 419ac50..0000000 --- a/venv/lib/python3.9/site-packages/gunicorn/http/wsgi.py +++ /dev/null @@ -1,401 +0,0 @@ -# -# This file is part of gunicorn released under the MIT license. -# See the NOTICE for more information. - -import io -import logging -import os -import re -import sys - -from gunicorn.http.message import TOKEN_RE -from gunicorn.http.errors import ConfigurationProblem, InvalidHeader, InvalidHeaderName -from gunicorn import SERVER_SOFTWARE, SERVER -from gunicorn import util - -# Send files in at most 1GB blocks as some operating systems can have problems -# with sending files in blocks over 2GB. -BLKSIZE = 0x3FFFFFFF - -# RFC9110 5.5: field-vchar = VCHAR / obs-text -# RFC4234 B.1: VCHAR = 0x21-x07E = printable ASCII -HEADER_VALUE_RE = re.compile(r'[ \t\x21-\x7e\x80-\xff]*') - -log = logging.getLogger(__name__) - - -class FileWrapper: - - def __init__(self, filelike, blksize=8192): - self.filelike = filelike - self.blksize = blksize - if hasattr(filelike, 'close'): - self.close = filelike.close - - def __getitem__(self, key): - data = self.filelike.read(self.blksize) - if data: - return data - raise IndexError - - -class WSGIErrorsWrapper(io.RawIOBase): - - def __init__(self, cfg): - # There is no public __init__ method for RawIOBase so - # we don't need to call super() in the __init__ method. - # pylint: disable=super-init-not-called - errorlog = logging.getLogger("gunicorn.error") - handlers = errorlog.handlers - self.streams = [] - - if cfg.errorlog == "-": - self.streams.append(sys.stderr) - handlers = handlers[1:] - - for h in handlers: - if hasattr(h, "stream"): - self.streams.append(h.stream) - - def write(self, data): - for stream in self.streams: - try: - stream.write(data) - except UnicodeError: - stream.write(data.encode("UTF-8")) - stream.flush() - - -def base_environ(cfg): - return { - "wsgi.errors": WSGIErrorsWrapper(cfg), - "wsgi.version": (1, 0), - "wsgi.multithread": False, - "wsgi.multiprocess": (cfg.workers > 1), - "wsgi.run_once": False, - "wsgi.file_wrapper": FileWrapper, - "wsgi.input_terminated": True, - "SERVER_SOFTWARE": SERVER_SOFTWARE, - } - - -def default_environ(req, sock, cfg): - env = base_environ(cfg) - env.update({ - "wsgi.input": req.body, - "gunicorn.socket": sock, - "REQUEST_METHOD": req.method, - "QUERY_STRING": req.query, - "RAW_URI": req.uri, - "SERVER_PROTOCOL": "HTTP/%s" % ".".join([str(v) for v in req.version]) - }) - return env - - -def proxy_environ(req): - info = req.proxy_protocol_info - - if not info: - return {} - - return { - "PROXY_PROTOCOL": info["proxy_protocol"], - "REMOTE_ADDR": info["client_addr"], - "REMOTE_PORT": str(info["client_port"]), - "PROXY_ADDR": info["proxy_addr"], - "PROXY_PORT": str(info["proxy_port"]), - } - - -def create(req, sock, client, server, cfg): - resp = Response(req, sock, cfg) - - # set initial environ - environ = default_environ(req, sock, cfg) - - # default variables - host = None - script_name = os.environ.get("SCRIPT_NAME", "") - - # add the headers to the environ - for hdr_name, hdr_value in req.headers: - if hdr_name == "EXPECT": - # handle expect - if hdr_value.lower() == "100-continue": - sock.send(b"HTTP/1.1 100 Continue\r\n\r\n") - elif hdr_name == 'HOST': - host = hdr_value - elif hdr_name == "SCRIPT_NAME": - script_name = hdr_value - elif hdr_name == "CONTENT-TYPE": - environ['CONTENT_TYPE'] = hdr_value - continue - elif hdr_name == "CONTENT-LENGTH": - environ['CONTENT_LENGTH'] = hdr_value - continue - - # do not change lightly, this is a common source of security problems - # RFC9110 Section 17.10 discourages ambiguous or incomplete mappings - key = 'HTTP_' + hdr_name.replace('-', '_') - if key in environ: - hdr_value = "%s,%s" % (environ[key], hdr_value) - environ[key] = hdr_value - - # set the url scheme - environ['wsgi.url_scheme'] = req.scheme - - # set the REMOTE_* keys in environ - # authors should be aware that REMOTE_HOST and REMOTE_ADDR - # may not qualify the remote addr: - # http://www.ietf.org/rfc/rfc3875 - if isinstance(client, str): - environ['REMOTE_ADDR'] = client - elif isinstance(client, bytes): - environ['REMOTE_ADDR'] = client.decode() - else: - environ['REMOTE_ADDR'] = client[0] - environ['REMOTE_PORT'] = str(client[1]) - - # handle the SERVER_* - # Normally only the application should use the Host header but since the - # WSGI spec doesn't support unix sockets, we are using it to create - # viable SERVER_* if possible. - if isinstance(server, str): - server = server.split(":") - if len(server) == 1: - # unix socket - if host: - server = host.split(':') - if len(server) == 1: - if req.scheme == "http": - server.append(80) - elif req.scheme == "https": - server.append(443) - else: - server.append('') - else: - # no host header given which means that we are not behind a - # proxy, so append an empty port. - server.append('') - environ['SERVER_NAME'] = server[0] - environ['SERVER_PORT'] = str(server[1]) - - # set the path and script name - path_info = req.path - if script_name: - if not path_info.startswith(script_name): - raise ConfigurationProblem( - "Request path %r does not start with SCRIPT_NAME %r" % - (path_info, script_name)) - path_info = path_info[len(script_name):] - environ['PATH_INFO'] = util.unquote_to_wsgi_str(path_info) - environ['SCRIPT_NAME'] = script_name - - # override the environ with the correct remote and server address if - # we are behind a proxy using the proxy protocol. - environ.update(proxy_environ(req)) - return resp, environ - - -class Response: - - def __init__(self, req, sock, cfg): - self.req = req - self.sock = sock - self.version = SERVER - self.status = None - self.chunked = False - self.must_close = False - self.headers = [] - self.headers_sent = False - self.response_length = None - self.sent = 0 - self.upgrade = False - self.cfg = cfg - - def force_close(self): - self.must_close = True - - def should_close(self): - if self.must_close or self.req.should_close(): - return True - if self.response_length is not None or self.chunked: - return False - if self.req.method == 'HEAD': - return False - if self.status_code < 200 or self.status_code in (204, 304): - return False - return True - - def start_response(self, status, headers, exc_info=None): - if exc_info: - try: - if self.status and self.headers_sent: - util.reraise(exc_info[0], exc_info[1], exc_info[2]) - finally: - exc_info = None - elif self.status is not None: - raise AssertionError("Response headers already set!") - - self.status = status - - # get the status code from the response here so we can use it to check - # the need for the connection header later without parsing the string - # each time. - try: - self.status_code = int(self.status.split()[0]) - except ValueError: - self.status_code = None - - self.process_headers(headers) - self.chunked = self.is_chunked() - return self.write - - def process_headers(self, headers): - for name, value in headers: - if not isinstance(name, str): - raise TypeError('%r is not a string' % name) - - if not TOKEN_RE.fullmatch(name): - raise InvalidHeaderName('%r' % name) - - if not isinstance(value, str): - raise TypeError('%r is not a string' % value) - - if not HEADER_VALUE_RE.fullmatch(value): - raise InvalidHeader('%r' % value) - - # RFC9110 5.5 - value = value.strip(" \t") - lname = name.lower() - if lname == "content-length": - self.response_length = int(value) - elif util.is_hoppish(name): - if lname == "connection": - # handle websocket - if value.lower() == "upgrade": - self.upgrade = True - elif lname == "upgrade": - if value.lower() == "websocket": - self.headers.append((name, value)) - - # ignore hopbyhop headers - continue - self.headers.append((name, value)) - - def is_chunked(self): - # Only use chunked responses when the client is - # speaking HTTP/1.1 or newer and there was - # no Content-Length header set. - if self.response_length is not None: - return False - elif self.req.version <= (1, 0): - return False - elif self.req.method == 'HEAD': - # Responses to a HEAD request MUST NOT contain a response body. - return False - elif self.status_code in (204, 304): - # Do not use chunked responses when the response is guaranteed to - # not have a response body. - return False - return True - - def default_headers(self): - # set the connection header - if self.upgrade: - connection = "upgrade" - elif self.should_close(): - connection = "close" - else: - connection = "keep-alive" - - headers = [ - "HTTP/%s.%s %s\r\n" % (self.req.version[0], - self.req.version[1], self.status), - "Server: %s\r\n" % self.version, - "Date: %s\r\n" % util.http_date(), - "Connection: %s\r\n" % connection - ] - if self.chunked: - headers.append("Transfer-Encoding: chunked\r\n") - return headers - - def send_headers(self): - if self.headers_sent: - return - tosend = self.default_headers() - tosend.extend(["%s: %s\r\n" % (k, v) for k, v in self.headers]) - - header_str = "%s\r\n" % "".join(tosend) - util.write(self.sock, util.to_bytestring(header_str, "latin-1")) - self.headers_sent = True - - def write(self, arg): - self.send_headers() - if not isinstance(arg, bytes): - raise TypeError('%r is not a byte' % arg) - arglen = len(arg) - tosend = arglen - if self.response_length is not None: - if self.sent >= self.response_length: - # Never write more than self.response_length bytes - return - - tosend = min(self.response_length - self.sent, tosend) - if tosend < arglen: - arg = arg[:tosend] - - # Sending an empty chunk signals the end of the - # response and prematurely closes the response - if self.chunked and tosend == 0: - return - - self.sent += tosend - util.write(self.sock, arg, self.chunked) - - def can_sendfile(self): - return self.cfg.sendfile is not False - - def sendfile(self, respiter): - if self.cfg.is_ssl or not self.can_sendfile(): - return False - - if not util.has_fileno(respiter.filelike): - return False - - fileno = respiter.filelike.fileno() - try: - offset = os.lseek(fileno, 0, os.SEEK_CUR) - if self.response_length is None: - filesize = os.fstat(fileno).st_size - nbytes = filesize - offset - else: - nbytes = self.response_length - except (OSError, io.UnsupportedOperation): - return False - - self.send_headers() - - if self.is_chunked(): - chunk_size = "%X\r\n" % nbytes - self.sock.sendall(chunk_size.encode('utf-8')) - if nbytes > 0: - self.sock.sendfile(respiter.filelike, offset=offset, count=nbytes) - - if self.is_chunked(): - self.sock.sendall(b"\r\n") - - os.lseek(fileno, offset, os.SEEK_SET) - - return True - - def write_file(self, respiter): - if not self.sendfile(respiter): - for item in respiter: - self.write(item) - - def close(self): - if not self.headers_sent: - self.send_headers() - if self.chunked: - util.write_chunk(self.sock, b"") diff --git a/venv/lib/python3.9/site-packages/gunicorn/instrument/__init__.py b/venv/lib/python3.9/site-packages/gunicorn/instrument/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/venv/lib/python3.9/site-packages/gunicorn/instrument/statsd.py b/venv/lib/python3.9/site-packages/gunicorn/instrument/statsd.py deleted file mode 100644 index 7bc4e6f..0000000 --- a/venv/lib/python3.9/site-packages/gunicorn/instrument/statsd.py +++ /dev/null @@ -1,134 +0,0 @@ -# -# This file is part of gunicorn released under the MIT license. -# See the NOTICE for more information. - -"Bare-bones implementation of statsD's protocol, client-side" - -import logging -import socket -from re import sub - -from gunicorn.glogging import Logger - -# Instrumentation constants -METRIC_VAR = "metric" -VALUE_VAR = "value" -MTYPE_VAR = "mtype" -GAUGE_TYPE = "gauge" -COUNTER_TYPE = "counter" -HISTOGRAM_TYPE = "histogram" - - -class Statsd(Logger): - """statsD-based instrumentation, that passes as a logger - """ - def __init__(self, cfg): - Logger.__init__(self, cfg) - self.prefix = sub(r"^(.+[^.]+)\.*$", "\\g<1>.", cfg.statsd_prefix) - - if isinstance(cfg.statsd_host, str): - address_family = socket.AF_UNIX - else: - address_family = socket.AF_INET - - try: - self.sock = socket.socket(address_family, socket.SOCK_DGRAM) - self.sock.connect(cfg.statsd_host) - except Exception: - self.sock = None - - self.dogstatsd_tags = cfg.dogstatsd_tags - - # Log errors and warnings - def critical(self, msg, *args, **kwargs): - Logger.critical(self, msg, *args, **kwargs) - self.increment("gunicorn.log.critical", 1) - - def error(self, msg, *args, **kwargs): - Logger.error(self, msg, *args, **kwargs) - self.increment("gunicorn.log.error", 1) - - def warning(self, msg, *args, **kwargs): - Logger.warning(self, msg, *args, **kwargs) - self.increment("gunicorn.log.warning", 1) - - def exception(self, msg, *args, **kwargs): - Logger.exception(self, msg, *args, **kwargs) - self.increment("gunicorn.log.exception", 1) - - # Special treatment for info, the most common log level - def info(self, msg, *args, **kwargs): - self.log(logging.INFO, msg, *args, **kwargs) - - # skip the run-of-the-mill logs - def debug(self, msg, *args, **kwargs): - self.log(logging.DEBUG, msg, *args, **kwargs) - - def log(self, lvl, msg, *args, **kwargs): - """Log a given statistic if metric, value and type are present - """ - try: - extra = kwargs.get("extra", None) - if extra is not None: - metric = extra.get(METRIC_VAR, None) - value = extra.get(VALUE_VAR, None) - typ = extra.get(MTYPE_VAR, None) - if metric and value and typ: - if typ == GAUGE_TYPE: - self.gauge(metric, value) - elif typ == COUNTER_TYPE: - self.increment(metric, value) - elif typ == HISTOGRAM_TYPE: - self.histogram(metric, value) - else: - pass - - # Log to parent logger only if there is something to say - if msg: - Logger.log(self, lvl, msg, *args, **kwargs) - except Exception: - Logger.warning(self, "Failed to log to statsd", exc_info=True) - - # access logging - def access(self, resp, req, environ, request_time): - """Measure request duration - request_time is a datetime.timedelta - """ - Logger.access(self, resp, req, environ, request_time) - duration_in_ms = request_time.seconds * 1000 + float(request_time.microseconds) / 10 ** 3 - status = resp.status - if isinstance(status, bytes): - status = status.decode('utf-8') - if isinstance(status, str): - status = int(status.split(None, 1)[0]) - self.histogram("gunicorn.request.duration", duration_in_ms) - self.increment("gunicorn.requests", 1) - self.increment("gunicorn.request.status.%d" % status, 1) - - # statsD methods - # you can use those directly if you want - def gauge(self, name, value): - self._sock_send("{0}{1}:{2}|g".format(self.prefix, name, value)) - - def increment(self, name, value, sampling_rate=1.0): - self._sock_send("{0}{1}:{2}|c|@{3}".format(self.prefix, name, value, sampling_rate)) - - def decrement(self, name, value, sampling_rate=1.0): - self._sock_send("{0}{1}:-{2}|c|@{3}".format(self.prefix, name, value, sampling_rate)) - - def histogram(self, name, value): - self._sock_send("{0}{1}:{2}|ms".format(self.prefix, name, value)) - - def _sock_send(self, msg): - try: - if isinstance(msg, str): - msg = msg.encode("ascii") - - # http://docs.datadoghq.com/guides/dogstatsd/#datagram-format - if self.dogstatsd_tags: - msg = msg + b"|#" + self.dogstatsd_tags.encode('ascii') - - if self.sock: - self.sock.send(msg) - except Exception: - Logger.warning(self, "Error sending message to statsd", exc_info=True) diff --git a/venv/lib/python3.9/site-packages/gunicorn/pidfile.py b/venv/lib/python3.9/site-packages/gunicorn/pidfile.py deleted file mode 100644 index b171f7d..0000000 --- a/venv/lib/python3.9/site-packages/gunicorn/pidfile.py +++ /dev/null @@ -1,85 +0,0 @@ -# -# This file is part of gunicorn released under the MIT license. -# See the NOTICE for more information. - -import errno -import os -import tempfile - - -class Pidfile: - """\ - Manage a PID file. If a specific name is provided - it and '"%s.oldpid" % name' will be used. Otherwise - we create a temp file using os.mkstemp. - """ - - def __init__(self, fname): - self.fname = fname - self.pid = None - - def create(self, pid): - oldpid = self.validate() - if oldpid: - if oldpid == os.getpid(): - return - msg = "Already running on PID %s (or pid file '%s' is stale)" - raise RuntimeError(msg % (oldpid, self.fname)) - - self.pid = pid - - # Write pidfile - fdir = os.path.dirname(self.fname) - if fdir and not os.path.isdir(fdir): - raise RuntimeError("%s doesn't exist. Can't create pidfile." % fdir) - fd, fname = tempfile.mkstemp(dir=fdir) - os.write(fd, ("%s\n" % self.pid).encode('utf-8')) - if self.fname: - os.rename(fname, self.fname) - else: - self.fname = fname - os.close(fd) - - # set permissions to -rw-r--r-- - os.chmod(self.fname, 420) - - def rename(self, path): - self.unlink() - self.fname = path - self.create(self.pid) - - def unlink(self): - """ delete pidfile""" - try: - with open(self.fname) as f: - pid1 = int(f.read() or 0) - - if pid1 == self.pid: - os.unlink(self.fname) - except Exception: - pass - - def validate(self): - """ Validate pidfile and make it stale if needed""" - if not self.fname: - return - try: - with open(self.fname) as f: - try: - wpid = int(f.read()) - except ValueError: - return - - try: - os.kill(wpid, 0) - return wpid - except OSError as e: - if e.args[0] == errno.EPERM: - return wpid - if e.args[0] == errno.ESRCH: - return - raise - except OSError as e: - if e.args[0] == errno.ENOENT: - return - raise diff --git a/venv/lib/python3.9/site-packages/gunicorn/reloader.py b/venv/lib/python3.9/site-packages/gunicorn/reloader.py deleted file mode 100644 index 1c67f2a..0000000 --- a/venv/lib/python3.9/site-packages/gunicorn/reloader.py +++ /dev/null @@ -1,131 +0,0 @@ -# -# This file is part of gunicorn released under the MIT license. -# See the NOTICE for more information. -# pylint: disable=no-else-continue - -import os -import os.path -import re -import sys -import time -import threading - -COMPILED_EXT_RE = re.compile(r'py[co]$') - - -class Reloader(threading.Thread): - def __init__(self, extra_files=None, interval=1, callback=None): - super().__init__() - self.daemon = True - self._extra_files = set(extra_files or ()) - self._interval = interval - self._callback = callback - - def add_extra_file(self, filename): - self._extra_files.add(filename) - - def get_files(self): - fnames = [ - COMPILED_EXT_RE.sub('py', module.__file__) - for module in tuple(sys.modules.values()) - if getattr(module, '__file__', None) - ] - - fnames.extend(self._extra_files) - - return fnames - - def run(self): - mtimes = {} - while True: - for filename in self.get_files(): - try: - mtime = os.stat(filename).st_mtime - except OSError: - continue - old_time = mtimes.get(filename) - if old_time is None: - mtimes[filename] = mtime - continue - elif mtime > old_time: - if self._callback: - self._callback(filename) - time.sleep(self._interval) - - -has_inotify = False -if sys.platform.startswith('linux'): - try: - from inotify.adapters import Inotify - import inotify.constants - has_inotify = True - except ImportError: - pass - - -if has_inotify: - - class InotifyReloader(threading.Thread): - event_mask = (inotify.constants.IN_CREATE | inotify.constants.IN_DELETE - | inotify.constants.IN_DELETE_SELF | inotify.constants.IN_MODIFY - | inotify.constants.IN_MOVE_SELF | inotify.constants.IN_MOVED_FROM - | inotify.constants.IN_MOVED_TO) - - def __init__(self, extra_files=None, callback=None): - super().__init__() - self.daemon = True - self._callback = callback - self._dirs = set() - self._watcher = Inotify() - - for extra_file in extra_files: - self.add_extra_file(extra_file) - - def add_extra_file(self, filename): - dirname = os.path.dirname(filename) - - if dirname in self._dirs: - return - - self._watcher.add_watch(dirname, mask=self.event_mask) - self._dirs.add(dirname) - - def get_dirs(self): - fnames = [ - os.path.dirname(os.path.abspath(COMPILED_EXT_RE.sub('py', module.__file__))) - for module in tuple(sys.modules.values()) - if getattr(module, '__file__', None) - ] - - return set(fnames) - - def run(self): - self._dirs = self.get_dirs() - - for dirname in self._dirs: - if os.path.isdir(dirname): - self._watcher.add_watch(dirname, mask=self.event_mask) - - for event in self._watcher.event_gen(): - if event is None: - continue - - filename = event[3] - - self._callback(filename) - -else: - - class InotifyReloader: - def __init__(self, extra_files=None, callback=None): - raise ImportError('You must have the inotify module installed to ' - 'use the inotify reloader') - - -preferred_reloader = InotifyReloader if has_inotify else Reloader - -reloader_engines = { - 'auto': preferred_reloader, - 'poll': Reloader, - 'inotify': InotifyReloader, -} diff --git a/venv/lib/python3.9/site-packages/gunicorn/sock.py b/venv/lib/python3.9/site-packages/gunicorn/sock.py deleted file mode 100644 index eb2b6fa..0000000 --- a/venv/lib/python3.9/site-packages/gunicorn/sock.py +++ /dev/null @@ -1,231 +0,0 @@ -# -# This file is part of gunicorn released under the MIT license. -# See the NOTICE for more information. - -import errno -import os -import socket -import ssl -import stat -import sys -import time - -from gunicorn import util - - -class BaseSocket: - - def __init__(self, address, conf, log, fd=None): - self.log = log - self.conf = conf - - self.cfg_addr = address - if fd is None: - sock = socket.socket(self.FAMILY, socket.SOCK_STREAM) - bound = False - else: - sock = socket.fromfd(fd, self.FAMILY, socket.SOCK_STREAM) - os.close(fd) - bound = True - - self.sock = self.set_options(sock, bound=bound) - - def __str__(self): - return "" % self.sock.fileno() - - def __getattr__(self, name): - return getattr(self.sock, name) - - def set_options(self, sock, bound=False): - sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) - if (self.conf.reuse_port - and hasattr(socket, 'SO_REUSEPORT')): # pragma: no cover - try: - sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEPORT, 1) - except OSError as err: - if err.errno not in (errno.ENOPROTOOPT, errno.EINVAL): - raise - if not bound: - self.bind(sock) - sock.setblocking(0) - - # make sure that the socket can be inherited - if hasattr(sock, "set_inheritable"): - sock.set_inheritable(True) - - sock.listen(self.conf.backlog) - return sock - - def bind(self, sock): - sock.bind(self.cfg_addr) - - def close(self): - if self.sock is None: - return - - try: - self.sock.close() - except OSError as e: - self.log.info("Error while closing socket %s", str(e)) - - self.sock = None - - -class TCPSocket(BaseSocket): - - FAMILY = socket.AF_INET - - def __str__(self): - if self.conf.is_ssl: - scheme = "https" - else: - scheme = "http" - - addr = self.sock.getsockname() - return "%s://%s:%d" % (scheme, addr[0], addr[1]) - - def set_options(self, sock, bound=False): - sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1) - return super().set_options(sock, bound=bound) - - -class TCP6Socket(TCPSocket): - - FAMILY = socket.AF_INET6 - - def __str__(self): - (host, port, _, _) = self.sock.getsockname() - return "http://[%s]:%d" % (host, port) - - -class UnixSocket(BaseSocket): - - FAMILY = socket.AF_UNIX - - def __init__(self, addr, conf, log, fd=None): - if fd is None: - try: - st = os.stat(addr) - except OSError as e: - if e.args[0] != errno.ENOENT: - raise - else: - if stat.S_ISSOCK(st.st_mode): - os.remove(addr) - else: - raise ValueError("%r is not a socket" % addr) - super().__init__(addr, conf, log, fd=fd) - - def __str__(self): - return "unix:%s" % self.cfg_addr - - def bind(self, sock): - old_umask = os.umask(self.conf.umask) - sock.bind(self.cfg_addr) - util.chown(self.cfg_addr, self.conf.uid, self.conf.gid) - os.umask(old_umask) - - -def _sock_type(addr): - if isinstance(addr, tuple): - if util.is_ipv6(addr[0]): - sock_type = TCP6Socket - else: - sock_type = TCPSocket - elif isinstance(addr, (str, bytes)): - sock_type = UnixSocket - else: - raise TypeError("Unable to create socket from: %r" % addr) - return sock_type - - -def create_sockets(conf, log, fds=None): - """ - Create a new socket for the configured addresses or file descriptors. - - If a configured address is a tuple then a TCP socket is created. - If it is a string, a Unix socket is created. Otherwise, a TypeError is - raised. - """ - listeners = [] - - # get it only once - addr = conf.address - fdaddr = [bind for bind in addr if isinstance(bind, int)] - if fds: - fdaddr += list(fds) - laddr = [bind for bind in addr if not isinstance(bind, int)] - - # check ssl config early to raise the error on startup - # only the certfile is needed since it can contains the keyfile - if conf.certfile and not os.path.exists(conf.certfile): - raise ValueError('certfile "%s" does not exist' % conf.certfile) - - if conf.keyfile and not os.path.exists(conf.keyfile): - raise ValueError('keyfile "%s" does not exist' % conf.keyfile) - - # sockets are already bound - if fdaddr: - for fd in fdaddr: - sock = socket.fromfd(fd, socket.AF_UNIX, socket.SOCK_STREAM) - sock_name = sock.getsockname() - sock_type = _sock_type(sock_name) - listener = sock_type(sock_name, conf, log, fd=fd) - listeners.append(listener) - - return listeners - - # no sockets is bound, first initialization of gunicorn in this env. - for addr in laddr: - sock_type = _sock_type(addr) - sock = None - for i in range(5): - try: - sock = sock_type(addr, conf, log) - except OSError as e: - if e.args[0] == errno.EADDRINUSE: - log.error("Connection in use: %s", str(addr)) - if e.args[0] == errno.EADDRNOTAVAIL: - log.error("Invalid address: %s", str(addr)) - msg = "connection to {addr} failed: {error}" - log.error(msg.format(addr=str(addr), error=str(e))) - if i < 5: - log.debug("Retrying in 1 second.") - time.sleep(1) - else: - break - - if sock is None: - log.error("Can't connect to %s", str(addr)) - sys.exit(1) - - listeners.append(sock) - - return listeners - - -def close_sockets(listeners, unlink=True): - for sock in listeners: - sock_name = sock.getsockname() - sock.close() - if unlink and _sock_type(sock_name) is UnixSocket: - os.unlink(sock_name) - - -def ssl_context(conf): - def default_ssl_context_factory(): - context = ssl.create_default_context(ssl.Purpose.CLIENT_AUTH, cafile=conf.ca_certs) - context.load_cert_chain(certfile=conf.certfile, keyfile=conf.keyfile) - context.verify_mode = conf.cert_reqs - if conf.ciphers: - context.set_ciphers(conf.ciphers) - return context - - return conf.ssl_context(conf, default_ssl_context_factory) - - -def ssl_wrap_socket(sock, conf): - return ssl_context(conf).wrap_socket(sock, - server_side=True, - suppress_ragged_eofs=conf.suppress_ragged_eofs, - do_handshake_on_connect=conf.do_handshake_on_connect) diff --git a/venv/lib/python3.9/site-packages/gunicorn/systemd.py b/venv/lib/python3.9/site-packages/gunicorn/systemd.py deleted file mode 100644 index 9b18550..0000000 --- a/venv/lib/python3.9/site-packages/gunicorn/systemd.py +++ /dev/null @@ -1,75 +0,0 @@ -# -# This file is part of gunicorn released under the MIT license. -# See the NOTICE for more information. - -import os -import socket - -SD_LISTEN_FDS_START = 3 - - -def listen_fds(unset_environment=True): - """ - Get the number of sockets inherited from systemd socket activation. - - :param unset_environment: clear systemd environment variables unless False - :type unset_environment: bool - :return: the number of sockets to inherit from systemd socket activation - :rtype: int - - Returns zero immediately if $LISTEN_PID is not set to the current pid. - Otherwise, returns the number of systemd activation sockets specified by - $LISTEN_FDS. - - When $LISTEN_PID matches the current pid, unsets the environment variables - unless the ``unset_environment`` flag is ``False``. - - .. note:: - Unlike the sd_listen_fds C function, this implementation does not set - the FD_CLOEXEC flag because the gunicorn arbiter never needs to do this. - - .. seealso:: - ``_ - - """ - fds = int(os.environ.get('LISTEN_FDS', 0)) - listen_pid = int(os.environ.get('LISTEN_PID', 0)) - - if listen_pid != os.getpid(): - return 0 - - if unset_environment: - os.environ.pop('LISTEN_PID', None) - os.environ.pop('LISTEN_FDS', None) - - return fds - - -def sd_notify(state, logger, unset_environment=False): - """Send a notification to systemd. state is a string; see - the man page of sd_notify (http://www.freedesktop.org/software/systemd/man/sd_notify.html) - for a description of the allowable values. - - If the unset_environment parameter is True, sd_notify() will unset - the $NOTIFY_SOCKET environment variable before returning (regardless of - whether the function call itself succeeded or not). Further calls to - sd_notify() will then fail, but the variable is no longer inherited by - child processes. - """ - - addr = os.environ.get('NOTIFY_SOCKET') - if addr is None: - # not run in a service, just a noop - return - try: - sock = socket.socket(socket.AF_UNIX, socket.SOCK_DGRAM | socket.SOCK_CLOEXEC) - if addr[0] == '@': - addr = '\0' + addr[1:] - sock.connect(addr) - sock.sendall(state.encode('utf-8')) - except Exception: - logger.debug("Exception while invoking sd_notify()", exc_info=True) - finally: - if unset_environment: - os.environ.pop('NOTIFY_SOCKET') - sock.close() diff --git a/venv/lib/python3.9/site-packages/gunicorn/util.py b/venv/lib/python3.9/site-packages/gunicorn/util.py deleted file mode 100644 index ecd8174..0000000 --- a/venv/lib/python3.9/site-packages/gunicorn/util.py +++ /dev/null @@ -1,653 +0,0 @@ -# -# This file is part of gunicorn released under the MIT license. -# See the NOTICE for more information. -import ast -import email.utils -import errno -import fcntl -import html -import importlib -import inspect -import io -import logging -import os -import pwd -import random -import re -import socket -import sys -import textwrap -import time -import traceback -import warnings - -try: - import importlib.metadata as importlib_metadata -except (ModuleNotFoundError, ImportError): - import importlib_metadata - -from gunicorn.errors import AppImportError -from gunicorn.workers import SUPPORTED_WORKERS -import urllib.parse - -REDIRECT_TO = getattr(os, 'devnull', '/dev/null') - -# Server and Date aren't technically hop-by-hop -# headers, but they are in the purview of the -# origin server which the WSGI spec says we should -# act like. So we drop them and add our own. -# -# In the future, concatenation server header values -# might be better, but nothing else does it and -# dropping them is easier. -hop_headers = set(""" - connection keep-alive proxy-authenticate proxy-authorization - te trailers transfer-encoding upgrade - server date - """.split()) - -try: - from setproctitle import setproctitle - - def _setproctitle(title): - setproctitle("gunicorn: %s" % title) -except ImportError: - def _setproctitle(title): - pass - - -def load_entry_point(distribution, group, name): - dist_obj = importlib_metadata.distribution(distribution) - eps = [ep for ep in dist_obj.entry_points - if ep.group == group and ep.name == name] - if not eps: - raise ImportError("Entry point %r not found" % ((group, name),)) - return eps[0].load() - - -def load_class(uri, default="gunicorn.workers.sync.SyncWorker", - section="gunicorn.workers"): - if inspect.isclass(uri): - return uri - if uri.startswith("egg:"): - # uses entry points - entry_str = uri.split("egg:")[1] - try: - dist, name = entry_str.rsplit("#", 1) - except ValueError: - dist = entry_str - name = default - - try: - return load_entry_point(dist, section, name) - except Exception: - exc = traceback.format_exc() - msg = "class uri %r invalid or not found: \n\n[%s]" - raise RuntimeError(msg % (uri, exc)) - else: - components = uri.split('.') - if len(components) == 1: - while True: - if uri.startswith("#"): - uri = uri[1:] - - if uri in SUPPORTED_WORKERS: - components = SUPPORTED_WORKERS[uri].split(".") - break - - try: - return load_entry_point( - "gunicorn", section, uri - ) - except Exception: - exc = traceback.format_exc() - msg = "class uri %r invalid or not found: \n\n[%s]" - raise RuntimeError(msg % (uri, exc)) - - klass = components.pop(-1) - - try: - mod = importlib.import_module('.'.join(components)) - except Exception: - exc = traceback.format_exc() - msg = "class uri %r invalid or not found: \n\n[%s]" - raise RuntimeError(msg % (uri, exc)) - return getattr(mod, klass) - - -positionals = ( - inspect.Parameter.POSITIONAL_ONLY, - inspect.Parameter.POSITIONAL_OR_KEYWORD, -) - - -def get_arity(f): - sig = inspect.signature(f) - arity = 0 - - for param in sig.parameters.values(): - if param.kind in positionals: - arity += 1 - - return arity - - -def get_username(uid): - """ get the username for a user id""" - return pwd.getpwuid(uid).pw_name - - -def set_owner_process(uid, gid, initgroups=False): - """ set user and group of workers processes """ - - if gid: - if uid: - try: - username = get_username(uid) - except KeyError: - initgroups = False - - # versions of python < 2.6.2 don't manage unsigned int for - # groups like on osx or fedora - gid = abs(gid) & 0x7FFFFFFF - - if initgroups: - os.initgroups(username, gid) - elif gid != os.getgid(): - os.setgid(gid) - - if uid and uid != os.getuid(): - os.setuid(uid) - - -def chown(path, uid, gid): - os.chown(path, uid, gid) - - -if sys.platform.startswith("win"): - def _waitfor(func, pathname, waitall=False): - # Perform the operation - func(pathname) - # Now setup the wait loop - if waitall: - dirname = pathname - else: - dirname, name = os.path.split(pathname) - dirname = dirname or '.' - # Check for `pathname` to be removed from the filesystem. - # The exponential backoff of the timeout amounts to a total - # of ~1 second after which the deletion is probably an error - # anyway. - # Testing on a i7@4.3GHz shows that usually only 1 iteration is - # required when contention occurs. - timeout = 0.001 - while timeout < 1.0: - # Note we are only testing for the existence of the file(s) in - # the contents of the directory regardless of any security or - # access rights. If we have made it this far, we have sufficient - # permissions to do that much using Python's equivalent of the - # Windows API FindFirstFile. - # Other Windows APIs can fail or give incorrect results when - # dealing with files that are pending deletion. - L = os.listdir(dirname) - if not L if waitall else name in L: - return - # Increase the timeout and try again - time.sleep(timeout) - timeout *= 2 - warnings.warn('tests may fail, delete still pending for ' + pathname, - RuntimeWarning, stacklevel=4) - - def _unlink(filename): - _waitfor(os.unlink, filename) -else: - _unlink = os.unlink - - -def unlink(filename): - try: - _unlink(filename) - except OSError as error: - # The filename need not exist. - if error.errno not in (errno.ENOENT, errno.ENOTDIR): - raise - - -def is_ipv6(addr): - try: - socket.inet_pton(socket.AF_INET6, addr) - except OSError: # not a valid address - return False - except ValueError: # ipv6 not supported on this platform - return False - return True - - -def parse_address(netloc, default_port='8000'): - if re.match(r'unix:(//)?', netloc): - return re.split(r'unix:(//)?', netloc)[-1] - - if netloc.startswith("fd://"): - fd = netloc[5:] - try: - return int(fd) - except ValueError: - raise RuntimeError("%r is not a valid file descriptor." % fd) from None - - if netloc.startswith("tcp://"): - netloc = netloc.split("tcp://")[1] - host, port = netloc, default_port - - if '[' in netloc and ']' in netloc: - host = netloc.split(']')[0][1:] - port = (netloc.split(']:') + [default_port])[1] - elif ':' in netloc: - host, port = (netloc.split(':') + [default_port])[:2] - elif netloc == "": - host, port = "0.0.0.0", default_port - - try: - port = int(port) - except ValueError: - raise RuntimeError("%r is not a valid port number." % port) - - return host.lower(), port - - -def close_on_exec(fd): - flags = fcntl.fcntl(fd, fcntl.F_GETFD) - flags |= fcntl.FD_CLOEXEC - fcntl.fcntl(fd, fcntl.F_SETFD, flags) - - -def set_non_blocking(fd): - flags = fcntl.fcntl(fd, fcntl.F_GETFL) | os.O_NONBLOCK - fcntl.fcntl(fd, fcntl.F_SETFL, flags) - - -def close(sock): - try: - sock.close() - except OSError: - pass - - -try: - from os import closerange -except ImportError: - def closerange(fd_low, fd_high): - # Iterate through and close all file descriptors. - for fd in range(fd_low, fd_high): - try: - os.close(fd) - except OSError: # ERROR, fd wasn't open to begin with (ignored) - pass - - -def write_chunk(sock, data): - if isinstance(data, str): - data = data.encode('utf-8') - chunk_size = "%X\r\n" % len(data) - chunk = b"".join([chunk_size.encode('utf-8'), data, b"\r\n"]) - sock.sendall(chunk) - - -def write(sock, data, chunked=False): - if chunked: - return write_chunk(sock, data) - sock.sendall(data) - - -def write_nonblock(sock, data, chunked=False): - timeout = sock.gettimeout() - if timeout != 0.0: - try: - sock.setblocking(0) - return write(sock, data, chunked) - finally: - sock.setblocking(1) - else: - return write(sock, data, chunked) - - -def write_error(sock, status_int, reason, mesg): - html_error = textwrap.dedent("""\ - - - %(reason)s - - -

    %(reason)s

    - %(mesg)s - - - """) % {"reason": reason, "mesg": html.escape(mesg)} - - http = textwrap.dedent("""\ - HTTP/1.1 %s %s\r - Connection: close\r - Content-Type: text/html\r - Content-Length: %d\r - \r - %s""") % (str(status_int), reason, len(html_error), html_error) - write_nonblock(sock, http.encode('latin1')) - - -def _called_with_wrong_args(f): - """Check whether calling a function raised a ``TypeError`` because - the call failed or because something in the function raised the - error. - - :param f: The function that was called. - :return: ``True`` if the call failed. - """ - tb = sys.exc_info()[2] - - try: - while tb is not None: - if tb.tb_frame.f_code is f.__code__: - # In the function, it was called successfully. - return False - - tb = tb.tb_next - - # Didn't reach the function. - return True - finally: - # Delete tb to break a circular reference in Python 2. - # https://docs.python.org/2/library/sys.html#sys.exc_info - del tb - - -def import_app(module): - parts = module.split(":", 1) - if len(parts) == 1: - obj = "application" - else: - module, obj = parts[0], parts[1] - - try: - mod = importlib.import_module(module) - except ImportError: - if module.endswith(".py") and os.path.exists(module): - msg = "Failed to find application, did you mean '%s:%s'?" - raise ImportError(msg % (module.rsplit(".", 1)[0], obj)) - raise - - # Parse obj as a single expression to determine if it's a valid - # attribute name or function call. - try: - expression = ast.parse(obj, mode="eval").body - except SyntaxError: - raise AppImportError( - "Failed to parse %r as an attribute name or function call." % obj - ) - - if isinstance(expression, ast.Name): - name = expression.id - args = kwargs = None - elif isinstance(expression, ast.Call): - # Ensure the function name is an attribute name only. - if not isinstance(expression.func, ast.Name): - raise AppImportError("Function reference must be a simple name: %r" % obj) - - name = expression.func.id - - # Parse the positional and keyword arguments as literals. - try: - args = [ast.literal_eval(arg) for arg in expression.args] - kwargs = {kw.arg: ast.literal_eval(kw.value) for kw in expression.keywords} - except ValueError: - # literal_eval gives cryptic error messages, show a generic - # message with the full expression instead. - raise AppImportError( - "Failed to parse arguments as literal values: %r" % obj - ) - else: - raise AppImportError( - "Failed to parse %r as an attribute name or function call." % obj - ) - - is_debug = logging.root.level == logging.DEBUG - try: - app = getattr(mod, name) - except AttributeError: - if is_debug: - traceback.print_exception(*sys.exc_info()) - raise AppImportError("Failed to find attribute %r in %r." % (name, module)) - - # If the expression was a function call, call the retrieved object - # to get the real application. - if args is not None: - try: - app = app(*args, **kwargs) - except TypeError as e: - # If the TypeError was due to bad arguments to the factory - # function, show Python's nice error message without a - # traceback. - if _called_with_wrong_args(app): - raise AppImportError( - "".join(traceback.format_exception_only(TypeError, e)).strip() - ) - - # Otherwise it was raised from within the function, show the - # full traceback. - raise - - if app is None: - raise AppImportError("Failed to find application object: %r" % obj) - - if not callable(app): - raise AppImportError("Application object must be callable.") - return app - - -def getcwd(): - # get current path, try to use PWD env first - try: - a = os.stat(os.environ['PWD']) - b = os.stat(os.getcwd()) - if a.st_ino == b.st_ino and a.st_dev == b.st_dev: - cwd = os.environ['PWD'] - else: - cwd = os.getcwd() - except Exception: - cwd = os.getcwd() - return cwd - - -def http_date(timestamp=None): - """Return the current date and time formatted for a message header.""" - if timestamp is None: - timestamp = time.time() - s = email.utils.formatdate(timestamp, localtime=False, usegmt=True) - return s - - -def is_hoppish(header): - return header.lower().strip() in hop_headers - - -def daemonize(enable_stdio_inheritance=False): - """\ - Standard daemonization of a process. - http://www.faqs.org/faqs/unix-faq/programmer/faq/ section 1.7 - """ - if 'GUNICORN_FD' not in os.environ: - if os.fork(): - os._exit(0) - os.setsid() - - if os.fork(): - os._exit(0) - - os.umask(0o22) - - # In both the following any file descriptors above stdin - # stdout and stderr are left untouched. The inheritance - # option simply allows one to have output go to a file - # specified by way of shell redirection when not wanting - # to use --error-log option. - - if not enable_stdio_inheritance: - # Remap all of stdin, stdout and stderr on to - # /dev/null. The expectation is that users have - # specified the --error-log option. - - closerange(0, 3) - - fd_null = os.open(REDIRECT_TO, os.O_RDWR) - # PEP 446, make fd for /dev/null inheritable - os.set_inheritable(fd_null, True) - - # expect fd_null to be always 0 here, but in-case not ... - if fd_null != 0: - os.dup2(fd_null, 0) - - os.dup2(fd_null, 1) - os.dup2(fd_null, 2) - - else: - fd_null = os.open(REDIRECT_TO, os.O_RDWR) - - # Always redirect stdin to /dev/null as we would - # never expect to need to read interactive input. - - if fd_null != 0: - os.close(0) - os.dup2(fd_null, 0) - - # If stdout and stderr are still connected to - # their original file descriptors we check to see - # if they are associated with terminal devices. - # When they are we map them to /dev/null so that - # are still detached from any controlling terminal - # properly. If not we preserve them as they are. - # - # If stdin and stdout were not hooked up to the - # original file descriptors, then all bets are - # off and all we can really do is leave them as - # they were. - # - # This will allow 'gunicorn ... > output.log 2>&1' - # to work with stdout/stderr going to the file - # as expected. - # - # Note that if using --error-log option, the log - # file specified through shell redirection will - # only be used up until the log file specified - # by the option takes over. As it replaces stdout - # and stderr at the file descriptor level, then - # anything using stdout or stderr, including having - # cached a reference to them, will still work. - - def redirect(stream, fd_expect): - try: - fd = stream.fileno() - if fd == fd_expect and stream.isatty(): - os.close(fd) - os.dup2(fd_null, fd) - except AttributeError: - pass - - redirect(sys.stdout, 1) - redirect(sys.stderr, 2) - - -def seed(): - try: - random.seed(os.urandom(64)) - except NotImplementedError: - random.seed('%s.%s' % (time.time(), os.getpid())) - - -def check_is_writable(path): - try: - with open(path, 'a') as f: - f.close() - except OSError as e: - raise RuntimeError("Error: '%s' isn't writable [%r]" % (path, e)) - - -def to_bytestring(value, encoding="utf8"): - """Converts a string argument to a byte string""" - if isinstance(value, bytes): - return value - if not isinstance(value, str): - raise TypeError('%r is not a string' % value) - - return value.encode(encoding) - - -def has_fileno(obj): - if not hasattr(obj, "fileno"): - return False - - # check BytesIO case and maybe others - try: - obj.fileno() - except (AttributeError, OSError, io.UnsupportedOperation): - return False - - return True - - -def warn(msg): - print("!!!", file=sys.stderr) - - lines = msg.splitlines() - for i, line in enumerate(lines): - if i == 0: - line = "WARNING: %s" % line - print("!!! %s" % line, file=sys.stderr) - - print("!!!\n", file=sys.stderr) - sys.stderr.flush() - - -def make_fail_app(msg): - msg = to_bytestring(msg) - - def app(environ, start_response): - start_response("500 Internal Server Error", [ - ("Content-Type", "text/plain"), - ("Content-Length", str(len(msg))) - ]) - return [msg] - - return app - - -def split_request_uri(uri): - if uri.startswith("//"): - # When the path starts with //, urlsplit considers it as a - # relative uri while the RFC says we should consider it as abs_path - # http://www.w3.org/Protocols/rfc2616/rfc2616-sec5.html#sec5.1.2 - # We use temporary dot prefix to workaround this behaviour - parts = urllib.parse.urlsplit("." + uri) - return parts._replace(path=parts.path[1:]) - - return urllib.parse.urlsplit(uri) - - -# From six.reraise -def reraise(tp, value, tb=None): - try: - if value is None: - value = tp() - if value.__traceback__ is not tb: - raise value.with_traceback(tb) - raise value - finally: - value = None - tb = None - - -def bytes_to_str(b): - if isinstance(b, str): - return b - return str(b, 'latin1') - - -def unquote_to_wsgi_str(string): - return urllib.parse.unquote_to_bytes(string).decode('latin-1') diff --git a/venv/lib/python3.9/site-packages/gunicorn/workers/__init__.py b/venv/lib/python3.9/site-packages/gunicorn/workers/__init__.py deleted file mode 100644 index 3da5f85..0000000 --- a/venv/lib/python3.9/site-packages/gunicorn/workers/__init__.py +++ /dev/null @@ -1,14 +0,0 @@ -# -# This file is part of gunicorn released under the MIT license. -# See the NOTICE for more information. - -# supported gunicorn workers. -SUPPORTED_WORKERS = { - "sync": "gunicorn.workers.sync.SyncWorker", - "eventlet": "gunicorn.workers.geventlet.EventletWorker", - "gevent": "gunicorn.workers.ggevent.GeventWorker", - "gevent_wsgi": "gunicorn.workers.ggevent.GeventPyWSGIWorker", - "gevent_pywsgi": "gunicorn.workers.ggevent.GeventPyWSGIWorker", - "tornado": "gunicorn.workers.gtornado.TornadoWorker", - "gthread": "gunicorn.workers.gthread.ThreadWorker", -} diff --git a/venv/lib/python3.9/site-packages/gunicorn/workers/base.py b/venv/lib/python3.9/site-packages/gunicorn/workers/base.py deleted file mode 100644 index 93c465c..0000000 --- a/venv/lib/python3.9/site-packages/gunicorn/workers/base.py +++ /dev/null @@ -1,287 +0,0 @@ -# -# This file is part of gunicorn released under the MIT license. -# See the NOTICE for more information. - -import io -import os -import signal -import sys -import time -import traceback -from datetime import datetime -from random import randint -from ssl import SSLError - -from gunicorn import util -from gunicorn.http.errors import ( - ForbiddenProxyRequest, InvalidHeader, - InvalidHeaderName, InvalidHTTPVersion, - InvalidProxyLine, InvalidRequestLine, - InvalidRequestMethod, InvalidSchemeHeaders, - LimitRequestHeaders, LimitRequestLine, - UnsupportedTransferCoding, - ConfigurationProblem, ObsoleteFolding, -) -from gunicorn.http.wsgi import Response, default_environ -from gunicorn.reloader import reloader_engines -from gunicorn.workers.workertmp import WorkerTmp - - -class Worker: - - SIGNALS = [getattr(signal, "SIG%s" % x) for x in ( - "ABRT HUP QUIT INT TERM USR1 USR2 WINCH CHLD".split() - )] - - PIPE = [] - - def __init__(self, age, ppid, sockets, app, timeout, cfg, log): - """\ - This is called pre-fork so it shouldn't do anything to the - current process. If there's a need to make process wide - changes you'll want to do that in ``self.init_process()``. - """ - self.age = age - self.pid = "[booting]" - self.ppid = ppid - self.sockets = sockets - self.app = app - self.timeout = timeout - self.cfg = cfg - self.booted = False - self.aborted = False - self.reloader = None - - self.nr = 0 - - if cfg.max_requests > 0: - jitter = randint(0, cfg.max_requests_jitter) - self.max_requests = cfg.max_requests + jitter - else: - self.max_requests = sys.maxsize - - self.alive = True - self.log = log - self.tmp = WorkerTmp(cfg) - - def __str__(self): - return "" % self.pid - - def notify(self): - """\ - Your worker subclass must arrange to have this method called - once every ``self.timeout`` seconds. If you fail in accomplishing - this task, the master process will murder your workers. - """ - self.tmp.notify() - - def run(self): - """\ - This is the mainloop of a worker process. You should override - this method in a subclass to provide the intended behaviour - for your particular evil schemes. - """ - raise NotImplementedError() - - def init_process(self): - """\ - If you override this method in a subclass, the last statement - in the function should be to call this method with - super().init_process() so that the ``run()`` loop is initiated. - """ - - # set environment' variables - if self.cfg.env: - for k, v in self.cfg.env.items(): - os.environ[k] = v - - util.set_owner_process(self.cfg.uid, self.cfg.gid, - initgroups=self.cfg.initgroups) - - # Reseed the random number generator - util.seed() - - # For waking ourselves up - self.PIPE = os.pipe() - for p in self.PIPE: - util.set_non_blocking(p) - util.close_on_exec(p) - - # Prevent fd inheritance - for s in self.sockets: - util.close_on_exec(s) - util.close_on_exec(self.tmp.fileno()) - - self.wait_fds = self.sockets + [self.PIPE[0]] - - self.log.close_on_exec() - - self.init_signals() - - # start the reloader - if self.cfg.reload: - def changed(fname): - self.log.info("Worker reloading: %s modified", fname) - self.alive = False - os.write(self.PIPE[1], b"1") - self.cfg.worker_int(self) - time.sleep(0.1) - sys.exit(0) - - reloader_cls = reloader_engines[self.cfg.reload_engine] - self.reloader = reloader_cls(extra_files=self.cfg.reload_extra_files, - callback=changed) - - self.load_wsgi() - if self.reloader: - self.reloader.start() - - self.cfg.post_worker_init(self) - - # Enter main run loop - self.booted = True - self.run() - - def load_wsgi(self): - try: - self.wsgi = self.app.wsgi() - except SyntaxError as e: - if not self.cfg.reload: - raise - - self.log.exception(e) - - # fix from PR #1228 - # storing the traceback into exc_tb will create a circular reference. - # per https://docs.python.org/2/library/sys.html#sys.exc_info warning, - # delete the traceback after use. - try: - _, exc_val, exc_tb = sys.exc_info() - self.reloader.add_extra_file(exc_val.filename) - - tb_string = io.StringIO() - traceback.print_tb(exc_tb, file=tb_string) - self.wsgi = util.make_fail_app(tb_string.getvalue()) - finally: - del exc_tb - - def init_signals(self): - # reset signaling - for s in self.SIGNALS: - signal.signal(s, signal.SIG_DFL) - # init new signaling - signal.signal(signal.SIGQUIT, self.handle_quit) - signal.signal(signal.SIGTERM, self.handle_exit) - signal.signal(signal.SIGINT, self.handle_quit) - signal.signal(signal.SIGWINCH, self.handle_winch) - signal.signal(signal.SIGUSR1, self.handle_usr1) - signal.signal(signal.SIGABRT, self.handle_abort) - - # Don't let SIGTERM and SIGUSR1 disturb active requests - # by interrupting system calls - signal.siginterrupt(signal.SIGTERM, False) - signal.siginterrupt(signal.SIGUSR1, False) - - if hasattr(signal, 'set_wakeup_fd'): - signal.set_wakeup_fd(self.PIPE[1]) - - def handle_usr1(self, sig, frame): - self.log.reopen_files() - - def handle_exit(self, sig, frame): - self.alive = False - - def handle_quit(self, sig, frame): - self.alive = False - # worker_int callback - self.cfg.worker_int(self) - time.sleep(0.1) - sys.exit(0) - - def handle_abort(self, sig, frame): - self.alive = False - self.cfg.worker_abort(self) - sys.exit(1) - - def handle_error(self, req, client, addr, exc): - request_start = datetime.now() - addr = addr or ('', -1) # unix socket case - if isinstance(exc, ( - InvalidRequestLine, InvalidRequestMethod, - InvalidHTTPVersion, InvalidHeader, InvalidHeaderName, - LimitRequestLine, LimitRequestHeaders, - InvalidProxyLine, ForbiddenProxyRequest, - InvalidSchemeHeaders, UnsupportedTransferCoding, - ConfigurationProblem, ObsoleteFolding, - SSLError, - )): - - status_int = 400 - reason = "Bad Request" - - if isinstance(exc, InvalidRequestLine): - mesg = "Invalid Request Line '%s'" % str(exc) - elif isinstance(exc, InvalidRequestMethod): - mesg = "Invalid Method '%s'" % str(exc) - elif isinstance(exc, InvalidHTTPVersion): - mesg = "Invalid HTTP Version '%s'" % str(exc) - elif isinstance(exc, UnsupportedTransferCoding): - mesg = "%s" % str(exc) - status_int = 501 - elif isinstance(exc, ConfigurationProblem): - mesg = "%s" % str(exc) - status_int = 500 - elif isinstance(exc, ObsoleteFolding): - mesg = "%s" % str(exc) - elif isinstance(exc, (InvalidHeaderName, InvalidHeader,)): - mesg = "%s" % str(exc) - if not req and hasattr(exc, "req"): - req = exc.req # for access log - elif isinstance(exc, LimitRequestLine): - mesg = "%s" % str(exc) - elif isinstance(exc, LimitRequestHeaders): - reason = "Request Header Fields Too Large" - mesg = "Error parsing headers: '%s'" % str(exc) - status_int = 431 - elif isinstance(exc, InvalidProxyLine): - mesg = "'%s'" % str(exc) - elif isinstance(exc, ForbiddenProxyRequest): - reason = "Forbidden" - mesg = "Request forbidden" - status_int = 403 - elif isinstance(exc, InvalidSchemeHeaders): - mesg = "%s" % str(exc) - elif isinstance(exc, SSLError): - reason = "Forbidden" - mesg = "'%s'" % str(exc) - status_int = 403 - - msg = "Invalid request from ip={ip}: {error}" - self.log.warning(msg.format(ip=addr[0], error=str(exc))) - else: - if hasattr(req, "uri"): - self.log.exception("Error handling request %s", req.uri) - else: - self.log.exception("Error handling request (no URI read)") - status_int = 500 - reason = "Internal Server Error" - mesg = "" - - if req is not None: - request_time = datetime.now() - request_start - environ = default_environ(req, client, self.cfg) - environ['REMOTE_ADDR'] = addr[0] - environ['REMOTE_PORT'] = str(addr[1]) - resp = Response(req, client, self.cfg) - resp.status = "%s %s" % (status_int, reason) - resp.response_length = len(mesg) - self.log.access(resp, req, environ, request_time) - - try: - util.write_error(client, status_int, reason, mesg) - except Exception: - self.log.debug("Failed to send error message.") - - def handle_winch(self, sig, fname): - # Ignore SIGWINCH in worker. Fixes a crash on OpenBSD. - self.log.debug("worker: SIGWINCH ignored.") diff --git a/venv/lib/python3.9/site-packages/gunicorn/workers/base_async.py b/venv/lib/python3.9/site-packages/gunicorn/workers/base_async.py deleted file mode 100644 index 9466d6a..0000000 --- a/venv/lib/python3.9/site-packages/gunicorn/workers/base_async.py +++ /dev/null @@ -1,147 +0,0 @@ -# -# This file is part of gunicorn released under the MIT license. -# See the NOTICE for more information. - -from datetime import datetime -import errno -import socket -import ssl -import sys - -from gunicorn import http -from gunicorn.http import wsgi -from gunicorn import util -from gunicorn.workers import base - -ALREADY_HANDLED = object() - - -class AsyncWorker(base.Worker): - - def __init__(self, *args, **kwargs): - super().__init__(*args, **kwargs) - self.worker_connections = self.cfg.worker_connections - - def timeout_ctx(self): - raise NotImplementedError() - - def is_already_handled(self, respiter): - # some workers will need to overload this function to raise a StopIteration - return respiter == ALREADY_HANDLED - - def handle(self, listener, client, addr): - req = None - try: - parser = http.RequestParser(self.cfg, client, addr) - try: - listener_name = listener.getsockname() - if not self.cfg.keepalive: - req = next(parser) - self.handle_request(listener_name, req, client, addr) - else: - # keepalive loop - proxy_protocol_info = {} - while True: - req = None - with self.timeout_ctx(): - req = next(parser) - if not req: - break - if req.proxy_protocol_info: - proxy_protocol_info = req.proxy_protocol_info - else: - req.proxy_protocol_info = proxy_protocol_info - self.handle_request(listener_name, req, client, addr) - except http.errors.NoMoreData as e: - self.log.debug("Ignored premature client disconnection. %s", e) - except StopIteration as e: - self.log.debug("Closing connection. %s", e) - except ssl.SSLError: - # pass to next try-except level - util.reraise(*sys.exc_info()) - except OSError: - # pass to next try-except level - util.reraise(*sys.exc_info()) - except Exception as e: - self.handle_error(req, client, addr, e) - except ssl.SSLError as e: - if e.args[0] == ssl.SSL_ERROR_EOF: - self.log.debug("ssl connection closed") - client.close() - else: - self.log.debug("Error processing SSL request.") - self.handle_error(req, client, addr, e) - except OSError as e: - if e.errno not in (errno.EPIPE, errno.ECONNRESET, errno.ENOTCONN): - self.log.exception("Socket error processing request.") - else: - if e.errno == errno.ECONNRESET: - self.log.debug("Ignoring connection reset") - elif e.errno == errno.ENOTCONN: - self.log.debug("Ignoring socket not connected") - else: - self.log.debug("Ignoring EPIPE") - except BaseException as e: - self.handle_error(req, client, addr, e) - finally: - util.close(client) - - def handle_request(self, listener_name, req, sock, addr): - request_start = datetime.now() - environ = {} - resp = None - try: - self.cfg.pre_request(self, req) - resp, environ = wsgi.create(req, sock, addr, - listener_name, self.cfg) - environ["wsgi.multithread"] = True - self.nr += 1 - if self.nr >= self.max_requests: - if self.alive: - self.log.info("Autorestarting worker after current request.") - self.alive = False - - if not self.alive or not self.cfg.keepalive: - resp.force_close() - - respiter = self.wsgi(environ, resp.start_response) - if self.is_already_handled(respiter): - return False - try: - if isinstance(respiter, environ['wsgi.file_wrapper']): - resp.write_file(respiter) - else: - for item in respiter: - resp.write(item) - resp.close() - finally: - request_time = datetime.now() - request_start - self.log.access(resp, req, environ, request_time) - if hasattr(respiter, "close"): - respiter.close() - if resp.should_close(): - raise StopIteration() - except StopIteration: - raise - except OSError: - # If the original exception was a socket.error we delegate - # handling it to the caller (where handle() might ignore it) - util.reraise(*sys.exc_info()) - except Exception: - if resp and resp.headers_sent: - # If the requests have already been sent, we should close the - # connection to indicate the error. - self.log.exception("Error handling request") - try: - sock.shutdown(socket.SHUT_RDWR) - sock.close() - except OSError: - pass - raise StopIteration() - raise - finally: - try: - self.cfg.post_request(self, req, environ, resp) - except Exception: - self.log.exception("Exception in post_request hook") - return True diff --git a/venv/lib/python3.9/site-packages/gunicorn/workers/geventlet.py b/venv/lib/python3.9/site-packages/gunicorn/workers/geventlet.py deleted file mode 100644 index 087eb61..0000000 --- a/venv/lib/python3.9/site-packages/gunicorn/workers/geventlet.py +++ /dev/null @@ -1,186 +0,0 @@ -# -# This file is part of gunicorn released under the MIT license. -# See the NOTICE for more information. - -from functools import partial -import sys - -try: - import eventlet -except ImportError: - raise RuntimeError("eventlet worker requires eventlet 0.24.1 or higher") -else: - from packaging.version import parse as parse_version - if parse_version(eventlet.__version__) < parse_version('0.24.1'): - raise RuntimeError("eventlet worker requires eventlet 0.24.1 or higher") - -from eventlet import hubs, greenthread -from eventlet.greenio import GreenSocket -import eventlet.wsgi -import greenlet - -from gunicorn.workers.base_async import AsyncWorker -from gunicorn.sock import ssl_wrap_socket - -# ALREADY_HANDLED is removed in 0.30.3+ now it's `WSGI_LOCAL.already_handled: bool` -# https://github.com/eventlet/eventlet/pull/544 -EVENTLET_WSGI_LOCAL = getattr(eventlet.wsgi, "WSGI_LOCAL", None) -EVENTLET_ALREADY_HANDLED = getattr(eventlet.wsgi, "ALREADY_HANDLED", None) - - -def _eventlet_socket_sendfile(self, file, offset=0, count=None): - # Based on the implementation in gevent which in turn is slightly - # modified from the standard library implementation. - if self.gettimeout() == 0: - raise ValueError("non-blocking sockets are not supported") - if offset: - file.seek(offset) - blocksize = min(count, 8192) if count else 8192 - total_sent = 0 - # localize variable access to minimize overhead - file_read = file.read - sock_send = self.send - try: - while True: - if count: - blocksize = min(count - total_sent, blocksize) - if blocksize <= 0: - break - data = memoryview(file_read(blocksize)) - if not data: - break # EOF - while True: - try: - sent = sock_send(data) - except BlockingIOError: - continue - else: - total_sent += sent - if sent < len(data): - data = data[sent:] - else: - break - return total_sent - finally: - if total_sent > 0 and hasattr(file, 'seek'): - file.seek(offset + total_sent) - - -def _eventlet_serve(sock, handle, concurrency): - """ - Serve requests forever. - - This code is nearly identical to ``eventlet.convenience.serve`` except - that it attempts to join the pool at the end, which allows for gunicorn - graceful shutdowns. - """ - pool = eventlet.greenpool.GreenPool(concurrency) - server_gt = eventlet.greenthread.getcurrent() - - while True: - try: - conn, addr = sock.accept() - gt = pool.spawn(handle, conn, addr) - gt.link(_eventlet_stop, server_gt, conn) - conn, addr, gt = None, None, None - except eventlet.StopServe: - sock.close() - pool.waitall() - return - - -def _eventlet_stop(client, server, conn): - """ - Stop a greenlet handling a request and close its connection. - - This code is lifted from eventlet so as not to depend on undocumented - functions in the library. - """ - try: - try: - client.wait() - finally: - conn.close() - except greenlet.GreenletExit: - pass - except Exception: - greenthread.kill(server, *sys.exc_info()) - - -def patch_sendfile(): - # As of eventlet 0.25.1, GreenSocket.sendfile doesn't exist, - # meaning the native implementations of socket.sendfile will be used. - # If os.sendfile exists, it will attempt to use that, failing explicitly - # if the socket is in non-blocking mode, which the underlying - # socket object /is/. Even the regular _sendfile_use_send will - # fail in that way; plus, it would use the underlying socket.send which isn't - # properly cooperative. So we have to monkey-patch a working socket.sendfile() - # into GreenSocket; in this method, `self.send` will be the GreenSocket's - # send method which is properly cooperative. - if not hasattr(GreenSocket, 'sendfile'): - GreenSocket.sendfile = _eventlet_socket_sendfile - - -class EventletWorker(AsyncWorker): - - def patch(self): - hubs.use_hub() - eventlet.monkey_patch() - patch_sendfile() - - def is_already_handled(self, respiter): - # eventlet >= 0.30.3 - if getattr(EVENTLET_WSGI_LOCAL, "already_handled", None): - raise StopIteration() - # eventlet < 0.30.3 - if respiter == EVENTLET_ALREADY_HANDLED: - raise StopIteration() - return super().is_already_handled(respiter) - - def init_process(self): - self.patch() - super().init_process() - - def handle_quit(self, sig, frame): - eventlet.spawn(super().handle_quit, sig, frame) - - def handle_usr1(self, sig, frame): - eventlet.spawn(super().handle_usr1, sig, frame) - - def timeout_ctx(self): - return eventlet.Timeout(self.cfg.keepalive or None, False) - - def handle(self, listener, client, addr): - if self.cfg.is_ssl: - client = ssl_wrap_socket(client, self.cfg) - super().handle(listener, client, addr) - - def run(self): - acceptors = [] - for sock in self.sockets: - gsock = GreenSocket(sock) - gsock.setblocking(1) - hfun = partial(self.handle, gsock) - acceptor = eventlet.spawn(_eventlet_serve, gsock, hfun, - self.worker_connections) - - acceptors.append(acceptor) - eventlet.sleep(0.0) - - while self.alive: - self.notify() - eventlet.sleep(1.0) - - self.notify() - t = None - try: - with eventlet.Timeout(self.cfg.graceful_timeout) as t: - for a in acceptors: - a.kill(eventlet.StopServe()) - for a in acceptors: - a.wait() - except eventlet.Timeout as te: - if te != t: - raise - for a in acceptors: - a.kill() diff --git a/venv/lib/python3.9/site-packages/gunicorn/workers/ggevent.py b/venv/lib/python3.9/site-packages/gunicorn/workers/ggevent.py deleted file mode 100644 index b9b9b44..0000000 --- a/venv/lib/python3.9/site-packages/gunicorn/workers/ggevent.py +++ /dev/null @@ -1,193 +0,0 @@ -# -# This file is part of gunicorn released under the MIT license. -# See the NOTICE for more information. - -import os -import sys -from datetime import datetime -from functools import partial -import time - -try: - import gevent -except ImportError: - raise RuntimeError("gevent worker requires gevent 1.4 or higher") -else: - from packaging.version import parse as parse_version - if parse_version(gevent.__version__) < parse_version('1.4'): - raise RuntimeError("gevent worker requires gevent 1.4 or higher") - -from gevent.pool import Pool -from gevent.server import StreamServer -from gevent import hub, monkey, socket, pywsgi - -import gunicorn -from gunicorn.http.wsgi import base_environ -from gunicorn.sock import ssl_context -from gunicorn.workers.base_async import AsyncWorker - -VERSION = "gevent/%s gunicorn/%s" % (gevent.__version__, gunicorn.__version__) - - -class GeventWorker(AsyncWorker): - - server_class = None - wsgi_handler = None - - def patch(self): - monkey.patch_all() - - # patch sockets - sockets = [] - for s in self.sockets: - sockets.append(socket.socket(s.FAMILY, socket.SOCK_STREAM, - fileno=s.sock.fileno())) - self.sockets = sockets - - def notify(self): - super().notify() - if self.ppid != os.getppid(): - self.log.info("Parent changed, shutting down: %s", self) - sys.exit(0) - - def timeout_ctx(self): - return gevent.Timeout(self.cfg.keepalive, False) - - def run(self): - servers = [] - ssl_args = {} - - if self.cfg.is_ssl: - ssl_args = {"ssl_context": ssl_context(self.cfg)} - - for s in self.sockets: - s.setblocking(1) - pool = Pool(self.worker_connections) - if self.server_class is not None: - environ = base_environ(self.cfg) - environ.update({ - "wsgi.multithread": True, - "SERVER_SOFTWARE": VERSION, - }) - server = self.server_class( - s, application=self.wsgi, spawn=pool, log=self.log, - handler_class=self.wsgi_handler, environ=environ, - **ssl_args) - else: - hfun = partial(self.handle, s) - server = StreamServer(s, handle=hfun, spawn=pool, **ssl_args) - if self.cfg.workers > 1: - server.max_accept = 1 - - server.start() - servers.append(server) - - while self.alive: - self.notify() - gevent.sleep(1.0) - - try: - # Stop accepting requests - for server in servers: - if hasattr(server, 'close'): # gevent 1.0 - server.close() - if hasattr(server, 'kill'): # gevent < 1.0 - server.kill() - - # Handle current requests until graceful_timeout - ts = time.time() - while time.time() - ts <= self.cfg.graceful_timeout: - accepting = 0 - for server in servers: - if server.pool.free_count() != server.pool.size: - accepting += 1 - - # if no server is accepting a connection, we can exit - if not accepting: - return - - self.notify() - gevent.sleep(1.0) - - # Force kill all active the handlers - self.log.warning("Worker graceful timeout (pid:%s)", self.pid) - for server in servers: - server.stop(timeout=1) - except Exception: - pass - - def handle(self, listener, client, addr): - # Connected socket timeout defaults to socket.getdefaulttimeout(). - # This forces to blocking mode. - client.setblocking(1) - super().handle(listener, client, addr) - - def handle_request(self, listener_name, req, sock, addr): - try: - super().handle_request(listener_name, req, sock, addr) - except gevent.GreenletExit: - pass - except SystemExit: - pass - - def handle_quit(self, sig, frame): - # Move this out of the signal handler so we can use - # blocking calls. See #1126 - gevent.spawn(super().handle_quit, sig, frame) - - def handle_usr1(self, sig, frame): - # Make the gevent workers handle the usr1 signal - # by deferring to a new greenlet. See #1645 - gevent.spawn(super().handle_usr1, sig, frame) - - def init_process(self): - self.patch() - hub.reinit() - super().init_process() - - -class GeventResponse: - - status = None - headers = None - sent = None - - def __init__(self, status, headers, clength): - self.status = status - self.headers = headers - self.sent = clength - - -class PyWSGIHandler(pywsgi.WSGIHandler): - - def log_request(self): - start = datetime.fromtimestamp(self.time_start) - finish = datetime.fromtimestamp(self.time_finish) - response_time = finish - start - resp_headers = getattr(self, 'response_headers', {}) - - # Status is expected to be a string but is encoded to bytes in gevent for PY3 - # Except when it isn't because gevent uses hardcoded strings for network errors. - status = self.status.decode() if isinstance(self.status, bytes) else self.status - resp = GeventResponse(status, resp_headers, self.response_length) - if hasattr(self, 'headers'): - req_headers = self.headers.items() - else: - req_headers = [] - self.server.log.access(resp, req_headers, self.environ, response_time) - - def get_environ(self): - env = super().get_environ() - env['gunicorn.sock'] = self.socket - env['RAW_URI'] = self.path - return env - - -class PyWSGIServer(pywsgi.WSGIServer): - pass - - -class GeventPyWSGIWorker(GeventWorker): - "The Gevent StreamServer based workers." - server_class = PyWSGIServer - wsgi_handler = PyWSGIHandler diff --git a/venv/lib/python3.9/site-packages/gunicorn/workers/gthread.py b/venv/lib/python3.9/site-packages/gunicorn/workers/gthread.py deleted file mode 100644 index 7a23228..0000000 --- a/venv/lib/python3.9/site-packages/gunicorn/workers/gthread.py +++ /dev/null @@ -1,372 +0,0 @@ -# -# This file is part of gunicorn released under the MIT license. -# See the NOTICE for more information. - -# design: -# A threaded worker accepts connections in the main loop, accepted -# connections are added to the thread pool as a connection job. -# Keepalive connections are put back in the loop waiting for an event. -# If no event happen after the keep alive timeout, the connection is -# closed. -# pylint: disable=no-else-break - -from concurrent import futures -import errno -import os -import selectors -import socket -import ssl -import sys -import time -from collections import deque -from datetime import datetime -from functools import partial -from threading import RLock - -from . import base -from .. import http -from .. import util -from .. import sock -from ..http import wsgi - - -class TConn: - - def __init__(self, cfg, sock, client, server): - self.cfg = cfg - self.sock = sock - self.client = client - self.server = server - - self.timeout = None - self.parser = None - self.initialized = False - - # set the socket to non blocking - self.sock.setblocking(False) - - def init(self): - self.initialized = True - self.sock.setblocking(True) - - if self.parser is None: - # wrap the socket if needed - if self.cfg.is_ssl: - self.sock = sock.ssl_wrap_socket(self.sock, self.cfg) - - # initialize the parser - self.parser = http.RequestParser(self.cfg, self.sock, self.client) - - def set_timeout(self): - # set the timeout - self.timeout = time.time() + self.cfg.keepalive - - def close(self): - util.close(self.sock) - - -class ThreadWorker(base.Worker): - - def __init__(self, *args, **kwargs): - super().__init__(*args, **kwargs) - self.worker_connections = self.cfg.worker_connections - self.max_keepalived = self.cfg.worker_connections - self.cfg.threads - # initialise the pool - self.tpool = None - self.poller = None - self._lock = None - self.futures = deque() - self._keep = deque() - self.nr_conns = 0 - - @classmethod - def check_config(cls, cfg, log): - max_keepalived = cfg.worker_connections - cfg.threads - - if max_keepalived <= 0 and cfg.keepalive: - log.warning("No keepalived connections can be handled. " + - "Check the number of worker connections and threads.") - - def init_process(self): - self.tpool = self.get_thread_pool() - self.poller = selectors.DefaultSelector() - self._lock = RLock() - super().init_process() - - def get_thread_pool(self): - """Override this method to customize how the thread pool is created""" - return futures.ThreadPoolExecutor(max_workers=self.cfg.threads) - - def handle_quit(self, sig, frame): - self.alive = False - # worker_int callback - self.cfg.worker_int(self) - self.tpool.shutdown(False) - time.sleep(0.1) - sys.exit(0) - - def _wrap_future(self, fs, conn): - fs.conn = conn - self.futures.append(fs) - fs.add_done_callback(self.finish_request) - - def enqueue_req(self, conn): - conn.init() - # submit the connection to a worker - fs = self.tpool.submit(self.handle, conn) - self._wrap_future(fs, conn) - - def accept(self, server, listener): - try: - sock, client = listener.accept() - # initialize the connection object - conn = TConn(self.cfg, sock, client, server) - - self.nr_conns += 1 - # wait until socket is readable - with self._lock: - self.poller.register(conn.sock, selectors.EVENT_READ, - partial(self.on_client_socket_readable, conn)) - except OSError as e: - if e.errno not in (errno.EAGAIN, errno.ECONNABORTED, - errno.EWOULDBLOCK): - raise - - def on_client_socket_readable(self, conn, client): - with self._lock: - # unregister the client from the poller - self.poller.unregister(client) - - if conn.initialized: - # remove the connection from keepalive - try: - self._keep.remove(conn) - except ValueError: - # race condition - return - - # submit the connection to a worker - self.enqueue_req(conn) - - def murder_keepalived(self): - now = time.time() - while True: - with self._lock: - try: - # remove the connection from the queue - conn = self._keep.popleft() - except IndexError: - break - - delta = conn.timeout - now - if delta > 0: - # add the connection back to the queue - with self._lock: - self._keep.appendleft(conn) - break - else: - self.nr_conns -= 1 - # remove the socket from the poller - with self._lock: - try: - self.poller.unregister(conn.sock) - except OSError as e: - if e.errno != errno.EBADF: - raise - except KeyError: - # already removed by the system, continue - pass - except ValueError: - # already removed by the system continue - pass - - # close the socket - conn.close() - - def is_parent_alive(self): - # If our parent changed then we shut down. - if self.ppid != os.getppid(): - self.log.info("Parent changed, shutting down: %s", self) - return False - return True - - def run(self): - # init listeners, add them to the event loop - for sock in self.sockets: - sock.setblocking(False) - # a race condition during graceful shutdown may make the listener - # name unavailable in the request handler so capture it once here - server = sock.getsockname() - acceptor = partial(self.accept, server) - self.poller.register(sock, selectors.EVENT_READ, acceptor) - - while self.alive: - # notify the arbiter we are alive - self.notify() - - # can we accept more connections? - if self.nr_conns < self.worker_connections: - # wait for an event - events = self.poller.select(1.0) - for key, _ in events: - callback = key.data - callback(key.fileobj) - - # check (but do not wait) for finished requests - result = futures.wait(self.futures, timeout=0, - return_when=futures.FIRST_COMPLETED) - else: - # wait for a request to finish - result = futures.wait(self.futures, timeout=1.0, - return_when=futures.FIRST_COMPLETED) - - # clean up finished requests - for fut in result.done: - self.futures.remove(fut) - - if not self.is_parent_alive(): - break - - # handle keepalive timeouts - self.murder_keepalived() - - self.tpool.shutdown(False) - self.poller.close() - - for s in self.sockets: - s.close() - - futures.wait(self.futures, timeout=self.cfg.graceful_timeout) - - def finish_request(self, fs): - if fs.cancelled(): - self.nr_conns -= 1 - fs.conn.close() - return - - try: - (keepalive, conn) = fs.result() - # if the connection should be kept alived add it - # to the eventloop and record it - if keepalive and self.alive: - # flag the socket as non blocked - conn.sock.setblocking(False) - - # register the connection - conn.set_timeout() - with self._lock: - self._keep.append(conn) - - # add the socket to the event loop - self.poller.register(conn.sock, selectors.EVENT_READ, - partial(self.on_client_socket_readable, conn)) - else: - self.nr_conns -= 1 - conn.close() - except Exception: - # an exception happened, make sure to close the - # socket. - self.nr_conns -= 1 - fs.conn.close() - - def handle(self, conn): - keepalive = False - req = None - try: - req = next(conn.parser) - if not req: - return (False, conn) - - # handle the request - keepalive = self.handle_request(req, conn) - if keepalive: - return (keepalive, conn) - except http.errors.NoMoreData as e: - self.log.debug("Ignored premature client disconnection. %s", e) - - except StopIteration as e: - self.log.debug("Closing connection. %s", e) - except ssl.SSLError as e: - if e.args[0] == ssl.SSL_ERROR_EOF: - self.log.debug("ssl connection closed") - conn.sock.close() - else: - self.log.debug("Error processing SSL request.") - self.handle_error(req, conn.sock, conn.client, e) - - except OSError as e: - if e.errno not in (errno.EPIPE, errno.ECONNRESET, errno.ENOTCONN): - self.log.exception("Socket error processing request.") - else: - if e.errno == errno.ECONNRESET: - self.log.debug("Ignoring connection reset") - elif e.errno == errno.ENOTCONN: - self.log.debug("Ignoring socket not connected") - else: - self.log.debug("Ignoring connection epipe") - except Exception as e: - self.handle_error(req, conn.sock, conn.client, e) - - return (False, conn) - - def handle_request(self, req, conn): - environ = {} - resp = None - try: - self.cfg.pre_request(self, req) - request_start = datetime.now() - resp, environ = wsgi.create(req, conn.sock, conn.client, - conn.server, self.cfg) - environ["wsgi.multithread"] = True - self.nr += 1 - if self.nr >= self.max_requests: - if self.alive: - self.log.info("Autorestarting worker after current request.") - self.alive = False - resp.force_close() - - if not self.alive or not self.cfg.keepalive: - resp.force_close() - elif len(self._keep) >= self.max_keepalived: - resp.force_close() - - respiter = self.wsgi(environ, resp.start_response) - try: - if isinstance(respiter, environ['wsgi.file_wrapper']): - resp.write_file(respiter) - else: - for item in respiter: - resp.write(item) - - resp.close() - finally: - request_time = datetime.now() - request_start - self.log.access(resp, req, environ, request_time) - if hasattr(respiter, "close"): - respiter.close() - - if resp.should_close(): - self.log.debug("Closing connection.") - return False - except OSError: - # pass to next try-except level - util.reraise(*sys.exc_info()) - except Exception: - if resp and resp.headers_sent: - # If the requests have already been sent, we should close the - # connection to indicate the error. - self.log.exception("Error handling request") - try: - conn.sock.shutdown(socket.SHUT_RDWR) - conn.sock.close() - except OSError: - pass - raise StopIteration() - raise - finally: - try: - self.cfg.post_request(self, req, environ, resp) - except Exception: - self.log.exception("Exception in post_request hook") - - return True diff --git a/venv/lib/python3.9/site-packages/gunicorn/workers/gtornado.py b/venv/lib/python3.9/site-packages/gunicorn/workers/gtornado.py deleted file mode 100644 index 544af7d..0000000 --- a/venv/lib/python3.9/site-packages/gunicorn/workers/gtornado.py +++ /dev/null @@ -1,166 +0,0 @@ -# -# This file is part of gunicorn released under the MIT license. -# See the NOTICE for more information. - -import os -import sys - -try: - import tornado -except ImportError: - raise RuntimeError("You need tornado installed to use this worker.") -import tornado.web -import tornado.httpserver -from tornado.ioloop import IOLoop, PeriodicCallback -from tornado.wsgi import WSGIContainer -from gunicorn.workers.base import Worker -from gunicorn import __version__ as gversion -from gunicorn.sock import ssl_context - - -# Tornado 5.0 updated its IOLoop, and the `io_loop` arguments to many -# Tornado functions have been removed in Tornado 5.0. Also, they no -# longer store PeriodCallbacks in ioloop._callbacks. Instead we store -# them on our side, and use stop() on them when stopping the worker. -# See https://www.tornadoweb.org/en/stable/releases/v5.0.0.html#backwards-compatibility-notes -# for more details. -TORNADO5 = tornado.version_info >= (5, 0, 0) - - -class TornadoWorker(Worker): - - @classmethod - def setup(cls): - web = sys.modules.pop("tornado.web") - old_clear = web.RequestHandler.clear - - def clear(self): - old_clear(self) - if "Gunicorn" not in self._headers["Server"]: - self._headers["Server"] += " (Gunicorn/%s)" % gversion - web.RequestHandler.clear = clear - sys.modules["tornado.web"] = web - - def handle_exit(self, sig, frame): - if self.alive: - super().handle_exit(sig, frame) - - def handle_request(self): - self.nr += 1 - if self.alive and self.nr >= self.max_requests: - self.log.info("Autorestarting worker after current request.") - self.alive = False - - def watchdog(self): - if self.alive: - self.notify() - - if self.ppid != os.getppid(): - self.log.info("Parent changed, shutting down: %s", self) - self.alive = False - - def heartbeat(self): - if not self.alive: - if self.server_alive: - if hasattr(self, 'server'): - try: - self.server.stop() - except Exception: - pass - self.server_alive = False - else: - if TORNADO5: - for callback in self.callbacks: - callback.stop() - self.ioloop.stop() - else: - if not self.ioloop._callbacks: - self.ioloop.stop() - - def init_process(self): - # IOLoop cannot survive a fork or be shared across processes - # in any way. When multiple processes are being used, each process - # should create its own IOLoop. We should clear current IOLoop - # if exists before os.fork. - IOLoop.clear_current() - super().init_process() - - def run(self): - self.ioloop = IOLoop.instance() - self.alive = True - self.server_alive = False - - if TORNADO5: - self.callbacks = [] - self.callbacks.append(PeriodicCallback(self.watchdog, 1000)) - self.callbacks.append(PeriodicCallback(self.heartbeat, 1000)) - for callback in self.callbacks: - callback.start() - else: - PeriodicCallback(self.watchdog, 1000, io_loop=self.ioloop).start() - PeriodicCallback(self.heartbeat, 1000, io_loop=self.ioloop).start() - - # Assume the app is a WSGI callable if its not an - # instance of tornado.web.Application or is an - # instance of tornado.wsgi.WSGIApplication - app = self.wsgi - - if tornado.version_info[0] < 6: - if not isinstance(app, tornado.web.Application) or \ - isinstance(app, tornado.wsgi.WSGIApplication): - app = WSGIContainer(app) - elif not isinstance(app, WSGIContainer) and \ - not isinstance(app, tornado.web.Application): - app = WSGIContainer(app) - - # Monkey-patching HTTPConnection.finish to count the - # number of requests being handled by Tornado. This - # will help gunicorn shutdown the worker if max_requests - # is exceeded. - httpserver = sys.modules["tornado.httpserver"] - if hasattr(httpserver, 'HTTPConnection'): - old_connection_finish = httpserver.HTTPConnection.finish - - def finish(other): - self.handle_request() - old_connection_finish(other) - httpserver.HTTPConnection.finish = finish - sys.modules["tornado.httpserver"] = httpserver - - server_class = tornado.httpserver.HTTPServer - else: - - class _HTTPServer(tornado.httpserver.HTTPServer): - - def on_close(instance, server_conn): - self.handle_request() - super().on_close(server_conn) - - server_class = _HTTPServer - - if self.cfg.is_ssl: - if TORNADO5: - server = server_class(app, ssl_options=ssl_context(self.cfg)) - else: - server = server_class(app, io_loop=self.ioloop, - ssl_options=ssl_context(self.cfg)) - else: - if TORNADO5: - server = server_class(app) - else: - server = server_class(app, io_loop=self.ioloop) - - self.server = server - self.server_alive = True - - for s in self.sockets: - s.setblocking(0) - if hasattr(server, "add_socket"): # tornado > 2.0 - server.add_socket(s) - elif hasattr(server, "_sockets"): # tornado 2.0 - server._sockets[s.fileno()] = s - - server.no_keep_alive = self.cfg.keepalive <= 0 - server.start(num_processes=1) - - self.ioloop.start() diff --git a/venv/lib/python3.9/site-packages/gunicorn/workers/sync.py b/venv/lib/python3.9/site-packages/gunicorn/workers/sync.py deleted file mode 100644 index 4c029f9..0000000 --- a/venv/lib/python3.9/site-packages/gunicorn/workers/sync.py +++ /dev/null @@ -1,209 +0,0 @@ -# -# This file is part of gunicorn released under the MIT license. -# See the NOTICE for more information. -# - -from datetime import datetime -import errno -import os -import select -import socket -import ssl -import sys - -from gunicorn import http -from gunicorn.http import wsgi -from gunicorn import sock -from gunicorn import util -from gunicorn.workers import base - - -class StopWaiting(Exception): - """ exception raised to stop waiting for a connection """ - - -class SyncWorker(base.Worker): - - def accept(self, listener): - client, addr = listener.accept() - client.setblocking(1) - util.close_on_exec(client) - self.handle(listener, client, addr) - - def wait(self, timeout): - try: - self.notify() - ret = select.select(self.wait_fds, [], [], timeout) - if ret[0]: - if self.PIPE[0] in ret[0]: - os.read(self.PIPE[0], 1) - return ret[0] - - except OSError as e: - if e.args[0] == errno.EINTR: - return self.sockets - if e.args[0] == errno.EBADF: - if self.nr < 0: - return self.sockets - else: - raise StopWaiting - raise - - def is_parent_alive(self): - # If our parent changed then we shut down. - if self.ppid != os.getppid(): - self.log.info("Parent changed, shutting down: %s", self) - return False - return True - - def run_for_one(self, timeout): - listener = self.sockets[0] - while self.alive: - self.notify() - - # Accept a connection. If we get an error telling us - # that no connection is waiting we fall down to the - # select which is where we'll wait for a bit for new - # workers to come give us some love. - try: - self.accept(listener) - # Keep processing clients until no one is waiting. This - # prevents the need to select() for every client that we - # process. - continue - - except OSError as e: - if e.errno not in (errno.EAGAIN, errno.ECONNABORTED, - errno.EWOULDBLOCK): - raise - - if not self.is_parent_alive(): - return - - try: - self.wait(timeout) - except StopWaiting: - return - - def run_for_multiple(self, timeout): - while self.alive: - self.notify() - - try: - ready = self.wait(timeout) - except StopWaiting: - return - - if ready is not None: - for listener in ready: - if listener == self.PIPE[0]: - continue - - try: - self.accept(listener) - except OSError as e: - if e.errno not in (errno.EAGAIN, errno.ECONNABORTED, - errno.EWOULDBLOCK): - raise - - if not self.is_parent_alive(): - return - - def run(self): - # if no timeout is given the worker will never wait and will - # use the CPU for nothing. This minimal timeout prevent it. - timeout = self.timeout or 0.5 - - # self.socket appears to lose its blocking status after - # we fork in the arbiter. Reset it here. - for s in self.sockets: - s.setblocking(0) - - if len(self.sockets) > 1: - self.run_for_multiple(timeout) - else: - self.run_for_one(timeout) - - def handle(self, listener, client, addr): - req = None - try: - if self.cfg.is_ssl: - client = sock.ssl_wrap_socket(client, self.cfg) - parser = http.RequestParser(self.cfg, client, addr) - req = next(parser) - self.handle_request(listener, req, client, addr) - except http.errors.NoMoreData as e: - self.log.debug("Ignored premature client disconnection. %s", e) - except StopIteration as e: - self.log.debug("Closing connection. %s", e) - except ssl.SSLError as e: - if e.args[0] == ssl.SSL_ERROR_EOF: - self.log.debug("ssl connection closed") - client.close() - else: - self.log.debug("Error processing SSL request.") - self.handle_error(req, client, addr, e) - except OSError as e: - if e.errno not in (errno.EPIPE, errno.ECONNRESET, errno.ENOTCONN): - self.log.exception("Socket error processing request.") - else: - if e.errno == errno.ECONNRESET: - self.log.debug("Ignoring connection reset") - elif e.errno == errno.ENOTCONN: - self.log.debug("Ignoring socket not connected") - else: - self.log.debug("Ignoring EPIPE") - except BaseException as e: - self.handle_error(req, client, addr, e) - finally: - util.close(client) - - def handle_request(self, listener, req, client, addr): - environ = {} - resp = None - try: - self.cfg.pre_request(self, req) - request_start = datetime.now() - resp, environ = wsgi.create(req, client, addr, - listener.getsockname(), self.cfg) - # Force the connection closed until someone shows - # a buffering proxy that supports Keep-Alive to - # the backend. - resp.force_close() - self.nr += 1 - if self.nr >= self.max_requests: - self.log.info("Autorestarting worker after current request.") - self.alive = False - respiter = self.wsgi(environ, resp.start_response) - try: - if isinstance(respiter, environ['wsgi.file_wrapper']): - resp.write_file(respiter) - else: - for item in respiter: - resp.write(item) - resp.close() - finally: - request_time = datetime.now() - request_start - self.log.access(resp, req, environ, request_time) - if hasattr(respiter, "close"): - respiter.close() - except OSError: - # pass to next try-except level - util.reraise(*sys.exc_info()) - except Exception: - if resp and resp.headers_sent: - # If the requests have already been sent, we should close the - # connection to indicate the error. - self.log.exception("Error handling request") - try: - client.shutdown(socket.SHUT_RDWR) - client.close() - except OSError: - pass - raise StopIteration() - raise - finally: - try: - self.cfg.post_request(self, req, environ, resp) - except Exception: - self.log.exception("Exception in post_request hook") diff --git a/venv/lib/python3.9/site-packages/gunicorn/workers/workertmp.py b/venv/lib/python3.9/site-packages/gunicorn/workers/workertmp.py deleted file mode 100644 index 8ef00a5..0000000 --- a/venv/lib/python3.9/site-packages/gunicorn/workers/workertmp.py +++ /dev/null @@ -1,53 +0,0 @@ -# -# This file is part of gunicorn released under the MIT license. -# See the NOTICE for more information. - -import os -import time -import platform -import tempfile - -from gunicorn import util - -PLATFORM = platform.system() -IS_CYGWIN = PLATFORM.startswith('CYGWIN') - - -class WorkerTmp: - - def __init__(self, cfg): - old_umask = os.umask(cfg.umask) - fdir = cfg.worker_tmp_dir - if fdir and not os.path.isdir(fdir): - raise RuntimeError("%s doesn't exist. Can't create workertmp." % fdir) - fd, name = tempfile.mkstemp(prefix="wgunicorn-", dir=fdir) - os.umask(old_umask) - - # change the owner and group of the file if the worker will run as - # a different user or group, so that the worker can modify the file - if cfg.uid != os.geteuid() or cfg.gid != os.getegid(): - util.chown(name, cfg.uid, cfg.gid) - - # unlink the file so we don't leak temporary files - try: - if not IS_CYGWIN: - util.unlink(name) - # In Python 3.8, open() emits RuntimeWarning if buffering=1 for binary mode. - # Because we never write to this file, pass 0 to switch buffering off. - self._tmp = os.fdopen(fd, 'w+b', 0) - except Exception: - os.close(fd) - raise - - def notify(self): - new_time = time.monotonic() - os.utime(self._tmp.fileno(), (new_time, new_time)) - - def last_update(self): - return os.fstat(self._tmp.fileno()).st_mtime - - def fileno(self): - return self._tmp.fileno() - - def close(self): - return self._tmp.close() diff --git a/venv/lib/python3.9/site-packages/h11-0.16.0.dist-info/INSTALLER b/venv/lib/python3.9/site-packages/h11-0.16.0.dist-info/INSTALLER deleted file mode 100644 index a1b589e..0000000 --- a/venv/lib/python3.9/site-packages/h11-0.16.0.dist-info/INSTALLER +++ /dev/null @@ -1 +0,0 @@ -pip diff --git a/venv/lib/python3.9/site-packages/h11-0.16.0.dist-info/METADATA b/venv/lib/python3.9/site-packages/h11-0.16.0.dist-info/METADATA deleted file mode 100644 index 8a2f639..0000000 --- a/venv/lib/python3.9/site-packages/h11-0.16.0.dist-info/METADATA +++ /dev/null @@ -1,202 +0,0 @@ -Metadata-Version: 2.4 -Name: h11 -Version: 0.16.0 -Summary: A pure-Python, bring-your-own-I/O implementation of HTTP/1.1 -Home-page: https://github.com/python-hyper/h11 -Author: Nathaniel J. Smith -Author-email: njs@pobox.com -License: MIT -Classifier: Development Status :: 3 - Alpha -Classifier: Intended Audience :: Developers -Classifier: License :: OSI Approved :: MIT License -Classifier: Programming Language :: Python :: Implementation :: CPython -Classifier: Programming Language :: Python :: Implementation :: PyPy -Classifier: Programming Language :: Python :: 3 -Classifier: Programming Language :: Python :: 3 :: Only -Classifier: Programming Language :: Python :: 3.8 -Classifier: Programming Language :: Python :: 3.9 -Classifier: Programming Language :: Python :: 3.10 -Classifier: Programming Language :: Python :: 3.11 -Classifier: Programming Language :: Python :: 3.12 -Classifier: Topic :: Internet :: WWW/HTTP -Classifier: Topic :: System :: Networking -Requires-Python: >=3.8 -License-File: LICENSE.txt -Dynamic: author -Dynamic: author-email -Dynamic: classifier -Dynamic: description -Dynamic: home-page -Dynamic: license -Dynamic: license-file -Dynamic: requires-python -Dynamic: summary - -h11 -=== - -.. image:: https://travis-ci.org/python-hyper/h11.svg?branch=master - :target: https://travis-ci.org/python-hyper/h11 - :alt: Automated test status - -.. image:: https://codecov.io/gh/python-hyper/h11/branch/master/graph/badge.svg - :target: https://codecov.io/gh/python-hyper/h11 - :alt: Test coverage - -.. image:: https://readthedocs.org/projects/h11/badge/?version=latest - :target: http://h11.readthedocs.io/en/latest/?badge=latest - :alt: Documentation Status - -This is a little HTTP/1.1 library written from scratch in Python, -heavily inspired by `hyper-h2 `_. - -It's a "bring-your-own-I/O" library; h11 contains no IO code -whatsoever. This means you can hook h11 up to your favorite network -API, and that could be anything you want: synchronous, threaded, -asynchronous, or your own implementation of `RFC 6214 -`_ -- h11 won't judge you. -(Compare this to the current state of the art, where every time a `new -network API `_ comes along then someone -gets to start over reimplementing the entire HTTP protocol from -scratch.) Cory Benfield made an `excellent blog post describing the -benefits of this approach -`_, or if you like video -then here's his `PyCon 2016 talk on the same theme -`_. - -This also means that h11 is not immediately useful out of the box: -it's a toolkit for building programs that speak HTTP, not something -that could directly replace ``requests`` or ``twisted.web`` or -whatever. But h11 makes it much easier to implement something like -``requests`` or ``twisted.web``. - -At a high level, working with h11 goes like this: - -1) First, create an ``h11.Connection`` object to track the state of a - single HTTP/1.1 connection. - -2) When you read data off the network, pass it to - ``conn.receive_data(...)``; you'll get back a list of objects - representing high-level HTTP "events". - -3) When you want to send a high-level HTTP event, create the - corresponding "event" object and pass it to ``conn.send(...)``; - this will give you back some bytes that you can then push out - through the network. - -For example, a client might instantiate and then send a -``h11.Request`` object, then zero or more ``h11.Data`` objects for the -request body (e.g., if this is a POST), and then a -``h11.EndOfMessage`` to indicate the end of the message. Then the -server would then send back a ``h11.Response``, some ``h11.Data``, and -its own ``h11.EndOfMessage``. If either side violates the protocol, -you'll get a ``h11.ProtocolError`` exception. - -h11 is suitable for implementing both servers and clients, and has a -pleasantly symmetric API: the events you send as a client are exactly -the ones that you receive as a server and vice-versa. - -`Here's an example of a tiny HTTP client -`_ - -It also has `a fine manual `_. - -FAQ ---- - -*Whyyyyy?* - -I wanted to play with HTTP in `Curio -`__ and `Trio -`__, which at the time didn't have any -HTTP libraries. So I thought, no big deal, Python has, like, a dozen -different implementations of HTTP, surely I can find one that's -reusable. I didn't find one, but I did find Cory's call-to-arms -blog-post. So I figured, well, fine, if I have to implement HTTP from -scratch, at least I can make sure no-one *else* has to ever again. - -*Should I use it?* - -Maybe. You should be aware that it's a very young project. But, it's -feature complete and has an exhaustive test-suite and complete docs, -so the next step is for people to try using it and see how it goes -:-). If you do then please let us know -- if nothing else we'll want -to talk to you before making any incompatible changes! - -*What are the features/limitations?* - -Roughly speaking, it's trying to be a robust, complete, and non-hacky -implementation of the first "chapter" of the HTTP/1.1 spec: `RFC 7230: -HTTP/1.1 Message Syntax and Routing -`_. That is, it mostly focuses on -implementing HTTP at the level of taking bytes on and off the wire, -and the headers related to that, and tries to be anal about spec -conformance. It doesn't know about higher-level concerns like URL -routing, conditional GETs, cross-origin cookie policies, or content -negotiation. But it does know how to take care of framing, -cross-version differences in keep-alive handling, and the "obsolete -line folding" rule, so you can focus your energies on the hard / -interesting parts for your application, and it tries to support the -full specification in the sense that any useful HTTP/1.1 conformant -application should be able to use h11. - -It's pure Python, and has no dependencies outside of the standard -library. - -It has a test suite with 100.0% coverage for both statements and -branches. - -Currently it supports Python 3 (testing on 3.8-3.12) and PyPy 3. -The last Python 2-compatible version was h11 0.11.x. -(Originally it had a Cython wrapper for `http-parser -`_ and a beautiful nested state -machine implemented with ``yield from`` to postprocess the output. But -I had to take these out -- the new *parser* needs fewer lines-of-code -than the old *parser wrapper*, is written in pure Python, uses no -exotic language syntax, and has more features. It's sad, really; that -old state machine was really slick. I just need a few sentences here -to mourn that.) - -I don't know how fast it is. I haven't benchmarked or profiled it yet, -so it's probably got a few pointless hot spots, and I've been trying -to err on the side of simplicity and robustness instead of -micro-optimization. But at the architectural level I tried hard to -avoid fundamentally bad decisions, e.g., I believe that all the -parsing algorithms remain linear-time even in the face of pathological -input like slowloris, and there are no byte-by-byte loops. (I also -believe that it maintains bounded memory usage in the face of -arbitrary/pathological input.) - -The whole library is ~800 lines-of-code. You can read and understand -the whole thing in less than an hour. Most of the energy invested in -this so far has been spent on trying to keep things simple by -minimizing special-cases and ad hoc state manipulation; even though it -is now quite small and simple, I'm still annoyed that I haven't -figured out how to make it even smaller and simpler. (Unfortunately, -HTTP does not lend itself to simplicity.) - -The API is ~feature complete and I don't expect the general outlines -to change much, but you can't judge an API's ergonomics until you -actually document and use it, so I'd expect some changes in the -details. - -*How do I try it?* - -.. code-block:: sh - - $ pip install h11 - $ git clone git@github.com:python-hyper/h11 - $ cd h11/examples - $ python basic-client.py - -and go from there. - -*License?* - -MIT - -*Code of conduct?* - -Contributors are requested to follow our `code of conduct -`_ in -all project spaces. diff --git a/venv/lib/python3.9/site-packages/h11-0.16.0.dist-info/RECORD b/venv/lib/python3.9/site-packages/h11-0.16.0.dist-info/RECORD deleted file mode 100644 index 9d2b934..0000000 --- a/venv/lib/python3.9/site-packages/h11-0.16.0.dist-info/RECORD +++ /dev/null @@ -1,29 +0,0 @@ -h11-0.16.0.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 -h11-0.16.0.dist-info/METADATA,sha256=KPMmCYrAn8unm48YD5YIfIQf4kViFct7hyqcfVzRnWQ,8348 -h11-0.16.0.dist-info/RECORD,, -h11-0.16.0.dist-info/WHEEL,sha256=CmyFI0kx5cdEMTLiONQRbGQwjIoR1aIYB7eCAQ4KPJ0,91 -h11-0.16.0.dist-info/licenses/LICENSE.txt,sha256=N9tbuFkm2yikJ6JYZ_ELEjIAOuob5pzLhRE4rbjm82E,1124 -h11-0.16.0.dist-info/top_level.txt,sha256=F7dC4jl3zeh8TGHEPaWJrMbeuoWbS379Gwdi-Yvdcis,4 -h11/__init__.py,sha256=iO1KzkSO42yZ6ffg-VMgbx_ZVTWGUY00nRYEWn-s3kY,1507 -h11/__pycache__/__init__.cpython-39.pyc,, -h11/__pycache__/_abnf.cpython-39.pyc,, -h11/__pycache__/_connection.cpython-39.pyc,, -h11/__pycache__/_events.cpython-39.pyc,, -h11/__pycache__/_headers.cpython-39.pyc,, -h11/__pycache__/_readers.cpython-39.pyc,, -h11/__pycache__/_receivebuffer.cpython-39.pyc,, -h11/__pycache__/_state.cpython-39.pyc,, -h11/__pycache__/_util.cpython-39.pyc,, -h11/__pycache__/_version.cpython-39.pyc,, -h11/__pycache__/_writers.cpython-39.pyc,, -h11/_abnf.py,sha256=ybixr0xsupnkA6GFAyMubuXF6Tc1lb_hF890NgCsfNc,4815 -h11/_connection.py,sha256=k9YRVf6koZqbttBW36xSWaJpWdZwa-xQVU9AHEo9DuI,26863 -h11/_events.py,sha256=I97aXoal1Wu7dkL548BANBUCkOIbe-x5CioYA9IBY14,11792 -h11/_headers.py,sha256=P7D-lBNxHwdLZPLimmYwrPG-9ZkjElvvJZJdZAgSP-4,10412 -h11/_readers.py,sha256=a4RypORUCC3d0q_kxPuBIM7jTD8iLt5X91TH0FsduN4,8590 -h11/_receivebuffer.py,sha256=xrspsdsNgWFxRfQcTXxR8RrdjRXXTK0Io5cQYWpJ1Ws,5252 -h11/_state.py,sha256=_5LG_BGR8FCcFQeBPH-TMHgm_-B-EUcWCnQof_9XjFE,13231 -h11/_util.py,sha256=LWkkjXyJaFlAy6Lt39w73UStklFT5ovcvo0TkY7RYuk,4888 -h11/_version.py,sha256=GVSsbPSPDcOuF6ptfIiXnVJoaEm3ygXbMnqlr_Giahw,686 -h11/_writers.py,sha256=oFKm6PtjeHfbj4RLX7VB7KDc1gIY53gXG3_HR9ltmTA,5081 -h11/py.typed,sha256=sow9soTwP9T_gEAQSVh7Gb8855h04Nwmhs2We-JRgZM,7 diff --git a/venv/lib/python3.9/site-packages/h11-0.16.0.dist-info/WHEEL b/venv/lib/python3.9/site-packages/h11-0.16.0.dist-info/WHEEL deleted file mode 100644 index 1eb3c49..0000000 --- a/venv/lib/python3.9/site-packages/h11-0.16.0.dist-info/WHEEL +++ /dev/null @@ -1,5 +0,0 @@ -Wheel-Version: 1.0 -Generator: setuptools (78.1.0) -Root-Is-Purelib: true -Tag: py3-none-any - diff --git a/venv/lib/python3.9/site-packages/h11-0.16.0.dist-info/licenses/LICENSE.txt b/venv/lib/python3.9/site-packages/h11-0.16.0.dist-info/licenses/LICENSE.txt deleted file mode 100644 index 8f080ea..0000000 --- a/venv/lib/python3.9/site-packages/h11-0.16.0.dist-info/licenses/LICENSE.txt +++ /dev/null @@ -1,22 +0,0 @@ -The MIT License (MIT) - -Copyright (c) 2016 Nathaniel J. Smith and other contributors - -Permission is hereby granted, free of charge, to any person obtaining -a copy of this software and associated documentation files (the -"Software"), to deal in the Software without restriction, including -without limitation the rights to use, copy, modify, merge, publish, -distribute, sublicense, and/or sell copies of the Software, and to -permit persons to whom the Software is furnished to do so, subject to -the following conditions: - -The above copyright notice and this permission notice shall be -included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/venv/lib/python3.9/site-packages/h11-0.16.0.dist-info/top_level.txt b/venv/lib/python3.9/site-packages/h11-0.16.0.dist-info/top_level.txt deleted file mode 100644 index 0d24def..0000000 --- a/venv/lib/python3.9/site-packages/h11-0.16.0.dist-info/top_level.txt +++ /dev/null @@ -1 +0,0 @@ -h11 diff --git a/venv/lib/python3.9/site-packages/h11/__init__.py b/venv/lib/python3.9/site-packages/h11/__init__.py deleted file mode 100644 index 989e92c..0000000 --- a/venv/lib/python3.9/site-packages/h11/__init__.py +++ /dev/null @@ -1,62 +0,0 @@ -# A highish-level implementation of the HTTP/1.1 wire protocol (RFC 7230), -# containing no networking code at all, loosely modelled on hyper-h2's generic -# implementation of HTTP/2 (and in particular the h2.connection.H2Connection -# class). There's still a bunch of subtle details you need to get right if you -# want to make this actually useful, because it doesn't implement all the -# semantics to check that what you're asking to write to the wire is sensible, -# but at least it gets you out of dealing with the wire itself. - -from h11._connection import Connection, NEED_DATA, PAUSED -from h11._events import ( - ConnectionClosed, - Data, - EndOfMessage, - Event, - InformationalResponse, - Request, - Response, -) -from h11._state import ( - CLIENT, - CLOSED, - DONE, - ERROR, - IDLE, - MIGHT_SWITCH_PROTOCOL, - MUST_CLOSE, - SEND_BODY, - SEND_RESPONSE, - SERVER, - SWITCHED_PROTOCOL, -) -from h11._util import LocalProtocolError, ProtocolError, RemoteProtocolError -from h11._version import __version__ - -PRODUCT_ID = "python-h11/" + __version__ - - -__all__ = ( - "Connection", - "NEED_DATA", - "PAUSED", - "ConnectionClosed", - "Data", - "EndOfMessage", - "Event", - "InformationalResponse", - "Request", - "Response", - "CLIENT", - "CLOSED", - "DONE", - "ERROR", - "IDLE", - "MUST_CLOSE", - "SEND_BODY", - "SEND_RESPONSE", - "SERVER", - "SWITCHED_PROTOCOL", - "ProtocolError", - "LocalProtocolError", - "RemoteProtocolError", -) diff --git a/venv/lib/python3.9/site-packages/h11/_abnf.py b/venv/lib/python3.9/site-packages/h11/_abnf.py deleted file mode 100644 index 933587f..0000000 --- a/venv/lib/python3.9/site-packages/h11/_abnf.py +++ /dev/null @@ -1,132 +0,0 @@ -# We use native strings for all the re patterns, to take advantage of string -# formatting, and then convert to bytestrings when compiling the final re -# objects. - -# https://svn.tools.ietf.org/svn/wg/httpbis/specs/rfc7230.html#whitespace -# OWS = *( SP / HTAB ) -# ; optional whitespace -OWS = r"[ \t]*" - -# https://svn.tools.ietf.org/svn/wg/httpbis/specs/rfc7230.html#rule.token.separators -# token = 1*tchar -# -# tchar = "!" / "#" / "$" / "%" / "&" / "'" / "*" -# / "+" / "-" / "." / "^" / "_" / "`" / "|" / "~" -# / DIGIT / ALPHA -# ; any VCHAR, except delimiters -token = r"[-!#$%&'*+.^_`|~0-9a-zA-Z]+" - -# https://svn.tools.ietf.org/svn/wg/httpbis/specs/rfc7230.html#header.fields -# field-name = token -field_name = token - -# The standard says: -# -# field-value = *( field-content / obs-fold ) -# field-content = field-vchar [ 1*( SP / HTAB ) field-vchar ] -# field-vchar = VCHAR / obs-text -# obs-fold = CRLF 1*( SP / HTAB ) -# ; obsolete line folding -# ; see Section 3.2.4 -# -# https://tools.ietf.org/html/rfc5234#appendix-B.1 -# -# VCHAR = %x21-7E -# ; visible (printing) characters -# -# https://svn.tools.ietf.org/svn/wg/httpbis/specs/rfc7230.html#rule.quoted-string -# obs-text = %x80-FF -# -# However, the standard definition of field-content is WRONG! It disallows -# fields containing a single visible character surrounded by whitespace, -# e.g. "foo a bar". -# -# See: https://www.rfc-editor.org/errata_search.php?rfc=7230&eid=4189 -# -# So our definition of field_content attempts to fix it up... -# -# Also, we allow lots of control characters, because apparently people assume -# that they're legal in practice (e.g., google analytics makes cookies with -# \x01 in them!): -# https://github.com/python-hyper/h11/issues/57 -# We still don't allow NUL or whitespace, because those are often treated as -# meta-characters and letting them through can lead to nasty issues like SSRF. -vchar = r"[\x21-\x7e]" -vchar_or_obs_text = r"[^\x00\s]" -field_vchar = vchar_or_obs_text -field_content = r"{field_vchar}+(?:[ \t]+{field_vchar}+)*".format(**globals()) - -# We handle obs-fold at a different level, and our fixed-up field_content -# already grows to swallow the whole value, so ? instead of * -field_value = r"({field_content})?".format(**globals()) - -# header-field = field-name ":" OWS field-value OWS -header_field = ( - r"(?P{field_name})" - r":" - r"{OWS}" - r"(?P{field_value})" - r"{OWS}".format(**globals()) -) - -# https://svn.tools.ietf.org/svn/wg/httpbis/specs/rfc7230.html#request.line -# -# request-line = method SP request-target SP HTTP-version CRLF -# method = token -# HTTP-version = HTTP-name "/" DIGIT "." DIGIT -# HTTP-name = %x48.54.54.50 ; "HTTP", case-sensitive -# -# request-target is complicated (see RFC 7230 sec 5.3) -- could be path, full -# URL, host+port (for connect), or even "*", but in any case we are guaranteed -# that it contists of the visible printing characters. -method = token -request_target = r"{vchar}+".format(**globals()) -http_version = r"HTTP/(?P[0-9]\.[0-9])" -request_line = ( - r"(?P{method})" - r" " - r"(?P{request_target})" - r" " - r"{http_version}".format(**globals()) -) - -# https://svn.tools.ietf.org/svn/wg/httpbis/specs/rfc7230.html#status.line -# -# status-line = HTTP-version SP status-code SP reason-phrase CRLF -# status-code = 3DIGIT -# reason-phrase = *( HTAB / SP / VCHAR / obs-text ) -status_code = r"[0-9]{3}" -reason_phrase = r"([ \t]|{vchar_or_obs_text})*".format(**globals()) -status_line = ( - r"{http_version}" - r" " - r"(?P{status_code})" - # However, there are apparently a few too many servers out there that just - # leave out the reason phrase: - # https://github.com/scrapy/scrapy/issues/345#issuecomment-281756036 - # https://github.com/seanmonstar/httparse/issues/29 - # so make it optional. ?: is a non-capturing group. - r"(?: (?P{reason_phrase}))?".format(**globals()) -) - -HEXDIG = r"[0-9A-Fa-f]" -# Actually -# -# chunk-size = 1*HEXDIG -# -# but we impose an upper-limit to avoid ridiculosity. len(str(2**64)) == 20 -chunk_size = r"({HEXDIG}){{1,20}}".format(**globals()) -# Actually -# -# chunk-ext = *( ";" chunk-ext-name [ "=" chunk-ext-val ] ) -# -# but we aren't parsing the things so we don't really care. -chunk_ext = r";.*" -chunk_header = ( - r"(?P{chunk_size})" - r"(?P{chunk_ext})?" - r"{OWS}\r\n".format( - **globals() - ) # Even though the specification does not allow for extra whitespaces, - # we are lenient with trailing whitespaces because some servers on the wild use it. -) diff --git a/venv/lib/python3.9/site-packages/h11/_connection.py b/venv/lib/python3.9/site-packages/h11/_connection.py deleted file mode 100644 index e37d82a..0000000 --- a/venv/lib/python3.9/site-packages/h11/_connection.py +++ /dev/null @@ -1,659 +0,0 @@ -# This contains the main Connection class. Everything in h11 revolves around -# this. -from typing import ( - Any, - Callable, - cast, - Dict, - List, - Optional, - overload, - Tuple, - Type, - Union, -) - -from ._events import ( - ConnectionClosed, - Data, - EndOfMessage, - Event, - InformationalResponse, - Request, - Response, -) -from ._headers import get_comma_header, has_expect_100_continue, set_comma_header -from ._readers import READERS, ReadersType -from ._receivebuffer import ReceiveBuffer -from ._state import ( - _SWITCH_CONNECT, - _SWITCH_UPGRADE, - CLIENT, - ConnectionState, - DONE, - ERROR, - MIGHT_SWITCH_PROTOCOL, - SEND_BODY, - SERVER, - SWITCHED_PROTOCOL, -) -from ._util import ( # Import the internal things we need - LocalProtocolError, - RemoteProtocolError, - Sentinel, -) -from ._writers import WRITERS, WritersType - -# Everything in __all__ gets re-exported as part of the h11 public API. -__all__ = ["Connection", "NEED_DATA", "PAUSED"] - - -class NEED_DATA(Sentinel, metaclass=Sentinel): - pass - - -class PAUSED(Sentinel, metaclass=Sentinel): - pass - - -# If we ever have this much buffered without it making a complete parseable -# event, we error out. The only time we really buffer is when reading the -# request/response line + headers together, so this is effectively the limit on -# the size of that. -# -# Some precedents for defaults: -# - node.js: 80 * 1024 -# - tomcat: 8 * 1024 -# - IIS: 16 * 1024 -# - Apache: <8 KiB per line> -DEFAULT_MAX_INCOMPLETE_EVENT_SIZE = 16 * 1024 - - -# RFC 7230's rules for connection lifecycles: -# - If either side says they want to close the connection, then the connection -# must close. -# - HTTP/1.1 defaults to keep-alive unless someone says Connection: close -# - HTTP/1.0 defaults to close unless both sides say Connection: keep-alive -# (and even this is a mess -- e.g. if you're implementing a proxy then -# sending Connection: keep-alive is forbidden). -# -# We simplify life by simply not supporting keep-alive with HTTP/1.0 peers. So -# our rule is: -# - If someone says Connection: close, we will close -# - If someone uses HTTP/1.0, we will close. -def _keep_alive(event: Union[Request, Response]) -> bool: - connection = get_comma_header(event.headers, b"connection") - if b"close" in connection: - return False - if getattr(event, "http_version", b"1.1") < b"1.1": - return False - return True - - -def _body_framing( - request_method: bytes, event: Union[Request, Response] -) -> Tuple[str, Union[Tuple[()], Tuple[int]]]: - # Called when we enter SEND_BODY to figure out framing information for - # this body. - # - # These are the only two events that can trigger a SEND_BODY state: - assert type(event) in (Request, Response) - # Returns one of: - # - # ("content-length", count) - # ("chunked", ()) - # ("http/1.0", ()) - # - # which are (lookup key, *args) for constructing body reader/writer - # objects. - # - # Reference: https://tools.ietf.org/html/rfc7230#section-3.3.3 - # - # Step 1: some responses always have an empty body, regardless of what the - # headers say. - if type(event) is Response: - if ( - event.status_code in (204, 304) - or request_method == b"HEAD" - or (request_method == b"CONNECT" and 200 <= event.status_code < 300) - ): - return ("content-length", (0,)) - # Section 3.3.3 also lists another case -- responses with status_code - # < 200. For us these are InformationalResponses, not Responses, so - # they can't get into this function in the first place. - assert event.status_code >= 200 - - # Step 2: check for Transfer-Encoding (T-E beats C-L): - transfer_encodings = get_comma_header(event.headers, b"transfer-encoding") - if transfer_encodings: - assert transfer_encodings == [b"chunked"] - return ("chunked", ()) - - # Step 3: check for Content-Length - content_lengths = get_comma_header(event.headers, b"content-length") - if content_lengths: - return ("content-length", (int(content_lengths[0]),)) - - # Step 4: no applicable headers; fallback/default depends on type - if type(event) is Request: - return ("content-length", (0,)) - else: - return ("http/1.0", ()) - - -################################################################ -# -# The main Connection class -# -################################################################ - - -class Connection: - """An object encapsulating the state of an HTTP connection. - - Args: - our_role: If you're implementing a client, pass :data:`h11.CLIENT`. If - you're implementing a server, pass :data:`h11.SERVER`. - - max_incomplete_event_size (int): - The maximum number of bytes we're willing to buffer of an - incomplete event. In practice this mostly sets a limit on the - maximum size of the request/response line + headers. If this is - exceeded, then :meth:`next_event` will raise - :exc:`RemoteProtocolError`. - - """ - - def __init__( - self, - our_role: Type[Sentinel], - max_incomplete_event_size: int = DEFAULT_MAX_INCOMPLETE_EVENT_SIZE, - ) -> None: - self._max_incomplete_event_size = max_incomplete_event_size - # State and role tracking - if our_role not in (CLIENT, SERVER): - raise ValueError(f"expected CLIENT or SERVER, not {our_role!r}") - self.our_role = our_role - self.their_role: Type[Sentinel] - if our_role is CLIENT: - self.their_role = SERVER - else: - self.their_role = CLIENT - self._cstate = ConnectionState() - - # Callables for converting data->events or vice-versa given the - # current state - self._writer = self._get_io_object(self.our_role, None, WRITERS) - self._reader = self._get_io_object(self.their_role, None, READERS) - - # Holds any unprocessed received data - self._receive_buffer = ReceiveBuffer() - # If this is true, then it indicates that the incoming connection was - # closed *after* the end of whatever's in self._receive_buffer: - self._receive_buffer_closed = False - - # Extra bits of state that don't fit into the state machine. - # - # These two are only used to interpret framing headers for figuring - # out how to read/write response bodies. their_http_version is also - # made available as a convenient public API. - self.their_http_version: Optional[bytes] = None - self._request_method: Optional[bytes] = None - # This is pure flow-control and doesn't at all affect the set of legal - # transitions, so no need to bother ConnectionState with it: - self.client_is_waiting_for_100_continue = False - - @property - def states(self) -> Dict[Type[Sentinel], Type[Sentinel]]: - """A dictionary like:: - - {CLIENT: , SERVER: } - - See :ref:`state-machine` for details. - - """ - return dict(self._cstate.states) - - @property - def our_state(self) -> Type[Sentinel]: - """The current state of whichever role we are playing. See - :ref:`state-machine` for details. - """ - return self._cstate.states[self.our_role] - - @property - def their_state(self) -> Type[Sentinel]: - """The current state of whichever role we are NOT playing. See - :ref:`state-machine` for details. - """ - return self._cstate.states[self.their_role] - - @property - def they_are_waiting_for_100_continue(self) -> bool: - return self.their_role is CLIENT and self.client_is_waiting_for_100_continue - - def start_next_cycle(self) -> None: - """Attempt to reset our connection state for a new request/response - cycle. - - If both client and server are in :data:`DONE` state, then resets them - both to :data:`IDLE` state in preparation for a new request/response - cycle on this same connection. Otherwise, raises a - :exc:`LocalProtocolError`. - - See :ref:`keepalive-and-pipelining`. - - """ - old_states = dict(self._cstate.states) - self._cstate.start_next_cycle() - self._request_method = None - # self.their_http_version gets left alone, since it presumably lasts - # beyond a single request/response cycle - assert not self.client_is_waiting_for_100_continue - self._respond_to_state_changes(old_states) - - def _process_error(self, role: Type[Sentinel]) -> None: - old_states = dict(self._cstate.states) - self._cstate.process_error(role) - self._respond_to_state_changes(old_states) - - def _server_switch_event(self, event: Event) -> Optional[Type[Sentinel]]: - if type(event) is InformationalResponse and event.status_code == 101: - return _SWITCH_UPGRADE - if type(event) is Response: - if ( - _SWITCH_CONNECT in self._cstate.pending_switch_proposals - and 200 <= event.status_code < 300 - ): - return _SWITCH_CONNECT - return None - - # All events go through here - def _process_event(self, role: Type[Sentinel], event: Event) -> None: - # First, pass the event through the state machine to make sure it - # succeeds. - old_states = dict(self._cstate.states) - if role is CLIENT and type(event) is Request: - if event.method == b"CONNECT": - self._cstate.process_client_switch_proposal(_SWITCH_CONNECT) - if get_comma_header(event.headers, b"upgrade"): - self._cstate.process_client_switch_proposal(_SWITCH_UPGRADE) - server_switch_event = None - if role is SERVER: - server_switch_event = self._server_switch_event(event) - self._cstate.process_event(role, type(event), server_switch_event) - - # Then perform the updates triggered by it. - - if type(event) is Request: - self._request_method = event.method - - if role is self.their_role and type(event) in ( - Request, - Response, - InformationalResponse, - ): - event = cast(Union[Request, Response, InformationalResponse], event) - self.their_http_version = event.http_version - - # Keep alive handling - # - # RFC 7230 doesn't really say what one should do if Connection: close - # shows up on a 1xx InformationalResponse. I think the idea is that - # this is not supposed to happen. In any case, if it does happen, we - # ignore it. - if type(event) in (Request, Response) and not _keep_alive( - cast(Union[Request, Response], event) - ): - self._cstate.process_keep_alive_disabled() - - # 100-continue - if type(event) is Request and has_expect_100_continue(event): - self.client_is_waiting_for_100_continue = True - if type(event) in (InformationalResponse, Response): - self.client_is_waiting_for_100_continue = False - if role is CLIENT and type(event) in (Data, EndOfMessage): - self.client_is_waiting_for_100_continue = False - - self._respond_to_state_changes(old_states, event) - - def _get_io_object( - self, - role: Type[Sentinel], - event: Optional[Event], - io_dict: Union[ReadersType, WritersType], - ) -> Optional[Callable[..., Any]]: - # event may be None; it's only used when entering SEND_BODY - state = self._cstate.states[role] - if state is SEND_BODY: - # Special case: the io_dict has a dict of reader/writer factories - # that depend on the request/response framing. - framing_type, args = _body_framing( - cast(bytes, self._request_method), cast(Union[Request, Response], event) - ) - return io_dict[SEND_BODY][framing_type](*args) # type: ignore[index] - else: - # General case: the io_dict just has the appropriate reader/writer - # for this state - return io_dict.get((role, state)) # type: ignore[return-value] - - # This must be called after any action that might have caused - # self._cstate.states to change. - def _respond_to_state_changes( - self, - old_states: Dict[Type[Sentinel], Type[Sentinel]], - event: Optional[Event] = None, - ) -> None: - # Update reader/writer - if self.our_state != old_states[self.our_role]: - self._writer = self._get_io_object(self.our_role, event, WRITERS) - if self.their_state != old_states[self.their_role]: - self._reader = self._get_io_object(self.their_role, event, READERS) - - @property - def trailing_data(self) -> Tuple[bytes, bool]: - """Data that has been received, but not yet processed, represented as - a tuple with two elements, where the first is a byte-string containing - the unprocessed data itself, and the second is a bool that is True if - the receive connection was closed. - - See :ref:`switching-protocols` for discussion of why you'd want this. - """ - return (bytes(self._receive_buffer), self._receive_buffer_closed) - - def receive_data(self, data: bytes) -> None: - """Add data to our internal receive buffer. - - This does not actually do any processing on the data, just stores - it. To trigger processing, you have to call :meth:`next_event`. - - Args: - data (:term:`bytes-like object`): - The new data that was just received. - - Special case: If *data* is an empty byte-string like ``b""``, - then this indicates that the remote side has closed the - connection (end of file). Normally this is convenient, because - standard Python APIs like :meth:`file.read` or - :meth:`socket.recv` use ``b""`` to indicate end-of-file, while - other failures to read are indicated using other mechanisms - like raising :exc:`TimeoutError`. When using such an API you - can just blindly pass through whatever you get from ``read`` - to :meth:`receive_data`, and everything will work. - - But, if you have an API where reading an empty string is a - valid non-EOF condition, then you need to be aware of this and - make sure to check for such strings and avoid passing them to - :meth:`receive_data`. - - Returns: - Nothing, but after calling this you should call :meth:`next_event` - to parse the newly received data. - - Raises: - RuntimeError: - Raised if you pass an empty *data*, indicating EOF, and then - pass a non-empty *data*, indicating more data that somehow - arrived after the EOF. - - (Calling ``receive_data(b"")`` multiple times is fine, - and equivalent to calling it once.) - - """ - if data: - if self._receive_buffer_closed: - raise RuntimeError("received close, then received more data?") - self._receive_buffer += data - else: - self._receive_buffer_closed = True - - def _extract_next_receive_event( - self, - ) -> Union[Event, Type[NEED_DATA], Type[PAUSED]]: - state = self.their_state - # We don't pause immediately when they enter DONE, because even in - # DONE state we can still process a ConnectionClosed() event. But - # if we have data in our buffer, then we definitely aren't getting - # a ConnectionClosed() immediately and we need to pause. - if state is DONE and self._receive_buffer: - return PAUSED - if state is MIGHT_SWITCH_PROTOCOL or state is SWITCHED_PROTOCOL: - return PAUSED - assert self._reader is not None - event = self._reader(self._receive_buffer) - if event is None: - if not self._receive_buffer and self._receive_buffer_closed: - # In some unusual cases (basically just HTTP/1.0 bodies), EOF - # triggers an actual protocol event; in that case, we want to - # return that event, and then the state will change and we'll - # get called again to generate the actual ConnectionClosed(). - if hasattr(self._reader, "read_eof"): - event = self._reader.read_eof() - else: - event = ConnectionClosed() - if event is None: - event = NEED_DATA - return event # type: ignore[no-any-return] - - def next_event(self) -> Union[Event, Type[NEED_DATA], Type[PAUSED]]: - """Parse the next event out of our receive buffer, update our internal - state, and return it. - - This is a mutating operation -- think of it like calling :func:`next` - on an iterator. - - Returns: - : One of three things: - - 1) An event object -- see :ref:`events`. - - 2) The special constant :data:`NEED_DATA`, which indicates that - you need to read more data from your socket and pass it to - :meth:`receive_data` before this method will be able to return - any more events. - - 3) The special constant :data:`PAUSED`, which indicates that we - are not in a state where we can process incoming data (usually - because the peer has finished their part of the current - request/response cycle, and you have not yet called - :meth:`start_next_cycle`). See :ref:`flow-control` for details. - - Raises: - RemoteProtocolError: - The peer has misbehaved. You should close the connection - (possibly after sending some kind of 4xx response). - - Once this method returns :class:`ConnectionClosed` once, then all - subsequent calls will also return :class:`ConnectionClosed`. - - If this method raises any exception besides :exc:`RemoteProtocolError` - then that's a bug -- if it happens please file a bug report! - - If this method raises any exception then it also sets - :attr:`Connection.their_state` to :data:`ERROR` -- see - :ref:`error-handling` for discussion. - - """ - - if self.their_state is ERROR: - raise RemoteProtocolError("Can't receive data when peer state is ERROR") - try: - event = self._extract_next_receive_event() - if event not in [NEED_DATA, PAUSED]: - self._process_event(self.their_role, cast(Event, event)) - if event is NEED_DATA: - if len(self._receive_buffer) > self._max_incomplete_event_size: - # 431 is "Request header fields too large" which is pretty - # much the only situation where we can get here - raise RemoteProtocolError( - "Receive buffer too long", error_status_hint=431 - ) - if self._receive_buffer_closed: - # We're still trying to complete some event, but that's - # never going to happen because no more data is coming - raise RemoteProtocolError("peer unexpectedly closed connection") - return event - except BaseException as exc: - self._process_error(self.their_role) - if isinstance(exc, LocalProtocolError): - exc._reraise_as_remote_protocol_error() - else: - raise - - @overload - def send(self, event: ConnectionClosed) -> None: - ... - - @overload - def send( - self, event: Union[Request, InformationalResponse, Response, Data, EndOfMessage] - ) -> bytes: - ... - - @overload - def send(self, event: Event) -> Optional[bytes]: - ... - - def send(self, event: Event) -> Optional[bytes]: - """Convert a high-level event into bytes that can be sent to the peer, - while updating our internal state machine. - - Args: - event: The :ref:`event ` to send. - - Returns: - If ``type(event) is ConnectionClosed``, then returns - ``None``. Otherwise, returns a :term:`bytes-like object`. - - Raises: - LocalProtocolError: - Sending this event at this time would violate our - understanding of the HTTP/1.1 protocol. - - If this method raises any exception then it also sets - :attr:`Connection.our_state` to :data:`ERROR` -- see - :ref:`error-handling` for discussion. - - """ - data_list = self.send_with_data_passthrough(event) - if data_list is None: - return None - else: - return b"".join(data_list) - - def send_with_data_passthrough(self, event: Event) -> Optional[List[bytes]]: - """Identical to :meth:`send`, except that in situations where - :meth:`send` returns a single :term:`bytes-like object`, this instead - returns a list of them -- and when sending a :class:`Data` event, this - list is guaranteed to contain the exact object you passed in as - :attr:`Data.data`. See :ref:`sendfile` for discussion. - - """ - if self.our_state is ERROR: - raise LocalProtocolError("Can't send data when our state is ERROR") - try: - if type(event) is Response: - event = self._clean_up_response_headers_for_sending(event) - # We want to call _process_event before calling the writer, - # because if someone tries to do something invalid then this will - # give a sensible error message, while our writers all just assume - # they will only receive valid events. But, _process_event might - # change self._writer. So we have to do a little dance: - writer = self._writer - self._process_event(self.our_role, event) - if type(event) is ConnectionClosed: - return None - else: - # In any situation where writer is None, process_event should - # have raised ProtocolError - assert writer is not None - data_list: List[bytes] = [] - writer(event, data_list.append) - return data_list - except: - self._process_error(self.our_role) - raise - - def send_failed(self) -> None: - """Notify the state machine that we failed to send the data it gave - us. - - This causes :attr:`Connection.our_state` to immediately become - :data:`ERROR` -- see :ref:`error-handling` for discussion. - - """ - self._process_error(self.our_role) - - # When sending a Response, we take responsibility for a few things: - # - # - Sometimes you MUST set Connection: close. We take care of those - # times. (You can also set it yourself if you want, and if you do then - # we'll respect that and close the connection at the right time. But you - # don't have to worry about that unless you want to.) - # - # - The user has to set Content-Length if they want it. Otherwise, for - # responses that have bodies (e.g. not HEAD), then we will automatically - # select the right mechanism for streaming a body of unknown length, - # which depends on depending on the peer's HTTP version. - # - # This function's *only* responsibility is making sure headers are set up - # right -- everything downstream just looks at the headers. There are no - # side channels. - def _clean_up_response_headers_for_sending(self, response: Response) -> Response: - assert type(response) is Response - - headers = response.headers - need_close = False - - # HEAD requests need some special handling: they always act like they - # have Content-Length: 0, and that's how _body_framing treats - # them. But their headers are supposed to match what we would send if - # the request was a GET. (Technically there is one deviation allowed: - # we're allowed to leave out the framing headers -- see - # https://tools.ietf.org/html/rfc7231#section-4.3.2 . But it's just as - # easy to get them right.) - method_for_choosing_headers = cast(bytes, self._request_method) - if method_for_choosing_headers == b"HEAD": - method_for_choosing_headers = b"GET" - framing_type, _ = _body_framing(method_for_choosing_headers, response) - if framing_type in ("chunked", "http/1.0"): - # This response has a body of unknown length. - # If our peer is HTTP/1.1, we use Transfer-Encoding: chunked - # If our peer is HTTP/1.0, we use no framing headers, and close the - # connection afterwards. - # - # Make sure to clear Content-Length (in principle user could have - # set both and then we ignored Content-Length b/c - # Transfer-Encoding overwrote it -- this would be naughty of them, - # but the HTTP spec says that if our peer does this then we have - # to fix it instead of erroring out, so we'll accord the user the - # same respect). - headers = set_comma_header(headers, b"content-length", []) - if self.their_http_version is None or self.their_http_version < b"1.1": - # Either we never got a valid request and are sending back an - # error (their_http_version is None), so we assume the worst; - # or else we did get a valid HTTP/1.0 request, so we know that - # they don't understand chunked encoding. - headers = set_comma_header(headers, b"transfer-encoding", []) - # This is actually redundant ATM, since currently we - # unconditionally disable keep-alive when talking to HTTP/1.0 - # peers. But let's be defensive just in case we add - # Connection: keep-alive support later: - if self._request_method != b"HEAD": - need_close = True - else: - headers = set_comma_header(headers, b"transfer-encoding", [b"chunked"]) - - if not self._cstate.keep_alive or need_close: - # Make sure Connection: close is set - connection = set(get_comma_header(headers, b"connection")) - connection.discard(b"keep-alive") - connection.add(b"close") - headers = set_comma_header(headers, b"connection", sorted(connection)) - - return Response( - headers=headers, - status_code=response.status_code, - http_version=response.http_version, - reason=response.reason, - ) diff --git a/venv/lib/python3.9/site-packages/h11/_events.py b/venv/lib/python3.9/site-packages/h11/_events.py deleted file mode 100644 index ca1c3ad..0000000 --- a/venv/lib/python3.9/site-packages/h11/_events.py +++ /dev/null @@ -1,369 +0,0 @@ -# High level events that make up HTTP/1.1 conversations. Loosely inspired by -# the corresponding events in hyper-h2: -# -# http://python-hyper.org/h2/en/stable/api.html#events -# -# Don't subclass these. Stuff will break. - -import re -from abc import ABC -from dataclasses import dataclass -from typing import List, Tuple, Union - -from ._abnf import method, request_target -from ._headers import Headers, normalize_and_validate -from ._util import bytesify, LocalProtocolError, validate - -# Everything in __all__ gets re-exported as part of the h11 public API. -__all__ = [ - "Event", - "Request", - "InformationalResponse", - "Response", - "Data", - "EndOfMessage", - "ConnectionClosed", -] - -method_re = re.compile(method.encode("ascii")) -request_target_re = re.compile(request_target.encode("ascii")) - - -class Event(ABC): - """ - Base class for h11 events. - """ - - __slots__ = () - - -@dataclass(init=False, frozen=True) -class Request(Event): - """The beginning of an HTTP request. - - Fields: - - .. attribute:: method - - An HTTP method, e.g. ``b"GET"`` or ``b"POST"``. Always a byte - string. :term:`Bytes-like objects ` and native - strings containing only ascii characters will be automatically - converted to byte strings. - - .. attribute:: target - - The target of an HTTP request, e.g. ``b"/index.html"``, or one of the - more exotic formats described in `RFC 7320, section 5.3 - `_. Always a byte - string. :term:`Bytes-like objects ` and native - strings containing only ascii characters will be automatically - converted to byte strings. - - .. attribute:: headers - - Request headers, represented as a list of (name, value) pairs. See - :ref:`the header normalization rules ` for details. - - .. attribute:: http_version - - The HTTP protocol version, represented as a byte string like - ``b"1.1"``. See :ref:`the HTTP version normalization rules - ` for details. - - """ - - __slots__ = ("method", "headers", "target", "http_version") - - method: bytes - headers: Headers - target: bytes - http_version: bytes - - def __init__( - self, - *, - method: Union[bytes, str], - headers: Union[Headers, List[Tuple[bytes, bytes]], List[Tuple[str, str]]], - target: Union[bytes, str], - http_version: Union[bytes, str] = b"1.1", - _parsed: bool = False, - ) -> None: - super().__init__() - if isinstance(headers, Headers): - object.__setattr__(self, "headers", headers) - else: - object.__setattr__( - self, "headers", normalize_and_validate(headers, _parsed=_parsed) - ) - if not _parsed: - object.__setattr__(self, "method", bytesify(method)) - object.__setattr__(self, "target", bytesify(target)) - object.__setattr__(self, "http_version", bytesify(http_version)) - else: - object.__setattr__(self, "method", method) - object.__setattr__(self, "target", target) - object.__setattr__(self, "http_version", http_version) - - # "A server MUST respond with a 400 (Bad Request) status code to any - # HTTP/1.1 request message that lacks a Host header field and to any - # request message that contains more than one Host header field or a - # Host header field with an invalid field-value." - # -- https://tools.ietf.org/html/rfc7230#section-5.4 - host_count = 0 - for name, value in self.headers: - if name == b"host": - host_count += 1 - if self.http_version == b"1.1" and host_count == 0: - raise LocalProtocolError("Missing mandatory Host: header") - if host_count > 1: - raise LocalProtocolError("Found multiple Host: headers") - - validate(method_re, self.method, "Illegal method characters") - validate(request_target_re, self.target, "Illegal target characters") - - # This is an unhashable type. - __hash__ = None # type: ignore - - -@dataclass(init=False, frozen=True) -class _ResponseBase(Event): - __slots__ = ("headers", "http_version", "reason", "status_code") - - headers: Headers - http_version: bytes - reason: bytes - status_code: int - - def __init__( - self, - *, - headers: Union[Headers, List[Tuple[bytes, bytes]], List[Tuple[str, str]]], - status_code: int, - http_version: Union[bytes, str] = b"1.1", - reason: Union[bytes, str] = b"", - _parsed: bool = False, - ) -> None: - super().__init__() - if isinstance(headers, Headers): - object.__setattr__(self, "headers", headers) - else: - object.__setattr__( - self, "headers", normalize_and_validate(headers, _parsed=_parsed) - ) - if not _parsed: - object.__setattr__(self, "reason", bytesify(reason)) - object.__setattr__(self, "http_version", bytesify(http_version)) - if not isinstance(status_code, int): - raise LocalProtocolError("status code must be integer") - # Because IntEnum objects are instances of int, but aren't - # duck-compatible (sigh), see gh-72. - object.__setattr__(self, "status_code", int(status_code)) - else: - object.__setattr__(self, "reason", reason) - object.__setattr__(self, "http_version", http_version) - object.__setattr__(self, "status_code", status_code) - - self.__post_init__() - - def __post_init__(self) -> None: - pass - - # This is an unhashable type. - __hash__ = None # type: ignore - - -@dataclass(init=False, frozen=True) -class InformationalResponse(_ResponseBase): - """An HTTP informational response. - - Fields: - - .. attribute:: status_code - - The status code of this response, as an integer. For an - :class:`InformationalResponse`, this is always in the range [100, - 200). - - .. attribute:: headers - - Request headers, represented as a list of (name, value) pairs. See - :ref:`the header normalization rules ` for - details. - - .. attribute:: http_version - - The HTTP protocol version, represented as a byte string like - ``b"1.1"``. See :ref:`the HTTP version normalization rules - ` for details. - - .. attribute:: reason - - The reason phrase of this response, as a byte string. For example: - ``b"OK"``, or ``b"Not Found"``. - - """ - - def __post_init__(self) -> None: - if not (100 <= self.status_code < 200): - raise LocalProtocolError( - "InformationalResponse status_code should be in range " - "[100, 200), not {}".format(self.status_code) - ) - - # This is an unhashable type. - __hash__ = None # type: ignore - - -@dataclass(init=False, frozen=True) -class Response(_ResponseBase): - """The beginning of an HTTP response. - - Fields: - - .. attribute:: status_code - - The status code of this response, as an integer. For an - :class:`Response`, this is always in the range [200, - 1000). - - .. attribute:: headers - - Request headers, represented as a list of (name, value) pairs. See - :ref:`the header normalization rules ` for details. - - .. attribute:: http_version - - The HTTP protocol version, represented as a byte string like - ``b"1.1"``. See :ref:`the HTTP version normalization rules - ` for details. - - .. attribute:: reason - - The reason phrase of this response, as a byte string. For example: - ``b"OK"``, or ``b"Not Found"``. - - """ - - def __post_init__(self) -> None: - if not (200 <= self.status_code < 1000): - raise LocalProtocolError( - "Response status_code should be in range [200, 1000), not {}".format( - self.status_code - ) - ) - - # This is an unhashable type. - __hash__ = None # type: ignore - - -@dataclass(init=False, frozen=True) -class Data(Event): - """Part of an HTTP message body. - - Fields: - - .. attribute:: data - - A :term:`bytes-like object` containing part of a message body. Or, if - using the ``combine=False`` argument to :meth:`Connection.send`, then - any object that your socket writing code knows what to do with, and for - which calling :func:`len` returns the number of bytes that will be - written -- see :ref:`sendfile` for details. - - .. attribute:: chunk_start - - A marker that indicates whether this data object is from the start of a - chunked transfer encoding chunk. This field is ignored when when a Data - event is provided to :meth:`Connection.send`: it is only valid on - events emitted from :meth:`Connection.next_event`. You probably - shouldn't use this attribute at all; see - :ref:`chunk-delimiters-are-bad` for details. - - .. attribute:: chunk_end - - A marker that indicates whether this data object is the last for a - given chunked transfer encoding chunk. This field is ignored when when - a Data event is provided to :meth:`Connection.send`: it is only valid - on events emitted from :meth:`Connection.next_event`. You probably - shouldn't use this attribute at all; see - :ref:`chunk-delimiters-are-bad` for details. - - """ - - __slots__ = ("data", "chunk_start", "chunk_end") - - data: bytes - chunk_start: bool - chunk_end: bool - - def __init__( - self, data: bytes, chunk_start: bool = False, chunk_end: bool = False - ) -> None: - object.__setattr__(self, "data", data) - object.__setattr__(self, "chunk_start", chunk_start) - object.__setattr__(self, "chunk_end", chunk_end) - - # This is an unhashable type. - __hash__ = None # type: ignore - - -# XX FIXME: "A recipient MUST ignore (or consider as an error) any fields that -# are forbidden to be sent in a trailer, since processing them as if they were -# present in the header section might bypass external security filters." -# https://svn.tools.ietf.org/svn/wg/httpbis/specs/rfc7230.html#chunked.trailer.part -# Unfortunately, the list of forbidden fields is long and vague :-/ -@dataclass(init=False, frozen=True) -class EndOfMessage(Event): - """The end of an HTTP message. - - Fields: - - .. attribute:: headers - - Default value: ``[]`` - - Any trailing headers attached to this message, represented as a list of - (name, value) pairs. See :ref:`the header normalization rules - ` for details. - - Must be empty unless ``Transfer-Encoding: chunked`` is in use. - - """ - - __slots__ = ("headers",) - - headers: Headers - - def __init__( - self, - *, - headers: Union[ - Headers, List[Tuple[bytes, bytes]], List[Tuple[str, str]], None - ] = None, - _parsed: bool = False, - ) -> None: - super().__init__() - if headers is None: - headers = Headers([]) - elif not isinstance(headers, Headers): - headers = normalize_and_validate(headers, _parsed=_parsed) - - object.__setattr__(self, "headers", headers) - - # This is an unhashable type. - __hash__ = None # type: ignore - - -@dataclass(frozen=True) -class ConnectionClosed(Event): - """This event indicates that the sender has closed their outgoing - connection. - - Note that this does not necessarily mean that they can't *receive* further - data, because TCP connections are composed to two one-way channels which - can be closed independently. See :ref:`closing` for details. - - No fields. - """ - - pass diff --git a/venv/lib/python3.9/site-packages/h11/_headers.py b/venv/lib/python3.9/site-packages/h11/_headers.py deleted file mode 100644 index 31da3e2..0000000 --- a/venv/lib/python3.9/site-packages/h11/_headers.py +++ /dev/null @@ -1,282 +0,0 @@ -import re -from typing import AnyStr, cast, List, overload, Sequence, Tuple, TYPE_CHECKING, Union - -from ._abnf import field_name, field_value -from ._util import bytesify, LocalProtocolError, validate - -if TYPE_CHECKING: - from ._events import Request - -try: - from typing import Literal -except ImportError: - from typing_extensions import Literal # type: ignore - -CONTENT_LENGTH_MAX_DIGITS = 20 # allow up to 1 billion TB - 1 - - -# Facts -# ----- -# -# Headers are: -# keys: case-insensitive ascii -# values: mixture of ascii and raw bytes -# -# "Historically, HTTP has allowed field content with text in the ISO-8859-1 -# charset [ISO-8859-1], supporting other charsets only through use of -# [RFC2047] encoding. In practice, most HTTP header field values use only a -# subset of the US-ASCII charset [USASCII]. Newly defined header fields SHOULD -# limit their field values to US-ASCII octets. A recipient SHOULD treat other -# octets in field content (obs-text) as opaque data." -# And it deprecates all non-ascii values -# -# Leading/trailing whitespace in header names is forbidden -# -# Values get leading/trailing whitespace stripped -# -# Content-Disposition actually needs to contain unicode semantically; to -# accomplish this it has a terrifically weird way of encoding the filename -# itself as ascii (and even this still has lots of cross-browser -# incompatibilities) -# -# Order is important: -# "a proxy MUST NOT change the order of these field values when forwarding a -# message" -# (and there are several headers where the order indicates a preference) -# -# Multiple occurences of the same header: -# "A sender MUST NOT generate multiple header fields with the same field name -# in a message unless either the entire field value for that header field is -# defined as a comma-separated list [or the header is Set-Cookie which gets a -# special exception]" - RFC 7230. (cookies are in RFC 6265) -# -# So every header aside from Set-Cookie can be merged by b", ".join if it -# occurs repeatedly. But, of course, they can't necessarily be split by -# .split(b","), because quoting. -# -# Given all this mess (case insensitive, duplicates allowed, order is -# important, ...), there doesn't appear to be any standard way to handle -# headers in Python -- they're almost like dicts, but... actually just -# aren't. For now we punt and just use a super simple representation: headers -# are a list of pairs -# -# [(name1, value1), (name2, value2), ...] -# -# where all entries are bytestrings, names are lowercase and have no -# leading/trailing whitespace, and values are bytestrings with no -# leading/trailing whitespace. Searching and updating are done via naive O(n) -# methods. -# -# Maybe a dict-of-lists would be better? - -_content_length_re = re.compile(rb"[0-9]+") -_field_name_re = re.compile(field_name.encode("ascii")) -_field_value_re = re.compile(field_value.encode("ascii")) - - -class Headers(Sequence[Tuple[bytes, bytes]]): - """ - A list-like interface that allows iterating over headers as byte-pairs - of (lowercased-name, value). - - Internally we actually store the representation as three-tuples, - including both the raw original casing, in order to preserve casing - over-the-wire, and the lowercased name, for case-insensitive comparisions. - - r = Request( - method="GET", - target="/", - headers=[("Host", "example.org"), ("Connection", "keep-alive")], - http_version="1.1", - ) - assert r.headers == [ - (b"host", b"example.org"), - (b"connection", b"keep-alive") - ] - assert r.headers.raw_items() == [ - (b"Host", b"example.org"), - (b"Connection", b"keep-alive") - ] - """ - - __slots__ = "_full_items" - - def __init__(self, full_items: List[Tuple[bytes, bytes, bytes]]) -> None: - self._full_items = full_items - - def __bool__(self) -> bool: - return bool(self._full_items) - - def __eq__(self, other: object) -> bool: - return list(self) == list(other) # type: ignore - - def __len__(self) -> int: - return len(self._full_items) - - def __repr__(self) -> str: - return "" % repr(list(self)) - - def __getitem__(self, idx: int) -> Tuple[bytes, bytes]: # type: ignore[override] - _, name, value = self._full_items[idx] - return (name, value) - - def raw_items(self) -> List[Tuple[bytes, bytes]]: - return [(raw_name, value) for raw_name, _, value in self._full_items] - - -HeaderTypes = Union[ - List[Tuple[bytes, bytes]], - List[Tuple[bytes, str]], - List[Tuple[str, bytes]], - List[Tuple[str, str]], -] - - -@overload -def normalize_and_validate(headers: Headers, _parsed: Literal[True]) -> Headers: - ... - - -@overload -def normalize_and_validate(headers: HeaderTypes, _parsed: Literal[False]) -> Headers: - ... - - -@overload -def normalize_and_validate( - headers: Union[Headers, HeaderTypes], _parsed: bool = False -) -> Headers: - ... - - -def normalize_and_validate( - headers: Union[Headers, HeaderTypes], _parsed: bool = False -) -> Headers: - new_headers = [] - seen_content_length = None - saw_transfer_encoding = False - for name, value in headers: - # For headers coming out of the parser, we can safely skip some steps, - # because it always returns bytes and has already run these regexes - # over the data: - if not _parsed: - name = bytesify(name) - value = bytesify(value) - validate(_field_name_re, name, "Illegal header name {!r}", name) - validate(_field_value_re, value, "Illegal header value {!r}", value) - assert isinstance(name, bytes) - assert isinstance(value, bytes) - - raw_name = name - name = name.lower() - if name == b"content-length": - lengths = {length.strip() for length in value.split(b",")} - if len(lengths) != 1: - raise LocalProtocolError("conflicting Content-Length headers") - value = lengths.pop() - validate(_content_length_re, value, "bad Content-Length") - if len(value) > CONTENT_LENGTH_MAX_DIGITS: - raise LocalProtocolError("bad Content-Length") - if seen_content_length is None: - seen_content_length = value - new_headers.append((raw_name, name, value)) - elif seen_content_length != value: - raise LocalProtocolError("conflicting Content-Length headers") - elif name == b"transfer-encoding": - # "A server that receives a request message with a transfer coding - # it does not understand SHOULD respond with 501 (Not - # Implemented)." - # https://tools.ietf.org/html/rfc7230#section-3.3.1 - if saw_transfer_encoding: - raise LocalProtocolError( - "multiple Transfer-Encoding headers", error_status_hint=501 - ) - # "All transfer-coding names are case-insensitive" - # -- https://tools.ietf.org/html/rfc7230#section-4 - value = value.lower() - if value != b"chunked": - raise LocalProtocolError( - "Only Transfer-Encoding: chunked is supported", - error_status_hint=501, - ) - saw_transfer_encoding = True - new_headers.append((raw_name, name, value)) - else: - new_headers.append((raw_name, name, value)) - return Headers(new_headers) - - -def get_comma_header(headers: Headers, name: bytes) -> List[bytes]: - # Should only be used for headers whose value is a list of - # comma-separated, case-insensitive values. - # - # The header name `name` is expected to be lower-case bytes. - # - # Connection: meets these criteria (including cast insensitivity). - # - # Content-Length: technically is just a single value (1*DIGIT), but the - # standard makes reference to implementations that do multiple values, and - # using this doesn't hurt. Ditto, case insensitivity doesn't things either - # way. - # - # Transfer-Encoding: is more complex (allows for quoted strings), so - # splitting on , is actually wrong. For example, this is legal: - # - # Transfer-Encoding: foo; options="1,2", chunked - # - # and should be parsed as - # - # foo; options="1,2" - # chunked - # - # but this naive function will parse it as - # - # foo; options="1 - # 2" - # chunked - # - # However, this is okay because the only thing we are going to do with - # any Transfer-Encoding is reject ones that aren't just "chunked", so - # both of these will be treated the same anyway. - # - # Expect: the only legal value is the literal string - # "100-continue". Splitting on commas is harmless. Case insensitive. - # - out: List[bytes] = [] - for _, found_name, found_raw_value in headers._full_items: - if found_name == name: - found_raw_value = found_raw_value.lower() - for found_split_value in found_raw_value.split(b","): - found_split_value = found_split_value.strip() - if found_split_value: - out.append(found_split_value) - return out - - -def set_comma_header(headers: Headers, name: bytes, new_values: List[bytes]) -> Headers: - # The header name `name` is expected to be lower-case bytes. - # - # Note that when we store the header we use title casing for the header - # names, in order to match the conventional HTTP header style. - # - # Simply calling `.title()` is a blunt approach, but it's correct - # here given the cases where we're using `set_comma_header`... - # - # Connection, Content-Length, Transfer-Encoding. - new_headers: List[Tuple[bytes, bytes]] = [] - for found_raw_name, found_name, found_raw_value in headers._full_items: - if found_name != name: - new_headers.append((found_raw_name, found_raw_value)) - for new_value in new_values: - new_headers.append((name.title(), new_value)) - return normalize_and_validate(new_headers) - - -def has_expect_100_continue(request: "Request") -> bool: - # https://tools.ietf.org/html/rfc7231#section-5.1.1 - # "A server that receives a 100-continue expectation in an HTTP/1.0 request - # MUST ignore that expectation." - if request.http_version < b"1.1": - return False - expect = get_comma_header(request.headers, b"expect") - return b"100-continue" in expect diff --git a/venv/lib/python3.9/site-packages/h11/_readers.py b/venv/lib/python3.9/site-packages/h11/_readers.py deleted file mode 100644 index 576804c..0000000 --- a/venv/lib/python3.9/site-packages/h11/_readers.py +++ /dev/null @@ -1,250 +0,0 @@ -# Code to read HTTP data -# -# Strategy: each reader is a callable which takes a ReceiveBuffer object, and -# either: -# 1) consumes some of it and returns an Event -# 2) raises a LocalProtocolError (for consistency -- e.g. we call validate() -# and it might raise a LocalProtocolError, so simpler just to always use -# this) -# 3) returns None, meaning "I need more data" -# -# If they have a .read_eof attribute, then this will be called if an EOF is -# received -- but this is optional. Either way, the actual ConnectionClosed -# event will be generated afterwards. -# -# READERS is a dict describing how to pick a reader. It maps states to either: -# - a reader -# - or, for body readers, a dict of per-framing reader factories - -import re -from typing import Any, Callable, Dict, Iterable, NoReturn, Optional, Tuple, Type, Union - -from ._abnf import chunk_header, header_field, request_line, status_line -from ._events import Data, EndOfMessage, InformationalResponse, Request, Response -from ._receivebuffer import ReceiveBuffer -from ._state import ( - CLIENT, - CLOSED, - DONE, - IDLE, - MUST_CLOSE, - SEND_BODY, - SEND_RESPONSE, - SERVER, -) -from ._util import LocalProtocolError, RemoteProtocolError, Sentinel, validate - -__all__ = ["READERS"] - -header_field_re = re.compile(header_field.encode("ascii")) -obs_fold_re = re.compile(rb"[ \t]+") - - -def _obsolete_line_fold(lines: Iterable[bytes]) -> Iterable[bytes]: - it = iter(lines) - last: Optional[bytes] = None - for line in it: - match = obs_fold_re.match(line) - if match: - if last is None: - raise LocalProtocolError("continuation line at start of headers") - if not isinstance(last, bytearray): - # Cast to a mutable type, avoiding copy on append to ensure O(n) time - last = bytearray(last) - last += b" " - last += line[match.end() :] - else: - if last is not None: - yield last - last = line - if last is not None: - yield last - - -def _decode_header_lines( - lines: Iterable[bytes], -) -> Iterable[Tuple[bytes, bytes]]: - for line in _obsolete_line_fold(lines): - matches = validate(header_field_re, line, "illegal header line: {!r}", line) - yield (matches["field_name"], matches["field_value"]) - - -request_line_re = re.compile(request_line.encode("ascii")) - - -def maybe_read_from_IDLE_client(buf: ReceiveBuffer) -> Optional[Request]: - lines = buf.maybe_extract_lines() - if lines is None: - if buf.is_next_line_obviously_invalid_request_line(): - raise LocalProtocolError("illegal request line") - return None - if not lines: - raise LocalProtocolError("no request line received") - matches = validate( - request_line_re, lines[0], "illegal request line: {!r}", lines[0] - ) - return Request( - headers=list(_decode_header_lines(lines[1:])), _parsed=True, **matches - ) - - -status_line_re = re.compile(status_line.encode("ascii")) - - -def maybe_read_from_SEND_RESPONSE_server( - buf: ReceiveBuffer, -) -> Union[InformationalResponse, Response, None]: - lines = buf.maybe_extract_lines() - if lines is None: - if buf.is_next_line_obviously_invalid_request_line(): - raise LocalProtocolError("illegal request line") - return None - if not lines: - raise LocalProtocolError("no response line received") - matches = validate(status_line_re, lines[0], "illegal status line: {!r}", lines[0]) - http_version = ( - b"1.1" if matches["http_version"] is None else matches["http_version"] - ) - reason = b"" if matches["reason"] is None else matches["reason"] - status_code = int(matches["status_code"]) - class_: Union[Type[InformationalResponse], Type[Response]] = ( - InformationalResponse if status_code < 200 else Response - ) - return class_( - headers=list(_decode_header_lines(lines[1:])), - _parsed=True, - status_code=status_code, - reason=reason, - http_version=http_version, - ) - - -class ContentLengthReader: - def __init__(self, length: int) -> None: - self._length = length - self._remaining = length - - def __call__(self, buf: ReceiveBuffer) -> Union[Data, EndOfMessage, None]: - if self._remaining == 0: - return EndOfMessage() - data = buf.maybe_extract_at_most(self._remaining) - if data is None: - return None - self._remaining -= len(data) - return Data(data=data) - - def read_eof(self) -> NoReturn: - raise RemoteProtocolError( - "peer closed connection without sending complete message body " - "(received {} bytes, expected {})".format( - self._length - self._remaining, self._length - ) - ) - - -chunk_header_re = re.compile(chunk_header.encode("ascii")) - - -class ChunkedReader: - def __init__(self) -> None: - self._bytes_in_chunk = 0 - # After reading a chunk, we have to throw away the trailing \r\n. - # This tracks the bytes that we need to match and throw away. - self._bytes_to_discard = b"" - self._reading_trailer = False - - def __call__(self, buf: ReceiveBuffer) -> Union[Data, EndOfMessage, None]: - if self._reading_trailer: - lines = buf.maybe_extract_lines() - if lines is None: - return None - return EndOfMessage(headers=list(_decode_header_lines(lines))) - if self._bytes_to_discard: - data = buf.maybe_extract_at_most(len(self._bytes_to_discard)) - if data is None: - return None - if data != self._bytes_to_discard[: len(data)]: - raise LocalProtocolError( - f"malformed chunk footer: {data!r} (expected {self._bytes_to_discard!r})" - ) - self._bytes_to_discard = self._bytes_to_discard[len(data) :] - if self._bytes_to_discard: - return None - # else, fall through and read some more - assert self._bytes_to_discard == b"" - if self._bytes_in_chunk == 0: - # We need to refill our chunk count - chunk_header = buf.maybe_extract_next_line() - if chunk_header is None: - return None - matches = validate( - chunk_header_re, - chunk_header, - "illegal chunk header: {!r}", - chunk_header, - ) - # XX FIXME: we discard chunk extensions. Does anyone care? - self._bytes_in_chunk = int(matches["chunk_size"], base=16) - if self._bytes_in_chunk == 0: - self._reading_trailer = True - return self(buf) - chunk_start = True - else: - chunk_start = False - assert self._bytes_in_chunk > 0 - data = buf.maybe_extract_at_most(self._bytes_in_chunk) - if data is None: - return None - self._bytes_in_chunk -= len(data) - if self._bytes_in_chunk == 0: - self._bytes_to_discard = b"\r\n" - chunk_end = True - else: - chunk_end = False - return Data(data=data, chunk_start=chunk_start, chunk_end=chunk_end) - - def read_eof(self) -> NoReturn: - raise RemoteProtocolError( - "peer closed connection without sending complete message body " - "(incomplete chunked read)" - ) - - -class Http10Reader: - def __call__(self, buf: ReceiveBuffer) -> Optional[Data]: - data = buf.maybe_extract_at_most(999999999) - if data is None: - return None - return Data(data=data) - - def read_eof(self) -> EndOfMessage: - return EndOfMessage() - - -def expect_nothing(buf: ReceiveBuffer) -> None: - if buf: - raise LocalProtocolError("Got data when expecting EOF") - return None - - -ReadersType = Dict[ - Union[Type[Sentinel], Tuple[Type[Sentinel], Type[Sentinel]]], - Union[Callable[..., Any], Dict[str, Callable[..., Any]]], -] - -READERS: ReadersType = { - (CLIENT, IDLE): maybe_read_from_IDLE_client, - (SERVER, IDLE): maybe_read_from_SEND_RESPONSE_server, - (SERVER, SEND_RESPONSE): maybe_read_from_SEND_RESPONSE_server, - (CLIENT, DONE): expect_nothing, - (CLIENT, MUST_CLOSE): expect_nothing, - (CLIENT, CLOSED): expect_nothing, - (SERVER, DONE): expect_nothing, - (SERVER, MUST_CLOSE): expect_nothing, - (SERVER, CLOSED): expect_nothing, - SEND_BODY: { - "chunked": ChunkedReader, - "content-length": ContentLengthReader, - "http/1.0": Http10Reader, - }, -} diff --git a/venv/lib/python3.9/site-packages/h11/_receivebuffer.py b/venv/lib/python3.9/site-packages/h11/_receivebuffer.py deleted file mode 100644 index e5c4e08..0000000 --- a/venv/lib/python3.9/site-packages/h11/_receivebuffer.py +++ /dev/null @@ -1,153 +0,0 @@ -import re -import sys -from typing import List, Optional, Union - -__all__ = ["ReceiveBuffer"] - - -# Operations we want to support: -# - find next \r\n or \r\n\r\n (\n or \n\n are also acceptable), -# or wait until there is one -# - read at-most-N bytes -# Goals: -# - on average, do this fast -# - worst case, do this in O(n) where n is the number of bytes processed -# Plan: -# - store bytearray, offset, how far we've searched for a separator token -# - use the how-far-we've-searched data to avoid rescanning -# - while doing a stream of uninterrupted processing, advance offset instead -# of constantly copying -# WARNING: -# - I haven't benchmarked or profiled any of this yet. -# -# Note that starting in Python 3.4, deleting the initial n bytes from a -# bytearray is amortized O(n), thanks to some excellent work by Antoine -# Martin: -# -# https://bugs.python.org/issue19087 -# -# This means that if we only supported 3.4+, we could get rid of the code here -# involving self._start and self.compress, because it's doing exactly the same -# thing that bytearray now does internally. -# -# BUT unfortunately, we still support 2.7, and reading short segments out of a -# long buffer MUST be O(bytes read) to avoid DoS issues, so we can't actually -# delete this code. Yet: -# -# https://pythonclock.org/ -# -# (Two things to double-check first though: make sure PyPy also has the -# optimization, and benchmark to make sure it's a win, since we do have a -# slightly clever thing where we delay calling compress() until we've -# processed a whole event, which could in theory be slightly more efficient -# than the internal bytearray support.) -blank_line_regex = re.compile(b"\n\r?\n", re.MULTILINE) - - -class ReceiveBuffer: - def __init__(self) -> None: - self._data = bytearray() - self._next_line_search = 0 - self._multiple_lines_search = 0 - - def __iadd__(self, byteslike: Union[bytes, bytearray]) -> "ReceiveBuffer": - self._data += byteslike - return self - - def __bool__(self) -> bool: - return bool(len(self)) - - def __len__(self) -> int: - return len(self._data) - - # for @property unprocessed_data - def __bytes__(self) -> bytes: - return bytes(self._data) - - def _extract(self, count: int) -> bytearray: - # extracting an initial slice of the data buffer and return it - out = self._data[:count] - del self._data[:count] - - self._next_line_search = 0 - self._multiple_lines_search = 0 - - return out - - def maybe_extract_at_most(self, count: int) -> Optional[bytearray]: - """ - Extract a fixed number of bytes from the buffer. - """ - out = self._data[:count] - if not out: - return None - - return self._extract(count) - - def maybe_extract_next_line(self) -> Optional[bytearray]: - """ - Extract the first line, if it is completed in the buffer. - """ - # Only search in buffer space that we've not already looked at. - search_start_index = max(0, self._next_line_search - 1) - partial_idx = self._data.find(b"\r\n", search_start_index) - - if partial_idx == -1: - self._next_line_search = len(self._data) - return None - - # + 2 is to compensate len(b"\r\n") - idx = partial_idx + 2 - - return self._extract(idx) - - def maybe_extract_lines(self) -> Optional[List[bytearray]]: - """ - Extract everything up to the first blank line, and return a list of lines. - """ - # Handle the case where we have an immediate empty line. - if self._data[:1] == b"\n": - self._extract(1) - return [] - - if self._data[:2] == b"\r\n": - self._extract(2) - return [] - - # Only search in buffer space that we've not already looked at. - match = blank_line_regex.search(self._data, self._multiple_lines_search) - if match is None: - self._multiple_lines_search = max(0, len(self._data) - 2) - return None - - # Truncate the buffer and return it. - idx = match.span(0)[-1] - out = self._extract(idx) - lines = out.split(b"\n") - - for line in lines: - if line.endswith(b"\r"): - del line[-1] - - assert lines[-2] == lines[-1] == b"" - - del lines[-2:] - - return lines - - # In theory we should wait until `\r\n` before starting to validate - # incoming data. However it's interesting to detect (very) invalid data - # early given they might not even contain `\r\n` at all (hence only - # timeout will get rid of them). - # This is not a 100% effective detection but more of a cheap sanity check - # allowing for early abort in some useful cases. - # This is especially interesting when peer is messing up with HTTPS and - # sent us a TLS stream where we were expecting plain HTTP given all - # versions of TLS so far start handshake with a 0x16 message type code. - def is_next_line_obviously_invalid_request_line(self) -> bool: - try: - # HTTP header line must not contain non-printable characters - # and should not start with a space - return self._data[0] < 0x21 - except IndexError: - return False diff --git a/venv/lib/python3.9/site-packages/h11/_state.py b/venv/lib/python3.9/site-packages/h11/_state.py deleted file mode 100644 index 3ad444b..0000000 --- a/venv/lib/python3.9/site-packages/h11/_state.py +++ /dev/null @@ -1,365 +0,0 @@ -################################################################ -# The core state machine -################################################################ -# -# Rule 1: everything that affects the state machine and state transitions must -# live here in this file. As much as possible goes into the table-based -# representation, but for the bits that don't quite fit, the actual code and -# state must nonetheless live here. -# -# Rule 2: this file does not know about what role we're playing; it only knows -# about HTTP request/response cycles in the abstract. This ensures that we -# don't cheat and apply different rules to local and remote parties. -# -# -# Theory of operation -# =================== -# -# Possibly the simplest way to think about this is that we actually have 5 -# different state machines here. Yes, 5. These are: -# -# 1) The client state, with its complicated automaton (see the docs) -# 2) The server state, with its complicated automaton (see the docs) -# 3) The keep-alive state, with possible states {True, False} -# 4) The SWITCH_CONNECT state, with possible states {False, True} -# 5) The SWITCH_UPGRADE state, with possible states {False, True} -# -# For (3)-(5), the first state listed is the initial state. -# -# (1)-(3) are stored explicitly in member variables. The last -# two are stored implicitly in the pending_switch_proposals set as: -# (state of 4) == (_SWITCH_CONNECT in pending_switch_proposals) -# (state of 5) == (_SWITCH_UPGRADE in pending_switch_proposals) -# -# And each of these machines has two different kinds of transitions: -# -# a) Event-triggered -# b) State-triggered -# -# Event triggered is the obvious thing that you'd think it is: some event -# happens, and if it's the right event at the right time then a transition -# happens. But there are somewhat complicated rules for which machines can -# "see" which events. (As a rule of thumb, if a machine "sees" an event, this -# means two things: the event can affect the machine, and if the machine is -# not in a state where it expects that event then it's an error.) These rules -# are: -# -# 1) The client machine sees all h11.events objects emitted by the client. -# -# 2) The server machine sees all h11.events objects emitted by the server. -# -# It also sees the client's Request event. -# -# And sometimes, server events are annotated with a _SWITCH_* event. For -# example, we can have a (Response, _SWITCH_CONNECT) event, which is -# different from a regular Response event. -# -# 3) The keep-alive machine sees the process_keep_alive_disabled() event -# (which is derived from Request/Response events), and this event -# transitions it from True -> False, or from False -> False. There's no way -# to transition back. -# -# 4&5) The _SWITCH_* machines transition from False->True when we get a -# Request that proposes the relevant type of switch (via -# process_client_switch_proposals), and they go from True->False when we -# get a Response that has no _SWITCH_* annotation. -# -# So that's event-triggered transitions. -# -# State-triggered transitions are less standard. What they do here is couple -# the machines together. The way this works is, when certain *joint* -# configurations of states are achieved, then we automatically transition to a -# new *joint* state. So, for example, if we're ever in a joint state with -# -# client: DONE -# keep-alive: False -# -# then the client state immediately transitions to: -# -# client: MUST_CLOSE -# -# This is fundamentally different from an event-based transition, because it -# doesn't matter how we arrived at the {client: DONE, keep-alive: False} state -# -- maybe the client transitioned SEND_BODY -> DONE, or keep-alive -# transitioned True -> False. Either way, once this precondition is satisfied, -# this transition is immediately triggered. -# -# What if two conflicting state-based transitions get enabled at the same -# time? In practice there's only one case where this arises (client DONE -> -# MIGHT_SWITCH_PROTOCOL versus DONE -> MUST_CLOSE), and we resolve it by -# explicitly prioritizing the DONE -> MIGHT_SWITCH_PROTOCOL transition. -# -# Implementation -# -------------- -# -# The event-triggered transitions for the server and client machines are all -# stored explicitly in a table. Ditto for the state-triggered transitions that -# involve just the server and client state. -# -# The transitions for the other machines, and the state-triggered transitions -# that involve the other machines, are written out as explicit Python code. -# -# It'd be nice if there were some cleaner way to do all this. This isn't -# *too* terrible, but I feel like it could probably be better. -# -# WARNING -# ------- -# -# The script that generates the state machine diagrams for the docs knows how -# to read out the EVENT_TRIGGERED_TRANSITIONS and STATE_TRIGGERED_TRANSITIONS -# tables. But it can't automatically read the transitions that are written -# directly in Python code. So if you touch those, you need to also update the -# script to keep it in sync! -from typing import cast, Dict, Optional, Set, Tuple, Type, Union - -from ._events import * -from ._util import LocalProtocolError, Sentinel - -# Everything in __all__ gets re-exported as part of the h11 public API. -__all__ = [ - "CLIENT", - "SERVER", - "IDLE", - "SEND_RESPONSE", - "SEND_BODY", - "DONE", - "MUST_CLOSE", - "CLOSED", - "MIGHT_SWITCH_PROTOCOL", - "SWITCHED_PROTOCOL", - "ERROR", -] - - -class CLIENT(Sentinel, metaclass=Sentinel): - pass - - -class SERVER(Sentinel, metaclass=Sentinel): - pass - - -# States -class IDLE(Sentinel, metaclass=Sentinel): - pass - - -class SEND_RESPONSE(Sentinel, metaclass=Sentinel): - pass - - -class SEND_BODY(Sentinel, metaclass=Sentinel): - pass - - -class DONE(Sentinel, metaclass=Sentinel): - pass - - -class MUST_CLOSE(Sentinel, metaclass=Sentinel): - pass - - -class CLOSED(Sentinel, metaclass=Sentinel): - pass - - -class ERROR(Sentinel, metaclass=Sentinel): - pass - - -# Switch types -class MIGHT_SWITCH_PROTOCOL(Sentinel, metaclass=Sentinel): - pass - - -class SWITCHED_PROTOCOL(Sentinel, metaclass=Sentinel): - pass - - -class _SWITCH_UPGRADE(Sentinel, metaclass=Sentinel): - pass - - -class _SWITCH_CONNECT(Sentinel, metaclass=Sentinel): - pass - - -EventTransitionType = Dict[ - Type[Sentinel], - Dict[ - Type[Sentinel], - Dict[Union[Type[Event], Tuple[Type[Event], Type[Sentinel]]], Type[Sentinel]], - ], -] - -EVENT_TRIGGERED_TRANSITIONS: EventTransitionType = { - CLIENT: { - IDLE: {Request: SEND_BODY, ConnectionClosed: CLOSED}, - SEND_BODY: {Data: SEND_BODY, EndOfMessage: DONE}, - DONE: {ConnectionClosed: CLOSED}, - MUST_CLOSE: {ConnectionClosed: CLOSED}, - CLOSED: {ConnectionClosed: CLOSED}, - MIGHT_SWITCH_PROTOCOL: {}, - SWITCHED_PROTOCOL: {}, - ERROR: {}, - }, - SERVER: { - IDLE: { - ConnectionClosed: CLOSED, - Response: SEND_BODY, - # Special case: server sees client Request events, in this form - (Request, CLIENT): SEND_RESPONSE, - }, - SEND_RESPONSE: { - InformationalResponse: SEND_RESPONSE, - Response: SEND_BODY, - (InformationalResponse, _SWITCH_UPGRADE): SWITCHED_PROTOCOL, - (Response, _SWITCH_CONNECT): SWITCHED_PROTOCOL, - }, - SEND_BODY: {Data: SEND_BODY, EndOfMessage: DONE}, - DONE: {ConnectionClosed: CLOSED}, - MUST_CLOSE: {ConnectionClosed: CLOSED}, - CLOSED: {ConnectionClosed: CLOSED}, - SWITCHED_PROTOCOL: {}, - ERROR: {}, - }, -} - -StateTransitionType = Dict[ - Tuple[Type[Sentinel], Type[Sentinel]], Dict[Type[Sentinel], Type[Sentinel]] -] - -# NB: there are also some special-case state-triggered transitions hard-coded -# into _fire_state_triggered_transitions below. -STATE_TRIGGERED_TRANSITIONS: StateTransitionType = { - # (Client state, Server state) -> new states - # Protocol negotiation - (MIGHT_SWITCH_PROTOCOL, SWITCHED_PROTOCOL): {CLIENT: SWITCHED_PROTOCOL}, - # Socket shutdown - (CLOSED, DONE): {SERVER: MUST_CLOSE}, - (CLOSED, IDLE): {SERVER: MUST_CLOSE}, - (ERROR, DONE): {SERVER: MUST_CLOSE}, - (DONE, CLOSED): {CLIENT: MUST_CLOSE}, - (IDLE, CLOSED): {CLIENT: MUST_CLOSE}, - (DONE, ERROR): {CLIENT: MUST_CLOSE}, -} - - -class ConnectionState: - def __init__(self) -> None: - # Extra bits of state that don't quite fit into the state model. - - # If this is False then it enables the automatic DONE -> MUST_CLOSE - # transition. Don't set this directly; call .keep_alive_disabled() - self.keep_alive = True - - # This is a subset of {UPGRADE, CONNECT}, containing the proposals - # made by the client for switching protocols. - self.pending_switch_proposals: Set[Type[Sentinel]] = set() - - self.states: Dict[Type[Sentinel], Type[Sentinel]] = {CLIENT: IDLE, SERVER: IDLE} - - def process_error(self, role: Type[Sentinel]) -> None: - self.states[role] = ERROR - self._fire_state_triggered_transitions() - - def process_keep_alive_disabled(self) -> None: - self.keep_alive = False - self._fire_state_triggered_transitions() - - def process_client_switch_proposal(self, switch_event: Type[Sentinel]) -> None: - self.pending_switch_proposals.add(switch_event) - self._fire_state_triggered_transitions() - - def process_event( - self, - role: Type[Sentinel], - event_type: Type[Event], - server_switch_event: Optional[Type[Sentinel]] = None, - ) -> None: - _event_type: Union[Type[Event], Tuple[Type[Event], Type[Sentinel]]] = event_type - if server_switch_event is not None: - assert role is SERVER - if server_switch_event not in self.pending_switch_proposals: - raise LocalProtocolError( - "Received server _SWITCH_UPGRADE event without a pending proposal" - ) - _event_type = (event_type, server_switch_event) - if server_switch_event is None and _event_type is Response: - self.pending_switch_proposals = set() - self._fire_event_triggered_transitions(role, _event_type) - # Special case: the server state does get to see Request - # events. - if _event_type is Request: - assert role is CLIENT - self._fire_event_triggered_transitions(SERVER, (Request, CLIENT)) - self._fire_state_triggered_transitions() - - def _fire_event_triggered_transitions( - self, - role: Type[Sentinel], - event_type: Union[Type[Event], Tuple[Type[Event], Type[Sentinel]]], - ) -> None: - state = self.states[role] - try: - new_state = EVENT_TRIGGERED_TRANSITIONS[role][state][event_type] - except KeyError: - event_type = cast(Type[Event], event_type) - raise LocalProtocolError( - "can't handle event type {} when role={} and state={}".format( - event_type.__name__, role, self.states[role] - ) - ) from None - self.states[role] = new_state - - def _fire_state_triggered_transitions(self) -> None: - # We apply these rules repeatedly until converging on a fixed point - while True: - start_states = dict(self.states) - - # It could happen that both these special-case transitions are - # enabled at the same time: - # - # DONE -> MIGHT_SWITCH_PROTOCOL - # DONE -> MUST_CLOSE - # - # For example, this will always be true of a HTTP/1.0 client - # requesting CONNECT. If this happens, the protocol switch takes - # priority. From there the client will either go to - # SWITCHED_PROTOCOL, in which case it's none of our business when - # they close the connection, or else the server will deny the - # request, in which case the client will go back to DONE and then - # from there to MUST_CLOSE. - if self.pending_switch_proposals: - if self.states[CLIENT] is DONE: - self.states[CLIENT] = MIGHT_SWITCH_PROTOCOL - - if not self.pending_switch_proposals: - if self.states[CLIENT] is MIGHT_SWITCH_PROTOCOL: - self.states[CLIENT] = DONE - - if not self.keep_alive: - for role in (CLIENT, SERVER): - if self.states[role] is DONE: - self.states[role] = MUST_CLOSE - - # Tabular state-triggered transitions - joint_state = (self.states[CLIENT], self.states[SERVER]) - changes = STATE_TRIGGERED_TRANSITIONS.get(joint_state, {}) - self.states.update(changes) - - if self.states == start_states: - # Fixed point reached - return - - def start_next_cycle(self) -> None: - if self.states != {CLIENT: DONE, SERVER: DONE}: - raise LocalProtocolError( - f"not in a reusable state. self.states={self.states}" - ) - # Can't reach DONE/DONE with any of these active, but still, let's be - # sure. - assert self.keep_alive - assert not self.pending_switch_proposals - self.states = {CLIENT: IDLE, SERVER: IDLE} diff --git a/venv/lib/python3.9/site-packages/h11/_util.py b/venv/lib/python3.9/site-packages/h11/_util.py deleted file mode 100644 index 6718445..0000000 --- a/venv/lib/python3.9/site-packages/h11/_util.py +++ /dev/null @@ -1,135 +0,0 @@ -from typing import Any, Dict, NoReturn, Pattern, Tuple, Type, TypeVar, Union - -__all__ = [ - "ProtocolError", - "LocalProtocolError", - "RemoteProtocolError", - "validate", - "bytesify", -] - - -class ProtocolError(Exception): - """Exception indicating a violation of the HTTP/1.1 protocol. - - This as an abstract base class, with two concrete base classes: - :exc:`LocalProtocolError`, which indicates that you tried to do something - that HTTP/1.1 says is illegal, and :exc:`RemoteProtocolError`, which - indicates that the remote peer tried to do something that HTTP/1.1 says is - illegal. See :ref:`error-handling` for details. - - In addition to the normal :exc:`Exception` features, it has one attribute: - - .. attribute:: error_status_hint - - This gives a suggestion as to what status code a server might use if - this error occurred as part of a request. - - For a :exc:`RemoteProtocolError`, this is useful as a suggestion for - how you might want to respond to a misbehaving peer, if you're - implementing a server. - - For a :exc:`LocalProtocolError`, this can be taken as a suggestion for - how your peer might have responded to *you* if h11 had allowed you to - continue. - - The default is 400 Bad Request, a generic catch-all for protocol - violations. - - """ - - def __init__(self, msg: str, error_status_hint: int = 400) -> None: - if type(self) is ProtocolError: - raise TypeError("tried to directly instantiate ProtocolError") - Exception.__init__(self, msg) - self.error_status_hint = error_status_hint - - -# Strategy: there are a number of public APIs where a LocalProtocolError can -# be raised (send(), all the different event constructors, ...), and only one -# public API where RemoteProtocolError can be raised -# (receive_data()). Therefore we always raise LocalProtocolError internally, -# and then receive_data will translate this into a RemoteProtocolError. -# -# Internally: -# LocalProtocolError is the generic "ProtocolError". -# Externally: -# LocalProtocolError is for local errors and RemoteProtocolError is for -# remote errors. -class LocalProtocolError(ProtocolError): - def _reraise_as_remote_protocol_error(self) -> NoReturn: - # After catching a LocalProtocolError, use this method to re-raise it - # as a RemoteProtocolError. This method must be called from inside an - # except: block. - # - # An easy way to get an equivalent RemoteProtocolError is just to - # modify 'self' in place. - self.__class__ = RemoteProtocolError # type: ignore - # But the re-raising is somewhat non-trivial -- you might think that - # now that we've modified the in-flight exception object, that just - # doing 'raise' to re-raise it would be enough. But it turns out that - # this doesn't work, because Python tracks the exception type - # (exc_info[0]) separately from the exception object (exc_info[1]), - # and we only modified the latter. So we really do need to re-raise - # the new type explicitly. - # On py3, the traceback is part of the exception object, so our - # in-place modification preserved it and we can just re-raise: - raise self - - -class RemoteProtocolError(ProtocolError): - pass - - -def validate( - regex: Pattern[bytes], data: bytes, msg: str = "malformed data", *format_args: Any -) -> Dict[str, bytes]: - match = regex.fullmatch(data) - if not match: - if format_args: - msg = msg.format(*format_args) - raise LocalProtocolError(msg) - return match.groupdict() - - -# Sentinel values -# -# - Inherit identity-based comparison and hashing from object -# - Have a nice repr -# - Have a *bonus property*: type(sentinel) is sentinel -# -# The bonus property is useful if you want to take the return value from -# next_event() and do some sort of dispatch based on type(event). - -_T_Sentinel = TypeVar("_T_Sentinel", bound="Sentinel") - - -class Sentinel(type): - def __new__( - cls: Type[_T_Sentinel], - name: str, - bases: Tuple[type, ...], - namespace: Dict[str, Any], - **kwds: Any - ) -> _T_Sentinel: - assert bases == (Sentinel,) - v = super().__new__(cls, name, bases, namespace, **kwds) - v.__class__ = v # type: ignore - return v - - def __repr__(self) -> str: - return self.__name__ - - -# Used for methods, request targets, HTTP versions, header names, and header -# values. Accepts ascii-strings, or bytes/bytearray/memoryview/..., and always -# returns bytes. -def bytesify(s: Union[bytes, bytearray, memoryview, int, str]) -> bytes: - # Fast-path: - if type(s) is bytes: - return s - if isinstance(s, str): - s = s.encode("ascii") - if isinstance(s, int): - raise TypeError("expected bytes-like object, not int") - return bytes(s) diff --git a/venv/lib/python3.9/site-packages/h11/_version.py b/venv/lib/python3.9/site-packages/h11/_version.py deleted file mode 100644 index 76e7327..0000000 --- a/venv/lib/python3.9/site-packages/h11/_version.py +++ /dev/null @@ -1,16 +0,0 @@ -# This file must be kept very simple, because it is consumed from several -# places -- it is imported by h11/__init__.py, execfile'd by setup.py, etc. - -# We use a simple scheme: -# 1.0.0 -> 1.0.0+dev -> 1.1.0 -> 1.1.0+dev -# where the +dev versions are never released into the wild, they're just what -# we stick into the VCS in between releases. -# -# This is compatible with PEP 440: -# http://legacy.python.org/dev/peps/pep-0440/ -# via the use of the "local suffix" "+dev", which is disallowed on index -# servers and causes 1.0.0+dev to sort after plain 1.0.0, which is what we -# want. (Contrast with the special suffix 1.0.0.dev, which sorts *before* -# 1.0.0.) - -__version__ = "0.16.0" diff --git a/venv/lib/python3.9/site-packages/h11/_writers.py b/venv/lib/python3.9/site-packages/h11/_writers.py deleted file mode 100644 index 939cdb9..0000000 --- a/venv/lib/python3.9/site-packages/h11/_writers.py +++ /dev/null @@ -1,145 +0,0 @@ -# Code to read HTTP data -# -# Strategy: each writer takes an event + a write-some-bytes function, which is -# calls. -# -# WRITERS is a dict describing how to pick a reader. It maps states to either: -# - a writer -# - or, for body writers, a dict of framin-dependent writer factories - -from typing import Any, Callable, Dict, List, Tuple, Type, Union - -from ._events import Data, EndOfMessage, Event, InformationalResponse, Request, Response -from ._headers import Headers -from ._state import CLIENT, IDLE, SEND_BODY, SEND_RESPONSE, SERVER -from ._util import LocalProtocolError, Sentinel - -__all__ = ["WRITERS"] - -Writer = Callable[[bytes], Any] - - -def write_headers(headers: Headers, write: Writer) -> None: - # "Since the Host field-value is critical information for handling a - # request, a user agent SHOULD generate Host as the first header field - # following the request-line." - RFC 7230 - raw_items = headers._full_items - for raw_name, name, value in raw_items: - if name == b"host": - write(b"%s: %s\r\n" % (raw_name, value)) - for raw_name, name, value in raw_items: - if name != b"host": - write(b"%s: %s\r\n" % (raw_name, value)) - write(b"\r\n") - - -def write_request(request: Request, write: Writer) -> None: - if request.http_version != b"1.1": - raise LocalProtocolError("I only send HTTP/1.1") - write(b"%s %s HTTP/1.1\r\n" % (request.method, request.target)) - write_headers(request.headers, write) - - -# Shared between InformationalResponse and Response -def write_any_response( - response: Union[InformationalResponse, Response], write: Writer -) -> None: - if response.http_version != b"1.1": - raise LocalProtocolError("I only send HTTP/1.1") - status_bytes = str(response.status_code).encode("ascii") - # We don't bother sending ascii status messages like "OK"; they're - # optional and ignored by the protocol. (But the space after the numeric - # status code is mandatory.) - # - # XX FIXME: could at least make an effort to pull out the status message - # from stdlib's http.HTTPStatus table. Or maybe just steal their enums - # (either by import or copy/paste). We already accept them as status codes - # since they're of type IntEnum < int. - write(b"HTTP/1.1 %s %s\r\n" % (status_bytes, response.reason)) - write_headers(response.headers, write) - - -class BodyWriter: - def __call__(self, event: Event, write: Writer) -> None: - if type(event) is Data: - self.send_data(event.data, write) - elif type(event) is EndOfMessage: - self.send_eom(event.headers, write) - else: # pragma: no cover - assert False - - def send_data(self, data: bytes, write: Writer) -> None: - pass - - def send_eom(self, headers: Headers, write: Writer) -> None: - pass - - -# -# These are all careful not to do anything to 'data' except call len(data) and -# write(data). This allows us to transparently pass-through funny objects, -# like placeholder objects referring to files on disk that will be sent via -# sendfile(2). -# -class ContentLengthWriter(BodyWriter): - def __init__(self, length: int) -> None: - self._length = length - - def send_data(self, data: bytes, write: Writer) -> None: - self._length -= len(data) - if self._length < 0: - raise LocalProtocolError("Too much data for declared Content-Length") - write(data) - - def send_eom(self, headers: Headers, write: Writer) -> None: - if self._length != 0: - raise LocalProtocolError("Too little data for declared Content-Length") - if headers: - raise LocalProtocolError("Content-Length and trailers don't mix") - - -class ChunkedWriter(BodyWriter): - def send_data(self, data: bytes, write: Writer) -> None: - # if we encoded 0-length data in the naive way, it would look like an - # end-of-message. - if not data: - return - write(b"%x\r\n" % len(data)) - write(data) - write(b"\r\n") - - def send_eom(self, headers: Headers, write: Writer) -> None: - write(b"0\r\n") - write_headers(headers, write) - - -class Http10Writer(BodyWriter): - def send_data(self, data: bytes, write: Writer) -> None: - write(data) - - def send_eom(self, headers: Headers, write: Writer) -> None: - if headers: - raise LocalProtocolError("can't send trailers to HTTP/1.0 client") - # no need to close the socket ourselves, that will be taken care of by - # Connection: close machinery - - -WritersType = Dict[ - Union[Tuple[Type[Sentinel], Type[Sentinel]], Type[Sentinel]], - Union[ - Dict[str, Type[BodyWriter]], - Callable[[Union[InformationalResponse, Response], Writer], None], - Callable[[Request, Writer], None], - ], -] - -WRITERS: WritersType = { - (CLIENT, IDLE): write_request, - (SERVER, IDLE): write_any_response, - (SERVER, SEND_RESPONSE): write_any_response, - SEND_BODY: { - "chunked": ChunkedWriter, - "content-length": ContentLengthWriter, - "http/1.0": Http10Writer, - }, -} diff --git a/venv/lib/python3.9/site-packages/h11/py.typed b/venv/lib/python3.9/site-packages/h11/py.typed deleted file mode 100644 index f5642f7..0000000 --- a/venv/lib/python3.9/site-packages/h11/py.typed +++ /dev/null @@ -1 +0,0 @@ -Marker diff --git a/venv/lib/python3.9/site-packages/http_ece-1.2.1.dist-info/INSTALLER b/venv/lib/python3.9/site-packages/http_ece-1.2.1.dist-info/INSTALLER deleted file mode 100644 index a1b589e..0000000 --- a/venv/lib/python3.9/site-packages/http_ece-1.2.1.dist-info/INSTALLER +++ /dev/null @@ -1 +0,0 @@ -pip diff --git a/venv/lib/python3.9/site-packages/http_ece-1.2.1.dist-info/METADATA b/venv/lib/python3.9/site-packages/http_ece-1.2.1.dist-info/METADATA deleted file mode 100644 index c7ea82d..0000000 --- a/venv/lib/python3.9/site-packages/http_ece-1.2.1.dist-info/METADATA +++ /dev/null @@ -1,33 +0,0 @@ -Metadata-Version: 2.4 -Name: http_ece -Version: 1.2.1 -Summary: Encrypted Content Encoding for HTTP -Home-page: https://github.com/martinthomson/encrypted-content-encoding -Author: Martin Thomson -Author-email: martin.thomson@gmail.com -License: MIT -Keywords: crypto http -Classifier: Development Status :: 4 - Beta -Classifier: License :: OSI Approved :: MIT License -Classifier: Programming Language :: Python :: 2.7 -Classifier: Programming Language :: Python :: 3.4 -Classifier: Programming Language :: Python :: 3.5 -Classifier: Programming Language :: Python :: 3.6 -Classifier: Programming Language :: Python :: 3.7 -Classifier: Programming Language :: Python :: 3.8 -Classifier: Programming Language :: Python :: 3.9 -Classifier: Programming Language :: Python :: 3.10 -Classifier: Programming Language :: Python :: 3.11 -Classifier: Programming Language :: Python :: 3.12 -Requires-Dist: cryptography>=2.5 -Dynamic: author -Dynamic: author-email -Dynamic: classifier -Dynamic: description -Dynamic: home-page -Dynamic: keywords -Dynamic: license -Dynamic: requires-dist -Dynamic: summary - -Encipher HTTP Messages diff --git a/venv/lib/python3.9/site-packages/http_ece-1.2.1.dist-info/RECORD b/venv/lib/python3.9/site-packages/http_ece-1.2.1.dist-info/RECORD deleted file mode 100644 index 5db0d58..0000000 --- a/venv/lib/python3.9/site-packages/http_ece-1.2.1.dist-info/RECORD +++ /dev/null @@ -1,7 +0,0 @@ -http_ece-1.2.1.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 -http_ece-1.2.1.dist-info/METADATA,sha256=O44G_AI2K-3Pc1-s7L2DUUmvXzOeaCemhJbfX1M0nQg,1092 -http_ece-1.2.1.dist-info/RECORD,, -http_ece-1.2.1.dist-info/WHEEL,sha256=TdQ5LtNwLuxTCjgxN51AgdU5w-KkB9ttmLbzjTH02pg,109 -http_ece-1.2.1.dist-info/top_level.txt,sha256=-74Do2Twxx-mpdqAgnY6SjAfhncdj5LOK9ImmXbDtj4,9 -http_ece/__init__.py,sha256=Ld0PGOGwwof-a-pTvn-6sdlQ_hW3GEu4D_q9mMQEM_k,13073 -http_ece/__pycache__/__init__.cpython-39.pyc,, diff --git a/venv/lib/python3.9/site-packages/http_ece-1.2.1.dist-info/WHEEL b/venv/lib/python3.9/site-packages/http_ece-1.2.1.dist-info/WHEEL deleted file mode 100644 index b9b700f..0000000 --- a/venv/lib/python3.9/site-packages/http_ece-1.2.1.dist-info/WHEEL +++ /dev/null @@ -1,6 +0,0 @@ -Wheel-Version: 1.0 -Generator: setuptools (82.0.1) -Root-Is-Purelib: true -Tag: py2-none-any -Tag: py3-none-any - diff --git a/venv/lib/python3.9/site-packages/http_ece-1.2.1.dist-info/top_level.txt b/venv/lib/python3.9/site-packages/http_ece-1.2.1.dist-info/top_level.txt deleted file mode 100644 index 7411b2f..0000000 --- a/venv/lib/python3.9/site-packages/http_ece-1.2.1.dist-info/top_level.txt +++ /dev/null @@ -1 +0,0 @@ -http_ece diff --git a/venv/lib/python3.9/site-packages/http_ece/__init__.py b/venv/lib/python3.9/site-packages/http_ece/__init__.py deleted file mode 100644 index d69263a..0000000 --- a/venv/lib/python3.9/site-packages/http_ece/__init__.py +++ /dev/null @@ -1,434 +0,0 @@ -import functools -import os -import struct - -from cryptography.exceptions import InvalidTag -from cryptography.hazmat.backends import default_backend -from cryptography.hazmat.primitives import hashes -from cryptography.hazmat.primitives.kdf.hkdf import HKDF -from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes -from cryptography.hazmat.primitives.serialization import Encoding, PublicFormat -from cryptography.hazmat.primitives.asymmetric import ec - -MAX_RECORD_SIZE = pow(2, 31) - 1 -MIN_RECORD_SIZE = 3 -KEY_LENGTH = 16 -NONCE_LENGTH = 12 -TAG_LENGTH = 16 - -# Valid content types (ordered from newest, to most obsolete) -versions = { - "aes128gcm": {"pad": 1}, - "aesgcm": {"pad": 2}, - "aesgcm128": {"pad": 1}, -} - - -class ECEException(Exception): - """Exception for ECE encryption functions""" - - def __init__(self, message): - self.message = message - - -def derive_key( - mode, version, salt, key, private_key, dh, auth_secret, keyid, keylabel="P-256" -): - """Derive the encryption key - - :param mode: operational mode (encrypt or decrypt) - :type mode: enumerate('encrypt', 'decrypt) - :param salt: encryption salt value - :type salt: str - :param key: raw key - :type key: str - :param private_key: DH private key - :type key: object - :param dh: Diffie Helman public key value - :type dh: str - :param keyid: key identifier label - :type keyid: str - :param keylabel: label for aesgcm/aesgcm128 - :type keylabel: str - :param auth_secret: authorization secret - :type auth_secret: str - :param version: Content Type identifier - :type version: enumerate('aes128gcm', 'aesgcm', 'aesgcm128') - - """ - context = b"" - keyinfo = "" - nonceinfo = "" - - def build_info(base, info_context): - return b"Content-Encoding: " + base + b"\0" + info_context - - def derive_dh(mode, version, private_key, dh, keylabel): - def length_prefix(key): - return struct.pack("!H", len(key)) + key - - if isinstance(dh, ec.EllipticCurvePublicKey): - pubkey = dh - dh = dh.public_bytes(Encoding.X962, PublicFormat.UncompressedPoint) - else: - pubkey = ec.EllipticCurvePublicKey.from_encoded_point(ec.SECP256R1(), dh) - - encoded = private_key.public_key().public_bytes( - Encoding.X962, PublicFormat.UncompressedPoint - ) - if mode == "encrypt": - sender_pub_key = encoded - receiver_pub_key = dh - else: - sender_pub_key = dh - receiver_pub_key = encoded - - if version == "aes128gcm": - context = b"WebPush: info\x00" + receiver_pub_key + sender_pub_key - else: - context = ( - keylabel.encode("utf-8") - + b"\0" - + length_prefix(receiver_pub_key) - + length_prefix(sender_pub_key) - ) - - return private_key.exchange(ec.ECDH(), pubkey), context - - if version not in versions: - raise ECEException("Invalid version") - if mode not in ["encrypt", "decrypt"]: - raise ECEException("unknown 'mode' specified: " + mode) - if salt is None or len(salt) != KEY_LENGTH: - raise ECEException("'salt' must be a 16 octet value") - if dh is not None: - if private_key is None: - raise ECEException("DH requires a private_key") - (secret, context) = derive_dh( - mode=mode, - version=version, - private_key=private_key, - dh=dh, - keylabel=keylabel, - ) - else: - secret = key - - if secret is None: - raise ECEException("unable to determine the secret") - - if version == "aesgcm": - keyinfo = build_info(b"aesgcm", context) - nonceinfo = build_info(b"nonce", context) - elif version == "aesgcm128": - keyinfo = b"Content-Encoding: aesgcm128" - nonceinfo = b"Content-Encoding: nonce" - elif version == "aes128gcm": - keyinfo = b"Content-Encoding: aes128gcm\x00" - nonceinfo = b"Content-Encoding: nonce\x00" - if dh is None: - # Only mix the authentication secret when using DH for aes128gcm - auth_secret = None - - if auth_secret is not None: - if version == "aes128gcm": - info = context - else: - info = build_info(b"auth", b"") - hkdf_auth = HKDF( - algorithm=hashes.SHA256(), - length=32, - salt=auth_secret, - info=info, - backend=default_backend(), - ) - secret = hkdf_auth.derive(secret) - - hkdf_key = HKDF( - algorithm=hashes.SHA256(), - length=KEY_LENGTH, - salt=salt, - info=keyinfo, - backend=default_backend(), - ) - hkdf_nonce = HKDF( - algorithm=hashes.SHA256(), - length=NONCE_LENGTH, - salt=salt, - info=nonceinfo, - backend=default_backend(), - ) - return hkdf_key.derive(secret), hkdf_nonce.derive(secret) - - -def iv(base, counter): - """Generate an initialization vector.""" - if (counter >> 64) != 0: - raise ECEException("Counter too big") - (mask,) = struct.unpack("!Q", base[4:]) - return base[:4] + struct.pack("!Q", counter ^ mask) - - -def decrypt( - content, - salt=None, - key=None, - private_key=None, - dh=None, - auth_secret=None, - keyid=None, - keylabel="P-256", - rs=4096, - version="aes128gcm", -): - """ - Decrypt a data block - - :param content: Data to be decrypted - :type content: str - :param salt: Encryption salt - :type salt: str - :param key: local public key - :type key: str - :param private_key: DH private key - :type key: object - :param keyid: Internal key identifier for private key info - :type keyid: str - :param dh: Remote Diffie Hellman sequence (omit for aes128gcm) - :type dh: str - :param rs: Record size - :type rs: int - :param auth_secret: Authorization secret - :type auth_secret: str - :param version: ECE Method version - :type version: enumerate('aes128gcm', 'aesgcm', 'aesgcm128') - :return: Decrypted message content - :rtype str - - """ - - def parse_content_header(content): - """Parse an aes128gcm content body and extract the header values. - - :param content: The encrypted body of the message - :type content: str - - """ - id_len = struct.unpack("!B", content[20:21])[0] - return { - "salt": content[:16], - "rs": struct.unpack("!L", content[16:20])[0], - "keyid": content[21 : 21 + id_len], - "content": content[21 + id_len :], - } - - def decrypt_record(key, nonce, counter, content): - decryptor = Cipher( - algorithms.AES(key), - modes.GCM(iv(nonce, counter), tag=content[-TAG_LENGTH:]), - backend=default_backend(), - ).decryptor() - return decryptor.update(content[:-TAG_LENGTH]) + decryptor.finalize() - - def unpad_legacy(data): - pad_size = versions[version]["pad"] - pad = functools.reduce( - lambda x, y: x << 8 | y, - struct.unpack("!" + ("B" * pad_size), data[0:pad_size]), - ) - if pad_size + pad > len(data) or data[pad_size : pad_size + pad] != ( - b"\x00" * pad - ): - raise ECEException("Bad padding") - return data[pad_size + pad :] - - def unpad(data, last): - i = len(data) - 1 - for i in range(len(data) - 1, -1, -1): - v = struct.unpack("B", data[i : i + 1])[0] - if v != 0: - if not last and v != 1: - raise ECEException("record delimiter != 1") - if last and v != 2: - raise ECEException("last record delimiter != 2") - return data[0:i] - raise ECEException("all zero record plaintext") - - if version not in versions: - raise ECEException("Invalid version") - - overhead = versions[version]["pad"] - if version == "aes128gcm": - try: - content_header = parse_content_header(content) - except Exception: - raise ECEException("Could not parse the content header") - salt = content_header["salt"] - rs = content_header["rs"] - keyid = content_header["keyid"] - if private_key is not None and not dh: - dh = keyid - else: - keyid = keyid.decode("utf-8") - content = content_header["content"] - overhead += 16 - - (key_, nonce_) = derive_key( - "decrypt", - version=version, - salt=salt, - key=key, - private_key=private_key, - dh=dh, - auth_secret=auth_secret, - keyid=keyid, - keylabel=keylabel, - ) - if rs <= overhead: - raise ECEException("Record size too small") - chunk = rs - if version != "aes128gcm": - chunk += 16 # account for tags in old versions - if len(content) % chunk == 0: - raise ECEException("Message truncated") - - result = b"" - counter = 0 - try: - for i in list(range(0, len(content), chunk)): - data = decrypt_record(key_, nonce_, counter, content[i : i + chunk]) - if version == "aes128gcm": - last = (i + chunk) >= len(content) - result += unpad(data, last) - else: - result += unpad_legacy(data) - counter += 1 - except InvalidTag as ex: - raise ECEException("Decryption error: {}".format(repr(ex))) - return result - - -def encrypt( - content, - salt=None, - key=None, - private_key=None, - dh=None, - auth_secret=None, - keyid=None, - keylabel="P-256", - rs=4096, - version="aes128gcm", -): - """ - Encrypt a data block - - :param content: block of data to encrypt - :type content: str - :param salt: Encryption salt - :type salt: str - :param key: Encryption key data - :type key: str - :param private_key: DH private key - :type key: object - :param keyid: Internal key identifier for private key info - :type keyid: str - :param dh: Remote Diffie Hellman sequence - :type dh: str - :param rs: Record size - :type rs: int - :param auth_secret: Authorization secret - :type auth_secret: str - :param version: ECE Method version - :type version: enumerate('aes128gcm', 'aesgcm', 'aesgcm128') - :return: Encrypted message content - :rtype str - - """ - - def encrypt_record(key, nonce, counter, buf, last): - encryptor = Cipher( - algorithms.AES(key), - modes.GCM(iv(nonce, counter)), - backend=default_backend(), - ).encryptor() - - if version == "aes128gcm": - data = encryptor.update(buf + (b"\x02" if last else b"\x01")) - else: - data = encryptor.update((b"\x00" * versions[version]["pad"]) + buf) - data += encryptor.finalize() - data += encryptor.tag - return data - - def compose_aes128gcm(salt, content, rs, keyid): - """Compose the header and content of an aes128gcm encrypted - message body - - :param salt: The sender's salt value - :type salt: str - :param content: The encrypted body of the message - :type content: str - :param rs: Override for the content length - :type rs: int - :param keyid: The keyid to use for this message - :type keyid: str - - """ - if len(keyid) > 255: - raise ECEException("keyid is too long") - header = salt - if rs > MAX_RECORD_SIZE: - raise ECEException("Too much content") - header += struct.pack("!L", rs) - header += struct.pack("!B", len(keyid)) - header += keyid - return header + content - - if version not in versions: - raise ECEException("Invalid version") - - if salt is None: - salt = os.urandom(16) - - (key_, nonce_) = derive_key( - "encrypt", - version=version, - salt=salt, - key=key, - private_key=private_key, - dh=dh, - auth_secret=auth_secret, - keyid=keyid, - keylabel=keylabel, - ) - - overhead = versions[version]["pad"] - if version == "aes128gcm": - overhead += 16 - end = len(content) - else: - end = len(content) + 1 - if rs <= overhead: - raise ECEException("Record size too small") - chunk_size = rs - overhead - - result = b"" - counter = 0 - - # the extra one on the loop ensures that we produce a padding only - # record if the data length is an exact multiple of the chunk size - for i in list(range(0, end, chunk_size)): - result += encrypt_record( - key_, nonce_, counter, content[i : i + chunk_size], (i + chunk_size) >= end - ) - counter += 1 - if version == "aes128gcm": - if keyid is None and private_key is not None: - kid = private_key.public_key().public_bytes( - Encoding.X962, PublicFormat.UncompressedPoint - ) - else: - kid = (keyid or "").encode("utf-8") - return compose_aes128gcm(salt, result, rs, keyid=kid) - return result diff --git a/venv/lib/python3.9/site-packages/idna-3.13.dist-info/INSTALLER b/venv/lib/python3.9/site-packages/idna-3.13.dist-info/INSTALLER deleted file mode 100644 index a1b589e..0000000 --- a/venv/lib/python3.9/site-packages/idna-3.13.dist-info/INSTALLER +++ /dev/null @@ -1 +0,0 @@ -pip diff --git a/venv/lib/python3.9/site-packages/idna-3.13.dist-info/METADATA b/venv/lib/python3.9/site-packages/idna-3.13.dist-info/METADATA deleted file mode 100644 index b30fccc..0000000 --- a/venv/lib/python3.9/site-packages/idna-3.13.dist-info/METADATA +++ /dev/null @@ -1,204 +0,0 @@ -Metadata-Version: 2.4 -Name: idna -Version: 3.13 -Summary: Internationalized Domain Names in Applications (IDNA) -Author-email: Kim Davies -Requires-Python: >=3.8 -Description-Content-Type: text/x-rst -License-Expression: BSD-3-Clause -Classifier: Development Status :: 5 - Production/Stable -Classifier: Intended Audience :: Developers -Classifier: Intended Audience :: System Administrators -Classifier: Operating System :: OS Independent -Classifier: Programming Language :: Python -Classifier: Programming Language :: Python :: 3 -Classifier: Programming Language :: Python :: 3 :: Only -Classifier: Programming Language :: Python :: 3.8 -Classifier: Programming Language :: Python :: 3.9 -Classifier: Programming Language :: Python :: 3.10 -Classifier: Programming Language :: Python :: 3.11 -Classifier: Programming Language :: Python :: 3.12 -Classifier: Programming Language :: Python :: 3.13 -Classifier: Programming Language :: Python :: 3.14 -Classifier: Programming Language :: Python :: Implementation :: CPython -Classifier: Programming Language :: Python :: Implementation :: PyPy -Classifier: Topic :: Internet :: Name Service (DNS) -Classifier: Topic :: Software Development :: Libraries :: Python Modules -Classifier: Topic :: Utilities -License-File: LICENSE.md -Requires-Dist: ruff >= 0.6.2 ; extra == "all" -Requires-Dist: mypy >= 1.11.2 ; extra == "all" -Requires-Dist: pytest >= 8.3.2 ; extra == "all" -Project-URL: Changelog, https://github.com/kjd/idna/blob/master/HISTORY.rst -Project-URL: Issue tracker, https://github.com/kjd/idna/issues -Project-URL: Source, https://github.com/kjd/idna -Provides-Extra: all - -Internationalized Domain Names in Applications (IDNA) -===================================================== - -Support for `Internationalized Domain Names in -Applications (IDNA) `_ -and `Unicode IDNA Compatibility Processing -`_. - -The latest versions of these standards supplied here provide -more comprehensive language coverage and reduce the potential of -allowing domains with known security vulnerabilities. This library -is a suitable replacement for the “encodings.idna” -module that comes with the Python standard library, but which -only supports an older superseded IDNA specification from 2003. - -Basic functions are simply executed: - -.. code-block:: pycon - - >>> import idna - >>> idna.encode('ドメイン.テスト') - b'xn--eckwd4c7c.xn--zckzah' - >>> print(idna.decode('xn--eckwd4c7c.xn--zckzah')) - ドメイン.テスト - - -Installation ------------- - -This package is available for installation from PyPI via the -typical mechanisms, such as: - -.. code-block:: bash - - $ python3 -m pip install idna - - -Usage ------ - -For typical usage, the ``encode`` and ``decode`` functions will take a -domain name argument and perform a conversion to ASCII-compatible encoding -(known as A-labels), or to Unicode strings (known as U-labels) -respectively. - -.. code-block:: pycon - - >>> import idna - >>> idna.encode('ドメイン.テスト') - b'xn--eckwd4c7c.xn--zckzah' - >>> print(idna.decode('xn--eckwd4c7c.xn--zckzah')) - ドメイン.テスト - -Conversions can be applied at a per-label basis using the ``ulabel`` or -``alabel`` functions if necessary: - -.. code-block:: pycon - - >>> idna.alabel('测试') - b'xn--0zwm56d' - - -Compatibility Mapping (UTS #46) -+++++++++++++++++++++++++++++++ - -This library provides support for `Unicode IDNA Compatibility -Processing `_ which normalizes input from -different potential ways a user may input a domain prior to performing the IDNA -conversion operations. This functionality, known as a -`mapping `_, is considered by the -specification to be a local user-interface issue distinct from IDNA -conversion functionality. - -For example, “Königsgäßchen” is not a permissible label as *LATIN -CAPITAL LETTER K* is not allowed (nor are capital letters in general). -UTS 46 will convert this into lower case prior to applying the IDNA -conversion. - -.. code-block:: pycon - - >>> import idna - >>> idna.encode('Königsgäßchen') - ... - idna.core.InvalidCodepoint: Codepoint U+004B at position 1 of 'Königsgäßchen' not allowed - >>> idna.encode('Königsgäßchen', uts46=True) - b'xn--knigsgchen-b4a3dun' - >>> print(idna.decode('xn--knigsgchen-b4a3dun')) - königsgäßchen - - -Exceptions ----------- - -All errors raised during the conversion following the specification -should raise an exception derived from the ``idna.IDNAError`` base -class. - -More specific exceptions that may be generated as ``idna.IDNABidiError`` -when the error reflects an illegal combination of left-to-right and -right-to-left characters in a label; ``idna.InvalidCodepoint`` when -a specific codepoint is an illegal character in an IDN label (i.e. -INVALID); and ``idna.InvalidCodepointContext`` when the codepoint is -illegal based on its position in the string (i.e. it is CONTEXTO or CONTEXTJ -but the contextual requirements are not satisfied.) - -Building and Diagnostics ------------------------- - -The IDNA and UTS 46 functionality relies upon pre-calculated lookup -tables for performance. These tables are derived from computing against -eligibility criteria in the respective standards using the command-line -script ``tools/idna-data``. - -This tool will fetch relevant codepoint data from the Unicode repository -and perform the required calculations to identify eligibility. There are -three main modes: - -* ``idna-data make-libdata``. Generates ``idnadata.py`` and - ``uts46data.py``, the pre-calculated lookup tables used for IDNA and - UTS 46 conversions. Implementers who wish to track this library against - a different Unicode version may use this tool to manually generate a - different version of the ``idnadata.py`` and ``uts46data.py`` files. - -* ``idna-data make-table``. Generate a table of the IDNA disposition - (e.g. PVALID, CONTEXTJ, CONTEXTO) in the format found in Appendix - B.1 of RFC 5892 and the pre-computed tables published by `IANA - `_. - -* ``idna-data U+0061``. Prints debugging output on the various - properties associated with an individual Unicode codepoint (in this - case, U+0061), that are used to assess the IDNA and UTS 46 status of a - codepoint. This is helpful in debugging or analysis. - -The tool accepts a number of arguments, described using ``idna-data -h``. -Most notably, the ``--version`` argument allows the specification -of the version of Unicode to be used in computing the table data. For -example, ``idna-data --version 9.0.0 make-libdata`` will generate -library data against Unicode 9.0.0. - - -Additional Notes ----------------- - -* **Packages**. The latest tagged release version is published in the - `Python Package Index `_. - -* **Version support**. This library supports Python 3.8 and higher. - As this library serves as a low-level toolkit for a variety of - applications, many of which strive for broad compatibility with older - Python versions, there is no rush to remove older interpreter support. - Support for older versions are likely to be removed from new releases - as automated tests can no longer easily be run, i.e. once the Python - version is officially end-of-life. - -* **Testing**. The library has a test suite based on each rule of the - IDNA specification, as well as tests that are provided as part of the - Unicode Technical Standard 46, `Unicode IDNA Compatibility Processing - `_. - -* **Emoji**. It is an occasional request to support emoji domains in - this library. Encoding of symbols like emoji is expressly prohibited by - the IDNA technical standard, and emoji domains are broadly phased - out across the domain industry due to associated security risks. - -* **Transitional processing**. Unicode 16.0.0 removed transitional - processing so the `transitional` argument for the encode() method - no longer has any effect and will be removed at a later date. - diff --git a/venv/lib/python3.9/site-packages/idna-3.13.dist-info/RECORD b/venv/lib/python3.9/site-packages/idna-3.13.dist-info/RECORD deleted file mode 100644 index 460558d..0000000 --- a/venv/lib/python3.9/site-packages/idna-3.13.dist-info/RECORD +++ /dev/null @@ -1,22 +0,0 @@ -idna-3.13.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 -idna-3.13.dist-info/METADATA,sha256=aCJPP9iIHtp9NZSENIrzP52rgjQxw0-PWNfHGJ7ffQA,8033 -idna-3.13.dist-info/RECORD,, -idna-3.13.dist-info/WHEEL,sha256=G2gURzTEtmeR8nrdXUJfNiB3VYVxigPQ-bEQujpNiNs,82 -idna-3.13.dist-info/licenses/LICENSE.md,sha256=GppPDj1HmickDd1ZqRN6ZqtKD539yMphiMwL_YUYfwQ,1541 -idna/__init__.py,sha256=MPqNDLZbXqGaNdXxAFhiqFPKEQXju2jNQhCey6-5eJM,868 -idna/__pycache__/__init__.cpython-39.pyc,, -idna/__pycache__/codec.cpython-39.pyc,, -idna/__pycache__/compat.cpython-39.pyc,, -idna/__pycache__/core.cpython-39.pyc,, -idna/__pycache__/idnadata.cpython-39.pyc,, -idna/__pycache__/intranges.cpython-39.pyc,, -idna/__pycache__/package_data.cpython-39.pyc,, -idna/__pycache__/uts46data.cpython-39.pyc,, -idna/codec.py,sha256=M2SGWN7cs_6B32QmKTyTN6xQGZeYQgQ2wiX3_DR6loE,3438 -idna/compat.py,sha256=RzLy6QQCdl9784aFhb2EX9EKGCJjg0P3PilGdeXXcx8,316 -idna/core.py,sha256=0_28DR8hKT_pJKcmbeIQiiO1rHOpS3kJTtp9pyrk-4k,13374 -idna/idnadata.py,sha256=EYkhqhOze0Whw1pIMum_-qEHM-8utUwc_IBoIUWW8Go,92613 -idna/intranges.py,sha256=amUtkdhYcQG8Zr-CoMM_kVRacxkivC1WgxN1b63KKdU,1898 -idna/package_data.py,sha256=Nc4yldCrxxvai27WL76JL60jhw0ajOoboFGsm5L8FxM,21 -idna/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 -idna/uts46data.py,sha256=JAacELsMTouJI-U6jk_UcKuAM4K7ffGCYpbDLux8iVk,202713 diff --git a/venv/lib/python3.9/site-packages/idna-3.13.dist-info/WHEEL b/venv/lib/python3.9/site-packages/idna-3.13.dist-info/WHEEL deleted file mode 100644 index d8b9936..0000000 --- a/venv/lib/python3.9/site-packages/idna-3.13.dist-info/WHEEL +++ /dev/null @@ -1,4 +0,0 @@ -Wheel-Version: 1.0 -Generator: flit 3.12.0 -Root-Is-Purelib: true -Tag: py3-none-any diff --git a/venv/lib/python3.9/site-packages/idna-3.13.dist-info/licenses/LICENSE.md b/venv/lib/python3.9/site-packages/idna-3.13.dist-info/licenses/LICENSE.md deleted file mode 100644 index f706835..0000000 --- a/venv/lib/python3.9/site-packages/idna-3.13.dist-info/licenses/LICENSE.md +++ /dev/null @@ -1,31 +0,0 @@ -BSD 3-Clause License - -Copyright (c) 2013-2026, Kim Davies and contributors. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - -1. Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - -2. Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - -3. Neither the name of the copyright holder nor the names of its - contributors may be used to endorse or promote products derived from - this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED -TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR -PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF -LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING -NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/venv/lib/python3.9/site-packages/idna/__init__.py b/venv/lib/python3.9/site-packages/idna/__init__.py deleted file mode 100644 index cfdc030..0000000 --- a/venv/lib/python3.9/site-packages/idna/__init__.py +++ /dev/null @@ -1,45 +0,0 @@ -from .core import ( - IDNABidiError, - IDNAError, - InvalidCodepoint, - InvalidCodepointContext, - alabel, - check_bidi, - check_hyphen_ok, - check_initial_combiner, - check_label, - check_nfc, - decode, - encode, - ulabel, - uts46_remap, - valid_contextj, - valid_contexto, - valid_label_length, - valid_string_length, -) -from .intranges import intranges_contain -from .package_data import __version__ - -__all__ = [ - "__version__", - "IDNABidiError", - "IDNAError", - "InvalidCodepoint", - "InvalidCodepointContext", - "alabel", - "check_bidi", - "check_hyphen_ok", - "check_initial_combiner", - "check_label", - "check_nfc", - "decode", - "encode", - "intranges_contain", - "ulabel", - "uts46_remap", - "valid_contextj", - "valid_contexto", - "valid_label_length", - "valid_string_length", -] diff --git a/venv/lib/python3.9/site-packages/idna/codec.py b/venv/lib/python3.9/site-packages/idna/codec.py deleted file mode 100644 index cbc2e4f..0000000 --- a/venv/lib/python3.9/site-packages/idna/codec.py +++ /dev/null @@ -1,122 +0,0 @@ -import codecs -import re -from typing import Any, Optional, Tuple - -from .core import IDNAError, alabel, decode, encode, ulabel - -_unicode_dots_re = re.compile("[\u002e\u3002\uff0e\uff61]") - - -class Codec(codecs.Codec): - def encode(self, data: str, errors: str = "strict") -> Tuple[bytes, int]: - if errors != "strict": - raise IDNAError('Unsupported error handling "{}"'.format(errors)) - - if not data: - return b"", 0 - - return encode(data), len(data) - - def decode(self, data: bytes, errors: str = "strict") -> Tuple[str, int]: - if errors != "strict": - raise IDNAError('Unsupported error handling "{}"'.format(errors)) - - if not data: - return "", 0 - - return decode(data), len(data) - - -class IncrementalEncoder(codecs.BufferedIncrementalEncoder): - def _buffer_encode(self, data: str, errors: str, final: bool) -> Tuple[bytes, int]: - if errors != "strict": - raise IDNAError('Unsupported error handling "{}"'.format(errors)) - - if not data: - return b"", 0 - - labels = _unicode_dots_re.split(data) - trailing_dot = b"" - if labels: - if not labels[-1]: - trailing_dot = b"." - del labels[-1] - elif not final: - # Keep potentially unfinished label until the next call - del labels[-1] - if labels: - trailing_dot = b"." - - result = [] - size = 0 - for label in labels: - result.append(alabel(label)) - if size: - size += 1 - size += len(label) - - # Join with U+002E - result_bytes = b".".join(result) + trailing_dot - size += len(trailing_dot) - return result_bytes, size - - -class IncrementalDecoder(codecs.BufferedIncrementalDecoder): - def _buffer_decode(self, data: Any, errors: str, final: bool) -> Tuple[str, int]: - if errors != "strict": - raise IDNAError('Unsupported error handling "{}"'.format(errors)) - - if not data: - return ("", 0) - - if not isinstance(data, str): - data = str(data, "ascii") - - labels = _unicode_dots_re.split(data) - trailing_dot = "" - if labels: - if not labels[-1]: - trailing_dot = "." - del labels[-1] - elif not final: - # Keep potentially unfinished label until the next call - del labels[-1] - if labels: - trailing_dot = "." - - result = [] - size = 0 - for label in labels: - result.append(ulabel(label)) - if size: - size += 1 - size += len(label) - - result_str = ".".join(result) + trailing_dot - size += len(trailing_dot) - return (result_str, size) - - -class StreamWriter(Codec, codecs.StreamWriter): - pass - - -class StreamReader(Codec, codecs.StreamReader): - pass - - -def search_function(name: str) -> Optional[codecs.CodecInfo]: - if name != "idna2008": - return None - return codecs.CodecInfo( - name=name, - encode=Codec().encode, - decode=Codec().decode, # type: ignore - incrementalencoder=IncrementalEncoder, - incrementaldecoder=IncrementalDecoder, - streamwriter=StreamWriter, - streamreader=StreamReader, - ) - - -codecs.register(search_function) diff --git a/venv/lib/python3.9/site-packages/idna/compat.py b/venv/lib/python3.9/site-packages/idna/compat.py deleted file mode 100644 index 1df9f2a..0000000 --- a/venv/lib/python3.9/site-packages/idna/compat.py +++ /dev/null @@ -1,15 +0,0 @@ -from typing import Any, Union - -from .core import decode, encode - - -def ToASCII(label: str) -> bytes: - return encode(label) - - -def ToUnicode(label: Union[bytes, bytearray]) -> str: - return decode(label) - - -def nameprep(s: Any) -> None: - raise NotImplementedError("IDNA 2008 does not utilise nameprep protocol") diff --git a/venv/lib/python3.9/site-packages/idna/core.py b/venv/lib/python3.9/site-packages/idna/core.py deleted file mode 100644 index e6ac1f9..0000000 --- a/venv/lib/python3.9/site-packages/idna/core.py +++ /dev/null @@ -1,440 +0,0 @@ -import bisect -import re -import unicodedata -import warnings -from typing import Optional, Union - -from . import idnadata -from .intranges import intranges_contain - -_virama_combining_class = 9 -_alabel_prefix = b"xn--" -_unicode_dots_re = re.compile("[\u002e\u3002\uff0e\uff61]") - - -class IDNAError(UnicodeError): - """Base exception for all IDNA-encoding related problems""" - - pass - - -class IDNABidiError(IDNAError): - """Exception when bidirectional requirements are not satisfied""" - - pass - - -class InvalidCodepoint(IDNAError): - """Exception when a disallowed or unallocated codepoint is used""" - - pass - - -class InvalidCodepointContext(IDNAError): - """Exception when the codepoint is not valid in the context it is used""" - - pass - - -def _combining_class(cp: int) -> int: - v = unicodedata.combining(chr(cp)) - if v == 0: - if not unicodedata.name(chr(cp)): - raise ValueError("Unknown character in unicodedata") - return v - - -def _is_script(cp: str, script: str) -> bool: - return intranges_contain(ord(cp), idnadata.scripts[script]) - - -def _punycode(s: str) -> bytes: - return s.encode("punycode") - - -def _unot(s: int) -> str: - return "U+{:04X}".format(s) - - -def valid_label_length(label: Union[bytes, str]) -> bool: - if len(label) > 63: - return False - return True - - -def valid_string_length(label: Union[bytes, str], trailing_dot: bool) -> bool: - if len(label) > (254 if trailing_dot else 253): - return False - return True - - -def check_bidi(label: str, check_ltr: bool = False) -> bool: - # Bidi rules should only be applied if string contains RTL characters - bidi_label = False - for idx, cp in enumerate(label, 1): - direction = unicodedata.bidirectional(cp) - if direction == "": - # String likely comes from a newer version of Unicode - raise IDNABidiError("Unknown directionality in label {} at position {}".format(repr(label), idx)) - if direction in ["R", "AL", "AN"]: - bidi_label = True - if not bidi_label and not check_ltr: - return True - - # Bidi rule 1 - direction = unicodedata.bidirectional(label[0]) - if direction in ["R", "AL"]: - rtl = True - elif direction == "L": - rtl = False - else: - raise IDNABidiError("First codepoint in label {} must be directionality L, R or AL".format(repr(label))) - - valid_ending = False - number_type: Optional[str] = None - for idx, cp in enumerate(label, 1): - direction = unicodedata.bidirectional(cp) - - if rtl: - # Bidi rule 2 - if direction not in [ - "R", - "AL", - "AN", - "EN", - "ES", - "CS", - "ET", - "ON", - "BN", - "NSM", - ]: - raise IDNABidiError("Invalid direction for codepoint at position {} in a right-to-left label".format(idx)) - # Bidi rule 3 - if direction in ["R", "AL", "EN", "AN"]: - valid_ending = True - elif direction != "NSM": - valid_ending = False - # Bidi rule 4 - if direction in ["AN", "EN"]: - if not number_type: - number_type = direction - else: - if number_type != direction: - raise IDNABidiError("Can not mix numeral types in a right-to-left label") - else: - # Bidi rule 5 - if direction not in ["L", "EN", "ES", "CS", "ET", "ON", "BN", "NSM"]: - raise IDNABidiError("Invalid direction for codepoint at position {} in a left-to-right label".format(idx)) - # Bidi rule 6 - if direction in ["L", "EN"]: - valid_ending = True - elif direction != "NSM": - valid_ending = False - - if not valid_ending: - raise IDNABidiError("Label ends with illegal codepoint directionality") - - return True - - -def check_initial_combiner(label: str) -> bool: - if unicodedata.category(label[0])[0] == "M": - raise IDNAError("Label begins with an illegal combining character") - return True - - -def check_hyphen_ok(label: str) -> bool: - if label[2:4] == "--": - raise IDNAError("Label has disallowed hyphens in 3rd and 4th position") - if label[0] == "-" or label[-1] == "-": - raise IDNAError("Label must not start or end with a hyphen") - return True - - -def check_nfc(label: str) -> None: - if unicodedata.normalize("NFC", label) != label: - raise IDNAError("Label must be in Normalization Form C") - - -def valid_contextj(label: str, pos: int) -> bool: - cp_value = ord(label[pos]) - - if cp_value == 0x200C: - if pos > 0: - if _combining_class(ord(label[pos - 1])) == _virama_combining_class: - return True - - ok = False - for i in range(pos - 1, -1, -1): - joining_type = idnadata.joining_types().get(ord(label[i])) - if joining_type == ord("T"): - continue - elif joining_type in [ord("L"), ord("D")]: - ok = True - break - else: - break - - if not ok: - return False - - ok = False - for i in range(pos + 1, len(label)): - joining_type = idnadata.joining_types().get(ord(label[i])) - if joining_type == ord("T"): - continue - elif joining_type in [ord("R"), ord("D")]: - ok = True - break - else: - break - return ok - - if cp_value == 0x200D: - if pos > 0: - if _combining_class(ord(label[pos - 1])) == _virama_combining_class: - return True - return False - - else: - return False - - -def valid_contexto(label: str, pos: int, exception: bool = False) -> bool: - cp_value = ord(label[pos]) - - if cp_value == 0x00B7: - if 0 < pos < len(label) - 1: - if ord(label[pos - 1]) == 0x006C and ord(label[pos + 1]) == 0x006C: - return True - return False - - elif cp_value == 0x0375: - if pos < len(label) - 1 and len(label) > 1: - return _is_script(label[pos + 1], "Greek") - return False - - elif cp_value == 0x05F3 or cp_value == 0x05F4: - if pos > 0: - return _is_script(label[pos - 1], "Hebrew") - return False - - elif cp_value == 0x30FB: - for cp in label: - if cp == "\u30fb": - continue - if _is_script(cp, "Hiragana") or _is_script(cp, "Katakana") or _is_script(cp, "Han"): - return True - return False - - elif 0x660 <= cp_value <= 0x669: - for cp in label: - if 0x6F0 <= ord(cp) <= 0x06F9: - return False - return True - - elif 0x6F0 <= cp_value <= 0x6F9: - for cp in label: - if 0x660 <= ord(cp) <= 0x0669: - return False - return True - - return False - - -def check_label(label: Union[str, bytes, bytearray]) -> None: - if isinstance(label, (bytes, bytearray)): - label = label.decode("utf-8") - if len(label) == 0: - raise IDNAError("Empty Label") - - check_nfc(label) - check_hyphen_ok(label) - check_initial_combiner(label) - - for pos, cp in enumerate(label): - cp_value = ord(cp) - if intranges_contain(cp_value, idnadata.codepoint_classes["PVALID"]): - continue - elif intranges_contain(cp_value, idnadata.codepoint_classes["CONTEXTJ"]): - try: - if not valid_contextj(label, pos): - raise InvalidCodepointContext( - "Joiner {} not allowed at position {} in {}".format(_unot(cp_value), pos + 1, repr(label)) - ) - except ValueError: - raise IDNAError( - "Unknown codepoint adjacent to joiner {} at position {} in {}".format( - _unot(cp_value), pos + 1, repr(label) - ) - ) - elif intranges_contain(cp_value, idnadata.codepoint_classes["CONTEXTO"]): - if not valid_contexto(label, pos): - raise InvalidCodepointContext( - "Codepoint {} not allowed at position {} in {}".format(_unot(cp_value), pos + 1, repr(label)) - ) - else: - raise InvalidCodepoint( - "Codepoint {} at position {} of {} not allowed".format(_unot(cp_value), pos + 1, repr(label)) - ) - - check_bidi(label) - - -def alabel(label: str) -> bytes: - try: - label_bytes = label.encode("ascii") - ulabel(label_bytes) - if not valid_label_length(label_bytes): - raise IDNAError("Label too long") - return label_bytes - except UnicodeEncodeError: - pass - - check_label(label) - label_bytes = _alabel_prefix + _punycode(label) - - if not valid_label_length(label_bytes): - raise IDNAError("Label too long") - - return label_bytes - - -def ulabel(label: Union[str, bytes, bytearray]) -> str: - if not isinstance(label, (bytes, bytearray)): - try: - label_bytes = label.encode("ascii") - except UnicodeEncodeError: - check_label(label) - return label - else: - label_bytes = bytes(label) - - label_bytes = label_bytes.lower() - if label_bytes.startswith(_alabel_prefix): - label_bytes = label_bytes[len(_alabel_prefix) :] - if not label_bytes: - raise IDNAError("Malformed A-label, no Punycode eligible content found") - if label_bytes.decode("ascii")[-1] == "-": - raise IDNAError("A-label must not end with a hyphen") - else: - check_label(label_bytes) - return label_bytes.decode("ascii") - - try: - label = label_bytes.decode("punycode") - except UnicodeError: - raise IDNAError("Invalid A-label") - check_label(label) - return label - - -def uts46_remap(domain: str, std3_rules: bool = True, transitional: bool = False) -> str: - """Re-map the characters in the string according to UTS46 processing.""" - from .uts46data import uts46data - - output = "" - - for pos, char in enumerate(domain): - code_point = ord(char) - uts46row = uts46data[code_point if code_point < 256 else bisect.bisect_left(uts46data, (code_point, "Z")) - 1] - status = uts46row[1] - replacement: Optional[str] = None - if len(uts46row) == 3: - replacement = uts46row[2] - if status == "V" or (status == "D" and not transitional) or (status == "3" and not std3_rules and replacement is None): - output += char - elif replacement is not None and ( - status == "M" or (status == "3" and not std3_rules) or (status == "D" and transitional) - ): - output += replacement - elif status == "I": - continue - else: - raise InvalidCodepoint( - "Codepoint {} not allowed at position {} in {}".format(_unot(code_point), pos + 1, repr(domain)) - ) - - return unicodedata.normalize("NFC", output) - - -def encode( - s: Union[str, bytes, bytearray], - strict: bool = False, - uts46: bool = False, - std3_rules: bool = False, - transitional: bool = False, -) -> bytes: - if transitional: - warnings.warn( - "Transitional processing has been removed from UTS #46. " - "The transitional argument will be removed in a future version.", - DeprecationWarning, - stacklevel=2, - ) - if not isinstance(s, str): - try: - s = str(s, "ascii") - except UnicodeDecodeError: - raise IDNAError("should pass a unicode string to the function rather than a byte string.") - if uts46: - s = uts46_remap(s, std3_rules, transitional) - trailing_dot = False - result = [] - if strict: - labels = s.split(".") - else: - labels = _unicode_dots_re.split(s) - if not labels or labels == [""]: - raise IDNAError("Empty domain") - if labels[-1] == "": - del labels[-1] - trailing_dot = True - for label in labels: - s = alabel(label) - if s: - result.append(s) - else: - raise IDNAError("Empty label") - if trailing_dot: - result.append(b"") - s = b".".join(result) - if not valid_string_length(s, trailing_dot): - raise IDNAError("Domain too long") - return s - - -def decode( - s: Union[str, bytes, bytearray], - strict: bool = False, - uts46: bool = False, - std3_rules: bool = False, -) -> str: - try: - if not isinstance(s, str): - s = str(s, "ascii") - except UnicodeDecodeError: - raise IDNAError("Invalid ASCII in A-label") - if uts46: - s = uts46_remap(s, std3_rules, False) - trailing_dot = False - result = [] - if not strict: - labels = _unicode_dots_re.split(s) - else: - labels = s.split(".") - if not labels or labels == [""]: - raise IDNAError("Empty domain") - if not labels[-1]: - del labels[-1] - trailing_dot = True - for label in labels: - s = ulabel(label) - if s: - result.append(s) - else: - raise IDNAError("Empty label") - if trailing_dot: - result.append("") - return ".".join(result) diff --git a/venv/lib/python3.9/site-packages/idna/idnadata.py b/venv/lib/python3.9/site-packages/idna/idnadata.py deleted file mode 100644 index 8335f26..0000000 --- a/venv/lib/python3.9/site-packages/idna/idnadata.py +++ /dev/null @@ -1,4367 +0,0 @@ -# This file is automatically generated by tools/idna-data - -from functools import lru_cache -from typing import Dict - -__version__ = "17.0.0" - -scripts = { - "Greek": ( - 0x37000000374, - 0x37500000378, - 0x37A0000037E, - 0x37F00000380, - 0x38400000385, - 0x38600000387, - 0x3880000038B, - 0x38C0000038D, - 0x38E000003A2, - 0x3A3000003E2, - 0x3F000000400, - 0x1D2600001D2B, - 0x1D5D00001D62, - 0x1D6600001D6B, - 0x1DBF00001DC0, - 0x1F0000001F16, - 0x1F1800001F1E, - 0x1F2000001F46, - 0x1F4800001F4E, - 0x1F5000001F58, - 0x1F5900001F5A, - 0x1F5B00001F5C, - 0x1F5D00001F5E, - 0x1F5F00001F7E, - 0x1F8000001FB5, - 0x1FB600001FC5, - 0x1FC600001FD4, - 0x1FD600001FDC, - 0x1FDD00001FF0, - 0x1FF200001FF5, - 0x1FF600001FFF, - 0x212600002127, - 0xAB650000AB66, - 0x101400001018F, - 0x101A0000101A1, - 0x1D2000001D246, - ), - "Han": ( - 0x2E8000002E9A, - 0x2E9B00002EF4, - 0x2F0000002FD6, - 0x300500003006, - 0x300700003008, - 0x30210000302A, - 0x30380000303C, - 0x340000004DC0, - 0x4E000000A000, - 0xF9000000FA6E, - 0xFA700000FADA, - 0x16FE200016FE4, - 0x16FF000016FF7, - 0x200000002A6E0, - 0x2A7000002B81E, - 0x2B8200002CEAE, - 0x2CEB00002EBE1, - 0x2EBF00002EE5E, - 0x2F8000002FA1E, - 0x300000003134B, - 0x313500003347A, - ), - "Hebrew": ( - 0x591000005C8, - 0x5D0000005EB, - 0x5EF000005F5, - 0xFB1D0000FB37, - 0xFB380000FB3D, - 0xFB3E0000FB3F, - 0xFB400000FB42, - 0xFB430000FB45, - 0xFB460000FB50, - ), - "Hiragana": ( - 0x304100003097, - 0x309D000030A0, - 0x1B0010001B120, - 0x1B1320001B133, - 0x1B1500001B153, - 0x1F2000001F201, - ), - "Katakana": ( - 0x30A1000030FB, - 0x30FD00003100, - 0x31F000003200, - 0x32D0000032FF, - 0x330000003358, - 0xFF660000FF70, - 0xFF710000FF9E, - 0x1AFF00001AFF4, - 0x1AFF50001AFFC, - 0x1AFFD0001AFFF, - 0x1B0000001B001, - 0x1B1200001B123, - 0x1B1550001B156, - 0x1B1640001B168, - ), -} - - -@lru_cache(None) -def joining_types() -> Dict[int, int]: - return { - 0xAD: 84, - 0x300: 84, - 0x301: 84, - 0x302: 84, - 0x303: 84, - 0x304: 84, - 0x305: 84, - 0x306: 84, - 0x307: 84, - 0x308: 84, - 0x309: 84, - 0x30A: 84, - 0x30B: 84, - 0x30C: 84, - 0x30D: 84, - 0x30E: 84, - 0x30F: 84, - 0x310: 84, - 0x311: 84, - 0x312: 84, - 0x313: 84, - 0x314: 84, - 0x315: 84, - 0x316: 84, - 0x317: 84, - 0x318: 84, - 0x319: 84, - 0x31A: 84, - 0x31B: 84, - 0x31C: 84, - 0x31D: 84, - 0x31E: 84, - 0x31F: 84, - 0x320: 84, - 0x321: 84, - 0x322: 84, - 0x323: 84, - 0x324: 84, - 0x325: 84, - 0x326: 84, - 0x327: 84, - 0x328: 84, - 0x329: 84, - 0x32A: 84, - 0x32B: 84, - 0x32C: 84, - 0x32D: 84, - 0x32E: 84, - 0x32F: 84, - 0x330: 84, - 0x331: 84, - 0x332: 84, - 0x333: 84, - 0x334: 84, - 0x335: 84, - 0x336: 84, - 0x337: 84, - 0x338: 84, - 0x339: 84, - 0x33A: 84, - 0x33B: 84, - 0x33C: 84, - 0x33D: 84, - 0x33E: 84, - 0x33F: 84, - 0x340: 84, - 0x341: 84, - 0x342: 84, - 0x343: 84, - 0x344: 84, - 0x345: 84, - 0x346: 84, - 0x347: 84, - 0x348: 84, - 0x349: 84, - 0x34A: 84, - 0x34B: 84, - 0x34C: 84, - 0x34D: 84, - 0x34E: 84, - 0x34F: 84, - 0x350: 84, - 0x351: 84, - 0x352: 84, - 0x353: 84, - 0x354: 84, - 0x355: 84, - 0x356: 84, - 0x357: 84, - 0x358: 84, - 0x359: 84, - 0x35A: 84, - 0x35B: 84, - 0x35C: 84, - 0x35D: 84, - 0x35E: 84, - 0x35F: 84, - 0x360: 84, - 0x361: 84, - 0x362: 84, - 0x363: 84, - 0x364: 84, - 0x365: 84, - 0x366: 84, - 0x367: 84, - 0x368: 84, - 0x369: 84, - 0x36A: 84, - 0x36B: 84, - 0x36C: 84, - 0x36D: 84, - 0x36E: 84, - 0x36F: 84, - 0x483: 84, - 0x484: 84, - 0x485: 84, - 0x486: 84, - 0x487: 84, - 0x488: 84, - 0x489: 84, - 0x591: 84, - 0x592: 84, - 0x593: 84, - 0x594: 84, - 0x595: 84, - 0x596: 84, - 0x597: 84, - 0x598: 84, - 0x599: 84, - 0x59A: 84, - 0x59B: 84, - 0x59C: 84, - 0x59D: 84, - 0x59E: 84, - 0x59F: 84, - 0x5A0: 84, - 0x5A1: 84, - 0x5A2: 84, - 0x5A3: 84, - 0x5A4: 84, - 0x5A5: 84, - 0x5A6: 84, - 0x5A7: 84, - 0x5A8: 84, - 0x5A9: 84, - 0x5AA: 84, - 0x5AB: 84, - 0x5AC: 84, - 0x5AD: 84, - 0x5AE: 84, - 0x5AF: 84, - 0x5B0: 84, - 0x5B1: 84, - 0x5B2: 84, - 0x5B3: 84, - 0x5B4: 84, - 0x5B5: 84, - 0x5B6: 84, - 0x5B7: 84, - 0x5B8: 84, - 0x5B9: 84, - 0x5BA: 84, - 0x5BB: 84, - 0x5BC: 84, - 0x5BD: 84, - 0x5BF: 84, - 0x5C1: 84, - 0x5C2: 84, - 0x5C4: 84, - 0x5C5: 84, - 0x5C7: 84, - 0x610: 84, - 0x611: 84, - 0x612: 84, - 0x613: 84, - 0x614: 84, - 0x615: 84, - 0x616: 84, - 0x617: 84, - 0x618: 84, - 0x619: 84, - 0x61A: 84, - 0x61C: 84, - 0x620: 68, - 0x622: 82, - 0x623: 82, - 0x624: 82, - 0x625: 82, - 0x626: 68, - 0x627: 82, - 0x628: 68, - 0x629: 82, - 0x62A: 68, - 0x62B: 68, - 0x62C: 68, - 0x62D: 68, - 0x62E: 68, - 0x62F: 82, - 0x630: 82, - 0x631: 82, - 0x632: 82, - 0x633: 68, - 0x634: 68, - 0x635: 68, - 0x636: 68, - 0x637: 68, - 0x638: 68, - 0x639: 68, - 0x63A: 68, - 0x63B: 68, - 0x63C: 68, - 0x63D: 68, - 0x63E: 68, - 0x63F: 68, - 0x640: 67, - 0x641: 68, - 0x642: 68, - 0x643: 68, - 0x644: 68, - 0x645: 68, - 0x646: 68, - 0x647: 68, - 0x648: 82, - 0x649: 68, - 0x64A: 68, - 0x64B: 84, - 0x64C: 84, - 0x64D: 84, - 0x64E: 84, - 0x64F: 84, - 0x650: 84, - 0x651: 84, - 0x652: 84, - 0x653: 84, - 0x654: 84, - 0x655: 84, - 0x656: 84, - 0x657: 84, - 0x658: 84, - 0x659: 84, - 0x65A: 84, - 0x65B: 84, - 0x65C: 84, - 0x65D: 84, - 0x65E: 84, - 0x65F: 84, - 0x66E: 68, - 0x66F: 68, - 0x670: 84, - 0x671: 82, - 0x672: 82, - 0x673: 82, - 0x675: 82, - 0x676: 82, - 0x677: 82, - 0x678: 68, - 0x679: 68, - 0x67A: 68, - 0x67B: 68, - 0x67C: 68, - 0x67D: 68, - 0x67E: 68, - 0x67F: 68, - 0x680: 68, - 0x681: 68, - 0x682: 68, - 0x683: 68, - 0x684: 68, - 0x685: 68, - 0x686: 68, - 0x687: 68, - 0x688: 82, - 0x689: 82, - 0x68A: 82, - 0x68B: 82, - 0x68C: 82, - 0x68D: 82, - 0x68E: 82, - 0x68F: 82, - 0x690: 82, - 0x691: 82, - 0x692: 82, - 0x693: 82, - 0x694: 82, - 0x695: 82, - 0x696: 82, - 0x697: 82, - 0x698: 82, - 0x699: 82, - 0x69A: 68, - 0x69B: 68, - 0x69C: 68, - 0x69D: 68, - 0x69E: 68, - 0x69F: 68, - 0x6A0: 68, - 0x6A1: 68, - 0x6A2: 68, - 0x6A3: 68, - 0x6A4: 68, - 0x6A5: 68, - 0x6A6: 68, - 0x6A7: 68, - 0x6A8: 68, - 0x6A9: 68, - 0x6AA: 68, - 0x6AB: 68, - 0x6AC: 68, - 0x6AD: 68, - 0x6AE: 68, - 0x6AF: 68, - 0x6B0: 68, - 0x6B1: 68, - 0x6B2: 68, - 0x6B3: 68, - 0x6B4: 68, - 0x6B5: 68, - 0x6B6: 68, - 0x6B7: 68, - 0x6B8: 68, - 0x6B9: 68, - 0x6BA: 68, - 0x6BB: 68, - 0x6BC: 68, - 0x6BD: 68, - 0x6BE: 68, - 0x6BF: 68, - 0x6C0: 82, - 0x6C1: 68, - 0x6C2: 68, - 0x6C3: 82, - 0x6C4: 82, - 0x6C5: 82, - 0x6C6: 82, - 0x6C7: 82, - 0x6C8: 82, - 0x6C9: 82, - 0x6CA: 82, - 0x6CB: 82, - 0x6CC: 68, - 0x6CD: 82, - 0x6CE: 68, - 0x6CF: 82, - 0x6D0: 68, - 0x6D1: 68, - 0x6D2: 82, - 0x6D3: 82, - 0x6D5: 82, - 0x6D6: 84, - 0x6D7: 84, - 0x6D8: 84, - 0x6D9: 84, - 0x6DA: 84, - 0x6DB: 84, - 0x6DC: 84, - 0x6DF: 84, - 0x6E0: 84, - 0x6E1: 84, - 0x6E2: 84, - 0x6E3: 84, - 0x6E4: 84, - 0x6E7: 84, - 0x6E8: 84, - 0x6EA: 84, - 0x6EB: 84, - 0x6EC: 84, - 0x6ED: 84, - 0x6EE: 82, - 0x6EF: 82, - 0x6FA: 68, - 0x6FB: 68, - 0x6FC: 68, - 0x6FF: 68, - 0x70F: 84, - 0x710: 82, - 0x711: 84, - 0x712: 68, - 0x713: 68, - 0x714: 68, - 0x715: 82, - 0x716: 82, - 0x717: 82, - 0x718: 82, - 0x719: 82, - 0x71A: 68, - 0x71B: 68, - 0x71C: 68, - 0x71D: 68, - 0x71E: 82, - 0x71F: 68, - 0x720: 68, - 0x721: 68, - 0x722: 68, - 0x723: 68, - 0x724: 68, - 0x725: 68, - 0x726: 68, - 0x727: 68, - 0x728: 82, - 0x729: 68, - 0x72A: 82, - 0x72B: 68, - 0x72C: 82, - 0x72D: 68, - 0x72E: 68, - 0x72F: 82, - 0x730: 84, - 0x731: 84, - 0x732: 84, - 0x733: 84, - 0x734: 84, - 0x735: 84, - 0x736: 84, - 0x737: 84, - 0x738: 84, - 0x739: 84, - 0x73A: 84, - 0x73B: 84, - 0x73C: 84, - 0x73D: 84, - 0x73E: 84, - 0x73F: 84, - 0x740: 84, - 0x741: 84, - 0x742: 84, - 0x743: 84, - 0x744: 84, - 0x745: 84, - 0x746: 84, - 0x747: 84, - 0x748: 84, - 0x749: 84, - 0x74A: 84, - 0x74D: 82, - 0x74E: 68, - 0x74F: 68, - 0x750: 68, - 0x751: 68, - 0x752: 68, - 0x753: 68, - 0x754: 68, - 0x755: 68, - 0x756: 68, - 0x757: 68, - 0x758: 68, - 0x759: 82, - 0x75A: 82, - 0x75B: 82, - 0x75C: 68, - 0x75D: 68, - 0x75E: 68, - 0x75F: 68, - 0x760: 68, - 0x761: 68, - 0x762: 68, - 0x763: 68, - 0x764: 68, - 0x765: 68, - 0x766: 68, - 0x767: 68, - 0x768: 68, - 0x769: 68, - 0x76A: 68, - 0x76B: 82, - 0x76C: 82, - 0x76D: 68, - 0x76E: 68, - 0x76F: 68, - 0x770: 68, - 0x771: 82, - 0x772: 68, - 0x773: 82, - 0x774: 82, - 0x775: 68, - 0x776: 68, - 0x777: 68, - 0x778: 82, - 0x779: 82, - 0x77A: 68, - 0x77B: 68, - 0x77C: 68, - 0x77D: 68, - 0x77E: 68, - 0x77F: 68, - 0x7A6: 84, - 0x7A7: 84, - 0x7A8: 84, - 0x7A9: 84, - 0x7AA: 84, - 0x7AB: 84, - 0x7AC: 84, - 0x7AD: 84, - 0x7AE: 84, - 0x7AF: 84, - 0x7B0: 84, - 0x7CA: 68, - 0x7CB: 68, - 0x7CC: 68, - 0x7CD: 68, - 0x7CE: 68, - 0x7CF: 68, - 0x7D0: 68, - 0x7D1: 68, - 0x7D2: 68, - 0x7D3: 68, - 0x7D4: 68, - 0x7D5: 68, - 0x7D6: 68, - 0x7D7: 68, - 0x7D8: 68, - 0x7D9: 68, - 0x7DA: 68, - 0x7DB: 68, - 0x7DC: 68, - 0x7DD: 68, - 0x7DE: 68, - 0x7DF: 68, - 0x7E0: 68, - 0x7E1: 68, - 0x7E2: 68, - 0x7E3: 68, - 0x7E4: 68, - 0x7E5: 68, - 0x7E6: 68, - 0x7E7: 68, - 0x7E8: 68, - 0x7E9: 68, - 0x7EA: 68, - 0x7EB: 84, - 0x7EC: 84, - 0x7ED: 84, - 0x7EE: 84, - 0x7EF: 84, - 0x7F0: 84, - 0x7F1: 84, - 0x7F2: 84, - 0x7F3: 84, - 0x7FA: 67, - 0x7FD: 84, - 0x816: 84, - 0x817: 84, - 0x818: 84, - 0x819: 84, - 0x81B: 84, - 0x81C: 84, - 0x81D: 84, - 0x81E: 84, - 0x81F: 84, - 0x820: 84, - 0x821: 84, - 0x822: 84, - 0x823: 84, - 0x825: 84, - 0x826: 84, - 0x827: 84, - 0x829: 84, - 0x82A: 84, - 0x82B: 84, - 0x82C: 84, - 0x82D: 84, - 0x840: 82, - 0x841: 68, - 0x842: 68, - 0x843: 68, - 0x844: 68, - 0x845: 68, - 0x846: 82, - 0x847: 82, - 0x848: 68, - 0x849: 82, - 0x84A: 68, - 0x84B: 68, - 0x84C: 68, - 0x84D: 68, - 0x84E: 68, - 0x84F: 68, - 0x850: 68, - 0x851: 68, - 0x852: 68, - 0x853: 68, - 0x854: 82, - 0x855: 68, - 0x856: 82, - 0x857: 82, - 0x858: 82, - 0x859: 84, - 0x85A: 84, - 0x85B: 84, - 0x860: 68, - 0x862: 68, - 0x863: 68, - 0x864: 68, - 0x865: 68, - 0x867: 82, - 0x868: 68, - 0x869: 82, - 0x86A: 82, - 0x870: 82, - 0x871: 82, - 0x872: 82, - 0x873: 82, - 0x874: 82, - 0x875: 82, - 0x876: 82, - 0x877: 82, - 0x878: 82, - 0x879: 82, - 0x87A: 82, - 0x87B: 82, - 0x87C: 82, - 0x87D: 82, - 0x87E: 82, - 0x87F: 82, - 0x880: 82, - 0x881: 82, - 0x882: 82, - 0x883: 67, - 0x884: 67, - 0x885: 67, - 0x886: 68, - 0x889: 68, - 0x88A: 68, - 0x88B: 68, - 0x88C: 68, - 0x88D: 68, - 0x88E: 82, - 0x88F: 68, - 0x897: 84, - 0x898: 84, - 0x899: 84, - 0x89A: 84, - 0x89B: 84, - 0x89C: 84, - 0x89D: 84, - 0x89E: 84, - 0x89F: 84, - 0x8A0: 68, - 0x8A1: 68, - 0x8A2: 68, - 0x8A3: 68, - 0x8A4: 68, - 0x8A5: 68, - 0x8A6: 68, - 0x8A7: 68, - 0x8A8: 68, - 0x8A9: 68, - 0x8AA: 82, - 0x8AB: 82, - 0x8AC: 82, - 0x8AE: 82, - 0x8AF: 68, - 0x8B0: 68, - 0x8B1: 82, - 0x8B2: 82, - 0x8B3: 68, - 0x8B4: 68, - 0x8B5: 68, - 0x8B6: 68, - 0x8B7: 68, - 0x8B8: 68, - 0x8B9: 82, - 0x8BA: 68, - 0x8BB: 68, - 0x8BC: 68, - 0x8BD: 68, - 0x8BE: 68, - 0x8BF: 68, - 0x8C0: 68, - 0x8C1: 68, - 0x8C2: 68, - 0x8C3: 68, - 0x8C4: 68, - 0x8C5: 68, - 0x8C6: 68, - 0x8C7: 68, - 0x8C8: 68, - 0x8CA: 84, - 0x8CB: 84, - 0x8CC: 84, - 0x8CD: 84, - 0x8CE: 84, - 0x8CF: 84, - 0x8D0: 84, - 0x8D1: 84, - 0x8D2: 84, - 0x8D3: 84, - 0x8D4: 84, - 0x8D5: 84, - 0x8D6: 84, - 0x8D7: 84, - 0x8D8: 84, - 0x8D9: 84, - 0x8DA: 84, - 0x8DB: 84, - 0x8DC: 84, - 0x8DD: 84, - 0x8DE: 84, - 0x8DF: 84, - 0x8E0: 84, - 0x8E1: 84, - 0x8E3: 84, - 0x8E4: 84, - 0x8E5: 84, - 0x8E6: 84, - 0x8E7: 84, - 0x8E8: 84, - 0x8E9: 84, - 0x8EA: 84, - 0x8EB: 84, - 0x8EC: 84, - 0x8ED: 84, - 0x8EE: 84, - 0x8EF: 84, - 0x8F0: 84, - 0x8F1: 84, - 0x8F2: 84, - 0x8F3: 84, - 0x8F4: 84, - 0x8F5: 84, - 0x8F6: 84, - 0x8F7: 84, - 0x8F8: 84, - 0x8F9: 84, - 0x8FA: 84, - 0x8FB: 84, - 0x8FC: 84, - 0x8FD: 84, - 0x8FE: 84, - 0x8FF: 84, - 0x900: 84, - 0x901: 84, - 0x902: 84, - 0x93A: 84, - 0x93C: 84, - 0x941: 84, - 0x942: 84, - 0x943: 84, - 0x944: 84, - 0x945: 84, - 0x946: 84, - 0x947: 84, - 0x948: 84, - 0x94D: 84, - 0x951: 84, - 0x952: 84, - 0x953: 84, - 0x954: 84, - 0x955: 84, - 0x956: 84, - 0x957: 84, - 0x962: 84, - 0x963: 84, - 0x981: 84, - 0x9BC: 84, - 0x9C1: 84, - 0x9C2: 84, - 0x9C3: 84, - 0x9C4: 84, - 0x9CD: 84, - 0x9E2: 84, - 0x9E3: 84, - 0x9FE: 84, - 0xA01: 84, - 0xA02: 84, - 0xA3C: 84, - 0xA41: 84, - 0xA42: 84, - 0xA47: 84, - 0xA48: 84, - 0xA4B: 84, - 0xA4C: 84, - 0xA4D: 84, - 0xA51: 84, - 0xA70: 84, - 0xA71: 84, - 0xA75: 84, - 0xA81: 84, - 0xA82: 84, - 0xABC: 84, - 0xAC1: 84, - 0xAC2: 84, - 0xAC3: 84, - 0xAC4: 84, - 0xAC5: 84, - 0xAC7: 84, - 0xAC8: 84, - 0xACD: 84, - 0xAE2: 84, - 0xAE3: 84, - 0xAFA: 84, - 0xAFB: 84, - 0xAFC: 84, - 0xAFD: 84, - 0xAFE: 84, - 0xAFF: 84, - 0xB01: 84, - 0xB3C: 84, - 0xB3F: 84, - 0xB41: 84, - 0xB42: 84, - 0xB43: 84, - 0xB44: 84, - 0xB4D: 84, - 0xB55: 84, - 0xB56: 84, - 0xB62: 84, - 0xB63: 84, - 0xB82: 84, - 0xBC0: 84, - 0xBCD: 84, - 0xC00: 84, - 0xC04: 84, - 0xC3C: 84, - 0xC3E: 84, - 0xC3F: 84, - 0xC40: 84, - 0xC46: 84, - 0xC47: 84, - 0xC48: 84, - 0xC4A: 84, - 0xC4B: 84, - 0xC4C: 84, - 0xC4D: 84, - 0xC55: 84, - 0xC56: 84, - 0xC62: 84, - 0xC63: 84, - 0xC81: 84, - 0xCBC: 84, - 0xCBF: 84, - 0xCC6: 84, - 0xCCC: 84, - 0xCCD: 84, - 0xCE2: 84, - 0xCE3: 84, - 0xD00: 84, - 0xD01: 84, - 0xD3B: 84, - 0xD3C: 84, - 0xD41: 84, - 0xD42: 84, - 0xD43: 84, - 0xD44: 84, - 0xD4D: 84, - 0xD62: 84, - 0xD63: 84, - 0xD81: 84, - 0xDCA: 84, - 0xDD2: 84, - 0xDD3: 84, - 0xDD4: 84, - 0xDD6: 84, - 0xE31: 84, - 0xE34: 84, - 0xE35: 84, - 0xE36: 84, - 0xE37: 84, - 0xE38: 84, - 0xE39: 84, - 0xE3A: 84, - 0xE47: 84, - 0xE48: 84, - 0xE49: 84, - 0xE4A: 84, - 0xE4B: 84, - 0xE4C: 84, - 0xE4D: 84, - 0xE4E: 84, - 0xEB1: 84, - 0xEB4: 84, - 0xEB5: 84, - 0xEB6: 84, - 0xEB7: 84, - 0xEB8: 84, - 0xEB9: 84, - 0xEBA: 84, - 0xEBB: 84, - 0xEBC: 84, - 0xEC8: 84, - 0xEC9: 84, - 0xECA: 84, - 0xECB: 84, - 0xECC: 84, - 0xECD: 84, - 0xECE: 84, - 0xF18: 84, - 0xF19: 84, - 0xF35: 84, - 0xF37: 84, - 0xF39: 84, - 0xF71: 84, - 0xF72: 84, - 0xF73: 84, - 0xF74: 84, - 0xF75: 84, - 0xF76: 84, - 0xF77: 84, - 0xF78: 84, - 0xF79: 84, - 0xF7A: 84, - 0xF7B: 84, - 0xF7C: 84, - 0xF7D: 84, - 0xF7E: 84, - 0xF80: 84, - 0xF81: 84, - 0xF82: 84, - 0xF83: 84, - 0xF84: 84, - 0xF86: 84, - 0xF87: 84, - 0xF8D: 84, - 0xF8E: 84, - 0xF8F: 84, - 0xF90: 84, - 0xF91: 84, - 0xF92: 84, - 0xF93: 84, - 0xF94: 84, - 0xF95: 84, - 0xF96: 84, - 0xF97: 84, - 0xF99: 84, - 0xF9A: 84, - 0xF9B: 84, - 0xF9C: 84, - 0xF9D: 84, - 0xF9E: 84, - 0xF9F: 84, - 0xFA0: 84, - 0xFA1: 84, - 0xFA2: 84, - 0xFA3: 84, - 0xFA4: 84, - 0xFA5: 84, - 0xFA6: 84, - 0xFA7: 84, - 0xFA8: 84, - 0xFA9: 84, - 0xFAA: 84, - 0xFAB: 84, - 0xFAC: 84, - 0xFAD: 84, - 0xFAE: 84, - 0xFAF: 84, - 0xFB0: 84, - 0xFB1: 84, - 0xFB2: 84, - 0xFB3: 84, - 0xFB4: 84, - 0xFB5: 84, - 0xFB6: 84, - 0xFB7: 84, - 0xFB8: 84, - 0xFB9: 84, - 0xFBA: 84, - 0xFBB: 84, - 0xFBC: 84, - 0xFC6: 84, - 0x102D: 84, - 0x102E: 84, - 0x102F: 84, - 0x1030: 84, - 0x1032: 84, - 0x1033: 84, - 0x1034: 84, - 0x1035: 84, - 0x1036: 84, - 0x1037: 84, - 0x1039: 84, - 0x103A: 84, - 0x103D: 84, - 0x103E: 84, - 0x1058: 84, - 0x1059: 84, - 0x105E: 84, - 0x105F: 84, - 0x1060: 84, - 0x1071: 84, - 0x1072: 84, - 0x1073: 84, - 0x1074: 84, - 0x1082: 84, - 0x1085: 84, - 0x1086: 84, - 0x108D: 84, - 0x109D: 84, - 0x135D: 84, - 0x135E: 84, - 0x135F: 84, - 0x1712: 84, - 0x1713: 84, - 0x1714: 84, - 0x1732: 84, - 0x1733: 84, - 0x1752: 84, - 0x1753: 84, - 0x1772: 84, - 0x1773: 84, - 0x17B4: 84, - 0x17B5: 84, - 0x17B7: 84, - 0x17B8: 84, - 0x17B9: 84, - 0x17BA: 84, - 0x17BB: 84, - 0x17BC: 84, - 0x17BD: 84, - 0x17C6: 84, - 0x17C9: 84, - 0x17CA: 84, - 0x17CB: 84, - 0x17CC: 84, - 0x17CD: 84, - 0x17CE: 84, - 0x17CF: 84, - 0x17D0: 84, - 0x17D1: 84, - 0x17D2: 84, - 0x17D3: 84, - 0x17DD: 84, - 0x1807: 68, - 0x180A: 67, - 0x180B: 84, - 0x180C: 84, - 0x180D: 84, - 0x180F: 84, - 0x1820: 68, - 0x1821: 68, - 0x1822: 68, - 0x1823: 68, - 0x1824: 68, - 0x1825: 68, - 0x1826: 68, - 0x1827: 68, - 0x1828: 68, - 0x1829: 68, - 0x182A: 68, - 0x182B: 68, - 0x182C: 68, - 0x182D: 68, - 0x182E: 68, - 0x182F: 68, - 0x1830: 68, - 0x1831: 68, - 0x1832: 68, - 0x1833: 68, - 0x1834: 68, - 0x1835: 68, - 0x1836: 68, - 0x1837: 68, - 0x1838: 68, - 0x1839: 68, - 0x183A: 68, - 0x183B: 68, - 0x183C: 68, - 0x183D: 68, - 0x183E: 68, - 0x183F: 68, - 0x1840: 68, - 0x1841: 68, - 0x1842: 68, - 0x1843: 68, - 0x1844: 68, - 0x1845: 68, - 0x1846: 68, - 0x1847: 68, - 0x1848: 68, - 0x1849: 68, - 0x184A: 68, - 0x184B: 68, - 0x184C: 68, - 0x184D: 68, - 0x184E: 68, - 0x184F: 68, - 0x1850: 68, - 0x1851: 68, - 0x1852: 68, - 0x1853: 68, - 0x1854: 68, - 0x1855: 68, - 0x1856: 68, - 0x1857: 68, - 0x1858: 68, - 0x1859: 68, - 0x185A: 68, - 0x185B: 68, - 0x185C: 68, - 0x185D: 68, - 0x185E: 68, - 0x185F: 68, - 0x1860: 68, - 0x1861: 68, - 0x1862: 68, - 0x1863: 68, - 0x1864: 68, - 0x1865: 68, - 0x1866: 68, - 0x1867: 68, - 0x1868: 68, - 0x1869: 68, - 0x186A: 68, - 0x186B: 68, - 0x186C: 68, - 0x186D: 68, - 0x186E: 68, - 0x186F: 68, - 0x1870: 68, - 0x1871: 68, - 0x1872: 68, - 0x1873: 68, - 0x1874: 68, - 0x1875: 68, - 0x1876: 68, - 0x1877: 68, - 0x1878: 68, - 0x1885: 84, - 0x1886: 84, - 0x1887: 68, - 0x1888: 68, - 0x1889: 68, - 0x188A: 68, - 0x188B: 68, - 0x188C: 68, - 0x188D: 68, - 0x188E: 68, - 0x188F: 68, - 0x1890: 68, - 0x1891: 68, - 0x1892: 68, - 0x1893: 68, - 0x1894: 68, - 0x1895: 68, - 0x1896: 68, - 0x1897: 68, - 0x1898: 68, - 0x1899: 68, - 0x189A: 68, - 0x189B: 68, - 0x189C: 68, - 0x189D: 68, - 0x189E: 68, - 0x189F: 68, - 0x18A0: 68, - 0x18A1: 68, - 0x18A2: 68, - 0x18A3: 68, - 0x18A4: 68, - 0x18A5: 68, - 0x18A6: 68, - 0x18A7: 68, - 0x18A8: 68, - 0x18A9: 84, - 0x18AA: 68, - 0x1920: 84, - 0x1921: 84, - 0x1922: 84, - 0x1927: 84, - 0x1928: 84, - 0x1932: 84, - 0x1939: 84, - 0x193A: 84, - 0x193B: 84, - 0x1A17: 84, - 0x1A18: 84, - 0x1A1B: 84, - 0x1A56: 84, - 0x1A58: 84, - 0x1A59: 84, - 0x1A5A: 84, - 0x1A5B: 84, - 0x1A5C: 84, - 0x1A5D: 84, - 0x1A5E: 84, - 0x1A60: 84, - 0x1A62: 84, - 0x1A65: 84, - 0x1A66: 84, - 0x1A67: 84, - 0x1A68: 84, - 0x1A69: 84, - 0x1A6A: 84, - 0x1A6B: 84, - 0x1A6C: 84, - 0x1A73: 84, - 0x1A74: 84, - 0x1A75: 84, - 0x1A76: 84, - 0x1A77: 84, - 0x1A78: 84, - 0x1A79: 84, - 0x1A7A: 84, - 0x1A7B: 84, - 0x1A7C: 84, - 0x1A7F: 84, - 0x1AB0: 84, - 0x1AB1: 84, - 0x1AB2: 84, - 0x1AB3: 84, - 0x1AB4: 84, - 0x1AB5: 84, - 0x1AB6: 84, - 0x1AB7: 84, - 0x1AB8: 84, - 0x1AB9: 84, - 0x1ABA: 84, - 0x1ABB: 84, - 0x1ABC: 84, - 0x1ABD: 84, - 0x1ABE: 84, - 0x1ABF: 84, - 0x1AC0: 84, - 0x1AC1: 84, - 0x1AC2: 84, - 0x1AC3: 84, - 0x1AC4: 84, - 0x1AC5: 84, - 0x1AC6: 84, - 0x1AC7: 84, - 0x1AC8: 84, - 0x1AC9: 84, - 0x1ACA: 84, - 0x1ACB: 84, - 0x1ACC: 84, - 0x1ACD: 84, - 0x1ACE: 84, - 0x1ACF: 84, - 0x1AD0: 84, - 0x1AD1: 84, - 0x1AD2: 84, - 0x1AD3: 84, - 0x1AD4: 84, - 0x1AD5: 84, - 0x1AD6: 84, - 0x1AD7: 84, - 0x1AD8: 84, - 0x1AD9: 84, - 0x1ADA: 84, - 0x1ADB: 84, - 0x1ADC: 84, - 0x1ADD: 84, - 0x1AE0: 84, - 0x1AE1: 84, - 0x1AE2: 84, - 0x1AE3: 84, - 0x1AE4: 84, - 0x1AE5: 84, - 0x1AE6: 84, - 0x1AE7: 84, - 0x1AE8: 84, - 0x1AE9: 84, - 0x1AEA: 84, - 0x1AEB: 84, - 0x1B00: 84, - 0x1B01: 84, - 0x1B02: 84, - 0x1B03: 84, - 0x1B34: 84, - 0x1B36: 84, - 0x1B37: 84, - 0x1B38: 84, - 0x1B39: 84, - 0x1B3A: 84, - 0x1B3C: 84, - 0x1B42: 84, - 0x1B6B: 84, - 0x1B6C: 84, - 0x1B6D: 84, - 0x1B6E: 84, - 0x1B6F: 84, - 0x1B70: 84, - 0x1B71: 84, - 0x1B72: 84, - 0x1B73: 84, - 0x1B80: 84, - 0x1B81: 84, - 0x1BA2: 84, - 0x1BA3: 84, - 0x1BA4: 84, - 0x1BA5: 84, - 0x1BA8: 84, - 0x1BA9: 84, - 0x1BAB: 84, - 0x1BAC: 84, - 0x1BAD: 84, - 0x1BE6: 84, - 0x1BE8: 84, - 0x1BE9: 84, - 0x1BED: 84, - 0x1BEF: 84, - 0x1BF0: 84, - 0x1BF1: 84, - 0x1C2C: 84, - 0x1C2D: 84, - 0x1C2E: 84, - 0x1C2F: 84, - 0x1C30: 84, - 0x1C31: 84, - 0x1C32: 84, - 0x1C33: 84, - 0x1C36: 84, - 0x1C37: 84, - 0x1CD0: 84, - 0x1CD1: 84, - 0x1CD2: 84, - 0x1CD4: 84, - 0x1CD5: 84, - 0x1CD6: 84, - 0x1CD7: 84, - 0x1CD8: 84, - 0x1CD9: 84, - 0x1CDA: 84, - 0x1CDB: 84, - 0x1CDC: 84, - 0x1CDD: 84, - 0x1CDE: 84, - 0x1CDF: 84, - 0x1CE0: 84, - 0x1CE2: 84, - 0x1CE3: 84, - 0x1CE4: 84, - 0x1CE5: 84, - 0x1CE6: 84, - 0x1CE7: 84, - 0x1CE8: 84, - 0x1CED: 84, - 0x1CF4: 84, - 0x1CF8: 84, - 0x1CF9: 84, - 0x1DC0: 84, - 0x1DC1: 84, - 0x1DC2: 84, - 0x1DC3: 84, - 0x1DC4: 84, - 0x1DC5: 84, - 0x1DC6: 84, - 0x1DC7: 84, - 0x1DC8: 84, - 0x1DC9: 84, - 0x1DCA: 84, - 0x1DCB: 84, - 0x1DCC: 84, - 0x1DCD: 84, - 0x1DCE: 84, - 0x1DCF: 84, - 0x1DD0: 84, - 0x1DD1: 84, - 0x1DD2: 84, - 0x1DD3: 84, - 0x1DD4: 84, - 0x1DD5: 84, - 0x1DD6: 84, - 0x1DD7: 84, - 0x1DD8: 84, - 0x1DD9: 84, - 0x1DDA: 84, - 0x1DDB: 84, - 0x1DDC: 84, - 0x1DDD: 84, - 0x1DDE: 84, - 0x1DDF: 84, - 0x1DE0: 84, - 0x1DE1: 84, - 0x1DE2: 84, - 0x1DE3: 84, - 0x1DE4: 84, - 0x1DE5: 84, - 0x1DE6: 84, - 0x1DE7: 84, - 0x1DE8: 84, - 0x1DE9: 84, - 0x1DEA: 84, - 0x1DEB: 84, - 0x1DEC: 84, - 0x1DED: 84, - 0x1DEE: 84, - 0x1DEF: 84, - 0x1DF0: 84, - 0x1DF1: 84, - 0x1DF2: 84, - 0x1DF3: 84, - 0x1DF4: 84, - 0x1DF5: 84, - 0x1DF6: 84, - 0x1DF7: 84, - 0x1DF8: 84, - 0x1DF9: 84, - 0x1DFA: 84, - 0x1DFB: 84, - 0x1DFC: 84, - 0x1DFD: 84, - 0x1DFE: 84, - 0x1DFF: 84, - 0x200B: 84, - 0x200D: 67, - 0x200E: 84, - 0x200F: 84, - 0x202A: 84, - 0x202B: 84, - 0x202C: 84, - 0x202D: 84, - 0x202E: 84, - 0x2060: 84, - 0x2061: 84, - 0x2062: 84, - 0x2063: 84, - 0x2064: 84, - 0x206A: 84, - 0x206B: 84, - 0x206C: 84, - 0x206D: 84, - 0x206E: 84, - 0x206F: 84, - 0x20D0: 84, - 0x20D1: 84, - 0x20D2: 84, - 0x20D3: 84, - 0x20D4: 84, - 0x20D5: 84, - 0x20D6: 84, - 0x20D7: 84, - 0x20D8: 84, - 0x20D9: 84, - 0x20DA: 84, - 0x20DB: 84, - 0x20DC: 84, - 0x20DD: 84, - 0x20DE: 84, - 0x20DF: 84, - 0x20E0: 84, - 0x20E1: 84, - 0x20E2: 84, - 0x20E3: 84, - 0x20E4: 84, - 0x20E5: 84, - 0x20E6: 84, - 0x20E7: 84, - 0x20E8: 84, - 0x20E9: 84, - 0x20EA: 84, - 0x20EB: 84, - 0x20EC: 84, - 0x20ED: 84, - 0x20EE: 84, - 0x20EF: 84, - 0x20F0: 84, - 0x2CEF: 84, - 0x2CF0: 84, - 0x2CF1: 84, - 0x2D7F: 84, - 0x2DE0: 84, - 0x2DE1: 84, - 0x2DE2: 84, - 0x2DE3: 84, - 0x2DE4: 84, - 0x2DE5: 84, - 0x2DE6: 84, - 0x2DE7: 84, - 0x2DE8: 84, - 0x2DE9: 84, - 0x2DEA: 84, - 0x2DEB: 84, - 0x2DEC: 84, - 0x2DED: 84, - 0x2DEE: 84, - 0x2DEF: 84, - 0x2DF0: 84, - 0x2DF1: 84, - 0x2DF2: 84, - 0x2DF3: 84, - 0x2DF4: 84, - 0x2DF5: 84, - 0x2DF6: 84, - 0x2DF7: 84, - 0x2DF8: 84, - 0x2DF9: 84, - 0x2DFA: 84, - 0x2DFB: 84, - 0x2DFC: 84, - 0x2DFD: 84, - 0x2DFE: 84, - 0x2DFF: 84, - 0x302A: 84, - 0x302B: 84, - 0x302C: 84, - 0x302D: 84, - 0x3099: 84, - 0x309A: 84, - 0xA66F: 84, - 0xA670: 84, - 0xA671: 84, - 0xA672: 84, - 0xA674: 84, - 0xA675: 84, - 0xA676: 84, - 0xA677: 84, - 0xA678: 84, - 0xA679: 84, - 0xA67A: 84, - 0xA67B: 84, - 0xA67C: 84, - 0xA67D: 84, - 0xA69E: 84, - 0xA69F: 84, - 0xA6F0: 84, - 0xA6F1: 84, - 0xA802: 84, - 0xA806: 84, - 0xA80B: 84, - 0xA825: 84, - 0xA826: 84, - 0xA82C: 84, - 0xA840: 68, - 0xA841: 68, - 0xA842: 68, - 0xA843: 68, - 0xA844: 68, - 0xA845: 68, - 0xA846: 68, - 0xA847: 68, - 0xA848: 68, - 0xA849: 68, - 0xA84A: 68, - 0xA84B: 68, - 0xA84C: 68, - 0xA84D: 68, - 0xA84E: 68, - 0xA84F: 68, - 0xA850: 68, - 0xA851: 68, - 0xA852: 68, - 0xA853: 68, - 0xA854: 68, - 0xA855: 68, - 0xA856: 68, - 0xA857: 68, - 0xA858: 68, - 0xA859: 68, - 0xA85A: 68, - 0xA85B: 68, - 0xA85C: 68, - 0xA85D: 68, - 0xA85E: 68, - 0xA85F: 68, - 0xA860: 68, - 0xA861: 68, - 0xA862: 68, - 0xA863: 68, - 0xA864: 68, - 0xA865: 68, - 0xA866: 68, - 0xA867: 68, - 0xA868: 68, - 0xA869: 68, - 0xA86A: 68, - 0xA86B: 68, - 0xA86C: 68, - 0xA86D: 68, - 0xA86E: 68, - 0xA86F: 68, - 0xA870: 68, - 0xA871: 68, - 0xA872: 76, - 0xA8C4: 84, - 0xA8C5: 84, - 0xA8E0: 84, - 0xA8E1: 84, - 0xA8E2: 84, - 0xA8E3: 84, - 0xA8E4: 84, - 0xA8E5: 84, - 0xA8E6: 84, - 0xA8E7: 84, - 0xA8E8: 84, - 0xA8E9: 84, - 0xA8EA: 84, - 0xA8EB: 84, - 0xA8EC: 84, - 0xA8ED: 84, - 0xA8EE: 84, - 0xA8EF: 84, - 0xA8F0: 84, - 0xA8F1: 84, - 0xA8FF: 84, - 0xA926: 84, - 0xA927: 84, - 0xA928: 84, - 0xA929: 84, - 0xA92A: 84, - 0xA92B: 84, - 0xA92C: 84, - 0xA92D: 84, - 0xA947: 84, - 0xA948: 84, - 0xA949: 84, - 0xA94A: 84, - 0xA94B: 84, - 0xA94C: 84, - 0xA94D: 84, - 0xA94E: 84, - 0xA94F: 84, - 0xA950: 84, - 0xA951: 84, - 0xA980: 84, - 0xA981: 84, - 0xA982: 84, - 0xA9B3: 84, - 0xA9B6: 84, - 0xA9B7: 84, - 0xA9B8: 84, - 0xA9B9: 84, - 0xA9BC: 84, - 0xA9BD: 84, - 0xA9E5: 84, - 0xAA29: 84, - 0xAA2A: 84, - 0xAA2B: 84, - 0xAA2C: 84, - 0xAA2D: 84, - 0xAA2E: 84, - 0xAA31: 84, - 0xAA32: 84, - 0xAA35: 84, - 0xAA36: 84, - 0xAA43: 84, - 0xAA4C: 84, - 0xAA7C: 84, - 0xAAB0: 84, - 0xAAB2: 84, - 0xAAB3: 84, - 0xAAB4: 84, - 0xAAB7: 84, - 0xAAB8: 84, - 0xAABE: 84, - 0xAABF: 84, - 0xAAC1: 84, - 0xAAEC: 84, - 0xAAED: 84, - 0xAAF6: 84, - 0xABE5: 84, - 0xABE8: 84, - 0xABED: 84, - 0xFB1E: 84, - 0xFE00: 84, - 0xFE01: 84, - 0xFE02: 84, - 0xFE03: 84, - 0xFE04: 84, - 0xFE05: 84, - 0xFE06: 84, - 0xFE07: 84, - 0xFE08: 84, - 0xFE09: 84, - 0xFE0A: 84, - 0xFE0B: 84, - 0xFE0C: 84, - 0xFE0D: 84, - 0xFE0E: 84, - 0xFE0F: 84, - 0xFE20: 84, - 0xFE21: 84, - 0xFE22: 84, - 0xFE23: 84, - 0xFE24: 84, - 0xFE25: 84, - 0xFE26: 84, - 0xFE27: 84, - 0xFE28: 84, - 0xFE29: 84, - 0xFE2A: 84, - 0xFE2B: 84, - 0xFE2C: 84, - 0xFE2D: 84, - 0xFE2E: 84, - 0xFE2F: 84, - 0xFEFF: 84, - 0xFFF9: 84, - 0xFFFA: 84, - 0xFFFB: 84, - 0x101FD: 84, - 0x102E0: 84, - 0x10376: 84, - 0x10377: 84, - 0x10378: 84, - 0x10379: 84, - 0x1037A: 84, - 0x10A01: 84, - 0x10A02: 84, - 0x10A03: 84, - 0x10A05: 84, - 0x10A06: 84, - 0x10A0C: 84, - 0x10A0D: 84, - 0x10A0E: 84, - 0x10A0F: 84, - 0x10A38: 84, - 0x10A39: 84, - 0x10A3A: 84, - 0x10A3F: 84, - 0x10AC0: 68, - 0x10AC1: 68, - 0x10AC2: 68, - 0x10AC3: 68, - 0x10AC4: 68, - 0x10AC5: 82, - 0x10AC7: 82, - 0x10AC9: 82, - 0x10ACA: 82, - 0x10ACD: 76, - 0x10ACE: 82, - 0x10ACF: 82, - 0x10AD0: 82, - 0x10AD1: 82, - 0x10AD2: 82, - 0x10AD3: 68, - 0x10AD4: 68, - 0x10AD5: 68, - 0x10AD6: 68, - 0x10AD7: 76, - 0x10AD8: 68, - 0x10AD9: 68, - 0x10ADA: 68, - 0x10ADB: 68, - 0x10ADC: 68, - 0x10ADD: 82, - 0x10ADE: 68, - 0x10ADF: 68, - 0x10AE0: 68, - 0x10AE1: 82, - 0x10AE4: 82, - 0x10AE5: 84, - 0x10AE6: 84, - 0x10AEB: 68, - 0x10AEC: 68, - 0x10AED: 68, - 0x10AEE: 68, - 0x10AEF: 82, - 0x10B80: 68, - 0x10B81: 82, - 0x10B82: 68, - 0x10B83: 82, - 0x10B84: 82, - 0x10B85: 82, - 0x10B86: 68, - 0x10B87: 68, - 0x10B88: 68, - 0x10B89: 82, - 0x10B8A: 68, - 0x10B8B: 68, - 0x10B8C: 82, - 0x10B8D: 68, - 0x10B8E: 82, - 0x10B8F: 82, - 0x10B90: 68, - 0x10B91: 82, - 0x10BA9: 82, - 0x10BAA: 82, - 0x10BAB: 82, - 0x10BAC: 82, - 0x10BAD: 68, - 0x10BAE: 68, - 0x10D00: 76, - 0x10D01: 68, - 0x10D02: 68, - 0x10D03: 68, - 0x10D04: 68, - 0x10D05: 68, - 0x10D06: 68, - 0x10D07: 68, - 0x10D08: 68, - 0x10D09: 68, - 0x10D0A: 68, - 0x10D0B: 68, - 0x10D0C: 68, - 0x10D0D: 68, - 0x10D0E: 68, - 0x10D0F: 68, - 0x10D10: 68, - 0x10D11: 68, - 0x10D12: 68, - 0x10D13: 68, - 0x10D14: 68, - 0x10D15: 68, - 0x10D16: 68, - 0x10D17: 68, - 0x10D18: 68, - 0x10D19: 68, - 0x10D1A: 68, - 0x10D1B: 68, - 0x10D1C: 68, - 0x10D1D: 68, - 0x10D1E: 68, - 0x10D1F: 68, - 0x10D20: 68, - 0x10D21: 68, - 0x10D22: 82, - 0x10D23: 68, - 0x10D24: 84, - 0x10D25: 84, - 0x10D26: 84, - 0x10D27: 84, - 0x10D69: 84, - 0x10D6A: 84, - 0x10D6B: 84, - 0x10D6C: 84, - 0x10D6D: 84, - 0x10EAB: 84, - 0x10EAC: 84, - 0x10EC2: 82, - 0x10EC3: 68, - 0x10EC4: 68, - 0x10EC6: 68, - 0x10EC7: 68, - 0x10EFA: 84, - 0x10EFB: 84, - 0x10EFC: 84, - 0x10EFD: 84, - 0x10EFE: 84, - 0x10EFF: 84, - 0x10F30: 68, - 0x10F31: 68, - 0x10F32: 68, - 0x10F33: 82, - 0x10F34: 68, - 0x10F35: 68, - 0x10F36: 68, - 0x10F37: 68, - 0x10F38: 68, - 0x10F39: 68, - 0x10F3A: 68, - 0x10F3B: 68, - 0x10F3C: 68, - 0x10F3D: 68, - 0x10F3E: 68, - 0x10F3F: 68, - 0x10F40: 68, - 0x10F41: 68, - 0x10F42: 68, - 0x10F43: 68, - 0x10F44: 68, - 0x10F46: 84, - 0x10F47: 84, - 0x10F48: 84, - 0x10F49: 84, - 0x10F4A: 84, - 0x10F4B: 84, - 0x10F4C: 84, - 0x10F4D: 84, - 0x10F4E: 84, - 0x10F4F: 84, - 0x10F50: 84, - 0x10F51: 68, - 0x10F52: 68, - 0x10F53: 68, - 0x10F54: 82, - 0x10F70: 68, - 0x10F71: 68, - 0x10F72: 68, - 0x10F73: 68, - 0x10F74: 82, - 0x10F75: 82, - 0x10F76: 68, - 0x10F77: 68, - 0x10F78: 68, - 0x10F79: 68, - 0x10F7A: 68, - 0x10F7B: 68, - 0x10F7C: 68, - 0x10F7D: 68, - 0x10F7E: 68, - 0x10F7F: 68, - 0x10F80: 68, - 0x10F81: 68, - 0x10F82: 84, - 0x10F83: 84, - 0x10F84: 84, - 0x10F85: 84, - 0x10FB0: 68, - 0x10FB2: 68, - 0x10FB3: 68, - 0x10FB4: 82, - 0x10FB5: 82, - 0x10FB6: 82, - 0x10FB8: 68, - 0x10FB9: 82, - 0x10FBA: 82, - 0x10FBB: 68, - 0x10FBC: 68, - 0x10FBD: 82, - 0x10FBE: 68, - 0x10FBF: 68, - 0x10FC1: 68, - 0x10FC2: 82, - 0x10FC3: 82, - 0x10FC4: 68, - 0x10FC9: 82, - 0x10FCA: 68, - 0x10FCB: 76, - 0x11001: 84, - 0x11038: 84, - 0x11039: 84, - 0x1103A: 84, - 0x1103B: 84, - 0x1103C: 84, - 0x1103D: 84, - 0x1103E: 84, - 0x1103F: 84, - 0x11040: 84, - 0x11041: 84, - 0x11042: 84, - 0x11043: 84, - 0x11044: 84, - 0x11045: 84, - 0x11046: 84, - 0x11070: 84, - 0x11073: 84, - 0x11074: 84, - 0x1107F: 84, - 0x11080: 84, - 0x11081: 84, - 0x110B3: 84, - 0x110B4: 84, - 0x110B5: 84, - 0x110B6: 84, - 0x110B9: 84, - 0x110BA: 84, - 0x110C2: 84, - 0x11100: 84, - 0x11101: 84, - 0x11102: 84, - 0x11127: 84, - 0x11128: 84, - 0x11129: 84, - 0x1112A: 84, - 0x1112B: 84, - 0x1112D: 84, - 0x1112E: 84, - 0x1112F: 84, - 0x11130: 84, - 0x11131: 84, - 0x11132: 84, - 0x11133: 84, - 0x11134: 84, - 0x11173: 84, - 0x11180: 84, - 0x11181: 84, - 0x111B6: 84, - 0x111B7: 84, - 0x111B8: 84, - 0x111B9: 84, - 0x111BA: 84, - 0x111BB: 84, - 0x111BC: 84, - 0x111BD: 84, - 0x111BE: 84, - 0x111C9: 84, - 0x111CA: 84, - 0x111CB: 84, - 0x111CC: 84, - 0x111CF: 84, - 0x1122F: 84, - 0x11230: 84, - 0x11231: 84, - 0x11234: 84, - 0x11236: 84, - 0x11237: 84, - 0x1123E: 84, - 0x11241: 84, - 0x112DF: 84, - 0x112E3: 84, - 0x112E4: 84, - 0x112E5: 84, - 0x112E6: 84, - 0x112E7: 84, - 0x112E8: 84, - 0x112E9: 84, - 0x112EA: 84, - 0x11300: 84, - 0x11301: 84, - 0x1133B: 84, - 0x1133C: 84, - 0x11340: 84, - 0x11366: 84, - 0x11367: 84, - 0x11368: 84, - 0x11369: 84, - 0x1136A: 84, - 0x1136B: 84, - 0x1136C: 84, - 0x11370: 84, - 0x11371: 84, - 0x11372: 84, - 0x11373: 84, - 0x11374: 84, - 0x113BB: 84, - 0x113BC: 84, - 0x113BD: 84, - 0x113BE: 84, - 0x113BF: 84, - 0x113C0: 84, - 0x113CE: 84, - 0x113D0: 84, - 0x113D2: 84, - 0x113E1: 84, - 0x113E2: 84, - 0x11438: 84, - 0x11439: 84, - 0x1143A: 84, - 0x1143B: 84, - 0x1143C: 84, - 0x1143D: 84, - 0x1143E: 84, - 0x1143F: 84, - 0x11442: 84, - 0x11443: 84, - 0x11444: 84, - 0x11446: 84, - 0x1145E: 84, - 0x114B3: 84, - 0x114B4: 84, - 0x114B5: 84, - 0x114B6: 84, - 0x114B7: 84, - 0x114B8: 84, - 0x114BA: 84, - 0x114BF: 84, - 0x114C0: 84, - 0x114C2: 84, - 0x114C3: 84, - 0x115B2: 84, - 0x115B3: 84, - 0x115B4: 84, - 0x115B5: 84, - 0x115BC: 84, - 0x115BD: 84, - 0x115BF: 84, - 0x115C0: 84, - 0x115DC: 84, - 0x115DD: 84, - 0x11633: 84, - 0x11634: 84, - 0x11635: 84, - 0x11636: 84, - 0x11637: 84, - 0x11638: 84, - 0x11639: 84, - 0x1163A: 84, - 0x1163D: 84, - 0x1163F: 84, - 0x11640: 84, - 0x116AB: 84, - 0x116AD: 84, - 0x116B0: 84, - 0x116B1: 84, - 0x116B2: 84, - 0x116B3: 84, - 0x116B4: 84, - 0x116B5: 84, - 0x116B7: 84, - 0x1171D: 84, - 0x1171F: 84, - 0x11722: 84, - 0x11723: 84, - 0x11724: 84, - 0x11725: 84, - 0x11727: 84, - 0x11728: 84, - 0x11729: 84, - 0x1172A: 84, - 0x1172B: 84, - 0x1182F: 84, - 0x11830: 84, - 0x11831: 84, - 0x11832: 84, - 0x11833: 84, - 0x11834: 84, - 0x11835: 84, - 0x11836: 84, - 0x11837: 84, - 0x11839: 84, - 0x1183A: 84, - 0x1193B: 84, - 0x1193C: 84, - 0x1193E: 84, - 0x11943: 84, - 0x119D4: 84, - 0x119D5: 84, - 0x119D6: 84, - 0x119D7: 84, - 0x119DA: 84, - 0x119DB: 84, - 0x119E0: 84, - 0x11A01: 84, - 0x11A02: 84, - 0x11A03: 84, - 0x11A04: 84, - 0x11A05: 84, - 0x11A06: 84, - 0x11A07: 84, - 0x11A08: 84, - 0x11A09: 84, - 0x11A0A: 84, - 0x11A33: 84, - 0x11A34: 84, - 0x11A35: 84, - 0x11A36: 84, - 0x11A37: 84, - 0x11A38: 84, - 0x11A3B: 84, - 0x11A3C: 84, - 0x11A3D: 84, - 0x11A3E: 84, - 0x11A47: 84, - 0x11A51: 84, - 0x11A52: 84, - 0x11A53: 84, - 0x11A54: 84, - 0x11A55: 84, - 0x11A56: 84, - 0x11A59: 84, - 0x11A5A: 84, - 0x11A5B: 84, - 0x11A8A: 84, - 0x11A8B: 84, - 0x11A8C: 84, - 0x11A8D: 84, - 0x11A8E: 84, - 0x11A8F: 84, - 0x11A90: 84, - 0x11A91: 84, - 0x11A92: 84, - 0x11A93: 84, - 0x11A94: 84, - 0x11A95: 84, - 0x11A96: 84, - 0x11A98: 84, - 0x11A99: 84, - 0x11B60: 84, - 0x11B62: 84, - 0x11B63: 84, - 0x11B64: 84, - 0x11B66: 84, - 0x11C30: 84, - 0x11C31: 84, - 0x11C32: 84, - 0x11C33: 84, - 0x11C34: 84, - 0x11C35: 84, - 0x11C36: 84, - 0x11C38: 84, - 0x11C39: 84, - 0x11C3A: 84, - 0x11C3B: 84, - 0x11C3C: 84, - 0x11C3D: 84, - 0x11C3F: 84, - 0x11C92: 84, - 0x11C93: 84, - 0x11C94: 84, - 0x11C95: 84, - 0x11C96: 84, - 0x11C97: 84, - 0x11C98: 84, - 0x11C99: 84, - 0x11C9A: 84, - 0x11C9B: 84, - 0x11C9C: 84, - 0x11C9D: 84, - 0x11C9E: 84, - 0x11C9F: 84, - 0x11CA0: 84, - 0x11CA1: 84, - 0x11CA2: 84, - 0x11CA3: 84, - 0x11CA4: 84, - 0x11CA5: 84, - 0x11CA6: 84, - 0x11CA7: 84, - 0x11CAA: 84, - 0x11CAB: 84, - 0x11CAC: 84, - 0x11CAD: 84, - 0x11CAE: 84, - 0x11CAF: 84, - 0x11CB0: 84, - 0x11CB2: 84, - 0x11CB3: 84, - 0x11CB5: 84, - 0x11CB6: 84, - 0x11D31: 84, - 0x11D32: 84, - 0x11D33: 84, - 0x11D34: 84, - 0x11D35: 84, - 0x11D36: 84, - 0x11D3A: 84, - 0x11D3C: 84, - 0x11D3D: 84, - 0x11D3F: 84, - 0x11D40: 84, - 0x11D41: 84, - 0x11D42: 84, - 0x11D43: 84, - 0x11D44: 84, - 0x11D45: 84, - 0x11D47: 84, - 0x11D90: 84, - 0x11D91: 84, - 0x11D95: 84, - 0x11D97: 84, - 0x11EF3: 84, - 0x11EF4: 84, - 0x11F00: 84, - 0x11F01: 84, - 0x11F36: 84, - 0x11F37: 84, - 0x11F38: 84, - 0x11F39: 84, - 0x11F3A: 84, - 0x11F40: 84, - 0x11F42: 84, - 0x11F5A: 84, - 0x13430: 84, - 0x13431: 84, - 0x13432: 84, - 0x13433: 84, - 0x13434: 84, - 0x13435: 84, - 0x13436: 84, - 0x13437: 84, - 0x13438: 84, - 0x13439: 84, - 0x1343A: 84, - 0x1343B: 84, - 0x1343C: 84, - 0x1343D: 84, - 0x1343E: 84, - 0x1343F: 84, - 0x13440: 84, - 0x13447: 84, - 0x13448: 84, - 0x13449: 84, - 0x1344A: 84, - 0x1344B: 84, - 0x1344C: 84, - 0x1344D: 84, - 0x1344E: 84, - 0x1344F: 84, - 0x13450: 84, - 0x13451: 84, - 0x13452: 84, - 0x13453: 84, - 0x13454: 84, - 0x13455: 84, - 0x1611E: 84, - 0x1611F: 84, - 0x16120: 84, - 0x16121: 84, - 0x16122: 84, - 0x16123: 84, - 0x16124: 84, - 0x16125: 84, - 0x16126: 84, - 0x16127: 84, - 0x16128: 84, - 0x16129: 84, - 0x1612D: 84, - 0x1612E: 84, - 0x1612F: 84, - 0x16AF0: 84, - 0x16AF1: 84, - 0x16AF2: 84, - 0x16AF3: 84, - 0x16AF4: 84, - 0x16B30: 84, - 0x16B31: 84, - 0x16B32: 84, - 0x16B33: 84, - 0x16B34: 84, - 0x16B35: 84, - 0x16B36: 84, - 0x16F4F: 84, - 0x16F8F: 84, - 0x16F90: 84, - 0x16F91: 84, - 0x16F92: 84, - 0x16FE4: 84, - 0x1BC9D: 84, - 0x1BC9E: 84, - 0x1BCA0: 84, - 0x1BCA1: 84, - 0x1BCA2: 84, - 0x1BCA3: 84, - 0x1CF00: 84, - 0x1CF01: 84, - 0x1CF02: 84, - 0x1CF03: 84, - 0x1CF04: 84, - 0x1CF05: 84, - 0x1CF06: 84, - 0x1CF07: 84, - 0x1CF08: 84, - 0x1CF09: 84, - 0x1CF0A: 84, - 0x1CF0B: 84, - 0x1CF0C: 84, - 0x1CF0D: 84, - 0x1CF0E: 84, - 0x1CF0F: 84, - 0x1CF10: 84, - 0x1CF11: 84, - 0x1CF12: 84, - 0x1CF13: 84, - 0x1CF14: 84, - 0x1CF15: 84, - 0x1CF16: 84, - 0x1CF17: 84, - 0x1CF18: 84, - 0x1CF19: 84, - 0x1CF1A: 84, - 0x1CF1B: 84, - 0x1CF1C: 84, - 0x1CF1D: 84, - 0x1CF1E: 84, - 0x1CF1F: 84, - 0x1CF20: 84, - 0x1CF21: 84, - 0x1CF22: 84, - 0x1CF23: 84, - 0x1CF24: 84, - 0x1CF25: 84, - 0x1CF26: 84, - 0x1CF27: 84, - 0x1CF28: 84, - 0x1CF29: 84, - 0x1CF2A: 84, - 0x1CF2B: 84, - 0x1CF2C: 84, - 0x1CF2D: 84, - 0x1CF30: 84, - 0x1CF31: 84, - 0x1CF32: 84, - 0x1CF33: 84, - 0x1CF34: 84, - 0x1CF35: 84, - 0x1CF36: 84, - 0x1CF37: 84, - 0x1CF38: 84, - 0x1CF39: 84, - 0x1CF3A: 84, - 0x1CF3B: 84, - 0x1CF3C: 84, - 0x1CF3D: 84, - 0x1CF3E: 84, - 0x1CF3F: 84, - 0x1CF40: 84, - 0x1CF41: 84, - 0x1CF42: 84, - 0x1CF43: 84, - 0x1CF44: 84, - 0x1CF45: 84, - 0x1CF46: 84, - 0x1D167: 84, - 0x1D168: 84, - 0x1D169: 84, - 0x1D173: 84, - 0x1D174: 84, - 0x1D175: 84, - 0x1D176: 84, - 0x1D177: 84, - 0x1D178: 84, - 0x1D179: 84, - 0x1D17A: 84, - 0x1D17B: 84, - 0x1D17C: 84, - 0x1D17D: 84, - 0x1D17E: 84, - 0x1D17F: 84, - 0x1D180: 84, - 0x1D181: 84, - 0x1D182: 84, - 0x1D185: 84, - 0x1D186: 84, - 0x1D187: 84, - 0x1D188: 84, - 0x1D189: 84, - 0x1D18A: 84, - 0x1D18B: 84, - 0x1D1AA: 84, - 0x1D1AB: 84, - 0x1D1AC: 84, - 0x1D1AD: 84, - 0x1D242: 84, - 0x1D243: 84, - 0x1D244: 84, - 0x1DA00: 84, - 0x1DA01: 84, - 0x1DA02: 84, - 0x1DA03: 84, - 0x1DA04: 84, - 0x1DA05: 84, - 0x1DA06: 84, - 0x1DA07: 84, - 0x1DA08: 84, - 0x1DA09: 84, - 0x1DA0A: 84, - 0x1DA0B: 84, - 0x1DA0C: 84, - 0x1DA0D: 84, - 0x1DA0E: 84, - 0x1DA0F: 84, - 0x1DA10: 84, - 0x1DA11: 84, - 0x1DA12: 84, - 0x1DA13: 84, - 0x1DA14: 84, - 0x1DA15: 84, - 0x1DA16: 84, - 0x1DA17: 84, - 0x1DA18: 84, - 0x1DA19: 84, - 0x1DA1A: 84, - 0x1DA1B: 84, - 0x1DA1C: 84, - 0x1DA1D: 84, - 0x1DA1E: 84, - 0x1DA1F: 84, - 0x1DA20: 84, - 0x1DA21: 84, - 0x1DA22: 84, - 0x1DA23: 84, - 0x1DA24: 84, - 0x1DA25: 84, - 0x1DA26: 84, - 0x1DA27: 84, - 0x1DA28: 84, - 0x1DA29: 84, - 0x1DA2A: 84, - 0x1DA2B: 84, - 0x1DA2C: 84, - 0x1DA2D: 84, - 0x1DA2E: 84, - 0x1DA2F: 84, - 0x1DA30: 84, - 0x1DA31: 84, - 0x1DA32: 84, - 0x1DA33: 84, - 0x1DA34: 84, - 0x1DA35: 84, - 0x1DA36: 84, - 0x1DA3B: 84, - 0x1DA3C: 84, - 0x1DA3D: 84, - 0x1DA3E: 84, - 0x1DA3F: 84, - 0x1DA40: 84, - 0x1DA41: 84, - 0x1DA42: 84, - 0x1DA43: 84, - 0x1DA44: 84, - 0x1DA45: 84, - 0x1DA46: 84, - 0x1DA47: 84, - 0x1DA48: 84, - 0x1DA49: 84, - 0x1DA4A: 84, - 0x1DA4B: 84, - 0x1DA4C: 84, - 0x1DA4D: 84, - 0x1DA4E: 84, - 0x1DA4F: 84, - 0x1DA50: 84, - 0x1DA51: 84, - 0x1DA52: 84, - 0x1DA53: 84, - 0x1DA54: 84, - 0x1DA55: 84, - 0x1DA56: 84, - 0x1DA57: 84, - 0x1DA58: 84, - 0x1DA59: 84, - 0x1DA5A: 84, - 0x1DA5B: 84, - 0x1DA5C: 84, - 0x1DA5D: 84, - 0x1DA5E: 84, - 0x1DA5F: 84, - 0x1DA60: 84, - 0x1DA61: 84, - 0x1DA62: 84, - 0x1DA63: 84, - 0x1DA64: 84, - 0x1DA65: 84, - 0x1DA66: 84, - 0x1DA67: 84, - 0x1DA68: 84, - 0x1DA69: 84, - 0x1DA6A: 84, - 0x1DA6B: 84, - 0x1DA6C: 84, - 0x1DA75: 84, - 0x1DA84: 84, - 0x1DA9B: 84, - 0x1DA9C: 84, - 0x1DA9D: 84, - 0x1DA9E: 84, - 0x1DA9F: 84, - 0x1DAA1: 84, - 0x1DAA2: 84, - 0x1DAA3: 84, - 0x1DAA4: 84, - 0x1DAA5: 84, - 0x1DAA6: 84, - 0x1DAA7: 84, - 0x1DAA8: 84, - 0x1DAA9: 84, - 0x1DAAA: 84, - 0x1DAAB: 84, - 0x1DAAC: 84, - 0x1DAAD: 84, - 0x1DAAE: 84, - 0x1DAAF: 84, - 0x1E000: 84, - 0x1E001: 84, - 0x1E002: 84, - 0x1E003: 84, - 0x1E004: 84, - 0x1E005: 84, - 0x1E006: 84, - 0x1E008: 84, - 0x1E009: 84, - 0x1E00A: 84, - 0x1E00B: 84, - 0x1E00C: 84, - 0x1E00D: 84, - 0x1E00E: 84, - 0x1E00F: 84, - 0x1E010: 84, - 0x1E011: 84, - 0x1E012: 84, - 0x1E013: 84, - 0x1E014: 84, - 0x1E015: 84, - 0x1E016: 84, - 0x1E017: 84, - 0x1E018: 84, - 0x1E01B: 84, - 0x1E01C: 84, - 0x1E01D: 84, - 0x1E01E: 84, - 0x1E01F: 84, - 0x1E020: 84, - 0x1E021: 84, - 0x1E023: 84, - 0x1E024: 84, - 0x1E026: 84, - 0x1E027: 84, - 0x1E028: 84, - 0x1E029: 84, - 0x1E02A: 84, - 0x1E08F: 84, - 0x1E130: 84, - 0x1E131: 84, - 0x1E132: 84, - 0x1E133: 84, - 0x1E134: 84, - 0x1E135: 84, - 0x1E136: 84, - 0x1E2AE: 84, - 0x1E2EC: 84, - 0x1E2ED: 84, - 0x1E2EE: 84, - 0x1E2EF: 84, - 0x1E4EC: 84, - 0x1E4ED: 84, - 0x1E4EE: 84, - 0x1E4EF: 84, - 0x1E5EE: 84, - 0x1E5EF: 84, - 0x1E6E3: 84, - 0x1E6E6: 84, - 0x1E6EE: 84, - 0x1E6EF: 84, - 0x1E6F5: 84, - 0x1E8D0: 84, - 0x1E8D1: 84, - 0x1E8D2: 84, - 0x1E8D3: 84, - 0x1E8D4: 84, - 0x1E8D5: 84, - 0x1E8D6: 84, - 0x1E900: 68, - 0x1E901: 68, - 0x1E902: 68, - 0x1E903: 68, - 0x1E904: 68, - 0x1E905: 68, - 0x1E906: 68, - 0x1E907: 68, - 0x1E908: 68, - 0x1E909: 68, - 0x1E90A: 68, - 0x1E90B: 68, - 0x1E90C: 68, - 0x1E90D: 68, - 0x1E90E: 68, - 0x1E90F: 68, - 0x1E910: 68, - 0x1E911: 68, - 0x1E912: 68, - 0x1E913: 68, - 0x1E914: 68, - 0x1E915: 68, - 0x1E916: 68, - 0x1E917: 68, - 0x1E918: 68, - 0x1E919: 68, - 0x1E91A: 68, - 0x1E91B: 68, - 0x1E91C: 68, - 0x1E91D: 68, - 0x1E91E: 68, - 0x1E91F: 68, - 0x1E920: 68, - 0x1E921: 68, - 0x1E922: 68, - 0x1E923: 68, - 0x1E924: 68, - 0x1E925: 68, - 0x1E926: 68, - 0x1E927: 68, - 0x1E928: 68, - 0x1E929: 68, - 0x1E92A: 68, - 0x1E92B: 68, - 0x1E92C: 68, - 0x1E92D: 68, - 0x1E92E: 68, - 0x1E92F: 68, - 0x1E930: 68, - 0x1E931: 68, - 0x1E932: 68, - 0x1E933: 68, - 0x1E934: 68, - 0x1E935: 68, - 0x1E936: 68, - 0x1E937: 68, - 0x1E938: 68, - 0x1E939: 68, - 0x1E93A: 68, - 0x1E93B: 68, - 0x1E93C: 68, - 0x1E93D: 68, - 0x1E93E: 68, - 0x1E93F: 68, - 0x1E940: 68, - 0x1E941: 68, - 0x1E942: 68, - 0x1E943: 68, - 0x1E944: 84, - 0x1E945: 84, - 0x1E946: 84, - 0x1E947: 84, - 0x1E948: 84, - 0x1E949: 84, - 0x1E94A: 84, - 0x1E94B: 84, - 0xE0001: 84, - 0xE0020: 84, - 0xE0021: 84, - 0xE0022: 84, - 0xE0023: 84, - 0xE0024: 84, - 0xE0025: 84, - 0xE0026: 84, - 0xE0027: 84, - 0xE0028: 84, - 0xE0029: 84, - 0xE002A: 84, - 0xE002B: 84, - 0xE002C: 84, - 0xE002D: 84, - 0xE002E: 84, - 0xE002F: 84, - 0xE0030: 84, - 0xE0031: 84, - 0xE0032: 84, - 0xE0033: 84, - 0xE0034: 84, - 0xE0035: 84, - 0xE0036: 84, - 0xE0037: 84, - 0xE0038: 84, - 0xE0039: 84, - 0xE003A: 84, - 0xE003B: 84, - 0xE003C: 84, - 0xE003D: 84, - 0xE003E: 84, - 0xE003F: 84, - 0xE0040: 84, - 0xE0041: 84, - 0xE0042: 84, - 0xE0043: 84, - 0xE0044: 84, - 0xE0045: 84, - 0xE0046: 84, - 0xE0047: 84, - 0xE0048: 84, - 0xE0049: 84, - 0xE004A: 84, - 0xE004B: 84, - 0xE004C: 84, - 0xE004D: 84, - 0xE004E: 84, - 0xE004F: 84, - 0xE0050: 84, - 0xE0051: 84, - 0xE0052: 84, - 0xE0053: 84, - 0xE0054: 84, - 0xE0055: 84, - 0xE0056: 84, - 0xE0057: 84, - 0xE0058: 84, - 0xE0059: 84, - 0xE005A: 84, - 0xE005B: 84, - 0xE005C: 84, - 0xE005D: 84, - 0xE005E: 84, - 0xE005F: 84, - 0xE0060: 84, - 0xE0061: 84, - 0xE0062: 84, - 0xE0063: 84, - 0xE0064: 84, - 0xE0065: 84, - 0xE0066: 84, - 0xE0067: 84, - 0xE0068: 84, - 0xE0069: 84, - 0xE006A: 84, - 0xE006B: 84, - 0xE006C: 84, - 0xE006D: 84, - 0xE006E: 84, - 0xE006F: 84, - 0xE0070: 84, - 0xE0071: 84, - 0xE0072: 84, - 0xE0073: 84, - 0xE0074: 84, - 0xE0075: 84, - 0xE0076: 84, - 0xE0077: 84, - 0xE0078: 84, - 0xE0079: 84, - 0xE007A: 84, - 0xE007B: 84, - 0xE007C: 84, - 0xE007D: 84, - 0xE007E: 84, - 0xE007F: 84, - 0xE0100: 84, - 0xE0101: 84, - 0xE0102: 84, - 0xE0103: 84, - 0xE0104: 84, - 0xE0105: 84, - 0xE0106: 84, - 0xE0107: 84, - 0xE0108: 84, - 0xE0109: 84, - 0xE010A: 84, - 0xE010B: 84, - 0xE010C: 84, - 0xE010D: 84, - 0xE010E: 84, - 0xE010F: 84, - 0xE0110: 84, - 0xE0111: 84, - 0xE0112: 84, - 0xE0113: 84, - 0xE0114: 84, - 0xE0115: 84, - 0xE0116: 84, - 0xE0117: 84, - 0xE0118: 84, - 0xE0119: 84, - 0xE011A: 84, - 0xE011B: 84, - 0xE011C: 84, - 0xE011D: 84, - 0xE011E: 84, - 0xE011F: 84, - 0xE0120: 84, - 0xE0121: 84, - 0xE0122: 84, - 0xE0123: 84, - 0xE0124: 84, - 0xE0125: 84, - 0xE0126: 84, - 0xE0127: 84, - 0xE0128: 84, - 0xE0129: 84, - 0xE012A: 84, - 0xE012B: 84, - 0xE012C: 84, - 0xE012D: 84, - 0xE012E: 84, - 0xE012F: 84, - 0xE0130: 84, - 0xE0131: 84, - 0xE0132: 84, - 0xE0133: 84, - 0xE0134: 84, - 0xE0135: 84, - 0xE0136: 84, - 0xE0137: 84, - 0xE0138: 84, - 0xE0139: 84, - 0xE013A: 84, - 0xE013B: 84, - 0xE013C: 84, - 0xE013D: 84, - 0xE013E: 84, - 0xE013F: 84, - 0xE0140: 84, - 0xE0141: 84, - 0xE0142: 84, - 0xE0143: 84, - 0xE0144: 84, - 0xE0145: 84, - 0xE0146: 84, - 0xE0147: 84, - 0xE0148: 84, - 0xE0149: 84, - 0xE014A: 84, - 0xE014B: 84, - 0xE014C: 84, - 0xE014D: 84, - 0xE014E: 84, - 0xE014F: 84, - 0xE0150: 84, - 0xE0151: 84, - 0xE0152: 84, - 0xE0153: 84, - 0xE0154: 84, - 0xE0155: 84, - 0xE0156: 84, - 0xE0157: 84, - 0xE0158: 84, - 0xE0159: 84, - 0xE015A: 84, - 0xE015B: 84, - 0xE015C: 84, - 0xE015D: 84, - 0xE015E: 84, - 0xE015F: 84, - 0xE0160: 84, - 0xE0161: 84, - 0xE0162: 84, - 0xE0163: 84, - 0xE0164: 84, - 0xE0165: 84, - 0xE0166: 84, - 0xE0167: 84, - 0xE0168: 84, - 0xE0169: 84, - 0xE016A: 84, - 0xE016B: 84, - 0xE016C: 84, - 0xE016D: 84, - 0xE016E: 84, - 0xE016F: 84, - 0xE0170: 84, - 0xE0171: 84, - 0xE0172: 84, - 0xE0173: 84, - 0xE0174: 84, - 0xE0175: 84, - 0xE0176: 84, - 0xE0177: 84, - 0xE0178: 84, - 0xE0179: 84, - 0xE017A: 84, - 0xE017B: 84, - 0xE017C: 84, - 0xE017D: 84, - 0xE017E: 84, - 0xE017F: 84, - 0xE0180: 84, - 0xE0181: 84, - 0xE0182: 84, - 0xE0183: 84, - 0xE0184: 84, - 0xE0185: 84, - 0xE0186: 84, - 0xE0187: 84, - 0xE0188: 84, - 0xE0189: 84, - 0xE018A: 84, - 0xE018B: 84, - 0xE018C: 84, - 0xE018D: 84, - 0xE018E: 84, - 0xE018F: 84, - 0xE0190: 84, - 0xE0191: 84, - 0xE0192: 84, - 0xE0193: 84, - 0xE0194: 84, - 0xE0195: 84, - 0xE0196: 84, - 0xE0197: 84, - 0xE0198: 84, - 0xE0199: 84, - 0xE019A: 84, - 0xE019B: 84, - 0xE019C: 84, - 0xE019D: 84, - 0xE019E: 84, - 0xE019F: 84, - 0xE01A0: 84, - 0xE01A1: 84, - 0xE01A2: 84, - 0xE01A3: 84, - 0xE01A4: 84, - 0xE01A5: 84, - 0xE01A6: 84, - 0xE01A7: 84, - 0xE01A8: 84, - 0xE01A9: 84, - 0xE01AA: 84, - 0xE01AB: 84, - 0xE01AC: 84, - 0xE01AD: 84, - 0xE01AE: 84, - 0xE01AF: 84, - 0xE01B0: 84, - 0xE01B1: 84, - 0xE01B2: 84, - 0xE01B3: 84, - 0xE01B4: 84, - 0xE01B5: 84, - 0xE01B6: 84, - 0xE01B7: 84, - 0xE01B8: 84, - 0xE01B9: 84, - 0xE01BA: 84, - 0xE01BB: 84, - 0xE01BC: 84, - 0xE01BD: 84, - 0xE01BE: 84, - 0xE01BF: 84, - 0xE01C0: 84, - 0xE01C1: 84, - 0xE01C2: 84, - 0xE01C3: 84, - 0xE01C4: 84, - 0xE01C5: 84, - 0xE01C6: 84, - 0xE01C7: 84, - 0xE01C8: 84, - 0xE01C9: 84, - 0xE01CA: 84, - 0xE01CB: 84, - 0xE01CC: 84, - 0xE01CD: 84, - 0xE01CE: 84, - 0xE01CF: 84, - 0xE01D0: 84, - 0xE01D1: 84, - 0xE01D2: 84, - 0xE01D3: 84, - 0xE01D4: 84, - 0xE01D5: 84, - 0xE01D6: 84, - 0xE01D7: 84, - 0xE01D8: 84, - 0xE01D9: 84, - 0xE01DA: 84, - 0xE01DB: 84, - 0xE01DC: 84, - 0xE01DD: 84, - 0xE01DE: 84, - 0xE01DF: 84, - 0xE01E0: 84, - 0xE01E1: 84, - 0xE01E2: 84, - 0xE01E3: 84, - 0xE01E4: 84, - 0xE01E5: 84, - 0xE01E6: 84, - 0xE01E7: 84, - 0xE01E8: 84, - 0xE01E9: 84, - 0xE01EA: 84, - 0xE01EB: 84, - 0xE01EC: 84, - 0xE01ED: 84, - 0xE01EE: 84, - 0xE01EF: 84, - } - - -codepoint_classes = { - "PVALID": ( - 0x2D0000002E, - 0x300000003A, - 0x610000007B, - 0xDF000000F7, - 0xF800000100, - 0x10100000102, - 0x10300000104, - 0x10500000106, - 0x10700000108, - 0x1090000010A, - 0x10B0000010C, - 0x10D0000010E, - 0x10F00000110, - 0x11100000112, - 0x11300000114, - 0x11500000116, - 0x11700000118, - 0x1190000011A, - 0x11B0000011C, - 0x11D0000011E, - 0x11F00000120, - 0x12100000122, - 0x12300000124, - 0x12500000126, - 0x12700000128, - 0x1290000012A, - 0x12B0000012C, - 0x12D0000012E, - 0x12F00000130, - 0x13100000132, - 0x13500000136, - 0x13700000139, - 0x13A0000013B, - 0x13C0000013D, - 0x13E0000013F, - 0x14200000143, - 0x14400000145, - 0x14600000147, - 0x14800000149, - 0x14B0000014C, - 0x14D0000014E, - 0x14F00000150, - 0x15100000152, - 0x15300000154, - 0x15500000156, - 0x15700000158, - 0x1590000015A, - 0x15B0000015C, - 0x15D0000015E, - 0x15F00000160, - 0x16100000162, - 0x16300000164, - 0x16500000166, - 0x16700000168, - 0x1690000016A, - 0x16B0000016C, - 0x16D0000016E, - 0x16F00000170, - 0x17100000172, - 0x17300000174, - 0x17500000176, - 0x17700000178, - 0x17A0000017B, - 0x17C0000017D, - 0x17E0000017F, - 0x18000000181, - 0x18300000184, - 0x18500000186, - 0x18800000189, - 0x18C0000018E, - 0x19200000193, - 0x19500000196, - 0x1990000019C, - 0x19E0000019F, - 0x1A1000001A2, - 0x1A3000001A4, - 0x1A5000001A6, - 0x1A8000001A9, - 0x1AA000001AC, - 0x1AD000001AE, - 0x1B0000001B1, - 0x1B4000001B5, - 0x1B6000001B7, - 0x1B9000001BC, - 0x1BD000001C4, - 0x1CE000001CF, - 0x1D0000001D1, - 0x1D2000001D3, - 0x1D4000001D5, - 0x1D6000001D7, - 0x1D8000001D9, - 0x1DA000001DB, - 0x1DC000001DE, - 0x1DF000001E0, - 0x1E1000001E2, - 0x1E3000001E4, - 0x1E5000001E6, - 0x1E7000001E8, - 0x1E9000001EA, - 0x1EB000001EC, - 0x1ED000001EE, - 0x1EF000001F1, - 0x1F5000001F6, - 0x1F9000001FA, - 0x1FB000001FC, - 0x1FD000001FE, - 0x1FF00000200, - 0x20100000202, - 0x20300000204, - 0x20500000206, - 0x20700000208, - 0x2090000020A, - 0x20B0000020C, - 0x20D0000020E, - 0x20F00000210, - 0x21100000212, - 0x21300000214, - 0x21500000216, - 0x21700000218, - 0x2190000021A, - 0x21B0000021C, - 0x21D0000021E, - 0x21F00000220, - 0x22100000222, - 0x22300000224, - 0x22500000226, - 0x22700000228, - 0x2290000022A, - 0x22B0000022C, - 0x22D0000022E, - 0x22F00000230, - 0x23100000232, - 0x2330000023A, - 0x23C0000023D, - 0x23F00000241, - 0x24200000243, - 0x24700000248, - 0x2490000024A, - 0x24B0000024C, - 0x24D0000024E, - 0x24F000002B0, - 0x2B9000002C2, - 0x2C6000002D2, - 0x2EC000002ED, - 0x2EE000002EF, - 0x30000000340, - 0x34200000343, - 0x3460000034F, - 0x35000000370, - 0x37100000372, - 0x37300000374, - 0x37700000378, - 0x37B0000037E, - 0x39000000391, - 0x3AC000003CF, - 0x3D7000003D8, - 0x3D9000003DA, - 0x3DB000003DC, - 0x3DD000003DE, - 0x3DF000003E0, - 0x3E1000003E2, - 0x3E3000003E4, - 0x3E5000003E6, - 0x3E7000003E8, - 0x3E9000003EA, - 0x3EB000003EC, - 0x3ED000003EE, - 0x3EF000003F0, - 0x3F3000003F4, - 0x3F8000003F9, - 0x3FB000003FD, - 0x43000000460, - 0x46100000462, - 0x46300000464, - 0x46500000466, - 0x46700000468, - 0x4690000046A, - 0x46B0000046C, - 0x46D0000046E, - 0x46F00000470, - 0x47100000472, - 0x47300000474, - 0x47500000476, - 0x47700000478, - 0x4790000047A, - 0x47B0000047C, - 0x47D0000047E, - 0x47F00000480, - 0x48100000482, - 0x48300000488, - 0x48B0000048C, - 0x48D0000048E, - 0x48F00000490, - 0x49100000492, - 0x49300000494, - 0x49500000496, - 0x49700000498, - 0x4990000049A, - 0x49B0000049C, - 0x49D0000049E, - 0x49F000004A0, - 0x4A1000004A2, - 0x4A3000004A4, - 0x4A5000004A6, - 0x4A7000004A8, - 0x4A9000004AA, - 0x4AB000004AC, - 0x4AD000004AE, - 0x4AF000004B0, - 0x4B1000004B2, - 0x4B3000004B4, - 0x4B5000004B6, - 0x4B7000004B8, - 0x4B9000004BA, - 0x4BB000004BC, - 0x4BD000004BE, - 0x4BF000004C0, - 0x4C2000004C3, - 0x4C4000004C5, - 0x4C6000004C7, - 0x4C8000004C9, - 0x4CA000004CB, - 0x4CC000004CD, - 0x4CE000004D0, - 0x4D1000004D2, - 0x4D3000004D4, - 0x4D5000004D6, - 0x4D7000004D8, - 0x4D9000004DA, - 0x4DB000004DC, - 0x4DD000004DE, - 0x4DF000004E0, - 0x4E1000004E2, - 0x4E3000004E4, - 0x4E5000004E6, - 0x4E7000004E8, - 0x4E9000004EA, - 0x4EB000004EC, - 0x4ED000004EE, - 0x4EF000004F0, - 0x4F1000004F2, - 0x4F3000004F4, - 0x4F5000004F6, - 0x4F7000004F8, - 0x4F9000004FA, - 0x4FB000004FC, - 0x4FD000004FE, - 0x4FF00000500, - 0x50100000502, - 0x50300000504, - 0x50500000506, - 0x50700000508, - 0x5090000050A, - 0x50B0000050C, - 0x50D0000050E, - 0x50F00000510, - 0x51100000512, - 0x51300000514, - 0x51500000516, - 0x51700000518, - 0x5190000051A, - 0x51B0000051C, - 0x51D0000051E, - 0x51F00000520, - 0x52100000522, - 0x52300000524, - 0x52500000526, - 0x52700000528, - 0x5290000052A, - 0x52B0000052C, - 0x52D0000052E, - 0x52F00000530, - 0x5590000055A, - 0x56000000587, - 0x58800000589, - 0x591000005BE, - 0x5BF000005C0, - 0x5C1000005C3, - 0x5C4000005C6, - 0x5C7000005C8, - 0x5D0000005EB, - 0x5EF000005F3, - 0x6100000061B, - 0x62000000640, - 0x64100000660, - 0x66E00000675, - 0x679000006D4, - 0x6D5000006DD, - 0x6DF000006E9, - 0x6EA000006F0, - 0x6FA00000700, - 0x7100000074B, - 0x74D000007B2, - 0x7C0000007F6, - 0x7FD000007FE, - 0x8000000082E, - 0x8400000085C, - 0x8600000086B, - 0x87000000888, - 0x88900000890, - 0x897000008E2, - 0x8E300000958, - 0x96000000964, - 0x96600000970, - 0x97100000984, - 0x9850000098D, - 0x98F00000991, - 0x993000009A9, - 0x9AA000009B1, - 0x9B2000009B3, - 0x9B6000009BA, - 0x9BC000009C5, - 0x9C7000009C9, - 0x9CB000009CF, - 0x9D7000009D8, - 0x9E0000009E4, - 0x9E6000009F2, - 0x9FC000009FD, - 0x9FE000009FF, - 0xA0100000A04, - 0xA0500000A0B, - 0xA0F00000A11, - 0xA1300000A29, - 0xA2A00000A31, - 0xA3200000A33, - 0xA3500000A36, - 0xA3800000A3A, - 0xA3C00000A3D, - 0xA3E00000A43, - 0xA4700000A49, - 0xA4B00000A4E, - 0xA5100000A52, - 0xA5C00000A5D, - 0xA6600000A76, - 0xA8100000A84, - 0xA8500000A8E, - 0xA8F00000A92, - 0xA9300000AA9, - 0xAAA00000AB1, - 0xAB200000AB4, - 0xAB500000ABA, - 0xABC00000AC6, - 0xAC700000ACA, - 0xACB00000ACE, - 0xAD000000AD1, - 0xAE000000AE4, - 0xAE600000AF0, - 0xAF900000B00, - 0xB0100000B04, - 0xB0500000B0D, - 0xB0F00000B11, - 0xB1300000B29, - 0xB2A00000B31, - 0xB3200000B34, - 0xB3500000B3A, - 0xB3C00000B45, - 0xB4700000B49, - 0xB4B00000B4E, - 0xB5500000B58, - 0xB5F00000B64, - 0xB6600000B70, - 0xB7100000B72, - 0xB8200000B84, - 0xB8500000B8B, - 0xB8E00000B91, - 0xB9200000B96, - 0xB9900000B9B, - 0xB9C00000B9D, - 0xB9E00000BA0, - 0xBA300000BA5, - 0xBA800000BAB, - 0xBAE00000BBA, - 0xBBE00000BC3, - 0xBC600000BC9, - 0xBCA00000BCE, - 0xBD000000BD1, - 0xBD700000BD8, - 0xBE600000BF0, - 0xC0000000C0D, - 0xC0E00000C11, - 0xC1200000C29, - 0xC2A00000C3A, - 0xC3C00000C45, - 0xC4600000C49, - 0xC4A00000C4E, - 0xC5500000C57, - 0xC5800000C5B, - 0xC5C00000C5E, - 0xC6000000C64, - 0xC6600000C70, - 0xC8000000C84, - 0xC8500000C8D, - 0xC8E00000C91, - 0xC9200000CA9, - 0xCAA00000CB4, - 0xCB500000CBA, - 0xCBC00000CC5, - 0xCC600000CC9, - 0xCCA00000CCE, - 0xCD500000CD7, - 0xCDC00000CDF, - 0xCE000000CE4, - 0xCE600000CF0, - 0xCF100000CF4, - 0xD0000000D0D, - 0xD0E00000D11, - 0xD1200000D45, - 0xD4600000D49, - 0xD4A00000D4F, - 0xD5400000D58, - 0xD5F00000D64, - 0xD6600000D70, - 0xD7A00000D80, - 0xD8100000D84, - 0xD8500000D97, - 0xD9A00000DB2, - 0xDB300000DBC, - 0xDBD00000DBE, - 0xDC000000DC7, - 0xDCA00000DCB, - 0xDCF00000DD5, - 0xDD600000DD7, - 0xDD800000DE0, - 0xDE600000DF0, - 0xDF200000DF4, - 0xE0100000E33, - 0xE3400000E3B, - 0xE4000000E4F, - 0xE5000000E5A, - 0xE8100000E83, - 0xE8400000E85, - 0xE8600000E8B, - 0xE8C00000EA4, - 0xEA500000EA6, - 0xEA700000EB3, - 0xEB400000EBE, - 0xEC000000EC5, - 0xEC600000EC7, - 0xEC800000ECF, - 0xED000000EDA, - 0xEDE00000EE0, - 0xF0000000F01, - 0xF0B00000F0C, - 0xF1800000F1A, - 0xF2000000F2A, - 0xF3500000F36, - 0xF3700000F38, - 0xF3900000F3A, - 0xF3E00000F43, - 0xF4400000F48, - 0xF4900000F4D, - 0xF4E00000F52, - 0xF5300000F57, - 0xF5800000F5C, - 0xF5D00000F69, - 0xF6A00000F6D, - 0xF7100000F73, - 0xF7400000F75, - 0xF7A00000F81, - 0xF8200000F85, - 0xF8600000F93, - 0xF9400000F98, - 0xF9900000F9D, - 0xF9E00000FA2, - 0xFA300000FA7, - 0xFA800000FAC, - 0xFAD00000FB9, - 0xFBA00000FBD, - 0xFC600000FC7, - 0x10000000104A, - 0x10500000109E, - 0x10D0000010FB, - 0x10FD00001100, - 0x120000001249, - 0x124A0000124E, - 0x125000001257, - 0x125800001259, - 0x125A0000125E, - 0x126000001289, - 0x128A0000128E, - 0x1290000012B1, - 0x12B2000012B6, - 0x12B8000012BF, - 0x12C0000012C1, - 0x12C2000012C6, - 0x12C8000012D7, - 0x12D800001311, - 0x131200001316, - 0x13180000135B, - 0x135D00001360, - 0x138000001390, - 0x13A0000013F6, - 0x14010000166D, - 0x166F00001680, - 0x16810000169B, - 0x16A0000016EB, - 0x16F1000016F9, - 0x170000001716, - 0x171F00001735, - 0x174000001754, - 0x17600000176D, - 0x176E00001771, - 0x177200001774, - 0x1780000017B4, - 0x17B6000017D4, - 0x17D7000017D8, - 0x17DC000017DE, - 0x17E0000017EA, - 0x18100000181A, - 0x182000001879, - 0x1880000018AB, - 0x18B0000018F6, - 0x19000000191F, - 0x19200000192C, - 0x19300000193C, - 0x19460000196E, - 0x197000001975, - 0x1980000019AC, - 0x19B0000019CA, - 0x19D0000019DA, - 0x1A0000001A1C, - 0x1A2000001A5F, - 0x1A6000001A7D, - 0x1A7F00001A8A, - 0x1A9000001A9A, - 0x1AA700001AA8, - 0x1AB000001ABE, - 0x1ABF00001ADE, - 0x1AE000001AEC, - 0x1B0000001B4D, - 0x1B5000001B5A, - 0x1B6B00001B74, - 0x1B8000001BF4, - 0x1C0000001C38, - 0x1C4000001C4A, - 0x1C4D00001C7E, - 0x1C8A00001C8B, - 0x1CD000001CD3, - 0x1CD400001CFB, - 0x1D0000001D2C, - 0x1D2F00001D30, - 0x1D3B00001D3C, - 0x1D4E00001D4F, - 0x1D6B00001D78, - 0x1D7900001D9B, - 0x1DC000001E00, - 0x1E0100001E02, - 0x1E0300001E04, - 0x1E0500001E06, - 0x1E0700001E08, - 0x1E0900001E0A, - 0x1E0B00001E0C, - 0x1E0D00001E0E, - 0x1E0F00001E10, - 0x1E1100001E12, - 0x1E1300001E14, - 0x1E1500001E16, - 0x1E1700001E18, - 0x1E1900001E1A, - 0x1E1B00001E1C, - 0x1E1D00001E1E, - 0x1E1F00001E20, - 0x1E2100001E22, - 0x1E2300001E24, - 0x1E2500001E26, - 0x1E2700001E28, - 0x1E2900001E2A, - 0x1E2B00001E2C, - 0x1E2D00001E2E, - 0x1E2F00001E30, - 0x1E3100001E32, - 0x1E3300001E34, - 0x1E3500001E36, - 0x1E3700001E38, - 0x1E3900001E3A, - 0x1E3B00001E3C, - 0x1E3D00001E3E, - 0x1E3F00001E40, - 0x1E4100001E42, - 0x1E4300001E44, - 0x1E4500001E46, - 0x1E4700001E48, - 0x1E4900001E4A, - 0x1E4B00001E4C, - 0x1E4D00001E4E, - 0x1E4F00001E50, - 0x1E5100001E52, - 0x1E5300001E54, - 0x1E5500001E56, - 0x1E5700001E58, - 0x1E5900001E5A, - 0x1E5B00001E5C, - 0x1E5D00001E5E, - 0x1E5F00001E60, - 0x1E6100001E62, - 0x1E6300001E64, - 0x1E6500001E66, - 0x1E6700001E68, - 0x1E6900001E6A, - 0x1E6B00001E6C, - 0x1E6D00001E6E, - 0x1E6F00001E70, - 0x1E7100001E72, - 0x1E7300001E74, - 0x1E7500001E76, - 0x1E7700001E78, - 0x1E7900001E7A, - 0x1E7B00001E7C, - 0x1E7D00001E7E, - 0x1E7F00001E80, - 0x1E8100001E82, - 0x1E8300001E84, - 0x1E8500001E86, - 0x1E8700001E88, - 0x1E8900001E8A, - 0x1E8B00001E8C, - 0x1E8D00001E8E, - 0x1E8F00001E90, - 0x1E9100001E92, - 0x1E9300001E94, - 0x1E9500001E9A, - 0x1E9C00001E9E, - 0x1E9F00001EA0, - 0x1EA100001EA2, - 0x1EA300001EA4, - 0x1EA500001EA6, - 0x1EA700001EA8, - 0x1EA900001EAA, - 0x1EAB00001EAC, - 0x1EAD00001EAE, - 0x1EAF00001EB0, - 0x1EB100001EB2, - 0x1EB300001EB4, - 0x1EB500001EB6, - 0x1EB700001EB8, - 0x1EB900001EBA, - 0x1EBB00001EBC, - 0x1EBD00001EBE, - 0x1EBF00001EC0, - 0x1EC100001EC2, - 0x1EC300001EC4, - 0x1EC500001EC6, - 0x1EC700001EC8, - 0x1EC900001ECA, - 0x1ECB00001ECC, - 0x1ECD00001ECE, - 0x1ECF00001ED0, - 0x1ED100001ED2, - 0x1ED300001ED4, - 0x1ED500001ED6, - 0x1ED700001ED8, - 0x1ED900001EDA, - 0x1EDB00001EDC, - 0x1EDD00001EDE, - 0x1EDF00001EE0, - 0x1EE100001EE2, - 0x1EE300001EE4, - 0x1EE500001EE6, - 0x1EE700001EE8, - 0x1EE900001EEA, - 0x1EEB00001EEC, - 0x1EED00001EEE, - 0x1EEF00001EF0, - 0x1EF100001EF2, - 0x1EF300001EF4, - 0x1EF500001EF6, - 0x1EF700001EF8, - 0x1EF900001EFA, - 0x1EFB00001EFC, - 0x1EFD00001EFE, - 0x1EFF00001F08, - 0x1F1000001F16, - 0x1F2000001F28, - 0x1F3000001F38, - 0x1F4000001F46, - 0x1F5000001F58, - 0x1F6000001F68, - 0x1F7000001F71, - 0x1F7200001F73, - 0x1F7400001F75, - 0x1F7600001F77, - 0x1F7800001F79, - 0x1F7A00001F7B, - 0x1F7C00001F7D, - 0x1FB000001FB2, - 0x1FB600001FB7, - 0x1FC600001FC7, - 0x1FD000001FD3, - 0x1FD600001FD8, - 0x1FE000001FE3, - 0x1FE400001FE8, - 0x1FF600001FF7, - 0x214E0000214F, - 0x218400002185, - 0x2C3000002C60, - 0x2C6100002C62, - 0x2C6500002C67, - 0x2C6800002C69, - 0x2C6A00002C6B, - 0x2C6C00002C6D, - 0x2C7100002C72, - 0x2C7300002C75, - 0x2C7600002C7C, - 0x2C8100002C82, - 0x2C8300002C84, - 0x2C8500002C86, - 0x2C8700002C88, - 0x2C8900002C8A, - 0x2C8B00002C8C, - 0x2C8D00002C8E, - 0x2C8F00002C90, - 0x2C9100002C92, - 0x2C9300002C94, - 0x2C9500002C96, - 0x2C9700002C98, - 0x2C9900002C9A, - 0x2C9B00002C9C, - 0x2C9D00002C9E, - 0x2C9F00002CA0, - 0x2CA100002CA2, - 0x2CA300002CA4, - 0x2CA500002CA6, - 0x2CA700002CA8, - 0x2CA900002CAA, - 0x2CAB00002CAC, - 0x2CAD00002CAE, - 0x2CAF00002CB0, - 0x2CB100002CB2, - 0x2CB300002CB4, - 0x2CB500002CB6, - 0x2CB700002CB8, - 0x2CB900002CBA, - 0x2CBB00002CBC, - 0x2CBD00002CBE, - 0x2CBF00002CC0, - 0x2CC100002CC2, - 0x2CC300002CC4, - 0x2CC500002CC6, - 0x2CC700002CC8, - 0x2CC900002CCA, - 0x2CCB00002CCC, - 0x2CCD00002CCE, - 0x2CCF00002CD0, - 0x2CD100002CD2, - 0x2CD300002CD4, - 0x2CD500002CD6, - 0x2CD700002CD8, - 0x2CD900002CDA, - 0x2CDB00002CDC, - 0x2CDD00002CDE, - 0x2CDF00002CE0, - 0x2CE100002CE2, - 0x2CE300002CE5, - 0x2CEC00002CED, - 0x2CEE00002CF2, - 0x2CF300002CF4, - 0x2D0000002D26, - 0x2D2700002D28, - 0x2D2D00002D2E, - 0x2D3000002D68, - 0x2D7F00002D97, - 0x2DA000002DA7, - 0x2DA800002DAF, - 0x2DB000002DB7, - 0x2DB800002DBF, - 0x2DC000002DC7, - 0x2DC800002DCF, - 0x2DD000002DD7, - 0x2DD800002DDF, - 0x2DE000002E00, - 0x2E2F00002E30, - 0x300500003008, - 0x302A0000302E, - 0x303C0000303D, - 0x304100003097, - 0x30990000309B, - 0x309D0000309F, - 0x30A1000030FB, - 0x30FC000030FF, - 0x310500003130, - 0x31A0000031C0, - 0x31F000003200, - 0x340000004DC0, - 0x4E000000A48D, - 0xA4D00000A4FE, - 0xA5000000A60D, - 0xA6100000A62C, - 0xA6410000A642, - 0xA6430000A644, - 0xA6450000A646, - 0xA6470000A648, - 0xA6490000A64A, - 0xA64B0000A64C, - 0xA64D0000A64E, - 0xA64F0000A650, - 0xA6510000A652, - 0xA6530000A654, - 0xA6550000A656, - 0xA6570000A658, - 0xA6590000A65A, - 0xA65B0000A65C, - 0xA65D0000A65E, - 0xA65F0000A660, - 0xA6610000A662, - 0xA6630000A664, - 0xA6650000A666, - 0xA6670000A668, - 0xA6690000A66A, - 0xA66B0000A66C, - 0xA66D0000A670, - 0xA6740000A67E, - 0xA67F0000A680, - 0xA6810000A682, - 0xA6830000A684, - 0xA6850000A686, - 0xA6870000A688, - 0xA6890000A68A, - 0xA68B0000A68C, - 0xA68D0000A68E, - 0xA68F0000A690, - 0xA6910000A692, - 0xA6930000A694, - 0xA6950000A696, - 0xA6970000A698, - 0xA6990000A69A, - 0xA69B0000A69C, - 0xA69E0000A6E6, - 0xA6F00000A6F2, - 0xA7170000A720, - 0xA7230000A724, - 0xA7250000A726, - 0xA7270000A728, - 0xA7290000A72A, - 0xA72B0000A72C, - 0xA72D0000A72E, - 0xA72F0000A732, - 0xA7330000A734, - 0xA7350000A736, - 0xA7370000A738, - 0xA7390000A73A, - 0xA73B0000A73C, - 0xA73D0000A73E, - 0xA73F0000A740, - 0xA7410000A742, - 0xA7430000A744, - 0xA7450000A746, - 0xA7470000A748, - 0xA7490000A74A, - 0xA74B0000A74C, - 0xA74D0000A74E, - 0xA74F0000A750, - 0xA7510000A752, - 0xA7530000A754, - 0xA7550000A756, - 0xA7570000A758, - 0xA7590000A75A, - 0xA75B0000A75C, - 0xA75D0000A75E, - 0xA75F0000A760, - 0xA7610000A762, - 0xA7630000A764, - 0xA7650000A766, - 0xA7670000A768, - 0xA7690000A76A, - 0xA76B0000A76C, - 0xA76D0000A76E, - 0xA76F0000A770, - 0xA7710000A779, - 0xA77A0000A77B, - 0xA77C0000A77D, - 0xA77F0000A780, - 0xA7810000A782, - 0xA7830000A784, - 0xA7850000A786, - 0xA7870000A789, - 0xA78C0000A78D, - 0xA78E0000A790, - 0xA7910000A792, - 0xA7930000A796, - 0xA7970000A798, - 0xA7990000A79A, - 0xA79B0000A79C, - 0xA79D0000A79E, - 0xA79F0000A7A0, - 0xA7A10000A7A2, - 0xA7A30000A7A4, - 0xA7A50000A7A6, - 0xA7A70000A7A8, - 0xA7A90000A7AA, - 0xA7AF0000A7B0, - 0xA7B50000A7B6, - 0xA7B70000A7B8, - 0xA7B90000A7BA, - 0xA7BB0000A7BC, - 0xA7BD0000A7BE, - 0xA7BF0000A7C0, - 0xA7C10000A7C2, - 0xA7C30000A7C4, - 0xA7C80000A7C9, - 0xA7CA0000A7CB, - 0xA7CD0000A7CE, - 0xA7CF0000A7D0, - 0xA7D10000A7D2, - 0xA7D30000A7D4, - 0xA7D50000A7D6, - 0xA7D70000A7D8, - 0xA7D90000A7DA, - 0xA7DB0000A7DC, - 0xA7F60000A7F8, - 0xA7FA0000A828, - 0xA82C0000A82D, - 0xA8400000A874, - 0xA8800000A8C6, - 0xA8D00000A8DA, - 0xA8E00000A8F8, - 0xA8FB0000A8FC, - 0xA8FD0000A92E, - 0xA9300000A954, - 0xA9800000A9C1, - 0xA9CF0000A9DA, - 0xA9E00000A9FF, - 0xAA000000AA37, - 0xAA400000AA4E, - 0xAA500000AA5A, - 0xAA600000AA77, - 0xAA7A0000AAC3, - 0xAADB0000AADE, - 0xAAE00000AAF0, - 0xAAF20000AAF7, - 0xAB010000AB07, - 0xAB090000AB0F, - 0xAB110000AB17, - 0xAB200000AB27, - 0xAB280000AB2F, - 0xAB300000AB5B, - 0xAB600000AB69, - 0xABC00000ABEB, - 0xABEC0000ABEE, - 0xABF00000ABFA, - 0xAC000000D7A4, - 0xFA0E0000FA10, - 0xFA110000FA12, - 0xFA130000FA15, - 0xFA1F0000FA20, - 0xFA210000FA22, - 0xFA230000FA25, - 0xFA270000FA2A, - 0xFB1E0000FB1F, - 0xFE200000FE30, - 0xFE730000FE74, - 0x100000001000C, - 0x1000D00010027, - 0x100280001003B, - 0x1003C0001003E, - 0x1003F0001004E, - 0x100500001005E, - 0x10080000100FB, - 0x101FD000101FE, - 0x102800001029D, - 0x102A0000102D1, - 0x102E0000102E1, - 0x1030000010320, - 0x1032D00010341, - 0x103420001034A, - 0x103500001037B, - 0x103800001039E, - 0x103A0000103C4, - 0x103C8000103D0, - 0x104280001049E, - 0x104A0000104AA, - 0x104D8000104FC, - 0x1050000010528, - 0x1053000010564, - 0x10597000105A2, - 0x105A3000105B2, - 0x105B3000105BA, - 0x105BB000105BD, - 0x105C0000105F4, - 0x1060000010737, - 0x1074000010756, - 0x1076000010768, - 0x1078000010781, - 0x1080000010806, - 0x1080800010809, - 0x1080A00010836, - 0x1083700010839, - 0x1083C0001083D, - 0x1083F00010856, - 0x1086000010877, - 0x108800001089F, - 0x108E0000108F3, - 0x108F4000108F6, - 0x1090000010916, - 0x109200001093A, - 0x109400001095A, - 0x10980000109B8, - 0x109BE000109C0, - 0x10A0000010A04, - 0x10A0500010A07, - 0x10A0C00010A14, - 0x10A1500010A18, - 0x10A1900010A36, - 0x10A3800010A3B, - 0x10A3F00010A40, - 0x10A6000010A7D, - 0x10A8000010A9D, - 0x10AC000010AC8, - 0x10AC900010AE7, - 0x10B0000010B36, - 0x10B4000010B56, - 0x10B6000010B73, - 0x10B8000010B92, - 0x10C0000010C49, - 0x10CC000010CF3, - 0x10D0000010D28, - 0x10D3000010D3A, - 0x10D4000010D50, - 0x10D6900010D6E, - 0x10D6F00010D86, - 0x10E8000010EAA, - 0x10EAB00010EAD, - 0x10EB000010EB2, - 0x10EC200010EC8, - 0x10EFA00010F1D, - 0x10F2700010F28, - 0x10F3000010F51, - 0x10F7000010F86, - 0x10FB000010FC5, - 0x10FE000010FF7, - 0x1100000011047, - 0x1106600011076, - 0x1107F000110BB, - 0x110C2000110C3, - 0x110D0000110E9, - 0x110F0000110FA, - 0x1110000011135, - 0x1113600011140, - 0x1114400011148, - 0x1115000011174, - 0x1117600011177, - 0x11180000111C5, - 0x111C9000111CD, - 0x111CE000111DB, - 0x111DC000111DD, - 0x1120000011212, - 0x1121300011238, - 0x1123E00011242, - 0x1128000011287, - 0x1128800011289, - 0x1128A0001128E, - 0x1128F0001129E, - 0x1129F000112A9, - 0x112B0000112EB, - 0x112F0000112FA, - 0x1130000011304, - 0x113050001130D, - 0x1130F00011311, - 0x1131300011329, - 0x1132A00011331, - 0x1133200011334, - 0x113350001133A, - 0x1133B00011345, - 0x1134700011349, - 0x1134B0001134E, - 0x1135000011351, - 0x1135700011358, - 0x1135D00011364, - 0x113660001136D, - 0x1137000011375, - 0x113800001138A, - 0x1138B0001138C, - 0x1138E0001138F, - 0x11390000113B6, - 0x113B7000113C1, - 0x113C2000113C3, - 0x113C5000113C6, - 0x113C7000113CB, - 0x113CC000113D4, - 0x113E1000113E3, - 0x114000001144B, - 0x114500001145A, - 0x1145E00011462, - 0x11480000114C6, - 0x114C7000114C8, - 0x114D0000114DA, - 0x11580000115B6, - 0x115B8000115C1, - 0x115D8000115DE, - 0x1160000011641, - 0x1164400011645, - 0x116500001165A, - 0x11680000116B9, - 0x116C0000116CA, - 0x116D0000116E4, - 0x117000001171B, - 0x1171D0001172C, - 0x117300001173A, - 0x1174000011747, - 0x118000001183B, - 0x118C0000118EA, - 0x118FF00011907, - 0x119090001190A, - 0x1190C00011914, - 0x1191500011917, - 0x1191800011936, - 0x1193700011939, - 0x1193B00011944, - 0x119500001195A, - 0x119A0000119A8, - 0x119AA000119D8, - 0x119DA000119E2, - 0x119E3000119E5, - 0x11A0000011A3F, - 0x11A4700011A48, - 0x11A5000011A9A, - 0x11A9D00011A9E, - 0x11AB000011AF9, - 0x11B6000011B68, - 0x11BC000011BE1, - 0x11BF000011BFA, - 0x11C0000011C09, - 0x11C0A00011C37, - 0x11C3800011C41, - 0x11C5000011C5A, - 0x11C7200011C90, - 0x11C9200011CA8, - 0x11CA900011CB7, - 0x11D0000011D07, - 0x11D0800011D0A, - 0x11D0B00011D37, - 0x11D3A00011D3B, - 0x11D3C00011D3E, - 0x11D3F00011D48, - 0x11D5000011D5A, - 0x11D6000011D66, - 0x11D6700011D69, - 0x11D6A00011D8F, - 0x11D9000011D92, - 0x11D9300011D99, - 0x11DA000011DAA, - 0x11DB000011DDC, - 0x11DE000011DEA, - 0x11EE000011EF7, - 0x11F0000011F11, - 0x11F1200011F3B, - 0x11F3E00011F43, - 0x11F5000011F5B, - 0x11FB000011FB1, - 0x120000001239A, - 0x1248000012544, - 0x12F9000012FF1, - 0x1300000013430, - 0x1344000013456, - 0x13460000143FB, - 0x1440000014647, - 0x161000001613A, - 0x1680000016A39, - 0x16A4000016A5F, - 0x16A6000016A6A, - 0x16A7000016ABF, - 0x16AC000016ACA, - 0x16AD000016AEE, - 0x16AF000016AF5, - 0x16B0000016B37, - 0x16B4000016B44, - 0x16B5000016B5A, - 0x16B6300016B78, - 0x16B7D00016B90, - 0x16D4000016D6D, - 0x16D7000016D7A, - 0x16E6000016E80, - 0x16EBB00016ED4, - 0x16F0000016F4B, - 0x16F4F00016F88, - 0x16F8F00016FA0, - 0x16FE000016FE2, - 0x16FE300016FE5, - 0x16FF000016FF4, - 0x1700000018CD6, - 0x18CFF00018D1F, - 0x18D8000018DF3, - 0x1AFF00001AFF4, - 0x1AFF50001AFFC, - 0x1AFFD0001AFFF, - 0x1B0000001B123, - 0x1B1320001B133, - 0x1B1500001B153, - 0x1B1550001B156, - 0x1B1640001B168, - 0x1B1700001B2FC, - 0x1BC000001BC6B, - 0x1BC700001BC7D, - 0x1BC800001BC89, - 0x1BC900001BC9A, - 0x1BC9D0001BC9F, - 0x1CF000001CF2E, - 0x1CF300001CF47, - 0x1DA000001DA37, - 0x1DA3B0001DA6D, - 0x1DA750001DA76, - 0x1DA840001DA85, - 0x1DA9B0001DAA0, - 0x1DAA10001DAB0, - 0x1DF000001DF1F, - 0x1DF250001DF2B, - 0x1E0000001E007, - 0x1E0080001E019, - 0x1E01B0001E022, - 0x1E0230001E025, - 0x1E0260001E02B, - 0x1E08F0001E090, - 0x1E1000001E12D, - 0x1E1300001E13E, - 0x1E1400001E14A, - 0x1E14E0001E14F, - 0x1E2900001E2AF, - 0x1E2C00001E2FA, - 0x1E4D00001E4FA, - 0x1E5D00001E5FB, - 0x1E6C00001E6DF, - 0x1E6E00001E6F6, - 0x1E6FE0001E700, - 0x1E7E00001E7E7, - 0x1E7E80001E7EC, - 0x1E7ED0001E7EF, - 0x1E7F00001E7FF, - 0x1E8000001E8C5, - 0x1E8D00001E8D7, - 0x1E9220001E94C, - 0x1E9500001E95A, - 0x200000002A6E0, - 0x2A7000002B81E, - 0x2B8200002CEAE, - 0x2CEB00002EBE1, - 0x2EBF00002EE5E, - 0x300000003134B, - 0x313500003347A, - ), - "CONTEXTJ": (0x200C0000200E,), - "CONTEXTO": ( - 0xB7000000B8, - 0x37500000376, - 0x5F3000005F5, - 0x6600000066A, - 0x6F0000006FA, - 0x30FB000030FC, - ), -} diff --git a/venv/lib/python3.9/site-packages/idna/intranges.py b/venv/lib/python3.9/site-packages/idna/intranges.py deleted file mode 100644 index 7bfaa8d..0000000 --- a/venv/lib/python3.9/site-packages/idna/intranges.py +++ /dev/null @@ -1,57 +0,0 @@ -""" -Given a list of integers, made up of (hopefully) a small number of long runs -of consecutive integers, compute a representation of the form -((start1, end1), (start2, end2) ...). Then answer the question "was x present -in the original list?" in time O(log(# runs)). -""" - -import bisect -from typing import List, Tuple - - -def intranges_from_list(list_: List[int]) -> Tuple[int, ...]: - """Represent a list of integers as a sequence of ranges: - ((start_0, end_0), (start_1, end_1), ...), such that the original - integers are exactly those x such that start_i <= x < end_i for some i. - - Ranges are encoded as single integers (start << 32 | end), not as tuples. - """ - - sorted_list = sorted(list_) - ranges = [] - last_write = -1 - for i in range(len(sorted_list)): - if i + 1 < len(sorted_list): - if sorted_list[i] == sorted_list[i + 1] - 1: - continue - current_range = sorted_list[last_write + 1 : i + 1] - ranges.append(_encode_range(current_range[0], current_range[-1] + 1)) - last_write = i - - return tuple(ranges) - - -def _encode_range(start: int, end: int) -> int: - return (start << 32) | end - - -def _decode_range(r: int) -> Tuple[int, int]: - return (r >> 32), (r & ((1 << 32) - 1)) - - -def intranges_contain(int_: int, ranges: Tuple[int, ...]) -> bool: - """Determine if `int_` falls into one of the ranges in `ranges`.""" - tuple_ = _encode_range(int_, 0) - pos = bisect.bisect_left(ranges, tuple_) - # we could be immediately ahead of a tuple (start, end) - # with start < int_ <= end - if pos > 0: - left, right = _decode_range(ranges[pos - 1]) - if left <= int_ < right: - return True - # or we could be immediately behind a tuple (int_, end) - if pos < len(ranges): - left, _ = _decode_range(ranges[pos]) - if left == int_: - return True - return False diff --git a/venv/lib/python3.9/site-packages/idna/package_data.py b/venv/lib/python3.9/site-packages/idna/package_data.py deleted file mode 100644 index fc1788c..0000000 --- a/venv/lib/python3.9/site-packages/idna/package_data.py +++ /dev/null @@ -1 +0,0 @@ -__version__ = "3.13" diff --git a/venv/lib/python3.9/site-packages/idna/py.typed b/venv/lib/python3.9/site-packages/idna/py.typed deleted file mode 100644 index e69de29..0000000 diff --git a/venv/lib/python3.9/site-packages/idna/uts46data.py b/venv/lib/python3.9/site-packages/idna/uts46data.py deleted file mode 100644 index cc2453e..0000000 --- a/venv/lib/python3.9/site-packages/idna/uts46data.py +++ /dev/null @@ -1,8384 +0,0 @@ -# This file is automatically generated by tools/idna-data -# vim: set fileencoding=utf-8 : - -from typing import Tuple, Union - -"""IDNA Mapping Table from UTS46.""" - - -__version__ = "17.0.0" - -uts46data: Tuple[Union[Tuple[int, str], Tuple[int, str, str]], ...] = ( - (0x0, "V"), - (0x1, "V"), - (0x2, "V"), - (0x3, "V"), - (0x4, "V"), - (0x5, "V"), - (0x6, "V"), - (0x7, "V"), - (0x8, "V"), - (0x9, "V"), - (0xA, "V"), - (0xB, "V"), - (0xC, "V"), - (0xD, "V"), - (0xE, "V"), - (0xF, "V"), - (0x10, "V"), - (0x11, "V"), - (0x12, "V"), - (0x13, "V"), - (0x14, "V"), - (0x15, "V"), - (0x16, "V"), - (0x17, "V"), - (0x18, "V"), - (0x19, "V"), - (0x1A, "V"), - (0x1B, "V"), - (0x1C, "V"), - (0x1D, "V"), - (0x1E, "V"), - (0x1F, "V"), - (0x20, "V"), - (0x21, "V"), - (0x22, "V"), - (0x23, "V"), - (0x24, "V"), - (0x25, "V"), - (0x26, "V"), - (0x27, "V"), - (0x28, "V"), - (0x29, "V"), - (0x2A, "V"), - (0x2B, "V"), - (0x2C, "V"), - (0x2D, "V"), - (0x2E, "V"), - (0x2F, "V"), - (0x30, "V"), - (0x31, "V"), - (0x32, "V"), - (0x33, "V"), - (0x34, "V"), - (0x35, "V"), - (0x36, "V"), - (0x37, "V"), - (0x38, "V"), - (0x39, "V"), - (0x3A, "V"), - (0x3B, "V"), - (0x3C, "V"), - (0x3D, "V"), - (0x3E, "V"), - (0x3F, "V"), - (0x40, "V"), - (0x41, "M", "a"), - (0x42, "M", "b"), - (0x43, "M", "c"), - (0x44, "M", "d"), - (0x45, "M", "e"), - (0x46, "M", "f"), - (0x47, "M", "g"), - (0x48, "M", "h"), - (0x49, "M", "i"), - (0x4A, "M", "j"), - (0x4B, "M", "k"), - (0x4C, "M", "l"), - (0x4D, "M", "m"), - (0x4E, "M", "n"), - (0x4F, "M", "o"), - (0x50, "M", "p"), - (0x51, "M", "q"), - (0x52, "M", "r"), - (0x53, "M", "s"), - (0x54, "M", "t"), - (0x55, "M", "u"), - (0x56, "M", "v"), - (0x57, "M", "w"), - (0x58, "M", "x"), - (0x59, "M", "y"), - (0x5A, "M", "z"), - (0x5B, "V"), - (0x5C, "V"), - (0x5D, "V"), - (0x5E, "V"), - (0x5F, "V"), - (0x60, "V"), - (0x61, "V"), - (0x62, "V"), - (0x63, "V"), - (0x64, "V"), - (0x65, "V"), - (0x66, "V"), - (0x67, "V"), - (0x68, "V"), - (0x69, "V"), - (0x6A, "V"), - (0x6B, "V"), - (0x6C, "V"), - (0x6D, "V"), - (0x6E, "V"), - (0x6F, "V"), - (0x70, "V"), - (0x71, "V"), - (0x72, "V"), - (0x73, "V"), - (0x74, "V"), - (0x75, "V"), - (0x76, "V"), - (0x77, "V"), - (0x78, "V"), - (0x79, "V"), - (0x7A, "V"), - (0x7B, "V"), - (0x7C, "V"), - (0x7D, "V"), - (0x7E, "V"), - (0x7F, "V"), - (0x80, "X"), - (0x81, "X"), - (0x82, "X"), - (0x83, "X"), - (0x84, "X"), - (0x85, "X"), - (0x86, "X"), - (0x87, "X"), - (0x88, "X"), - (0x89, "X"), - (0x8A, "X"), - (0x8B, "X"), - (0x8C, "X"), - (0x8D, "X"), - (0x8E, "X"), - (0x8F, "X"), - (0x90, "X"), - (0x91, "X"), - (0x92, "X"), - (0x93, "X"), - (0x94, "X"), - (0x95, "X"), - (0x96, "X"), - (0x97, "X"), - (0x98, "X"), - (0x99, "X"), - (0x9A, "X"), - (0x9B, "X"), - (0x9C, "X"), - (0x9D, "X"), - (0x9E, "X"), - (0x9F, "X"), - (0xA0, "M", " "), - (0xA1, "V"), - (0xA2, "V"), - (0xA3, "V"), - (0xA4, "V"), - (0xA5, "V"), - (0xA6, "V"), - (0xA7, "V"), - (0xA8, "M", " ̈"), - (0xA9, "V"), - (0xAA, "M", "a"), - (0xAB, "V"), - (0xAC, "V"), - (0xAD, "I"), - (0xAE, "V"), - (0xAF, "M", " ̄"), - (0xB0, "V"), - (0xB1, "V"), - (0xB2, "M", "2"), - (0xB3, "M", "3"), - (0xB4, "M", " ́"), - (0xB5, "M", "μ"), - (0xB6, "V"), - (0xB7, "V"), - (0xB8, "M", " ̧"), - (0xB9, "M", "1"), - (0xBA, "M", "o"), - (0xBB, "V"), - (0xBC, "M", "1⁄4"), - (0xBD, "M", "1⁄2"), - (0xBE, "M", "3⁄4"), - (0xBF, "V"), - (0xC0, "M", "à"), - (0xC1, "M", "á"), - (0xC2, "M", "â"), - (0xC3, "M", "ã"), - (0xC4, "M", "ä"), - (0xC5, "M", "å"), - (0xC6, "M", "æ"), - (0xC7, "M", "ç"), - (0xC8, "M", "è"), - (0xC9, "M", "é"), - (0xCA, "M", "ê"), - (0xCB, "M", "ë"), - (0xCC, "M", "ì"), - (0xCD, "M", "í"), - (0xCE, "M", "î"), - (0xCF, "M", "ï"), - (0xD0, "M", "ð"), - (0xD1, "M", "ñ"), - (0xD2, "M", "ò"), - (0xD3, "M", "ó"), - (0xD4, "M", "ô"), - (0xD5, "M", "õ"), - (0xD6, "M", "ö"), - (0xD7, "V"), - (0xD8, "M", "ø"), - (0xD9, "M", "ù"), - (0xDA, "M", "ú"), - (0xDB, "M", "û"), - (0xDC, "M", "ü"), - (0xDD, "M", "ý"), - (0xDE, "M", "þ"), - (0xDF, "D", "ss"), - (0xE0, "V"), - (0xE1, "V"), - (0xE2, "V"), - (0xE3, "V"), - (0xE4, "V"), - (0xE5, "V"), - (0xE6, "V"), - (0xE7, "V"), - (0xE8, "V"), - (0xE9, "V"), - (0xEA, "V"), - (0xEB, "V"), - (0xEC, "V"), - (0xED, "V"), - (0xEE, "V"), - (0xEF, "V"), - (0xF0, "V"), - (0xF1, "V"), - (0xF2, "V"), - (0xF3, "V"), - (0xF4, "V"), - (0xF5, "V"), - (0xF6, "V"), - (0xF7, "V"), - (0xF8, "V"), - (0xF9, "V"), - (0xFA, "V"), - (0xFB, "V"), - (0xFC, "V"), - (0xFD, "V"), - (0xFE, "V"), - (0xFF, "V"), - (0x100, "M", "ā"), - (0x101, "V"), - (0x102, "M", "ă"), - (0x103, "V"), - (0x104, "M", "ą"), - (0x105, "V"), - (0x106, "M", "ć"), - (0x107, "V"), - (0x108, "M", "ĉ"), - (0x109, "V"), - (0x10A, "M", "ċ"), - (0x10B, "V"), - (0x10C, "M", "č"), - (0x10D, "V"), - (0x10E, "M", "ď"), - (0x10F, "V"), - (0x110, "M", "đ"), - (0x111, "V"), - (0x112, "M", "ē"), - (0x113, "V"), - (0x114, "M", "ĕ"), - (0x115, "V"), - (0x116, "M", "ė"), - (0x117, "V"), - (0x118, "M", "ę"), - (0x119, "V"), - (0x11A, "M", "ě"), - (0x11B, "V"), - (0x11C, "M", "ĝ"), - (0x11D, "V"), - (0x11E, "M", "ğ"), - (0x11F, "V"), - (0x120, "M", "ġ"), - (0x121, "V"), - (0x122, "M", "ģ"), - (0x123, "V"), - (0x124, "M", "ĥ"), - (0x125, "V"), - (0x126, "M", "ħ"), - (0x127, "V"), - (0x128, "M", "ĩ"), - (0x129, "V"), - (0x12A, "M", "ī"), - (0x12B, "V"), - (0x12C, "M", "ĭ"), - (0x12D, "V"), - (0x12E, "M", "į"), - (0x12F, "V"), - (0x130, "M", "i̇"), - (0x131, "V"), - (0x132, "M", "ij"), - (0x134, "M", "ĵ"), - (0x135, "V"), - (0x136, "M", "ķ"), - (0x137, "V"), - (0x139, "M", "ĺ"), - (0x13A, "V"), - (0x13B, "M", "ļ"), - (0x13C, "V"), - (0x13D, "M", "ľ"), - (0x13E, "V"), - (0x13F, "M", "l·"), - (0x141, "M", "ł"), - (0x142, "V"), - (0x143, "M", "ń"), - (0x144, "V"), - (0x145, "M", "ņ"), - (0x146, "V"), - (0x147, "M", "ň"), - (0x148, "V"), - (0x149, "M", "ʼn"), - (0x14A, "M", "ŋ"), - (0x14B, "V"), - (0x14C, "M", "ō"), - (0x14D, "V"), - (0x14E, "M", "ŏ"), - (0x14F, "V"), - (0x150, "M", "ő"), - (0x151, "V"), - (0x152, "M", "œ"), - (0x153, "V"), - (0x154, "M", "ŕ"), - (0x155, "V"), - (0x156, "M", "ŗ"), - (0x157, "V"), - (0x158, "M", "ř"), - (0x159, "V"), - (0x15A, "M", "ś"), - (0x15B, "V"), - (0x15C, "M", "ŝ"), - (0x15D, "V"), - (0x15E, "M", "ş"), - (0x15F, "V"), - (0x160, "M", "š"), - (0x161, "V"), - (0x162, "M", "ţ"), - (0x163, "V"), - (0x164, "M", "ť"), - (0x165, "V"), - (0x166, "M", "ŧ"), - (0x167, "V"), - (0x168, "M", "ũ"), - (0x169, "V"), - (0x16A, "M", "ū"), - (0x16B, "V"), - (0x16C, "M", "ŭ"), - (0x16D, "V"), - (0x16E, "M", "ů"), - (0x16F, "V"), - (0x170, "M", "ű"), - (0x171, "V"), - (0x172, "M", "ų"), - (0x173, "V"), - (0x174, "M", "ŵ"), - (0x175, "V"), - (0x176, "M", "ŷ"), - (0x177, "V"), - (0x178, "M", "ÿ"), - (0x179, "M", "ź"), - (0x17A, "V"), - (0x17B, "M", "ż"), - (0x17C, "V"), - (0x17D, "M", "ž"), - (0x17E, "V"), - (0x17F, "M", "s"), - (0x180, "V"), - (0x181, "M", "ɓ"), - (0x182, "M", "ƃ"), - (0x183, "V"), - (0x184, "M", "ƅ"), - (0x185, "V"), - (0x186, "M", "ɔ"), - (0x187, "M", "ƈ"), - (0x188, "V"), - (0x189, "M", "ɖ"), - (0x18A, "M", "ɗ"), - (0x18B, "M", "ƌ"), - (0x18C, "V"), - (0x18E, "M", "ǝ"), - (0x18F, "M", "ə"), - (0x190, "M", "ɛ"), - (0x191, "M", "ƒ"), - (0x192, "V"), - (0x193, "M", "ɠ"), - (0x194, "M", "ɣ"), - (0x195, "V"), - (0x196, "M", "ɩ"), - (0x197, "M", "ɨ"), - (0x198, "M", "ƙ"), - (0x199, "V"), - (0x19C, "M", "ɯ"), - (0x19D, "M", "ɲ"), - (0x19E, "V"), - (0x19F, "M", "ɵ"), - (0x1A0, "M", "ơ"), - (0x1A1, "V"), - (0x1A2, "M", "ƣ"), - (0x1A3, "V"), - (0x1A4, "M", "ƥ"), - (0x1A5, "V"), - (0x1A6, "M", "ʀ"), - (0x1A7, "M", "ƨ"), - (0x1A8, "V"), - (0x1A9, "M", "ʃ"), - (0x1AA, "V"), - (0x1AC, "M", "ƭ"), - (0x1AD, "V"), - (0x1AE, "M", "ʈ"), - (0x1AF, "M", "ư"), - (0x1B0, "V"), - (0x1B1, "M", "ʊ"), - (0x1B2, "M", "ʋ"), - (0x1B3, "M", "ƴ"), - (0x1B4, "V"), - (0x1B5, "M", "ƶ"), - (0x1B6, "V"), - (0x1B7, "M", "ʒ"), - (0x1B8, "M", "ƹ"), - (0x1B9, "V"), - (0x1BC, "M", "ƽ"), - (0x1BD, "V"), - (0x1C4, "M", "dž"), - (0x1C7, "M", "lj"), - (0x1CA, "M", "nj"), - (0x1CD, "M", "ǎ"), - (0x1CE, "V"), - (0x1CF, "M", "ǐ"), - (0x1D0, "V"), - (0x1D1, "M", "ǒ"), - (0x1D2, "V"), - (0x1D3, "M", "ǔ"), - (0x1D4, "V"), - (0x1D5, "M", "ǖ"), - (0x1D6, "V"), - (0x1D7, "M", "ǘ"), - (0x1D8, "V"), - (0x1D9, "M", "ǚ"), - (0x1DA, "V"), - (0x1DB, "M", "ǜ"), - (0x1DC, "V"), - (0x1DE, "M", "ǟ"), - (0x1DF, "V"), - (0x1E0, "M", "ǡ"), - (0x1E1, "V"), - (0x1E2, "M", "ǣ"), - (0x1E3, "V"), - (0x1E4, "M", "ǥ"), - (0x1E5, "V"), - (0x1E6, "M", "ǧ"), - (0x1E7, "V"), - (0x1E8, "M", "ǩ"), - (0x1E9, "V"), - (0x1EA, "M", "ǫ"), - (0x1EB, "V"), - (0x1EC, "M", "ǭ"), - (0x1ED, "V"), - (0x1EE, "M", "ǯ"), - (0x1EF, "V"), - (0x1F1, "M", "dz"), - (0x1F4, "M", "ǵ"), - (0x1F5, "V"), - (0x1F6, "M", "ƕ"), - (0x1F7, "M", "ƿ"), - (0x1F8, "M", "ǹ"), - (0x1F9, "V"), - (0x1FA, "M", "ǻ"), - (0x1FB, "V"), - (0x1FC, "M", "ǽ"), - (0x1FD, "V"), - (0x1FE, "M", "ǿ"), - (0x1FF, "V"), - (0x200, "M", "ȁ"), - (0x201, "V"), - (0x202, "M", "ȃ"), - (0x203, "V"), - (0x204, "M", "ȅ"), - (0x205, "V"), - (0x206, "M", "ȇ"), - (0x207, "V"), - (0x208, "M", "ȉ"), - (0x209, "V"), - (0x20A, "M", "ȋ"), - (0x20B, "V"), - (0x20C, "M", "ȍ"), - (0x20D, "V"), - (0x20E, "M", "ȏ"), - (0x20F, "V"), - (0x210, "M", "ȑ"), - (0x211, "V"), - (0x212, "M", "ȓ"), - (0x213, "V"), - (0x214, "M", "ȕ"), - (0x215, "V"), - (0x216, "M", "ȗ"), - (0x217, "V"), - (0x218, "M", "ș"), - (0x219, "V"), - (0x21A, "M", "ț"), - (0x21B, "V"), - (0x21C, "M", "ȝ"), - (0x21D, "V"), - (0x21E, "M", "ȟ"), - (0x21F, "V"), - (0x220, "M", "ƞ"), - (0x221, "V"), - (0x222, "M", "ȣ"), - (0x223, "V"), - (0x224, "M", "ȥ"), - (0x225, "V"), - (0x226, "M", "ȧ"), - (0x227, "V"), - (0x228, "M", "ȩ"), - (0x229, "V"), - (0x22A, "M", "ȫ"), - (0x22B, "V"), - (0x22C, "M", "ȭ"), - (0x22D, "V"), - (0x22E, "M", "ȯ"), - (0x22F, "V"), - (0x230, "M", "ȱ"), - (0x231, "V"), - (0x232, "M", "ȳ"), - (0x233, "V"), - (0x23A, "M", "ⱥ"), - (0x23B, "M", "ȼ"), - (0x23C, "V"), - (0x23D, "M", "ƚ"), - (0x23E, "M", "ⱦ"), - (0x23F, "V"), - (0x241, "M", "ɂ"), - (0x242, "V"), - (0x243, "M", "ƀ"), - (0x244, "M", "ʉ"), - (0x245, "M", "ʌ"), - (0x246, "M", "ɇ"), - (0x247, "V"), - (0x248, "M", "ɉ"), - (0x249, "V"), - (0x24A, "M", "ɋ"), - (0x24B, "V"), - (0x24C, "M", "ɍ"), - (0x24D, "V"), - (0x24E, "M", "ɏ"), - (0x24F, "V"), - (0x2B0, "M", "h"), - (0x2B1, "M", "ɦ"), - (0x2B2, "M", "j"), - (0x2B3, "M", "r"), - (0x2B4, "M", "ɹ"), - (0x2B5, "M", "ɻ"), - (0x2B6, "M", "ʁ"), - (0x2B7, "M", "w"), - (0x2B8, "M", "y"), - (0x2B9, "V"), - (0x2D8, "M", " ̆"), - (0x2D9, "M", " ̇"), - (0x2DA, "M", " ̊"), - (0x2DB, "M", " ̨"), - (0x2DC, "M", " ̃"), - (0x2DD, "M", " ̋"), - (0x2DE, "V"), - (0x2E0, "M", "ɣ"), - (0x2E1, "M", "l"), - (0x2E2, "M", "s"), - (0x2E3, "M", "x"), - (0x2E4, "M", "ʕ"), - (0x2E5, "V"), - (0x340, "M", "̀"), - (0x341, "M", "́"), - (0x342, "V"), - (0x343, "M", "̓"), - (0x344, "M", "̈́"), - (0x345, "M", "ι"), - (0x346, "V"), - (0x34F, "I"), - (0x350, "V"), - (0x370, "M", "ͱ"), - (0x371, "V"), - (0x372, "M", "ͳ"), - (0x373, "V"), - (0x374, "M", "ʹ"), - (0x375, "V"), - (0x376, "M", "ͷ"), - (0x377, "V"), - (0x378, "X"), - (0x37A, "M", " ι"), - (0x37B, "V"), - (0x37E, "M", ";"), - (0x37F, "M", "ϳ"), - (0x380, "X"), - (0x384, "M", " ́"), - (0x385, "M", " ̈́"), - (0x386, "M", "ά"), - (0x387, "M", "·"), - (0x388, "M", "έ"), - (0x389, "M", "ή"), - (0x38A, "M", "ί"), - (0x38B, "X"), - (0x38C, "M", "ό"), - (0x38D, "X"), - (0x38E, "M", "ύ"), - (0x38F, "M", "ώ"), - (0x390, "V"), - (0x391, "M", "α"), - (0x392, "M", "β"), - (0x393, "M", "γ"), - (0x394, "M", "δ"), - (0x395, "M", "ε"), - (0x396, "M", "ζ"), - (0x397, "M", "η"), - (0x398, "M", "θ"), - (0x399, "M", "ι"), - (0x39A, "M", "κ"), - (0x39B, "M", "λ"), - (0x39C, "M", "μ"), - (0x39D, "M", "ν"), - (0x39E, "M", "ξ"), - (0x39F, "M", "ο"), - (0x3A0, "M", "π"), - (0x3A1, "M", "ρ"), - (0x3A2, "X"), - (0x3A3, "M", "σ"), - (0x3A4, "M", "τ"), - (0x3A5, "M", "υ"), - (0x3A6, "M", "φ"), - (0x3A7, "M", "χ"), - (0x3A8, "M", "ψ"), - (0x3A9, "M", "ω"), - (0x3AA, "M", "ϊ"), - (0x3AB, "M", "ϋ"), - (0x3AC, "V"), - (0x3C2, "D", "σ"), - (0x3C3, "V"), - (0x3CF, "M", "ϗ"), - (0x3D0, "M", "β"), - (0x3D1, "M", "θ"), - (0x3D2, "M", "υ"), - (0x3D3, "M", "ύ"), - (0x3D4, "M", "ϋ"), - (0x3D5, "M", "φ"), - (0x3D6, "M", "π"), - (0x3D7, "V"), - (0x3D8, "M", "ϙ"), - (0x3D9, "V"), - (0x3DA, "M", "ϛ"), - (0x3DB, "V"), - (0x3DC, "M", "ϝ"), - (0x3DD, "V"), - (0x3DE, "M", "ϟ"), - (0x3DF, "V"), - (0x3E0, "M", "ϡ"), - (0x3E1, "V"), - (0x3E2, "M", "ϣ"), - (0x3E3, "V"), - (0x3E4, "M", "ϥ"), - (0x3E5, "V"), - (0x3E6, "M", "ϧ"), - (0x3E7, "V"), - (0x3E8, "M", "ϩ"), - (0x3E9, "V"), - (0x3EA, "M", "ϫ"), - (0x3EB, "V"), - (0x3EC, "M", "ϭ"), - (0x3ED, "V"), - (0x3EE, "M", "ϯ"), - (0x3EF, "V"), - (0x3F0, "M", "κ"), - (0x3F1, "M", "ρ"), - (0x3F2, "M", "σ"), - (0x3F3, "V"), - (0x3F4, "M", "θ"), - (0x3F5, "M", "ε"), - (0x3F6, "V"), - (0x3F7, "M", "ϸ"), - (0x3F8, "V"), - (0x3F9, "M", "σ"), - (0x3FA, "M", "ϻ"), - (0x3FB, "V"), - (0x3FD, "M", "ͻ"), - (0x3FE, "M", "ͼ"), - (0x3FF, "M", "ͽ"), - (0x400, "M", "ѐ"), - (0x401, "M", "ё"), - (0x402, "M", "ђ"), - (0x403, "M", "ѓ"), - (0x404, "M", "є"), - (0x405, "M", "ѕ"), - (0x406, "M", "і"), - (0x407, "M", "ї"), - (0x408, "M", "ј"), - (0x409, "M", "љ"), - (0x40A, "M", "њ"), - (0x40B, "M", "ћ"), - (0x40C, "M", "ќ"), - (0x40D, "M", "ѝ"), - (0x40E, "M", "ў"), - (0x40F, "M", "џ"), - (0x410, "M", "а"), - (0x411, "M", "б"), - (0x412, "M", "в"), - (0x413, "M", "г"), - (0x414, "M", "д"), - (0x415, "M", "е"), - (0x416, "M", "ж"), - (0x417, "M", "з"), - (0x418, "M", "и"), - (0x419, "M", "й"), - (0x41A, "M", "к"), - (0x41B, "M", "л"), - (0x41C, "M", "м"), - (0x41D, "M", "н"), - (0x41E, "M", "о"), - (0x41F, "M", "п"), - (0x420, "M", "р"), - (0x421, "M", "с"), - (0x422, "M", "т"), - (0x423, "M", "у"), - (0x424, "M", "ф"), - (0x425, "M", "х"), - (0x426, "M", "ц"), - (0x427, "M", "ч"), - (0x428, "M", "ш"), - (0x429, "M", "щ"), - (0x42A, "M", "ъ"), - (0x42B, "M", "ы"), - (0x42C, "M", "ь"), - (0x42D, "M", "э"), - (0x42E, "M", "ю"), - (0x42F, "M", "я"), - (0x430, "V"), - (0x460, "M", "ѡ"), - (0x461, "V"), - (0x462, "M", "ѣ"), - (0x463, "V"), - (0x464, "M", "ѥ"), - (0x465, "V"), - (0x466, "M", "ѧ"), - (0x467, "V"), - (0x468, "M", "ѩ"), - (0x469, "V"), - (0x46A, "M", "ѫ"), - (0x46B, "V"), - (0x46C, "M", "ѭ"), - (0x46D, "V"), - (0x46E, "M", "ѯ"), - (0x46F, "V"), - (0x470, "M", "ѱ"), - (0x471, "V"), - (0x472, "M", "ѳ"), - (0x473, "V"), - (0x474, "M", "ѵ"), - (0x475, "V"), - (0x476, "M", "ѷ"), - (0x477, "V"), - (0x478, "M", "ѹ"), - (0x479, "V"), - (0x47A, "M", "ѻ"), - (0x47B, "V"), - (0x47C, "M", "ѽ"), - (0x47D, "V"), - (0x47E, "M", "ѿ"), - (0x47F, "V"), - (0x480, "M", "ҁ"), - (0x481, "V"), - (0x48A, "M", "ҋ"), - (0x48B, "V"), - (0x48C, "M", "ҍ"), - (0x48D, "V"), - (0x48E, "M", "ҏ"), - (0x48F, "V"), - (0x490, "M", "ґ"), - (0x491, "V"), - (0x492, "M", "ғ"), - (0x493, "V"), - (0x494, "M", "ҕ"), - (0x495, "V"), - (0x496, "M", "җ"), - (0x497, "V"), - (0x498, "M", "ҙ"), - (0x499, "V"), - (0x49A, "M", "қ"), - (0x49B, "V"), - (0x49C, "M", "ҝ"), - (0x49D, "V"), - (0x49E, "M", "ҟ"), - (0x49F, "V"), - (0x4A0, "M", "ҡ"), - (0x4A1, "V"), - (0x4A2, "M", "ң"), - (0x4A3, "V"), - (0x4A4, "M", "ҥ"), - (0x4A5, "V"), - (0x4A6, "M", "ҧ"), - (0x4A7, "V"), - (0x4A8, "M", "ҩ"), - (0x4A9, "V"), - (0x4AA, "M", "ҫ"), - (0x4AB, "V"), - (0x4AC, "M", "ҭ"), - (0x4AD, "V"), - (0x4AE, "M", "ү"), - (0x4AF, "V"), - (0x4B0, "M", "ұ"), - (0x4B1, "V"), - (0x4B2, "M", "ҳ"), - (0x4B3, "V"), - (0x4B4, "M", "ҵ"), - (0x4B5, "V"), - (0x4B6, "M", "ҷ"), - (0x4B7, "V"), - (0x4B8, "M", "ҹ"), - (0x4B9, "V"), - (0x4BA, "M", "һ"), - (0x4BB, "V"), - (0x4BC, "M", "ҽ"), - (0x4BD, "V"), - (0x4BE, "M", "ҿ"), - (0x4BF, "V"), - (0x4C0, "M", "ӏ"), - (0x4C1, "M", "ӂ"), - (0x4C2, "V"), - (0x4C3, "M", "ӄ"), - (0x4C4, "V"), - (0x4C5, "M", "ӆ"), - (0x4C6, "V"), - (0x4C7, "M", "ӈ"), - (0x4C8, "V"), - (0x4C9, "M", "ӊ"), - (0x4CA, "V"), - (0x4CB, "M", "ӌ"), - (0x4CC, "V"), - (0x4CD, "M", "ӎ"), - (0x4CE, "V"), - (0x4D0, "M", "ӑ"), - (0x4D1, "V"), - (0x4D2, "M", "ӓ"), - (0x4D3, "V"), - (0x4D4, "M", "ӕ"), - (0x4D5, "V"), - (0x4D6, "M", "ӗ"), - (0x4D7, "V"), - (0x4D8, "M", "ә"), - (0x4D9, "V"), - (0x4DA, "M", "ӛ"), - (0x4DB, "V"), - (0x4DC, "M", "ӝ"), - (0x4DD, "V"), - (0x4DE, "M", "ӟ"), - (0x4DF, "V"), - (0x4E0, "M", "ӡ"), - (0x4E1, "V"), - (0x4E2, "M", "ӣ"), - (0x4E3, "V"), - (0x4E4, "M", "ӥ"), - (0x4E5, "V"), - (0x4E6, "M", "ӧ"), - (0x4E7, "V"), - (0x4E8, "M", "ө"), - (0x4E9, "V"), - (0x4EA, "M", "ӫ"), - (0x4EB, "V"), - (0x4EC, "M", "ӭ"), - (0x4ED, "V"), - (0x4EE, "M", "ӯ"), - (0x4EF, "V"), - (0x4F0, "M", "ӱ"), - (0x4F1, "V"), - (0x4F2, "M", "ӳ"), - (0x4F3, "V"), - (0x4F4, "M", "ӵ"), - (0x4F5, "V"), - (0x4F6, "M", "ӷ"), - (0x4F7, "V"), - (0x4F8, "M", "ӹ"), - (0x4F9, "V"), - (0x4FA, "M", "ӻ"), - (0x4FB, "V"), - (0x4FC, "M", "ӽ"), - (0x4FD, "V"), - (0x4FE, "M", "ӿ"), - (0x4FF, "V"), - (0x500, "M", "ԁ"), - (0x501, "V"), - (0x502, "M", "ԃ"), - (0x503, "V"), - (0x504, "M", "ԅ"), - (0x505, "V"), - (0x506, "M", "ԇ"), - (0x507, "V"), - (0x508, "M", "ԉ"), - (0x509, "V"), - (0x50A, "M", "ԋ"), - (0x50B, "V"), - (0x50C, "M", "ԍ"), - (0x50D, "V"), - (0x50E, "M", "ԏ"), - (0x50F, "V"), - (0x510, "M", "ԑ"), - (0x511, "V"), - (0x512, "M", "ԓ"), - (0x513, "V"), - (0x514, "M", "ԕ"), - (0x515, "V"), - (0x516, "M", "ԗ"), - (0x517, "V"), - (0x518, "M", "ԙ"), - (0x519, "V"), - (0x51A, "M", "ԛ"), - (0x51B, "V"), - (0x51C, "M", "ԝ"), - (0x51D, "V"), - (0x51E, "M", "ԟ"), - (0x51F, "V"), - (0x520, "M", "ԡ"), - (0x521, "V"), - (0x522, "M", "ԣ"), - (0x523, "V"), - (0x524, "M", "ԥ"), - (0x525, "V"), - (0x526, "M", "ԧ"), - (0x527, "V"), - (0x528, "M", "ԩ"), - (0x529, "V"), - (0x52A, "M", "ԫ"), - (0x52B, "V"), - (0x52C, "M", "ԭ"), - (0x52D, "V"), - (0x52E, "M", "ԯ"), - (0x52F, "V"), - (0x530, "X"), - (0x531, "M", "ա"), - (0x532, "M", "բ"), - (0x533, "M", "գ"), - (0x534, "M", "դ"), - (0x535, "M", "ե"), - (0x536, "M", "զ"), - (0x537, "M", "է"), - (0x538, "M", "ը"), - (0x539, "M", "թ"), - (0x53A, "M", "ժ"), - (0x53B, "M", "ի"), - (0x53C, "M", "լ"), - (0x53D, "M", "խ"), - (0x53E, "M", "ծ"), - (0x53F, "M", "կ"), - (0x540, "M", "հ"), - (0x541, "M", "ձ"), - (0x542, "M", "ղ"), - (0x543, "M", "ճ"), - (0x544, "M", "մ"), - (0x545, "M", "յ"), - (0x546, "M", "ն"), - (0x547, "M", "շ"), - (0x548, "M", "ո"), - (0x549, "M", "չ"), - (0x54A, "M", "պ"), - (0x54B, "M", "ջ"), - (0x54C, "M", "ռ"), - (0x54D, "M", "ս"), - (0x54E, "M", "վ"), - (0x54F, "M", "տ"), - (0x550, "M", "ր"), - (0x551, "M", "ց"), - (0x552, "M", "ւ"), - (0x553, "M", "փ"), - (0x554, "M", "ք"), - (0x555, "M", "օ"), - (0x556, "M", "ֆ"), - (0x557, "X"), - (0x559, "V"), - (0x587, "M", "եւ"), - (0x588, "V"), - (0x58B, "X"), - (0x58D, "V"), - (0x590, "X"), - (0x591, "V"), - (0x5C8, "X"), - (0x5D0, "V"), - (0x5EB, "X"), - (0x5EF, "V"), - (0x5F5, "X"), - (0x606, "V"), - (0x61C, "X"), - (0x61D, "V"), - (0x675, "M", "اٴ"), - (0x676, "M", "وٴ"), - (0x677, "M", "ۇٴ"), - (0x678, "M", "يٴ"), - (0x679, "V"), - (0x6DD, "X"), - (0x6DE, "V"), - (0x70E, "X"), - (0x710, "V"), - (0x74B, "X"), - (0x74D, "V"), - (0x7B2, "X"), - (0x7C0, "V"), - (0x7FB, "X"), - (0x7FD, "V"), - (0x82E, "X"), - (0x830, "V"), - (0x83F, "X"), - (0x840, "V"), - (0x85C, "X"), - (0x85E, "V"), - (0x85F, "X"), - (0x860, "V"), - (0x86B, "X"), - (0x870, "V"), - (0x890, "X"), - (0x897, "V"), - (0x8E2, "X"), - (0x8E3, "V"), - (0x958, "M", "क़"), - (0x959, "M", "ख़"), - (0x95A, "M", "ग़"), - (0x95B, "M", "ज़"), - (0x95C, "M", "ड़"), - (0x95D, "M", "ढ़"), - (0x95E, "M", "फ़"), - (0x95F, "M", "य़"), - (0x960, "V"), - (0x984, "X"), - (0x985, "V"), - (0x98D, "X"), - (0x98F, "V"), - (0x991, "X"), - (0x993, "V"), - (0x9A9, "X"), - (0x9AA, "V"), - (0x9B1, "X"), - (0x9B2, "V"), - (0x9B3, "X"), - (0x9B6, "V"), - (0x9BA, "X"), - (0x9BC, "V"), - (0x9C5, "X"), - (0x9C7, "V"), - (0x9C9, "X"), - (0x9CB, "V"), - (0x9CF, "X"), - (0x9D7, "V"), - (0x9D8, "X"), - (0x9DC, "M", "ড়"), - (0x9DD, "M", "ঢ়"), - (0x9DE, "X"), - (0x9DF, "M", "য়"), - (0x9E0, "V"), - (0x9E4, "X"), - (0x9E6, "V"), - (0x9FF, "X"), - (0xA01, "V"), - (0xA04, "X"), - (0xA05, "V"), - (0xA0B, "X"), - (0xA0F, "V"), - (0xA11, "X"), - (0xA13, "V"), - (0xA29, "X"), - (0xA2A, "V"), - (0xA31, "X"), - (0xA32, "V"), - (0xA33, "M", "ਲ਼"), - (0xA34, "X"), - (0xA35, "V"), - (0xA36, "M", "ਸ਼"), - (0xA37, "X"), - (0xA38, "V"), - (0xA3A, "X"), - (0xA3C, "V"), - (0xA3D, "X"), - (0xA3E, "V"), - (0xA43, "X"), - (0xA47, "V"), - (0xA49, "X"), - (0xA4B, "V"), - (0xA4E, "X"), - (0xA51, "V"), - (0xA52, "X"), - (0xA59, "M", "ਖ਼"), - (0xA5A, "M", "ਗ਼"), - (0xA5B, "M", "ਜ਼"), - (0xA5C, "V"), - (0xA5D, "X"), - (0xA5E, "M", "ਫ਼"), - (0xA5F, "X"), - (0xA66, "V"), - (0xA77, "X"), - (0xA81, "V"), - (0xA84, "X"), - (0xA85, "V"), - (0xA8E, "X"), - (0xA8F, "V"), - (0xA92, "X"), - (0xA93, "V"), - (0xAA9, "X"), - (0xAAA, "V"), - (0xAB1, "X"), - (0xAB2, "V"), - (0xAB4, "X"), - (0xAB5, "V"), - (0xABA, "X"), - (0xABC, "V"), - (0xAC6, "X"), - (0xAC7, "V"), - (0xACA, "X"), - (0xACB, "V"), - (0xACE, "X"), - (0xAD0, "V"), - (0xAD1, "X"), - (0xAE0, "V"), - (0xAE4, "X"), - (0xAE6, "V"), - (0xAF2, "X"), - (0xAF9, "V"), - (0xB00, "X"), - (0xB01, "V"), - (0xB04, "X"), - (0xB05, "V"), - (0xB0D, "X"), - (0xB0F, "V"), - (0xB11, "X"), - (0xB13, "V"), - (0xB29, "X"), - (0xB2A, "V"), - (0xB31, "X"), - (0xB32, "V"), - (0xB34, "X"), - (0xB35, "V"), - (0xB3A, "X"), - (0xB3C, "V"), - (0xB45, "X"), - (0xB47, "V"), - (0xB49, "X"), - (0xB4B, "V"), - (0xB4E, "X"), - (0xB55, "V"), - (0xB58, "X"), - (0xB5C, "M", "ଡ଼"), - (0xB5D, "M", "ଢ଼"), - (0xB5E, "X"), - (0xB5F, "V"), - (0xB64, "X"), - (0xB66, "V"), - (0xB78, "X"), - (0xB82, "V"), - (0xB84, "X"), - (0xB85, "V"), - (0xB8B, "X"), - (0xB8E, "V"), - (0xB91, "X"), - (0xB92, "V"), - (0xB96, "X"), - (0xB99, "V"), - (0xB9B, "X"), - (0xB9C, "V"), - (0xB9D, "X"), - (0xB9E, "V"), - (0xBA0, "X"), - (0xBA3, "V"), - (0xBA5, "X"), - (0xBA8, "V"), - (0xBAB, "X"), - (0xBAE, "V"), - (0xBBA, "X"), - (0xBBE, "V"), - (0xBC3, "X"), - (0xBC6, "V"), - (0xBC9, "X"), - (0xBCA, "V"), - (0xBCE, "X"), - (0xBD0, "V"), - (0xBD1, "X"), - (0xBD7, "V"), - (0xBD8, "X"), - (0xBE6, "V"), - (0xBFB, "X"), - (0xC00, "V"), - (0xC0D, "X"), - (0xC0E, "V"), - (0xC11, "X"), - (0xC12, "V"), - (0xC29, "X"), - (0xC2A, "V"), - (0xC3A, "X"), - (0xC3C, "V"), - (0xC45, "X"), - (0xC46, "V"), - (0xC49, "X"), - (0xC4A, "V"), - (0xC4E, "X"), - (0xC55, "V"), - (0xC57, "X"), - (0xC58, "V"), - (0xC5B, "X"), - (0xC5C, "V"), - (0xC5E, "X"), - (0xC60, "V"), - (0xC64, "X"), - (0xC66, "V"), - (0xC70, "X"), - (0xC77, "V"), - (0xC8D, "X"), - (0xC8E, "V"), - (0xC91, "X"), - (0xC92, "V"), - (0xCA9, "X"), - (0xCAA, "V"), - (0xCB4, "X"), - (0xCB5, "V"), - (0xCBA, "X"), - (0xCBC, "V"), - (0xCC5, "X"), - (0xCC6, "V"), - (0xCC9, "X"), - (0xCCA, "V"), - (0xCCE, "X"), - (0xCD5, "V"), - (0xCD7, "X"), - (0xCDC, "V"), - (0xCDF, "X"), - (0xCE0, "V"), - (0xCE4, "X"), - (0xCE6, "V"), - (0xCF0, "X"), - (0xCF1, "V"), - (0xCF4, "X"), - (0xD00, "V"), - (0xD0D, "X"), - (0xD0E, "V"), - (0xD11, "X"), - (0xD12, "V"), - (0xD45, "X"), - (0xD46, "V"), - (0xD49, "X"), - (0xD4A, "V"), - (0xD50, "X"), - (0xD54, "V"), - (0xD64, "X"), - (0xD66, "V"), - (0xD80, "X"), - (0xD81, "V"), - (0xD84, "X"), - (0xD85, "V"), - (0xD97, "X"), - (0xD9A, "V"), - (0xDB2, "X"), - (0xDB3, "V"), - (0xDBC, "X"), - (0xDBD, "V"), - (0xDBE, "X"), - (0xDC0, "V"), - (0xDC7, "X"), - (0xDCA, "V"), - (0xDCB, "X"), - (0xDCF, "V"), - (0xDD5, "X"), - (0xDD6, "V"), - (0xDD7, "X"), - (0xDD8, "V"), - (0xDE0, "X"), - (0xDE6, "V"), - (0xDF0, "X"), - (0xDF2, "V"), - (0xDF5, "X"), - (0xE01, "V"), - (0xE33, "M", "ํา"), - (0xE34, "V"), - (0xE3B, "X"), - (0xE3F, "V"), - (0xE5C, "X"), - (0xE81, "V"), - (0xE83, "X"), - (0xE84, "V"), - (0xE85, "X"), - (0xE86, "V"), - (0xE8B, "X"), - (0xE8C, "V"), - (0xEA4, "X"), - (0xEA5, "V"), - (0xEA6, "X"), - (0xEA7, "V"), - (0xEB3, "M", "ໍາ"), - (0xEB4, "V"), - (0xEBE, "X"), - (0xEC0, "V"), - (0xEC5, "X"), - (0xEC6, "V"), - (0xEC7, "X"), - (0xEC8, "V"), - (0xECF, "X"), - (0xED0, "V"), - (0xEDA, "X"), - (0xEDC, "M", "ຫນ"), - (0xEDD, "M", "ຫມ"), - (0xEDE, "V"), - (0xEE0, "X"), - (0xF00, "V"), - (0xF0C, "M", "་"), - (0xF0D, "V"), - (0xF43, "M", "གྷ"), - (0xF44, "V"), - (0xF48, "X"), - (0xF49, "V"), - (0xF4D, "M", "ཌྷ"), - (0xF4E, "V"), - (0xF52, "M", "དྷ"), - (0xF53, "V"), - (0xF57, "M", "བྷ"), - (0xF58, "V"), - (0xF5C, "M", "ཛྷ"), - (0xF5D, "V"), - (0xF69, "M", "ཀྵ"), - (0xF6A, "V"), - (0xF6D, "X"), - (0xF71, "V"), - (0xF73, "M", "ཱི"), - (0xF74, "V"), - (0xF75, "M", "ཱུ"), - (0xF76, "M", "ྲྀ"), - (0xF77, "M", "ྲཱྀ"), - (0xF78, "M", "ླྀ"), - (0xF79, "M", "ླཱྀ"), - (0xF7A, "V"), - (0xF81, "M", "ཱྀ"), - (0xF82, "V"), - (0xF93, "M", "ྒྷ"), - (0xF94, "V"), - (0xF98, "X"), - (0xF99, "V"), - (0xF9D, "M", "ྜྷ"), - (0xF9E, "V"), - (0xFA2, "M", "ྡྷ"), - (0xFA3, "V"), - (0xFA7, "M", "ྦྷ"), - (0xFA8, "V"), - (0xFAC, "M", "ྫྷ"), - (0xFAD, "V"), - (0xFB9, "M", "ྐྵ"), - (0xFBA, "V"), - (0xFBD, "X"), - (0xFBE, "V"), - (0xFCD, "X"), - (0xFCE, "V"), - (0xFDB, "X"), - (0x1000, "V"), - (0x10A0, "M", "ⴀ"), - (0x10A1, "M", "ⴁ"), - (0x10A2, "M", "ⴂ"), - (0x10A3, "M", "ⴃ"), - (0x10A4, "M", "ⴄ"), - (0x10A5, "M", "ⴅ"), - (0x10A6, "M", "ⴆ"), - (0x10A7, "M", "ⴇ"), - (0x10A8, "M", "ⴈ"), - (0x10A9, "M", "ⴉ"), - (0x10AA, "M", "ⴊ"), - (0x10AB, "M", "ⴋ"), - (0x10AC, "M", "ⴌ"), - (0x10AD, "M", "ⴍ"), - (0x10AE, "M", "ⴎ"), - (0x10AF, "M", "ⴏ"), - (0x10B0, "M", "ⴐ"), - (0x10B1, "M", "ⴑ"), - (0x10B2, "M", "ⴒ"), - (0x10B3, "M", "ⴓ"), - (0x10B4, "M", "ⴔ"), - (0x10B5, "M", "ⴕ"), - (0x10B6, "M", "ⴖ"), - (0x10B7, "M", "ⴗ"), - (0x10B8, "M", "ⴘ"), - (0x10B9, "M", "ⴙ"), - (0x10BA, "M", "ⴚ"), - (0x10BB, "M", "ⴛ"), - (0x10BC, "M", "ⴜ"), - (0x10BD, "M", "ⴝ"), - (0x10BE, "M", "ⴞ"), - (0x10BF, "M", "ⴟ"), - (0x10C0, "M", "ⴠ"), - (0x10C1, "M", "ⴡ"), - (0x10C2, "M", "ⴢ"), - (0x10C3, "M", "ⴣ"), - (0x10C4, "M", "ⴤ"), - (0x10C5, "M", "ⴥ"), - (0x10C6, "X"), - (0x10C7, "M", "ⴧ"), - (0x10C8, "X"), - (0x10CD, "M", "ⴭ"), - (0x10CE, "X"), - (0x10D0, "V"), - (0x10FC, "M", "ნ"), - (0x10FD, "V"), - (0x115F, "I"), - (0x1161, "V"), - (0x1249, "X"), - (0x124A, "V"), - (0x124E, "X"), - (0x1250, "V"), - (0x1257, "X"), - (0x1258, "V"), - (0x1259, "X"), - (0x125A, "V"), - (0x125E, "X"), - (0x1260, "V"), - (0x1289, "X"), - (0x128A, "V"), - (0x128E, "X"), - (0x1290, "V"), - (0x12B1, "X"), - (0x12B2, "V"), - (0x12B6, "X"), - (0x12B8, "V"), - (0x12BF, "X"), - (0x12C0, "V"), - (0x12C1, "X"), - (0x12C2, "V"), - (0x12C6, "X"), - (0x12C8, "V"), - (0x12D7, "X"), - (0x12D8, "V"), - (0x1311, "X"), - (0x1312, "V"), - (0x1316, "X"), - (0x1318, "V"), - (0x135B, "X"), - (0x135D, "V"), - (0x137D, "X"), - (0x1380, "V"), - (0x139A, "X"), - (0x13A0, "V"), - (0x13F6, "X"), - (0x13F8, "M", "Ᏸ"), - (0x13F9, "M", "Ᏹ"), - (0x13FA, "M", "Ᏺ"), - (0x13FB, "M", "Ᏻ"), - (0x13FC, "M", "Ᏼ"), - (0x13FD, "M", "Ᏽ"), - (0x13FE, "X"), - (0x1400, "V"), - (0x1680, "X"), - (0x1681, "V"), - (0x169D, "X"), - (0x16A0, "V"), - (0x16F9, "X"), - (0x1700, "V"), - (0x1716, "X"), - (0x171F, "V"), - (0x1737, "X"), - (0x1740, "V"), - (0x1754, "X"), - (0x1760, "V"), - (0x176D, "X"), - (0x176E, "V"), - (0x1771, "X"), - (0x1772, "V"), - (0x1774, "X"), - (0x1780, "V"), - (0x17B4, "I"), - (0x17B6, "V"), - (0x17DE, "X"), - (0x17E0, "V"), - (0x17EA, "X"), - (0x17F0, "V"), - (0x17FA, "X"), - (0x1800, "V"), - (0x180B, "I"), - (0x1810, "V"), - (0x181A, "X"), - (0x1820, "V"), - (0x1879, "X"), - (0x1880, "V"), - (0x18AB, "X"), - (0x18B0, "V"), - (0x18F6, "X"), - (0x1900, "V"), - (0x191F, "X"), - (0x1920, "V"), - (0x192C, "X"), - (0x1930, "V"), - (0x193C, "X"), - (0x1940, "V"), - (0x1941, "X"), - (0x1944, "V"), - (0x196E, "X"), - (0x1970, "V"), - (0x1975, "X"), - (0x1980, "V"), - (0x19AC, "X"), - (0x19B0, "V"), - (0x19CA, "X"), - (0x19D0, "V"), - (0x19DB, "X"), - (0x19DE, "V"), - (0x1A1C, "X"), - (0x1A1E, "V"), - (0x1A5F, "X"), - (0x1A60, "V"), - (0x1A7D, "X"), - (0x1A7F, "V"), - (0x1A8A, "X"), - (0x1A90, "V"), - (0x1A9A, "X"), - (0x1AA0, "V"), - (0x1AAE, "X"), - (0x1AB0, "V"), - (0x1ADE, "X"), - (0x1AE0, "V"), - (0x1AEC, "X"), - (0x1B00, "V"), - (0x1B4D, "X"), - (0x1B4E, "V"), - (0x1BF4, "X"), - (0x1BFC, "V"), - (0x1C38, "X"), - (0x1C3B, "V"), - (0x1C4A, "X"), - (0x1C4D, "V"), - (0x1C80, "M", "в"), - (0x1C81, "M", "д"), - (0x1C82, "M", "о"), - (0x1C83, "M", "с"), - (0x1C84, "M", "т"), - (0x1C86, "M", "ъ"), - (0x1C87, "M", "ѣ"), - (0x1C88, "M", "ꙋ"), - (0x1C89, "M", "ᲊ"), - (0x1C8A, "V"), - (0x1C8B, "X"), - (0x1C90, "M", "ა"), - (0x1C91, "M", "ბ"), - (0x1C92, "M", "გ"), - (0x1C93, "M", "დ"), - (0x1C94, "M", "ე"), - (0x1C95, "M", "ვ"), - (0x1C96, "M", "ზ"), - (0x1C97, "M", "თ"), - (0x1C98, "M", "ი"), - (0x1C99, "M", "კ"), - (0x1C9A, "M", "ლ"), - (0x1C9B, "M", "მ"), - (0x1C9C, "M", "ნ"), - (0x1C9D, "M", "ო"), - (0x1C9E, "M", "პ"), - (0x1C9F, "M", "ჟ"), - (0x1CA0, "M", "რ"), - (0x1CA1, "M", "ს"), - (0x1CA2, "M", "ტ"), - (0x1CA3, "M", "უ"), - (0x1CA4, "M", "ფ"), - (0x1CA5, "M", "ქ"), - (0x1CA6, "M", "ღ"), - (0x1CA7, "M", "ყ"), - (0x1CA8, "M", "შ"), - (0x1CA9, "M", "ჩ"), - (0x1CAA, "M", "ც"), - (0x1CAB, "M", "ძ"), - (0x1CAC, "M", "წ"), - (0x1CAD, "M", "ჭ"), - (0x1CAE, "M", "ხ"), - (0x1CAF, "M", "ჯ"), - (0x1CB0, "M", "ჰ"), - (0x1CB1, "M", "ჱ"), - (0x1CB2, "M", "ჲ"), - (0x1CB3, "M", "ჳ"), - (0x1CB4, "M", "ჴ"), - (0x1CB5, "M", "ჵ"), - (0x1CB6, "M", "ჶ"), - (0x1CB7, "M", "ჷ"), - (0x1CB8, "M", "ჸ"), - (0x1CB9, "M", "ჹ"), - (0x1CBA, "M", "ჺ"), - (0x1CBB, "X"), - (0x1CBD, "M", "ჽ"), - (0x1CBE, "M", "ჾ"), - (0x1CBF, "M", "ჿ"), - (0x1CC0, "V"), - (0x1CC8, "X"), - (0x1CD0, "V"), - (0x1CFB, "X"), - (0x1D00, "V"), - (0x1D2C, "M", "a"), - (0x1D2D, "M", "æ"), - (0x1D2E, "M", "b"), - (0x1D2F, "V"), - (0x1D30, "M", "d"), - (0x1D31, "M", "e"), - (0x1D32, "M", "ǝ"), - (0x1D33, "M", "g"), - (0x1D34, "M", "h"), - (0x1D35, "M", "i"), - (0x1D36, "M", "j"), - (0x1D37, "M", "k"), - (0x1D38, "M", "l"), - (0x1D39, "M", "m"), - (0x1D3A, "M", "n"), - (0x1D3B, "V"), - (0x1D3C, "M", "o"), - (0x1D3D, "M", "ȣ"), - (0x1D3E, "M", "p"), - (0x1D3F, "M", "r"), - (0x1D40, "M", "t"), - (0x1D41, "M", "u"), - (0x1D42, "M", "w"), - (0x1D43, "M", "a"), - (0x1D44, "M", "ɐ"), - (0x1D45, "M", "ɑ"), - (0x1D46, "M", "ᴂ"), - (0x1D47, "M", "b"), - (0x1D48, "M", "d"), - (0x1D49, "M", "e"), - (0x1D4A, "M", "ə"), - (0x1D4B, "M", "ɛ"), - (0x1D4C, "M", "ɜ"), - (0x1D4D, "M", "g"), - (0x1D4E, "V"), - (0x1D4F, "M", "k"), - (0x1D50, "M", "m"), - (0x1D51, "M", "ŋ"), - (0x1D52, "M", "o"), - (0x1D53, "M", "ɔ"), - (0x1D54, "M", "ᴖ"), - (0x1D55, "M", "ᴗ"), - (0x1D56, "M", "p"), - (0x1D57, "M", "t"), - (0x1D58, "M", "u"), - (0x1D59, "M", "ᴝ"), - (0x1D5A, "M", "ɯ"), - (0x1D5B, "M", "v"), - (0x1D5C, "M", "ᴥ"), - (0x1D5D, "M", "β"), - (0x1D5E, "M", "γ"), - (0x1D5F, "M", "δ"), - (0x1D60, "M", "φ"), - (0x1D61, "M", "χ"), - (0x1D62, "M", "i"), - (0x1D63, "M", "r"), - (0x1D64, "M", "u"), - (0x1D65, "M", "v"), - (0x1D66, "M", "β"), - (0x1D67, "M", "γ"), - (0x1D68, "M", "ρ"), - (0x1D69, "M", "φ"), - (0x1D6A, "M", "χ"), - (0x1D6B, "V"), - (0x1D78, "M", "н"), - (0x1D79, "V"), - (0x1D9B, "M", "ɒ"), - (0x1D9C, "M", "c"), - (0x1D9D, "M", "ɕ"), - (0x1D9E, "M", "ð"), - (0x1D9F, "M", "ɜ"), - (0x1DA0, "M", "f"), - (0x1DA1, "M", "ɟ"), - (0x1DA2, "M", "ɡ"), - (0x1DA3, "M", "ɥ"), - (0x1DA4, "M", "ɨ"), - (0x1DA5, "M", "ɩ"), - (0x1DA6, "M", "ɪ"), - (0x1DA7, "M", "ᵻ"), - (0x1DA8, "M", "ʝ"), - (0x1DA9, "M", "ɭ"), - (0x1DAA, "M", "ᶅ"), - (0x1DAB, "M", "ʟ"), - (0x1DAC, "M", "ɱ"), - (0x1DAD, "M", "ɰ"), - (0x1DAE, "M", "ɲ"), - (0x1DAF, "M", "ɳ"), - (0x1DB0, "M", "ɴ"), - (0x1DB1, "M", "ɵ"), - (0x1DB2, "M", "ɸ"), - (0x1DB3, "M", "ʂ"), - (0x1DB4, "M", "ʃ"), - (0x1DB5, "M", "ƫ"), - (0x1DB6, "M", "ʉ"), - (0x1DB7, "M", "ʊ"), - (0x1DB8, "M", "ᴜ"), - (0x1DB9, "M", "ʋ"), - (0x1DBA, "M", "ʌ"), - (0x1DBB, "M", "z"), - (0x1DBC, "M", "ʐ"), - (0x1DBD, "M", "ʑ"), - (0x1DBE, "M", "ʒ"), - (0x1DBF, "M", "θ"), - (0x1DC0, "V"), - (0x1E00, "M", "ḁ"), - (0x1E01, "V"), - (0x1E02, "M", "ḃ"), - (0x1E03, "V"), - (0x1E04, "M", "ḅ"), - (0x1E05, "V"), - (0x1E06, "M", "ḇ"), - (0x1E07, "V"), - (0x1E08, "M", "ḉ"), - (0x1E09, "V"), - (0x1E0A, "M", "ḋ"), - (0x1E0B, "V"), - (0x1E0C, "M", "ḍ"), - (0x1E0D, "V"), - (0x1E0E, "M", "ḏ"), - (0x1E0F, "V"), - (0x1E10, "M", "ḑ"), - (0x1E11, "V"), - (0x1E12, "M", "ḓ"), - (0x1E13, "V"), - (0x1E14, "M", "ḕ"), - (0x1E15, "V"), - (0x1E16, "M", "ḗ"), - (0x1E17, "V"), - (0x1E18, "M", "ḙ"), - (0x1E19, "V"), - (0x1E1A, "M", "ḛ"), - (0x1E1B, "V"), - (0x1E1C, "M", "ḝ"), - (0x1E1D, "V"), - (0x1E1E, "M", "ḟ"), - (0x1E1F, "V"), - (0x1E20, "M", "ḡ"), - (0x1E21, "V"), - (0x1E22, "M", "ḣ"), - (0x1E23, "V"), - (0x1E24, "M", "ḥ"), - (0x1E25, "V"), - (0x1E26, "M", "ḧ"), - (0x1E27, "V"), - (0x1E28, "M", "ḩ"), - (0x1E29, "V"), - (0x1E2A, "M", "ḫ"), - (0x1E2B, "V"), - (0x1E2C, "M", "ḭ"), - (0x1E2D, "V"), - (0x1E2E, "M", "ḯ"), - (0x1E2F, "V"), - (0x1E30, "M", "ḱ"), - (0x1E31, "V"), - (0x1E32, "M", "ḳ"), - (0x1E33, "V"), - (0x1E34, "M", "ḵ"), - (0x1E35, "V"), - (0x1E36, "M", "ḷ"), - (0x1E37, "V"), - (0x1E38, "M", "ḹ"), - (0x1E39, "V"), - (0x1E3A, "M", "ḻ"), - (0x1E3B, "V"), - (0x1E3C, "M", "ḽ"), - (0x1E3D, "V"), - (0x1E3E, "M", "ḿ"), - (0x1E3F, "V"), - (0x1E40, "M", "ṁ"), - (0x1E41, "V"), - (0x1E42, "M", "ṃ"), - (0x1E43, "V"), - (0x1E44, "M", "ṅ"), - (0x1E45, "V"), - (0x1E46, "M", "ṇ"), - (0x1E47, "V"), - (0x1E48, "M", "ṉ"), - (0x1E49, "V"), - (0x1E4A, "M", "ṋ"), - (0x1E4B, "V"), - (0x1E4C, "M", "ṍ"), - (0x1E4D, "V"), - (0x1E4E, "M", "ṏ"), - (0x1E4F, "V"), - (0x1E50, "M", "ṑ"), - (0x1E51, "V"), - (0x1E52, "M", "ṓ"), - (0x1E53, "V"), - (0x1E54, "M", "ṕ"), - (0x1E55, "V"), - (0x1E56, "M", "ṗ"), - (0x1E57, "V"), - (0x1E58, "M", "ṙ"), - (0x1E59, "V"), - (0x1E5A, "M", "ṛ"), - (0x1E5B, "V"), - (0x1E5C, "M", "ṝ"), - (0x1E5D, "V"), - (0x1E5E, "M", "ṟ"), - (0x1E5F, "V"), - (0x1E60, "M", "ṡ"), - (0x1E61, "V"), - (0x1E62, "M", "ṣ"), - (0x1E63, "V"), - (0x1E64, "M", "ṥ"), - (0x1E65, "V"), - (0x1E66, "M", "ṧ"), - (0x1E67, "V"), - (0x1E68, "M", "ṩ"), - (0x1E69, "V"), - (0x1E6A, "M", "ṫ"), - (0x1E6B, "V"), - (0x1E6C, "M", "ṭ"), - (0x1E6D, "V"), - (0x1E6E, "M", "ṯ"), - (0x1E6F, "V"), - (0x1E70, "M", "ṱ"), - (0x1E71, "V"), - (0x1E72, "M", "ṳ"), - (0x1E73, "V"), - (0x1E74, "M", "ṵ"), - (0x1E75, "V"), - (0x1E76, "M", "ṷ"), - (0x1E77, "V"), - (0x1E78, "M", "ṹ"), - (0x1E79, "V"), - (0x1E7A, "M", "ṻ"), - (0x1E7B, "V"), - (0x1E7C, "M", "ṽ"), - (0x1E7D, "V"), - (0x1E7E, "M", "ṿ"), - (0x1E7F, "V"), - (0x1E80, "M", "ẁ"), - (0x1E81, "V"), - (0x1E82, "M", "ẃ"), - (0x1E83, "V"), - (0x1E84, "M", "ẅ"), - (0x1E85, "V"), - (0x1E86, "M", "ẇ"), - (0x1E87, "V"), - (0x1E88, "M", "ẉ"), - (0x1E89, "V"), - (0x1E8A, "M", "ẋ"), - (0x1E8B, "V"), - (0x1E8C, "M", "ẍ"), - (0x1E8D, "V"), - (0x1E8E, "M", "ẏ"), - (0x1E8F, "V"), - (0x1E90, "M", "ẑ"), - (0x1E91, "V"), - (0x1E92, "M", "ẓ"), - (0x1E93, "V"), - (0x1E94, "M", "ẕ"), - (0x1E95, "V"), - (0x1E9A, "M", "aʾ"), - (0x1E9B, "M", "ṡ"), - (0x1E9C, "V"), - (0x1E9E, "M", "ß"), - (0x1E9F, "V"), - (0x1EA0, "M", "ạ"), - (0x1EA1, "V"), - (0x1EA2, "M", "ả"), - (0x1EA3, "V"), - (0x1EA4, "M", "ấ"), - (0x1EA5, "V"), - (0x1EA6, "M", "ầ"), - (0x1EA7, "V"), - (0x1EA8, "M", "ẩ"), - (0x1EA9, "V"), - (0x1EAA, "M", "ẫ"), - (0x1EAB, "V"), - (0x1EAC, "M", "ậ"), - (0x1EAD, "V"), - (0x1EAE, "M", "ắ"), - (0x1EAF, "V"), - (0x1EB0, "M", "ằ"), - (0x1EB1, "V"), - (0x1EB2, "M", "ẳ"), - (0x1EB3, "V"), - (0x1EB4, "M", "ẵ"), - (0x1EB5, "V"), - (0x1EB6, "M", "ặ"), - (0x1EB7, "V"), - (0x1EB8, "M", "ẹ"), - (0x1EB9, "V"), - (0x1EBA, "M", "ẻ"), - (0x1EBB, "V"), - (0x1EBC, "M", "ẽ"), - (0x1EBD, "V"), - (0x1EBE, "M", "ế"), - (0x1EBF, "V"), - (0x1EC0, "M", "ề"), - (0x1EC1, "V"), - (0x1EC2, "M", "ể"), - (0x1EC3, "V"), - (0x1EC4, "M", "ễ"), - (0x1EC5, "V"), - (0x1EC6, "M", "ệ"), - (0x1EC7, "V"), - (0x1EC8, "M", "ỉ"), - (0x1EC9, "V"), - (0x1ECA, "M", "ị"), - (0x1ECB, "V"), - (0x1ECC, "M", "ọ"), - (0x1ECD, "V"), - (0x1ECE, "M", "ỏ"), - (0x1ECF, "V"), - (0x1ED0, "M", "ố"), - (0x1ED1, "V"), - (0x1ED2, "M", "ồ"), - (0x1ED3, "V"), - (0x1ED4, "M", "ổ"), - (0x1ED5, "V"), - (0x1ED6, "M", "ỗ"), - (0x1ED7, "V"), - (0x1ED8, "M", "ộ"), - (0x1ED9, "V"), - (0x1EDA, "M", "ớ"), - (0x1EDB, "V"), - (0x1EDC, "M", "ờ"), - (0x1EDD, "V"), - (0x1EDE, "M", "ở"), - (0x1EDF, "V"), - (0x1EE0, "M", "ỡ"), - (0x1EE1, "V"), - (0x1EE2, "M", "ợ"), - (0x1EE3, "V"), - (0x1EE4, "M", "ụ"), - (0x1EE5, "V"), - (0x1EE6, "M", "ủ"), - (0x1EE7, "V"), - (0x1EE8, "M", "ứ"), - (0x1EE9, "V"), - (0x1EEA, "M", "ừ"), - (0x1EEB, "V"), - (0x1EEC, "M", "ử"), - (0x1EED, "V"), - (0x1EEE, "M", "ữ"), - (0x1EEF, "V"), - (0x1EF0, "M", "ự"), - (0x1EF1, "V"), - (0x1EF2, "M", "ỳ"), - (0x1EF3, "V"), - (0x1EF4, "M", "ỵ"), - (0x1EF5, "V"), - (0x1EF6, "M", "ỷ"), - (0x1EF7, "V"), - (0x1EF8, "M", "ỹ"), - (0x1EF9, "V"), - (0x1EFA, "M", "ỻ"), - (0x1EFB, "V"), - (0x1EFC, "M", "ỽ"), - (0x1EFD, "V"), - (0x1EFE, "M", "ỿ"), - (0x1EFF, "V"), - (0x1F08, "M", "ἀ"), - (0x1F09, "M", "ἁ"), - (0x1F0A, "M", "ἂ"), - (0x1F0B, "M", "ἃ"), - (0x1F0C, "M", "ἄ"), - (0x1F0D, "M", "ἅ"), - (0x1F0E, "M", "ἆ"), - (0x1F0F, "M", "ἇ"), - (0x1F10, "V"), - (0x1F16, "X"), - (0x1F18, "M", "ἐ"), - (0x1F19, "M", "ἑ"), - (0x1F1A, "M", "ἒ"), - (0x1F1B, "M", "ἓ"), - (0x1F1C, "M", "ἔ"), - (0x1F1D, "M", "ἕ"), - (0x1F1E, "X"), - (0x1F20, "V"), - (0x1F28, "M", "ἠ"), - (0x1F29, "M", "ἡ"), - (0x1F2A, "M", "ἢ"), - (0x1F2B, "M", "ἣ"), - (0x1F2C, "M", "ἤ"), - (0x1F2D, "M", "ἥ"), - (0x1F2E, "M", "ἦ"), - (0x1F2F, "M", "ἧ"), - (0x1F30, "V"), - (0x1F38, "M", "ἰ"), - (0x1F39, "M", "ἱ"), - (0x1F3A, "M", "ἲ"), - (0x1F3B, "M", "ἳ"), - (0x1F3C, "M", "ἴ"), - (0x1F3D, "M", "ἵ"), - (0x1F3E, "M", "ἶ"), - (0x1F3F, "M", "ἷ"), - (0x1F40, "V"), - (0x1F46, "X"), - (0x1F48, "M", "ὀ"), - (0x1F49, "M", "ὁ"), - (0x1F4A, "M", "ὂ"), - (0x1F4B, "M", "ὃ"), - (0x1F4C, "M", "ὄ"), - (0x1F4D, "M", "ὅ"), - (0x1F4E, "X"), - (0x1F50, "V"), - (0x1F58, "X"), - (0x1F59, "M", "ὑ"), - (0x1F5A, "X"), - (0x1F5B, "M", "ὓ"), - (0x1F5C, "X"), - (0x1F5D, "M", "ὕ"), - (0x1F5E, "X"), - (0x1F5F, "M", "ὗ"), - (0x1F60, "V"), - (0x1F68, "M", "ὠ"), - (0x1F69, "M", "ὡ"), - (0x1F6A, "M", "ὢ"), - (0x1F6B, "M", "ὣ"), - (0x1F6C, "M", "ὤ"), - (0x1F6D, "M", "ὥ"), - (0x1F6E, "M", "ὦ"), - (0x1F6F, "M", "ὧ"), - (0x1F70, "V"), - (0x1F71, "M", "ά"), - (0x1F72, "V"), - (0x1F73, "M", "έ"), - (0x1F74, "V"), - (0x1F75, "M", "ή"), - (0x1F76, "V"), - (0x1F77, "M", "ί"), - (0x1F78, "V"), - (0x1F79, "M", "ό"), - (0x1F7A, "V"), - (0x1F7B, "M", "ύ"), - (0x1F7C, "V"), - (0x1F7D, "M", "ώ"), - (0x1F7E, "X"), - (0x1F80, "M", "ἀι"), - (0x1F81, "M", "ἁι"), - (0x1F82, "M", "ἂι"), - (0x1F83, "M", "ἃι"), - (0x1F84, "M", "ἄι"), - (0x1F85, "M", "ἅι"), - (0x1F86, "M", "ἆι"), - (0x1F87, "M", "ἇι"), - (0x1F88, "M", "ἀι"), - (0x1F89, "M", "ἁι"), - (0x1F8A, "M", "ἂι"), - (0x1F8B, "M", "ἃι"), - (0x1F8C, "M", "ἄι"), - (0x1F8D, "M", "ἅι"), - (0x1F8E, "M", "ἆι"), - (0x1F8F, "M", "ἇι"), - (0x1F90, "M", "ἠι"), - (0x1F91, "M", "ἡι"), - (0x1F92, "M", "ἢι"), - (0x1F93, "M", "ἣι"), - (0x1F94, "M", "ἤι"), - (0x1F95, "M", "ἥι"), - (0x1F96, "M", "ἦι"), - (0x1F97, "M", "ἧι"), - (0x1F98, "M", "ἠι"), - (0x1F99, "M", "ἡι"), - (0x1F9A, "M", "ἢι"), - (0x1F9B, "M", "ἣι"), - (0x1F9C, "M", "ἤι"), - (0x1F9D, "M", "ἥι"), - (0x1F9E, "M", "ἦι"), - (0x1F9F, "M", "ἧι"), - (0x1FA0, "M", "ὠι"), - (0x1FA1, "M", "ὡι"), - (0x1FA2, "M", "ὢι"), - (0x1FA3, "M", "ὣι"), - (0x1FA4, "M", "ὤι"), - (0x1FA5, "M", "ὥι"), - (0x1FA6, "M", "ὦι"), - (0x1FA7, "M", "ὧι"), - (0x1FA8, "M", "ὠι"), - (0x1FA9, "M", "ὡι"), - (0x1FAA, "M", "ὢι"), - (0x1FAB, "M", "ὣι"), - (0x1FAC, "M", "ὤι"), - (0x1FAD, "M", "ὥι"), - (0x1FAE, "M", "ὦι"), - (0x1FAF, "M", "ὧι"), - (0x1FB0, "V"), - (0x1FB2, "M", "ὰι"), - (0x1FB3, "M", "αι"), - (0x1FB4, "M", "άι"), - (0x1FB5, "X"), - (0x1FB6, "V"), - (0x1FB7, "M", "ᾶι"), - (0x1FB8, "M", "ᾰ"), - (0x1FB9, "M", "ᾱ"), - (0x1FBA, "M", "ὰ"), - (0x1FBB, "M", "ά"), - (0x1FBC, "M", "αι"), - (0x1FBD, "M", " ̓"), - (0x1FBE, "M", "ι"), - (0x1FBF, "M", " ̓"), - (0x1FC0, "M", " ͂"), - (0x1FC1, "M", " ̈͂"), - (0x1FC2, "M", "ὴι"), - (0x1FC3, "M", "ηι"), - (0x1FC4, "M", "ήι"), - (0x1FC5, "X"), - (0x1FC6, "V"), - (0x1FC7, "M", "ῆι"), - (0x1FC8, "M", "ὲ"), - (0x1FC9, "M", "έ"), - (0x1FCA, "M", "ὴ"), - (0x1FCB, "M", "ή"), - (0x1FCC, "M", "ηι"), - (0x1FCD, "M", " ̓̀"), - (0x1FCE, "M", " ̓́"), - (0x1FCF, "M", " ̓͂"), - (0x1FD0, "V"), - (0x1FD3, "M", "ΐ"), - (0x1FD4, "X"), - (0x1FD6, "V"), - (0x1FD8, "M", "ῐ"), - (0x1FD9, "M", "ῑ"), - (0x1FDA, "M", "ὶ"), - (0x1FDB, "M", "ί"), - (0x1FDC, "X"), - (0x1FDD, "M", " ̔̀"), - (0x1FDE, "M", " ̔́"), - (0x1FDF, "M", " ̔͂"), - (0x1FE0, "V"), - (0x1FE3, "M", "ΰ"), - (0x1FE4, "V"), - (0x1FE8, "M", "ῠ"), - (0x1FE9, "M", "ῡ"), - (0x1FEA, "M", "ὺ"), - (0x1FEB, "M", "ύ"), - (0x1FEC, "M", "ῥ"), - (0x1FED, "M", " ̈̀"), - (0x1FEE, "M", " ̈́"), - (0x1FEF, "M", "`"), - (0x1FF0, "X"), - (0x1FF2, "M", "ὼι"), - (0x1FF3, "M", "ωι"), - (0x1FF4, "M", "ώι"), - (0x1FF5, "X"), - (0x1FF6, "V"), - (0x1FF7, "M", "ῶι"), - (0x1FF8, "M", "ὸ"), - (0x1FF9, "M", "ό"), - (0x1FFA, "M", "ὼ"), - (0x1FFB, "M", "ώ"), - (0x1FFC, "M", "ωι"), - (0x1FFD, "M", " ́"), - (0x1FFE, "M", " ̔"), - (0x1FFF, "X"), - (0x2000, "M", " "), - (0x200B, "I"), - (0x200C, "D", ""), - (0x200E, "X"), - (0x2010, "V"), - (0x2011, "M", "‐"), - (0x2012, "V"), - (0x2017, "M", " ̳"), - (0x2018, "V"), - (0x2024, "X"), - (0x2027, "V"), - (0x2028, "X"), - (0x202F, "M", " "), - (0x2030, "V"), - (0x2033, "M", "′′"), - (0x2034, "M", "′′′"), - (0x2035, "V"), - (0x2036, "M", "‵‵"), - (0x2037, "M", "‵‵‵"), - (0x2038, "V"), - (0x203C, "M", "!!"), - (0x203D, "V"), - (0x203E, "M", " ̅"), - (0x203F, "V"), - (0x2047, "M", "??"), - (0x2048, "M", "?!"), - (0x2049, "M", "!?"), - (0x204A, "V"), - (0x2057, "M", "′′′′"), - (0x2058, "V"), - (0x205F, "M", " "), - (0x2060, "I"), - (0x2065, "X"), - (0x206A, "I"), - (0x2070, "M", "0"), - (0x2071, "M", "i"), - (0x2072, "X"), - (0x2074, "M", "4"), - (0x2075, "M", "5"), - (0x2076, "M", "6"), - (0x2077, "M", "7"), - (0x2078, "M", "8"), - (0x2079, "M", "9"), - (0x207A, "M", "+"), - (0x207B, "M", "−"), - (0x207C, "M", "="), - (0x207D, "M", "("), - (0x207E, "M", ")"), - (0x207F, "M", "n"), - (0x2080, "M", "0"), - (0x2081, "M", "1"), - (0x2082, "M", "2"), - (0x2083, "M", "3"), - (0x2084, "M", "4"), - (0x2085, "M", "5"), - (0x2086, "M", "6"), - (0x2087, "M", "7"), - (0x2088, "M", "8"), - (0x2089, "M", "9"), - (0x208A, "M", "+"), - (0x208B, "M", "−"), - (0x208C, "M", "="), - (0x208D, "M", "("), - (0x208E, "M", ")"), - (0x208F, "X"), - (0x2090, "M", "a"), - (0x2091, "M", "e"), - (0x2092, "M", "o"), - (0x2093, "M", "x"), - (0x2094, "M", "ə"), - (0x2095, "M", "h"), - (0x2096, "M", "k"), - (0x2097, "M", "l"), - (0x2098, "M", "m"), - (0x2099, "M", "n"), - (0x209A, "M", "p"), - (0x209B, "M", "s"), - (0x209C, "M", "t"), - (0x209D, "X"), - (0x20A0, "V"), - (0x20A8, "M", "rs"), - (0x20A9, "V"), - (0x20C2, "X"), - (0x20D0, "V"), - (0x20F1, "X"), - (0x2100, "M", "a/c"), - (0x2101, "M", "a/s"), - (0x2102, "M", "c"), - (0x2103, "M", "°c"), - (0x2104, "V"), - (0x2105, "M", "c/o"), - (0x2106, "M", "c/u"), - (0x2107, "M", "ɛ"), - (0x2108, "V"), - (0x2109, "M", "°f"), - (0x210A, "M", "g"), - (0x210B, "M", "h"), - (0x210F, "M", "ħ"), - (0x2110, "M", "i"), - (0x2112, "M", "l"), - (0x2114, "V"), - (0x2115, "M", "n"), - (0x2116, "M", "no"), - (0x2117, "V"), - (0x2119, "M", "p"), - (0x211A, "M", "q"), - (0x211B, "M", "r"), - (0x211E, "V"), - (0x2120, "M", "sm"), - (0x2121, "M", "tel"), - (0x2122, "M", "tm"), - (0x2123, "V"), - (0x2124, "M", "z"), - (0x2125, "V"), - (0x2126, "M", "ω"), - (0x2127, "V"), - (0x2128, "M", "z"), - (0x2129, "V"), - (0x212A, "M", "k"), - (0x212B, "M", "å"), - (0x212C, "M", "b"), - (0x212D, "M", "c"), - (0x212E, "V"), - (0x212F, "M", "e"), - (0x2131, "M", "f"), - (0x2132, "M", "ⅎ"), - (0x2133, "M", "m"), - (0x2134, "M", "o"), - (0x2135, "M", "א"), - (0x2136, "M", "ב"), - (0x2137, "M", "ג"), - (0x2138, "M", "ד"), - (0x2139, "M", "i"), - (0x213A, "V"), - (0x213B, "M", "fax"), - (0x213C, "M", "π"), - (0x213D, "M", "γ"), - (0x213F, "M", "π"), - (0x2140, "M", "∑"), - (0x2141, "V"), - (0x2145, "M", "d"), - (0x2147, "M", "e"), - (0x2148, "M", "i"), - (0x2149, "M", "j"), - (0x214A, "V"), - (0x2150, "M", "1⁄7"), - (0x2151, "M", "1⁄9"), - (0x2152, "M", "1⁄10"), - (0x2153, "M", "1⁄3"), - (0x2154, "M", "2⁄3"), - (0x2155, "M", "1⁄5"), - (0x2156, "M", "2⁄5"), - (0x2157, "M", "3⁄5"), - (0x2158, "M", "4⁄5"), - (0x2159, "M", "1⁄6"), - (0x215A, "M", "5⁄6"), - (0x215B, "M", "1⁄8"), - (0x215C, "M", "3⁄8"), - (0x215D, "M", "5⁄8"), - (0x215E, "M", "7⁄8"), - (0x215F, "M", "1⁄"), - (0x2160, "M", "i"), - (0x2161, "M", "ii"), - (0x2162, "M", "iii"), - (0x2163, "M", "iv"), - (0x2164, "M", "v"), - (0x2165, "M", "vi"), - (0x2166, "M", "vii"), - (0x2167, "M", "viii"), - (0x2168, "M", "ix"), - (0x2169, "M", "x"), - (0x216A, "M", "xi"), - (0x216B, "M", "xii"), - (0x216C, "M", "l"), - (0x216D, "M", "c"), - (0x216E, "M", "d"), - (0x216F, "M", "m"), - (0x2170, "M", "i"), - (0x2171, "M", "ii"), - (0x2172, "M", "iii"), - (0x2173, "M", "iv"), - (0x2174, "M", "v"), - (0x2175, "M", "vi"), - (0x2176, "M", "vii"), - (0x2177, "M", "viii"), - (0x2178, "M", "ix"), - (0x2179, "M", "x"), - (0x217A, "M", "xi"), - (0x217B, "M", "xii"), - (0x217C, "M", "l"), - (0x217D, "M", "c"), - (0x217E, "M", "d"), - (0x217F, "M", "m"), - (0x2180, "V"), - (0x2183, "M", "ↄ"), - (0x2184, "V"), - (0x2189, "M", "0⁄3"), - (0x218A, "V"), - (0x218C, "X"), - (0x2190, "V"), - (0x222C, "M", "∫∫"), - (0x222D, "M", "∫∫∫"), - (0x222E, "V"), - (0x222F, "M", "∮∮"), - (0x2230, "M", "∮∮∮"), - (0x2231, "V"), - (0x2329, "M", "〈"), - (0x232A, "M", "〉"), - (0x232B, "V"), - (0x242A, "X"), - (0x2440, "V"), - (0x244B, "X"), - (0x2460, "M", "1"), - (0x2461, "M", "2"), - (0x2462, "M", "3"), - (0x2463, "M", "4"), - (0x2464, "M", "5"), - (0x2465, "M", "6"), - (0x2466, "M", "7"), - (0x2467, "M", "8"), - (0x2468, "M", "9"), - (0x2469, "M", "10"), - (0x246A, "M", "11"), - (0x246B, "M", "12"), - (0x246C, "M", "13"), - (0x246D, "M", "14"), - (0x246E, "M", "15"), - (0x246F, "M", "16"), - (0x2470, "M", "17"), - (0x2471, "M", "18"), - (0x2472, "M", "19"), - (0x2473, "M", "20"), - (0x2474, "M", "(1)"), - (0x2475, "M", "(2)"), - (0x2476, "M", "(3)"), - (0x2477, "M", "(4)"), - (0x2478, "M", "(5)"), - (0x2479, "M", "(6)"), - (0x247A, "M", "(7)"), - (0x247B, "M", "(8)"), - (0x247C, "M", "(9)"), - (0x247D, "M", "(10)"), - (0x247E, "M", "(11)"), - (0x247F, "M", "(12)"), - (0x2480, "M", "(13)"), - (0x2481, "M", "(14)"), - (0x2482, "M", "(15)"), - (0x2483, "M", "(16)"), - (0x2484, "M", "(17)"), - (0x2485, "M", "(18)"), - (0x2486, "M", "(19)"), - (0x2487, "M", "(20)"), - (0x2488, "X"), - (0x249C, "M", "(a)"), - (0x249D, "M", "(b)"), - (0x249E, "M", "(c)"), - (0x249F, "M", "(d)"), - (0x24A0, "M", "(e)"), - (0x24A1, "M", "(f)"), - (0x24A2, "M", "(g)"), - (0x24A3, "M", "(h)"), - (0x24A4, "M", "(i)"), - (0x24A5, "M", "(j)"), - (0x24A6, "M", "(k)"), - (0x24A7, "M", "(l)"), - (0x24A8, "M", "(m)"), - (0x24A9, "M", "(n)"), - (0x24AA, "M", "(o)"), - (0x24AB, "M", "(p)"), - (0x24AC, "M", "(q)"), - (0x24AD, "M", "(r)"), - (0x24AE, "M", "(s)"), - (0x24AF, "M", "(t)"), - (0x24B0, "M", "(u)"), - (0x24B1, "M", "(v)"), - (0x24B2, "M", "(w)"), - (0x24B3, "M", "(x)"), - (0x24B4, "M", "(y)"), - (0x24B5, "M", "(z)"), - (0x24B6, "M", "a"), - (0x24B7, "M", "b"), - (0x24B8, "M", "c"), - (0x24B9, "M", "d"), - (0x24BA, "M", "e"), - (0x24BB, "M", "f"), - (0x24BC, "M", "g"), - (0x24BD, "M", "h"), - (0x24BE, "M", "i"), - (0x24BF, "M", "j"), - (0x24C0, "M", "k"), - (0x24C1, "M", "l"), - (0x24C2, "M", "m"), - (0x24C3, "M", "n"), - (0x24C4, "M", "o"), - (0x24C5, "M", "p"), - (0x24C6, "M", "q"), - (0x24C7, "M", "r"), - (0x24C8, "M", "s"), - (0x24C9, "M", "t"), - (0x24CA, "M", "u"), - (0x24CB, "M", "v"), - (0x24CC, "M", "w"), - (0x24CD, "M", "x"), - (0x24CE, "M", "y"), - (0x24CF, "M", "z"), - (0x24D0, "M", "a"), - (0x24D1, "M", "b"), - (0x24D2, "M", "c"), - (0x24D3, "M", "d"), - (0x24D4, "M", "e"), - (0x24D5, "M", "f"), - (0x24D6, "M", "g"), - (0x24D7, "M", "h"), - (0x24D8, "M", "i"), - (0x24D9, "M", "j"), - (0x24DA, "M", "k"), - (0x24DB, "M", "l"), - (0x24DC, "M", "m"), - (0x24DD, "M", "n"), - (0x24DE, "M", "o"), - (0x24DF, "M", "p"), - (0x24E0, "M", "q"), - (0x24E1, "M", "r"), - (0x24E2, "M", "s"), - (0x24E3, "M", "t"), - (0x24E4, "M", "u"), - (0x24E5, "M", "v"), - (0x24E6, "M", "w"), - (0x24E7, "M", "x"), - (0x24E8, "M", "y"), - (0x24E9, "M", "z"), - (0x24EA, "M", "0"), - (0x24EB, "V"), - (0x2A0C, "M", "∫∫∫∫"), - (0x2A0D, "V"), - (0x2A74, "M", "::="), - (0x2A75, "M", "=="), - (0x2A76, "M", "==="), - (0x2A77, "V"), - (0x2ADC, "M", "⫝̸"), - (0x2ADD, "V"), - (0x2B74, "X"), - (0x2B76, "V"), - (0x2C00, "M", "ⰰ"), - (0x2C01, "M", "ⰱ"), - (0x2C02, "M", "ⰲ"), - (0x2C03, "M", "ⰳ"), - (0x2C04, "M", "ⰴ"), - (0x2C05, "M", "ⰵ"), - (0x2C06, "M", "ⰶ"), - (0x2C07, "M", "ⰷ"), - (0x2C08, "M", "ⰸ"), - (0x2C09, "M", "ⰹ"), - (0x2C0A, "M", "ⰺ"), - (0x2C0B, "M", "ⰻ"), - (0x2C0C, "M", "ⰼ"), - (0x2C0D, "M", "ⰽ"), - (0x2C0E, "M", "ⰾ"), - (0x2C0F, "M", "ⰿ"), - (0x2C10, "M", "ⱀ"), - (0x2C11, "M", "ⱁ"), - (0x2C12, "M", "ⱂ"), - (0x2C13, "M", "ⱃ"), - (0x2C14, "M", "ⱄ"), - (0x2C15, "M", "ⱅ"), - (0x2C16, "M", "ⱆ"), - (0x2C17, "M", "ⱇ"), - (0x2C18, "M", "ⱈ"), - (0x2C19, "M", "ⱉ"), - (0x2C1A, "M", "ⱊ"), - (0x2C1B, "M", "ⱋ"), - (0x2C1C, "M", "ⱌ"), - (0x2C1D, "M", "ⱍ"), - (0x2C1E, "M", "ⱎ"), - (0x2C1F, "M", "ⱏ"), - (0x2C20, "M", "ⱐ"), - (0x2C21, "M", "ⱑ"), - (0x2C22, "M", "ⱒ"), - (0x2C23, "M", "ⱓ"), - (0x2C24, "M", "ⱔ"), - (0x2C25, "M", "ⱕ"), - (0x2C26, "M", "ⱖ"), - (0x2C27, "M", "ⱗ"), - (0x2C28, "M", "ⱘ"), - (0x2C29, "M", "ⱙ"), - (0x2C2A, "M", "ⱚ"), - (0x2C2B, "M", "ⱛ"), - (0x2C2C, "M", "ⱜ"), - (0x2C2D, "M", "ⱝ"), - (0x2C2E, "M", "ⱞ"), - (0x2C2F, "M", "ⱟ"), - (0x2C30, "V"), - (0x2C60, "M", "ⱡ"), - (0x2C61, "V"), - (0x2C62, "M", "ɫ"), - (0x2C63, "M", "ᵽ"), - (0x2C64, "M", "ɽ"), - (0x2C65, "V"), - (0x2C67, "M", "ⱨ"), - (0x2C68, "V"), - (0x2C69, "M", "ⱪ"), - (0x2C6A, "V"), - (0x2C6B, "M", "ⱬ"), - (0x2C6C, "V"), - (0x2C6D, "M", "ɑ"), - (0x2C6E, "M", "ɱ"), - (0x2C6F, "M", "ɐ"), - (0x2C70, "M", "ɒ"), - (0x2C71, "V"), - (0x2C72, "M", "ⱳ"), - (0x2C73, "V"), - (0x2C75, "M", "ⱶ"), - (0x2C76, "V"), - (0x2C7C, "M", "j"), - (0x2C7D, "M", "v"), - (0x2C7E, "M", "ȿ"), - (0x2C7F, "M", "ɀ"), - (0x2C80, "M", "ⲁ"), - (0x2C81, "V"), - (0x2C82, "M", "ⲃ"), - (0x2C83, "V"), - (0x2C84, "M", "ⲅ"), - (0x2C85, "V"), - (0x2C86, "M", "ⲇ"), - (0x2C87, "V"), - (0x2C88, "M", "ⲉ"), - (0x2C89, "V"), - (0x2C8A, "M", "ⲋ"), - (0x2C8B, "V"), - (0x2C8C, "M", "ⲍ"), - (0x2C8D, "V"), - (0x2C8E, "M", "ⲏ"), - (0x2C8F, "V"), - (0x2C90, "M", "ⲑ"), - (0x2C91, "V"), - (0x2C92, "M", "ⲓ"), - (0x2C93, "V"), - (0x2C94, "M", "ⲕ"), - (0x2C95, "V"), - (0x2C96, "M", "ⲗ"), - (0x2C97, "V"), - (0x2C98, "M", "ⲙ"), - (0x2C99, "V"), - (0x2C9A, "M", "ⲛ"), - (0x2C9B, "V"), - (0x2C9C, "M", "ⲝ"), - (0x2C9D, "V"), - (0x2C9E, "M", "ⲟ"), - (0x2C9F, "V"), - (0x2CA0, "M", "ⲡ"), - (0x2CA1, "V"), - (0x2CA2, "M", "ⲣ"), - (0x2CA3, "V"), - (0x2CA4, "M", "ⲥ"), - (0x2CA5, "V"), - (0x2CA6, "M", "ⲧ"), - (0x2CA7, "V"), - (0x2CA8, "M", "ⲩ"), - (0x2CA9, "V"), - (0x2CAA, "M", "ⲫ"), - (0x2CAB, "V"), - (0x2CAC, "M", "ⲭ"), - (0x2CAD, "V"), - (0x2CAE, "M", "ⲯ"), - (0x2CAF, "V"), - (0x2CB0, "M", "ⲱ"), - (0x2CB1, "V"), - (0x2CB2, "M", "ⲳ"), - (0x2CB3, "V"), - (0x2CB4, "M", "ⲵ"), - (0x2CB5, "V"), - (0x2CB6, "M", "ⲷ"), - (0x2CB7, "V"), - (0x2CB8, "M", "ⲹ"), - (0x2CB9, "V"), - (0x2CBA, "M", "ⲻ"), - (0x2CBB, "V"), - (0x2CBC, "M", "ⲽ"), - (0x2CBD, "V"), - (0x2CBE, "M", "ⲿ"), - (0x2CBF, "V"), - (0x2CC0, "M", "ⳁ"), - (0x2CC1, "V"), - (0x2CC2, "M", "ⳃ"), - (0x2CC3, "V"), - (0x2CC4, "M", "ⳅ"), - (0x2CC5, "V"), - (0x2CC6, "M", "ⳇ"), - (0x2CC7, "V"), - (0x2CC8, "M", "ⳉ"), - (0x2CC9, "V"), - (0x2CCA, "M", "ⳋ"), - (0x2CCB, "V"), - (0x2CCC, "M", "ⳍ"), - (0x2CCD, "V"), - (0x2CCE, "M", "ⳏ"), - (0x2CCF, "V"), - (0x2CD0, "M", "ⳑ"), - (0x2CD1, "V"), - (0x2CD2, "M", "ⳓ"), - (0x2CD3, "V"), - (0x2CD4, "M", "ⳕ"), - (0x2CD5, "V"), - (0x2CD6, "M", "ⳗ"), - (0x2CD7, "V"), - (0x2CD8, "M", "ⳙ"), - (0x2CD9, "V"), - (0x2CDA, "M", "ⳛ"), - (0x2CDB, "V"), - (0x2CDC, "M", "ⳝ"), - (0x2CDD, "V"), - (0x2CDE, "M", "ⳟ"), - (0x2CDF, "V"), - (0x2CE0, "M", "ⳡ"), - (0x2CE1, "V"), - (0x2CE2, "M", "ⳣ"), - (0x2CE3, "V"), - (0x2CEB, "M", "ⳬ"), - (0x2CEC, "V"), - (0x2CED, "M", "ⳮ"), - (0x2CEE, "V"), - (0x2CF2, "M", "ⳳ"), - (0x2CF3, "V"), - (0x2CF4, "X"), - (0x2CF9, "V"), - (0x2D26, "X"), - (0x2D27, "V"), - (0x2D28, "X"), - (0x2D2D, "V"), - (0x2D2E, "X"), - (0x2D30, "V"), - (0x2D68, "X"), - (0x2D6F, "M", "ⵡ"), - (0x2D70, "V"), - (0x2D71, "X"), - (0x2D7F, "V"), - (0x2D97, "X"), - (0x2DA0, "V"), - (0x2DA7, "X"), - (0x2DA8, "V"), - (0x2DAF, "X"), - (0x2DB0, "V"), - (0x2DB7, "X"), - (0x2DB8, "V"), - (0x2DBF, "X"), - (0x2DC0, "V"), - (0x2DC7, "X"), - (0x2DC8, "V"), - (0x2DCF, "X"), - (0x2DD0, "V"), - (0x2DD7, "X"), - (0x2DD8, "V"), - (0x2DDF, "X"), - (0x2DE0, "V"), - (0x2E5E, "X"), - (0x2E80, "V"), - (0x2E9A, "X"), - (0x2E9B, "V"), - (0x2E9F, "M", "母"), - (0x2EA0, "V"), - (0x2EF3, "M", "龟"), - (0x2EF4, "X"), - (0x2F00, "M", "一"), - (0x2F01, "M", "丨"), - (0x2F02, "M", "丶"), - (0x2F03, "M", "丿"), - (0x2F04, "M", "乙"), - (0x2F05, "M", "亅"), - (0x2F06, "M", "二"), - (0x2F07, "M", "亠"), - (0x2F08, "M", "人"), - (0x2F09, "M", "儿"), - (0x2F0A, "M", "入"), - (0x2F0B, "M", "八"), - (0x2F0C, "M", "冂"), - (0x2F0D, "M", "冖"), - (0x2F0E, "M", "冫"), - (0x2F0F, "M", "几"), - (0x2F10, "M", "凵"), - (0x2F11, "M", "刀"), - (0x2F12, "M", "力"), - (0x2F13, "M", "勹"), - (0x2F14, "M", "匕"), - (0x2F15, "M", "匚"), - (0x2F16, "M", "匸"), - (0x2F17, "M", "十"), - (0x2F18, "M", "卜"), - (0x2F19, "M", "卩"), - (0x2F1A, "M", "厂"), - (0x2F1B, "M", "厶"), - (0x2F1C, "M", "又"), - (0x2F1D, "M", "口"), - (0x2F1E, "M", "囗"), - (0x2F1F, "M", "土"), - (0x2F20, "M", "士"), - (0x2F21, "M", "夂"), - (0x2F22, "M", "夊"), - (0x2F23, "M", "夕"), - (0x2F24, "M", "大"), - (0x2F25, "M", "女"), - (0x2F26, "M", "子"), - (0x2F27, "M", "宀"), - (0x2F28, "M", "寸"), - (0x2F29, "M", "小"), - (0x2F2A, "M", "尢"), - (0x2F2B, "M", "尸"), - (0x2F2C, "M", "屮"), - (0x2F2D, "M", "山"), - (0x2F2E, "M", "巛"), - (0x2F2F, "M", "工"), - (0x2F30, "M", "己"), - (0x2F31, "M", "巾"), - (0x2F32, "M", "干"), - (0x2F33, "M", "幺"), - (0x2F34, "M", "广"), - (0x2F35, "M", "廴"), - (0x2F36, "M", "廾"), - (0x2F37, "M", "弋"), - (0x2F38, "M", "弓"), - (0x2F39, "M", "彐"), - (0x2F3A, "M", "彡"), - (0x2F3B, "M", "彳"), - (0x2F3C, "M", "心"), - (0x2F3D, "M", "戈"), - (0x2F3E, "M", "戶"), - (0x2F3F, "M", "手"), - (0x2F40, "M", "支"), - (0x2F41, "M", "攴"), - (0x2F42, "M", "文"), - (0x2F43, "M", "斗"), - (0x2F44, "M", "斤"), - (0x2F45, "M", "方"), - (0x2F46, "M", "无"), - (0x2F47, "M", "日"), - (0x2F48, "M", "曰"), - (0x2F49, "M", "月"), - (0x2F4A, "M", "木"), - (0x2F4B, "M", "欠"), - (0x2F4C, "M", "止"), - (0x2F4D, "M", "歹"), - (0x2F4E, "M", "殳"), - (0x2F4F, "M", "毋"), - (0x2F50, "M", "比"), - (0x2F51, "M", "毛"), - (0x2F52, "M", "氏"), - (0x2F53, "M", "气"), - (0x2F54, "M", "水"), - (0x2F55, "M", "火"), - (0x2F56, "M", "爪"), - (0x2F57, "M", "父"), - (0x2F58, "M", "爻"), - (0x2F59, "M", "爿"), - (0x2F5A, "M", "片"), - (0x2F5B, "M", "牙"), - (0x2F5C, "M", "牛"), - (0x2F5D, "M", "犬"), - (0x2F5E, "M", "玄"), - (0x2F5F, "M", "玉"), - (0x2F60, "M", "瓜"), - (0x2F61, "M", "瓦"), - (0x2F62, "M", "甘"), - (0x2F63, "M", "生"), - (0x2F64, "M", "用"), - (0x2F65, "M", "田"), - (0x2F66, "M", "疋"), - (0x2F67, "M", "疒"), - (0x2F68, "M", "癶"), - (0x2F69, "M", "白"), - (0x2F6A, "M", "皮"), - (0x2F6B, "M", "皿"), - (0x2F6C, "M", "目"), - (0x2F6D, "M", "矛"), - (0x2F6E, "M", "矢"), - (0x2F6F, "M", "石"), - (0x2F70, "M", "示"), - (0x2F71, "M", "禸"), - (0x2F72, "M", "禾"), - (0x2F73, "M", "穴"), - (0x2F74, "M", "立"), - (0x2F75, "M", "竹"), - (0x2F76, "M", "米"), - (0x2F77, "M", "糸"), - (0x2F78, "M", "缶"), - (0x2F79, "M", "网"), - (0x2F7A, "M", "羊"), - (0x2F7B, "M", "羽"), - (0x2F7C, "M", "老"), - (0x2F7D, "M", "而"), - (0x2F7E, "M", "耒"), - (0x2F7F, "M", "耳"), - (0x2F80, "M", "聿"), - (0x2F81, "M", "肉"), - (0x2F82, "M", "臣"), - (0x2F83, "M", "自"), - (0x2F84, "M", "至"), - (0x2F85, "M", "臼"), - (0x2F86, "M", "舌"), - (0x2F87, "M", "舛"), - (0x2F88, "M", "舟"), - (0x2F89, "M", "艮"), - (0x2F8A, "M", "色"), - (0x2F8B, "M", "艸"), - (0x2F8C, "M", "虍"), - (0x2F8D, "M", "虫"), - (0x2F8E, "M", "血"), - (0x2F8F, "M", "行"), - (0x2F90, "M", "衣"), - (0x2F91, "M", "襾"), - (0x2F92, "M", "見"), - (0x2F93, "M", "角"), - (0x2F94, "M", "言"), - (0x2F95, "M", "谷"), - (0x2F96, "M", "豆"), - (0x2F97, "M", "豕"), - (0x2F98, "M", "豸"), - (0x2F99, "M", "貝"), - (0x2F9A, "M", "赤"), - (0x2F9B, "M", "走"), - (0x2F9C, "M", "足"), - (0x2F9D, "M", "身"), - (0x2F9E, "M", "車"), - (0x2F9F, "M", "辛"), - (0x2FA0, "M", "辰"), - (0x2FA1, "M", "辵"), - (0x2FA2, "M", "邑"), - (0x2FA3, "M", "酉"), - (0x2FA4, "M", "釆"), - (0x2FA5, "M", "里"), - (0x2FA6, "M", "金"), - (0x2FA7, "M", "長"), - (0x2FA8, "M", "門"), - (0x2FA9, "M", "阜"), - (0x2FAA, "M", "隶"), - (0x2FAB, "M", "隹"), - (0x2FAC, "M", "雨"), - (0x2FAD, "M", "靑"), - (0x2FAE, "M", "非"), - (0x2FAF, "M", "面"), - (0x2FB0, "M", "革"), - (0x2FB1, "M", "韋"), - (0x2FB2, "M", "韭"), - (0x2FB3, "M", "音"), - (0x2FB4, "M", "頁"), - (0x2FB5, "M", "風"), - (0x2FB6, "M", "飛"), - (0x2FB7, "M", "食"), - (0x2FB8, "M", "首"), - (0x2FB9, "M", "香"), - (0x2FBA, "M", "馬"), - (0x2FBB, "M", "骨"), - (0x2FBC, "M", "高"), - (0x2FBD, "M", "髟"), - (0x2FBE, "M", "鬥"), - (0x2FBF, "M", "鬯"), - (0x2FC0, "M", "鬲"), - (0x2FC1, "M", "鬼"), - (0x2FC2, "M", "魚"), - (0x2FC3, "M", "鳥"), - (0x2FC4, "M", "鹵"), - (0x2FC5, "M", "鹿"), - (0x2FC6, "M", "麥"), - (0x2FC7, "M", "麻"), - (0x2FC8, "M", "黃"), - (0x2FC9, "M", "黍"), - (0x2FCA, "M", "黑"), - (0x2FCB, "M", "黹"), - (0x2FCC, "M", "黽"), - (0x2FCD, "M", "鼎"), - (0x2FCE, "M", "鼓"), - (0x2FCF, "M", "鼠"), - (0x2FD0, "M", "鼻"), - (0x2FD1, "M", "齊"), - (0x2FD2, "M", "齒"), - (0x2FD3, "M", "龍"), - (0x2FD4, "M", "龜"), - (0x2FD5, "M", "龠"), - (0x2FD6, "X"), - (0x3000, "M", " "), - (0x3001, "V"), - (0x3002, "M", "."), - (0x3003, "V"), - (0x3036, "M", "〒"), - (0x3037, "V"), - (0x3038, "M", "十"), - (0x3039, "M", "卄"), - (0x303A, "M", "卅"), - (0x303B, "V"), - (0x3040, "X"), - (0x3041, "V"), - (0x3097, "X"), - (0x3099, "V"), - (0x309B, "M", " ゙"), - (0x309C, "M", " ゚"), - (0x309D, "V"), - (0x309F, "M", "より"), - (0x30A0, "V"), - (0x30FF, "M", "コト"), - (0x3100, "X"), - (0x3105, "V"), - (0x3130, "X"), - (0x3131, "M", "ᄀ"), - (0x3132, "M", "ᄁ"), - (0x3133, "M", "ᆪ"), - (0x3134, "M", "ᄂ"), - (0x3135, "M", "ᆬ"), - (0x3136, "M", "ᆭ"), - (0x3137, "M", "ᄃ"), - (0x3138, "M", "ᄄ"), - (0x3139, "M", "ᄅ"), - (0x313A, "M", "ᆰ"), - (0x313B, "M", "ᆱ"), - (0x313C, "M", "ᆲ"), - (0x313D, "M", "ᆳ"), - (0x313E, "M", "ᆴ"), - (0x313F, "M", "ᆵ"), - (0x3140, "M", "ᄚ"), - (0x3141, "M", "ᄆ"), - (0x3142, "M", "ᄇ"), - (0x3143, "M", "ᄈ"), - (0x3144, "M", "ᄡ"), - (0x3145, "M", "ᄉ"), - (0x3146, "M", "ᄊ"), - (0x3147, "M", "ᄋ"), - (0x3148, "M", "ᄌ"), - (0x3149, "M", "ᄍ"), - (0x314A, "M", "ᄎ"), - (0x314B, "M", "ᄏ"), - (0x314C, "M", "ᄐ"), - (0x314D, "M", "ᄑ"), - (0x314E, "M", "ᄒ"), - (0x314F, "M", "ᅡ"), - (0x3150, "M", "ᅢ"), - (0x3151, "M", "ᅣ"), - (0x3152, "M", "ᅤ"), - (0x3153, "M", "ᅥ"), - (0x3154, "M", "ᅦ"), - (0x3155, "M", "ᅧ"), - (0x3156, "M", "ᅨ"), - (0x3157, "M", "ᅩ"), - (0x3158, "M", "ᅪ"), - (0x3159, "M", "ᅫ"), - (0x315A, "M", "ᅬ"), - (0x315B, "M", "ᅭ"), - (0x315C, "M", "ᅮ"), - (0x315D, "M", "ᅯ"), - (0x315E, "M", "ᅰ"), - (0x315F, "M", "ᅱ"), - (0x3160, "M", "ᅲ"), - (0x3161, "M", "ᅳ"), - (0x3162, "M", "ᅴ"), - (0x3163, "M", "ᅵ"), - (0x3164, "I"), - (0x3165, "M", "ᄔ"), - (0x3166, "M", "ᄕ"), - (0x3167, "M", "ᇇ"), - (0x3168, "M", "ᇈ"), - (0x3169, "M", "ᇌ"), - (0x316A, "M", "ᇎ"), - (0x316B, "M", "ᇓ"), - (0x316C, "M", "ᇗ"), - (0x316D, "M", "ᇙ"), - (0x316E, "M", "ᄜ"), - (0x316F, "M", "ᇝ"), - (0x3170, "M", "ᇟ"), - (0x3171, "M", "ᄝ"), - (0x3172, "M", "ᄞ"), - (0x3173, "M", "ᄠ"), - (0x3174, "M", "ᄢ"), - (0x3175, "M", "ᄣ"), - (0x3176, "M", "ᄧ"), - (0x3177, "M", "ᄩ"), - (0x3178, "M", "ᄫ"), - (0x3179, "M", "ᄬ"), - (0x317A, "M", "ᄭ"), - (0x317B, "M", "ᄮ"), - (0x317C, "M", "ᄯ"), - (0x317D, "M", "ᄲ"), - (0x317E, "M", "ᄶ"), - (0x317F, "M", "ᅀ"), - (0x3180, "M", "ᅇ"), - (0x3181, "M", "ᅌ"), - (0x3182, "M", "ᇱ"), - (0x3183, "M", "ᇲ"), - (0x3184, "M", "ᅗ"), - (0x3185, "M", "ᅘ"), - (0x3186, "M", "ᅙ"), - (0x3187, "M", "ᆄ"), - (0x3188, "M", "ᆅ"), - (0x3189, "M", "ᆈ"), - (0x318A, "M", "ᆑ"), - (0x318B, "M", "ᆒ"), - (0x318C, "M", "ᆔ"), - (0x318D, "M", "ᆞ"), - (0x318E, "M", "ᆡ"), - (0x318F, "X"), - (0x3190, "V"), - (0x3192, "M", "一"), - (0x3193, "M", "二"), - (0x3194, "M", "三"), - (0x3195, "M", "四"), - (0x3196, "M", "上"), - (0x3197, "M", "中"), - (0x3198, "M", "下"), - (0x3199, "M", "甲"), - (0x319A, "M", "乙"), - (0x319B, "M", "丙"), - (0x319C, "M", "丁"), - (0x319D, "M", "天"), - (0x319E, "M", "地"), - (0x319F, "M", "人"), - (0x31A0, "V"), - (0x31E6, "X"), - (0x31F0, "V"), - (0x3200, "M", "(ᄀ)"), - (0x3201, "M", "(ᄂ)"), - (0x3202, "M", "(ᄃ)"), - (0x3203, "M", "(ᄅ)"), - (0x3204, "M", "(ᄆ)"), - (0x3205, "M", "(ᄇ)"), - (0x3206, "M", "(ᄉ)"), - (0x3207, "M", "(ᄋ)"), - (0x3208, "M", "(ᄌ)"), - (0x3209, "M", "(ᄎ)"), - (0x320A, "M", "(ᄏ)"), - (0x320B, "M", "(ᄐ)"), - (0x320C, "M", "(ᄑ)"), - (0x320D, "M", "(ᄒ)"), - (0x320E, "M", "(가)"), - (0x320F, "M", "(나)"), - (0x3210, "M", "(다)"), - (0x3211, "M", "(라)"), - (0x3212, "M", "(마)"), - (0x3213, "M", "(바)"), - (0x3214, "M", "(사)"), - (0x3215, "M", "(아)"), - (0x3216, "M", "(자)"), - (0x3217, "M", "(차)"), - (0x3218, "M", "(카)"), - (0x3219, "M", "(타)"), - (0x321A, "M", "(파)"), - (0x321B, "M", "(하)"), - (0x321C, "M", "(주)"), - (0x321D, "M", "(오전)"), - (0x321E, "M", "(오후)"), - (0x321F, "X"), - (0x3220, "M", "(一)"), - (0x3221, "M", "(二)"), - (0x3222, "M", "(三)"), - (0x3223, "M", "(四)"), - (0x3224, "M", "(五)"), - (0x3225, "M", "(六)"), - (0x3226, "M", "(七)"), - (0x3227, "M", "(八)"), - (0x3228, "M", "(九)"), - (0x3229, "M", "(十)"), - (0x322A, "M", "(月)"), - (0x322B, "M", "(火)"), - (0x322C, "M", "(水)"), - (0x322D, "M", "(木)"), - (0x322E, "M", "(金)"), - (0x322F, "M", "(土)"), - (0x3230, "M", "(日)"), - (0x3231, "M", "(株)"), - (0x3232, "M", "(有)"), - (0x3233, "M", "(社)"), - (0x3234, "M", "(名)"), - (0x3235, "M", "(特)"), - (0x3236, "M", "(財)"), - (0x3237, "M", "(祝)"), - (0x3238, "M", "(労)"), - (0x3239, "M", "(代)"), - (0x323A, "M", "(呼)"), - (0x323B, "M", "(学)"), - (0x323C, "M", "(監)"), - (0x323D, "M", "(企)"), - (0x323E, "M", "(資)"), - (0x323F, "M", "(協)"), - (0x3240, "M", "(祭)"), - (0x3241, "M", "(休)"), - (0x3242, "M", "(自)"), - (0x3243, "M", "(至)"), - (0x3244, "M", "問"), - (0x3245, "M", "幼"), - (0x3246, "M", "文"), - (0x3247, "M", "箏"), - (0x3248, "V"), - (0x3250, "M", "pte"), - (0x3251, "M", "21"), - (0x3252, "M", "22"), - (0x3253, "M", "23"), - (0x3254, "M", "24"), - (0x3255, "M", "25"), - (0x3256, "M", "26"), - (0x3257, "M", "27"), - (0x3258, "M", "28"), - (0x3259, "M", "29"), - (0x325A, "M", "30"), - (0x325B, "M", "31"), - (0x325C, "M", "32"), - (0x325D, "M", "33"), - (0x325E, "M", "34"), - (0x325F, "M", "35"), - (0x3260, "M", "ᄀ"), - (0x3261, "M", "ᄂ"), - (0x3262, "M", "ᄃ"), - (0x3263, "M", "ᄅ"), - (0x3264, "M", "ᄆ"), - (0x3265, "M", "ᄇ"), - (0x3266, "M", "ᄉ"), - (0x3267, "M", "ᄋ"), - (0x3268, "M", "ᄌ"), - (0x3269, "M", "ᄎ"), - (0x326A, "M", "ᄏ"), - (0x326B, "M", "ᄐ"), - (0x326C, "M", "ᄑ"), - (0x326D, "M", "ᄒ"), - (0x326E, "M", "가"), - (0x326F, "M", "나"), - (0x3270, "M", "다"), - (0x3271, "M", "라"), - (0x3272, "M", "마"), - (0x3273, "M", "바"), - (0x3274, "M", "사"), - (0x3275, "M", "아"), - (0x3276, "M", "자"), - (0x3277, "M", "차"), - (0x3278, "M", "카"), - (0x3279, "M", "타"), - (0x327A, "M", "파"), - (0x327B, "M", "하"), - (0x327C, "M", "참고"), - (0x327D, "M", "주의"), - (0x327E, "M", "우"), - (0x327F, "V"), - (0x3280, "M", "一"), - (0x3281, "M", "二"), - (0x3282, "M", "三"), - (0x3283, "M", "四"), - (0x3284, "M", "五"), - (0x3285, "M", "六"), - (0x3286, "M", "七"), - (0x3287, "M", "八"), - (0x3288, "M", "九"), - (0x3289, "M", "十"), - (0x328A, "M", "月"), - (0x328B, "M", "火"), - (0x328C, "M", "水"), - (0x328D, "M", "木"), - (0x328E, "M", "金"), - (0x328F, "M", "土"), - (0x3290, "M", "日"), - (0x3291, "M", "株"), - (0x3292, "M", "有"), - (0x3293, "M", "社"), - (0x3294, "M", "名"), - (0x3295, "M", "特"), - (0x3296, "M", "財"), - (0x3297, "M", "祝"), - (0x3298, "M", "労"), - (0x3299, "M", "秘"), - (0x329A, "M", "男"), - (0x329B, "M", "女"), - (0x329C, "M", "適"), - (0x329D, "M", "優"), - (0x329E, "M", "印"), - (0x329F, "M", "注"), - (0x32A0, "M", "項"), - (0x32A1, "M", "休"), - (0x32A2, "M", "写"), - (0x32A3, "M", "正"), - (0x32A4, "M", "上"), - (0x32A5, "M", "中"), - (0x32A6, "M", "下"), - (0x32A7, "M", "左"), - (0x32A8, "M", "右"), - (0x32A9, "M", "医"), - (0x32AA, "M", "宗"), - (0x32AB, "M", "学"), - (0x32AC, "M", "監"), - (0x32AD, "M", "企"), - (0x32AE, "M", "資"), - (0x32AF, "M", "協"), - (0x32B0, "M", "夜"), - (0x32B1, "M", "36"), - (0x32B2, "M", "37"), - (0x32B3, "M", "38"), - (0x32B4, "M", "39"), - (0x32B5, "M", "40"), - (0x32B6, "M", "41"), - (0x32B7, "M", "42"), - (0x32B8, "M", "43"), - (0x32B9, "M", "44"), - (0x32BA, "M", "45"), - (0x32BB, "M", "46"), - (0x32BC, "M", "47"), - (0x32BD, "M", "48"), - (0x32BE, "M", "49"), - (0x32BF, "M", "50"), - (0x32C0, "M", "1月"), - (0x32C1, "M", "2月"), - (0x32C2, "M", "3月"), - (0x32C3, "M", "4月"), - (0x32C4, "M", "5月"), - (0x32C5, "M", "6月"), - (0x32C6, "M", "7月"), - (0x32C7, "M", "8月"), - (0x32C8, "M", "9月"), - (0x32C9, "M", "10月"), - (0x32CA, "M", "11月"), - (0x32CB, "M", "12月"), - (0x32CC, "M", "hg"), - (0x32CD, "M", "erg"), - (0x32CE, "M", "ev"), - (0x32CF, "M", "ltd"), - (0x32D0, "M", "ア"), - (0x32D1, "M", "イ"), - (0x32D2, "M", "ウ"), - (0x32D3, "M", "エ"), - (0x32D4, "M", "オ"), - (0x32D5, "M", "カ"), - (0x32D6, "M", "キ"), - (0x32D7, "M", "ク"), - (0x32D8, "M", "ケ"), - (0x32D9, "M", "コ"), - (0x32DA, "M", "サ"), - (0x32DB, "M", "シ"), - (0x32DC, "M", "ス"), - (0x32DD, "M", "セ"), - (0x32DE, "M", "ソ"), - (0x32DF, "M", "タ"), - (0x32E0, "M", "チ"), - (0x32E1, "M", "ツ"), - (0x32E2, "M", "テ"), - (0x32E3, "M", "ト"), - (0x32E4, "M", "ナ"), - (0x32E5, "M", "ニ"), - (0x32E6, "M", "ヌ"), - (0x32E7, "M", "ネ"), - (0x32E8, "M", "ノ"), - (0x32E9, "M", "ハ"), - (0x32EA, "M", "ヒ"), - (0x32EB, "M", "フ"), - (0x32EC, "M", "ヘ"), - (0x32ED, "M", "ホ"), - (0x32EE, "M", "マ"), - (0x32EF, "M", "ミ"), - (0x32F0, "M", "ム"), - (0x32F1, "M", "メ"), - (0x32F2, "M", "モ"), - (0x32F3, "M", "ヤ"), - (0x32F4, "M", "ユ"), - (0x32F5, "M", "ヨ"), - (0x32F6, "M", "ラ"), - (0x32F7, "M", "リ"), - (0x32F8, "M", "ル"), - (0x32F9, "M", "レ"), - (0x32FA, "M", "ロ"), - (0x32FB, "M", "ワ"), - (0x32FC, "M", "ヰ"), - (0x32FD, "M", "ヱ"), - (0x32FE, "M", "ヲ"), - (0x32FF, "M", "令和"), - (0x3300, "M", "アパート"), - (0x3301, "M", "アルファ"), - (0x3302, "M", "アンペア"), - (0x3303, "M", "アール"), - (0x3304, "M", "イニング"), - (0x3305, "M", "インチ"), - (0x3306, "M", "ウォン"), - (0x3307, "M", "エスクード"), - (0x3308, "M", "エーカー"), - (0x3309, "M", "オンス"), - (0x330A, "M", "オーム"), - (0x330B, "M", "カイリ"), - (0x330C, "M", "カラット"), - (0x330D, "M", "カロリー"), - (0x330E, "M", "ガロン"), - (0x330F, "M", "ガンマ"), - (0x3310, "M", "ギガ"), - (0x3311, "M", "ギニー"), - (0x3312, "M", "キュリー"), - (0x3313, "M", "ギルダー"), - (0x3314, "M", "キロ"), - (0x3315, "M", "キログラム"), - (0x3316, "M", "キロメートル"), - (0x3317, "M", "キロワット"), - (0x3318, "M", "グラム"), - (0x3319, "M", "グラムトン"), - (0x331A, "M", "クルゼイロ"), - (0x331B, "M", "クローネ"), - (0x331C, "M", "ケース"), - (0x331D, "M", "コルナ"), - (0x331E, "M", "コーポ"), - (0x331F, "M", "サイクル"), - (0x3320, "M", "サンチーム"), - (0x3321, "M", "シリング"), - (0x3322, "M", "センチ"), - (0x3323, "M", "セント"), - (0x3324, "M", "ダース"), - (0x3325, "M", "デシ"), - (0x3326, "M", "ドル"), - (0x3327, "M", "トン"), - (0x3328, "M", "ナノ"), - (0x3329, "M", "ノット"), - (0x332A, "M", "ハイツ"), - (0x332B, "M", "パーセント"), - (0x332C, "M", "パーツ"), - (0x332D, "M", "バーレル"), - (0x332E, "M", "ピアストル"), - (0x332F, "M", "ピクル"), - (0x3330, "M", "ピコ"), - (0x3331, "M", "ビル"), - (0x3332, "M", "ファラッド"), - (0x3333, "M", "フィート"), - (0x3334, "M", "ブッシェル"), - (0x3335, "M", "フラン"), - (0x3336, "M", "ヘクタール"), - (0x3337, "M", "ペソ"), - (0x3338, "M", "ペニヒ"), - (0x3339, "M", "ヘルツ"), - (0x333A, "M", "ペンス"), - (0x333B, "M", "ページ"), - (0x333C, "M", "ベータ"), - (0x333D, "M", "ポイント"), - (0x333E, "M", "ボルト"), - (0x333F, "M", "ホン"), - (0x3340, "M", "ポンド"), - (0x3341, "M", "ホール"), - (0x3342, "M", "ホーン"), - (0x3343, "M", "マイクロ"), - (0x3344, "M", "マイル"), - (0x3345, "M", "マッハ"), - (0x3346, "M", "マルク"), - (0x3347, "M", "マンション"), - (0x3348, "M", "ミクロン"), - (0x3349, "M", "ミリ"), - (0x334A, "M", "ミリバール"), - (0x334B, "M", "メガ"), - (0x334C, "M", "メガトン"), - (0x334D, "M", "メートル"), - (0x334E, "M", "ヤード"), - (0x334F, "M", "ヤール"), - (0x3350, "M", "ユアン"), - (0x3351, "M", "リットル"), - (0x3352, "M", "リラ"), - (0x3353, "M", "ルピー"), - (0x3354, "M", "ルーブル"), - (0x3355, "M", "レム"), - (0x3356, "M", "レントゲン"), - (0x3357, "M", "ワット"), - (0x3358, "M", "0点"), - (0x3359, "M", "1点"), - (0x335A, "M", "2点"), - (0x335B, "M", "3点"), - (0x335C, "M", "4点"), - (0x335D, "M", "5点"), - (0x335E, "M", "6点"), - (0x335F, "M", "7点"), - (0x3360, "M", "8点"), - (0x3361, "M", "9点"), - (0x3362, "M", "10点"), - (0x3363, "M", "11点"), - (0x3364, "M", "12点"), - (0x3365, "M", "13点"), - (0x3366, "M", "14点"), - (0x3367, "M", "15点"), - (0x3368, "M", "16点"), - (0x3369, "M", "17点"), - (0x336A, "M", "18点"), - (0x336B, "M", "19点"), - (0x336C, "M", "20点"), - (0x336D, "M", "21点"), - (0x336E, "M", "22点"), - (0x336F, "M", "23点"), - (0x3370, "M", "24点"), - (0x3371, "M", "hpa"), - (0x3372, "M", "da"), - (0x3373, "M", "au"), - (0x3374, "M", "bar"), - (0x3375, "M", "ov"), - (0x3376, "M", "pc"), - (0x3377, "M", "dm"), - (0x3378, "M", "dm2"), - (0x3379, "M", "dm3"), - (0x337A, "M", "iu"), - (0x337B, "M", "平成"), - (0x337C, "M", "昭和"), - (0x337D, "M", "大正"), - (0x337E, "M", "明治"), - (0x337F, "M", "株式会社"), - (0x3380, "M", "pa"), - (0x3381, "M", "na"), - (0x3382, "M", "μa"), - (0x3383, "M", "ma"), - (0x3384, "M", "ka"), - (0x3385, "M", "kb"), - (0x3386, "M", "mb"), - (0x3387, "M", "gb"), - (0x3388, "M", "cal"), - (0x3389, "M", "kcal"), - (0x338A, "M", "pf"), - (0x338B, "M", "nf"), - (0x338C, "M", "μf"), - (0x338D, "M", "μg"), - (0x338E, "M", "mg"), - (0x338F, "M", "kg"), - (0x3390, "M", "hz"), - (0x3391, "M", "khz"), - (0x3392, "M", "mhz"), - (0x3393, "M", "ghz"), - (0x3394, "M", "thz"), - (0x3395, "M", "μl"), - (0x3396, "M", "ml"), - (0x3397, "M", "dl"), - (0x3398, "M", "kl"), - (0x3399, "M", "fm"), - (0x339A, "M", "nm"), - (0x339B, "M", "μm"), - (0x339C, "M", "mm"), - (0x339D, "M", "cm"), - (0x339E, "M", "km"), - (0x339F, "M", "mm2"), - (0x33A0, "M", "cm2"), - (0x33A1, "M", "m2"), - (0x33A2, "M", "km2"), - (0x33A3, "M", "mm3"), - (0x33A4, "M", "cm3"), - (0x33A5, "M", "m3"), - (0x33A6, "M", "km3"), - (0x33A7, "M", "m∕s"), - (0x33A8, "M", "m∕s2"), - (0x33A9, "M", "pa"), - (0x33AA, "M", "kpa"), - (0x33AB, "M", "mpa"), - (0x33AC, "M", "gpa"), - (0x33AD, "M", "rad"), - (0x33AE, "M", "rad∕s"), - (0x33AF, "M", "rad∕s2"), - (0x33B0, "M", "ps"), - (0x33B1, "M", "ns"), - (0x33B2, "M", "μs"), - (0x33B3, "M", "ms"), - (0x33B4, "M", "pv"), - (0x33B5, "M", "nv"), - (0x33B6, "M", "μv"), - (0x33B7, "M", "mv"), - (0x33B8, "M", "kv"), - (0x33B9, "M", "mv"), - (0x33BA, "M", "pw"), - (0x33BB, "M", "nw"), - (0x33BC, "M", "μw"), - (0x33BD, "M", "mw"), - (0x33BE, "M", "kw"), - (0x33BF, "M", "mw"), - (0x33C0, "M", "kω"), - (0x33C1, "M", "mω"), - (0x33C2, "X"), - (0x33C3, "M", "bq"), - (0x33C4, "M", "cc"), - (0x33C5, "M", "cd"), - (0x33C6, "M", "c∕kg"), - (0x33C7, "X"), - (0x33C8, "M", "db"), - (0x33C9, "M", "gy"), - (0x33CA, "M", "ha"), - (0x33CB, "M", "hp"), - (0x33CC, "M", "in"), - (0x33CD, "M", "kk"), - (0x33CE, "M", "km"), - (0x33CF, "M", "kt"), - (0x33D0, "M", "lm"), - (0x33D1, "M", "ln"), - (0x33D2, "M", "log"), - (0x33D3, "M", "lx"), - (0x33D4, "M", "mb"), - (0x33D5, "M", "mil"), - (0x33D6, "M", "mol"), - (0x33D7, "M", "ph"), - (0x33D8, "X"), - (0x33D9, "M", "ppm"), - (0x33DA, "M", "pr"), - (0x33DB, "M", "sr"), - (0x33DC, "M", "sv"), - (0x33DD, "M", "wb"), - (0x33DE, "M", "v∕m"), - (0x33DF, "M", "a∕m"), - (0x33E0, "M", "1日"), - (0x33E1, "M", "2日"), - (0x33E2, "M", "3日"), - (0x33E3, "M", "4日"), - (0x33E4, "M", "5日"), - (0x33E5, "M", "6日"), - (0x33E6, "M", "7日"), - (0x33E7, "M", "8日"), - (0x33E8, "M", "9日"), - (0x33E9, "M", "10日"), - (0x33EA, "M", "11日"), - (0x33EB, "M", "12日"), - (0x33EC, "M", "13日"), - (0x33ED, "M", "14日"), - (0x33EE, "M", "15日"), - (0x33EF, "M", "16日"), - (0x33F0, "M", "17日"), - (0x33F1, "M", "18日"), - (0x33F2, "M", "19日"), - (0x33F3, "M", "20日"), - (0x33F4, "M", "21日"), - (0x33F5, "M", "22日"), - (0x33F6, "M", "23日"), - (0x33F7, "M", "24日"), - (0x33F8, "M", "25日"), - (0x33F9, "M", "26日"), - (0x33FA, "M", "27日"), - (0x33FB, "M", "28日"), - (0x33FC, "M", "29日"), - (0x33FD, "M", "30日"), - (0x33FE, "M", "31日"), - (0x33FF, "M", "gal"), - (0x3400, "V"), - (0xA48D, "X"), - (0xA490, "V"), - (0xA4C7, "X"), - (0xA4D0, "V"), - (0xA62C, "X"), - (0xA640, "M", "ꙁ"), - (0xA641, "V"), - (0xA642, "M", "ꙃ"), - (0xA643, "V"), - (0xA644, "M", "ꙅ"), - (0xA645, "V"), - (0xA646, "M", "ꙇ"), - (0xA647, "V"), - (0xA648, "M", "ꙉ"), - (0xA649, "V"), - (0xA64A, "M", "ꙋ"), - (0xA64B, "V"), - (0xA64C, "M", "ꙍ"), - (0xA64D, "V"), - (0xA64E, "M", "ꙏ"), - (0xA64F, "V"), - (0xA650, "M", "ꙑ"), - (0xA651, "V"), - (0xA652, "M", "ꙓ"), - (0xA653, "V"), - (0xA654, "M", "ꙕ"), - (0xA655, "V"), - (0xA656, "M", "ꙗ"), - (0xA657, "V"), - (0xA658, "M", "ꙙ"), - (0xA659, "V"), - (0xA65A, "M", "ꙛ"), - (0xA65B, "V"), - (0xA65C, "M", "ꙝ"), - (0xA65D, "V"), - (0xA65E, "M", "ꙟ"), - (0xA65F, "V"), - (0xA660, "M", "ꙡ"), - (0xA661, "V"), - (0xA662, "M", "ꙣ"), - (0xA663, "V"), - (0xA664, "M", "ꙥ"), - (0xA665, "V"), - (0xA666, "M", "ꙧ"), - (0xA667, "V"), - (0xA668, "M", "ꙩ"), - (0xA669, "V"), - (0xA66A, "M", "ꙫ"), - (0xA66B, "V"), - (0xA66C, "M", "ꙭ"), - (0xA66D, "V"), - (0xA680, "M", "ꚁ"), - (0xA681, "V"), - (0xA682, "M", "ꚃ"), - (0xA683, "V"), - (0xA684, "M", "ꚅ"), - (0xA685, "V"), - (0xA686, "M", "ꚇ"), - (0xA687, "V"), - (0xA688, "M", "ꚉ"), - (0xA689, "V"), - (0xA68A, "M", "ꚋ"), - (0xA68B, "V"), - (0xA68C, "M", "ꚍ"), - (0xA68D, "V"), - (0xA68E, "M", "ꚏ"), - (0xA68F, "V"), - (0xA690, "M", "ꚑ"), - (0xA691, "V"), - (0xA692, "M", "ꚓ"), - (0xA693, "V"), - (0xA694, "M", "ꚕ"), - (0xA695, "V"), - (0xA696, "M", "ꚗ"), - (0xA697, "V"), - (0xA698, "M", "ꚙ"), - (0xA699, "V"), - (0xA69A, "M", "ꚛ"), - (0xA69B, "V"), - (0xA69C, "M", "ъ"), - (0xA69D, "M", "ь"), - (0xA69E, "V"), - (0xA6F8, "X"), - (0xA700, "V"), - (0xA722, "M", "ꜣ"), - (0xA723, "V"), - (0xA724, "M", "ꜥ"), - (0xA725, "V"), - (0xA726, "M", "ꜧ"), - (0xA727, "V"), - (0xA728, "M", "ꜩ"), - (0xA729, "V"), - (0xA72A, "M", "ꜫ"), - (0xA72B, "V"), - (0xA72C, "M", "ꜭ"), - (0xA72D, "V"), - (0xA72E, "M", "ꜯ"), - (0xA72F, "V"), - (0xA732, "M", "ꜳ"), - (0xA733, "V"), - (0xA734, "M", "ꜵ"), - (0xA735, "V"), - (0xA736, "M", "ꜷ"), - (0xA737, "V"), - (0xA738, "M", "ꜹ"), - (0xA739, "V"), - (0xA73A, "M", "ꜻ"), - (0xA73B, "V"), - (0xA73C, "M", "ꜽ"), - (0xA73D, "V"), - (0xA73E, "M", "ꜿ"), - (0xA73F, "V"), - (0xA740, "M", "ꝁ"), - (0xA741, "V"), - (0xA742, "M", "ꝃ"), - (0xA743, "V"), - (0xA744, "M", "ꝅ"), - (0xA745, "V"), - (0xA746, "M", "ꝇ"), - (0xA747, "V"), - (0xA748, "M", "ꝉ"), - (0xA749, "V"), - (0xA74A, "M", "ꝋ"), - (0xA74B, "V"), - (0xA74C, "M", "ꝍ"), - (0xA74D, "V"), - (0xA74E, "M", "ꝏ"), - (0xA74F, "V"), - (0xA750, "M", "ꝑ"), - (0xA751, "V"), - (0xA752, "M", "ꝓ"), - (0xA753, "V"), - (0xA754, "M", "ꝕ"), - (0xA755, "V"), - (0xA756, "M", "ꝗ"), - (0xA757, "V"), - (0xA758, "M", "ꝙ"), - (0xA759, "V"), - (0xA75A, "M", "ꝛ"), - (0xA75B, "V"), - (0xA75C, "M", "ꝝ"), - (0xA75D, "V"), - (0xA75E, "M", "ꝟ"), - (0xA75F, "V"), - (0xA760, "M", "ꝡ"), - (0xA761, "V"), - (0xA762, "M", "ꝣ"), - (0xA763, "V"), - (0xA764, "M", "ꝥ"), - (0xA765, "V"), - (0xA766, "M", "ꝧ"), - (0xA767, "V"), - (0xA768, "M", "ꝩ"), - (0xA769, "V"), - (0xA76A, "M", "ꝫ"), - (0xA76B, "V"), - (0xA76C, "M", "ꝭ"), - (0xA76D, "V"), - (0xA76E, "M", "ꝯ"), - (0xA76F, "V"), - (0xA770, "M", "ꝯ"), - (0xA771, "V"), - (0xA779, "M", "ꝺ"), - (0xA77A, "V"), - (0xA77B, "M", "ꝼ"), - (0xA77C, "V"), - (0xA77D, "M", "ᵹ"), - (0xA77E, "M", "ꝿ"), - (0xA77F, "V"), - (0xA780, "M", "ꞁ"), - (0xA781, "V"), - (0xA782, "M", "ꞃ"), - (0xA783, "V"), - (0xA784, "M", "ꞅ"), - (0xA785, "V"), - (0xA786, "M", "ꞇ"), - (0xA787, "V"), - (0xA78B, "M", "ꞌ"), - (0xA78C, "V"), - (0xA78D, "M", "ɥ"), - (0xA78E, "V"), - (0xA790, "M", "ꞑ"), - (0xA791, "V"), - (0xA792, "M", "ꞓ"), - (0xA793, "V"), - (0xA796, "M", "ꞗ"), - (0xA797, "V"), - (0xA798, "M", "ꞙ"), - (0xA799, "V"), - (0xA79A, "M", "ꞛ"), - (0xA79B, "V"), - (0xA79C, "M", "ꞝ"), - (0xA79D, "V"), - (0xA79E, "M", "ꞟ"), - (0xA79F, "V"), - (0xA7A0, "M", "ꞡ"), - (0xA7A1, "V"), - (0xA7A2, "M", "ꞣ"), - (0xA7A3, "V"), - (0xA7A4, "M", "ꞥ"), - (0xA7A5, "V"), - (0xA7A6, "M", "ꞧ"), - (0xA7A7, "V"), - (0xA7A8, "M", "ꞩ"), - (0xA7A9, "V"), - (0xA7AA, "M", "ɦ"), - (0xA7AB, "M", "ɜ"), - (0xA7AC, "M", "ɡ"), - (0xA7AD, "M", "ɬ"), - (0xA7AE, "M", "ɪ"), - (0xA7AF, "V"), - (0xA7B0, "M", "ʞ"), - (0xA7B1, "M", "ʇ"), - (0xA7B2, "M", "ʝ"), - (0xA7B3, "M", "ꭓ"), - (0xA7B4, "M", "ꞵ"), - (0xA7B5, "V"), - (0xA7B6, "M", "ꞷ"), - (0xA7B7, "V"), - (0xA7B8, "M", "ꞹ"), - (0xA7B9, "V"), - (0xA7BA, "M", "ꞻ"), - (0xA7BB, "V"), - (0xA7BC, "M", "ꞽ"), - (0xA7BD, "V"), - (0xA7BE, "M", "ꞿ"), - (0xA7BF, "V"), - (0xA7C0, "M", "ꟁ"), - (0xA7C1, "V"), - (0xA7C2, "M", "ꟃ"), - (0xA7C3, "V"), - (0xA7C4, "M", "ꞔ"), - (0xA7C5, "M", "ʂ"), - (0xA7C6, "M", "ᶎ"), - (0xA7C7, "M", "ꟈ"), - (0xA7C8, "V"), - (0xA7C9, "M", "ꟊ"), - (0xA7CA, "V"), - (0xA7CB, "M", "ɤ"), - (0xA7CC, "M", "ꟍ"), - (0xA7CD, "V"), - (0xA7CE, "M", "꟏"), - (0xA7CF, "V"), - (0xA7D0, "M", "ꟑ"), - (0xA7D1, "V"), - (0xA7D2, "M", "ꟓ"), - (0xA7D3, "V"), - (0xA7D4, "M", "ꟕ"), - (0xA7D5, "V"), - (0xA7D6, "M", "ꟗ"), - (0xA7D7, "V"), - (0xA7D8, "M", "ꟙ"), - (0xA7D9, "V"), - (0xA7DA, "M", "ꟛ"), - (0xA7DB, "V"), - (0xA7DC, "M", "ƛ"), - (0xA7DD, "X"), - (0xA7F1, "M", "s"), - (0xA7F2, "M", "c"), - (0xA7F3, "M", "f"), - (0xA7F4, "M", "q"), - (0xA7F5, "M", "ꟶ"), - (0xA7F6, "V"), - (0xA7F8, "M", "ħ"), - (0xA7F9, "M", "œ"), - (0xA7FA, "V"), - (0xA82D, "X"), - (0xA830, "V"), - (0xA83A, "X"), - (0xA840, "V"), - (0xA878, "X"), - (0xA880, "V"), - (0xA8C6, "X"), - (0xA8CE, "V"), - (0xA8DA, "X"), - (0xA8E0, "V"), - (0xA954, "X"), - (0xA95F, "V"), - (0xA97D, "X"), - (0xA980, "V"), - (0xA9CE, "X"), - (0xA9CF, "V"), - (0xA9DA, "X"), - (0xA9DE, "V"), - (0xA9FF, "X"), - (0xAA00, "V"), - (0xAA37, "X"), - (0xAA40, "V"), - (0xAA4E, "X"), - (0xAA50, "V"), - (0xAA5A, "X"), - (0xAA5C, "V"), - (0xAAC3, "X"), - (0xAADB, "V"), - (0xAAF7, "X"), - (0xAB01, "V"), - (0xAB07, "X"), - (0xAB09, "V"), - (0xAB0F, "X"), - (0xAB11, "V"), - (0xAB17, "X"), - (0xAB20, "V"), - (0xAB27, "X"), - (0xAB28, "V"), - (0xAB2F, "X"), - (0xAB30, "V"), - (0xAB5C, "M", "ꜧ"), - (0xAB5D, "M", "ꬷ"), - (0xAB5E, "M", "ɫ"), - (0xAB5F, "M", "ꭒ"), - (0xAB60, "V"), - (0xAB69, "M", "ʍ"), - (0xAB6A, "V"), - (0xAB6C, "X"), - (0xAB70, "M", "Ꭰ"), - (0xAB71, "M", "Ꭱ"), - (0xAB72, "M", "Ꭲ"), - (0xAB73, "M", "Ꭳ"), - (0xAB74, "M", "Ꭴ"), - (0xAB75, "M", "Ꭵ"), - (0xAB76, "M", "Ꭶ"), - (0xAB77, "M", "Ꭷ"), - (0xAB78, "M", "Ꭸ"), - (0xAB79, "M", "Ꭹ"), - (0xAB7A, "M", "Ꭺ"), - (0xAB7B, "M", "Ꭻ"), - (0xAB7C, "M", "Ꭼ"), - (0xAB7D, "M", "Ꭽ"), - (0xAB7E, "M", "Ꭾ"), - (0xAB7F, "M", "Ꭿ"), - (0xAB80, "M", "Ꮀ"), - (0xAB81, "M", "Ꮁ"), - (0xAB82, "M", "Ꮂ"), - (0xAB83, "M", "Ꮃ"), - (0xAB84, "M", "Ꮄ"), - (0xAB85, "M", "Ꮅ"), - (0xAB86, "M", "Ꮆ"), - (0xAB87, "M", "Ꮇ"), - (0xAB88, "M", "Ꮈ"), - (0xAB89, "M", "Ꮉ"), - (0xAB8A, "M", "Ꮊ"), - (0xAB8B, "M", "Ꮋ"), - (0xAB8C, "M", "Ꮌ"), - (0xAB8D, "M", "Ꮍ"), - (0xAB8E, "M", "Ꮎ"), - (0xAB8F, "M", "Ꮏ"), - (0xAB90, "M", "Ꮐ"), - (0xAB91, "M", "Ꮑ"), - (0xAB92, "M", "Ꮒ"), - (0xAB93, "M", "Ꮓ"), - (0xAB94, "M", "Ꮔ"), - (0xAB95, "M", "Ꮕ"), - (0xAB96, "M", "Ꮖ"), - (0xAB97, "M", "Ꮗ"), - (0xAB98, "M", "Ꮘ"), - (0xAB99, "M", "Ꮙ"), - (0xAB9A, "M", "Ꮚ"), - (0xAB9B, "M", "Ꮛ"), - (0xAB9C, "M", "Ꮜ"), - (0xAB9D, "M", "Ꮝ"), - (0xAB9E, "M", "Ꮞ"), - (0xAB9F, "M", "Ꮟ"), - (0xABA0, "M", "Ꮠ"), - (0xABA1, "M", "Ꮡ"), - (0xABA2, "M", "Ꮢ"), - (0xABA3, "M", "Ꮣ"), - (0xABA4, "M", "Ꮤ"), - (0xABA5, "M", "Ꮥ"), - (0xABA6, "M", "Ꮦ"), - (0xABA7, "M", "Ꮧ"), - (0xABA8, "M", "Ꮨ"), - (0xABA9, "M", "Ꮩ"), - (0xABAA, "M", "Ꮪ"), - (0xABAB, "M", "Ꮫ"), - (0xABAC, "M", "Ꮬ"), - (0xABAD, "M", "Ꮭ"), - (0xABAE, "M", "Ꮮ"), - (0xABAF, "M", "Ꮯ"), - (0xABB0, "M", "Ꮰ"), - (0xABB1, "M", "Ꮱ"), - (0xABB2, "M", "Ꮲ"), - (0xABB3, "M", "Ꮳ"), - (0xABB4, "M", "Ꮴ"), - (0xABB5, "M", "Ꮵ"), - (0xABB6, "M", "Ꮶ"), - (0xABB7, "M", "Ꮷ"), - (0xABB8, "M", "Ꮸ"), - (0xABB9, "M", "Ꮹ"), - (0xABBA, "M", "Ꮺ"), - (0xABBB, "M", "Ꮻ"), - (0xABBC, "M", "Ꮼ"), - (0xABBD, "M", "Ꮽ"), - (0xABBE, "M", "Ꮾ"), - (0xABBF, "M", "Ꮿ"), - (0xABC0, "V"), - (0xABEE, "X"), - (0xABF0, "V"), - (0xABFA, "X"), - (0xAC00, "V"), - (0xD7A4, "X"), - (0xD7B0, "V"), - (0xD7C7, "X"), - (0xD7CB, "V"), - (0xD7FC, "X"), - (0xF900, "M", "豈"), - (0xF901, "M", "更"), - (0xF902, "M", "車"), - (0xF903, "M", "賈"), - (0xF904, "M", "滑"), - (0xF905, "M", "串"), - (0xF906, "M", "句"), - (0xF907, "M", "龜"), - (0xF909, "M", "契"), - (0xF90A, "M", "金"), - (0xF90B, "M", "喇"), - (0xF90C, "M", "奈"), - (0xF90D, "M", "懶"), - (0xF90E, "M", "癩"), - (0xF90F, "M", "羅"), - (0xF910, "M", "蘿"), - (0xF911, "M", "螺"), - (0xF912, "M", "裸"), - (0xF913, "M", "邏"), - (0xF914, "M", "樂"), - (0xF915, "M", "洛"), - (0xF916, "M", "烙"), - (0xF917, "M", "珞"), - (0xF918, "M", "落"), - (0xF919, "M", "酪"), - (0xF91A, "M", "駱"), - (0xF91B, "M", "亂"), - (0xF91C, "M", "卵"), - (0xF91D, "M", "欄"), - (0xF91E, "M", "爛"), - (0xF91F, "M", "蘭"), - (0xF920, "M", "鸞"), - (0xF921, "M", "嵐"), - (0xF922, "M", "濫"), - (0xF923, "M", "藍"), - (0xF924, "M", "襤"), - (0xF925, "M", "拉"), - (0xF926, "M", "臘"), - (0xF927, "M", "蠟"), - (0xF928, "M", "廊"), - (0xF929, "M", "朗"), - (0xF92A, "M", "浪"), - (0xF92B, "M", "狼"), - (0xF92C, "M", "郎"), - (0xF92D, "M", "來"), - (0xF92E, "M", "冷"), - (0xF92F, "M", "勞"), - (0xF930, "M", "擄"), - (0xF931, "M", "櫓"), - (0xF932, "M", "爐"), - (0xF933, "M", "盧"), - (0xF934, "M", "老"), - (0xF935, "M", "蘆"), - (0xF936, "M", "虜"), - (0xF937, "M", "路"), - (0xF938, "M", "露"), - (0xF939, "M", "魯"), - (0xF93A, "M", "鷺"), - (0xF93B, "M", "碌"), - (0xF93C, "M", "祿"), - (0xF93D, "M", "綠"), - (0xF93E, "M", "菉"), - (0xF93F, "M", "錄"), - (0xF940, "M", "鹿"), - (0xF941, "M", "論"), - (0xF942, "M", "壟"), - (0xF943, "M", "弄"), - (0xF944, "M", "籠"), - (0xF945, "M", "聾"), - (0xF946, "M", "牢"), - (0xF947, "M", "磊"), - (0xF948, "M", "賂"), - (0xF949, "M", "雷"), - (0xF94A, "M", "壘"), - (0xF94B, "M", "屢"), - (0xF94C, "M", "樓"), - (0xF94D, "M", "淚"), - (0xF94E, "M", "漏"), - (0xF94F, "M", "累"), - (0xF950, "M", "縷"), - (0xF951, "M", "陋"), - (0xF952, "M", "勒"), - (0xF953, "M", "肋"), - (0xF954, "M", "凜"), - (0xF955, "M", "凌"), - (0xF956, "M", "稜"), - (0xF957, "M", "綾"), - (0xF958, "M", "菱"), - (0xF959, "M", "陵"), - (0xF95A, "M", "讀"), - (0xF95B, "M", "拏"), - (0xF95C, "M", "樂"), - (0xF95D, "M", "諾"), - (0xF95E, "M", "丹"), - (0xF95F, "M", "寧"), - (0xF960, "M", "怒"), - (0xF961, "M", "率"), - (0xF962, "M", "異"), - (0xF963, "M", "北"), - (0xF964, "M", "磻"), - (0xF965, "M", "便"), - (0xF966, "M", "復"), - (0xF967, "M", "不"), - (0xF968, "M", "泌"), - (0xF969, "M", "數"), - (0xF96A, "M", "索"), - (0xF96B, "M", "參"), - (0xF96C, "M", "塞"), - (0xF96D, "M", "省"), - (0xF96E, "M", "葉"), - (0xF96F, "M", "說"), - (0xF970, "M", "殺"), - (0xF971, "M", "辰"), - (0xF972, "M", "沈"), - (0xF973, "M", "拾"), - (0xF974, "M", "若"), - (0xF975, "M", "掠"), - (0xF976, "M", "略"), - (0xF977, "M", "亮"), - (0xF978, "M", "兩"), - (0xF979, "M", "凉"), - (0xF97A, "M", "梁"), - (0xF97B, "M", "糧"), - (0xF97C, "M", "良"), - (0xF97D, "M", "諒"), - (0xF97E, "M", "量"), - (0xF97F, "M", "勵"), - (0xF980, "M", "呂"), - (0xF981, "M", "女"), - (0xF982, "M", "廬"), - (0xF983, "M", "旅"), - (0xF984, "M", "濾"), - (0xF985, "M", "礪"), - (0xF986, "M", "閭"), - (0xF987, "M", "驪"), - (0xF988, "M", "麗"), - (0xF989, "M", "黎"), - (0xF98A, "M", "力"), - (0xF98B, "M", "曆"), - (0xF98C, "M", "歷"), - (0xF98D, "M", "轢"), - (0xF98E, "M", "年"), - (0xF98F, "M", "憐"), - (0xF990, "M", "戀"), - (0xF991, "M", "撚"), - (0xF992, "M", "漣"), - (0xF993, "M", "煉"), - (0xF994, "M", "璉"), - (0xF995, "M", "秊"), - (0xF996, "M", "練"), - (0xF997, "M", "聯"), - (0xF998, "M", "輦"), - (0xF999, "M", "蓮"), - (0xF99A, "M", "連"), - (0xF99B, "M", "鍊"), - (0xF99C, "M", "列"), - (0xF99D, "M", "劣"), - (0xF99E, "M", "咽"), - (0xF99F, "M", "烈"), - (0xF9A0, "M", "裂"), - (0xF9A1, "M", "說"), - (0xF9A2, "M", "廉"), - (0xF9A3, "M", "念"), - (0xF9A4, "M", "捻"), - (0xF9A5, "M", "殮"), - (0xF9A6, "M", "簾"), - (0xF9A7, "M", "獵"), - (0xF9A8, "M", "令"), - (0xF9A9, "M", "囹"), - (0xF9AA, "M", "寧"), - (0xF9AB, "M", "嶺"), - (0xF9AC, "M", "怜"), - (0xF9AD, "M", "玲"), - (0xF9AE, "M", "瑩"), - (0xF9AF, "M", "羚"), - (0xF9B0, "M", "聆"), - (0xF9B1, "M", "鈴"), - (0xF9B2, "M", "零"), - (0xF9B3, "M", "靈"), - (0xF9B4, "M", "領"), - (0xF9B5, "M", "例"), - (0xF9B6, "M", "禮"), - (0xF9B7, "M", "醴"), - (0xF9B8, "M", "隸"), - (0xF9B9, "M", "惡"), - (0xF9BA, "M", "了"), - (0xF9BB, "M", "僚"), - (0xF9BC, "M", "寮"), - (0xF9BD, "M", "尿"), - (0xF9BE, "M", "料"), - (0xF9BF, "M", "樂"), - (0xF9C0, "M", "燎"), - (0xF9C1, "M", "療"), - (0xF9C2, "M", "蓼"), - (0xF9C3, "M", "遼"), - (0xF9C4, "M", "龍"), - (0xF9C5, "M", "暈"), - (0xF9C6, "M", "阮"), - (0xF9C7, "M", "劉"), - (0xF9C8, "M", "杻"), - (0xF9C9, "M", "柳"), - (0xF9CA, "M", "流"), - (0xF9CB, "M", "溜"), - (0xF9CC, "M", "琉"), - (0xF9CD, "M", "留"), - (0xF9CE, "M", "硫"), - (0xF9CF, "M", "紐"), - (0xF9D0, "M", "類"), - (0xF9D1, "M", "六"), - (0xF9D2, "M", "戮"), - (0xF9D3, "M", "陸"), - (0xF9D4, "M", "倫"), - (0xF9D5, "M", "崙"), - (0xF9D6, "M", "淪"), - (0xF9D7, "M", "輪"), - (0xF9D8, "M", "律"), - (0xF9D9, "M", "慄"), - (0xF9DA, "M", "栗"), - (0xF9DB, "M", "率"), - (0xF9DC, "M", "隆"), - (0xF9DD, "M", "利"), - (0xF9DE, "M", "吏"), - (0xF9DF, "M", "履"), - (0xF9E0, "M", "易"), - (0xF9E1, "M", "李"), - (0xF9E2, "M", "梨"), - (0xF9E3, "M", "泥"), - (0xF9E4, "M", "理"), - (0xF9E5, "M", "痢"), - (0xF9E6, "M", "罹"), - (0xF9E7, "M", "裏"), - (0xF9E8, "M", "裡"), - (0xF9E9, "M", "里"), - (0xF9EA, "M", "離"), - (0xF9EB, "M", "匿"), - (0xF9EC, "M", "溺"), - (0xF9ED, "M", "吝"), - (0xF9EE, "M", "燐"), - (0xF9EF, "M", "璘"), - (0xF9F0, "M", "藺"), - (0xF9F1, "M", "隣"), - (0xF9F2, "M", "鱗"), - (0xF9F3, "M", "麟"), - (0xF9F4, "M", "林"), - (0xF9F5, "M", "淋"), - (0xF9F6, "M", "臨"), - (0xF9F7, "M", "立"), - (0xF9F8, "M", "笠"), - (0xF9F9, "M", "粒"), - (0xF9FA, "M", "狀"), - (0xF9FB, "M", "炙"), - (0xF9FC, "M", "識"), - (0xF9FD, "M", "什"), - (0xF9FE, "M", "茶"), - (0xF9FF, "M", "刺"), - (0xFA00, "M", "切"), - (0xFA01, "M", "度"), - (0xFA02, "M", "拓"), - (0xFA03, "M", "糖"), - (0xFA04, "M", "宅"), - (0xFA05, "M", "洞"), - (0xFA06, "M", "暴"), - (0xFA07, "M", "輻"), - (0xFA08, "M", "行"), - (0xFA09, "M", "降"), - (0xFA0A, "M", "見"), - (0xFA0B, "M", "廓"), - (0xFA0C, "M", "兀"), - (0xFA0D, "M", "嗀"), - (0xFA0E, "V"), - (0xFA10, "M", "塚"), - (0xFA11, "V"), - (0xFA12, "M", "晴"), - (0xFA13, "V"), - (0xFA15, "M", "凞"), - (0xFA16, "M", "猪"), - (0xFA17, "M", "益"), - (0xFA18, "M", "礼"), - (0xFA19, "M", "神"), - (0xFA1A, "M", "祥"), - (0xFA1B, "M", "福"), - (0xFA1C, "M", "靖"), - (0xFA1D, "M", "精"), - (0xFA1E, "M", "羽"), - (0xFA1F, "V"), - (0xFA20, "M", "蘒"), - (0xFA21, "V"), - (0xFA22, "M", "諸"), - (0xFA23, "V"), - (0xFA25, "M", "逸"), - (0xFA26, "M", "都"), - (0xFA27, "V"), - (0xFA2A, "M", "飯"), - (0xFA2B, "M", "飼"), - (0xFA2C, "M", "館"), - (0xFA2D, "M", "鶴"), - (0xFA2E, "M", "郞"), - (0xFA2F, "M", "隷"), - (0xFA30, "M", "侮"), - (0xFA31, "M", "僧"), - (0xFA32, "M", "免"), - (0xFA33, "M", "勉"), - (0xFA34, "M", "勤"), - (0xFA35, "M", "卑"), - (0xFA36, "M", "喝"), - (0xFA37, "M", "嘆"), - (0xFA38, "M", "器"), - (0xFA39, "M", "塀"), - (0xFA3A, "M", "墨"), - (0xFA3B, "M", "層"), - (0xFA3C, "M", "屮"), - (0xFA3D, "M", "悔"), - (0xFA3E, "M", "慨"), - (0xFA3F, "M", "憎"), - (0xFA40, "M", "懲"), - (0xFA41, "M", "敏"), - (0xFA42, "M", "既"), - (0xFA43, "M", "暑"), - (0xFA44, "M", "梅"), - (0xFA45, "M", "海"), - (0xFA46, "M", "渚"), - (0xFA47, "M", "漢"), - (0xFA48, "M", "煮"), - (0xFA49, "M", "爫"), - (0xFA4A, "M", "琢"), - (0xFA4B, "M", "碑"), - (0xFA4C, "M", "社"), - (0xFA4D, "M", "祉"), - (0xFA4E, "M", "祈"), - (0xFA4F, "M", "祐"), - (0xFA50, "M", "祖"), - (0xFA51, "M", "祝"), - (0xFA52, "M", "禍"), - (0xFA53, "M", "禎"), - (0xFA54, "M", "穀"), - (0xFA55, "M", "突"), - (0xFA56, "M", "節"), - (0xFA57, "M", "練"), - (0xFA58, "M", "縉"), - (0xFA59, "M", "繁"), - (0xFA5A, "M", "署"), - (0xFA5B, "M", "者"), - (0xFA5C, "M", "臭"), - (0xFA5D, "M", "艹"), - (0xFA5F, "M", "著"), - (0xFA60, "M", "褐"), - (0xFA61, "M", "視"), - (0xFA62, "M", "謁"), - (0xFA63, "M", "謹"), - (0xFA64, "M", "賓"), - (0xFA65, "M", "贈"), - (0xFA66, "M", "辶"), - (0xFA67, "M", "逸"), - (0xFA68, "M", "難"), - (0xFA69, "M", "響"), - (0xFA6A, "M", "頻"), - (0xFA6B, "M", "恵"), - (0xFA6C, "M", "𤋮"), - (0xFA6D, "M", "舘"), - (0xFA6E, "X"), - (0xFA70, "M", "並"), - (0xFA71, "M", "况"), - (0xFA72, "M", "全"), - (0xFA73, "M", "侀"), - (0xFA74, "M", "充"), - (0xFA75, "M", "冀"), - (0xFA76, "M", "勇"), - (0xFA77, "M", "勺"), - (0xFA78, "M", "喝"), - (0xFA79, "M", "啕"), - (0xFA7A, "M", "喙"), - (0xFA7B, "M", "嗢"), - (0xFA7C, "M", "塚"), - (0xFA7D, "M", "墳"), - (0xFA7E, "M", "奄"), - (0xFA7F, "M", "奔"), - (0xFA80, "M", "婢"), - (0xFA81, "M", "嬨"), - (0xFA82, "M", "廒"), - (0xFA83, "M", "廙"), - (0xFA84, "M", "彩"), - (0xFA85, "M", "徭"), - (0xFA86, "M", "惘"), - (0xFA87, "M", "慎"), - (0xFA88, "M", "愈"), - (0xFA89, "M", "憎"), - (0xFA8A, "M", "慠"), - (0xFA8B, "M", "懲"), - (0xFA8C, "M", "戴"), - (0xFA8D, "M", "揄"), - (0xFA8E, "M", "搜"), - (0xFA8F, "M", "摒"), - (0xFA90, "M", "敖"), - (0xFA91, "M", "晴"), - (0xFA92, "M", "朗"), - (0xFA93, "M", "望"), - (0xFA94, "M", "杖"), - (0xFA95, "M", "歹"), - (0xFA96, "M", "殺"), - (0xFA97, "M", "流"), - (0xFA98, "M", "滛"), - (0xFA99, "M", "滋"), - (0xFA9A, "M", "漢"), - (0xFA9B, "M", "瀞"), - (0xFA9C, "M", "煮"), - (0xFA9D, "M", "瞧"), - (0xFA9E, "M", "爵"), - (0xFA9F, "M", "犯"), - (0xFAA0, "M", "猪"), - (0xFAA1, "M", "瑱"), - (0xFAA2, "M", "甆"), - (0xFAA3, "M", "画"), - (0xFAA4, "M", "瘝"), - (0xFAA5, "M", "瘟"), - (0xFAA6, "M", "益"), - (0xFAA7, "M", "盛"), - (0xFAA8, "M", "直"), - (0xFAA9, "M", "睊"), - (0xFAAA, "M", "着"), - (0xFAAB, "M", "磌"), - (0xFAAC, "M", "窱"), - (0xFAAD, "M", "節"), - (0xFAAE, "M", "类"), - (0xFAAF, "M", "絛"), - (0xFAB0, "M", "練"), - (0xFAB1, "M", "缾"), - (0xFAB2, "M", "者"), - (0xFAB3, "M", "荒"), - (0xFAB4, "M", "華"), - (0xFAB5, "M", "蝹"), - (0xFAB6, "M", "襁"), - (0xFAB7, "M", "覆"), - (0xFAB8, "M", "視"), - (0xFAB9, "M", "調"), - (0xFABA, "M", "諸"), - (0xFABB, "M", "請"), - (0xFABC, "M", "謁"), - (0xFABD, "M", "諾"), - (0xFABE, "M", "諭"), - (0xFABF, "M", "謹"), - (0xFAC0, "M", "變"), - (0xFAC1, "M", "贈"), - (0xFAC2, "M", "輸"), - (0xFAC3, "M", "遲"), - (0xFAC4, "M", "醙"), - (0xFAC5, "M", "鉶"), - (0xFAC6, "M", "陼"), - (0xFAC7, "M", "難"), - (0xFAC8, "M", "靖"), - (0xFAC9, "M", "韛"), - (0xFACA, "M", "響"), - (0xFACB, "M", "頋"), - (0xFACC, "M", "頻"), - (0xFACD, "M", "鬒"), - (0xFACE, "M", "龜"), - (0xFACF, "M", "𢡊"), - (0xFAD0, "M", "𢡄"), - (0xFAD1, "M", "𣏕"), - (0xFAD2, "M", "㮝"), - (0xFAD3, "M", "䀘"), - (0xFAD4, "M", "䀹"), - (0xFAD5, "M", "𥉉"), - (0xFAD6, "M", "𥳐"), - (0xFAD7, "M", "𧻓"), - (0xFAD8, "M", "齃"), - (0xFAD9, "M", "龎"), - (0xFADA, "X"), - (0xFB00, "M", "ff"), - (0xFB01, "M", "fi"), - (0xFB02, "M", "fl"), - (0xFB03, "M", "ffi"), - (0xFB04, "M", "ffl"), - (0xFB05, "M", "st"), - (0xFB07, "X"), - (0xFB13, "M", "մն"), - (0xFB14, "M", "մե"), - (0xFB15, "M", "մի"), - (0xFB16, "M", "վն"), - (0xFB17, "M", "մխ"), - (0xFB18, "X"), - (0xFB1D, "M", "יִ"), - (0xFB1E, "V"), - (0xFB1F, "M", "ײַ"), - (0xFB20, "M", "ע"), - (0xFB21, "M", "א"), - (0xFB22, "M", "ד"), - (0xFB23, "M", "ה"), - (0xFB24, "M", "כ"), - (0xFB25, "M", "ל"), - (0xFB26, "M", "ם"), - (0xFB27, "M", "ר"), - (0xFB28, "M", "ת"), - (0xFB29, "M", "+"), - (0xFB2A, "M", "שׁ"), - (0xFB2B, "M", "שׂ"), - (0xFB2C, "M", "שּׁ"), - (0xFB2D, "M", "שּׂ"), - (0xFB2E, "M", "אַ"), - (0xFB2F, "M", "אָ"), - (0xFB30, "M", "אּ"), - (0xFB31, "M", "בּ"), - (0xFB32, "M", "גּ"), - (0xFB33, "M", "דּ"), - (0xFB34, "M", "הּ"), - (0xFB35, "M", "וּ"), - (0xFB36, "M", "זּ"), - (0xFB37, "X"), - (0xFB38, "M", "טּ"), - (0xFB39, "M", "יּ"), - (0xFB3A, "M", "ךּ"), - (0xFB3B, "M", "כּ"), - (0xFB3C, "M", "לּ"), - (0xFB3D, "X"), - (0xFB3E, "M", "מּ"), - (0xFB3F, "X"), - (0xFB40, "M", "נּ"), - (0xFB41, "M", "סּ"), - (0xFB42, "X"), - (0xFB43, "M", "ףּ"), - (0xFB44, "M", "פּ"), - (0xFB45, "X"), - (0xFB46, "M", "צּ"), - (0xFB47, "M", "קּ"), - (0xFB48, "M", "רּ"), - (0xFB49, "M", "שּ"), - (0xFB4A, "M", "תּ"), - (0xFB4B, "M", "וֹ"), - (0xFB4C, "M", "בֿ"), - (0xFB4D, "M", "כֿ"), - (0xFB4E, "M", "פֿ"), - (0xFB4F, "M", "אל"), - (0xFB50, "M", "ٱ"), - (0xFB52, "M", "ٻ"), - (0xFB56, "M", "پ"), - (0xFB5A, "M", "ڀ"), - (0xFB5E, "M", "ٺ"), - (0xFB62, "M", "ٿ"), - (0xFB66, "M", "ٹ"), - (0xFB6A, "M", "ڤ"), - (0xFB6E, "M", "ڦ"), - (0xFB72, "M", "ڄ"), - (0xFB76, "M", "ڃ"), - (0xFB7A, "M", "چ"), - (0xFB7E, "M", "ڇ"), - (0xFB82, "M", "ڍ"), - (0xFB84, "M", "ڌ"), - (0xFB86, "M", "ڎ"), - (0xFB88, "M", "ڈ"), - (0xFB8A, "M", "ژ"), - (0xFB8C, "M", "ڑ"), - (0xFB8E, "M", "ک"), - (0xFB92, "M", "گ"), - (0xFB96, "M", "ڳ"), - (0xFB9A, "M", "ڱ"), - (0xFB9E, "M", "ں"), - (0xFBA0, "M", "ڻ"), - (0xFBA4, "M", "ۀ"), - (0xFBA6, "M", "ہ"), - (0xFBAA, "M", "ھ"), - (0xFBAE, "M", "ے"), - (0xFBB0, "M", "ۓ"), - (0xFBB2, "V"), - (0xFBD3, "M", "ڭ"), - (0xFBD7, "M", "ۇ"), - (0xFBD9, "M", "ۆ"), - (0xFBDB, "M", "ۈ"), - (0xFBDD, "M", "ۇٴ"), - (0xFBDE, "M", "ۋ"), - (0xFBE0, "M", "ۅ"), - (0xFBE2, "M", "ۉ"), - (0xFBE4, "M", "ې"), - (0xFBE8, "M", "ى"), - (0xFBEA, "M", "ئا"), - (0xFBEC, "M", "ئە"), - (0xFBEE, "M", "ئو"), - (0xFBF0, "M", "ئۇ"), - (0xFBF2, "M", "ئۆ"), - (0xFBF4, "M", "ئۈ"), - (0xFBF6, "M", "ئې"), - (0xFBF9, "M", "ئى"), - (0xFBFC, "M", "ی"), - (0xFC00, "M", "ئج"), - (0xFC01, "M", "ئح"), - (0xFC02, "M", "ئم"), - (0xFC03, "M", "ئى"), - (0xFC04, "M", "ئي"), - (0xFC05, "M", "بج"), - (0xFC06, "M", "بح"), - (0xFC07, "M", "بخ"), - (0xFC08, "M", "بم"), - (0xFC09, "M", "بى"), - (0xFC0A, "M", "بي"), - (0xFC0B, "M", "تج"), - (0xFC0C, "M", "تح"), - (0xFC0D, "M", "تخ"), - (0xFC0E, "M", "تم"), - (0xFC0F, "M", "تى"), - (0xFC10, "M", "تي"), - (0xFC11, "M", "ثج"), - (0xFC12, "M", "ثم"), - (0xFC13, "M", "ثى"), - (0xFC14, "M", "ثي"), - (0xFC15, "M", "جح"), - (0xFC16, "M", "جم"), - (0xFC17, "M", "حج"), - (0xFC18, "M", "حم"), - (0xFC19, "M", "خج"), - (0xFC1A, "M", "خح"), - (0xFC1B, "M", "خم"), - (0xFC1C, "M", "سج"), - (0xFC1D, "M", "سح"), - (0xFC1E, "M", "سخ"), - (0xFC1F, "M", "سم"), - (0xFC20, "M", "صح"), - (0xFC21, "M", "صم"), - (0xFC22, "M", "ضج"), - (0xFC23, "M", "ضح"), - (0xFC24, "M", "ضخ"), - (0xFC25, "M", "ضم"), - (0xFC26, "M", "طح"), - (0xFC27, "M", "طم"), - (0xFC28, "M", "ظم"), - (0xFC29, "M", "عج"), - (0xFC2A, "M", "عم"), - (0xFC2B, "M", "غج"), - (0xFC2C, "M", "غم"), - (0xFC2D, "M", "فج"), - (0xFC2E, "M", "فح"), - (0xFC2F, "M", "فخ"), - (0xFC30, "M", "فم"), - (0xFC31, "M", "فى"), - (0xFC32, "M", "في"), - (0xFC33, "M", "قح"), - (0xFC34, "M", "قم"), - (0xFC35, "M", "قى"), - (0xFC36, "M", "قي"), - (0xFC37, "M", "كا"), - (0xFC38, "M", "كج"), - (0xFC39, "M", "كح"), - (0xFC3A, "M", "كخ"), - (0xFC3B, "M", "كل"), - (0xFC3C, "M", "كم"), - (0xFC3D, "M", "كى"), - (0xFC3E, "M", "كي"), - (0xFC3F, "M", "لج"), - (0xFC40, "M", "لح"), - (0xFC41, "M", "لخ"), - (0xFC42, "M", "لم"), - (0xFC43, "M", "لى"), - (0xFC44, "M", "لي"), - (0xFC45, "M", "مج"), - (0xFC46, "M", "مح"), - (0xFC47, "M", "مخ"), - (0xFC48, "M", "مم"), - (0xFC49, "M", "مى"), - (0xFC4A, "M", "مي"), - (0xFC4B, "M", "نج"), - (0xFC4C, "M", "نح"), - (0xFC4D, "M", "نخ"), - (0xFC4E, "M", "نم"), - (0xFC4F, "M", "نى"), - (0xFC50, "M", "ني"), - (0xFC51, "M", "هج"), - (0xFC52, "M", "هم"), - (0xFC53, "M", "هى"), - (0xFC54, "M", "هي"), - (0xFC55, "M", "يج"), - (0xFC56, "M", "يح"), - (0xFC57, "M", "يخ"), - (0xFC58, "M", "يم"), - (0xFC59, "M", "يى"), - (0xFC5A, "M", "يي"), - (0xFC5B, "M", "ذٰ"), - (0xFC5C, "M", "رٰ"), - (0xFC5D, "M", "ىٰ"), - (0xFC5E, "M", " ٌّ"), - (0xFC5F, "M", " ٍّ"), - (0xFC60, "M", " َّ"), - (0xFC61, "M", " ُّ"), - (0xFC62, "M", " ِّ"), - (0xFC63, "M", " ّٰ"), - (0xFC64, "M", "ئر"), - (0xFC65, "M", "ئز"), - (0xFC66, "M", "ئم"), - (0xFC67, "M", "ئن"), - (0xFC68, "M", "ئى"), - (0xFC69, "M", "ئي"), - (0xFC6A, "M", "بر"), - (0xFC6B, "M", "بز"), - (0xFC6C, "M", "بم"), - (0xFC6D, "M", "بن"), - (0xFC6E, "M", "بى"), - (0xFC6F, "M", "بي"), - (0xFC70, "M", "تر"), - (0xFC71, "M", "تز"), - (0xFC72, "M", "تم"), - (0xFC73, "M", "تن"), - (0xFC74, "M", "تى"), - (0xFC75, "M", "تي"), - (0xFC76, "M", "ثر"), - (0xFC77, "M", "ثز"), - (0xFC78, "M", "ثم"), - (0xFC79, "M", "ثن"), - (0xFC7A, "M", "ثى"), - (0xFC7B, "M", "ثي"), - (0xFC7C, "M", "فى"), - (0xFC7D, "M", "في"), - (0xFC7E, "M", "قى"), - (0xFC7F, "M", "قي"), - (0xFC80, "M", "كا"), - (0xFC81, "M", "كل"), - (0xFC82, "M", "كم"), - (0xFC83, "M", "كى"), - (0xFC84, "M", "كي"), - (0xFC85, "M", "لم"), - (0xFC86, "M", "لى"), - (0xFC87, "M", "لي"), - (0xFC88, "M", "ما"), - (0xFC89, "M", "مم"), - (0xFC8A, "M", "نر"), - (0xFC8B, "M", "نز"), - (0xFC8C, "M", "نم"), - (0xFC8D, "M", "نن"), - (0xFC8E, "M", "نى"), - (0xFC8F, "M", "ني"), - (0xFC90, "M", "ىٰ"), - (0xFC91, "M", "ير"), - (0xFC92, "M", "يز"), - (0xFC93, "M", "يم"), - (0xFC94, "M", "ين"), - (0xFC95, "M", "يى"), - (0xFC96, "M", "يي"), - (0xFC97, "M", "ئج"), - (0xFC98, "M", "ئح"), - (0xFC99, "M", "ئخ"), - (0xFC9A, "M", "ئم"), - (0xFC9B, "M", "ئه"), - (0xFC9C, "M", "بج"), - (0xFC9D, "M", "بح"), - (0xFC9E, "M", "بخ"), - (0xFC9F, "M", "بم"), - (0xFCA0, "M", "به"), - (0xFCA1, "M", "تج"), - (0xFCA2, "M", "تح"), - (0xFCA3, "M", "تخ"), - (0xFCA4, "M", "تم"), - (0xFCA5, "M", "ته"), - (0xFCA6, "M", "ثم"), - (0xFCA7, "M", "جح"), - (0xFCA8, "M", "جم"), - (0xFCA9, "M", "حج"), - (0xFCAA, "M", "حم"), - (0xFCAB, "M", "خج"), - (0xFCAC, "M", "خم"), - (0xFCAD, "M", "سج"), - (0xFCAE, "M", "سح"), - (0xFCAF, "M", "سخ"), - (0xFCB0, "M", "سم"), - (0xFCB1, "M", "صح"), - (0xFCB2, "M", "صخ"), - (0xFCB3, "M", "صم"), - (0xFCB4, "M", "ضج"), - (0xFCB5, "M", "ضح"), - (0xFCB6, "M", "ضخ"), - (0xFCB7, "M", "ضم"), - (0xFCB8, "M", "طح"), - (0xFCB9, "M", "ظم"), - (0xFCBA, "M", "عج"), - (0xFCBB, "M", "عم"), - (0xFCBC, "M", "غج"), - (0xFCBD, "M", "غم"), - (0xFCBE, "M", "فج"), - (0xFCBF, "M", "فح"), - (0xFCC0, "M", "فخ"), - (0xFCC1, "M", "فم"), - (0xFCC2, "M", "قح"), - (0xFCC3, "M", "قم"), - (0xFCC4, "M", "كج"), - (0xFCC5, "M", "كح"), - (0xFCC6, "M", "كخ"), - (0xFCC7, "M", "كل"), - (0xFCC8, "M", "كم"), - (0xFCC9, "M", "لج"), - (0xFCCA, "M", "لح"), - (0xFCCB, "M", "لخ"), - (0xFCCC, "M", "لم"), - (0xFCCD, "M", "له"), - (0xFCCE, "M", "مج"), - (0xFCCF, "M", "مح"), - (0xFCD0, "M", "مخ"), - (0xFCD1, "M", "مم"), - (0xFCD2, "M", "نج"), - (0xFCD3, "M", "نح"), - (0xFCD4, "M", "نخ"), - (0xFCD5, "M", "نم"), - (0xFCD6, "M", "نه"), - (0xFCD7, "M", "هج"), - (0xFCD8, "M", "هم"), - (0xFCD9, "M", "هٰ"), - (0xFCDA, "M", "يج"), - (0xFCDB, "M", "يح"), - (0xFCDC, "M", "يخ"), - (0xFCDD, "M", "يم"), - (0xFCDE, "M", "يه"), - (0xFCDF, "M", "ئم"), - (0xFCE0, "M", "ئه"), - (0xFCE1, "M", "بم"), - (0xFCE2, "M", "به"), - (0xFCE3, "M", "تم"), - (0xFCE4, "M", "ته"), - (0xFCE5, "M", "ثم"), - (0xFCE6, "M", "ثه"), - (0xFCE7, "M", "سم"), - (0xFCE8, "M", "سه"), - (0xFCE9, "M", "شم"), - (0xFCEA, "M", "شه"), - (0xFCEB, "M", "كل"), - (0xFCEC, "M", "كم"), - (0xFCED, "M", "لم"), - (0xFCEE, "M", "نم"), - (0xFCEF, "M", "نه"), - (0xFCF0, "M", "يم"), - (0xFCF1, "M", "يه"), - (0xFCF2, "M", "ـَّ"), - (0xFCF3, "M", "ـُّ"), - (0xFCF4, "M", "ـِّ"), - (0xFCF5, "M", "طى"), - (0xFCF6, "M", "طي"), - (0xFCF7, "M", "عى"), - (0xFCF8, "M", "عي"), - (0xFCF9, "M", "غى"), - (0xFCFA, "M", "غي"), - (0xFCFB, "M", "سى"), - (0xFCFC, "M", "سي"), - (0xFCFD, "M", "شى"), - (0xFCFE, "M", "شي"), - (0xFCFF, "M", "حى"), - (0xFD00, "M", "حي"), - (0xFD01, "M", "جى"), - (0xFD02, "M", "جي"), - (0xFD03, "M", "خى"), - (0xFD04, "M", "خي"), - (0xFD05, "M", "صى"), - (0xFD06, "M", "صي"), - (0xFD07, "M", "ضى"), - (0xFD08, "M", "ضي"), - (0xFD09, "M", "شج"), - (0xFD0A, "M", "شح"), - (0xFD0B, "M", "شخ"), - (0xFD0C, "M", "شم"), - (0xFD0D, "M", "شر"), - (0xFD0E, "M", "سر"), - (0xFD0F, "M", "صر"), - (0xFD10, "M", "ضر"), - (0xFD11, "M", "طى"), - (0xFD12, "M", "طي"), - (0xFD13, "M", "عى"), - (0xFD14, "M", "عي"), - (0xFD15, "M", "غى"), - (0xFD16, "M", "غي"), - (0xFD17, "M", "سى"), - (0xFD18, "M", "سي"), - (0xFD19, "M", "شى"), - (0xFD1A, "M", "شي"), - (0xFD1B, "M", "حى"), - (0xFD1C, "M", "حي"), - (0xFD1D, "M", "جى"), - (0xFD1E, "M", "جي"), - (0xFD1F, "M", "خى"), - (0xFD20, "M", "خي"), - (0xFD21, "M", "صى"), - (0xFD22, "M", "صي"), - (0xFD23, "M", "ضى"), - (0xFD24, "M", "ضي"), - (0xFD25, "M", "شج"), - (0xFD26, "M", "شح"), - (0xFD27, "M", "شخ"), - (0xFD28, "M", "شم"), - (0xFD29, "M", "شر"), - (0xFD2A, "M", "سر"), - (0xFD2B, "M", "صر"), - (0xFD2C, "M", "ضر"), - (0xFD2D, "M", "شج"), - (0xFD2E, "M", "شح"), - (0xFD2F, "M", "شخ"), - (0xFD30, "M", "شم"), - (0xFD31, "M", "سه"), - (0xFD32, "M", "شه"), - (0xFD33, "M", "طم"), - (0xFD34, "M", "سج"), - (0xFD35, "M", "سح"), - (0xFD36, "M", "سخ"), - (0xFD37, "M", "شج"), - (0xFD38, "M", "شح"), - (0xFD39, "M", "شخ"), - (0xFD3A, "M", "طم"), - (0xFD3B, "M", "ظم"), - (0xFD3C, "M", "اً"), - (0xFD3E, "V"), - (0xFD50, "M", "تجم"), - (0xFD51, "M", "تحج"), - (0xFD53, "M", "تحم"), - (0xFD54, "M", "تخم"), - (0xFD55, "M", "تمج"), - (0xFD56, "M", "تمح"), - (0xFD57, "M", "تمخ"), - (0xFD58, "M", "جمح"), - (0xFD5A, "M", "حمي"), - (0xFD5B, "M", "حمى"), - (0xFD5C, "M", "سحج"), - (0xFD5D, "M", "سجح"), - (0xFD5E, "M", "سجى"), - (0xFD5F, "M", "سمح"), - (0xFD61, "M", "سمج"), - (0xFD62, "M", "سمم"), - (0xFD64, "M", "صحح"), - (0xFD66, "M", "صمم"), - (0xFD67, "M", "شحم"), - (0xFD69, "M", "شجي"), - (0xFD6A, "M", "شمخ"), - (0xFD6C, "M", "شمم"), - (0xFD6E, "M", "ضحى"), - (0xFD6F, "M", "ضخم"), - (0xFD71, "M", "طمح"), - (0xFD73, "M", "طمم"), - (0xFD74, "M", "طمي"), - (0xFD75, "M", "عجم"), - (0xFD76, "M", "عمم"), - (0xFD78, "M", "عمى"), - (0xFD79, "M", "غمم"), - (0xFD7A, "M", "غمي"), - (0xFD7B, "M", "غمى"), - (0xFD7C, "M", "فخم"), - (0xFD7E, "M", "قمح"), - (0xFD7F, "M", "قمم"), - (0xFD80, "M", "لحم"), - (0xFD81, "M", "لحي"), - (0xFD82, "M", "لحى"), - (0xFD83, "M", "لجج"), - (0xFD85, "M", "لخم"), - (0xFD87, "M", "لمح"), - (0xFD89, "M", "محج"), - (0xFD8A, "M", "محم"), - (0xFD8B, "M", "محي"), - (0xFD8C, "M", "مجح"), - (0xFD8D, "M", "مجم"), - (0xFD8E, "M", "مخج"), - (0xFD8F, "M", "مخم"), - (0xFD90, "V"), - (0xFD92, "M", "مجخ"), - (0xFD93, "M", "همج"), - (0xFD94, "M", "همم"), - (0xFD95, "M", "نحم"), - (0xFD96, "M", "نحى"), - (0xFD97, "M", "نجم"), - (0xFD99, "M", "نجى"), - (0xFD9A, "M", "نمي"), - (0xFD9B, "M", "نمى"), - (0xFD9C, "M", "يمم"), - (0xFD9E, "M", "بخي"), - (0xFD9F, "M", "تجي"), - (0xFDA0, "M", "تجى"), - (0xFDA1, "M", "تخي"), - (0xFDA2, "M", "تخى"), - (0xFDA3, "M", "تمي"), - (0xFDA4, "M", "تمى"), - (0xFDA5, "M", "جمي"), - (0xFDA6, "M", "جحى"), - (0xFDA7, "M", "جمى"), - (0xFDA8, "M", "سخى"), - (0xFDA9, "M", "صحي"), - (0xFDAA, "M", "شحي"), - (0xFDAB, "M", "ضحي"), - (0xFDAC, "M", "لجي"), - (0xFDAD, "M", "لمي"), - (0xFDAE, "M", "يحي"), - (0xFDAF, "M", "يجي"), - (0xFDB0, "M", "يمي"), - (0xFDB1, "M", "ممي"), - (0xFDB2, "M", "قمي"), - (0xFDB3, "M", "نحي"), - (0xFDB4, "M", "قمح"), - (0xFDB5, "M", "لحم"), - (0xFDB6, "M", "عمي"), - (0xFDB7, "M", "كمي"), - (0xFDB8, "M", "نجح"), - (0xFDB9, "M", "مخي"), - (0xFDBA, "M", "لجم"), - (0xFDBB, "M", "كمم"), - (0xFDBC, "M", "لجم"), - (0xFDBD, "M", "نجح"), - (0xFDBE, "M", "جحي"), - (0xFDBF, "M", "حجي"), - (0xFDC0, "M", "مجي"), - (0xFDC1, "M", "فمي"), - (0xFDC2, "M", "بحي"), - (0xFDC3, "M", "كمم"), - (0xFDC4, "M", "عجم"), - (0xFDC5, "M", "صمم"), - (0xFDC6, "M", "سخي"), - (0xFDC7, "M", "نجي"), - (0xFDC8, "V"), - (0xFDD0, "X"), - (0xFDF0, "M", "صلے"), - (0xFDF1, "M", "قلے"), - (0xFDF2, "M", "الله"), - (0xFDF3, "M", "اكبر"), - (0xFDF4, "M", "محمد"), - (0xFDF5, "M", "صلعم"), - (0xFDF6, "M", "رسول"), - (0xFDF7, "M", "عليه"), - (0xFDF8, "M", "وسلم"), - (0xFDF9, "M", "صلى"), - (0xFDFA, "M", "صلى الله عليه وسلم"), - (0xFDFB, "M", "جل جلاله"), - (0xFDFC, "M", "ریال"), - (0xFDFD, "V"), - (0xFE00, "I"), - (0xFE10, "M", ","), - (0xFE11, "M", "、"), - (0xFE12, "X"), - (0xFE13, "M", ":"), - (0xFE14, "M", ";"), - (0xFE15, "M", "!"), - (0xFE16, "M", "?"), - (0xFE17, "M", "〖"), - (0xFE18, "M", "〗"), - (0xFE19, "X"), - (0xFE20, "V"), - (0xFE30, "X"), - (0xFE31, "M", "—"), - (0xFE32, "M", "–"), - (0xFE33, "M", "_"), - (0xFE35, "M", "("), - (0xFE36, "M", ")"), - (0xFE37, "M", "{"), - (0xFE38, "M", "}"), - (0xFE39, "M", "〔"), - (0xFE3A, "M", "〕"), - (0xFE3B, "M", "【"), - (0xFE3C, "M", "】"), - (0xFE3D, "M", "《"), - (0xFE3E, "M", "》"), - (0xFE3F, "M", "〈"), - (0xFE40, "M", "〉"), - (0xFE41, "M", "「"), - (0xFE42, "M", "」"), - (0xFE43, "M", "『"), - (0xFE44, "M", "』"), - (0xFE45, "V"), - (0xFE47, "M", "["), - (0xFE48, "M", "]"), - (0xFE49, "M", " ̅"), - (0xFE4D, "M", "_"), - (0xFE50, "M", ","), - (0xFE51, "M", "、"), - (0xFE52, "X"), - (0xFE54, "M", ";"), - (0xFE55, "M", ":"), - (0xFE56, "M", "?"), - (0xFE57, "M", "!"), - (0xFE58, "M", "—"), - (0xFE59, "M", "("), - (0xFE5A, "M", ")"), - (0xFE5B, "M", "{"), - (0xFE5C, "M", "}"), - (0xFE5D, "M", "〔"), - (0xFE5E, "M", "〕"), - (0xFE5F, "M", "#"), - (0xFE60, "M", "&"), - (0xFE61, "M", "*"), - (0xFE62, "M", "+"), - (0xFE63, "M", "-"), - (0xFE64, "M", "<"), - (0xFE65, "M", ">"), - (0xFE66, "M", "="), - (0xFE67, "X"), - (0xFE68, "M", "\\"), - (0xFE69, "M", "$"), - (0xFE6A, "M", "%"), - (0xFE6B, "M", "@"), - (0xFE6C, "X"), - (0xFE70, "M", " ً"), - (0xFE71, "M", "ـً"), - (0xFE72, "M", " ٌ"), - (0xFE73, "V"), - (0xFE74, "M", " ٍ"), - (0xFE75, "X"), - (0xFE76, "M", " َ"), - (0xFE77, "M", "ـَ"), - (0xFE78, "M", " ُ"), - (0xFE79, "M", "ـُ"), - (0xFE7A, "M", " ِ"), - (0xFE7B, "M", "ـِ"), - (0xFE7C, "M", " ّ"), - (0xFE7D, "M", "ـّ"), - (0xFE7E, "M", " ْ"), - (0xFE7F, "M", "ـْ"), - (0xFE80, "M", "ء"), - (0xFE81, "M", "آ"), - (0xFE83, "M", "أ"), - (0xFE85, "M", "ؤ"), - (0xFE87, "M", "إ"), - (0xFE89, "M", "ئ"), - (0xFE8D, "M", "ا"), - (0xFE8F, "M", "ب"), - (0xFE93, "M", "ة"), - (0xFE95, "M", "ت"), - (0xFE99, "M", "ث"), - (0xFE9D, "M", "ج"), - (0xFEA1, "M", "ح"), - (0xFEA5, "M", "خ"), - (0xFEA9, "M", "د"), - (0xFEAB, "M", "ذ"), - (0xFEAD, "M", "ر"), - (0xFEAF, "M", "ز"), - (0xFEB1, "M", "س"), - (0xFEB5, "M", "ش"), - (0xFEB9, "M", "ص"), - (0xFEBD, "M", "ض"), - (0xFEC1, "M", "ط"), - (0xFEC5, "M", "ظ"), - (0xFEC9, "M", "ع"), - (0xFECD, "M", "غ"), - (0xFED1, "M", "ف"), - (0xFED5, "M", "ق"), - (0xFED9, "M", "ك"), - (0xFEDD, "M", "ل"), - (0xFEE1, "M", "م"), - (0xFEE5, "M", "ن"), - (0xFEE9, "M", "ه"), - (0xFEED, "M", "و"), - (0xFEEF, "M", "ى"), - (0xFEF1, "M", "ي"), - (0xFEF5, "M", "لآ"), - (0xFEF7, "M", "لأ"), - (0xFEF9, "M", "لإ"), - (0xFEFB, "M", "لا"), - (0xFEFD, "X"), - (0xFEFF, "I"), - (0xFF00, "X"), - (0xFF01, "M", "!"), - (0xFF02, "M", '"'), - (0xFF03, "M", "#"), - (0xFF04, "M", "$"), - (0xFF05, "M", "%"), - (0xFF06, "M", "&"), - (0xFF07, "M", "'"), - (0xFF08, "M", "("), - (0xFF09, "M", ")"), - (0xFF0A, "M", "*"), - (0xFF0B, "M", "+"), - (0xFF0C, "M", ","), - (0xFF0D, "M", "-"), - (0xFF0E, "M", "."), - (0xFF0F, "M", "/"), - (0xFF10, "M", "0"), - (0xFF11, "M", "1"), - (0xFF12, "M", "2"), - (0xFF13, "M", "3"), - (0xFF14, "M", "4"), - (0xFF15, "M", "5"), - (0xFF16, "M", "6"), - (0xFF17, "M", "7"), - (0xFF18, "M", "8"), - (0xFF19, "M", "9"), - (0xFF1A, "M", ":"), - (0xFF1B, "M", ";"), - (0xFF1C, "M", "<"), - (0xFF1D, "M", "="), - (0xFF1E, "M", ">"), - (0xFF1F, "M", "?"), - (0xFF20, "M", "@"), - (0xFF21, "M", "a"), - (0xFF22, "M", "b"), - (0xFF23, "M", "c"), - (0xFF24, "M", "d"), - (0xFF25, "M", "e"), - (0xFF26, "M", "f"), - (0xFF27, "M", "g"), - (0xFF28, "M", "h"), - (0xFF29, "M", "i"), - (0xFF2A, "M", "j"), - (0xFF2B, "M", "k"), - (0xFF2C, "M", "l"), - (0xFF2D, "M", "m"), - (0xFF2E, "M", "n"), - (0xFF2F, "M", "o"), - (0xFF30, "M", "p"), - (0xFF31, "M", "q"), - (0xFF32, "M", "r"), - (0xFF33, "M", "s"), - (0xFF34, "M", "t"), - (0xFF35, "M", "u"), - (0xFF36, "M", "v"), - (0xFF37, "M", "w"), - (0xFF38, "M", "x"), - (0xFF39, "M", "y"), - (0xFF3A, "M", "z"), - (0xFF3B, "M", "["), - (0xFF3C, "M", "\\"), - (0xFF3D, "M", "]"), - (0xFF3E, "M", "^"), - (0xFF3F, "M", "_"), - (0xFF40, "M", "`"), - (0xFF41, "M", "a"), - (0xFF42, "M", "b"), - (0xFF43, "M", "c"), - (0xFF44, "M", "d"), - (0xFF45, "M", "e"), - (0xFF46, "M", "f"), - (0xFF47, "M", "g"), - (0xFF48, "M", "h"), - (0xFF49, "M", "i"), - (0xFF4A, "M", "j"), - (0xFF4B, "M", "k"), - (0xFF4C, "M", "l"), - (0xFF4D, "M", "m"), - (0xFF4E, "M", "n"), - (0xFF4F, "M", "o"), - (0xFF50, "M", "p"), - (0xFF51, "M", "q"), - (0xFF52, "M", "r"), - (0xFF53, "M", "s"), - (0xFF54, "M", "t"), - (0xFF55, "M", "u"), - (0xFF56, "M", "v"), - (0xFF57, "M", "w"), - (0xFF58, "M", "x"), - (0xFF59, "M", "y"), - (0xFF5A, "M", "z"), - (0xFF5B, "M", "{"), - (0xFF5C, "M", "|"), - (0xFF5D, "M", "}"), - (0xFF5E, "M", "~"), - (0xFF5F, "M", "⦅"), - (0xFF60, "M", "⦆"), - (0xFF61, "M", "."), - (0xFF62, "M", "「"), - (0xFF63, "M", "」"), - (0xFF64, "M", "、"), - (0xFF65, "M", "・"), - (0xFF66, "M", "ヲ"), - (0xFF67, "M", "ァ"), - (0xFF68, "M", "ィ"), - (0xFF69, "M", "ゥ"), - (0xFF6A, "M", "ェ"), - (0xFF6B, "M", "ォ"), - (0xFF6C, "M", "ャ"), - (0xFF6D, "M", "ュ"), - (0xFF6E, "M", "ョ"), - (0xFF6F, "M", "ッ"), - (0xFF70, "M", "ー"), - (0xFF71, "M", "ア"), - (0xFF72, "M", "イ"), - (0xFF73, "M", "ウ"), - (0xFF74, "M", "エ"), - (0xFF75, "M", "オ"), - (0xFF76, "M", "カ"), - (0xFF77, "M", "キ"), - (0xFF78, "M", "ク"), - (0xFF79, "M", "ケ"), - (0xFF7A, "M", "コ"), - (0xFF7B, "M", "サ"), - (0xFF7C, "M", "シ"), - (0xFF7D, "M", "ス"), - (0xFF7E, "M", "セ"), - (0xFF7F, "M", "ソ"), - (0xFF80, "M", "タ"), - (0xFF81, "M", "チ"), - (0xFF82, "M", "ツ"), - (0xFF83, "M", "テ"), - (0xFF84, "M", "ト"), - (0xFF85, "M", "ナ"), - (0xFF86, "M", "ニ"), - (0xFF87, "M", "ヌ"), - (0xFF88, "M", "ネ"), - (0xFF89, "M", "ノ"), - (0xFF8A, "M", "ハ"), - (0xFF8B, "M", "ヒ"), - (0xFF8C, "M", "フ"), - (0xFF8D, "M", "ヘ"), - (0xFF8E, "M", "ホ"), - (0xFF8F, "M", "マ"), - (0xFF90, "M", "ミ"), - (0xFF91, "M", "ム"), - (0xFF92, "M", "メ"), - (0xFF93, "M", "モ"), - (0xFF94, "M", "ヤ"), - (0xFF95, "M", "ユ"), - (0xFF96, "M", "ヨ"), - (0xFF97, "M", "ラ"), - (0xFF98, "M", "リ"), - (0xFF99, "M", "ル"), - (0xFF9A, "M", "レ"), - (0xFF9B, "M", "ロ"), - (0xFF9C, "M", "ワ"), - (0xFF9D, "M", "ン"), - (0xFF9E, "M", "゙"), - (0xFF9F, "M", "゚"), - (0xFFA0, "I"), - (0xFFA1, "M", "ᄀ"), - (0xFFA2, "M", "ᄁ"), - (0xFFA3, "M", "ᆪ"), - (0xFFA4, "M", "ᄂ"), - (0xFFA5, "M", "ᆬ"), - (0xFFA6, "M", "ᆭ"), - (0xFFA7, "M", "ᄃ"), - (0xFFA8, "M", "ᄄ"), - (0xFFA9, "M", "ᄅ"), - (0xFFAA, "M", "ᆰ"), - (0xFFAB, "M", "ᆱ"), - (0xFFAC, "M", "ᆲ"), - (0xFFAD, "M", "ᆳ"), - (0xFFAE, "M", "ᆴ"), - (0xFFAF, "M", "ᆵ"), - (0xFFB0, "M", "ᄚ"), - (0xFFB1, "M", "ᄆ"), - (0xFFB2, "M", "ᄇ"), - (0xFFB3, "M", "ᄈ"), - (0xFFB4, "M", "ᄡ"), - (0xFFB5, "M", "ᄉ"), - (0xFFB6, "M", "ᄊ"), - (0xFFB7, "M", "ᄋ"), - (0xFFB8, "M", "ᄌ"), - (0xFFB9, "M", "ᄍ"), - (0xFFBA, "M", "ᄎ"), - (0xFFBB, "M", "ᄏ"), - (0xFFBC, "M", "ᄐ"), - (0xFFBD, "M", "ᄑ"), - (0xFFBE, "M", "ᄒ"), - (0xFFBF, "X"), - (0xFFC2, "M", "ᅡ"), - (0xFFC3, "M", "ᅢ"), - (0xFFC4, "M", "ᅣ"), - (0xFFC5, "M", "ᅤ"), - (0xFFC6, "M", "ᅥ"), - (0xFFC7, "M", "ᅦ"), - (0xFFC8, "X"), - (0xFFCA, "M", "ᅧ"), - (0xFFCB, "M", "ᅨ"), - (0xFFCC, "M", "ᅩ"), - (0xFFCD, "M", "ᅪ"), - (0xFFCE, "M", "ᅫ"), - (0xFFCF, "M", "ᅬ"), - (0xFFD0, "X"), - (0xFFD2, "M", "ᅭ"), - (0xFFD3, "M", "ᅮ"), - (0xFFD4, "M", "ᅯ"), - (0xFFD5, "M", "ᅰ"), - (0xFFD6, "M", "ᅱ"), - (0xFFD7, "M", "ᅲ"), - (0xFFD8, "X"), - (0xFFDA, "M", "ᅳ"), - (0xFFDB, "M", "ᅴ"), - (0xFFDC, "M", "ᅵ"), - (0xFFDD, "X"), - (0xFFE0, "M", "¢"), - (0xFFE1, "M", "£"), - (0xFFE2, "M", "¬"), - (0xFFE3, "M", " ̄"), - (0xFFE4, "M", "¦"), - (0xFFE5, "M", "¥"), - (0xFFE6, "M", "₩"), - (0xFFE7, "X"), - (0xFFE8, "M", "│"), - (0xFFE9, "M", "←"), - (0xFFEA, "M", "↑"), - (0xFFEB, "M", "→"), - (0xFFEC, "M", "↓"), - (0xFFED, "M", "■"), - (0xFFEE, "M", "○"), - (0xFFEF, "X"), - (0x10000, "V"), - (0x1000C, "X"), - (0x1000D, "V"), - (0x10027, "X"), - (0x10028, "V"), - (0x1003B, "X"), - (0x1003C, "V"), - (0x1003E, "X"), - (0x1003F, "V"), - (0x1004E, "X"), - (0x10050, "V"), - (0x1005E, "X"), - (0x10080, "V"), - (0x100FB, "X"), - (0x10100, "V"), - (0x10103, "X"), - (0x10107, "V"), - (0x10134, "X"), - (0x10137, "V"), - (0x1018F, "X"), - (0x10190, "V"), - (0x1019D, "X"), - (0x101A0, "V"), - (0x101A1, "X"), - (0x101D0, "V"), - (0x101FE, "X"), - (0x10280, "V"), - (0x1029D, "X"), - (0x102A0, "V"), - (0x102D1, "X"), - (0x102E0, "V"), - (0x102FC, "X"), - (0x10300, "V"), - (0x10324, "X"), - (0x1032D, "V"), - (0x1034B, "X"), - (0x10350, "V"), - (0x1037B, "X"), - (0x10380, "V"), - (0x1039E, "X"), - (0x1039F, "V"), - (0x103C4, "X"), - (0x103C8, "V"), - (0x103D6, "X"), - (0x10400, "M", "𐐨"), - (0x10401, "M", "𐐩"), - (0x10402, "M", "𐐪"), - (0x10403, "M", "𐐫"), - (0x10404, "M", "𐐬"), - (0x10405, "M", "𐐭"), - (0x10406, "M", "𐐮"), - (0x10407, "M", "𐐯"), - (0x10408, "M", "𐐰"), - (0x10409, "M", "𐐱"), - (0x1040A, "M", "𐐲"), - (0x1040B, "M", "𐐳"), - (0x1040C, "M", "𐐴"), - (0x1040D, "M", "𐐵"), - (0x1040E, "M", "𐐶"), - (0x1040F, "M", "𐐷"), - (0x10410, "M", "𐐸"), - (0x10411, "M", "𐐹"), - (0x10412, "M", "𐐺"), - (0x10413, "M", "𐐻"), - (0x10414, "M", "𐐼"), - (0x10415, "M", "𐐽"), - (0x10416, "M", "𐐾"), - (0x10417, "M", "𐐿"), - (0x10418, "M", "𐑀"), - (0x10419, "M", "𐑁"), - (0x1041A, "M", "𐑂"), - (0x1041B, "M", "𐑃"), - (0x1041C, "M", "𐑄"), - (0x1041D, "M", "𐑅"), - (0x1041E, "M", "𐑆"), - (0x1041F, "M", "𐑇"), - (0x10420, "M", "𐑈"), - (0x10421, "M", "𐑉"), - (0x10422, "M", "𐑊"), - (0x10423, "M", "𐑋"), - (0x10424, "M", "𐑌"), - (0x10425, "M", "𐑍"), - (0x10426, "M", "𐑎"), - (0x10427, "M", "𐑏"), - (0x10428, "V"), - (0x1049E, "X"), - (0x104A0, "V"), - (0x104AA, "X"), - (0x104B0, "M", "𐓘"), - (0x104B1, "M", "𐓙"), - (0x104B2, "M", "𐓚"), - (0x104B3, "M", "𐓛"), - (0x104B4, "M", "𐓜"), - (0x104B5, "M", "𐓝"), - (0x104B6, "M", "𐓞"), - (0x104B7, "M", "𐓟"), - (0x104B8, "M", "𐓠"), - (0x104B9, "M", "𐓡"), - (0x104BA, "M", "𐓢"), - (0x104BB, "M", "𐓣"), - (0x104BC, "M", "𐓤"), - (0x104BD, "M", "𐓥"), - (0x104BE, "M", "𐓦"), - (0x104BF, "M", "𐓧"), - (0x104C0, "M", "𐓨"), - (0x104C1, "M", "𐓩"), - (0x104C2, "M", "𐓪"), - (0x104C3, "M", "𐓫"), - (0x104C4, "M", "𐓬"), - (0x104C5, "M", "𐓭"), - (0x104C6, "M", "𐓮"), - (0x104C7, "M", "𐓯"), - (0x104C8, "M", "𐓰"), - (0x104C9, "M", "𐓱"), - (0x104CA, "M", "𐓲"), - (0x104CB, "M", "𐓳"), - (0x104CC, "M", "𐓴"), - (0x104CD, "M", "𐓵"), - (0x104CE, "M", "𐓶"), - (0x104CF, "M", "𐓷"), - (0x104D0, "M", "𐓸"), - (0x104D1, "M", "𐓹"), - (0x104D2, "M", "𐓺"), - (0x104D3, "M", "𐓻"), - (0x104D4, "X"), - (0x104D8, "V"), - (0x104FC, "X"), - (0x10500, "V"), - (0x10528, "X"), - (0x10530, "V"), - (0x10564, "X"), - (0x1056F, "V"), - (0x10570, "M", "𐖗"), - (0x10571, "M", "𐖘"), - (0x10572, "M", "𐖙"), - (0x10573, "M", "𐖚"), - (0x10574, "M", "𐖛"), - (0x10575, "M", "𐖜"), - (0x10576, "M", "𐖝"), - (0x10577, "M", "𐖞"), - (0x10578, "M", "𐖟"), - (0x10579, "M", "𐖠"), - (0x1057A, "M", "𐖡"), - (0x1057B, "X"), - (0x1057C, "M", "𐖣"), - (0x1057D, "M", "𐖤"), - (0x1057E, "M", "𐖥"), - (0x1057F, "M", "𐖦"), - (0x10580, "M", "𐖧"), - (0x10581, "M", "𐖨"), - (0x10582, "M", "𐖩"), - (0x10583, "M", "𐖪"), - (0x10584, "M", "𐖫"), - (0x10585, "M", "𐖬"), - (0x10586, "M", "𐖭"), - (0x10587, "M", "𐖮"), - (0x10588, "M", "𐖯"), - (0x10589, "M", "𐖰"), - (0x1058A, "M", "𐖱"), - (0x1058B, "X"), - (0x1058C, "M", "𐖳"), - (0x1058D, "M", "𐖴"), - (0x1058E, "M", "𐖵"), - (0x1058F, "M", "𐖶"), - (0x10590, "M", "𐖷"), - (0x10591, "M", "𐖸"), - (0x10592, "M", "𐖹"), - (0x10593, "X"), - (0x10594, "M", "𐖻"), - (0x10595, "M", "𐖼"), - (0x10596, "X"), - (0x10597, "V"), - (0x105A2, "X"), - (0x105A3, "V"), - (0x105B2, "X"), - (0x105B3, "V"), - (0x105BA, "X"), - (0x105BB, "V"), - (0x105BD, "X"), - (0x105C0, "V"), - (0x105F4, "X"), - (0x10600, "V"), - (0x10737, "X"), - (0x10740, "V"), - (0x10756, "X"), - (0x10760, "V"), - (0x10768, "X"), - (0x10780, "V"), - (0x10781, "M", "ː"), - (0x10782, "M", "ˑ"), - (0x10783, "M", "æ"), - (0x10784, "M", "ʙ"), - (0x10785, "M", "ɓ"), - (0x10786, "X"), - (0x10787, "M", "ʣ"), - (0x10788, "M", "ꭦ"), - (0x10789, "M", "ʥ"), - (0x1078A, "M", "ʤ"), - (0x1078B, "M", "ɖ"), - (0x1078C, "M", "ɗ"), - (0x1078D, "M", "ᶑ"), - (0x1078E, "M", "ɘ"), - (0x1078F, "M", "ɞ"), - (0x10790, "M", "ʩ"), - (0x10791, "M", "ɤ"), - (0x10792, "M", "ɢ"), - (0x10793, "M", "ɠ"), - (0x10794, "M", "ʛ"), - (0x10795, "M", "ħ"), - (0x10796, "M", "ʜ"), - (0x10797, "M", "ɧ"), - (0x10798, "M", "ʄ"), - (0x10799, "M", "ʪ"), - (0x1079A, "M", "ʫ"), - (0x1079B, "M", "ɬ"), - (0x1079C, "M", "𝼄"), - (0x1079D, "M", "ꞎ"), - (0x1079E, "M", "ɮ"), - (0x1079F, "M", "𝼅"), - (0x107A0, "M", "ʎ"), - (0x107A1, "M", "𝼆"), - (0x107A2, "M", "ø"), - (0x107A3, "M", "ɶ"), - (0x107A4, "M", "ɷ"), - (0x107A5, "M", "q"), - (0x107A6, "M", "ɺ"), - (0x107A7, "M", "𝼈"), - (0x107A8, "M", "ɽ"), - (0x107A9, "M", "ɾ"), - (0x107AA, "M", "ʀ"), - (0x107AB, "M", "ʨ"), - (0x107AC, "M", "ʦ"), - (0x107AD, "M", "ꭧ"), - (0x107AE, "M", "ʧ"), - (0x107AF, "M", "ʈ"), - (0x107B0, "M", "ⱱ"), - (0x107B1, "X"), - (0x107B2, "M", "ʏ"), - (0x107B3, "M", "ʡ"), - (0x107B4, "M", "ʢ"), - (0x107B5, "M", "ʘ"), - (0x107B6, "M", "ǀ"), - (0x107B7, "M", "ǁ"), - (0x107B8, "M", "ǂ"), - (0x107B9, "M", "𝼊"), - (0x107BA, "M", "𝼞"), - (0x107BB, "X"), - (0x10800, "V"), - (0x10806, "X"), - (0x10808, "V"), - (0x10809, "X"), - (0x1080A, "V"), - (0x10836, "X"), - (0x10837, "V"), - (0x10839, "X"), - (0x1083C, "V"), - (0x1083D, "X"), - (0x1083F, "V"), - (0x10856, "X"), - (0x10857, "V"), - (0x1089F, "X"), - (0x108A7, "V"), - (0x108B0, "X"), - (0x108E0, "V"), - (0x108F3, "X"), - (0x108F4, "V"), - (0x108F6, "X"), - (0x108FB, "V"), - (0x1091C, "X"), - (0x1091F, "V"), - (0x1093A, "X"), - (0x1093F, "V"), - (0x1095A, "X"), - (0x10980, "V"), - (0x109B8, "X"), - (0x109BC, "V"), - (0x109D0, "X"), - (0x109D2, "V"), - (0x10A04, "X"), - (0x10A05, "V"), - (0x10A07, "X"), - (0x10A0C, "V"), - (0x10A14, "X"), - (0x10A15, "V"), - (0x10A18, "X"), - (0x10A19, "V"), - (0x10A36, "X"), - (0x10A38, "V"), - (0x10A3B, "X"), - (0x10A3F, "V"), - (0x10A49, "X"), - (0x10A50, "V"), - (0x10A59, "X"), - (0x10A60, "V"), - (0x10AA0, "X"), - (0x10AC0, "V"), - (0x10AE7, "X"), - (0x10AEB, "V"), - (0x10AF7, "X"), - (0x10B00, "V"), - (0x10B36, "X"), - (0x10B39, "V"), - (0x10B56, "X"), - (0x10B58, "V"), - (0x10B73, "X"), - (0x10B78, "V"), - (0x10B92, "X"), - (0x10B99, "V"), - (0x10B9D, "X"), - (0x10BA9, "V"), - (0x10BB0, "X"), - (0x10C00, "V"), - (0x10C49, "X"), - (0x10C80, "M", "𐳀"), - (0x10C81, "M", "𐳁"), - (0x10C82, "M", "𐳂"), - (0x10C83, "M", "𐳃"), - (0x10C84, "M", "𐳄"), - (0x10C85, "M", "𐳅"), - (0x10C86, "M", "𐳆"), - (0x10C87, "M", "𐳇"), - (0x10C88, "M", "𐳈"), - (0x10C89, "M", "𐳉"), - (0x10C8A, "M", "𐳊"), - (0x10C8B, "M", "𐳋"), - (0x10C8C, "M", "𐳌"), - (0x10C8D, "M", "𐳍"), - (0x10C8E, "M", "𐳎"), - (0x10C8F, "M", "𐳏"), - (0x10C90, "M", "𐳐"), - (0x10C91, "M", "𐳑"), - (0x10C92, "M", "𐳒"), - (0x10C93, "M", "𐳓"), - (0x10C94, "M", "𐳔"), - (0x10C95, "M", "𐳕"), - (0x10C96, "M", "𐳖"), - (0x10C97, "M", "𐳗"), - (0x10C98, "M", "𐳘"), - (0x10C99, "M", "𐳙"), - (0x10C9A, "M", "𐳚"), - (0x10C9B, "M", "𐳛"), - (0x10C9C, "M", "𐳜"), - (0x10C9D, "M", "𐳝"), - (0x10C9E, "M", "𐳞"), - (0x10C9F, "M", "𐳟"), - (0x10CA0, "M", "𐳠"), - (0x10CA1, "M", "𐳡"), - (0x10CA2, "M", "𐳢"), - (0x10CA3, "M", "𐳣"), - (0x10CA4, "M", "𐳤"), - (0x10CA5, "M", "𐳥"), - (0x10CA6, "M", "𐳦"), - (0x10CA7, "M", "𐳧"), - (0x10CA8, "M", "𐳨"), - (0x10CA9, "M", "𐳩"), - (0x10CAA, "M", "𐳪"), - (0x10CAB, "M", "𐳫"), - (0x10CAC, "M", "𐳬"), - (0x10CAD, "M", "𐳭"), - (0x10CAE, "M", "𐳮"), - (0x10CAF, "M", "𐳯"), - (0x10CB0, "M", "𐳰"), - (0x10CB1, "M", "𐳱"), - (0x10CB2, "M", "𐳲"), - (0x10CB3, "X"), - (0x10CC0, "V"), - (0x10CF3, "X"), - (0x10CFA, "V"), - (0x10D28, "X"), - (0x10D30, "V"), - (0x10D3A, "X"), - (0x10D40, "V"), - (0x10D50, "M", "𐵰"), - (0x10D51, "M", "𐵱"), - (0x10D52, "M", "𐵲"), - (0x10D53, "M", "𐵳"), - (0x10D54, "M", "𐵴"), - (0x10D55, "M", "𐵵"), - (0x10D56, "M", "𐵶"), - (0x10D57, "M", "𐵷"), - (0x10D58, "M", "𐵸"), - (0x10D59, "M", "𐵹"), - (0x10D5A, "M", "𐵺"), - (0x10D5B, "M", "𐵻"), - (0x10D5C, "M", "𐵼"), - (0x10D5D, "M", "𐵽"), - (0x10D5E, "M", "𐵾"), - (0x10D5F, "M", "𐵿"), - (0x10D60, "M", "𐶀"), - (0x10D61, "M", "𐶁"), - (0x10D62, "M", "𐶂"), - (0x10D63, "M", "𐶃"), - (0x10D64, "M", "𐶄"), - (0x10D65, "M", "𐶅"), - (0x10D66, "X"), - (0x10D69, "V"), - (0x10D86, "X"), - (0x10D8E, "V"), - (0x10D90, "X"), - (0x10E60, "V"), - (0x10E7F, "X"), - (0x10E80, "V"), - (0x10EAA, "X"), - (0x10EAB, "V"), - (0x10EAE, "X"), - (0x10EB0, "V"), - (0x10EB2, "X"), - (0x10EC2, "V"), - (0x10EC8, "X"), - (0x10ED0, "V"), - (0x10ED9, "X"), - (0x10EFA, "V"), - (0x10F28, "X"), - (0x10F30, "V"), - (0x10F5A, "X"), - (0x10F70, "V"), - (0x10F8A, "X"), - (0x10FB0, "V"), - (0x10FCC, "X"), - (0x10FE0, "V"), - (0x10FF7, "X"), - (0x11000, "V"), - (0x1104E, "X"), - (0x11052, "V"), - (0x11076, "X"), - (0x1107F, "V"), - (0x110BD, "X"), - (0x110BE, "V"), - (0x110C3, "X"), - (0x110D0, "V"), - (0x110E9, "X"), - (0x110F0, "V"), - (0x110FA, "X"), - (0x11100, "V"), - (0x11135, "X"), - (0x11136, "V"), - (0x11148, "X"), - (0x11150, "V"), - (0x11177, "X"), - (0x11180, "V"), - (0x111E0, "X"), - (0x111E1, "V"), - (0x111F5, "X"), - (0x11200, "V"), - (0x11212, "X"), - (0x11213, "V"), - (0x11242, "X"), - (0x11280, "V"), - (0x11287, "X"), - (0x11288, "V"), - (0x11289, "X"), - (0x1128A, "V"), - (0x1128E, "X"), - (0x1128F, "V"), - (0x1129E, "X"), - (0x1129F, "V"), - (0x112AA, "X"), - (0x112B0, "V"), - (0x112EB, "X"), - (0x112F0, "V"), - (0x112FA, "X"), - (0x11300, "V"), - (0x11304, "X"), - (0x11305, "V"), - (0x1130D, "X"), - (0x1130F, "V"), - (0x11311, "X"), - (0x11313, "V"), - (0x11329, "X"), - (0x1132A, "V"), - (0x11331, "X"), - (0x11332, "V"), - (0x11334, "X"), - (0x11335, "V"), - (0x1133A, "X"), - (0x1133B, "V"), - (0x11345, "X"), - (0x11347, "V"), - (0x11349, "X"), - (0x1134B, "V"), - (0x1134E, "X"), - (0x11350, "V"), - (0x11351, "X"), - (0x11357, "V"), - (0x11358, "X"), - (0x1135D, "V"), - (0x11364, "X"), - (0x11366, "V"), - (0x1136D, "X"), - (0x11370, "V"), - (0x11375, "X"), - (0x11380, "V"), - (0x1138A, "X"), - (0x1138B, "V"), - (0x1138C, "X"), - (0x1138E, "V"), - (0x1138F, "X"), - (0x11390, "V"), - (0x113B6, "X"), - (0x113B7, "V"), - (0x113C1, "X"), - (0x113C2, "V"), - (0x113C3, "X"), - (0x113C5, "V"), - (0x113C6, "X"), - (0x113C7, "V"), - (0x113CB, "X"), - (0x113CC, "V"), - (0x113D6, "X"), - (0x113D7, "V"), - (0x113D9, "X"), - (0x113E1, "V"), - (0x113E3, "X"), - (0x11400, "V"), - (0x1145C, "X"), - (0x1145D, "V"), - (0x11462, "X"), - (0x11480, "V"), - (0x114C8, "X"), - (0x114D0, "V"), - (0x114DA, "X"), - (0x11580, "V"), - (0x115B6, "X"), - (0x115B8, "V"), - (0x115DE, "X"), - (0x11600, "V"), - (0x11645, "X"), - (0x11650, "V"), - (0x1165A, "X"), - (0x11660, "V"), - (0x1166D, "X"), - (0x11680, "V"), - (0x116BA, "X"), - (0x116C0, "V"), - (0x116CA, "X"), - (0x116D0, "V"), - (0x116E4, "X"), - (0x11700, "V"), - (0x1171B, "X"), - (0x1171D, "V"), - (0x1172C, "X"), - (0x11730, "V"), - (0x11747, "X"), - (0x11800, "V"), - (0x1183C, "X"), - (0x118A0, "M", "𑣀"), - (0x118A1, "M", "𑣁"), - (0x118A2, "M", "𑣂"), - (0x118A3, "M", "𑣃"), - (0x118A4, "M", "𑣄"), - (0x118A5, "M", "𑣅"), - (0x118A6, "M", "𑣆"), - (0x118A7, "M", "𑣇"), - (0x118A8, "M", "𑣈"), - (0x118A9, "M", "𑣉"), - (0x118AA, "M", "𑣊"), - (0x118AB, "M", "𑣋"), - (0x118AC, "M", "𑣌"), - (0x118AD, "M", "𑣍"), - (0x118AE, "M", "𑣎"), - (0x118AF, "M", "𑣏"), - (0x118B0, "M", "𑣐"), - (0x118B1, "M", "𑣑"), - (0x118B2, "M", "𑣒"), - (0x118B3, "M", "𑣓"), - (0x118B4, "M", "𑣔"), - (0x118B5, "M", "𑣕"), - (0x118B6, "M", "𑣖"), - (0x118B7, "M", "𑣗"), - (0x118B8, "M", "𑣘"), - (0x118B9, "M", "𑣙"), - (0x118BA, "M", "𑣚"), - (0x118BB, "M", "𑣛"), - (0x118BC, "M", "𑣜"), - (0x118BD, "M", "𑣝"), - (0x118BE, "M", "𑣞"), - (0x118BF, "M", "𑣟"), - (0x118C0, "V"), - (0x118F3, "X"), - (0x118FF, "V"), - (0x11907, "X"), - (0x11909, "V"), - (0x1190A, "X"), - (0x1190C, "V"), - (0x11914, "X"), - (0x11915, "V"), - (0x11917, "X"), - (0x11918, "V"), - (0x11936, "X"), - (0x11937, "V"), - (0x11939, "X"), - (0x1193B, "V"), - (0x11947, "X"), - (0x11950, "V"), - (0x1195A, "X"), - (0x119A0, "V"), - (0x119A8, "X"), - (0x119AA, "V"), - (0x119D8, "X"), - (0x119DA, "V"), - (0x119E5, "X"), - (0x11A00, "V"), - (0x11A48, "X"), - (0x11A50, "V"), - (0x11AA3, "X"), - (0x11AB0, "V"), - (0x11AF9, "X"), - (0x11B00, "V"), - (0x11B0A, "X"), - (0x11B60, "V"), - (0x11B68, "X"), - (0x11BC0, "V"), - (0x11BE2, "X"), - (0x11BF0, "V"), - (0x11BFA, "X"), - (0x11C00, "V"), - (0x11C09, "X"), - (0x11C0A, "V"), - (0x11C37, "X"), - (0x11C38, "V"), - (0x11C46, "X"), - (0x11C50, "V"), - (0x11C6D, "X"), - (0x11C70, "V"), - (0x11C90, "X"), - (0x11C92, "V"), - (0x11CA8, "X"), - (0x11CA9, "V"), - (0x11CB7, "X"), - (0x11D00, "V"), - (0x11D07, "X"), - (0x11D08, "V"), - (0x11D0A, "X"), - (0x11D0B, "V"), - (0x11D37, "X"), - (0x11D3A, "V"), - (0x11D3B, "X"), - (0x11D3C, "V"), - (0x11D3E, "X"), - (0x11D3F, "V"), - (0x11D48, "X"), - (0x11D50, "V"), - (0x11D5A, "X"), - (0x11D60, "V"), - (0x11D66, "X"), - (0x11D67, "V"), - (0x11D69, "X"), - (0x11D6A, "V"), - (0x11D8F, "X"), - (0x11D90, "V"), - (0x11D92, "X"), - (0x11D93, "V"), - (0x11D99, "X"), - (0x11DA0, "V"), - (0x11DAA, "X"), - (0x11DB0, "V"), - (0x11DDC, "X"), - (0x11DE0, "V"), - (0x11DEA, "X"), - (0x11EE0, "V"), - (0x11EF9, "X"), - (0x11F00, "V"), - (0x11F11, "X"), - (0x11F12, "V"), - (0x11F3B, "X"), - (0x11F3E, "V"), - (0x11F5B, "X"), - (0x11FB0, "V"), - (0x11FB1, "X"), - (0x11FC0, "V"), - (0x11FF2, "X"), - (0x11FFF, "V"), - (0x1239A, "X"), - (0x12400, "V"), - (0x1246F, "X"), - (0x12470, "V"), - (0x12475, "X"), - (0x12480, "V"), - (0x12544, "X"), - (0x12F90, "V"), - (0x12FF3, "X"), - (0x13000, "V"), - (0x13430, "X"), - (0x13440, "V"), - (0x13456, "X"), - (0x13460, "V"), - (0x143FB, "X"), - (0x14400, "V"), - (0x14647, "X"), - (0x16100, "V"), - (0x1613A, "X"), - (0x16800, "V"), - (0x16A39, "X"), - (0x16A40, "V"), - (0x16A5F, "X"), - (0x16A60, "V"), - (0x16A6A, "X"), - (0x16A6E, "V"), - (0x16ABF, "X"), - (0x16AC0, "V"), - (0x16ACA, "X"), - (0x16AD0, "V"), - (0x16AEE, "X"), - (0x16AF0, "V"), - (0x16AF6, "X"), - (0x16B00, "V"), - (0x16B46, "X"), - (0x16B50, "V"), - (0x16B5A, "X"), - (0x16B5B, "V"), - (0x16B62, "X"), - (0x16B63, "V"), - (0x16B78, "X"), - (0x16B7D, "V"), - (0x16B90, "X"), - (0x16D40, "V"), - (0x16D7A, "X"), - (0x16E40, "M", "𖹠"), - (0x16E41, "M", "𖹡"), - (0x16E42, "M", "𖹢"), - (0x16E43, "M", "𖹣"), - (0x16E44, "M", "𖹤"), - (0x16E45, "M", "𖹥"), - (0x16E46, "M", "𖹦"), - (0x16E47, "M", "𖹧"), - (0x16E48, "M", "𖹨"), - (0x16E49, "M", "𖹩"), - (0x16E4A, "M", "𖹪"), - (0x16E4B, "M", "𖹫"), - (0x16E4C, "M", "𖹬"), - (0x16E4D, "M", "𖹭"), - (0x16E4E, "M", "𖹮"), - (0x16E4F, "M", "𖹯"), - (0x16E50, "M", "𖹰"), - (0x16E51, "M", "𖹱"), - (0x16E52, "M", "𖹲"), - (0x16E53, "M", "𖹳"), - (0x16E54, "M", "𖹴"), - (0x16E55, "M", "𖹵"), - (0x16E56, "M", "𖹶"), - (0x16E57, "M", "𖹷"), - (0x16E58, "M", "𖹸"), - (0x16E59, "M", "𖹹"), - (0x16E5A, "M", "𖹺"), - (0x16E5B, "M", "𖹻"), - (0x16E5C, "M", "𖹼"), - (0x16E5D, "M", "𖹽"), - (0x16E5E, "M", "𖹾"), - (0x16E5F, "M", "𖹿"), - (0x16E60, "V"), - (0x16E9B, "X"), - (0x16EA0, "M", "𖺻"), - (0x16EA1, "M", "𖺼"), - (0x16EA2, "M", "𖺽"), - (0x16EA3, "M", "𖺾"), - (0x16EA4, "M", "𖺿"), - (0x16EA5, "M", "𖻀"), - (0x16EA6, "M", "𖻁"), - (0x16EA7, "M", "𖻂"), - (0x16EA8, "M", "𖻃"), - (0x16EA9, "M", "𖻄"), - (0x16EAA, "M", "𖻅"), - (0x16EAB, "M", "𖻆"), - (0x16EAC, "M", "𖻇"), - (0x16EAD, "M", "𖻈"), - (0x16EAE, "M", "𖻉"), - (0x16EAF, "M", "𖻊"), - (0x16EB0, "M", "𖻋"), - (0x16EB1, "M", "𖻌"), - (0x16EB2, "M", "𖻍"), - (0x16EB3, "M", "𖻎"), - (0x16EB4, "M", "𖻏"), - (0x16EB5, "M", "𖻐"), - (0x16EB6, "M", "𖻑"), - (0x16EB7, "M", "𖻒"), - (0x16EB8, "M", "𖻓"), - (0x16EB9, "X"), - (0x16EBB, "V"), - (0x16ED4, "X"), - (0x16F00, "V"), - (0x16F4B, "X"), - (0x16F4F, "V"), - (0x16F88, "X"), - (0x16F8F, "V"), - (0x16FA0, "X"), - (0x16FE0, "V"), - (0x16FE5, "X"), - (0x16FF0, "V"), - (0x16FF7, "X"), - (0x17000, "V"), - (0x18CD6, "X"), - (0x18CFF, "V"), - (0x18D1F, "X"), - (0x18D80, "V"), - (0x18DF3, "X"), - (0x1AFF0, "V"), - (0x1AFF4, "X"), - (0x1AFF5, "V"), - (0x1AFFC, "X"), - (0x1AFFD, "V"), - (0x1AFFF, "X"), - (0x1B000, "V"), - (0x1B123, "X"), - (0x1B132, "V"), - (0x1B133, "X"), - (0x1B150, "V"), - (0x1B153, "X"), - (0x1B155, "V"), - (0x1B156, "X"), - (0x1B164, "V"), - (0x1B168, "X"), - (0x1B170, "V"), - (0x1B2FC, "X"), - (0x1BC00, "V"), - (0x1BC6B, "X"), - (0x1BC70, "V"), - (0x1BC7D, "X"), - (0x1BC80, "V"), - (0x1BC89, "X"), - (0x1BC90, "V"), - (0x1BC9A, "X"), - (0x1BC9C, "V"), - (0x1BCA0, "I"), - (0x1BCA4, "X"), - (0x1CC00, "V"), - (0x1CCD6, "M", "a"), - (0x1CCD7, "M", "b"), - (0x1CCD8, "M", "c"), - (0x1CCD9, "M", "d"), - (0x1CCDA, "M", "e"), - (0x1CCDB, "M", "f"), - (0x1CCDC, "M", "g"), - (0x1CCDD, "M", "h"), - (0x1CCDE, "M", "i"), - (0x1CCDF, "M", "j"), - (0x1CCE0, "M", "k"), - (0x1CCE1, "M", "l"), - (0x1CCE2, "M", "m"), - (0x1CCE3, "M", "n"), - (0x1CCE4, "M", "o"), - (0x1CCE5, "M", "p"), - (0x1CCE6, "M", "q"), - (0x1CCE7, "M", "r"), - (0x1CCE8, "M", "s"), - (0x1CCE9, "M", "t"), - (0x1CCEA, "M", "u"), - (0x1CCEB, "M", "v"), - (0x1CCEC, "M", "w"), - (0x1CCED, "M", "x"), - (0x1CCEE, "M", "y"), - (0x1CCEF, "M", "z"), - (0x1CCF0, "M", "0"), - (0x1CCF1, "M", "1"), - (0x1CCF2, "M", "2"), - (0x1CCF3, "M", "3"), - (0x1CCF4, "M", "4"), - (0x1CCF5, "M", "5"), - (0x1CCF6, "M", "6"), - (0x1CCF7, "M", "7"), - (0x1CCF8, "M", "8"), - (0x1CCF9, "M", "9"), - (0x1CCFA, "V"), - (0x1CCFD, "X"), - (0x1CD00, "V"), - (0x1CEB4, "X"), - (0x1CEBA, "V"), - (0x1CED1, "X"), - (0x1CEE0, "V"), - (0x1CEF1, "X"), - (0x1CF00, "V"), - (0x1CF2E, "X"), - (0x1CF30, "V"), - (0x1CF47, "X"), - (0x1CF50, "V"), - (0x1CFC4, "X"), - (0x1D000, "V"), - (0x1D0F6, "X"), - (0x1D100, "V"), - (0x1D127, "X"), - (0x1D129, "V"), - (0x1D15E, "M", "𝅗𝅥"), - (0x1D15F, "M", "𝅘𝅥"), - (0x1D160, "M", "𝅘𝅥𝅮"), - (0x1D161, "M", "𝅘𝅥𝅯"), - (0x1D162, "M", "𝅘𝅥𝅰"), - (0x1D163, "M", "𝅘𝅥𝅱"), - (0x1D164, "M", "𝅘𝅥𝅲"), - (0x1D165, "V"), - (0x1D173, "I"), - (0x1D17B, "V"), - (0x1D1BB, "M", "𝆹𝅥"), - (0x1D1BC, "M", "𝆺𝅥"), - (0x1D1BD, "M", "𝆹𝅥𝅮"), - (0x1D1BE, "M", "𝆺𝅥𝅮"), - (0x1D1BF, "M", "𝆹𝅥𝅯"), - (0x1D1C0, "M", "𝆺𝅥𝅯"), - (0x1D1C1, "V"), - (0x1D1EB, "X"), - (0x1D200, "V"), - (0x1D246, "X"), - (0x1D2C0, "V"), - (0x1D2D4, "X"), - (0x1D2E0, "V"), - (0x1D2F4, "X"), - (0x1D300, "V"), - (0x1D357, "X"), - (0x1D360, "V"), - (0x1D379, "X"), - (0x1D400, "M", "a"), - (0x1D401, "M", "b"), - (0x1D402, "M", "c"), - (0x1D403, "M", "d"), - (0x1D404, "M", "e"), - (0x1D405, "M", "f"), - (0x1D406, "M", "g"), - (0x1D407, "M", "h"), - (0x1D408, "M", "i"), - (0x1D409, "M", "j"), - (0x1D40A, "M", "k"), - (0x1D40B, "M", "l"), - (0x1D40C, "M", "m"), - (0x1D40D, "M", "n"), - (0x1D40E, "M", "o"), - (0x1D40F, "M", "p"), - (0x1D410, "M", "q"), - (0x1D411, "M", "r"), - (0x1D412, "M", "s"), - (0x1D413, "M", "t"), - (0x1D414, "M", "u"), - (0x1D415, "M", "v"), - (0x1D416, "M", "w"), - (0x1D417, "M", "x"), - (0x1D418, "M", "y"), - (0x1D419, "M", "z"), - (0x1D41A, "M", "a"), - (0x1D41B, "M", "b"), - (0x1D41C, "M", "c"), - (0x1D41D, "M", "d"), - (0x1D41E, "M", "e"), - (0x1D41F, "M", "f"), - (0x1D420, "M", "g"), - (0x1D421, "M", "h"), - (0x1D422, "M", "i"), - (0x1D423, "M", "j"), - (0x1D424, "M", "k"), - (0x1D425, "M", "l"), - (0x1D426, "M", "m"), - (0x1D427, "M", "n"), - (0x1D428, "M", "o"), - (0x1D429, "M", "p"), - (0x1D42A, "M", "q"), - (0x1D42B, "M", "r"), - (0x1D42C, "M", "s"), - (0x1D42D, "M", "t"), - (0x1D42E, "M", "u"), - (0x1D42F, "M", "v"), - (0x1D430, "M", "w"), - (0x1D431, "M", "x"), - (0x1D432, "M", "y"), - (0x1D433, "M", "z"), - (0x1D434, "M", "a"), - (0x1D435, "M", "b"), - (0x1D436, "M", "c"), - (0x1D437, "M", "d"), - (0x1D438, "M", "e"), - (0x1D439, "M", "f"), - (0x1D43A, "M", "g"), - (0x1D43B, "M", "h"), - (0x1D43C, "M", "i"), - (0x1D43D, "M", "j"), - (0x1D43E, "M", "k"), - (0x1D43F, "M", "l"), - (0x1D440, "M", "m"), - (0x1D441, "M", "n"), - (0x1D442, "M", "o"), - (0x1D443, "M", "p"), - (0x1D444, "M", "q"), - (0x1D445, "M", "r"), - (0x1D446, "M", "s"), - (0x1D447, "M", "t"), - (0x1D448, "M", "u"), - (0x1D449, "M", "v"), - (0x1D44A, "M", "w"), - (0x1D44B, "M", "x"), - (0x1D44C, "M", "y"), - (0x1D44D, "M", "z"), - (0x1D44E, "M", "a"), - (0x1D44F, "M", "b"), - (0x1D450, "M", "c"), - (0x1D451, "M", "d"), - (0x1D452, "M", "e"), - (0x1D453, "M", "f"), - (0x1D454, "M", "g"), - (0x1D455, "X"), - (0x1D456, "M", "i"), - (0x1D457, "M", "j"), - (0x1D458, "M", "k"), - (0x1D459, "M", "l"), - (0x1D45A, "M", "m"), - (0x1D45B, "M", "n"), - (0x1D45C, "M", "o"), - (0x1D45D, "M", "p"), - (0x1D45E, "M", "q"), - (0x1D45F, "M", "r"), - (0x1D460, "M", "s"), - (0x1D461, "M", "t"), - (0x1D462, "M", "u"), - (0x1D463, "M", "v"), - (0x1D464, "M", "w"), - (0x1D465, "M", "x"), - (0x1D466, "M", "y"), - (0x1D467, "M", "z"), - (0x1D468, "M", "a"), - (0x1D469, "M", "b"), - (0x1D46A, "M", "c"), - (0x1D46B, "M", "d"), - (0x1D46C, "M", "e"), - (0x1D46D, "M", "f"), - (0x1D46E, "M", "g"), - (0x1D46F, "M", "h"), - (0x1D470, "M", "i"), - (0x1D471, "M", "j"), - (0x1D472, "M", "k"), - (0x1D473, "M", "l"), - (0x1D474, "M", "m"), - (0x1D475, "M", "n"), - (0x1D476, "M", "o"), - (0x1D477, "M", "p"), - (0x1D478, "M", "q"), - (0x1D479, "M", "r"), - (0x1D47A, "M", "s"), - (0x1D47B, "M", "t"), - (0x1D47C, "M", "u"), - (0x1D47D, "M", "v"), - (0x1D47E, "M", "w"), - (0x1D47F, "M", "x"), - (0x1D480, "M", "y"), - (0x1D481, "M", "z"), - (0x1D482, "M", "a"), - (0x1D483, "M", "b"), - (0x1D484, "M", "c"), - (0x1D485, "M", "d"), - (0x1D486, "M", "e"), - (0x1D487, "M", "f"), - (0x1D488, "M", "g"), - (0x1D489, "M", "h"), - (0x1D48A, "M", "i"), - (0x1D48B, "M", "j"), - (0x1D48C, "M", "k"), - (0x1D48D, "M", "l"), - (0x1D48E, "M", "m"), - (0x1D48F, "M", "n"), - (0x1D490, "M", "o"), - (0x1D491, "M", "p"), - (0x1D492, "M", "q"), - (0x1D493, "M", "r"), - (0x1D494, "M", "s"), - (0x1D495, "M", "t"), - (0x1D496, "M", "u"), - (0x1D497, "M", "v"), - (0x1D498, "M", "w"), - (0x1D499, "M", "x"), - (0x1D49A, "M", "y"), - (0x1D49B, "M", "z"), - (0x1D49C, "M", "a"), - (0x1D49D, "X"), - (0x1D49E, "M", "c"), - (0x1D49F, "M", "d"), - (0x1D4A0, "X"), - (0x1D4A2, "M", "g"), - (0x1D4A3, "X"), - (0x1D4A5, "M", "j"), - (0x1D4A6, "M", "k"), - (0x1D4A7, "X"), - (0x1D4A9, "M", "n"), - (0x1D4AA, "M", "o"), - (0x1D4AB, "M", "p"), - (0x1D4AC, "M", "q"), - (0x1D4AD, "X"), - (0x1D4AE, "M", "s"), - (0x1D4AF, "M", "t"), - (0x1D4B0, "M", "u"), - (0x1D4B1, "M", "v"), - (0x1D4B2, "M", "w"), - (0x1D4B3, "M", "x"), - (0x1D4B4, "M", "y"), - (0x1D4B5, "M", "z"), - (0x1D4B6, "M", "a"), - (0x1D4B7, "M", "b"), - (0x1D4B8, "M", "c"), - (0x1D4B9, "M", "d"), - (0x1D4BA, "X"), - (0x1D4BB, "M", "f"), - (0x1D4BC, "X"), - (0x1D4BD, "M", "h"), - (0x1D4BE, "M", "i"), - (0x1D4BF, "M", "j"), - (0x1D4C0, "M", "k"), - (0x1D4C1, "M", "l"), - (0x1D4C2, "M", "m"), - (0x1D4C3, "M", "n"), - (0x1D4C4, "X"), - (0x1D4C5, "M", "p"), - (0x1D4C6, "M", "q"), - (0x1D4C7, "M", "r"), - (0x1D4C8, "M", "s"), - (0x1D4C9, "M", "t"), - (0x1D4CA, "M", "u"), - (0x1D4CB, "M", "v"), - (0x1D4CC, "M", "w"), - (0x1D4CD, "M", "x"), - (0x1D4CE, "M", "y"), - (0x1D4CF, "M", "z"), - (0x1D4D0, "M", "a"), - (0x1D4D1, "M", "b"), - (0x1D4D2, "M", "c"), - (0x1D4D3, "M", "d"), - (0x1D4D4, "M", "e"), - (0x1D4D5, "M", "f"), - (0x1D4D6, "M", "g"), - (0x1D4D7, "M", "h"), - (0x1D4D8, "M", "i"), - (0x1D4D9, "M", "j"), - (0x1D4DA, "M", "k"), - (0x1D4DB, "M", "l"), - (0x1D4DC, "M", "m"), - (0x1D4DD, "M", "n"), - (0x1D4DE, "M", "o"), - (0x1D4DF, "M", "p"), - (0x1D4E0, "M", "q"), - (0x1D4E1, "M", "r"), - (0x1D4E2, "M", "s"), - (0x1D4E3, "M", "t"), - (0x1D4E4, "M", "u"), - (0x1D4E5, "M", "v"), - (0x1D4E6, "M", "w"), - (0x1D4E7, "M", "x"), - (0x1D4E8, "M", "y"), - (0x1D4E9, "M", "z"), - (0x1D4EA, "M", "a"), - (0x1D4EB, "M", "b"), - (0x1D4EC, "M", "c"), - (0x1D4ED, "M", "d"), - (0x1D4EE, "M", "e"), - (0x1D4EF, "M", "f"), - (0x1D4F0, "M", "g"), - (0x1D4F1, "M", "h"), - (0x1D4F2, "M", "i"), - (0x1D4F3, "M", "j"), - (0x1D4F4, "M", "k"), - (0x1D4F5, "M", "l"), - (0x1D4F6, "M", "m"), - (0x1D4F7, "M", "n"), - (0x1D4F8, "M", "o"), - (0x1D4F9, "M", "p"), - (0x1D4FA, "M", "q"), - (0x1D4FB, "M", "r"), - (0x1D4FC, "M", "s"), - (0x1D4FD, "M", "t"), - (0x1D4FE, "M", "u"), - (0x1D4FF, "M", "v"), - (0x1D500, "M", "w"), - (0x1D501, "M", "x"), - (0x1D502, "M", "y"), - (0x1D503, "M", "z"), - (0x1D504, "M", "a"), - (0x1D505, "M", "b"), - (0x1D506, "X"), - (0x1D507, "M", "d"), - (0x1D508, "M", "e"), - (0x1D509, "M", "f"), - (0x1D50A, "M", "g"), - (0x1D50B, "X"), - (0x1D50D, "M", "j"), - (0x1D50E, "M", "k"), - (0x1D50F, "M", "l"), - (0x1D510, "M", "m"), - (0x1D511, "M", "n"), - (0x1D512, "M", "o"), - (0x1D513, "M", "p"), - (0x1D514, "M", "q"), - (0x1D515, "X"), - (0x1D516, "M", "s"), - (0x1D517, "M", "t"), - (0x1D518, "M", "u"), - (0x1D519, "M", "v"), - (0x1D51A, "M", "w"), - (0x1D51B, "M", "x"), - (0x1D51C, "M", "y"), - (0x1D51D, "X"), - (0x1D51E, "M", "a"), - (0x1D51F, "M", "b"), - (0x1D520, "M", "c"), - (0x1D521, "M", "d"), - (0x1D522, "M", "e"), - (0x1D523, "M", "f"), - (0x1D524, "M", "g"), - (0x1D525, "M", "h"), - (0x1D526, "M", "i"), - (0x1D527, "M", "j"), - (0x1D528, "M", "k"), - (0x1D529, "M", "l"), - (0x1D52A, "M", "m"), - (0x1D52B, "M", "n"), - (0x1D52C, "M", "o"), - (0x1D52D, "M", "p"), - (0x1D52E, "M", "q"), - (0x1D52F, "M", "r"), - (0x1D530, "M", "s"), - (0x1D531, "M", "t"), - (0x1D532, "M", "u"), - (0x1D533, "M", "v"), - (0x1D534, "M", "w"), - (0x1D535, "M", "x"), - (0x1D536, "M", "y"), - (0x1D537, "M", "z"), - (0x1D538, "M", "a"), - (0x1D539, "M", "b"), - (0x1D53A, "X"), - (0x1D53B, "M", "d"), - (0x1D53C, "M", "e"), - (0x1D53D, "M", "f"), - (0x1D53E, "M", "g"), - (0x1D53F, "X"), - (0x1D540, "M", "i"), - (0x1D541, "M", "j"), - (0x1D542, "M", "k"), - (0x1D543, "M", "l"), - (0x1D544, "M", "m"), - (0x1D545, "X"), - (0x1D546, "M", "o"), - (0x1D547, "X"), - (0x1D54A, "M", "s"), - (0x1D54B, "M", "t"), - (0x1D54C, "M", "u"), - (0x1D54D, "M", "v"), - (0x1D54E, "M", "w"), - (0x1D54F, "M", "x"), - (0x1D550, "M", "y"), - (0x1D551, "X"), - (0x1D552, "M", "a"), - (0x1D553, "M", "b"), - (0x1D554, "M", "c"), - (0x1D555, "M", "d"), - (0x1D556, "M", "e"), - (0x1D557, "M", "f"), - (0x1D558, "M", "g"), - (0x1D559, "M", "h"), - (0x1D55A, "M", "i"), - (0x1D55B, "M", "j"), - (0x1D55C, "M", "k"), - (0x1D55D, "M", "l"), - (0x1D55E, "M", "m"), - (0x1D55F, "M", "n"), - (0x1D560, "M", "o"), - (0x1D561, "M", "p"), - (0x1D562, "M", "q"), - (0x1D563, "M", "r"), - (0x1D564, "M", "s"), - (0x1D565, "M", "t"), - (0x1D566, "M", "u"), - (0x1D567, "M", "v"), - (0x1D568, "M", "w"), - (0x1D569, "M", "x"), - (0x1D56A, "M", "y"), - (0x1D56B, "M", "z"), - (0x1D56C, "M", "a"), - (0x1D56D, "M", "b"), - (0x1D56E, "M", "c"), - (0x1D56F, "M", "d"), - (0x1D570, "M", "e"), - (0x1D571, "M", "f"), - (0x1D572, "M", "g"), - (0x1D573, "M", "h"), - (0x1D574, "M", "i"), - (0x1D575, "M", "j"), - (0x1D576, "M", "k"), - (0x1D577, "M", "l"), - (0x1D578, "M", "m"), - (0x1D579, "M", "n"), - (0x1D57A, "M", "o"), - (0x1D57B, "M", "p"), - (0x1D57C, "M", "q"), - (0x1D57D, "M", "r"), - (0x1D57E, "M", "s"), - (0x1D57F, "M", "t"), - (0x1D580, "M", "u"), - (0x1D581, "M", "v"), - (0x1D582, "M", "w"), - (0x1D583, "M", "x"), - (0x1D584, "M", "y"), - (0x1D585, "M", "z"), - (0x1D586, "M", "a"), - (0x1D587, "M", "b"), - (0x1D588, "M", "c"), - (0x1D589, "M", "d"), - (0x1D58A, "M", "e"), - (0x1D58B, "M", "f"), - (0x1D58C, "M", "g"), - (0x1D58D, "M", "h"), - (0x1D58E, "M", "i"), - (0x1D58F, "M", "j"), - (0x1D590, "M", "k"), - (0x1D591, "M", "l"), - (0x1D592, "M", "m"), - (0x1D593, "M", "n"), - (0x1D594, "M", "o"), - (0x1D595, "M", "p"), - (0x1D596, "M", "q"), - (0x1D597, "M", "r"), - (0x1D598, "M", "s"), - (0x1D599, "M", "t"), - (0x1D59A, "M", "u"), - (0x1D59B, "M", "v"), - (0x1D59C, "M", "w"), - (0x1D59D, "M", "x"), - (0x1D59E, "M", "y"), - (0x1D59F, "M", "z"), - (0x1D5A0, "M", "a"), - (0x1D5A1, "M", "b"), - (0x1D5A2, "M", "c"), - (0x1D5A3, "M", "d"), - (0x1D5A4, "M", "e"), - (0x1D5A5, "M", "f"), - (0x1D5A6, "M", "g"), - (0x1D5A7, "M", "h"), - (0x1D5A8, "M", "i"), - (0x1D5A9, "M", "j"), - (0x1D5AA, "M", "k"), - (0x1D5AB, "M", "l"), - (0x1D5AC, "M", "m"), - (0x1D5AD, "M", "n"), - (0x1D5AE, "M", "o"), - (0x1D5AF, "M", "p"), - (0x1D5B0, "M", "q"), - (0x1D5B1, "M", "r"), - (0x1D5B2, "M", "s"), - (0x1D5B3, "M", "t"), - (0x1D5B4, "M", "u"), - (0x1D5B5, "M", "v"), - (0x1D5B6, "M", "w"), - (0x1D5B7, "M", "x"), - (0x1D5B8, "M", "y"), - (0x1D5B9, "M", "z"), - (0x1D5BA, "M", "a"), - (0x1D5BB, "M", "b"), - (0x1D5BC, "M", "c"), - (0x1D5BD, "M", "d"), - (0x1D5BE, "M", "e"), - (0x1D5BF, "M", "f"), - (0x1D5C0, "M", "g"), - (0x1D5C1, "M", "h"), - (0x1D5C2, "M", "i"), - (0x1D5C3, "M", "j"), - (0x1D5C4, "M", "k"), - (0x1D5C5, "M", "l"), - (0x1D5C6, "M", "m"), - (0x1D5C7, "M", "n"), - (0x1D5C8, "M", "o"), - (0x1D5C9, "M", "p"), - (0x1D5CA, "M", "q"), - (0x1D5CB, "M", "r"), - (0x1D5CC, "M", "s"), - (0x1D5CD, "M", "t"), - (0x1D5CE, "M", "u"), - (0x1D5CF, "M", "v"), - (0x1D5D0, "M", "w"), - (0x1D5D1, "M", "x"), - (0x1D5D2, "M", "y"), - (0x1D5D3, "M", "z"), - (0x1D5D4, "M", "a"), - (0x1D5D5, "M", "b"), - (0x1D5D6, "M", "c"), - (0x1D5D7, "M", "d"), - (0x1D5D8, "M", "e"), - (0x1D5D9, "M", "f"), - (0x1D5DA, "M", "g"), - (0x1D5DB, "M", "h"), - (0x1D5DC, "M", "i"), - (0x1D5DD, "M", "j"), - (0x1D5DE, "M", "k"), - (0x1D5DF, "M", "l"), - (0x1D5E0, "M", "m"), - (0x1D5E1, "M", "n"), - (0x1D5E2, "M", "o"), - (0x1D5E3, "M", "p"), - (0x1D5E4, "M", "q"), - (0x1D5E5, "M", "r"), - (0x1D5E6, "M", "s"), - (0x1D5E7, "M", "t"), - (0x1D5E8, "M", "u"), - (0x1D5E9, "M", "v"), - (0x1D5EA, "M", "w"), - (0x1D5EB, "M", "x"), - (0x1D5EC, "M", "y"), - (0x1D5ED, "M", "z"), - (0x1D5EE, "M", "a"), - (0x1D5EF, "M", "b"), - (0x1D5F0, "M", "c"), - (0x1D5F1, "M", "d"), - (0x1D5F2, "M", "e"), - (0x1D5F3, "M", "f"), - (0x1D5F4, "M", "g"), - (0x1D5F5, "M", "h"), - (0x1D5F6, "M", "i"), - (0x1D5F7, "M", "j"), - (0x1D5F8, "M", "k"), - (0x1D5F9, "M", "l"), - (0x1D5FA, "M", "m"), - (0x1D5FB, "M", "n"), - (0x1D5FC, "M", "o"), - (0x1D5FD, "M", "p"), - (0x1D5FE, "M", "q"), - (0x1D5FF, "M", "r"), - (0x1D600, "M", "s"), - (0x1D601, "M", "t"), - (0x1D602, "M", "u"), - (0x1D603, "M", "v"), - (0x1D604, "M", "w"), - (0x1D605, "M", "x"), - (0x1D606, "M", "y"), - (0x1D607, "M", "z"), - (0x1D608, "M", "a"), - (0x1D609, "M", "b"), - (0x1D60A, "M", "c"), - (0x1D60B, "M", "d"), - (0x1D60C, "M", "e"), - (0x1D60D, "M", "f"), - (0x1D60E, "M", "g"), - (0x1D60F, "M", "h"), - (0x1D610, "M", "i"), - (0x1D611, "M", "j"), - (0x1D612, "M", "k"), - (0x1D613, "M", "l"), - (0x1D614, "M", "m"), - (0x1D615, "M", "n"), - (0x1D616, "M", "o"), - (0x1D617, "M", "p"), - (0x1D618, "M", "q"), - (0x1D619, "M", "r"), - (0x1D61A, "M", "s"), - (0x1D61B, "M", "t"), - (0x1D61C, "M", "u"), - (0x1D61D, "M", "v"), - (0x1D61E, "M", "w"), - (0x1D61F, "M", "x"), - (0x1D620, "M", "y"), - (0x1D621, "M", "z"), - (0x1D622, "M", "a"), - (0x1D623, "M", "b"), - (0x1D624, "M", "c"), - (0x1D625, "M", "d"), - (0x1D626, "M", "e"), - (0x1D627, "M", "f"), - (0x1D628, "M", "g"), - (0x1D629, "M", "h"), - (0x1D62A, "M", "i"), - (0x1D62B, "M", "j"), - (0x1D62C, "M", "k"), - (0x1D62D, "M", "l"), - (0x1D62E, "M", "m"), - (0x1D62F, "M", "n"), - (0x1D630, "M", "o"), - (0x1D631, "M", "p"), - (0x1D632, "M", "q"), - (0x1D633, "M", "r"), - (0x1D634, "M", "s"), - (0x1D635, "M", "t"), - (0x1D636, "M", "u"), - (0x1D637, "M", "v"), - (0x1D638, "M", "w"), - (0x1D639, "M", "x"), - (0x1D63A, "M", "y"), - (0x1D63B, "M", "z"), - (0x1D63C, "M", "a"), - (0x1D63D, "M", "b"), - (0x1D63E, "M", "c"), - (0x1D63F, "M", "d"), - (0x1D640, "M", "e"), - (0x1D641, "M", "f"), - (0x1D642, "M", "g"), - (0x1D643, "M", "h"), - (0x1D644, "M", "i"), - (0x1D645, "M", "j"), - (0x1D646, "M", "k"), - (0x1D647, "M", "l"), - (0x1D648, "M", "m"), - (0x1D649, "M", "n"), - (0x1D64A, "M", "o"), - (0x1D64B, "M", "p"), - (0x1D64C, "M", "q"), - (0x1D64D, "M", "r"), - (0x1D64E, "M", "s"), - (0x1D64F, "M", "t"), - (0x1D650, "M", "u"), - (0x1D651, "M", "v"), - (0x1D652, "M", "w"), - (0x1D653, "M", "x"), - (0x1D654, "M", "y"), - (0x1D655, "M", "z"), - (0x1D656, "M", "a"), - (0x1D657, "M", "b"), - (0x1D658, "M", "c"), - (0x1D659, "M", "d"), - (0x1D65A, "M", "e"), - (0x1D65B, "M", "f"), - (0x1D65C, "M", "g"), - (0x1D65D, "M", "h"), - (0x1D65E, "M", "i"), - (0x1D65F, "M", "j"), - (0x1D660, "M", "k"), - (0x1D661, "M", "l"), - (0x1D662, "M", "m"), - (0x1D663, "M", "n"), - (0x1D664, "M", "o"), - (0x1D665, "M", "p"), - (0x1D666, "M", "q"), - (0x1D667, "M", "r"), - (0x1D668, "M", "s"), - (0x1D669, "M", "t"), - (0x1D66A, "M", "u"), - (0x1D66B, "M", "v"), - (0x1D66C, "M", "w"), - (0x1D66D, "M", "x"), - (0x1D66E, "M", "y"), - (0x1D66F, "M", "z"), - (0x1D670, "M", "a"), - (0x1D671, "M", "b"), - (0x1D672, "M", "c"), - (0x1D673, "M", "d"), - (0x1D674, "M", "e"), - (0x1D675, "M", "f"), - (0x1D676, "M", "g"), - (0x1D677, "M", "h"), - (0x1D678, "M", "i"), - (0x1D679, "M", "j"), - (0x1D67A, "M", "k"), - (0x1D67B, "M", "l"), - (0x1D67C, "M", "m"), - (0x1D67D, "M", "n"), - (0x1D67E, "M", "o"), - (0x1D67F, "M", "p"), - (0x1D680, "M", "q"), - (0x1D681, "M", "r"), - (0x1D682, "M", "s"), - (0x1D683, "M", "t"), - (0x1D684, "M", "u"), - (0x1D685, "M", "v"), - (0x1D686, "M", "w"), - (0x1D687, "M", "x"), - (0x1D688, "M", "y"), - (0x1D689, "M", "z"), - (0x1D68A, "M", "a"), - (0x1D68B, "M", "b"), - (0x1D68C, "M", "c"), - (0x1D68D, "M", "d"), - (0x1D68E, "M", "e"), - (0x1D68F, "M", "f"), - (0x1D690, "M", "g"), - (0x1D691, "M", "h"), - (0x1D692, "M", "i"), - (0x1D693, "M", "j"), - (0x1D694, "M", "k"), - (0x1D695, "M", "l"), - (0x1D696, "M", "m"), - (0x1D697, "M", "n"), - (0x1D698, "M", "o"), - (0x1D699, "M", "p"), - (0x1D69A, "M", "q"), - (0x1D69B, "M", "r"), - (0x1D69C, "M", "s"), - (0x1D69D, "M", "t"), - (0x1D69E, "M", "u"), - (0x1D69F, "M", "v"), - (0x1D6A0, "M", "w"), - (0x1D6A1, "M", "x"), - (0x1D6A2, "M", "y"), - (0x1D6A3, "M", "z"), - (0x1D6A4, "M", "ı"), - (0x1D6A5, "M", "ȷ"), - (0x1D6A6, "X"), - (0x1D6A8, "M", "α"), - (0x1D6A9, "M", "β"), - (0x1D6AA, "M", "γ"), - (0x1D6AB, "M", "δ"), - (0x1D6AC, "M", "ε"), - (0x1D6AD, "M", "ζ"), - (0x1D6AE, "M", "η"), - (0x1D6AF, "M", "θ"), - (0x1D6B0, "M", "ι"), - (0x1D6B1, "M", "κ"), - (0x1D6B2, "M", "λ"), - (0x1D6B3, "M", "μ"), - (0x1D6B4, "M", "ν"), - (0x1D6B5, "M", "ξ"), - (0x1D6B6, "M", "ο"), - (0x1D6B7, "M", "π"), - (0x1D6B8, "M", "ρ"), - (0x1D6B9, "M", "θ"), - (0x1D6BA, "M", "σ"), - (0x1D6BB, "M", "τ"), - (0x1D6BC, "M", "υ"), - (0x1D6BD, "M", "φ"), - (0x1D6BE, "M", "χ"), - (0x1D6BF, "M", "ψ"), - (0x1D6C0, "M", "ω"), - (0x1D6C1, "M", "∇"), - (0x1D6C2, "M", "α"), - (0x1D6C3, "M", "β"), - (0x1D6C4, "M", "γ"), - (0x1D6C5, "M", "δ"), - (0x1D6C6, "M", "ε"), - (0x1D6C7, "M", "ζ"), - (0x1D6C8, "M", "η"), - (0x1D6C9, "M", "θ"), - (0x1D6CA, "M", "ι"), - (0x1D6CB, "M", "κ"), - (0x1D6CC, "M", "λ"), - (0x1D6CD, "M", "μ"), - (0x1D6CE, "M", "ν"), - (0x1D6CF, "M", "ξ"), - (0x1D6D0, "M", "ο"), - (0x1D6D1, "M", "π"), - (0x1D6D2, "M", "ρ"), - (0x1D6D3, "M", "σ"), - (0x1D6D5, "M", "τ"), - (0x1D6D6, "M", "υ"), - (0x1D6D7, "M", "φ"), - (0x1D6D8, "M", "χ"), - (0x1D6D9, "M", "ψ"), - (0x1D6DA, "M", "ω"), - (0x1D6DB, "M", "∂"), - (0x1D6DC, "M", "ε"), - (0x1D6DD, "M", "θ"), - (0x1D6DE, "M", "κ"), - (0x1D6DF, "M", "φ"), - (0x1D6E0, "M", "ρ"), - (0x1D6E1, "M", "π"), - (0x1D6E2, "M", "α"), - (0x1D6E3, "M", "β"), - (0x1D6E4, "M", "γ"), - (0x1D6E5, "M", "δ"), - (0x1D6E6, "M", "ε"), - (0x1D6E7, "M", "ζ"), - (0x1D6E8, "M", "η"), - (0x1D6E9, "M", "θ"), - (0x1D6EA, "M", "ι"), - (0x1D6EB, "M", "κ"), - (0x1D6EC, "M", "λ"), - (0x1D6ED, "M", "μ"), - (0x1D6EE, "M", "ν"), - (0x1D6EF, "M", "ξ"), - (0x1D6F0, "M", "ο"), - (0x1D6F1, "M", "π"), - (0x1D6F2, "M", "ρ"), - (0x1D6F3, "M", "θ"), - (0x1D6F4, "M", "σ"), - (0x1D6F5, "M", "τ"), - (0x1D6F6, "M", "υ"), - (0x1D6F7, "M", "φ"), - (0x1D6F8, "M", "χ"), - (0x1D6F9, "M", "ψ"), - (0x1D6FA, "M", "ω"), - (0x1D6FB, "M", "∇"), - (0x1D6FC, "M", "α"), - (0x1D6FD, "M", "β"), - (0x1D6FE, "M", "γ"), - (0x1D6FF, "M", "δ"), - (0x1D700, "M", "ε"), - (0x1D701, "M", "ζ"), - (0x1D702, "M", "η"), - (0x1D703, "M", "θ"), - (0x1D704, "M", "ι"), - (0x1D705, "M", "κ"), - (0x1D706, "M", "λ"), - (0x1D707, "M", "μ"), - (0x1D708, "M", "ν"), - (0x1D709, "M", "ξ"), - (0x1D70A, "M", "ο"), - (0x1D70B, "M", "π"), - (0x1D70C, "M", "ρ"), - (0x1D70D, "M", "σ"), - (0x1D70F, "M", "τ"), - (0x1D710, "M", "υ"), - (0x1D711, "M", "φ"), - (0x1D712, "M", "χ"), - (0x1D713, "M", "ψ"), - (0x1D714, "M", "ω"), - (0x1D715, "M", "∂"), - (0x1D716, "M", "ε"), - (0x1D717, "M", "θ"), - (0x1D718, "M", "κ"), - (0x1D719, "M", "φ"), - (0x1D71A, "M", "ρ"), - (0x1D71B, "M", "π"), - (0x1D71C, "M", "α"), - (0x1D71D, "M", "β"), - (0x1D71E, "M", "γ"), - (0x1D71F, "M", "δ"), - (0x1D720, "M", "ε"), - (0x1D721, "M", "ζ"), - (0x1D722, "M", "η"), - (0x1D723, "M", "θ"), - (0x1D724, "M", "ι"), - (0x1D725, "M", "κ"), - (0x1D726, "M", "λ"), - (0x1D727, "M", "μ"), - (0x1D728, "M", "ν"), - (0x1D729, "M", "ξ"), - (0x1D72A, "M", "ο"), - (0x1D72B, "M", "π"), - (0x1D72C, "M", "ρ"), - (0x1D72D, "M", "θ"), - (0x1D72E, "M", "σ"), - (0x1D72F, "M", "τ"), - (0x1D730, "M", "υ"), - (0x1D731, "M", "φ"), - (0x1D732, "M", "χ"), - (0x1D733, "M", "ψ"), - (0x1D734, "M", "ω"), - (0x1D735, "M", "∇"), - (0x1D736, "M", "α"), - (0x1D737, "M", "β"), - (0x1D738, "M", "γ"), - (0x1D739, "M", "δ"), - (0x1D73A, "M", "ε"), - (0x1D73B, "M", "ζ"), - (0x1D73C, "M", "η"), - (0x1D73D, "M", "θ"), - (0x1D73E, "M", "ι"), - (0x1D73F, "M", "κ"), - (0x1D740, "M", "λ"), - (0x1D741, "M", "μ"), - (0x1D742, "M", "ν"), - (0x1D743, "M", "ξ"), - (0x1D744, "M", "ο"), - (0x1D745, "M", "π"), - (0x1D746, "M", "ρ"), - (0x1D747, "M", "σ"), - (0x1D749, "M", "τ"), - (0x1D74A, "M", "υ"), - (0x1D74B, "M", "φ"), - (0x1D74C, "M", "χ"), - (0x1D74D, "M", "ψ"), - (0x1D74E, "M", "ω"), - (0x1D74F, "M", "∂"), - (0x1D750, "M", "ε"), - (0x1D751, "M", "θ"), - (0x1D752, "M", "κ"), - (0x1D753, "M", "φ"), - (0x1D754, "M", "ρ"), - (0x1D755, "M", "π"), - (0x1D756, "M", "α"), - (0x1D757, "M", "β"), - (0x1D758, "M", "γ"), - (0x1D759, "M", "δ"), - (0x1D75A, "M", "ε"), - (0x1D75B, "M", "ζ"), - (0x1D75C, "M", "η"), - (0x1D75D, "M", "θ"), - (0x1D75E, "M", "ι"), - (0x1D75F, "M", "κ"), - (0x1D760, "M", "λ"), - (0x1D761, "M", "μ"), - (0x1D762, "M", "ν"), - (0x1D763, "M", "ξ"), - (0x1D764, "M", "ο"), - (0x1D765, "M", "π"), - (0x1D766, "M", "ρ"), - (0x1D767, "M", "θ"), - (0x1D768, "M", "σ"), - (0x1D769, "M", "τ"), - (0x1D76A, "M", "υ"), - (0x1D76B, "M", "φ"), - (0x1D76C, "M", "χ"), - (0x1D76D, "M", "ψ"), - (0x1D76E, "M", "ω"), - (0x1D76F, "M", "∇"), - (0x1D770, "M", "α"), - (0x1D771, "M", "β"), - (0x1D772, "M", "γ"), - (0x1D773, "M", "δ"), - (0x1D774, "M", "ε"), - (0x1D775, "M", "ζ"), - (0x1D776, "M", "η"), - (0x1D777, "M", "θ"), - (0x1D778, "M", "ι"), - (0x1D779, "M", "κ"), - (0x1D77A, "M", "λ"), - (0x1D77B, "M", "μ"), - (0x1D77C, "M", "ν"), - (0x1D77D, "M", "ξ"), - (0x1D77E, "M", "ο"), - (0x1D77F, "M", "π"), - (0x1D780, "M", "ρ"), - (0x1D781, "M", "σ"), - (0x1D783, "M", "τ"), - (0x1D784, "M", "υ"), - (0x1D785, "M", "φ"), - (0x1D786, "M", "χ"), - (0x1D787, "M", "ψ"), - (0x1D788, "M", "ω"), - (0x1D789, "M", "∂"), - (0x1D78A, "M", "ε"), - (0x1D78B, "M", "θ"), - (0x1D78C, "M", "κ"), - (0x1D78D, "M", "φ"), - (0x1D78E, "M", "ρ"), - (0x1D78F, "M", "π"), - (0x1D790, "M", "α"), - (0x1D791, "M", "β"), - (0x1D792, "M", "γ"), - (0x1D793, "M", "δ"), - (0x1D794, "M", "ε"), - (0x1D795, "M", "ζ"), - (0x1D796, "M", "η"), - (0x1D797, "M", "θ"), - (0x1D798, "M", "ι"), - (0x1D799, "M", "κ"), - (0x1D79A, "M", "λ"), - (0x1D79B, "M", "μ"), - (0x1D79C, "M", "ν"), - (0x1D79D, "M", "ξ"), - (0x1D79E, "M", "ο"), - (0x1D79F, "M", "π"), - (0x1D7A0, "M", "ρ"), - (0x1D7A1, "M", "θ"), - (0x1D7A2, "M", "σ"), - (0x1D7A3, "M", "τ"), - (0x1D7A4, "M", "υ"), - (0x1D7A5, "M", "φ"), - (0x1D7A6, "M", "χ"), - (0x1D7A7, "M", "ψ"), - (0x1D7A8, "M", "ω"), - (0x1D7A9, "M", "∇"), - (0x1D7AA, "M", "α"), - (0x1D7AB, "M", "β"), - (0x1D7AC, "M", "γ"), - (0x1D7AD, "M", "δ"), - (0x1D7AE, "M", "ε"), - (0x1D7AF, "M", "ζ"), - (0x1D7B0, "M", "η"), - (0x1D7B1, "M", "θ"), - (0x1D7B2, "M", "ι"), - (0x1D7B3, "M", "κ"), - (0x1D7B4, "M", "λ"), - (0x1D7B5, "M", "μ"), - (0x1D7B6, "M", "ν"), - (0x1D7B7, "M", "ξ"), - (0x1D7B8, "M", "ο"), - (0x1D7B9, "M", "π"), - (0x1D7BA, "M", "ρ"), - (0x1D7BB, "M", "σ"), - (0x1D7BD, "M", "τ"), - (0x1D7BE, "M", "υ"), - (0x1D7BF, "M", "φ"), - (0x1D7C0, "M", "χ"), - (0x1D7C1, "M", "ψ"), - (0x1D7C2, "M", "ω"), - (0x1D7C3, "M", "∂"), - (0x1D7C4, "M", "ε"), - (0x1D7C5, "M", "θ"), - (0x1D7C6, "M", "κ"), - (0x1D7C7, "M", "φ"), - (0x1D7C8, "M", "ρ"), - (0x1D7C9, "M", "π"), - (0x1D7CA, "M", "ϝ"), - (0x1D7CC, "X"), - (0x1D7CE, "M", "0"), - (0x1D7CF, "M", "1"), - (0x1D7D0, "M", "2"), - (0x1D7D1, "M", "3"), - (0x1D7D2, "M", "4"), - (0x1D7D3, "M", "5"), - (0x1D7D4, "M", "6"), - (0x1D7D5, "M", "7"), - (0x1D7D6, "M", "8"), - (0x1D7D7, "M", "9"), - (0x1D7D8, "M", "0"), - (0x1D7D9, "M", "1"), - (0x1D7DA, "M", "2"), - (0x1D7DB, "M", "3"), - (0x1D7DC, "M", "4"), - (0x1D7DD, "M", "5"), - (0x1D7DE, "M", "6"), - (0x1D7DF, "M", "7"), - (0x1D7E0, "M", "8"), - (0x1D7E1, "M", "9"), - (0x1D7E2, "M", "0"), - (0x1D7E3, "M", "1"), - (0x1D7E4, "M", "2"), - (0x1D7E5, "M", "3"), - (0x1D7E6, "M", "4"), - (0x1D7E7, "M", "5"), - (0x1D7E8, "M", "6"), - (0x1D7E9, "M", "7"), - (0x1D7EA, "M", "8"), - (0x1D7EB, "M", "9"), - (0x1D7EC, "M", "0"), - (0x1D7ED, "M", "1"), - (0x1D7EE, "M", "2"), - (0x1D7EF, "M", "3"), - (0x1D7F0, "M", "4"), - (0x1D7F1, "M", "5"), - (0x1D7F2, "M", "6"), - (0x1D7F3, "M", "7"), - (0x1D7F4, "M", "8"), - (0x1D7F5, "M", "9"), - (0x1D7F6, "M", "0"), - (0x1D7F7, "M", "1"), - (0x1D7F8, "M", "2"), - (0x1D7F9, "M", "3"), - (0x1D7FA, "M", "4"), - (0x1D7FB, "M", "5"), - (0x1D7FC, "M", "6"), - (0x1D7FD, "M", "7"), - (0x1D7FE, "M", "8"), - (0x1D7FF, "M", "9"), - (0x1D800, "V"), - (0x1DA8C, "X"), - (0x1DA9B, "V"), - (0x1DAA0, "X"), - (0x1DAA1, "V"), - (0x1DAB0, "X"), - (0x1DF00, "V"), - (0x1DF1F, "X"), - (0x1DF25, "V"), - (0x1DF2B, "X"), - (0x1E000, "V"), - (0x1E007, "X"), - (0x1E008, "V"), - (0x1E019, "X"), - (0x1E01B, "V"), - (0x1E022, "X"), - (0x1E023, "V"), - (0x1E025, "X"), - (0x1E026, "V"), - (0x1E02B, "X"), - (0x1E030, "M", "а"), - (0x1E031, "M", "б"), - (0x1E032, "M", "в"), - (0x1E033, "M", "г"), - (0x1E034, "M", "д"), - (0x1E035, "M", "е"), - (0x1E036, "M", "ж"), - (0x1E037, "M", "з"), - (0x1E038, "M", "и"), - (0x1E039, "M", "к"), - (0x1E03A, "M", "л"), - (0x1E03B, "M", "м"), - (0x1E03C, "M", "о"), - (0x1E03D, "M", "п"), - (0x1E03E, "M", "р"), - (0x1E03F, "M", "с"), - (0x1E040, "M", "т"), - (0x1E041, "M", "у"), - (0x1E042, "M", "ф"), - (0x1E043, "M", "х"), - (0x1E044, "M", "ц"), - (0x1E045, "M", "ч"), - (0x1E046, "M", "ш"), - (0x1E047, "M", "ы"), - (0x1E048, "M", "э"), - (0x1E049, "M", "ю"), - (0x1E04A, "M", "ꚉ"), - (0x1E04B, "M", "ә"), - (0x1E04C, "M", "і"), - (0x1E04D, "M", "ј"), - (0x1E04E, "M", "ө"), - (0x1E04F, "M", "ү"), - (0x1E050, "M", "ӏ"), - (0x1E051, "M", "а"), - (0x1E052, "M", "б"), - (0x1E053, "M", "в"), - (0x1E054, "M", "г"), - (0x1E055, "M", "д"), - (0x1E056, "M", "е"), - (0x1E057, "M", "ж"), - (0x1E058, "M", "з"), - (0x1E059, "M", "и"), - (0x1E05A, "M", "к"), - (0x1E05B, "M", "л"), - (0x1E05C, "M", "о"), - (0x1E05D, "M", "п"), - (0x1E05E, "M", "с"), - (0x1E05F, "M", "у"), - (0x1E060, "M", "ф"), - (0x1E061, "M", "х"), - (0x1E062, "M", "ц"), - (0x1E063, "M", "ч"), - (0x1E064, "M", "ш"), - (0x1E065, "M", "ъ"), - (0x1E066, "M", "ы"), - (0x1E067, "M", "ґ"), - (0x1E068, "M", "і"), - (0x1E069, "M", "ѕ"), - (0x1E06A, "M", "џ"), - (0x1E06B, "M", "ҫ"), - (0x1E06C, "M", "ꙑ"), - (0x1E06D, "M", "ұ"), - (0x1E06E, "X"), - (0x1E08F, "V"), - (0x1E090, "X"), - (0x1E100, "V"), - (0x1E12D, "X"), - (0x1E130, "V"), - (0x1E13E, "X"), - (0x1E140, "V"), - (0x1E14A, "X"), - (0x1E14E, "V"), - (0x1E150, "X"), - (0x1E290, "V"), - (0x1E2AF, "X"), - (0x1E2C0, "V"), - (0x1E2FA, "X"), - (0x1E2FF, "V"), - (0x1E300, "X"), - (0x1E4D0, "V"), - (0x1E4FA, "X"), - (0x1E5D0, "V"), - (0x1E5FB, "X"), - (0x1E5FF, "V"), - (0x1E600, "X"), - (0x1E6C0, "V"), - (0x1E6DF, "X"), - (0x1E6E0, "V"), - (0x1E6F6, "X"), - (0x1E6FE, "V"), - (0x1E700, "X"), - (0x1E7E0, "V"), - (0x1E7E7, "X"), - (0x1E7E8, "V"), - (0x1E7EC, "X"), - (0x1E7ED, "V"), - (0x1E7EF, "X"), - (0x1E7F0, "V"), - (0x1E7FF, "X"), - (0x1E800, "V"), - (0x1E8C5, "X"), - (0x1E8C7, "V"), - (0x1E8D7, "X"), - (0x1E900, "M", "𞤢"), - (0x1E901, "M", "𞤣"), - (0x1E902, "M", "𞤤"), - (0x1E903, "M", "𞤥"), - (0x1E904, "M", "𞤦"), - (0x1E905, "M", "𞤧"), - (0x1E906, "M", "𞤨"), - (0x1E907, "M", "𞤩"), - (0x1E908, "M", "𞤪"), - (0x1E909, "M", "𞤫"), - (0x1E90A, "M", "𞤬"), - (0x1E90B, "M", "𞤭"), - (0x1E90C, "M", "𞤮"), - (0x1E90D, "M", "𞤯"), - (0x1E90E, "M", "𞤰"), - (0x1E90F, "M", "𞤱"), - (0x1E910, "M", "𞤲"), - (0x1E911, "M", "𞤳"), - (0x1E912, "M", "𞤴"), - (0x1E913, "M", "𞤵"), - (0x1E914, "M", "𞤶"), - (0x1E915, "M", "𞤷"), - (0x1E916, "M", "𞤸"), - (0x1E917, "M", "𞤹"), - (0x1E918, "M", "𞤺"), - (0x1E919, "M", "𞤻"), - (0x1E91A, "M", "𞤼"), - (0x1E91B, "M", "𞤽"), - (0x1E91C, "M", "𞤾"), - (0x1E91D, "M", "𞤿"), - (0x1E91E, "M", "𞥀"), - (0x1E91F, "M", "𞥁"), - (0x1E920, "M", "𞥂"), - (0x1E921, "M", "𞥃"), - (0x1E922, "V"), - (0x1E94C, "X"), - (0x1E950, "V"), - (0x1E95A, "X"), - (0x1E95E, "V"), - (0x1E960, "X"), - (0x1EC71, "V"), - (0x1ECB5, "X"), - (0x1ED01, "V"), - (0x1ED3E, "X"), - (0x1EE00, "M", "ا"), - (0x1EE01, "M", "ب"), - (0x1EE02, "M", "ج"), - (0x1EE03, "M", "د"), - (0x1EE04, "X"), - (0x1EE05, "M", "و"), - (0x1EE06, "M", "ز"), - (0x1EE07, "M", "ح"), - (0x1EE08, "M", "ط"), - (0x1EE09, "M", "ي"), - (0x1EE0A, "M", "ك"), - (0x1EE0B, "M", "ل"), - (0x1EE0C, "M", "م"), - (0x1EE0D, "M", "ن"), - (0x1EE0E, "M", "س"), - (0x1EE0F, "M", "ع"), - (0x1EE10, "M", "ف"), - (0x1EE11, "M", "ص"), - (0x1EE12, "M", "ق"), - (0x1EE13, "M", "ر"), - (0x1EE14, "M", "ش"), - (0x1EE15, "M", "ت"), - (0x1EE16, "M", "ث"), - (0x1EE17, "M", "خ"), - (0x1EE18, "M", "ذ"), - (0x1EE19, "M", "ض"), - (0x1EE1A, "M", "ظ"), - (0x1EE1B, "M", "غ"), - (0x1EE1C, "M", "ٮ"), - (0x1EE1D, "M", "ں"), - (0x1EE1E, "M", "ڡ"), - (0x1EE1F, "M", "ٯ"), - (0x1EE20, "X"), - (0x1EE21, "M", "ب"), - (0x1EE22, "M", "ج"), - (0x1EE23, "X"), - (0x1EE24, "M", "ه"), - (0x1EE25, "X"), - (0x1EE27, "M", "ح"), - (0x1EE28, "X"), - (0x1EE29, "M", "ي"), - (0x1EE2A, "M", "ك"), - (0x1EE2B, "M", "ل"), - (0x1EE2C, "M", "م"), - (0x1EE2D, "M", "ن"), - (0x1EE2E, "M", "س"), - (0x1EE2F, "M", "ع"), - (0x1EE30, "M", "ف"), - (0x1EE31, "M", "ص"), - (0x1EE32, "M", "ق"), - (0x1EE33, "X"), - (0x1EE34, "M", "ش"), - (0x1EE35, "M", "ت"), - (0x1EE36, "M", "ث"), - (0x1EE37, "M", "خ"), - (0x1EE38, "X"), - (0x1EE39, "M", "ض"), - (0x1EE3A, "X"), - (0x1EE3B, "M", "غ"), - (0x1EE3C, "X"), - (0x1EE42, "M", "ج"), - (0x1EE43, "X"), - (0x1EE47, "M", "ح"), - (0x1EE48, "X"), - (0x1EE49, "M", "ي"), - (0x1EE4A, "X"), - (0x1EE4B, "M", "ل"), - (0x1EE4C, "X"), - (0x1EE4D, "M", "ن"), - (0x1EE4E, "M", "س"), - (0x1EE4F, "M", "ع"), - (0x1EE50, "X"), - (0x1EE51, "M", "ص"), - (0x1EE52, "M", "ق"), - (0x1EE53, "X"), - (0x1EE54, "M", "ش"), - (0x1EE55, "X"), - (0x1EE57, "M", "خ"), - (0x1EE58, "X"), - (0x1EE59, "M", "ض"), - (0x1EE5A, "X"), - (0x1EE5B, "M", "غ"), - (0x1EE5C, "X"), - (0x1EE5D, "M", "ں"), - (0x1EE5E, "X"), - (0x1EE5F, "M", "ٯ"), - (0x1EE60, "X"), - (0x1EE61, "M", "ب"), - (0x1EE62, "M", "ج"), - (0x1EE63, "X"), - (0x1EE64, "M", "ه"), - (0x1EE65, "X"), - (0x1EE67, "M", "ح"), - (0x1EE68, "M", "ط"), - (0x1EE69, "M", "ي"), - (0x1EE6A, "M", "ك"), - (0x1EE6B, "X"), - (0x1EE6C, "M", "م"), - (0x1EE6D, "M", "ن"), - (0x1EE6E, "M", "س"), - (0x1EE6F, "M", "ع"), - (0x1EE70, "M", "ف"), - (0x1EE71, "M", "ص"), - (0x1EE72, "M", "ق"), - (0x1EE73, "X"), - (0x1EE74, "M", "ش"), - (0x1EE75, "M", "ت"), - (0x1EE76, "M", "ث"), - (0x1EE77, "M", "خ"), - (0x1EE78, "X"), - (0x1EE79, "M", "ض"), - (0x1EE7A, "M", "ظ"), - (0x1EE7B, "M", "غ"), - (0x1EE7C, "M", "ٮ"), - (0x1EE7D, "X"), - (0x1EE7E, "M", "ڡ"), - (0x1EE7F, "X"), - (0x1EE80, "M", "ا"), - (0x1EE81, "M", "ب"), - (0x1EE82, "M", "ج"), - (0x1EE83, "M", "د"), - (0x1EE84, "M", "ه"), - (0x1EE85, "M", "و"), - (0x1EE86, "M", "ز"), - (0x1EE87, "M", "ح"), - (0x1EE88, "M", "ط"), - (0x1EE89, "M", "ي"), - (0x1EE8A, "X"), - (0x1EE8B, "M", "ل"), - (0x1EE8C, "M", "م"), - (0x1EE8D, "M", "ن"), - (0x1EE8E, "M", "س"), - (0x1EE8F, "M", "ع"), - (0x1EE90, "M", "ف"), - (0x1EE91, "M", "ص"), - (0x1EE92, "M", "ق"), - (0x1EE93, "M", "ر"), - (0x1EE94, "M", "ش"), - (0x1EE95, "M", "ت"), - (0x1EE96, "M", "ث"), - (0x1EE97, "M", "خ"), - (0x1EE98, "M", "ذ"), - (0x1EE99, "M", "ض"), - (0x1EE9A, "M", "ظ"), - (0x1EE9B, "M", "غ"), - (0x1EE9C, "X"), - (0x1EEA1, "M", "ب"), - (0x1EEA2, "M", "ج"), - (0x1EEA3, "M", "د"), - (0x1EEA4, "X"), - (0x1EEA5, "M", "و"), - (0x1EEA6, "M", "ز"), - (0x1EEA7, "M", "ح"), - (0x1EEA8, "M", "ط"), - (0x1EEA9, "M", "ي"), - (0x1EEAA, "X"), - (0x1EEAB, "M", "ل"), - (0x1EEAC, "M", "م"), - (0x1EEAD, "M", "ن"), - (0x1EEAE, "M", "س"), - (0x1EEAF, "M", "ع"), - (0x1EEB0, "M", "ف"), - (0x1EEB1, "M", "ص"), - (0x1EEB2, "M", "ق"), - (0x1EEB3, "M", "ر"), - (0x1EEB4, "M", "ش"), - (0x1EEB5, "M", "ت"), - (0x1EEB6, "M", "ث"), - (0x1EEB7, "M", "خ"), - (0x1EEB8, "M", "ذ"), - (0x1EEB9, "M", "ض"), - (0x1EEBA, "M", "ظ"), - (0x1EEBB, "M", "غ"), - (0x1EEBC, "X"), - (0x1EEF0, "V"), - (0x1EEF2, "X"), - (0x1F000, "V"), - (0x1F02C, "X"), - (0x1F030, "V"), - (0x1F094, "X"), - (0x1F0A0, "V"), - (0x1F0AF, "X"), - (0x1F0B1, "V"), - (0x1F0C0, "X"), - (0x1F0C1, "V"), - (0x1F0D0, "X"), - (0x1F0D1, "V"), - (0x1F0F6, "X"), - (0x1F101, "M", "0,"), - (0x1F102, "M", "1,"), - (0x1F103, "M", "2,"), - (0x1F104, "M", "3,"), - (0x1F105, "M", "4,"), - (0x1F106, "M", "5,"), - (0x1F107, "M", "6,"), - (0x1F108, "M", "7,"), - (0x1F109, "M", "8,"), - (0x1F10A, "M", "9,"), - (0x1F10B, "V"), - (0x1F110, "M", "(a)"), - (0x1F111, "M", "(b)"), - (0x1F112, "M", "(c)"), - (0x1F113, "M", "(d)"), - (0x1F114, "M", "(e)"), - (0x1F115, "M", "(f)"), - (0x1F116, "M", "(g)"), - (0x1F117, "M", "(h)"), - (0x1F118, "M", "(i)"), - (0x1F119, "M", "(j)"), - (0x1F11A, "M", "(k)"), - (0x1F11B, "M", "(l)"), - (0x1F11C, "M", "(m)"), - (0x1F11D, "M", "(n)"), - (0x1F11E, "M", "(o)"), - (0x1F11F, "M", "(p)"), - (0x1F120, "M", "(q)"), - (0x1F121, "M", "(r)"), - (0x1F122, "M", "(s)"), - (0x1F123, "M", "(t)"), - (0x1F124, "M", "(u)"), - (0x1F125, "M", "(v)"), - (0x1F126, "M", "(w)"), - (0x1F127, "M", "(x)"), - (0x1F128, "M", "(y)"), - (0x1F129, "M", "(z)"), - (0x1F12A, "M", "〔s〕"), - (0x1F12B, "M", "c"), - (0x1F12C, "M", "r"), - (0x1F12D, "M", "cd"), - (0x1F12E, "M", "wz"), - (0x1F12F, "V"), - (0x1F130, "M", "a"), - (0x1F131, "M", "b"), - (0x1F132, "M", "c"), - (0x1F133, "M", "d"), - (0x1F134, "M", "e"), - (0x1F135, "M", "f"), - (0x1F136, "M", "g"), - (0x1F137, "M", "h"), - (0x1F138, "M", "i"), - (0x1F139, "M", "j"), - (0x1F13A, "M", "k"), - (0x1F13B, "M", "l"), - (0x1F13C, "M", "m"), - (0x1F13D, "M", "n"), - (0x1F13E, "M", "o"), - (0x1F13F, "M", "p"), - (0x1F140, "M", "q"), - (0x1F141, "M", "r"), - (0x1F142, "M", "s"), - (0x1F143, "M", "t"), - (0x1F144, "M", "u"), - (0x1F145, "M", "v"), - (0x1F146, "M", "w"), - (0x1F147, "M", "x"), - (0x1F148, "M", "y"), - (0x1F149, "M", "z"), - (0x1F14A, "M", "hv"), - (0x1F14B, "M", "mv"), - (0x1F14C, "M", "sd"), - (0x1F14D, "M", "ss"), - (0x1F14E, "M", "ppv"), - (0x1F14F, "M", "wc"), - (0x1F150, "V"), - (0x1F16A, "M", "mc"), - (0x1F16B, "M", "md"), - (0x1F16C, "M", "mr"), - (0x1F16D, "V"), - (0x1F190, "M", "dj"), - (0x1F191, "V"), - (0x1F1AE, "X"), - (0x1F1E6, "V"), - (0x1F200, "M", "ほか"), - (0x1F201, "M", "ココ"), - (0x1F202, "M", "サ"), - (0x1F203, "X"), - (0x1F210, "M", "手"), - (0x1F211, "M", "字"), - (0x1F212, "M", "双"), - (0x1F213, "M", "デ"), - (0x1F214, "M", "二"), - (0x1F215, "M", "多"), - (0x1F216, "M", "解"), - (0x1F217, "M", "天"), - (0x1F218, "M", "交"), - (0x1F219, "M", "映"), - (0x1F21A, "M", "無"), - (0x1F21B, "M", "料"), - (0x1F21C, "M", "前"), - (0x1F21D, "M", "後"), - (0x1F21E, "M", "再"), - (0x1F21F, "M", "新"), - (0x1F220, "M", "初"), - (0x1F221, "M", "終"), - (0x1F222, "M", "生"), - (0x1F223, "M", "販"), - (0x1F224, "M", "声"), - (0x1F225, "M", "吹"), - (0x1F226, "M", "演"), - (0x1F227, "M", "投"), - (0x1F228, "M", "捕"), - (0x1F229, "M", "一"), - (0x1F22A, "M", "三"), - (0x1F22B, "M", "遊"), - (0x1F22C, "M", "左"), - (0x1F22D, "M", "中"), - (0x1F22E, "M", "右"), - (0x1F22F, "M", "指"), - (0x1F230, "M", "走"), - (0x1F231, "M", "打"), - (0x1F232, "M", "禁"), - (0x1F233, "M", "空"), - (0x1F234, "M", "合"), - (0x1F235, "M", "満"), - (0x1F236, "M", "有"), - (0x1F237, "M", "月"), - (0x1F238, "M", "申"), - (0x1F239, "M", "割"), - (0x1F23A, "M", "営"), - (0x1F23B, "M", "配"), - (0x1F23C, "X"), - (0x1F240, "M", "〔本〕"), - (0x1F241, "M", "〔三〕"), - (0x1F242, "M", "〔二〕"), - (0x1F243, "M", "〔安〕"), - (0x1F244, "M", "〔点〕"), - (0x1F245, "M", "〔打〕"), - (0x1F246, "M", "〔盗〕"), - (0x1F247, "M", "〔勝〕"), - (0x1F248, "M", "〔敗〕"), - (0x1F249, "X"), - (0x1F250, "M", "得"), - (0x1F251, "M", "可"), - (0x1F252, "X"), - (0x1F260, "V"), - (0x1F266, "X"), - (0x1F300, "V"), - (0x1F6D9, "X"), - (0x1F6DC, "V"), - (0x1F6ED, "X"), - (0x1F6F0, "V"), - (0x1F6FD, "X"), - (0x1F700, "V"), - (0x1F7DA, "X"), - (0x1F7E0, "V"), - (0x1F7EC, "X"), - (0x1F7F0, "V"), - (0x1F7F1, "X"), - (0x1F800, "V"), - (0x1F80C, "X"), - (0x1F810, "V"), - (0x1F848, "X"), - (0x1F850, "V"), - (0x1F85A, "X"), - (0x1F860, "V"), - (0x1F888, "X"), - (0x1F890, "V"), - (0x1F8AE, "X"), - (0x1F8B0, "V"), - (0x1F8BC, "X"), - (0x1F8C0, "V"), - (0x1F8C2, "X"), - (0x1F8D0, "V"), - (0x1F8D9, "X"), - (0x1F900, "V"), - (0x1FA58, "X"), - (0x1FA60, "V"), - (0x1FA6E, "X"), - (0x1FA70, "V"), - (0x1FA7D, "X"), - (0x1FA80, "V"), - (0x1FA8B, "X"), - (0x1FA8E, "V"), - (0x1FAC7, "X"), - (0x1FAC8, "V"), - (0x1FAC9, "X"), - (0x1FACD, "V"), - (0x1FADD, "X"), - (0x1FADF, "V"), - (0x1FAEB, "X"), - (0x1FAEF, "V"), - (0x1FAF9, "X"), - (0x1FB00, "V"), - (0x1FB93, "X"), - (0x1FB94, "V"), - (0x1FBF0, "M", "0"), - (0x1FBF1, "M", "1"), - (0x1FBF2, "M", "2"), - (0x1FBF3, "M", "3"), - (0x1FBF4, "M", "4"), - (0x1FBF5, "M", "5"), - (0x1FBF6, "M", "6"), - (0x1FBF7, "M", "7"), - (0x1FBF8, "M", "8"), - (0x1FBF9, "M", "9"), - (0x1FBFA, "V"), - (0x1FBFB, "X"), - (0x20000, "V"), - (0x2A6E0, "X"), - (0x2A700, "V"), - (0x2B81E, "X"), - (0x2B820, "V"), - (0x2CEAE, "X"), - (0x2CEB0, "V"), - (0x2EBE1, "X"), - (0x2EBF0, "V"), - (0x2EE5E, "X"), - (0x2F800, "M", "丽"), - (0x2F801, "M", "丸"), - (0x2F802, "M", "乁"), - (0x2F803, "M", "𠄢"), - (0x2F804, "M", "你"), - (0x2F805, "M", "侮"), - (0x2F806, "M", "侻"), - (0x2F807, "M", "倂"), - (0x2F808, "M", "偺"), - (0x2F809, "M", "備"), - (0x2F80A, "M", "僧"), - (0x2F80B, "M", "像"), - (0x2F80C, "M", "㒞"), - (0x2F80D, "M", "𠘺"), - (0x2F80E, "M", "免"), - (0x2F80F, "M", "兔"), - (0x2F810, "M", "兤"), - (0x2F811, "M", "具"), - (0x2F812, "M", "𠔜"), - (0x2F813, "M", "㒹"), - (0x2F814, "M", "內"), - (0x2F815, "M", "再"), - (0x2F816, "M", "𠕋"), - (0x2F817, "M", "冗"), - (0x2F818, "M", "冤"), - (0x2F819, "M", "仌"), - (0x2F81A, "M", "冬"), - (0x2F81B, "M", "况"), - (0x2F81C, "M", "𩇟"), - (0x2F81D, "M", "凵"), - (0x2F81E, "M", "刃"), - (0x2F81F, "M", "㓟"), - (0x2F820, "M", "刻"), - (0x2F821, "M", "剆"), - (0x2F822, "M", "割"), - (0x2F823, "M", "剷"), - (0x2F824, "M", "㔕"), - (0x2F825, "M", "勇"), - (0x2F826, "M", "勉"), - (0x2F827, "M", "勤"), - (0x2F828, "M", "勺"), - (0x2F829, "M", "包"), - (0x2F82A, "M", "匆"), - (0x2F82B, "M", "北"), - (0x2F82C, "M", "卉"), - (0x2F82D, "M", "卑"), - (0x2F82E, "M", "博"), - (0x2F82F, "M", "即"), - (0x2F830, "M", "卽"), - (0x2F831, "M", "卿"), - (0x2F834, "M", "𠨬"), - (0x2F835, "M", "灰"), - (0x2F836, "M", "及"), - (0x2F837, "M", "叟"), - (0x2F838, "M", "𠭣"), - (0x2F839, "M", "叫"), - (0x2F83A, "M", "叱"), - (0x2F83B, "M", "吆"), - (0x2F83C, "M", "咞"), - (0x2F83D, "M", "吸"), - (0x2F83E, "M", "呈"), - (0x2F83F, "M", "周"), - (0x2F840, "M", "咢"), - (0x2F841, "M", "哶"), - (0x2F842, "M", "唐"), - (0x2F843, "M", "啓"), - (0x2F844, "M", "啣"), - (0x2F845, "M", "善"), - (0x2F847, "M", "喙"), - (0x2F848, "M", "喫"), - (0x2F849, "M", "喳"), - (0x2F84A, "M", "嗂"), - (0x2F84B, "M", "圖"), - (0x2F84C, "M", "嘆"), - (0x2F84D, "M", "圗"), - (0x2F84E, "M", "噑"), - (0x2F84F, "M", "噴"), - (0x2F850, "M", "切"), - (0x2F851, "M", "壮"), - (0x2F852, "M", "城"), - (0x2F853, "M", "埴"), - (0x2F854, "M", "堍"), - (0x2F855, "M", "型"), - (0x2F856, "M", "堲"), - (0x2F857, "M", "報"), - (0x2F858, "M", "墬"), - (0x2F859, "M", "𡓤"), - (0x2F85A, "M", "売"), - (0x2F85B, "M", "壷"), - (0x2F85C, "M", "夆"), - (0x2F85D, "M", "多"), - (0x2F85E, "M", "夢"), - (0x2F85F, "M", "奢"), - (0x2F860, "M", "𡚨"), - (0x2F861, "M", "𡛪"), - (0x2F862, "M", "姬"), - (0x2F863, "M", "娛"), - (0x2F864, "M", "娧"), - (0x2F865, "M", "姘"), - (0x2F866, "M", "婦"), - (0x2F867, "M", "㛮"), - (0x2F868, "M", "㛼"), - (0x2F869, "M", "嬈"), - (0x2F86A, "M", "嬾"), - (0x2F86C, "M", "𡧈"), - (0x2F86D, "M", "寃"), - (0x2F86E, "M", "寘"), - (0x2F86F, "M", "寧"), - (0x2F870, "M", "寳"), - (0x2F871, "M", "𡬘"), - (0x2F872, "M", "寿"), - (0x2F873, "M", "将"), - (0x2F874, "M", "当"), - (0x2F875, "M", "尢"), - (0x2F876, "M", "㞁"), - (0x2F877, "M", "屠"), - (0x2F878, "M", "屮"), - (0x2F879, "M", "峀"), - (0x2F87A, "M", "岍"), - (0x2F87B, "M", "𡷤"), - (0x2F87C, "M", "嵃"), - (0x2F87D, "M", "𡷦"), - (0x2F87E, "M", "嵮"), - (0x2F87F, "M", "嵫"), - (0x2F880, "M", "嵼"), - (0x2F881, "M", "巡"), - (0x2F882, "M", "巢"), - (0x2F883, "M", "㠯"), - (0x2F884, "M", "巽"), - (0x2F885, "M", "帨"), - (0x2F886, "M", "帽"), - (0x2F887, "M", "幩"), - (0x2F888, "M", "㡢"), - (0x2F889, "M", "𢆃"), - (0x2F88A, "M", "㡼"), - (0x2F88B, "M", "庰"), - (0x2F88C, "M", "庳"), - (0x2F88D, "M", "庶"), - (0x2F88E, "M", "廊"), - (0x2F88F, "M", "𪎒"), - (0x2F890, "M", "廾"), - (0x2F891, "M", "𢌱"), - (0x2F893, "M", "舁"), - (0x2F894, "M", "弢"), - (0x2F896, "M", "㣇"), - (0x2F897, "M", "𣊸"), - (0x2F898, "M", "𦇚"), - (0x2F899, "M", "形"), - (0x2F89A, "M", "彫"), - (0x2F89B, "M", "㣣"), - (0x2F89C, "M", "徚"), - (0x2F89D, "M", "忍"), - (0x2F89E, "M", "志"), - (0x2F89F, "M", "忹"), - (0x2F8A0, "M", "悁"), - (0x2F8A1, "M", "㤺"), - (0x2F8A2, "M", "㤜"), - (0x2F8A3, "M", "悔"), - (0x2F8A4, "M", "𢛔"), - (0x2F8A5, "M", "惇"), - (0x2F8A6, "M", "慈"), - (0x2F8A7, "M", "慌"), - (0x2F8A8, "M", "慎"), - (0x2F8A9, "M", "慌"), - (0x2F8AA, "M", "慺"), - (0x2F8AB, "M", "憎"), - (0x2F8AC, "M", "憲"), - (0x2F8AD, "M", "憤"), - (0x2F8AE, "M", "憯"), - (0x2F8AF, "M", "懞"), - (0x2F8B0, "M", "懲"), - (0x2F8B1, "M", "懶"), - (0x2F8B2, "M", "成"), - (0x2F8B3, "M", "戛"), - (0x2F8B4, "M", "扝"), - (0x2F8B5, "M", "抱"), - (0x2F8B6, "M", "拔"), - (0x2F8B7, "M", "捐"), - (0x2F8B8, "M", "𢬌"), - (0x2F8B9, "M", "挽"), - (0x2F8BA, "M", "拼"), - (0x2F8BB, "M", "捨"), - (0x2F8BC, "M", "掃"), - (0x2F8BD, "M", "揤"), - (0x2F8BE, "M", "𢯱"), - (0x2F8BF, "M", "搢"), - (0x2F8C0, "M", "揅"), - (0x2F8C1, "M", "掩"), - (0x2F8C2, "M", "㨮"), - (0x2F8C3, "M", "摩"), - (0x2F8C4, "M", "摾"), - (0x2F8C5, "M", "撝"), - (0x2F8C6, "M", "摷"), - (0x2F8C7, "M", "㩬"), - (0x2F8C8, "M", "敏"), - (0x2F8C9, "M", "敬"), - (0x2F8CA, "M", "𣀊"), - (0x2F8CB, "M", "旣"), - (0x2F8CC, "M", "書"), - (0x2F8CD, "M", "晉"), - (0x2F8CE, "M", "㬙"), - (0x2F8CF, "M", "暑"), - (0x2F8D0, "M", "㬈"), - (0x2F8D1, "M", "㫤"), - (0x2F8D2, "M", "冒"), - (0x2F8D3, "M", "冕"), - (0x2F8D4, "M", "最"), - (0x2F8D5, "M", "暜"), - (0x2F8D6, "M", "肭"), - (0x2F8D7, "M", "䏙"), - (0x2F8D8, "M", "朗"), - (0x2F8D9, "M", "望"), - (0x2F8DA, "M", "朡"), - (0x2F8DB, "M", "杞"), - (0x2F8DC, "M", "杓"), - (0x2F8DD, "M", "𣏃"), - (0x2F8DE, "M", "㭉"), - (0x2F8DF, "M", "柺"), - (0x2F8E0, "M", "枅"), - (0x2F8E1, "M", "桒"), - (0x2F8E2, "M", "梅"), - (0x2F8E3, "M", "𣑭"), - (0x2F8E4, "M", "梎"), - (0x2F8E5, "M", "栟"), - (0x2F8E6, "M", "椔"), - (0x2F8E7, "M", "㮝"), - (0x2F8E8, "M", "楂"), - (0x2F8E9, "M", "榣"), - (0x2F8EA, "M", "槪"), - (0x2F8EB, "M", "檨"), - (0x2F8EC, "M", "𣚣"), - (0x2F8ED, "M", "櫛"), - (0x2F8EE, "M", "㰘"), - (0x2F8EF, "M", "次"), - (0x2F8F0, "M", "𣢧"), - (0x2F8F1, "M", "歔"), - (0x2F8F2, "M", "㱎"), - (0x2F8F3, "M", "歲"), - (0x2F8F4, "M", "殟"), - (0x2F8F5, "M", "殺"), - (0x2F8F6, "M", "殻"), - (0x2F8F7, "M", "𣪍"), - (0x2F8F8, "M", "𡴋"), - (0x2F8F9, "M", "𣫺"), - (0x2F8FA, "M", "汎"), - (0x2F8FB, "M", "𣲼"), - (0x2F8FC, "M", "沿"), - (0x2F8FD, "M", "泍"), - (0x2F8FE, "M", "汧"), - (0x2F8FF, "M", "洖"), - (0x2F900, "M", "派"), - (0x2F901, "M", "海"), - (0x2F902, "M", "流"), - (0x2F903, "M", "浩"), - (0x2F904, "M", "浸"), - (0x2F905, "M", "涅"), - (0x2F906, "M", "𣴞"), - (0x2F907, "M", "洴"), - (0x2F908, "M", "港"), - (0x2F909, "M", "湮"), - (0x2F90A, "M", "㴳"), - (0x2F90B, "M", "滋"), - (0x2F90C, "M", "滇"), - (0x2F90D, "M", "𣻑"), - (0x2F90E, "M", "淹"), - (0x2F90F, "M", "潮"), - (0x2F910, "M", "𣽞"), - (0x2F911, "M", "𣾎"), - (0x2F912, "M", "濆"), - (0x2F913, "M", "瀹"), - (0x2F914, "M", "瀞"), - (0x2F915, "M", "瀛"), - (0x2F916, "M", "㶖"), - (0x2F917, "M", "灊"), - (0x2F918, "M", "災"), - (0x2F919, "M", "灷"), - (0x2F91A, "M", "炭"), - (0x2F91B, "M", "𠔥"), - (0x2F91C, "M", "煅"), - (0x2F91D, "M", "𤉣"), - (0x2F91E, "M", "熜"), - (0x2F91F, "M", "𤎫"), - (0x2F920, "M", "爨"), - (0x2F921, "M", "爵"), - (0x2F922, "M", "牐"), - (0x2F923, "M", "𤘈"), - (0x2F924, "M", "犀"), - (0x2F925, "M", "犕"), - (0x2F926, "M", "𤜵"), - (0x2F927, "M", "𤠔"), - (0x2F928, "M", "獺"), - (0x2F929, "M", "王"), - (0x2F92A, "M", "㺬"), - (0x2F92B, "M", "玥"), - (0x2F92C, "M", "㺸"), - (0x2F92E, "M", "瑇"), - (0x2F92F, "M", "瑜"), - (0x2F930, "M", "瑱"), - (0x2F931, "M", "璅"), - (0x2F932, "M", "瓊"), - (0x2F933, "M", "㼛"), - (0x2F934, "M", "甤"), - (0x2F935, "M", "𤰶"), - (0x2F936, "M", "甾"), - (0x2F937, "M", "𤲒"), - (0x2F938, "M", "異"), - (0x2F939, "M", "𢆟"), - (0x2F93A, "M", "瘐"), - (0x2F93B, "M", "𤾡"), - (0x2F93C, "M", "𤾸"), - (0x2F93D, "M", "𥁄"), - (0x2F93E, "M", "㿼"), - (0x2F93F, "M", "䀈"), - (0x2F940, "M", "直"), - (0x2F941, "M", "𥃳"), - (0x2F942, "M", "𥃲"), - (0x2F943, "M", "𥄙"), - (0x2F944, "M", "𥄳"), - (0x2F945, "M", "眞"), - (0x2F946, "M", "真"), - (0x2F948, "M", "睊"), - (0x2F949, "M", "䀹"), - (0x2F94A, "M", "瞋"), - (0x2F94B, "M", "䁆"), - (0x2F94C, "M", "䂖"), - (0x2F94D, "M", "𥐝"), - (0x2F94E, "M", "硎"), - (0x2F94F, "M", "碌"), - (0x2F950, "M", "磌"), - (0x2F951, "M", "䃣"), - (0x2F952, "M", "𥘦"), - (0x2F953, "M", "祖"), - (0x2F954, "M", "𥚚"), - (0x2F955, "M", "𥛅"), - (0x2F956, "M", "福"), - (0x2F957, "M", "秫"), - (0x2F958, "M", "䄯"), - (0x2F959, "M", "穀"), - (0x2F95A, "M", "穊"), - (0x2F95B, "M", "穏"), - (0x2F95C, "M", "𥥼"), - (0x2F95D, "M", "𥪧"), - (0x2F95F, "M", "竮"), - (0x2F960, "M", "䈂"), - (0x2F961, "M", "𥮫"), - (0x2F962, "M", "篆"), - (0x2F963, "M", "築"), - (0x2F964, "M", "䈧"), - (0x2F965, "M", "𥲀"), - (0x2F966, "M", "糒"), - (0x2F967, "M", "䊠"), - (0x2F968, "M", "糨"), - (0x2F969, "M", "糣"), - (0x2F96A, "M", "紀"), - (0x2F96B, "M", "𥾆"), - (0x2F96C, "M", "絣"), - (0x2F96D, "M", "䌁"), - (0x2F96E, "M", "緇"), - (0x2F96F, "M", "縂"), - (0x2F970, "M", "繅"), - (0x2F971, "M", "䌴"), - (0x2F972, "M", "𦈨"), - (0x2F973, "M", "𦉇"), - (0x2F974, "M", "䍙"), - (0x2F975, "M", "𦋙"), - (0x2F976, "M", "罺"), - (0x2F977, "M", "𦌾"), - (0x2F978, "M", "羕"), - (0x2F979, "M", "翺"), - (0x2F97A, "M", "者"), - (0x2F97B, "M", "𦓚"), - (0x2F97C, "M", "𦔣"), - (0x2F97D, "M", "聠"), - (0x2F97E, "M", "𦖨"), - (0x2F97F, "M", "聰"), - (0x2F980, "M", "𣍟"), - (0x2F981, "M", "䏕"), - (0x2F982, "M", "育"), - (0x2F983, "M", "脃"), - (0x2F984, "M", "䐋"), - (0x2F985, "M", "脾"), - (0x2F986, "M", "媵"), - (0x2F987, "M", "𦞧"), - (0x2F988, "M", "𦞵"), - (0x2F989, "M", "𣎓"), - (0x2F98A, "M", "𣎜"), - (0x2F98B, "M", "舁"), - (0x2F98C, "M", "舄"), - (0x2F98D, "M", "辞"), - (0x2F98E, "M", "䑫"), - (0x2F98F, "M", "芑"), - (0x2F990, "M", "芋"), - (0x2F991, "M", "芝"), - (0x2F992, "M", "劳"), - (0x2F993, "M", "花"), - (0x2F994, "M", "芳"), - (0x2F995, "M", "芽"), - (0x2F996, "M", "苦"), - (0x2F997, "M", "𦬼"), - (0x2F998, "M", "若"), - (0x2F999, "M", "茝"), - (0x2F99A, "M", "荣"), - (0x2F99B, "M", "莭"), - (0x2F99C, "M", "茣"), - (0x2F99D, "M", "莽"), - (0x2F99E, "M", "菧"), - (0x2F99F, "M", "著"), - (0x2F9A0, "M", "荓"), - (0x2F9A1, "M", "菊"), - (0x2F9A2, "M", "菌"), - (0x2F9A3, "M", "菜"), - (0x2F9A4, "M", "𦰶"), - (0x2F9A5, "M", "𦵫"), - (0x2F9A6, "M", "𦳕"), - (0x2F9A7, "M", "䔫"), - (0x2F9A8, "M", "蓱"), - (0x2F9A9, "M", "蓳"), - (0x2F9AA, "M", "蔖"), - (0x2F9AB, "M", "𧏊"), - (0x2F9AC, "M", "蕤"), - (0x2F9AD, "M", "𦼬"), - (0x2F9AE, "M", "䕝"), - (0x2F9AF, "M", "䕡"), - (0x2F9B0, "M", "𦾱"), - (0x2F9B1, "M", "𧃒"), - (0x2F9B2, "M", "䕫"), - (0x2F9B3, "M", "虐"), - (0x2F9B4, "M", "虜"), - (0x2F9B5, "M", "虧"), - (0x2F9B6, "M", "虩"), - (0x2F9B7, "M", "蚩"), - (0x2F9B8, "M", "蚈"), - (0x2F9B9, "M", "蜎"), - (0x2F9BA, "M", "蛢"), - (0x2F9BB, "M", "蝹"), - (0x2F9BC, "M", "蜨"), - (0x2F9BD, "M", "蝫"), - (0x2F9BE, "M", "螆"), - (0x2F9BF, "M", "䗗"), - (0x2F9C0, "M", "蟡"), - (0x2F9C1, "M", "蠁"), - (0x2F9C2, "M", "䗹"), - (0x2F9C3, "M", "衠"), - (0x2F9C4, "M", "衣"), - (0x2F9C5, "M", "𧙧"), - (0x2F9C6, "M", "裗"), - (0x2F9C7, "M", "裞"), - (0x2F9C8, "M", "䘵"), - (0x2F9C9, "M", "裺"), - (0x2F9CA, "M", "㒻"), - (0x2F9CB, "M", "𧢮"), - (0x2F9CC, "M", "𧥦"), - (0x2F9CD, "M", "䚾"), - (0x2F9CE, "M", "䛇"), - (0x2F9CF, "M", "誠"), - (0x2F9D0, "M", "諭"), - (0x2F9D1, "M", "變"), - (0x2F9D2, "M", "豕"), - (0x2F9D3, "M", "𧲨"), - (0x2F9D4, "M", "貫"), - (0x2F9D5, "M", "賁"), - (0x2F9D6, "M", "贛"), - (0x2F9D7, "M", "起"), - (0x2F9D8, "M", "𧼯"), - (0x2F9D9, "M", "𠠄"), - (0x2F9DA, "M", "跋"), - (0x2F9DB, "M", "趼"), - (0x2F9DC, "M", "跰"), - (0x2F9DD, "M", "𠣞"), - (0x2F9DE, "M", "軔"), - (0x2F9DF, "M", "輸"), - (0x2F9E0, "M", "𨗒"), - (0x2F9E1, "M", "𨗭"), - (0x2F9E2, "M", "邔"), - (0x2F9E3, "M", "郱"), - (0x2F9E4, "M", "鄑"), - (0x2F9E5, "M", "𨜮"), - (0x2F9E6, "M", "鄛"), - (0x2F9E7, "M", "鈸"), - (0x2F9E8, "M", "鋗"), - (0x2F9E9, "M", "鋘"), - (0x2F9EA, "M", "鉼"), - (0x2F9EB, "M", "鏹"), - (0x2F9EC, "M", "鐕"), - (0x2F9ED, "M", "𨯺"), - (0x2F9EE, "M", "開"), - (0x2F9EF, "M", "䦕"), - (0x2F9F0, "M", "閷"), - (0x2F9F1, "M", "𨵷"), - (0x2F9F2, "M", "䧦"), - (0x2F9F3, "M", "雃"), - (0x2F9F4, "M", "嶲"), - (0x2F9F5, "M", "霣"), - (0x2F9F6, "M", "𩅅"), - (0x2F9F7, "M", "𩈚"), - (0x2F9F8, "M", "䩮"), - (0x2F9F9, "M", "䩶"), - (0x2F9FA, "M", "韠"), - (0x2F9FB, "M", "𩐊"), - (0x2F9FC, "M", "䪲"), - (0x2F9FD, "M", "𩒖"), - (0x2F9FE, "M", "頋"), - (0x2FA00, "M", "頩"), - (0x2FA01, "M", "𩖶"), - (0x2FA02, "M", "飢"), - (0x2FA03, "M", "䬳"), - (0x2FA04, "M", "餩"), - (0x2FA05, "M", "馧"), - (0x2FA06, "M", "駂"), - (0x2FA07, "M", "駾"), - (0x2FA08, "M", "䯎"), - (0x2FA09, "M", "𩬰"), - (0x2FA0A, "M", "鬒"), - (0x2FA0B, "M", "鱀"), - (0x2FA0C, "M", "鳽"), - (0x2FA0D, "M", "䳎"), - (0x2FA0E, "M", "䳭"), - (0x2FA0F, "M", "鵧"), - (0x2FA10, "M", "𪃎"), - (0x2FA11, "M", "䳸"), - (0x2FA12, "M", "𪄅"), - (0x2FA13, "M", "𪈎"), - (0x2FA14, "M", "𪊑"), - (0x2FA15, "M", "麻"), - (0x2FA16, "M", "䵖"), - (0x2FA17, "M", "黹"), - (0x2FA18, "M", "黾"), - (0x2FA19, "M", "鼅"), - (0x2FA1A, "M", "鼏"), - (0x2FA1B, "M", "鼖"), - (0x2FA1C, "M", "鼻"), - (0x2FA1D, "M", "𪘀"), - (0x2FA1E, "X"), - (0x30000, "V"), - (0x3134B, "X"), - (0x31350, "V"), - (0x3347A, "X"), - (0xE0100, "I"), - (0xE01F0, "X"), -) diff --git a/venv/lib/python3.9/site-packages/importlib_metadata-8.7.1.dist-info/INSTALLER b/venv/lib/python3.9/site-packages/importlib_metadata-8.7.1.dist-info/INSTALLER deleted file mode 100644 index a1b589e..0000000 --- a/venv/lib/python3.9/site-packages/importlib_metadata-8.7.1.dist-info/INSTALLER +++ /dev/null @@ -1 +0,0 @@ -pip diff --git a/venv/lib/python3.9/site-packages/importlib_metadata-8.7.1.dist-info/METADATA b/venv/lib/python3.9/site-packages/importlib_metadata-8.7.1.dist-info/METADATA deleted file mode 100644 index 9d894b4..0000000 --- a/venv/lib/python3.9/site-packages/importlib_metadata-8.7.1.dist-info/METADATA +++ /dev/null @@ -1,133 +0,0 @@ -Metadata-Version: 2.4 -Name: importlib_metadata -Version: 8.7.1 -Summary: Read metadata from Python packages -Author-email: "Jason R. Coombs" -License-Expression: Apache-2.0 -Project-URL: Source, https://github.com/python/importlib_metadata -Classifier: Development Status :: 5 - Production/Stable -Classifier: Intended Audience :: Developers -Classifier: Programming Language :: Python :: 3 -Classifier: Programming Language :: Python :: 3 :: Only -Requires-Python: >=3.9 -Description-Content-Type: text/x-rst -License-File: LICENSE -Requires-Dist: zipp>=3.20 -Provides-Extra: test -Requires-Dist: pytest!=8.1.*,>=6; extra == "test" -Requires-Dist: packaging; extra == "test" -Requires-Dist: pyfakefs; extra == "test" -Requires-Dist: flufl.flake8; extra == "test" -Requires-Dist: pytest-perf>=0.9.2; extra == "test" -Requires-Dist: jaraco.test>=5.4; extra == "test" -Provides-Extra: doc -Requires-Dist: sphinx>=3.5; extra == "doc" -Requires-Dist: jaraco.packaging>=9.3; extra == "doc" -Requires-Dist: rst.linker>=1.9; extra == "doc" -Requires-Dist: furo; extra == "doc" -Requires-Dist: sphinx-lint; extra == "doc" -Requires-Dist: jaraco.tidelift>=1.4; extra == "doc" -Provides-Extra: perf -Requires-Dist: ipython; extra == "perf" -Provides-Extra: check -Requires-Dist: pytest-checkdocs>=2.4; extra == "check" -Requires-Dist: pytest-ruff>=0.2.1; sys_platform != "cygwin" and extra == "check" -Provides-Extra: cover -Requires-Dist: pytest-cov; extra == "cover" -Provides-Extra: enabler -Requires-Dist: pytest-enabler>=3.4; extra == "enabler" -Provides-Extra: type -Requires-Dist: pytest-mypy>=1.0.1; extra == "type" -Requires-Dist: mypy<1.19; platform_python_implementation == "PyPy" and extra == "type" -Dynamic: license-file - -.. image:: https://img.shields.io/pypi/v/importlib_metadata.svg - :target: https://pypi.org/project/importlib_metadata - -.. image:: https://img.shields.io/pypi/pyversions/importlib_metadata.svg - -.. image:: https://github.com/python/importlib_metadata/actions/workflows/main.yml/badge.svg - :target: https://github.com/python/importlib_metadata/actions?query=workflow%3A%22tests%22 - :alt: tests - -.. image:: https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/ruff/main/assets/badge/v2.json - :target: https://github.com/astral-sh/ruff - :alt: Ruff - -.. image:: https://readthedocs.org/projects/importlib-metadata/badge/?version=latest - :target: https://importlib-metadata.readthedocs.io/en/latest/?badge=latest - -.. image:: https://img.shields.io/badge/skeleton-2025-informational - :target: https://blog.jaraco.com/skeleton - -.. image:: https://tidelift.com/badges/package/pypi/importlib-metadata - :target: https://tidelift.com/subscription/pkg/pypi-importlib-metadata?utm_source=pypi-importlib-metadata&utm_medium=readme - -Library to access the metadata for a Python package. - -This package supplies third-party access to the functionality of -`importlib.metadata `_ -including improvements added to subsequent Python versions. - - -Compatibility -============= - -New features are introduced in this third-party library and later merged -into CPython. The following table indicates which versions of this library -were contributed to different versions in the standard library: - -.. list-table:: - :header-rows: 1 - - * - importlib_metadata - - stdlib - * - 7.0 - - 3.13 - * - 6.5 - - 3.12 - * - 4.13 - - 3.11 - * - 4.6 - - 3.10 - * - 1.4 - - 3.8 - - -Usage -===== - -See the `online documentation `_ -for usage details. - -`Finder authors -`_ can -also add support for custom package installers. See the above documentation -for details. - - -Caveats -======= - -This project primarily supports third-party packages installed by PyPA -tools (or other conforming packages). It does not support: - -- Packages in the stdlib. -- Packages installed without metadata. - -Project details -=============== - - * Project home: https://github.com/python/importlib_metadata - * Report bugs at: https://github.com/python/importlib_metadata/issues - * Code hosting: https://github.com/python/importlib_metadata - * Documentation: https://importlib-metadata.readthedocs.io/ - -For Enterprise -============== - -Available as part of the Tidelift Subscription. - -This project and the maintainers of thousands of other packages are working with Tidelift to deliver one enterprise subscription that covers all of the open source you use. - -`Learn more `_. diff --git a/venv/lib/python3.9/site-packages/importlib_metadata-8.7.1.dist-info/RECORD b/venv/lib/python3.9/site-packages/importlib_metadata-8.7.1.dist-info/RECORD deleted file mode 100644 index 9d7f3ed..0000000 --- a/venv/lib/python3.9/site-packages/importlib_metadata-8.7.1.dist-info/RECORD +++ /dev/null @@ -1,33 +0,0 @@ -importlib_metadata-8.7.1.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 -importlib_metadata-8.7.1.dist-info/METADATA,sha256=o-OLnuQyYonUhkcE8w4pnudp4jCc6fSnXw3hpQrQo1Y,4670 -importlib_metadata-8.7.1.dist-info/RECORD,, -importlib_metadata-8.7.1.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91 -importlib_metadata-8.7.1.dist-info/licenses/LICENSE,sha256=RYUC4S2Xu_ZEOGBqIARKqF6wX7CoqAe7NdvsJT_R_AQ,10278 -importlib_metadata-8.7.1.dist-info/top_level.txt,sha256=CO3fD9yylANiXkrMo4qHLV_mqXL2sC5JFKgt1yWAT-A,19 -importlib_metadata/__init__.py,sha256=u7Ew4-UkpzNY-ka6k-WRkDhQZS1akkLMfWs2eEnUmGo,37734 -importlib_metadata/__pycache__/__init__.cpython-39.pyc,, -importlib_metadata/__pycache__/_adapters.cpython-39.pyc,, -importlib_metadata/__pycache__/_collections.cpython-39.pyc,, -importlib_metadata/__pycache__/_compat.cpython-39.pyc,, -importlib_metadata/__pycache__/_functools.cpython-39.pyc,, -importlib_metadata/__pycache__/_itertools.cpython-39.pyc,, -importlib_metadata/__pycache__/_meta.cpython-39.pyc,, -importlib_metadata/__pycache__/_text.cpython-39.pyc,, -importlib_metadata/__pycache__/_typing.cpython-39.pyc,, -importlib_metadata/__pycache__/diagnose.cpython-39.pyc,, -importlib_metadata/_adapters.py,sha256=r5i8XLrKT6xmrpoREZhZrfczOYDmrVZeJBW5u0HzIGU,3797 -importlib_metadata/_collections.py,sha256=CxAhzlF3g1rwu_fMiB53JtRQiUFh0RgiMpoOvmK_ocg,760 -importlib_metadata/_compat.py,sha256=VC5ZDLlT-BcshauCShdFJvMNLntJJfZzNK1meGa-enw,1313 -importlib_metadata/_functools.py,sha256=0pA2OoiVK6wnsGq8HvVIzgdkvLiZ0nfnfw7IsndjoHk,3510 -importlib_metadata/_itertools.py,sha256=nMvp9SfHAQ_JYwK4L2i64lr3GRXGlYlikGTVzWbys_E,5351 -importlib_metadata/_meta.py,sha256=EtHyiJ5kGzWFDfKyQ2XQp6Vu113CeadKW1Vf6aGc1B4,1765 -importlib_metadata/_text.py,sha256=HCsFksZpJLeTP3NEk_ngrAeXVRRtTrtyh9eOABoRP4A,2166 -importlib_metadata/_typing.py,sha256=EQKhhsEgz_Sa-FnePI-faC72rNOOQwopjA1i5pG8FDU,367 -importlib_metadata/compat/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 -importlib_metadata/compat/__pycache__/__init__.cpython-39.pyc,, -importlib_metadata/compat/__pycache__/py311.cpython-39.pyc,, -importlib_metadata/compat/__pycache__/py39.cpython-39.pyc,, -importlib_metadata/compat/py311.py,sha256=uqm-K-uohyj1042TH4a9Er_I5o7667DvulcD-gC_fSA,608 -importlib_metadata/compat/py39.py,sha256=J3W7PUVRPNYMmcvT12RF8ndBU9e8_T0Ac4U87Bsrq70,1187 -importlib_metadata/diagnose.py,sha256=nkSRMiowlmkhLYhKhvCg9glmt_11Cox-EmLzEbqYTa8,379 -importlib_metadata/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 diff --git a/venv/lib/python3.9/site-packages/importlib_metadata-8.7.1.dist-info/WHEEL b/venv/lib/python3.9/site-packages/importlib_metadata-8.7.1.dist-info/WHEEL deleted file mode 100644 index e7fa31b..0000000 --- a/venv/lib/python3.9/site-packages/importlib_metadata-8.7.1.dist-info/WHEEL +++ /dev/null @@ -1,5 +0,0 @@ -Wheel-Version: 1.0 -Generator: setuptools (80.9.0) -Root-Is-Purelib: true -Tag: py3-none-any - diff --git a/venv/lib/python3.9/site-packages/importlib_metadata-8.7.1.dist-info/licenses/LICENSE b/venv/lib/python3.9/site-packages/importlib_metadata-8.7.1.dist-info/licenses/LICENSE deleted file mode 100644 index 5c1d8bb..0000000 --- a/venv/lib/python3.9/site-packages/importlib_metadata-8.7.1.dist-info/licenses/LICENSE +++ /dev/null @@ -1,73 +0,0 @@ -Apache License -Version 2.0, January 2004 -http://www.apache.org/licenses/ - -TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - -1. Definitions. - -"License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. - -"Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. - -"Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. - -"You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. - -"Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. - -"Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. - -"Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). - -"Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. - -"Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." - -"Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. - -2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. - -3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. - -4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: - - (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. - - You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. - -5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. - -6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. - -7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. - -8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. - -9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. - -END OF TERMS AND CONDITIONS - -APPENDIX: How to apply the Apache License to your work. - -To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. - -Copyright 2025 [name of copyright owner] - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - -http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. diff --git a/venv/lib/python3.9/site-packages/importlib_metadata-8.7.1.dist-info/top_level.txt b/venv/lib/python3.9/site-packages/importlib_metadata-8.7.1.dist-info/top_level.txt deleted file mode 100644 index bbb0754..0000000 --- a/venv/lib/python3.9/site-packages/importlib_metadata-8.7.1.dist-info/top_level.txt +++ /dev/null @@ -1 +0,0 @@ -importlib_metadata diff --git a/venv/lib/python3.9/site-packages/importlib_metadata/__init__.py b/venv/lib/python3.9/site-packages/importlib_metadata/__init__.py deleted file mode 100644 index 508b02e..0000000 --- a/venv/lib/python3.9/site-packages/importlib_metadata/__init__.py +++ /dev/null @@ -1,1191 +0,0 @@ -""" -APIs exposing metadata from third-party Python packages. - -This codebase is shared between importlib.metadata in the stdlib -and importlib_metadata in PyPI. See -https://github.com/python/importlib_metadata/wiki/Development-Methodology -for more detail. -""" - -from __future__ import annotations - -import abc -import collections -import email -import functools -import itertools -import operator -import os -import pathlib -import posixpath -import re -import sys -import textwrap -import types -from collections.abc import Iterable, Mapping -from contextlib import suppress -from importlib import import_module -from importlib.abc import MetaPathFinder -from itertools import starmap -from typing import Any - -from . import _meta -from ._collections import FreezableDefaultDict, Pair -from ._compat import ( - NullFinder, - install, -) -from ._functools import method_cache, noop, pass_none, passthrough -from ._itertools import always_iterable, bucket, unique_everseen -from ._meta import PackageMetadata, SimplePath -from ._typing import md_none -from .compat import py39, py311 - -__all__ = [ - 'Distribution', - 'DistributionFinder', - 'PackageMetadata', - 'PackageNotFoundError', - 'SimplePath', - 'distribution', - 'distributions', - 'entry_points', - 'files', - 'metadata', - 'packages_distributions', - 'requires', - 'version', -] - - -class PackageNotFoundError(ModuleNotFoundError): - """The package was not found.""" - - def __str__(self) -> str: - return f"No package metadata was found for {self.name}" - - @property - def name(self) -> str: # type: ignore[override] # make readonly - (name,) = self.args - return name - - -class Sectioned: - """ - A simple entry point config parser for performance - - >>> for item in Sectioned.read(Sectioned._sample): - ... print(item) - Pair(name='sec1', value='# comments ignored') - Pair(name='sec1', value='a = 1') - Pair(name='sec1', value='b = 2') - Pair(name='sec2', value='a = 2') - - >>> res = Sectioned.section_pairs(Sectioned._sample) - >>> item = next(res) - >>> item.name - 'sec1' - >>> item.value - Pair(name='a', value='1') - >>> item = next(res) - >>> item.value - Pair(name='b', value='2') - >>> item = next(res) - >>> item.name - 'sec2' - >>> item.value - Pair(name='a', value='2') - >>> list(res) - [] - """ - - _sample = textwrap.dedent( - """ - [sec1] - # comments ignored - a = 1 - b = 2 - - [sec2] - a = 2 - """ - ).lstrip() - - @classmethod - def section_pairs(cls, text): - return ( - section._replace(value=Pair.parse(section.value)) - for section in cls.read(text, filter_=cls.valid) - if section.name is not None - ) - - @staticmethod - def read(text, filter_=None): - lines = filter(filter_, map(str.strip, text.splitlines())) - name = None - for value in lines: - section_match = value.startswith('[') and value.endswith(']') - if section_match: - name = value.strip('[]') - continue - yield Pair(name, value) - - @staticmethod - def valid(line: str): - return line and not line.startswith('#') - - -class _EntryPointMatch(types.SimpleNamespace): - module: str - attr: str - extras: str - - -class EntryPoint: - """An entry point as defined by Python packaging conventions. - - See `the packaging docs on entry points - `_ - for more information. - - >>> ep = EntryPoint( - ... name=None, group=None, value='package.module:attr [extra1, extra2]') - >>> ep.module - 'package.module' - >>> ep.attr - 'attr' - >>> ep.extras - ['extra1', 'extra2'] - - If the value package or module are not valid identifiers, a - ValueError is raised on access. - - >>> EntryPoint(name=None, group=None, value='invalid-name').module - Traceback (most recent call last): - ... - ValueError: ('Invalid object reference...invalid-name... - >>> EntryPoint(name=None, group=None, value='invalid-name').attr - Traceback (most recent call last): - ... - ValueError: ('Invalid object reference...invalid-name... - >>> EntryPoint(name=None, group=None, value='invalid-name').extras - Traceback (most recent call last): - ... - ValueError: ('Invalid object reference...invalid-name... - - The same thing happens on construction. - - >>> EntryPoint(name=None, group=None, value='invalid-name') - Traceback (most recent call last): - ... - ValueError: ('Invalid object reference...invalid-name... - - """ - - pattern = re.compile( - r'(?P[\w.]+)\s*' - r'(:\s*(?P[\w.]+)\s*)?' - r'((?P\[.*\])\s*)?$' - ) - """ - A regular expression describing the syntax for an entry point, - which might look like: - - - module - - package.module - - package.module:attribute - - package.module:object.attribute - - package.module:attr [extra1, extra2] - - Other combinations are possible as well. - - The expression is lenient about whitespace around the ':', - following the attr, and following any extras. - """ - - name: str - value: str - group: str - - dist: Distribution | None = None - - def __init__(self, name: str, value: str, group: str) -> None: - vars(self).update(name=name, value=value, group=group) - self.module - - def load(self) -> Any: - """Load the entry point from its definition. If only a module - is indicated by the value, return that module. Otherwise, - return the named object. - """ - module = import_module(self.module) - attrs = filter(None, (self.attr or '').split('.')) - return functools.reduce(getattr, attrs, module) - - @property - def module(self) -> str: - return self._match.module - - @property - def attr(self) -> str: - return self._match.attr - - @property - def extras(self) -> list[str]: - return re.findall(r'\w+', self._match.extras or '') - - @functools.cached_property - def _match(self) -> _EntryPointMatch: - match = self.pattern.match(self.value) - if not match: - raise ValueError( - 'Invalid object reference. ' - 'See https://packaging.python.org' - '/en/latest/specifications/entry-points/#data-model', - self.value, - ) - return _EntryPointMatch(**match.groupdict()) - - def _for(self, dist): - vars(self).update(dist=dist) - return self - - def matches(self, **params): - """ - EntryPoint matches the given parameters. - - >>> ep = EntryPoint(group='foo', name='bar', value='bing:bong [extra1, extra2]') - >>> ep.matches(group='foo') - True - >>> ep.matches(name='bar', value='bing:bong [extra1, extra2]') - True - >>> ep.matches(group='foo', name='other') - False - >>> ep.matches() - True - >>> ep.matches(extras=['extra1', 'extra2']) - True - >>> ep.matches(module='bing') - True - >>> ep.matches(attr='bong') - True - """ - self._disallow_dist(params) - attrs = (getattr(self, param) for param in params) - return all(map(operator.eq, params.values(), attrs)) - - @staticmethod - def _disallow_dist(params): - """ - Querying by dist is not allowed (dist objects are not comparable). - >>> EntryPoint(name='fan', value='fav', group='fag').matches(dist='foo') - Traceback (most recent call last): - ... - ValueError: "dist" is not suitable for matching... - """ - if "dist" in params: - raise ValueError( - '"dist" is not suitable for matching. ' - "Instead, use Distribution.entry_points.select() on a " - "located distribution." - ) - - def _key(self): - return self.name, self.value, self.group - - def __lt__(self, other): - return self._key() < other._key() - - def __eq__(self, other): - return self._key() == other._key() - - def __setattr__(self, name, value): - raise AttributeError("EntryPoint objects are immutable.") - - def __repr__(self): - return ( - f'EntryPoint(name={self.name!r}, value={self.value!r}, ' - f'group={self.group!r})' - ) - - def __hash__(self) -> int: - return hash(self._key()) - - -class EntryPoints(tuple): - """ - An immutable collection of selectable EntryPoint objects. - """ - - __slots__ = () - - def __getitem__(self, name: str) -> EntryPoint: # type: ignore[override] # Work with str instead of int - """ - Get the EntryPoint in self matching name. - """ - try: - return next(iter(self.select(name=name))) - except StopIteration: - raise KeyError(name) - - def __repr__(self): - """ - Repr with classname and tuple constructor to - signal that we deviate from regular tuple behavior. - """ - return '%s(%r)' % (self.__class__.__name__, tuple(self)) - - def select(self, **params) -> EntryPoints: - """ - Select entry points from self that match the - given parameters (typically group and/or name). - """ - return EntryPoints(ep for ep in self if py39.ep_matches(ep, **params)) - - @property - def names(self) -> set[str]: - """ - Return the set of all names of all entry points. - """ - return {ep.name for ep in self} - - @property - def groups(self) -> set[str]: - """ - Return the set of all groups of all entry points. - """ - return {ep.group for ep in self} - - @classmethod - def _from_text_for(cls, text, dist): - return cls(ep._for(dist) for ep in cls._from_text(text)) - - @staticmethod - def _from_text(text): - return ( - EntryPoint(name=item.value.name, value=item.value.value, group=item.name) - for item in Sectioned.section_pairs(text or '') - ) - - -class PackagePath(pathlib.PurePosixPath): - """A reference to a path in a package""" - - hash: FileHash | None - size: int - dist: Distribution - - def read_text(self, encoding: str = 'utf-8') -> str: - return self.locate().read_text(encoding=encoding) - - def read_binary(self) -> bytes: - return self.locate().read_bytes() - - def locate(self) -> SimplePath: - """Return a path-like object for this path""" - return self.dist.locate_file(self) - - -class FileHash: - def __init__(self, spec: str) -> None: - self.mode, _, self.value = spec.partition('=') - - def __repr__(self) -> str: - return f'' - - -class Distribution(metaclass=abc.ABCMeta): - """ - An abstract Python distribution package. - - Custom providers may derive from this class and define - the abstract methods to provide a concrete implementation - for their environment. Some providers may opt to override - the default implementation of some properties to bypass - the file-reading mechanism. - """ - - @abc.abstractmethod - def read_text(self, filename) -> str | None: - """Attempt to load metadata file given by the name. - - Python distribution metadata is organized by blobs of text - typically represented as "files" in the metadata directory - (e.g. package-1.0.dist-info). These files include things - like: - - - METADATA: The distribution metadata including fields - like Name and Version and Description. - - entry_points.txt: A series of entry points as defined in - `the entry points spec `_. - - RECORD: A record of files according to - `this recording spec `_. - - A package may provide any set of files, including those - not listed here or none at all. - - :param filename: The name of the file in the distribution info. - :return: The text if found, otherwise None. - """ - - @abc.abstractmethod - def locate_file(self, path: str | os.PathLike[str]) -> SimplePath: - """ - Given a path to a file in this distribution, return a SimplePath - to it. - - This method is used by callers of ``Distribution.files()`` to - locate files within the distribution. If it's possible for a - Distribution to represent files in the distribution as - ``SimplePath`` objects, it should implement this method - to resolve such objects. - - Some Distribution providers may elect not to resolve SimplePath - objects within the distribution by raising a - NotImplementedError, but consumers of such a Distribution would - be unable to invoke ``Distribution.files()``. - """ - - @classmethod - def from_name(cls, name: str) -> Distribution: - """Return the Distribution for the given package name. - - :param name: The name of the distribution package to search for. - :return: The Distribution instance (or subclass thereof) for the named - package, if found. - :raises PackageNotFoundError: When the named package's distribution - metadata cannot be found. - :raises ValueError: When an invalid value is supplied for name. - """ - if not name: - raise ValueError("A distribution name is required.") - try: - return next(iter(cls._prefer_valid(cls.discover(name=name)))) - except StopIteration: - raise PackageNotFoundError(name) - - @classmethod - def discover( - cls, *, context: DistributionFinder.Context | None = None, **kwargs - ) -> Iterable[Distribution]: - """Return an iterable of Distribution objects for all packages. - - Pass a ``context`` or pass keyword arguments for constructing - a context. - - :context: A ``DistributionFinder.Context`` object. - :return: Iterable of Distribution objects for packages matching - the context. - """ - if context and kwargs: - raise ValueError("cannot accept context and kwargs") - context = context or DistributionFinder.Context(**kwargs) - return itertools.chain.from_iterable( - resolver(context) for resolver in cls._discover_resolvers() - ) - - @staticmethod - def _prefer_valid(dists: Iterable[Distribution]) -> Iterable[Distribution]: - """ - Prefer (move to the front) distributions that have metadata. - - Ref python/importlib_resources#489. - """ - buckets = bucket(dists, lambda dist: bool(dist.metadata)) - return itertools.chain(buckets[True], buckets[False]) - - @staticmethod - def at(path: str | os.PathLike[str]) -> Distribution: - """Return a Distribution for the indicated metadata path. - - :param path: a string or path-like object - :return: a concrete Distribution instance for the path - """ - return PathDistribution(pathlib.Path(path)) - - @staticmethod - def _discover_resolvers(): - """Search the meta_path for resolvers (MetadataPathFinders).""" - declared = ( - getattr(finder, 'find_distributions', None) for finder in sys.meta_path - ) - return filter(None, declared) - - @property - def metadata(self) -> _meta.PackageMetadata | None: - """Return the parsed metadata for this Distribution. - - The returned object will have keys that name the various bits of - metadata per the - `Core metadata specifications `_. - - Custom providers may provide the METADATA file or override this - property. - """ - - text = ( - self.read_text('METADATA') - or self.read_text('PKG-INFO') - # This last clause is here to support old egg-info files. Its - # effect is to just end up using the PathDistribution's self._path - # (which points to the egg-info file) attribute unchanged. - or self.read_text('') - ) - return self._assemble_message(text) - - @staticmethod - @pass_none - def _assemble_message(text: str) -> _meta.PackageMetadata: - # deferred for performance (python/cpython#109829) - from . import _adapters - - return _adapters.Message(email.message_from_string(text)) - - @property - def name(self) -> str: - """Return the 'Name' metadata for the distribution package.""" - return md_none(self.metadata)['Name'] - - @property - def _normalized_name(self): - """Return a normalized version of the name.""" - return Prepared.normalize(self.name) - - @property - def version(self) -> str: - """Return the 'Version' metadata for the distribution package.""" - return md_none(self.metadata)['Version'] - - @property - def entry_points(self) -> EntryPoints: - """ - Return EntryPoints for this distribution. - - Custom providers may provide the ``entry_points.txt`` file - or override this property. - """ - return EntryPoints._from_text_for(self.read_text('entry_points.txt'), self) - - @property - def files(self) -> list[PackagePath] | None: - """Files in this distribution. - - :return: List of PackagePath for this distribution or None - - Result is `None` if the metadata file that enumerates files - (i.e. RECORD for dist-info, or installed-files.txt or - SOURCES.txt for egg-info) is missing. - Result may be empty if the metadata exists but is empty. - - Custom providers are recommended to provide a "RECORD" file (in - ``read_text``) or override this property to allow for callers to be - able to resolve filenames provided by the package. - """ - - def make_file(name, hash=None, size_str=None): - result = PackagePath(name) - result.hash = FileHash(hash) if hash else None - result.size = int(size_str) if size_str else None - result.dist = self - return result - - @pass_none - def make_files(lines): - # Delay csv import, since Distribution.files is not as widely used - # as other parts of importlib.metadata - import csv - - return starmap(make_file, csv.reader(lines)) - - @pass_none - def skip_missing_files(package_paths): - return list(filter(lambda path: path.locate().exists(), package_paths)) - - return skip_missing_files( - make_files( - self._read_files_distinfo() - or self._read_files_egginfo_installed() - or self._read_files_egginfo_sources() - ) - ) - - def _read_files_distinfo(self): - """ - Read the lines of RECORD. - """ - text = self.read_text('RECORD') - return text and text.splitlines() - - def _read_files_egginfo_installed(self): - """ - Read installed-files.txt and return lines in a similar - CSV-parsable format as RECORD: each file must be placed - relative to the site-packages directory and must also be - quoted (since file names can contain literal commas). - - This file is written when the package is installed by pip, - but it might not be written for other installation methods. - Assume the file is accurate if it exists. - """ - text = self.read_text('installed-files.txt') - # Prepend the .egg-info/ subdir to the lines in this file. - # But this subdir is only available from PathDistribution's - # self._path. - subdir = getattr(self, '_path', None) - if not text or not subdir: - return - - paths = ( - py311 - .relative_fix((subdir / name).resolve()) - .relative_to(self.locate_file('').resolve(), walk_up=True) - .as_posix() - for name in text.splitlines() - ) - return map('"{}"'.format, paths) - - def _read_files_egginfo_sources(self): - """ - Read SOURCES.txt and return lines in a similar CSV-parsable - format as RECORD: each file name must be quoted (since it - might contain literal commas). - - Note that SOURCES.txt is not a reliable source for what - files are installed by a package. This file is generated - for a source archive, and the files that are present - there (e.g. setup.py) may not correctly reflect the files - that are present after the package has been installed. - """ - text = self.read_text('SOURCES.txt') - return text and map('"{}"'.format, text.splitlines()) - - @property - def requires(self) -> list[str] | None: - """Generated requirements specified for this Distribution""" - reqs = self._read_dist_info_reqs() or self._read_egg_info_reqs() - return reqs and list(reqs) - - def _read_dist_info_reqs(self): - return self.metadata.get_all('Requires-Dist') - - def _read_egg_info_reqs(self): - source = self.read_text('requires.txt') - return pass_none(self._deps_from_requires_text)(source) - - @classmethod - def _deps_from_requires_text(cls, source): - return cls._convert_egg_info_reqs_to_simple_reqs(Sectioned.read(source)) - - @staticmethod - def _convert_egg_info_reqs_to_simple_reqs(sections): - """ - Historically, setuptools would solicit and store 'extra' - requirements, including those with environment markers, - in separate sections. More modern tools expect each - dependency to be defined separately, with any relevant - extras and environment markers attached directly to that - requirement. This method converts the former to the - latter. See _test_deps_from_requires_text for an example. - """ - - def make_condition(name): - return name and f'extra == "{name}"' - - def quoted_marker(section): - section = section or '' - extra, sep, markers = section.partition(':') - if extra and markers: - markers = f'({markers})' - conditions = list(filter(None, [markers, make_condition(extra)])) - return '; ' + ' and '.join(conditions) if conditions else '' - - def url_req_space(req): - """ - PEP 508 requires a space between the url_spec and the quoted_marker. - Ref python/importlib_metadata#357. - """ - # '@' is uniquely indicative of a url_req. - return ' ' * ('@' in req) - - for section in sections: - space = url_req_space(section.value) - yield section.value + space + quoted_marker(section.name) - - @property - def origin(self): - return self._load_json('direct_url.json') - - def _load_json(self, filename): - # Deferred for performance (python/importlib_metadata#503) - import json - - return pass_none(json.loads)( - self.read_text(filename), - object_hook=lambda data: types.SimpleNamespace(**data), - ) - - -class DistributionFinder(MetaPathFinder): - """ - A MetaPathFinder capable of discovering installed distributions. - - Custom providers should implement this interface in order to - supply metadata. - """ - - class Context: - """ - Keyword arguments presented by the caller to - ``distributions()`` or ``Distribution.discover()`` - to narrow the scope of a search for distributions - in all DistributionFinders. - - Each DistributionFinder may expect any parameters - and should attempt to honor the canonical - parameters defined below when appropriate. - - This mechanism gives a custom provider a means to - solicit additional details from the caller beyond - "name" and "path" when searching distributions. - For example, imagine a provider that exposes suites - of packages in either a "public" or "private" ``realm``. - A caller may wish to query only for distributions in - a particular realm and could call - ``distributions(realm="private")`` to signal to the - custom provider to only include distributions from that - realm. - """ - - name = None - """ - Specific name for which a distribution finder should match. - A name of ``None`` matches all distributions. - """ - - def __init__(self, **kwargs): - vars(self).update(kwargs) - - @property - def path(self) -> list[str]: - """ - The sequence of directory path that a distribution finder - should search. - - Typically refers to Python installed package paths such as - "site-packages" directories and defaults to ``sys.path``. - """ - return vars(self).get('path', sys.path) - - @abc.abstractmethod - def find_distributions(self, context=Context()) -> Iterable[Distribution]: - """ - Find distributions. - - Return an iterable of all Distribution instances capable of - loading the metadata for packages matching the ``context``, - a DistributionFinder.Context instance. - """ - - -@passthrough -def _clear_after_fork(cached): - """Ensure ``func`` clears cached state after ``fork`` when supported. - - ``FastPath`` caches zip-backed ``pathlib.Path`` objects that retain a - reference to the parent's open ``ZipFile`` handle. Re-using a cached - instance in a forked child can therefore resurrect invalid file pointers - and trigger ``BadZipFile``/``OSError`` failures (python/importlib_metadata#520). - Registering ``cache_clear`` with ``os.register_at_fork`` keeps each process - on its own cache. - """ - getattr(os, 'register_at_fork', noop)(after_in_child=cached.cache_clear) - - -class FastPath: - """ - Micro-optimized class for searching a root for children. - - Root is a path on the file system that may contain metadata - directories either as natural directories or within a zip file. - - >>> FastPath('').children() - ['...'] - - FastPath objects are cached and recycled for any given root. - - >>> FastPath('foobar') is FastPath('foobar') - True - """ - - @_clear_after_fork # type: ignore[misc] - @functools.lru_cache() - def __new__(cls, root): - return super().__new__(cls) - - def __init__(self, root): - self.root = root - - def joinpath(self, child): - return pathlib.Path(self.root, child) - - def children(self): - with suppress(Exception): - return os.listdir(self.root or '.') - with suppress(Exception): - return self.zip_children() - return [] - - def zip_children(self): - # deferred for performance (python/importlib_metadata#502) - from zipp.compat.overlay import zipfile - - zip_path = zipfile.Path(self.root) - names = zip_path.root.namelist() - self.joinpath = zip_path.joinpath - - return dict.fromkeys(child.split(posixpath.sep, 1)[0] for child in names) - - def search(self, name): - return self.lookup(self.mtime).search(name) - - @property - def mtime(self): - with suppress(OSError): - return os.stat(self.root).st_mtime - self.lookup.cache_clear() - - @method_cache - def lookup(self, mtime): - return Lookup(self) - - -class Lookup: - """ - A micro-optimized class for searching a (fast) path for metadata. - """ - - def __init__(self, path: FastPath): - """ - Calculate all of the children representing metadata. - - From the children in the path, calculate early all of the - children that appear to represent metadata (infos) or legacy - metadata (eggs). - """ - - base = os.path.basename(path.root).lower() - base_is_egg = base.endswith(".egg") - self.infos = FreezableDefaultDict(list) - self.eggs = FreezableDefaultDict(list) - - for child in path.children(): - low = child.lower() - if low.endswith((".dist-info", ".egg-info")): - # rpartition is faster than splitext and suitable for this purpose. - name = low.rpartition(".")[0].partition("-")[0] - normalized = Prepared.normalize(name) - self.infos[normalized].append(path.joinpath(child)) - elif base_is_egg and low == "egg-info": - name = base.rpartition(".")[0].partition("-")[0] - legacy_normalized = Prepared.legacy_normalize(name) - self.eggs[legacy_normalized].append(path.joinpath(child)) - - self.infos.freeze() - self.eggs.freeze() - - def search(self, prepared: Prepared): - """ - Yield all infos and eggs matching the Prepared query. - """ - infos = ( - self.infos[prepared.normalized] - if prepared - else itertools.chain.from_iterable(self.infos.values()) - ) - eggs = ( - self.eggs[prepared.legacy_normalized] - if prepared - else itertools.chain.from_iterable(self.eggs.values()) - ) - return itertools.chain(infos, eggs) - - -class Prepared: - """ - A prepared search query for metadata on a possibly-named package. - - Pre-calculates the normalization to prevent repeated operations. - - >>> none = Prepared(None) - >>> none.normalized - >>> none.legacy_normalized - >>> bool(none) - False - >>> sample = Prepared('Sample__Pkg-name.foo') - >>> sample.normalized - 'sample_pkg_name_foo' - >>> sample.legacy_normalized - 'sample__pkg_name.foo' - >>> bool(sample) - True - """ - - normalized = None - legacy_normalized = None - - def __init__(self, name: str | None): - self.name = name - if name is None: - return - self.normalized = self.normalize(name) - self.legacy_normalized = self.legacy_normalize(name) - - @staticmethod - def normalize(name): - """ - PEP 503 normalization plus dashes as underscores. - """ - return re.sub(r"[-_.]+", "-", name).lower().replace('-', '_') - - @staticmethod - def legacy_normalize(name): - """ - Normalize the package name as found in the convention in - older packaging tools versions and specs. - """ - return name.lower().replace('-', '_') - - def __bool__(self): - return bool(self.name) - - -@install -class MetadataPathFinder(NullFinder, DistributionFinder): - """A degenerate finder for distribution packages on the file system. - - This finder supplies only a find_distributions() method for versions - of Python that do not have a PathFinder find_distributions(). - """ - - @classmethod - def find_distributions( - cls, context=DistributionFinder.Context() - ) -> Iterable[PathDistribution]: - """ - Find distributions. - - Return an iterable of all Distribution instances capable of - loading the metadata for packages matching ``context.name`` - (or all names if ``None`` indicated) along the paths in the list - of directories ``context.path``. - """ - found = cls._search_paths(context.name, context.path) - return map(PathDistribution, found) - - @classmethod - def _search_paths(cls, name, paths): - """Find metadata directories in paths heuristically.""" - prepared = Prepared(name) - return itertools.chain.from_iterable( - path.search(prepared) for path in map(FastPath, paths) - ) - - @classmethod - def invalidate_caches(cls) -> None: - FastPath.__new__.cache_clear() - - -class PathDistribution(Distribution): - def __init__(self, path: SimplePath) -> None: - """Construct a distribution. - - :param path: SimplePath indicating the metadata directory. - """ - self._path = path - - def read_text(self, filename: str | os.PathLike[str]) -> str | None: - with suppress( - FileNotFoundError, - IsADirectoryError, - KeyError, - NotADirectoryError, - PermissionError, - ): - return self._path.joinpath(filename).read_text(encoding='utf-8') - - return None - - read_text.__doc__ = Distribution.read_text.__doc__ - - def locate_file(self, path: str | os.PathLike[str]) -> SimplePath: - return self._path.parent / path - - @property - def _normalized_name(self): - """ - Performance optimization: where possible, resolve the - normalized name from the file system path. - """ - stem = os.path.basename(str(self._path)) - return ( - pass_none(Prepared.normalize)(self._name_from_stem(stem)) - or super()._normalized_name - ) - - @staticmethod - def _name_from_stem(stem): - """ - >>> PathDistribution._name_from_stem('foo-3.0.egg-info') - 'foo' - >>> PathDistribution._name_from_stem('CherryPy-3.0.dist-info') - 'CherryPy' - >>> PathDistribution._name_from_stem('face.egg-info') - 'face' - >>> PathDistribution._name_from_stem('foo.bar') - """ - filename, ext = os.path.splitext(stem) - if ext not in ('.dist-info', '.egg-info'): - return - name, sep, rest = filename.partition('-') - return name - - -def distribution(distribution_name: str) -> Distribution: - """Get the ``Distribution`` instance for the named package. - - :param distribution_name: The name of the distribution package as a string. - :return: A ``Distribution`` instance (or subclass thereof). - """ - return Distribution.from_name(distribution_name) - - -def distributions(**kwargs) -> Iterable[Distribution]: - """Get all ``Distribution`` instances in the current environment. - - :return: An iterable of ``Distribution`` instances. - """ - return Distribution.discover(**kwargs) - - -def metadata(distribution_name: str) -> _meta.PackageMetadata | None: - """Get the metadata for the named package. - - :param distribution_name: The name of the distribution package to query. - :return: A PackageMetadata containing the parsed metadata. - """ - return Distribution.from_name(distribution_name).metadata - - -def version(distribution_name: str) -> str: - """Get the version string for the named package. - - :param distribution_name: The name of the distribution package to query. - :return: The version string for the package as defined in the package's - "Version" metadata key. - """ - return distribution(distribution_name).version - - -_unique = functools.partial( - unique_everseen, - key=py39.normalized_name, -) -""" -Wrapper for ``distributions`` to return unique distributions by name. -""" - - -def entry_points(**params) -> EntryPoints: - """Return EntryPoint objects for all installed packages. - - Pass selection parameters (group or name) to filter the - result to entry points matching those properties (see - EntryPoints.select()). - - :return: EntryPoints for all installed packages. - """ - eps = itertools.chain.from_iterable( - dist.entry_points for dist in _unique(distributions()) - ) - return EntryPoints(eps).select(**params) - - -def files(distribution_name: str) -> list[PackagePath] | None: - """Return a list of files for the named package. - - :param distribution_name: The name of the distribution package to query. - :return: List of files composing the distribution. - """ - return distribution(distribution_name).files - - -def requires(distribution_name: str) -> list[str] | None: - """ - Return a list of requirements for the named package. - - :return: An iterable of requirements, suitable for - packaging.requirement.Requirement. - """ - return distribution(distribution_name).requires - - -def packages_distributions() -> Mapping[str, list[str]]: - """ - Return a mapping of top-level packages to their - distributions. - - >>> import collections.abc - >>> pkgs = packages_distributions() - >>> all(isinstance(dist, collections.abc.Sequence) for dist in pkgs.values()) - True - """ - pkg_to_dist = collections.defaultdict(list) - for dist in distributions(): - for pkg in _top_level_declared(dist) or _top_level_inferred(dist): - pkg_to_dist[pkg].append(md_none(dist.metadata)['Name']) - return dict(pkg_to_dist) - - -def _top_level_declared(dist): - return (dist.read_text('top_level.txt') or '').split() - - -def _topmost(name: PackagePath) -> str | None: - """ - Return the top-most parent as long as there is a parent. - """ - top, *rest = name.parts - return top if rest else None - - -def _get_toplevel_name(name: PackagePath) -> str: - """ - Infer a possibly importable module name from a name presumed on - sys.path. - - >>> _get_toplevel_name(PackagePath('foo.py')) - 'foo' - >>> _get_toplevel_name(PackagePath('foo')) - 'foo' - >>> _get_toplevel_name(PackagePath('foo.pyc')) - 'foo' - >>> _get_toplevel_name(PackagePath('foo/__init__.py')) - 'foo' - >>> _get_toplevel_name(PackagePath('foo.pth')) - 'foo.pth' - >>> _get_toplevel_name(PackagePath('foo.dist-info')) - 'foo.dist-info' - """ - # Defer import of inspect for performance (python/cpython#118761) - import inspect - - return _topmost(name) or inspect.getmodulename(name) or str(name) - - -def _top_level_inferred(dist): - opt_names = set(map(_get_toplevel_name, always_iterable(dist.files))) - - def importable_name(name): - return '.' not in name - - return filter(importable_name, opt_names) diff --git a/venv/lib/python3.9/site-packages/importlib_metadata/_adapters.py b/venv/lib/python3.9/site-packages/importlib_metadata/_adapters.py deleted file mode 100644 index dede395..0000000 --- a/venv/lib/python3.9/site-packages/importlib_metadata/_adapters.py +++ /dev/null @@ -1,136 +0,0 @@ -import email.message -import email.policy -import re -import textwrap - -from ._text import FoldedCase - - -class RawPolicy(email.policy.EmailPolicy): - def fold(self, name, value): - folded = self.linesep.join( - textwrap - .indent(value, prefix=' ' * 8, predicate=lambda line: True) - .lstrip() - .splitlines() - ) - return f'{name}: {folded}{self.linesep}' - - -class Message(email.message.Message): - r""" - Specialized Message subclass to handle metadata naturally. - - Reads values that may have newlines in them and converts the - payload to the Description. - - >>> msg_text = textwrap.dedent(''' - ... Name: Foo - ... Version: 3.0 - ... License: blah - ... de-blah - ... - ... First line of description. - ... Second line of description. - ... - ... Fourth line! - ... ''').lstrip().replace('', '') - >>> msg = Message(email.message_from_string(msg_text)) - >>> msg['Description'] - 'First line of description.\nSecond line of description.\n\nFourth line!\n' - - Message should render even if values contain newlines. - - >>> print(msg) - Name: Foo - Version: 3.0 - License: blah - de-blah - Description: First line of description. - Second line of description. - - Fourth line! - - - """ - - multiple_use_keys = set( - map( - FoldedCase, - [ - 'Classifier', - 'Obsoletes-Dist', - 'Platform', - 'Project-URL', - 'Provides-Dist', - 'Provides-Extra', - 'Requires-Dist', - 'Requires-External', - 'Supported-Platform', - 'Dynamic', - ], - ) - ) - """ - Keys that may be indicated multiple times per PEP 566. - """ - - def __new__(cls, orig: email.message.Message): - res = super().__new__(cls) - vars(res).update(vars(orig)) - return res - - def __init__(self, *args, **kwargs): - self._headers = self._repair_headers() - - # suppress spurious error from mypy - def __iter__(self): - return super().__iter__() - - def __getitem__(self, item): - """ - Override parent behavior to typical dict behavior. - - ``email.message.Message`` will emit None values for missing - keys. Typical mappings, including this ``Message``, will raise - a key error for missing keys. - - Ref python/importlib_metadata#371. - """ - res = super().__getitem__(item) - if res is None: - raise KeyError(item) - return res - - def _repair_headers(self): - def redent(value): - "Correct for RFC822 indentation" - indent = ' ' * 8 - if not value or '\n' + indent not in value: - return value - return textwrap.dedent(indent + value) - - headers = [(key, redent(value)) for key, value in vars(self)['_headers']] - if self._payload: - headers.append(('Description', self.get_payload())) - self.set_payload('') - return headers - - def as_string(self): - return super().as_string(policy=RawPolicy()) - - @property - def json(self): - """ - Convert PackageMetadata to a JSON-compatible format - per PEP 0566. - """ - - def transform(key): - value = self.get_all(key) if key in self.multiple_use_keys else self[key] - if key == 'Keywords': - value = re.split(r'\s+', value) - tk = key.lower().replace('-', '_') - return tk, value - - return dict(map(transform, map(FoldedCase, self))) diff --git a/venv/lib/python3.9/site-packages/importlib_metadata/_collections.py b/venv/lib/python3.9/site-packages/importlib_metadata/_collections.py deleted file mode 100644 index fc5045d..0000000 --- a/venv/lib/python3.9/site-packages/importlib_metadata/_collections.py +++ /dev/null @@ -1,34 +0,0 @@ -import collections -import typing - - -# from jaraco.collections 3.3 -class FreezableDefaultDict(collections.defaultdict): - """ - Often it is desirable to prevent the mutation of - a default dict after its initial construction, such - as to prevent mutation during iteration. - - >>> dd = FreezableDefaultDict(list) - >>> dd[0].append('1') - >>> dd.freeze() - >>> dd[1] - [] - >>> len(dd) - 1 - """ - - def __missing__(self, key): - return getattr(self, '_frozen', super().__missing__)(key) - - def freeze(self): - self._frozen = lambda key: self.default_factory() - - -class Pair(typing.NamedTuple): - name: str - value: str - - @classmethod - def parse(cls, text): - return cls(*map(str.strip, text.split("=", 1))) diff --git a/venv/lib/python3.9/site-packages/importlib_metadata/_compat.py b/venv/lib/python3.9/site-packages/importlib_metadata/_compat.py deleted file mode 100644 index 01356d6..0000000 --- a/venv/lib/python3.9/site-packages/importlib_metadata/_compat.py +++ /dev/null @@ -1,56 +0,0 @@ -import platform -import sys - -__all__ = ['install', 'NullFinder'] - - -def install(cls): - """ - Class decorator for installation on sys.meta_path. - - Adds the backport DistributionFinder to sys.meta_path and - attempts to disable the finder functionality of the stdlib - DistributionFinder. - """ - sys.meta_path.append(cls()) - disable_stdlib_finder() - return cls - - -def disable_stdlib_finder(): - """ - Give the backport primacy for discovering path-based distributions - by monkey-patching the stdlib O_O. - - See #91 for more background for rationale on this sketchy - behavior. - """ - - def matches(finder): - return getattr( - finder, '__module__', None - ) == '_frozen_importlib_external' and hasattr(finder, 'find_distributions') - - for finder in filter(matches, sys.meta_path): # pragma: nocover - del finder.find_distributions - - -class NullFinder: - """ - A "Finder" (aka "MetaPathFinder") that never finds any modules, - but may find distributions. - """ - - @staticmethod - def find_spec(*args, **kwargs): - return None - - -def pypy_partial(val): - """ - Adjust for variable stacklevel on partial under PyPy. - - Workaround for #327. - """ - is_pypy = platform.python_implementation() == 'PyPy' - return val + is_pypy diff --git a/venv/lib/python3.9/site-packages/importlib_metadata/_functools.py b/venv/lib/python3.9/site-packages/importlib_metadata/_functools.py deleted file mode 100644 index b1fd04a..0000000 --- a/venv/lib/python3.9/site-packages/importlib_metadata/_functools.py +++ /dev/null @@ -1,135 +0,0 @@ -import functools -import types -from typing import Callable, TypeVar - - -# from jaraco.functools 3.3 -def method_cache(method, cache_wrapper=None): - """ - Wrap lru_cache to support storing the cache data in the object instances. - - Abstracts the common paradigm where the method explicitly saves an - underscore-prefixed protected property on first call and returns that - subsequently. - - >>> class MyClass: - ... calls = 0 - ... - ... @method_cache - ... def method(self, value): - ... self.calls += 1 - ... return value - - >>> a = MyClass() - >>> a.method(3) - 3 - >>> for x in range(75): - ... res = a.method(x) - >>> a.calls - 75 - - Note that the apparent behavior will be exactly like that of lru_cache - except that the cache is stored on each instance, so values in one - instance will not flush values from another, and when an instance is - deleted, so are the cached values for that instance. - - >>> b = MyClass() - >>> for x in range(35): - ... res = b.method(x) - >>> b.calls - 35 - >>> a.method(0) - 0 - >>> a.calls - 75 - - Note that if method had been decorated with ``functools.lru_cache()``, - a.calls would have been 76 (due to the cached value of 0 having been - flushed by the 'b' instance). - - Clear the cache with ``.cache_clear()`` - - >>> a.method.cache_clear() - - Same for a method that hasn't yet been called. - - >>> c = MyClass() - >>> c.method.cache_clear() - - Another cache wrapper may be supplied: - - >>> cache = functools.lru_cache(maxsize=2) - >>> MyClass.method2 = method_cache(lambda self: 3, cache_wrapper=cache) - >>> a = MyClass() - >>> a.method2() - 3 - - Caution - do not subsequently wrap the method with another decorator, such - as ``@property``, which changes the semantics of the function. - - See also - http://code.activestate.com/recipes/577452-a-memoize-decorator-for-instance-methods/ - for another implementation and additional justification. - """ - cache_wrapper = cache_wrapper or functools.lru_cache() - - def wrapper(self, *args, **kwargs): - # it's the first call, replace the method with a cached, bound method - bound_method = types.MethodType(method, self) - cached_method = cache_wrapper(bound_method) - setattr(self, method.__name__, cached_method) - return cached_method(*args, **kwargs) - - # Support cache clear even before cache has been created. - wrapper.cache_clear = lambda: None - - return wrapper - - -# From jaraco.functools 3.3 -def pass_none(func): - """ - Wrap func so it's not called if its first param is None - - >>> print_text = pass_none(print) - >>> print_text('text') - text - >>> print_text(None) - """ - - @functools.wraps(func) - def wrapper(param, *args, **kwargs): - if param is not None: - return func(param, *args, **kwargs) - - return wrapper - - -# From jaraco.functools 4.4 -def noop(*args, **kwargs): - """ - A no-operation function that does nothing. - - >>> noop(1, 2, three=3) - """ - - -_T = TypeVar('_T') - - -# From jaraco.functools 4.4 -def passthrough(func: Callable[..., object]) -> Callable[[_T], _T]: - """ - Wrap the function to always return the first parameter. - - >>> passthrough(print)('3') - 3 - '3' - """ - - @functools.wraps(func) - def wrapper(first: _T, *args, **kwargs) -> _T: - func(first, *args, **kwargs) - return first - - return wrapper # type: ignore[return-value] diff --git a/venv/lib/python3.9/site-packages/importlib_metadata/_itertools.py b/venv/lib/python3.9/site-packages/importlib_metadata/_itertools.py deleted file mode 100644 index 79d3719..0000000 --- a/venv/lib/python3.9/site-packages/importlib_metadata/_itertools.py +++ /dev/null @@ -1,171 +0,0 @@ -from collections import defaultdict, deque -from itertools import filterfalse - - -def unique_everseen(iterable, key=None): - "List unique elements, preserving order. Remember all elements ever seen." - # unique_everseen('AAAABBBCCDAABBB') --> A B C D - # unique_everseen('ABBCcAD', str.lower) --> A B C D - seen = set() - seen_add = seen.add - if key is None: - for element in filterfalse(seen.__contains__, iterable): - seen_add(element) - yield element - else: - for element in iterable: - k = key(element) - if k not in seen: - seen_add(k) - yield element - - -# copied from more_itertools 8.8 -def always_iterable(obj, base_type=(str, bytes)): - """If *obj* is iterable, return an iterator over its items:: - - >>> obj = (1, 2, 3) - >>> list(always_iterable(obj)) - [1, 2, 3] - - If *obj* is not iterable, return a one-item iterable containing *obj*:: - - >>> obj = 1 - >>> list(always_iterable(obj)) - [1] - - If *obj* is ``None``, return an empty iterable: - - >>> obj = None - >>> list(always_iterable(None)) - [] - - By default, binary and text strings are not considered iterable:: - - >>> obj = 'foo' - >>> list(always_iterable(obj)) - ['foo'] - - If *base_type* is set, objects for which ``isinstance(obj, base_type)`` - returns ``True`` won't be considered iterable. - - >>> obj = {'a': 1} - >>> list(always_iterable(obj)) # Iterate over the dict's keys - ['a'] - >>> list(always_iterable(obj, base_type=dict)) # Treat dicts as a unit - [{'a': 1}] - - Set *base_type* to ``None`` to avoid any special handling and treat objects - Python considers iterable as iterable: - - >>> obj = 'foo' - >>> list(always_iterable(obj, base_type=None)) - ['f', 'o', 'o'] - """ - if obj is None: - return iter(()) - - if (base_type is not None) and isinstance(obj, base_type): - return iter((obj,)) - - try: - return iter(obj) - except TypeError: - return iter((obj,)) - - -# Copied from more_itertools 10.3 -class bucket: - """Wrap *iterable* and return an object that buckets the iterable into - child iterables based on a *key* function. - - >>> iterable = ['a1', 'b1', 'c1', 'a2', 'b2', 'c2', 'b3'] - >>> s = bucket(iterable, key=lambda x: x[0]) # Bucket by 1st character - >>> sorted(list(s)) # Get the keys - ['a', 'b', 'c'] - >>> a_iterable = s['a'] - >>> next(a_iterable) - 'a1' - >>> next(a_iterable) - 'a2' - >>> list(s['b']) - ['b1', 'b2', 'b3'] - - The original iterable will be advanced and its items will be cached until - they are used by the child iterables. This may require significant storage. - - By default, attempting to select a bucket to which no items belong will - exhaust the iterable and cache all values. - If you specify a *validator* function, selected buckets will instead be - checked against it. - - >>> from itertools import count - >>> it = count(1, 2) # Infinite sequence of odd numbers - >>> key = lambda x: x % 10 # Bucket by last digit - >>> validator = lambda x: x in {1, 3, 5, 7, 9} # Odd digits only - >>> s = bucket(it, key=key, validator=validator) - >>> 2 in s - False - >>> list(s[2]) - [] - - """ - - def __init__(self, iterable, key, validator=None): - self._it = iter(iterable) - self._key = key - self._cache = defaultdict(deque) - self._validator = validator or (lambda x: True) - - def __contains__(self, value): - if not self._validator(value): - return False - - try: - item = next(self[value]) - except StopIteration: - return False - else: - self._cache[value].appendleft(item) - - return True - - def _get_values(self, value): - """ - Helper to yield items from the parent iterator that match *value*. - Items that don't match are stored in the local cache as they - are encountered. - """ - while True: - # If we've cached some items that match the target value, emit - # the first one and evict it from the cache. - if self._cache[value]: - yield self._cache[value].popleft() - # Otherwise we need to advance the parent iterator to search for - # a matching item, caching the rest. - else: - while True: - try: - item = next(self._it) - except StopIteration: - return - item_value = self._key(item) - if item_value == value: - yield item - break - elif self._validator(item_value): - self._cache[item_value].append(item) - - def __iter__(self): - for item in self._it: - item_value = self._key(item) - if self._validator(item_value): - self._cache[item_value].append(item) - - yield from self._cache.keys() - - def __getitem__(self, value): - if not self._validator(value): - return iter(()) - - return self._get_values(value) diff --git a/venv/lib/python3.9/site-packages/importlib_metadata/_meta.py b/venv/lib/python3.9/site-packages/importlib_metadata/_meta.py deleted file mode 100644 index 0c20eff..0000000 --- a/venv/lib/python3.9/site-packages/importlib_metadata/_meta.py +++ /dev/null @@ -1,71 +0,0 @@ -from __future__ import annotations - -import os -from collections.abc import Iterator -from typing import ( - Any, - Protocol, - TypeVar, - overload, -) - -_T = TypeVar("_T") - - -class PackageMetadata(Protocol): - def __len__(self) -> int: ... # pragma: no cover - - def __contains__(self, item: str) -> bool: ... # pragma: no cover - - def __getitem__(self, key: str) -> str: ... # pragma: no cover - - def __iter__(self) -> Iterator[str]: ... # pragma: no cover - - @overload - def get( - self, name: str, failobj: None = None - ) -> str | None: ... # pragma: no cover - - @overload - def get(self, name: str, failobj: _T) -> str | _T: ... # pragma: no cover - - # overload per python/importlib_metadata#435 - @overload - def get_all( - self, name: str, failobj: None = None - ) -> list[Any] | None: ... # pragma: no cover - - @overload - def get_all(self, name: str, failobj: _T) -> list[Any] | _T: - """ - Return all values associated with a possibly multi-valued key. - """ - - @property - def json(self) -> dict[str, str | list[str]]: - """ - A JSON-compatible form of the metadata. - """ - - -class SimplePath(Protocol): - """ - A minimal subset of pathlib.Path required by Distribution. - """ - - def joinpath( - self, other: str | os.PathLike[str] - ) -> SimplePath: ... # pragma: no cover - - def __truediv__( - self, other: str | os.PathLike[str] - ) -> SimplePath: ... # pragma: no cover - - @property - def parent(self) -> SimplePath: ... # pragma: no cover - - def read_text(self, encoding=None) -> str: ... # pragma: no cover - - def read_bytes(self) -> bytes: ... # pragma: no cover - - def exists(self) -> bool: ... # pragma: no cover diff --git a/venv/lib/python3.9/site-packages/importlib_metadata/_text.py b/venv/lib/python3.9/site-packages/importlib_metadata/_text.py deleted file mode 100644 index c88cfbb..0000000 --- a/venv/lib/python3.9/site-packages/importlib_metadata/_text.py +++ /dev/null @@ -1,99 +0,0 @@ -import re - -from ._functools import method_cache - - -# from jaraco.text 3.5 -class FoldedCase(str): - """ - A case insensitive string class; behaves just like str - except compares equal when the only variation is case. - - >>> s = FoldedCase('hello world') - - >>> s == 'Hello World' - True - - >>> 'Hello World' == s - True - - >>> s != 'Hello World' - False - - >>> s.index('O') - 4 - - >>> s.split('O') - ['hell', ' w', 'rld'] - - >>> sorted(map(FoldedCase, ['GAMMA', 'alpha', 'Beta'])) - ['alpha', 'Beta', 'GAMMA'] - - Sequence membership is straightforward. - - >>> "Hello World" in [s] - True - >>> s in ["Hello World"] - True - - You may test for set inclusion, but candidate and elements - must both be folded. - - >>> FoldedCase("Hello World") in {s} - True - >>> s in {FoldedCase("Hello World")} - True - - String inclusion works as long as the FoldedCase object - is on the right. - - >>> "hello" in FoldedCase("Hello World") - True - - But not if the FoldedCase object is on the left: - - >>> FoldedCase('hello') in 'Hello World' - False - - In that case, use in_: - - >>> FoldedCase('hello').in_('Hello World') - True - - >>> FoldedCase('hello') > FoldedCase('Hello') - False - """ - - def __lt__(self, other): - return self.lower() < other.lower() - - def __gt__(self, other): - return self.lower() > other.lower() - - def __eq__(self, other): - return self.lower() == other.lower() - - def __ne__(self, other): - return self.lower() != other.lower() - - def __hash__(self): - return hash(self.lower()) - - def __contains__(self, other): - return super().lower().__contains__(other.lower()) - - def in_(self, other): - "Does self appear in other?" - return self in FoldedCase(other) - - # cache lower since it's likely to be called frequently. - @method_cache - def lower(self): - return super().lower() - - def index(self, sub): - return self.lower().index(sub.lower()) - - def split(self, splitter=' ', maxsplit=0): - pattern = re.compile(re.escape(splitter), re.I) - return pattern.split(self, maxsplit) diff --git a/venv/lib/python3.9/site-packages/importlib_metadata/_typing.py b/venv/lib/python3.9/site-packages/importlib_metadata/_typing.py deleted file mode 100644 index 32b1d2b..0000000 --- a/venv/lib/python3.9/site-packages/importlib_metadata/_typing.py +++ /dev/null @@ -1,15 +0,0 @@ -import functools -import typing - -from ._meta import PackageMetadata - -md_none = functools.partial(typing.cast, PackageMetadata) -""" -Suppress type errors for optional metadata. - -Although Distribution.metadata can return None when metadata is corrupt -and thus None, allow callers to assume it's not None and crash if -that's the case. - -# python/importlib_metadata#493 -""" diff --git a/venv/lib/python3.9/site-packages/importlib_metadata/compat/__init__.py b/venv/lib/python3.9/site-packages/importlib_metadata/compat/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/venv/lib/python3.9/site-packages/importlib_metadata/compat/py311.py b/venv/lib/python3.9/site-packages/importlib_metadata/compat/py311.py deleted file mode 100644 index 3a53274..0000000 --- a/venv/lib/python3.9/site-packages/importlib_metadata/compat/py311.py +++ /dev/null @@ -1,22 +0,0 @@ -import os -import pathlib -import sys -import types - - -def wrap(path): # pragma: no cover - """ - Workaround for https://github.com/python/cpython/issues/84538 - to add backward compatibility for walk_up=True. - An example affected package is dask-labextension, which uses - jupyter-packaging to install JupyterLab javascript files outside - of site-packages. - """ - - def relative_to(root, *, walk_up=False): - return pathlib.Path(os.path.relpath(path, root)) - - return types.SimpleNamespace(relative_to=relative_to) - - -relative_fix = wrap if sys.version_info < (3, 12) else lambda x: x diff --git a/venv/lib/python3.9/site-packages/importlib_metadata/compat/py39.py b/venv/lib/python3.9/site-packages/importlib_metadata/compat/py39.py deleted file mode 100644 index 3eb9c01..0000000 --- a/venv/lib/python3.9/site-packages/importlib_metadata/compat/py39.py +++ /dev/null @@ -1,42 +0,0 @@ -""" -Compatibility layer with Python 3.8/3.9 -""" - -from __future__ import annotations - -from typing import TYPE_CHECKING, Any - -if TYPE_CHECKING: # pragma: no cover - # Prevent circular imports on runtime. - from .. import Distribution, EntryPoint -else: - Distribution = EntryPoint = Any - -from .._typing import md_none - - -def normalized_name(dist: Distribution) -> str | None: - """ - Honor name normalization for distributions that don't provide ``_normalized_name``. - """ - try: - return dist._normalized_name - except AttributeError: - from .. import Prepared # -> delay to prevent circular imports. - - return Prepared.normalize( - getattr(dist, "name", None) or md_none(dist.metadata)['Name'] - ) - - -def ep_matches(ep: EntryPoint, **params) -> bool: - """ - Workaround for ``EntryPoint`` objects without the ``matches`` method. - """ - try: - return ep.matches(**params) - except AttributeError: - from .. import EntryPoint # -> delay to prevent circular imports. - - # Reconstruct the EntryPoint object to make sure it is compatible. - return EntryPoint(ep.name, ep.value, ep.group).matches(**params) diff --git a/venv/lib/python3.9/site-packages/importlib_metadata/diagnose.py b/venv/lib/python3.9/site-packages/importlib_metadata/diagnose.py deleted file mode 100644 index e405471..0000000 --- a/venv/lib/python3.9/site-packages/importlib_metadata/diagnose.py +++ /dev/null @@ -1,21 +0,0 @@ -import sys - -from . import Distribution - - -def inspect(path): - print("Inspecting", path) - dists = list(Distribution.discover(path=[path])) - if not dists: - return - print("Found", len(dists), "packages:", end=' ') - print(', '.join(dist.name for dist in dists)) - - -def run(): - for path in sys.path: - inspect(path) - - -if __name__ == '__main__': - run() diff --git a/venv/lib/python3.9/site-packages/importlib_metadata/py.typed b/venv/lib/python3.9/site-packages/importlib_metadata/py.typed deleted file mode 100644 index e69de29..0000000 diff --git a/venv/lib/python3.9/site-packages/itsdangerous-2.2.0.dist-info/INSTALLER b/venv/lib/python3.9/site-packages/itsdangerous-2.2.0.dist-info/INSTALLER deleted file mode 100644 index a1b589e..0000000 --- a/venv/lib/python3.9/site-packages/itsdangerous-2.2.0.dist-info/INSTALLER +++ /dev/null @@ -1 +0,0 @@ -pip diff --git a/venv/lib/python3.9/site-packages/itsdangerous-2.2.0.dist-info/LICENSE.txt b/venv/lib/python3.9/site-packages/itsdangerous-2.2.0.dist-info/LICENSE.txt deleted file mode 100644 index 7b190ca..0000000 --- a/venv/lib/python3.9/site-packages/itsdangerous-2.2.0.dist-info/LICENSE.txt +++ /dev/null @@ -1,28 +0,0 @@ -Copyright 2011 Pallets - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - -1. Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - -2. Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - -3. Neither the name of the copyright holder nor the names of its - contributors may be used to endorse or promote products derived from - this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A -PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED -TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR -PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF -LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING -NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/venv/lib/python3.9/site-packages/itsdangerous-2.2.0.dist-info/METADATA b/venv/lib/python3.9/site-packages/itsdangerous-2.2.0.dist-info/METADATA deleted file mode 100644 index ddf5464..0000000 --- a/venv/lib/python3.9/site-packages/itsdangerous-2.2.0.dist-info/METADATA +++ /dev/null @@ -1,60 +0,0 @@ -Metadata-Version: 2.1 -Name: itsdangerous -Version: 2.2.0 -Summary: Safely pass data to untrusted environments and back. -Maintainer-email: Pallets -Requires-Python: >=3.8 -Description-Content-Type: text/markdown -Classifier: Development Status :: 5 - Production/Stable -Classifier: Intended Audience :: Developers -Classifier: License :: OSI Approved :: BSD License -Classifier: Operating System :: OS Independent -Classifier: Programming Language :: Python -Classifier: Typing :: Typed -Project-URL: Changes, https://itsdangerous.palletsprojects.com/changes/ -Project-URL: Chat, https://discord.gg/pallets -Project-URL: Documentation, https://itsdangerous.palletsprojects.com/ -Project-URL: Donate, https://palletsprojects.com/donate -Project-URL: Source, https://github.com/pallets/itsdangerous/ - -# ItsDangerous - -... so better sign this - -Various helpers to pass data to untrusted environments and to get it -back safe and sound. Data is cryptographically signed to ensure that a -token has not been tampered with. - -It's possible to customize how data is serialized. Data is compressed as -needed. A timestamp can be added and verified automatically while -loading a token. - - -## A Simple Example - -Here's how you could generate a token for transmitting a user's id and -name between web requests. - -```python -from itsdangerous import URLSafeSerializer -auth_s = URLSafeSerializer("secret key", "auth") -token = auth_s.dumps({"id": 5, "name": "itsdangerous"}) - -print(token) -# eyJpZCI6NSwibmFtZSI6Iml0c2Rhbmdlcm91cyJ9.6YP6T0BaO67XP--9UzTrmurXSmg - -data = auth_s.loads(token) -print(data["name"]) -# itsdangerous -``` - - -## Donate - -The Pallets organization develops and supports ItsDangerous and other -popular packages. In order to grow the community of contributors and -users, and allow the maintainers to devote more time to the projects, -[please donate today][]. - -[please donate today]: https://palletsprojects.com/donate - diff --git a/venv/lib/python3.9/site-packages/itsdangerous-2.2.0.dist-info/RECORD b/venv/lib/python3.9/site-packages/itsdangerous-2.2.0.dist-info/RECORD deleted file mode 100644 index 7c317e9..0000000 --- a/venv/lib/python3.9/site-packages/itsdangerous-2.2.0.dist-info/RECORD +++ /dev/null @@ -1,22 +0,0 @@ -itsdangerous-2.2.0.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 -itsdangerous-2.2.0.dist-info/LICENSE.txt,sha256=Y68JiRtr6K0aQlLtQ68PTvun_JSOIoNnvtfzxa4LCdc,1475 -itsdangerous-2.2.0.dist-info/METADATA,sha256=0rk0-1ZwihuU5DnwJVwPWoEI4yWOyCexih3JyZHblhE,1924 -itsdangerous-2.2.0.dist-info/RECORD,, -itsdangerous-2.2.0.dist-info/WHEEL,sha256=EZbGkh7Ie4PoZfRQ8I0ZuP9VklN_TvcZ6DSE5Uar4z4,81 -itsdangerous/__init__.py,sha256=4SK75sCe29xbRgQE1ZQtMHnKUuZYAf3bSpZOrff1IAY,1427 -itsdangerous/__pycache__/__init__.cpython-39.pyc,, -itsdangerous/__pycache__/_json.cpython-39.pyc,, -itsdangerous/__pycache__/encoding.cpython-39.pyc,, -itsdangerous/__pycache__/exc.cpython-39.pyc,, -itsdangerous/__pycache__/serializer.cpython-39.pyc,, -itsdangerous/__pycache__/signer.cpython-39.pyc,, -itsdangerous/__pycache__/timed.cpython-39.pyc,, -itsdangerous/__pycache__/url_safe.cpython-39.pyc,, -itsdangerous/_json.py,sha256=wPQGmge2yZ9328EHKF6gadGeyGYCJQKxtU-iLKE6UnA,473 -itsdangerous/encoding.py,sha256=wwTz5q_3zLcaAdunk6_vSoStwGqYWe307Zl_U87aRFM,1409 -itsdangerous/exc.py,sha256=Rr3exo0MRFEcPZltwecyK16VV1bE2K9_F1-d-ljcUn4,3201 -itsdangerous/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 -itsdangerous/serializer.py,sha256=PmdwADLqkSyQLZ0jOKAgDsAW4k_H0TlA71Ei3z0C5aI,15601 -itsdangerous/signer.py,sha256=YO0CV7NBvHA6j549REHJFUjUojw2pHqwcUpQnU7yNYQ,9647 -itsdangerous/timed.py,sha256=6RvDMqNumGMxf0-HlpaZdN9PUQQmRvrQGplKhxuivUs,8083 -itsdangerous/url_safe.py,sha256=az4e5fXi_vs-YbWj8YZwn4wiVKfeD--GEKRT5Ueu4P4,2505 diff --git a/venv/lib/python3.9/site-packages/itsdangerous-2.2.0.dist-info/WHEEL b/venv/lib/python3.9/site-packages/itsdangerous-2.2.0.dist-info/WHEEL deleted file mode 100644 index 3b5e64b..0000000 --- a/venv/lib/python3.9/site-packages/itsdangerous-2.2.0.dist-info/WHEEL +++ /dev/null @@ -1,4 +0,0 @@ -Wheel-Version: 1.0 -Generator: flit 3.9.0 -Root-Is-Purelib: true -Tag: py3-none-any diff --git a/venv/lib/python3.9/site-packages/itsdangerous/__init__.py b/venv/lib/python3.9/site-packages/itsdangerous/__init__.py deleted file mode 100644 index ea55256..0000000 --- a/venv/lib/python3.9/site-packages/itsdangerous/__init__.py +++ /dev/null @@ -1,38 +0,0 @@ -from __future__ import annotations - -import typing as t - -from .encoding import base64_decode as base64_decode -from .encoding import base64_encode as base64_encode -from .encoding import want_bytes as want_bytes -from .exc import BadData as BadData -from .exc import BadHeader as BadHeader -from .exc import BadPayload as BadPayload -from .exc import BadSignature as BadSignature -from .exc import BadTimeSignature as BadTimeSignature -from .exc import SignatureExpired as SignatureExpired -from .serializer import Serializer as Serializer -from .signer import HMACAlgorithm as HMACAlgorithm -from .signer import NoneAlgorithm as NoneAlgorithm -from .signer import Signer as Signer -from .timed import TimedSerializer as TimedSerializer -from .timed import TimestampSigner as TimestampSigner -from .url_safe import URLSafeSerializer as URLSafeSerializer -from .url_safe import URLSafeTimedSerializer as URLSafeTimedSerializer - - -def __getattr__(name: str) -> t.Any: - if name == "__version__": - import importlib.metadata - import warnings - - warnings.warn( - "The '__version__' attribute is deprecated and will be removed in" - " ItsDangerous 2.3. Use feature detection or" - " 'importlib.metadata.version(\"itsdangerous\")' instead.", - DeprecationWarning, - stacklevel=2, - ) - return importlib.metadata.version("itsdangerous") - - raise AttributeError(name) diff --git a/venv/lib/python3.9/site-packages/itsdangerous/_json.py b/venv/lib/python3.9/site-packages/itsdangerous/_json.py deleted file mode 100644 index fc23fea..0000000 --- a/venv/lib/python3.9/site-packages/itsdangerous/_json.py +++ /dev/null @@ -1,18 +0,0 @@ -from __future__ import annotations - -import json as _json -import typing as t - - -class _CompactJSON: - """Wrapper around json module that strips whitespace.""" - - @staticmethod - def loads(payload: str | bytes) -> t.Any: - return _json.loads(payload) - - @staticmethod - def dumps(obj: t.Any, **kwargs: t.Any) -> str: - kwargs.setdefault("ensure_ascii", False) - kwargs.setdefault("separators", (",", ":")) - return _json.dumps(obj, **kwargs) diff --git a/venv/lib/python3.9/site-packages/itsdangerous/encoding.py b/venv/lib/python3.9/site-packages/itsdangerous/encoding.py deleted file mode 100644 index f5ca80f..0000000 --- a/venv/lib/python3.9/site-packages/itsdangerous/encoding.py +++ /dev/null @@ -1,54 +0,0 @@ -from __future__ import annotations - -import base64 -import string -import struct -import typing as t - -from .exc import BadData - - -def want_bytes( - s: str | bytes, encoding: str = "utf-8", errors: str = "strict" -) -> bytes: - if isinstance(s, str): - s = s.encode(encoding, errors) - - return s - - -def base64_encode(string: str | bytes) -> bytes: - """Base64 encode a string of bytes or text. The resulting bytes are - safe to use in URLs. - """ - string = want_bytes(string) - return base64.urlsafe_b64encode(string).rstrip(b"=") - - -def base64_decode(string: str | bytes) -> bytes: - """Base64 decode a URL-safe string of bytes or text. The result is - bytes. - """ - string = want_bytes(string, encoding="ascii", errors="ignore") - string += b"=" * (-len(string) % 4) - - try: - return base64.urlsafe_b64decode(string) - except (TypeError, ValueError) as e: - raise BadData("Invalid base64-encoded data") from e - - -# The alphabet used by base64.urlsafe_* -_base64_alphabet = f"{string.ascii_letters}{string.digits}-_=".encode("ascii") - -_int64_struct = struct.Struct(">Q") -_int_to_bytes = _int64_struct.pack -_bytes_to_int = t.cast("t.Callable[[bytes], tuple[int]]", _int64_struct.unpack) - - -def int_to_bytes(num: int) -> bytes: - return _int_to_bytes(num).lstrip(b"\x00") - - -def bytes_to_int(bytestr: bytes) -> int: - return _bytes_to_int(bytestr.rjust(8, b"\x00"))[0] diff --git a/venv/lib/python3.9/site-packages/itsdangerous/exc.py b/venv/lib/python3.9/site-packages/itsdangerous/exc.py deleted file mode 100644 index a75adcd..0000000 --- a/venv/lib/python3.9/site-packages/itsdangerous/exc.py +++ /dev/null @@ -1,106 +0,0 @@ -from __future__ import annotations - -import typing as t -from datetime import datetime - - -class BadData(Exception): - """Raised if bad data of any sort was encountered. This is the base - for all exceptions that ItsDangerous defines. - - .. versionadded:: 0.15 - """ - - def __init__(self, message: str): - super().__init__(message) - self.message = message - - def __str__(self) -> str: - return self.message - - -class BadSignature(BadData): - """Raised if a signature does not match.""" - - def __init__(self, message: str, payload: t.Any | None = None): - super().__init__(message) - - #: The payload that failed the signature test. In some - #: situations you might still want to inspect this, even if - #: you know it was tampered with. - #: - #: .. versionadded:: 0.14 - self.payload: t.Any | None = payload - - -class BadTimeSignature(BadSignature): - """Raised if a time-based signature is invalid. This is a subclass - of :class:`BadSignature`. - """ - - def __init__( - self, - message: str, - payload: t.Any | None = None, - date_signed: datetime | None = None, - ): - super().__init__(message, payload) - - #: If the signature expired this exposes the date of when the - #: signature was created. This can be helpful in order to - #: tell the user how long a link has been gone stale. - #: - #: .. versionchanged:: 2.0 - #: The datetime value is timezone-aware rather than naive. - #: - #: .. versionadded:: 0.14 - self.date_signed = date_signed - - -class SignatureExpired(BadTimeSignature): - """Raised if a signature timestamp is older than ``max_age``. This - is a subclass of :exc:`BadTimeSignature`. - """ - - -class BadHeader(BadSignature): - """Raised if a signed header is invalid in some form. This only - happens for serializers that have a header that goes with the - signature. - - .. versionadded:: 0.24 - """ - - def __init__( - self, - message: str, - payload: t.Any | None = None, - header: t.Any | None = None, - original_error: Exception | None = None, - ): - super().__init__(message, payload) - - #: If the header is actually available but just malformed it - #: might be stored here. - self.header: t.Any | None = header - - #: If available, the error that indicates why the payload was - #: not valid. This might be ``None``. - self.original_error: Exception | None = original_error - - -class BadPayload(BadData): - """Raised if a payload is invalid. This could happen if the payload - is loaded despite an invalid signature, or if there is a mismatch - between the serializer and deserializer. The original exception - that occurred during loading is stored on as :attr:`original_error`. - - .. versionadded:: 0.15 - """ - - def __init__(self, message: str, original_error: Exception | None = None): - super().__init__(message) - - #: If available, the error that indicates why the payload was - #: not valid. This might be ``None``. - self.original_error: Exception | None = original_error diff --git a/venv/lib/python3.9/site-packages/itsdangerous/py.typed b/venv/lib/python3.9/site-packages/itsdangerous/py.typed deleted file mode 100644 index e69de29..0000000 diff --git a/venv/lib/python3.9/site-packages/itsdangerous/serializer.py b/venv/lib/python3.9/site-packages/itsdangerous/serializer.py deleted file mode 100644 index 5ddf387..0000000 --- a/venv/lib/python3.9/site-packages/itsdangerous/serializer.py +++ /dev/null @@ -1,406 +0,0 @@ -from __future__ import annotations - -import collections.abc as cabc -import json -import typing as t - -from .encoding import want_bytes -from .exc import BadPayload -from .exc import BadSignature -from .signer import _make_keys_list -from .signer import Signer - -if t.TYPE_CHECKING: - import typing_extensions as te - - # This should be either be str or bytes. To avoid having to specify the - # bound type, it falls back to a union if structural matching fails. - _TSerialized = te.TypeVar( - "_TSerialized", bound=t.Union[str, bytes], default=t.Union[str, bytes] - ) -else: - # Still available at runtime on Python < 3.13, but without the default. - _TSerialized = t.TypeVar("_TSerialized", bound=t.Union[str, bytes]) - - -class _PDataSerializer(t.Protocol[_TSerialized]): - def loads(self, payload: _TSerialized, /) -> t.Any: ... - # A signature with additional arguments is not handled correctly by type - # checkers right now, so an overload is used below for serializers that - # don't match this strict protocol. - def dumps(self, obj: t.Any, /) -> _TSerialized: ... - - -# Use TypeIs once it's available in typing_extensions or 3.13. -def is_text_serializer( - serializer: _PDataSerializer[t.Any], -) -> te.TypeGuard[_PDataSerializer[str]]: - """Checks whether a serializer generates text or binary.""" - return isinstance(serializer.dumps({}), str) - - -class Serializer(t.Generic[_TSerialized]): - """A serializer wraps a :class:`~itsdangerous.signer.Signer` to - enable serializing and securely signing data other than bytes. It - can unsign to verify that the data hasn't been changed. - - The serializer provides :meth:`dumps` and :meth:`loads`, similar to - :mod:`json`, and by default uses :mod:`json` internally to serialize - the data to bytes. - - The secret key should be a random string of ``bytes`` and should not - be saved to code or version control. Different salts should be used - to distinguish signing in different contexts. See :doc:`/concepts` - for information about the security of the secret key and salt. - - :param secret_key: The secret key to sign and verify with. Can be a - list of keys, oldest to newest, to support key rotation. - :param salt: Extra key to combine with ``secret_key`` to distinguish - signatures in different contexts. - :param serializer: An object that provides ``dumps`` and ``loads`` - methods for serializing data to a string. Defaults to - :attr:`default_serializer`, which defaults to :mod:`json`. - :param serializer_kwargs: Keyword arguments to pass when calling - ``serializer.dumps``. - :param signer: A ``Signer`` class to instantiate when signing data. - Defaults to :attr:`default_signer`, which defaults to - :class:`~itsdangerous.signer.Signer`. - :param signer_kwargs: Keyword arguments to pass when instantiating - the ``Signer`` class. - :param fallback_signers: List of signer parameters to try when - unsigning with the default signer fails. Each item can be a dict - of ``signer_kwargs``, a ``Signer`` class, or a tuple of - ``(signer, signer_kwargs)``. Defaults to - :attr:`default_fallback_signers`. - - .. versionchanged:: 2.0 - Added support for key rotation by passing a list to - ``secret_key``. - - .. versionchanged:: 2.0 - Removed the default SHA-512 fallback signer from - ``default_fallback_signers``. - - .. versionchanged:: 1.1 - Added support for ``fallback_signers`` and configured a default - SHA-512 fallback. This fallback is for users who used the yanked - 1.0.0 release which defaulted to SHA-512. - - .. versionchanged:: 0.14 - The ``signer`` and ``signer_kwargs`` parameters were added to - the constructor. - """ - - #: The default serialization module to use to serialize data to a - #: string internally. The default is :mod:`json`, but can be changed - #: to any object that provides ``dumps`` and ``loads`` methods. - default_serializer: _PDataSerializer[t.Any] = json - - #: The default ``Signer`` class to instantiate when signing data. - #: The default is :class:`itsdangerous.signer.Signer`. - default_signer: type[Signer] = Signer - - #: The default fallback signers to try when unsigning fails. - default_fallback_signers: list[ - dict[str, t.Any] | tuple[type[Signer], dict[str, t.Any]] | type[Signer] - ] = [] - - # Serializer[str] if no data serializer is provided, or if it returns str. - @t.overload - def __init__( - self: Serializer[str], - secret_key: str | bytes | cabc.Iterable[str] | cabc.Iterable[bytes], - salt: str | bytes | None = b"itsdangerous", - serializer: None | _PDataSerializer[str] = None, - serializer_kwargs: dict[str, t.Any] | None = None, - signer: type[Signer] | None = None, - signer_kwargs: dict[str, t.Any] | None = None, - fallback_signers: list[ - dict[str, t.Any] | tuple[type[Signer], dict[str, t.Any]] | type[Signer] - ] - | None = None, - ): ... - - # Serializer[bytes] with a bytes data serializer positional argument. - @t.overload - def __init__( - self: Serializer[bytes], - secret_key: str | bytes | cabc.Iterable[str] | cabc.Iterable[bytes], - salt: str | bytes | None, - serializer: _PDataSerializer[bytes], - serializer_kwargs: dict[str, t.Any] | None = None, - signer: type[Signer] | None = None, - signer_kwargs: dict[str, t.Any] | None = None, - fallback_signers: list[ - dict[str, t.Any] | tuple[type[Signer], dict[str, t.Any]] | type[Signer] - ] - | None = None, - ): ... - - # Serializer[bytes] with a bytes data serializer keyword argument. - @t.overload - def __init__( - self: Serializer[bytes], - secret_key: str | bytes | cabc.Iterable[str] | cabc.Iterable[bytes], - salt: str | bytes | None = b"itsdangerous", - *, - serializer: _PDataSerializer[bytes], - serializer_kwargs: dict[str, t.Any] | None = None, - signer: type[Signer] | None = None, - signer_kwargs: dict[str, t.Any] | None = None, - fallback_signers: list[ - dict[str, t.Any] | tuple[type[Signer], dict[str, t.Any]] | type[Signer] - ] - | None = None, - ): ... - - # Fall back with a positional argument. If the strict signature of - # _PDataSerializer doesn't match, fall back to a union, requiring the user - # to specify the type. - @t.overload - def __init__( - self, - secret_key: str | bytes | cabc.Iterable[str] | cabc.Iterable[bytes], - salt: str | bytes | None, - serializer: t.Any, - serializer_kwargs: dict[str, t.Any] | None = None, - signer: type[Signer] | None = None, - signer_kwargs: dict[str, t.Any] | None = None, - fallback_signers: list[ - dict[str, t.Any] | tuple[type[Signer], dict[str, t.Any]] | type[Signer] - ] - | None = None, - ): ... - - # Fall back with a keyword argument. - @t.overload - def __init__( - self, - secret_key: str | bytes | cabc.Iterable[str] | cabc.Iterable[bytes], - salt: str | bytes | None = b"itsdangerous", - *, - serializer: t.Any, - serializer_kwargs: dict[str, t.Any] | None = None, - signer: type[Signer] | None = None, - signer_kwargs: dict[str, t.Any] | None = None, - fallback_signers: list[ - dict[str, t.Any] | tuple[type[Signer], dict[str, t.Any]] | type[Signer] - ] - | None = None, - ): ... - - def __init__( - self, - secret_key: str | bytes | cabc.Iterable[str] | cabc.Iterable[bytes], - salt: str | bytes | None = b"itsdangerous", - serializer: t.Any | None = None, - serializer_kwargs: dict[str, t.Any] | None = None, - signer: type[Signer] | None = None, - signer_kwargs: dict[str, t.Any] | None = None, - fallback_signers: list[ - dict[str, t.Any] | tuple[type[Signer], dict[str, t.Any]] | type[Signer] - ] - | None = None, - ): - #: The list of secret keys to try for verifying signatures, from - #: oldest to newest. The newest (last) key is used for signing. - #: - #: This allows a key rotation system to keep a list of allowed - #: keys and remove expired ones. - self.secret_keys: list[bytes] = _make_keys_list(secret_key) - - if salt is not None: - salt = want_bytes(salt) - # if salt is None then the signer's default is used - - self.salt = salt - - if serializer is None: - serializer = self.default_serializer - - self.serializer: _PDataSerializer[_TSerialized] = serializer - self.is_text_serializer: bool = is_text_serializer(serializer) - - if signer is None: - signer = self.default_signer - - self.signer: type[Signer] = signer - self.signer_kwargs: dict[str, t.Any] = signer_kwargs or {} - - if fallback_signers is None: - fallback_signers = list(self.default_fallback_signers) - - self.fallback_signers: list[ - dict[str, t.Any] | tuple[type[Signer], dict[str, t.Any]] | type[Signer] - ] = fallback_signers - self.serializer_kwargs: dict[str, t.Any] = serializer_kwargs or {} - - @property - def secret_key(self) -> bytes: - """The newest (last) entry in the :attr:`secret_keys` list. This - is for compatibility from before key rotation support was added. - """ - return self.secret_keys[-1] - - def load_payload( - self, payload: bytes, serializer: _PDataSerializer[t.Any] | None = None - ) -> t.Any: - """Loads the encoded object. This function raises - :class:`.BadPayload` if the payload is not valid. The - ``serializer`` parameter can be used to override the serializer - stored on the class. The encoded ``payload`` should always be - bytes. - """ - if serializer is None: - use_serializer = self.serializer - is_text = self.is_text_serializer - else: - use_serializer = serializer - is_text = is_text_serializer(serializer) - - try: - if is_text: - return use_serializer.loads(payload.decode("utf-8")) # type: ignore[arg-type] - - return use_serializer.loads(payload) # type: ignore[arg-type] - except Exception as e: - raise BadPayload( - "Could not load the payload because an exception" - " occurred on unserializing the data.", - original_error=e, - ) from e - - def dump_payload(self, obj: t.Any) -> bytes: - """Dumps the encoded object. The return value is always bytes. - If the internal serializer returns text, the value will be - encoded as UTF-8. - """ - return want_bytes(self.serializer.dumps(obj, **self.serializer_kwargs)) - - def make_signer(self, salt: str | bytes | None = None) -> Signer: - """Creates a new instance of the signer to be used. The default - implementation uses the :class:`.Signer` base class. - """ - if salt is None: - salt = self.salt - - return self.signer(self.secret_keys, salt=salt, **self.signer_kwargs) - - def iter_unsigners(self, salt: str | bytes | None = None) -> cabc.Iterator[Signer]: - """Iterates over all signers to be tried for unsigning. Starts - with the configured signer, then constructs each signer - specified in ``fallback_signers``. - """ - if salt is None: - salt = self.salt - - yield self.make_signer(salt) - - for fallback in self.fallback_signers: - if isinstance(fallback, dict): - kwargs = fallback - fallback = self.signer - elif isinstance(fallback, tuple): - fallback, kwargs = fallback - else: - kwargs = self.signer_kwargs - - for secret_key in self.secret_keys: - yield fallback(secret_key, salt=salt, **kwargs) - - def dumps(self, obj: t.Any, salt: str | bytes | None = None) -> _TSerialized: - """Returns a signed string serialized with the internal - serializer. The return value can be either a byte or unicode - string depending on the format of the internal serializer. - """ - payload = want_bytes(self.dump_payload(obj)) - rv = self.make_signer(salt).sign(payload) - - if self.is_text_serializer: - return rv.decode("utf-8") # type: ignore[return-value] - - return rv # type: ignore[return-value] - - def dump(self, obj: t.Any, f: t.IO[t.Any], salt: str | bytes | None = None) -> None: - """Like :meth:`dumps` but dumps into a file. The file handle has - to be compatible with what the internal serializer expects. - """ - f.write(self.dumps(obj, salt)) - - def loads( - self, s: str | bytes, salt: str | bytes | None = None, **kwargs: t.Any - ) -> t.Any: - """Reverse of :meth:`dumps`. Raises :exc:`.BadSignature` if the - signature validation fails. - """ - s = want_bytes(s) - last_exception = None - - for signer in self.iter_unsigners(salt): - try: - return self.load_payload(signer.unsign(s)) - except BadSignature as err: - last_exception = err - - raise t.cast(BadSignature, last_exception) - - def load(self, f: t.IO[t.Any], salt: str | bytes | None = None) -> t.Any: - """Like :meth:`loads` but loads from a file.""" - return self.loads(f.read(), salt) - - def loads_unsafe( - self, s: str | bytes, salt: str | bytes | None = None - ) -> tuple[bool, t.Any]: - """Like :meth:`loads` but without verifying the signature. This - is potentially very dangerous to use depending on how your - serializer works. The return value is ``(signature_valid, - payload)`` instead of just the payload. The first item will be a - boolean that indicates if the signature is valid. This function - never fails. - - Use it for debugging only and if you know that your serializer - module is not exploitable (for example, do not use it with a - pickle serializer). - - .. versionadded:: 0.15 - """ - return self._loads_unsafe_impl(s, salt) - - def _loads_unsafe_impl( - self, - s: str | bytes, - salt: str | bytes | None, - load_kwargs: dict[str, t.Any] | None = None, - load_payload_kwargs: dict[str, t.Any] | None = None, - ) -> tuple[bool, t.Any]: - """Low level helper function to implement :meth:`loads_unsafe` - in serializer subclasses. - """ - if load_kwargs is None: - load_kwargs = {} - - try: - return True, self.loads(s, salt=salt, **load_kwargs) - except BadSignature as e: - if e.payload is None: - return False, None - - if load_payload_kwargs is None: - load_payload_kwargs = {} - - try: - return ( - False, - self.load_payload(e.payload, **load_payload_kwargs), - ) - except BadPayload: - return False, None - - def load_unsafe( - self, f: t.IO[t.Any], salt: str | bytes | None = None - ) -> tuple[bool, t.Any]: - """Like :meth:`loads_unsafe` but loads from a file. - - .. versionadded:: 0.15 - """ - return self.loads_unsafe(f.read(), salt=salt) diff --git a/venv/lib/python3.9/site-packages/itsdangerous/signer.py b/venv/lib/python3.9/site-packages/itsdangerous/signer.py deleted file mode 100644 index e324dc0..0000000 --- a/venv/lib/python3.9/site-packages/itsdangerous/signer.py +++ /dev/null @@ -1,266 +0,0 @@ -from __future__ import annotations - -import collections.abc as cabc -import hashlib -import hmac -import typing as t - -from .encoding import _base64_alphabet -from .encoding import base64_decode -from .encoding import base64_encode -from .encoding import want_bytes -from .exc import BadSignature - - -class SigningAlgorithm: - """Subclasses must implement :meth:`get_signature` to provide - signature generation functionality. - """ - - def get_signature(self, key: bytes, value: bytes) -> bytes: - """Returns the signature for the given key and value.""" - raise NotImplementedError() - - def verify_signature(self, key: bytes, value: bytes, sig: bytes) -> bool: - """Verifies the given signature matches the expected - signature. - """ - return hmac.compare_digest(sig, self.get_signature(key, value)) - - -class NoneAlgorithm(SigningAlgorithm): - """Provides an algorithm that does not perform any signing and - returns an empty signature. - """ - - def get_signature(self, key: bytes, value: bytes) -> bytes: - return b"" - - -def _lazy_sha1(string: bytes = b"") -> t.Any: - """Don't access ``hashlib.sha1`` until runtime. FIPS builds may not include - SHA-1, in which case the import and use as a default would fail before the - developer can configure something else. - """ - return hashlib.sha1(string) - - -class HMACAlgorithm(SigningAlgorithm): - """Provides signature generation using HMACs.""" - - #: The digest method to use with the MAC algorithm. This defaults to - #: SHA1, but can be changed to any other function in the hashlib - #: module. - default_digest_method: t.Any = staticmethod(_lazy_sha1) - - def __init__(self, digest_method: t.Any = None): - if digest_method is None: - digest_method = self.default_digest_method - - self.digest_method: t.Any = digest_method - - def get_signature(self, key: bytes, value: bytes) -> bytes: - mac = hmac.new(key, msg=value, digestmod=self.digest_method) - return mac.digest() - - -def _make_keys_list( - secret_key: str | bytes | cabc.Iterable[str] | cabc.Iterable[bytes], -) -> list[bytes]: - if isinstance(secret_key, (str, bytes)): - return [want_bytes(secret_key)] - - return [want_bytes(s) for s in secret_key] # pyright: ignore - - -class Signer: - """A signer securely signs bytes, then unsigns them to verify that - the value hasn't been changed. - - The secret key should be a random string of ``bytes`` and should not - be saved to code or version control. Different salts should be used - to distinguish signing in different contexts. See :doc:`/concepts` - for information about the security of the secret key and salt. - - :param secret_key: The secret key to sign and verify with. Can be a - list of keys, oldest to newest, to support key rotation. - :param salt: Extra key to combine with ``secret_key`` to distinguish - signatures in different contexts. - :param sep: Separator between the signature and value. - :param key_derivation: How to derive the signing key from the secret - key and salt. Possible values are ``concat``, ``django-concat``, - or ``hmac``. Defaults to :attr:`default_key_derivation`, which - defaults to ``django-concat``. - :param digest_method: Hash function to use when generating the HMAC - signature. Defaults to :attr:`default_digest_method`, which - defaults to :func:`hashlib.sha1`. Note that the security of the - hash alone doesn't apply when used intermediately in HMAC. - :param algorithm: A :class:`SigningAlgorithm` instance to use - instead of building a default :class:`HMACAlgorithm` with the - ``digest_method``. - - .. versionchanged:: 2.0 - Added support for key rotation by passing a list to - ``secret_key``. - - .. versionchanged:: 0.18 - ``algorithm`` was added as an argument to the class constructor. - - .. versionchanged:: 0.14 - ``key_derivation`` and ``digest_method`` were added as arguments - to the class constructor. - """ - - #: The default digest method to use for the signer. The default is - #: :func:`hashlib.sha1`, but can be changed to any :mod:`hashlib` or - #: compatible object. Note that the security of the hash alone - #: doesn't apply when used intermediately in HMAC. - #: - #: .. versionadded:: 0.14 - default_digest_method: t.Any = staticmethod(_lazy_sha1) - - #: The default scheme to use to derive the signing key from the - #: secret key and salt. The default is ``django-concat``. Possible - #: values are ``concat``, ``django-concat``, and ``hmac``. - #: - #: .. versionadded:: 0.14 - default_key_derivation: str = "django-concat" - - def __init__( - self, - secret_key: str | bytes | cabc.Iterable[str] | cabc.Iterable[bytes], - salt: str | bytes | None = b"itsdangerous.Signer", - sep: str | bytes = b".", - key_derivation: str | None = None, - digest_method: t.Any | None = None, - algorithm: SigningAlgorithm | None = None, - ): - #: The list of secret keys to try for verifying signatures, from - #: oldest to newest. The newest (last) key is used for signing. - #: - #: This allows a key rotation system to keep a list of allowed - #: keys and remove expired ones. - self.secret_keys: list[bytes] = _make_keys_list(secret_key) - self.sep: bytes = want_bytes(sep) - - if self.sep in _base64_alphabet: - raise ValueError( - "The given separator cannot be used because it may be" - " contained in the signature itself. ASCII letters," - " digits, and '-_=' must not be used." - ) - - if salt is not None: - salt = want_bytes(salt) - else: - salt = b"itsdangerous.Signer" - - self.salt = salt - - if key_derivation is None: - key_derivation = self.default_key_derivation - - self.key_derivation: str = key_derivation - - if digest_method is None: - digest_method = self.default_digest_method - - self.digest_method: t.Any = digest_method - - if algorithm is None: - algorithm = HMACAlgorithm(self.digest_method) - - self.algorithm: SigningAlgorithm = algorithm - - @property - def secret_key(self) -> bytes: - """The newest (last) entry in the :attr:`secret_keys` list. This - is for compatibility from before key rotation support was added. - """ - return self.secret_keys[-1] - - def derive_key(self, secret_key: str | bytes | None = None) -> bytes: - """This method is called to derive the key. The default key - derivation choices can be overridden here. Key derivation is not - intended to be used as a security method to make a complex key - out of a short password. Instead you should use large random - secret keys. - - :param secret_key: A specific secret key to derive from. - Defaults to the last item in :attr:`secret_keys`. - - .. versionchanged:: 2.0 - Added the ``secret_key`` parameter. - """ - if secret_key is None: - secret_key = self.secret_keys[-1] - else: - secret_key = want_bytes(secret_key) - - if self.key_derivation == "concat": - return t.cast(bytes, self.digest_method(self.salt + secret_key).digest()) - elif self.key_derivation == "django-concat": - return t.cast( - bytes, self.digest_method(self.salt + b"signer" + secret_key).digest() - ) - elif self.key_derivation == "hmac": - mac = hmac.new(secret_key, digestmod=self.digest_method) - mac.update(self.salt) - return mac.digest() - elif self.key_derivation == "none": - return secret_key - else: - raise TypeError("Unknown key derivation method") - - def get_signature(self, value: str | bytes) -> bytes: - """Returns the signature for the given value.""" - value = want_bytes(value) - key = self.derive_key() - sig = self.algorithm.get_signature(key, value) - return base64_encode(sig) - - def sign(self, value: str | bytes) -> bytes: - """Signs the given string.""" - value = want_bytes(value) - return value + self.sep + self.get_signature(value) - - def verify_signature(self, value: str | bytes, sig: str | bytes) -> bool: - """Verifies the signature for the given value.""" - try: - sig = base64_decode(sig) - except Exception: - return False - - value = want_bytes(value) - - for secret_key in reversed(self.secret_keys): - key = self.derive_key(secret_key) - - if self.algorithm.verify_signature(key, value, sig): - return True - - return False - - def unsign(self, signed_value: str | bytes) -> bytes: - """Unsigns the given string.""" - signed_value = want_bytes(signed_value) - - if self.sep not in signed_value: - raise BadSignature(f"No {self.sep!r} found in value") - - value, sig = signed_value.rsplit(self.sep, 1) - - if self.verify_signature(value, sig): - return value - - raise BadSignature(f"Signature {sig!r} does not match", payload=value) - - def validate(self, signed_value: str | bytes) -> bool: - """Only validates the given signed value. Returns ``True`` if - the signature exists and is valid. - """ - try: - self.unsign(signed_value) - return True - except BadSignature: - return False diff --git a/venv/lib/python3.9/site-packages/itsdangerous/timed.py b/venv/lib/python3.9/site-packages/itsdangerous/timed.py deleted file mode 100644 index 7384375..0000000 --- a/venv/lib/python3.9/site-packages/itsdangerous/timed.py +++ /dev/null @@ -1,228 +0,0 @@ -from __future__ import annotations - -import collections.abc as cabc -import time -import typing as t -from datetime import datetime -from datetime import timezone - -from .encoding import base64_decode -from .encoding import base64_encode -from .encoding import bytes_to_int -from .encoding import int_to_bytes -from .encoding import want_bytes -from .exc import BadSignature -from .exc import BadTimeSignature -from .exc import SignatureExpired -from .serializer import _TSerialized -from .serializer import Serializer -from .signer import Signer - - -class TimestampSigner(Signer): - """Works like the regular :class:`.Signer` but also records the time - of the signing and can be used to expire signatures. The - :meth:`unsign` method can raise :exc:`.SignatureExpired` if the - unsigning failed because the signature is expired. - """ - - def get_timestamp(self) -> int: - """Returns the current timestamp. The function must return an - integer. - """ - return int(time.time()) - - def timestamp_to_datetime(self, ts: int) -> datetime: - """Convert the timestamp from :meth:`get_timestamp` into an - aware :class`datetime.datetime` in UTC. - - .. versionchanged:: 2.0 - The timestamp is returned as a timezone-aware ``datetime`` - in UTC rather than a naive ``datetime`` assumed to be UTC. - """ - return datetime.fromtimestamp(ts, tz=timezone.utc) - - def sign(self, value: str | bytes) -> bytes: - """Signs the given string and also attaches time information.""" - value = want_bytes(value) - timestamp = base64_encode(int_to_bytes(self.get_timestamp())) - sep = want_bytes(self.sep) - value = value + sep + timestamp - return value + sep + self.get_signature(value) - - # Ignore overlapping signatures check, return_timestamp is the only - # parameter that affects the return type. - - @t.overload - def unsign( # type: ignore[overload-overlap] - self, - signed_value: str | bytes, - max_age: int | None = None, - return_timestamp: t.Literal[False] = False, - ) -> bytes: ... - - @t.overload - def unsign( - self, - signed_value: str | bytes, - max_age: int | None = None, - return_timestamp: t.Literal[True] = True, - ) -> tuple[bytes, datetime]: ... - - def unsign( - self, - signed_value: str | bytes, - max_age: int | None = None, - return_timestamp: bool = False, - ) -> tuple[bytes, datetime] | bytes: - """Works like the regular :meth:`.Signer.unsign` but can also - validate the time. See the base docstring of the class for - the general behavior. If ``return_timestamp`` is ``True`` the - timestamp of the signature will be returned as an aware - :class:`datetime.datetime` object in UTC. - - .. versionchanged:: 2.0 - The timestamp is returned as a timezone-aware ``datetime`` - in UTC rather than a naive ``datetime`` assumed to be UTC. - """ - try: - result = super().unsign(signed_value) - sig_error = None - except BadSignature as e: - sig_error = e - result = e.payload or b"" - - sep = want_bytes(self.sep) - - # If there is no timestamp in the result there is something - # seriously wrong. In case there was a signature error, we raise - # that one directly, otherwise we have a weird situation in - # which we shouldn't have come except someone uses a time-based - # serializer on non-timestamp data, so catch that. - if sep not in result: - if sig_error: - raise sig_error - - raise BadTimeSignature("timestamp missing", payload=result) - - value, ts_bytes = result.rsplit(sep, 1) - ts_int: int | None = None - ts_dt: datetime | None = None - - try: - ts_int = bytes_to_int(base64_decode(ts_bytes)) - except Exception: - pass - - # Signature is *not* okay. Raise a proper error now that we have - # split the value and the timestamp. - if sig_error is not None: - if ts_int is not None: - try: - ts_dt = self.timestamp_to_datetime(ts_int) - except (ValueError, OSError, OverflowError) as exc: - # Windows raises OSError - # 32-bit raises OverflowError - raise BadTimeSignature( - "Malformed timestamp", payload=value - ) from exc - - raise BadTimeSignature(str(sig_error), payload=value, date_signed=ts_dt) - - # Signature was okay but the timestamp is actually not there or - # malformed. Should not happen, but we handle it anyway. - if ts_int is None: - raise BadTimeSignature("Malformed timestamp", payload=value) - - # Check timestamp is not older than max_age - if max_age is not None: - age = self.get_timestamp() - ts_int - - if age > max_age: - raise SignatureExpired( - f"Signature age {age} > {max_age} seconds", - payload=value, - date_signed=self.timestamp_to_datetime(ts_int), - ) - - if age < 0: - raise SignatureExpired( - f"Signature age {age} < 0 seconds", - payload=value, - date_signed=self.timestamp_to_datetime(ts_int), - ) - - if return_timestamp: - return value, self.timestamp_to_datetime(ts_int) - - return value - - def validate(self, signed_value: str | bytes, max_age: int | None = None) -> bool: - """Only validates the given signed value. Returns ``True`` if - the signature exists and is valid.""" - try: - self.unsign(signed_value, max_age=max_age) - return True - except BadSignature: - return False - - -class TimedSerializer(Serializer[_TSerialized]): - """Uses :class:`TimestampSigner` instead of the default - :class:`.Signer`. - """ - - default_signer: type[TimestampSigner] = TimestampSigner - - def iter_unsigners( - self, salt: str | bytes | None = None - ) -> cabc.Iterator[TimestampSigner]: - return t.cast("cabc.Iterator[TimestampSigner]", super().iter_unsigners(salt)) - - # TODO: Signature is incompatible because parameters were added - # before salt. - - def loads( # type: ignore[override] - self, - s: str | bytes, - max_age: int | None = None, - return_timestamp: bool = False, - salt: str | bytes | None = None, - ) -> t.Any: - """Reverse of :meth:`dumps`, raises :exc:`.BadSignature` if the - signature validation fails. If a ``max_age`` is provided it will - ensure the signature is not older than that time in seconds. In - case the signature is outdated, :exc:`.SignatureExpired` is - raised. All arguments are forwarded to the signer's - :meth:`~TimestampSigner.unsign` method. - """ - s = want_bytes(s) - last_exception = None - - for signer in self.iter_unsigners(salt): - try: - base64d, timestamp = signer.unsign( - s, max_age=max_age, return_timestamp=True - ) - payload = self.load_payload(base64d) - - if return_timestamp: - return payload, timestamp - - return payload - except SignatureExpired: - # The signature was unsigned successfully but was - # expired. Do not try the next signer. - raise - except BadSignature as err: - last_exception = err - - raise t.cast(BadSignature, last_exception) - - def loads_unsafe( # type: ignore[override] - self, - s: str | bytes, - max_age: int | None = None, - salt: str | bytes | None = None, - ) -> tuple[bool, t.Any]: - return self._loads_unsafe_impl(s, salt, load_kwargs={"max_age": max_age}) diff --git a/venv/lib/python3.9/site-packages/itsdangerous/url_safe.py b/venv/lib/python3.9/site-packages/itsdangerous/url_safe.py deleted file mode 100644 index 56a0793..0000000 --- a/venv/lib/python3.9/site-packages/itsdangerous/url_safe.py +++ /dev/null @@ -1,83 +0,0 @@ -from __future__ import annotations - -import typing as t -import zlib - -from ._json import _CompactJSON -from .encoding import base64_decode -from .encoding import base64_encode -from .exc import BadPayload -from .serializer import _PDataSerializer -from .serializer import Serializer -from .timed import TimedSerializer - - -class URLSafeSerializerMixin(Serializer[str]): - """Mixed in with a regular serializer it will attempt to zlib - compress the string to make it shorter if necessary. It will also - base64 encode the string so that it can safely be placed in a URL. - """ - - default_serializer: _PDataSerializer[str] = _CompactJSON - - def load_payload( - self, - payload: bytes, - *args: t.Any, - serializer: t.Any | None = None, - **kwargs: t.Any, - ) -> t.Any: - decompress = False - - if payload.startswith(b"."): - payload = payload[1:] - decompress = True - - try: - json = base64_decode(payload) - except Exception as e: - raise BadPayload( - "Could not base64 decode the payload because of an exception", - original_error=e, - ) from e - - if decompress: - try: - json = zlib.decompress(json) - except Exception as e: - raise BadPayload( - "Could not zlib decompress the payload before decoding the payload", - original_error=e, - ) from e - - return super().load_payload(json, *args, **kwargs) - - def dump_payload(self, obj: t.Any) -> bytes: - json = super().dump_payload(obj) - is_compressed = False - compressed = zlib.compress(json) - - if len(compressed) < (len(json) - 1): - json = compressed - is_compressed = True - - base64d = base64_encode(json) - - if is_compressed: - base64d = b"." + base64d - - return base64d - - -class URLSafeSerializer(URLSafeSerializerMixin, Serializer[str]): - """Works like :class:`.Serializer` but dumps and loads into a URL - safe string consisting of the upper and lowercase character of the - alphabet as well as ``'_'``, ``'-'`` and ``'.'``. - """ - - -class URLSafeTimedSerializer(URLSafeSerializerMixin, TimedSerializer[str]): - """Works like :class:`.TimedSerializer` but dumps and loads into a - URL safe string consisting of the upper and lowercase character of - the alphabet as well as ``'_'``, ``'-'`` and ``'.'``. - """ diff --git a/venv/lib/python3.9/site-packages/jinja2-3.1.6.dist-info/INSTALLER b/venv/lib/python3.9/site-packages/jinja2-3.1.6.dist-info/INSTALLER deleted file mode 100644 index a1b589e..0000000 --- a/venv/lib/python3.9/site-packages/jinja2-3.1.6.dist-info/INSTALLER +++ /dev/null @@ -1 +0,0 @@ -pip diff --git a/venv/lib/python3.9/site-packages/jinja2-3.1.6.dist-info/METADATA b/venv/lib/python3.9/site-packages/jinja2-3.1.6.dist-info/METADATA deleted file mode 100644 index ffef2ff..0000000 --- a/venv/lib/python3.9/site-packages/jinja2-3.1.6.dist-info/METADATA +++ /dev/null @@ -1,84 +0,0 @@ -Metadata-Version: 2.4 -Name: Jinja2 -Version: 3.1.6 -Summary: A very fast and expressive template engine. -Maintainer-email: Pallets -Requires-Python: >=3.7 -Description-Content-Type: text/markdown -Classifier: Development Status :: 5 - Production/Stable -Classifier: Environment :: Web Environment -Classifier: Intended Audience :: Developers -Classifier: License :: OSI Approved :: BSD License -Classifier: Operating System :: OS Independent -Classifier: Programming Language :: Python -Classifier: Topic :: Internet :: WWW/HTTP :: Dynamic Content -Classifier: Topic :: Text Processing :: Markup :: HTML -Classifier: Typing :: Typed -License-File: LICENSE.txt -Requires-Dist: MarkupSafe>=2.0 -Requires-Dist: Babel>=2.7 ; extra == "i18n" -Project-URL: Changes, https://jinja.palletsprojects.com/changes/ -Project-URL: Chat, https://discord.gg/pallets -Project-URL: Documentation, https://jinja.palletsprojects.com/ -Project-URL: Donate, https://palletsprojects.com/donate -Project-URL: Source, https://github.com/pallets/jinja/ -Provides-Extra: i18n - -# Jinja - -Jinja is a fast, expressive, extensible templating engine. Special -placeholders in the template allow writing code similar to Python -syntax. Then the template is passed data to render the final document. - -It includes: - -- Template inheritance and inclusion. -- Define and import macros within templates. -- HTML templates can use autoescaping to prevent XSS from untrusted - user input. -- A sandboxed environment can safely render untrusted templates. -- AsyncIO support for generating templates and calling async - functions. -- I18N support with Babel. -- Templates are compiled to optimized Python code just-in-time and - cached, or can be compiled ahead-of-time. -- Exceptions point to the correct line in templates to make debugging - easier. -- Extensible filters, tests, functions, and even syntax. - -Jinja's philosophy is that while application logic belongs in Python if -possible, it shouldn't make the template designer's job difficult by -restricting functionality too much. - - -## In A Nutshell - -```jinja -{% extends "base.html" %} -{% block title %}Members{% endblock %} -{% block content %} - -{% endblock %} -``` - -## Donate - -The Pallets organization develops and supports Jinja and other popular -packages. In order to grow the community of contributors and users, and -allow the maintainers to devote more time to the projects, [please -donate today][]. - -[please donate today]: https://palletsprojects.com/donate - -## Contributing - -See our [detailed contributing documentation][contrib] for many ways to -contribute, including reporting issues, requesting features, asking or answering -questions, and making PRs. - -[contrib]: https://palletsprojects.com/contributing/ - diff --git a/venv/lib/python3.9/site-packages/jinja2-3.1.6.dist-info/RECORD b/venv/lib/python3.9/site-packages/jinja2-3.1.6.dist-info/RECORD deleted file mode 100644 index ea5876a..0000000 --- a/venv/lib/python3.9/site-packages/jinja2-3.1.6.dist-info/RECORD +++ /dev/null @@ -1,57 +0,0 @@ -jinja2-3.1.6.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 -jinja2-3.1.6.dist-info/METADATA,sha256=aMVUj7Z8QTKhOJjZsx7FDGvqKr3ZFdkh8hQ1XDpkmcg,2871 -jinja2-3.1.6.dist-info/RECORD,, -jinja2-3.1.6.dist-info/WHEEL,sha256=_2ozNFCLWc93bK4WKHCO-eDUENDlo-dgc9cU3qokYO4,82 -jinja2-3.1.6.dist-info/entry_points.txt,sha256=OL85gYU1eD8cuPlikifFngXpeBjaxl6rIJ8KkC_3r-I,58 -jinja2-3.1.6.dist-info/licenses/LICENSE.txt,sha256=O0nc7kEF6ze6wQ-vG-JgQI_oXSUrjp3y4JefweCUQ3s,1475 -jinja2/__init__.py,sha256=xxepO9i7DHsqkQrgBEduLtfoz2QCuT6_gbL4XSN1hbU,1928 -jinja2/__pycache__/__init__.cpython-39.pyc,, -jinja2/__pycache__/_identifier.cpython-39.pyc,, -jinja2/__pycache__/async_utils.cpython-39.pyc,, -jinja2/__pycache__/bccache.cpython-39.pyc,, -jinja2/__pycache__/compiler.cpython-39.pyc,, -jinja2/__pycache__/constants.cpython-39.pyc,, -jinja2/__pycache__/debug.cpython-39.pyc,, -jinja2/__pycache__/defaults.cpython-39.pyc,, -jinja2/__pycache__/environment.cpython-39.pyc,, -jinja2/__pycache__/exceptions.cpython-39.pyc,, -jinja2/__pycache__/ext.cpython-39.pyc,, -jinja2/__pycache__/filters.cpython-39.pyc,, -jinja2/__pycache__/idtracking.cpython-39.pyc,, -jinja2/__pycache__/lexer.cpython-39.pyc,, -jinja2/__pycache__/loaders.cpython-39.pyc,, -jinja2/__pycache__/meta.cpython-39.pyc,, -jinja2/__pycache__/nativetypes.cpython-39.pyc,, -jinja2/__pycache__/nodes.cpython-39.pyc,, -jinja2/__pycache__/optimizer.cpython-39.pyc,, -jinja2/__pycache__/parser.cpython-39.pyc,, -jinja2/__pycache__/runtime.cpython-39.pyc,, -jinja2/__pycache__/sandbox.cpython-39.pyc,, -jinja2/__pycache__/tests.cpython-39.pyc,, -jinja2/__pycache__/utils.cpython-39.pyc,, -jinja2/__pycache__/visitor.cpython-39.pyc,, -jinja2/_identifier.py,sha256=_zYctNKzRqlk_murTNlzrju1FFJL7Va_Ijqqd7ii2lU,1958 -jinja2/async_utils.py,sha256=vK-PdsuorOMnWSnEkT3iUJRIkTnYgO2T6MnGxDgHI5o,2834 -jinja2/bccache.py,sha256=gh0qs9rulnXo0PhX5jTJy2UHzI8wFnQ63o_vw7nhzRg,14061 -jinja2/compiler.py,sha256=9RpCQl5X88BHllJiPsHPh295Hh0uApvwFJNQuutULeM,74131 -jinja2/constants.py,sha256=GMoFydBF_kdpaRKPoM5cl5MviquVRLVyZtfp5-16jg0,1433 -jinja2/debug.py,sha256=CnHqCDHd-BVGvti_8ZsTolnXNhA3ECsY-6n_2pwU8Hw,6297 -jinja2/defaults.py,sha256=boBcSw78h-lp20YbaXSJsqkAI2uN_mD_TtCydpeq5wU,1267 -jinja2/environment.py,sha256=9nhrP7Ch-NbGX00wvyr4yy-uhNHq2OCc60ggGrni_fk,61513 -jinja2/exceptions.py,sha256=ioHeHrWwCWNaXX1inHmHVblvc4haO7AXsjCp3GfWvx0,5071 -jinja2/ext.py,sha256=5PF5eHfh8mXAIxXHHRB2xXbXohi8pE3nHSOxa66uS7E,31875 -jinja2/filters.py,sha256=PQ_Egd9n9jSgtnGQYyF4K5j2nYwhUIulhPnyimkdr-k,55212 -jinja2/idtracking.py,sha256=-ll5lIp73pML3ErUYiIJj7tdmWxcH_IlDv3yA_hiZYo,10555 -jinja2/lexer.py,sha256=LYiYio6br-Tep9nPcupWXsPEtjluw3p1mU-lNBVRUfk,29786 -jinja2/loaders.py,sha256=wIrnxjvcbqh5VwW28NSkfotiDq8qNCxIOSFbGUiSLB4,24055 -jinja2/meta.py,sha256=OTDPkaFvU2Hgvx-6akz7154F8BIWaRmvJcBFvwopHww,4397 -jinja2/nativetypes.py,sha256=7GIGALVJgdyL80oZJdQUaUfwSt5q2lSSZbXt0dNf_M4,4210 -jinja2/nodes.py,sha256=m1Duzcr6qhZI8JQ6VyJgUNinjAf5bQzijSmDnMsvUx8,34579 -jinja2/optimizer.py,sha256=rJnCRlQ7pZsEEmMhsQDgC_pKyDHxP5TPS6zVPGsgcu8,1651 -jinja2/parser.py,sha256=lLOFy3sEmHc5IaEHRiH1sQVnId2moUQzhyeJZTtdY30,40383 -jinja2/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 -jinja2/runtime.py,sha256=gDk-GvdriJXqgsGbHgrcKTP0Yp6zPXzhzrIpCFH3jAU,34249 -jinja2/sandbox.py,sha256=Mw2aitlY2I8la7FYhcX2YG9BtUYcLnD0Gh3d29cDWrY,15009 -jinja2/tests.py,sha256=VLsBhVFnWg-PxSBz1MhRnNWgP1ovXk3neO1FLQMeC9Q,5926 -jinja2/utils.py,sha256=rRp3o9e7ZKS4fyrWRbELyLcpuGVTFcnooaOa1qx_FIk,24129 -jinja2/visitor.py,sha256=EcnL1PIwf_4RVCOMxsRNuR8AXHbS1qfAdMOE2ngKJz4,3557 diff --git a/venv/lib/python3.9/site-packages/jinja2-3.1.6.dist-info/WHEEL b/venv/lib/python3.9/site-packages/jinja2-3.1.6.dist-info/WHEEL deleted file mode 100644 index 23d2d7e..0000000 --- a/venv/lib/python3.9/site-packages/jinja2-3.1.6.dist-info/WHEEL +++ /dev/null @@ -1,4 +0,0 @@ -Wheel-Version: 1.0 -Generator: flit 3.11.0 -Root-Is-Purelib: true -Tag: py3-none-any diff --git a/venv/lib/python3.9/site-packages/jinja2-3.1.6.dist-info/entry_points.txt b/venv/lib/python3.9/site-packages/jinja2-3.1.6.dist-info/entry_points.txt deleted file mode 100644 index abc3eae..0000000 --- a/venv/lib/python3.9/site-packages/jinja2-3.1.6.dist-info/entry_points.txt +++ /dev/null @@ -1,3 +0,0 @@ -[babel.extractors] -jinja2=jinja2.ext:babel_extract[i18n] - diff --git a/venv/lib/python3.9/site-packages/jinja2-3.1.6.dist-info/licenses/LICENSE.txt b/venv/lib/python3.9/site-packages/jinja2-3.1.6.dist-info/licenses/LICENSE.txt deleted file mode 100644 index c37cae4..0000000 --- a/venv/lib/python3.9/site-packages/jinja2-3.1.6.dist-info/licenses/LICENSE.txt +++ /dev/null @@ -1,28 +0,0 @@ -Copyright 2007 Pallets - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - -1. Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - -2. Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - -3. Neither the name of the copyright holder nor the names of its - contributors may be used to endorse or promote products derived from - this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A -PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED -TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR -PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF -LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING -NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/venv/lib/python3.9/site-packages/jinja2/__init__.py b/venv/lib/python3.9/site-packages/jinja2/__init__.py deleted file mode 100644 index 1a423a3..0000000 --- a/venv/lib/python3.9/site-packages/jinja2/__init__.py +++ /dev/null @@ -1,38 +0,0 @@ -"""Jinja is a template engine written in pure Python. It provides a -non-XML syntax that supports inline expressions and an optional -sandboxed environment. -""" - -from .bccache import BytecodeCache as BytecodeCache -from .bccache import FileSystemBytecodeCache as FileSystemBytecodeCache -from .bccache import MemcachedBytecodeCache as MemcachedBytecodeCache -from .environment import Environment as Environment -from .environment import Template as Template -from .exceptions import TemplateAssertionError as TemplateAssertionError -from .exceptions import TemplateError as TemplateError -from .exceptions import TemplateNotFound as TemplateNotFound -from .exceptions import TemplateRuntimeError as TemplateRuntimeError -from .exceptions import TemplatesNotFound as TemplatesNotFound -from .exceptions import TemplateSyntaxError as TemplateSyntaxError -from .exceptions import UndefinedError as UndefinedError -from .loaders import BaseLoader as BaseLoader -from .loaders import ChoiceLoader as ChoiceLoader -from .loaders import DictLoader as DictLoader -from .loaders import FileSystemLoader as FileSystemLoader -from .loaders import FunctionLoader as FunctionLoader -from .loaders import ModuleLoader as ModuleLoader -from .loaders import PackageLoader as PackageLoader -from .loaders import PrefixLoader as PrefixLoader -from .runtime import ChainableUndefined as ChainableUndefined -from .runtime import DebugUndefined as DebugUndefined -from .runtime import make_logging_undefined as make_logging_undefined -from .runtime import StrictUndefined as StrictUndefined -from .runtime import Undefined as Undefined -from .utils import clear_caches as clear_caches -from .utils import is_undefined as is_undefined -from .utils import pass_context as pass_context -from .utils import pass_environment as pass_environment -from .utils import pass_eval_context as pass_eval_context -from .utils import select_autoescape as select_autoescape - -__version__ = "3.1.6" diff --git a/venv/lib/python3.9/site-packages/jinja2/_identifier.py b/venv/lib/python3.9/site-packages/jinja2/_identifier.py deleted file mode 100644 index 928c150..0000000 --- a/venv/lib/python3.9/site-packages/jinja2/_identifier.py +++ /dev/null @@ -1,6 +0,0 @@ -import re - -# generated by scripts/generate_identifier_pattern.py -pattern = re.compile( - r"[\w·̀-ͯ·҃-֑҇-ׇֽֿׁׂׅׄؐ-ًؚ-ٰٟۖ-ۜ۟-۪ۤۧۨ-ܑۭܰ-݊ަ-ް߫-߽߳ࠖ-࠙ࠛ-ࠣࠥ-ࠧࠩ-࡙࠭-࡛࣓-ࣣ࣡-ःऺ-़ा-ॏ॑-ॗॢॣঁ-ঃ়া-ৄেৈো-্ৗৢৣ৾ਁ-ਃ਼ਾ-ੂੇੈੋ-੍ੑੰੱੵઁ-ઃ઼ા-ૅે-ૉો-્ૢૣૺ-૿ଁ-ଃ଼ା-ୄେୈୋ-୍ୖୗୢୣஂா-ூெ-ைொ-்ௗఀ-ఄా-ౄె-ైొ-్ౕౖౢౣಁ-ಃ಼ಾ-ೄೆ-ೈೊ-್ೕೖೢೣഀ-ഃ഻഼ാ-ൄെ-ൈൊ-്ൗൢൣංඃ්ා-ුූෘ-ෟෲෳัิ-ฺ็-๎ັິ-ູົຼ່-ໍ༹༘༙༵༷༾༿ཱ-྄྆྇ྍ-ྗྙ-ྼ࿆ါ-ှၖ-ၙၞ-ၠၢ-ၤၧ-ၭၱ-ၴႂ-ႍႏႚ-ႝ፝-፟ᜒ-᜔ᜲ-᜴ᝒᝓᝲᝳ឴-៓៝᠋-᠍ᢅᢆᢩᤠ-ᤫᤰ-᤻ᨗ-ᨛᩕ-ᩞ᩠-᩿᩼᪰-᪽ᬀ-ᬄ᬴-᭄᭫-᭳ᮀ-ᮂᮡ-ᮭ᯦-᯳ᰤ-᰷᳐-᳔᳒-᳨᳭ᳲ-᳴᳷-᳹᷀-᷹᷻-᷿‿⁀⁔⃐-⃥⃜⃡-⃰℘℮⳯-⵿⳱ⷠ-〪ⷿ-゙゚〯꙯ꙴ-꙽ꚞꚟ꛰꛱ꠂ꠆ꠋꠣ-ꠧꢀꢁꢴ-ꣅ꣠-꣱ꣿꤦ-꤭ꥇ-꥓ꦀ-ꦃ꦳-꧀ꧥꨩ-ꨶꩃꩌꩍꩻ-ꩽꪰꪲ-ꪴꪷꪸꪾ꪿꫁ꫫ-ꫯꫵ꫶ꯣ-ꯪ꯬꯭ﬞ︀-️︠-︯︳︴﹍-﹏_𐇽𐋠𐍶-𐍺𐨁-𐨃𐨅𐨆𐨌-𐨏𐨸-𐨿𐨺𐫦𐫥𐴤-𐽆𐴧-𐽐𑀀-𑀂𑀸-𑁆𑁿-𑂂𑂰-𑂺𑄀-𑄂𑄧-𑄴𑅅𑅆𑅳𑆀-𑆂𑆳-𑇀𑇉-𑇌𑈬-𑈷𑈾𑋟-𑋪𑌀-𑌃𑌻𑌼𑌾-𑍄𑍇𑍈𑍋-𑍍𑍗𑍢𑍣𑍦-𑍬𑍰-𑍴𑐵-𑑆𑑞𑒰-𑓃𑖯-𑖵𑖸-𑗀𑗜𑗝𑘰-𑙀𑚫-𑚷𑜝-𑜫𑠬-𑠺𑨁-𑨊𑨳-𑨹𑨻-𑨾𑩇𑩑-𑩛𑪊-𑪙𑰯-𑰶𑰸-𑰿𑲒-𑲧𑲩-𑲶𑴱-𑴶𑴺𑴼𑴽𑴿-𑵅𑵇𑶊-𑶎𑶐𑶑𑶓-𑶗𑻳-𑻶𖫰-𖫴𖬰-𖬶𖽑-𖽾𖾏-𖾒𛲝𛲞𝅥-𝅩𝅭-𝅲𝅻-𝆂𝆅-𝆋𝆪-𝆭𝉂-𝉄𝨀-𝨶𝨻-𝩬𝩵𝪄𝪛-𝪟𝪡-𝪯𞀀-𞀆𞀈-𞀘𞀛-𞀡𞀣𞀤𞀦-𞣐𞀪-𞣖𞥄-𞥊󠄀-󠇯]+" # noqa: B950 -) diff --git a/venv/lib/python3.9/site-packages/jinja2/async_utils.py b/venv/lib/python3.9/site-packages/jinja2/async_utils.py deleted file mode 100644 index f0c1402..0000000 --- a/venv/lib/python3.9/site-packages/jinja2/async_utils.py +++ /dev/null @@ -1,99 +0,0 @@ -import inspect -import typing as t -from functools import WRAPPER_ASSIGNMENTS -from functools import wraps - -from .utils import _PassArg -from .utils import pass_eval_context - -if t.TYPE_CHECKING: - import typing_extensions as te - -V = t.TypeVar("V") - - -def async_variant(normal_func): # type: ignore - def decorator(async_func): # type: ignore - pass_arg = _PassArg.from_obj(normal_func) - need_eval_context = pass_arg is None - - if pass_arg is _PassArg.environment: - - def is_async(args: t.Any) -> bool: - return t.cast(bool, args[0].is_async) - - else: - - def is_async(args: t.Any) -> bool: - return t.cast(bool, args[0].environment.is_async) - - # Take the doc and annotations from the sync function, but the - # name from the async function. Pallets-Sphinx-Themes - # build_function_directive expects __wrapped__ to point to the - # sync function. - async_func_attrs = ("__module__", "__name__", "__qualname__") - normal_func_attrs = tuple(set(WRAPPER_ASSIGNMENTS).difference(async_func_attrs)) - - @wraps(normal_func, assigned=normal_func_attrs) - @wraps(async_func, assigned=async_func_attrs, updated=()) - def wrapper(*args, **kwargs): # type: ignore - b = is_async(args) - - if need_eval_context: - args = args[1:] - - if b: - return async_func(*args, **kwargs) - - return normal_func(*args, **kwargs) - - if need_eval_context: - wrapper = pass_eval_context(wrapper) - - wrapper.jinja_async_variant = True # type: ignore[attr-defined] - return wrapper - - return decorator - - -_common_primitives = {int, float, bool, str, list, dict, tuple, type(None)} - - -async def auto_await(value: t.Union[t.Awaitable["V"], "V"]) -> "V": - # Avoid a costly call to isawaitable - if type(value) in _common_primitives: - return t.cast("V", value) - - if inspect.isawaitable(value): - return await t.cast("t.Awaitable[V]", value) - - return value - - -class _IteratorToAsyncIterator(t.Generic[V]): - def __init__(self, iterator: "t.Iterator[V]"): - self._iterator = iterator - - def __aiter__(self) -> "te.Self": - return self - - async def __anext__(self) -> V: - try: - return next(self._iterator) - except StopIteration as e: - raise StopAsyncIteration(e.value) from e - - -def auto_aiter( - iterable: "t.Union[t.AsyncIterable[V], t.Iterable[V]]", -) -> "t.AsyncIterator[V]": - if hasattr(iterable, "__aiter__"): - return iterable.__aiter__() - else: - return _IteratorToAsyncIterator(iter(iterable)) - - -async def auto_to_list( - value: "t.Union[t.AsyncIterable[V], t.Iterable[V]]", -) -> t.List["V"]: - return [x async for x in auto_aiter(value)] diff --git a/venv/lib/python3.9/site-packages/jinja2/bccache.py b/venv/lib/python3.9/site-packages/jinja2/bccache.py deleted file mode 100644 index ada8b09..0000000 --- a/venv/lib/python3.9/site-packages/jinja2/bccache.py +++ /dev/null @@ -1,408 +0,0 @@ -"""The optional bytecode cache system. This is useful if you have very -complex template situations and the compilation of all those templates -slows down your application too much. - -Situations where this is useful are often forking web applications that -are initialized on the first request. -""" - -import errno -import fnmatch -import marshal -import os -import pickle -import stat -import sys -import tempfile -import typing as t -from hashlib import sha1 -from io import BytesIO -from types import CodeType - -if t.TYPE_CHECKING: - import typing_extensions as te - - from .environment import Environment - - class _MemcachedClient(te.Protocol): - def get(self, key: str) -> bytes: ... - - def set( - self, key: str, value: bytes, timeout: t.Optional[int] = None - ) -> None: ... - - -bc_version = 5 -# Magic bytes to identify Jinja bytecode cache files. Contains the -# Python major and minor version to avoid loading incompatible bytecode -# if a project upgrades its Python version. -bc_magic = ( - b"j2" - + pickle.dumps(bc_version, 2) - + pickle.dumps((sys.version_info[0] << 24) | sys.version_info[1], 2) -) - - -class Bucket: - """Buckets are used to store the bytecode for one template. It's created - and initialized by the bytecode cache and passed to the loading functions. - - The buckets get an internal checksum from the cache assigned and use this - to automatically reject outdated cache material. Individual bytecode - cache subclasses don't have to care about cache invalidation. - """ - - def __init__(self, environment: "Environment", key: str, checksum: str) -> None: - self.environment = environment - self.key = key - self.checksum = checksum - self.reset() - - def reset(self) -> None: - """Resets the bucket (unloads the bytecode).""" - self.code: t.Optional[CodeType] = None - - def load_bytecode(self, f: t.BinaryIO) -> None: - """Loads bytecode from a file or file like object.""" - # make sure the magic header is correct - magic = f.read(len(bc_magic)) - if magic != bc_magic: - self.reset() - return - # the source code of the file changed, we need to reload - checksum = pickle.load(f) - if self.checksum != checksum: - self.reset() - return - # if marshal_load fails then we need to reload - try: - self.code = marshal.load(f) - except (EOFError, ValueError, TypeError): - self.reset() - return - - def write_bytecode(self, f: t.IO[bytes]) -> None: - """Dump the bytecode into the file or file like object passed.""" - if self.code is None: - raise TypeError("can't write empty bucket") - f.write(bc_magic) - pickle.dump(self.checksum, f, 2) - marshal.dump(self.code, f) - - def bytecode_from_string(self, string: bytes) -> None: - """Load bytecode from bytes.""" - self.load_bytecode(BytesIO(string)) - - def bytecode_to_string(self) -> bytes: - """Return the bytecode as bytes.""" - out = BytesIO() - self.write_bytecode(out) - return out.getvalue() - - -class BytecodeCache: - """To implement your own bytecode cache you have to subclass this class - and override :meth:`load_bytecode` and :meth:`dump_bytecode`. Both of - these methods are passed a :class:`~jinja2.bccache.Bucket`. - - A very basic bytecode cache that saves the bytecode on the file system:: - - from os import path - - class MyCache(BytecodeCache): - - def __init__(self, directory): - self.directory = directory - - def load_bytecode(self, bucket): - filename = path.join(self.directory, bucket.key) - if path.exists(filename): - with open(filename, 'rb') as f: - bucket.load_bytecode(f) - - def dump_bytecode(self, bucket): - filename = path.join(self.directory, bucket.key) - with open(filename, 'wb') as f: - bucket.write_bytecode(f) - - A more advanced version of a filesystem based bytecode cache is part of - Jinja. - """ - - def load_bytecode(self, bucket: Bucket) -> None: - """Subclasses have to override this method to load bytecode into a - bucket. If they are not able to find code in the cache for the - bucket, it must not do anything. - """ - raise NotImplementedError() - - def dump_bytecode(self, bucket: Bucket) -> None: - """Subclasses have to override this method to write the bytecode - from a bucket back to the cache. If it unable to do so it must not - fail silently but raise an exception. - """ - raise NotImplementedError() - - def clear(self) -> None: - """Clears the cache. This method is not used by Jinja but should be - implemented to allow applications to clear the bytecode cache used - by a particular environment. - """ - - def get_cache_key( - self, name: str, filename: t.Optional[t.Union[str]] = None - ) -> str: - """Returns the unique hash key for this template name.""" - hash = sha1(name.encode("utf-8")) - - if filename is not None: - hash.update(f"|{filename}".encode()) - - return hash.hexdigest() - - def get_source_checksum(self, source: str) -> str: - """Returns a checksum for the source.""" - return sha1(source.encode("utf-8")).hexdigest() - - def get_bucket( - self, - environment: "Environment", - name: str, - filename: t.Optional[str], - source: str, - ) -> Bucket: - """Return a cache bucket for the given template. All arguments are - mandatory but filename may be `None`. - """ - key = self.get_cache_key(name, filename) - checksum = self.get_source_checksum(source) - bucket = Bucket(environment, key, checksum) - self.load_bytecode(bucket) - return bucket - - def set_bucket(self, bucket: Bucket) -> None: - """Put the bucket into the cache.""" - self.dump_bytecode(bucket) - - -class FileSystemBytecodeCache(BytecodeCache): - """A bytecode cache that stores bytecode on the filesystem. It accepts - two arguments: The directory where the cache items are stored and a - pattern string that is used to build the filename. - - If no directory is specified a default cache directory is selected. On - Windows the user's temp directory is used, on UNIX systems a directory - is created for the user in the system temp directory. - - The pattern can be used to have multiple separate caches operate on the - same directory. The default pattern is ``'__jinja2_%s.cache'``. ``%s`` - is replaced with the cache key. - - >>> bcc = FileSystemBytecodeCache('/tmp/jinja_cache', '%s.cache') - - This bytecode cache supports clearing of the cache using the clear method. - """ - - def __init__( - self, directory: t.Optional[str] = None, pattern: str = "__jinja2_%s.cache" - ) -> None: - if directory is None: - directory = self._get_default_cache_dir() - self.directory = directory - self.pattern = pattern - - def _get_default_cache_dir(self) -> str: - def _unsafe_dir() -> "te.NoReturn": - raise RuntimeError( - "Cannot determine safe temp directory. You " - "need to explicitly provide one." - ) - - tmpdir = tempfile.gettempdir() - - # On windows the temporary directory is used specific unless - # explicitly forced otherwise. We can just use that. - if os.name == "nt": - return tmpdir - if not hasattr(os, "getuid"): - _unsafe_dir() - - dirname = f"_jinja2-cache-{os.getuid()}" - actual_dir = os.path.join(tmpdir, dirname) - - try: - os.mkdir(actual_dir, stat.S_IRWXU) - except OSError as e: - if e.errno != errno.EEXIST: - raise - try: - os.chmod(actual_dir, stat.S_IRWXU) - actual_dir_stat = os.lstat(actual_dir) - if ( - actual_dir_stat.st_uid != os.getuid() - or not stat.S_ISDIR(actual_dir_stat.st_mode) - or stat.S_IMODE(actual_dir_stat.st_mode) != stat.S_IRWXU - ): - _unsafe_dir() - except OSError as e: - if e.errno != errno.EEXIST: - raise - - actual_dir_stat = os.lstat(actual_dir) - if ( - actual_dir_stat.st_uid != os.getuid() - or not stat.S_ISDIR(actual_dir_stat.st_mode) - or stat.S_IMODE(actual_dir_stat.st_mode) != stat.S_IRWXU - ): - _unsafe_dir() - - return actual_dir - - def _get_cache_filename(self, bucket: Bucket) -> str: - return os.path.join(self.directory, self.pattern % (bucket.key,)) - - def load_bytecode(self, bucket: Bucket) -> None: - filename = self._get_cache_filename(bucket) - - # Don't test for existence before opening the file, since the - # file could disappear after the test before the open. - try: - f = open(filename, "rb") - except (FileNotFoundError, IsADirectoryError, PermissionError): - # PermissionError can occur on Windows when an operation is - # in progress, such as calling clear(). - return - - with f: - bucket.load_bytecode(f) - - def dump_bytecode(self, bucket: Bucket) -> None: - # Write to a temporary file, then rename to the real name after - # writing. This avoids another process reading the file before - # it is fully written. - name = self._get_cache_filename(bucket) - f = tempfile.NamedTemporaryFile( - mode="wb", - dir=os.path.dirname(name), - prefix=os.path.basename(name), - suffix=".tmp", - delete=False, - ) - - def remove_silent() -> None: - try: - os.remove(f.name) - except OSError: - # Another process may have called clear(). On Windows, - # another program may be holding the file open. - pass - - try: - with f: - bucket.write_bytecode(f) - except BaseException: - remove_silent() - raise - - try: - os.replace(f.name, name) - except OSError: - # Another process may have called clear(). On Windows, - # another program may be holding the file open. - remove_silent() - except BaseException: - remove_silent() - raise - - def clear(self) -> None: - # imported lazily here because google app-engine doesn't support - # write access on the file system and the function does not exist - # normally. - from os import remove - - files = fnmatch.filter(os.listdir(self.directory), self.pattern % ("*",)) - for filename in files: - try: - remove(os.path.join(self.directory, filename)) - except OSError: - pass - - -class MemcachedBytecodeCache(BytecodeCache): - """This class implements a bytecode cache that uses a memcache cache for - storing the information. It does not enforce a specific memcache library - (tummy's memcache or cmemcache) but will accept any class that provides - the minimal interface required. - - Libraries compatible with this class: - - - `cachelib `_ - - `python-memcached `_ - - (Unfortunately the django cache interface is not compatible because it - does not support storing binary data, only text. You can however pass - the underlying cache client to the bytecode cache which is available - as `django.core.cache.cache._client`.) - - The minimal interface for the client passed to the constructor is this: - - .. class:: MinimalClientInterface - - .. method:: set(key, value[, timeout]) - - Stores the bytecode in the cache. `value` is a string and - `timeout` the timeout of the key. If timeout is not provided - a default timeout or no timeout should be assumed, if it's - provided it's an integer with the number of seconds the cache - item should exist. - - .. method:: get(key) - - Returns the value for the cache key. If the item does not - exist in the cache the return value must be `None`. - - The other arguments to the constructor are the prefix for all keys that - is added before the actual cache key and the timeout for the bytecode in - the cache system. We recommend a high (or no) timeout. - - This bytecode cache does not support clearing of used items in the cache. - The clear method is a no-operation function. - - .. versionadded:: 2.7 - Added support for ignoring memcache errors through the - `ignore_memcache_errors` parameter. - """ - - def __init__( - self, - client: "_MemcachedClient", - prefix: str = "jinja2/bytecode/", - timeout: t.Optional[int] = None, - ignore_memcache_errors: bool = True, - ): - self.client = client - self.prefix = prefix - self.timeout = timeout - self.ignore_memcache_errors = ignore_memcache_errors - - def load_bytecode(self, bucket: Bucket) -> None: - try: - code = self.client.get(self.prefix + bucket.key) - except Exception: - if not self.ignore_memcache_errors: - raise - else: - bucket.bytecode_from_string(code) - - def dump_bytecode(self, bucket: Bucket) -> None: - key = self.prefix + bucket.key - value = bucket.bytecode_to_string() - - try: - if self.timeout is not None: - self.client.set(key, value, self.timeout) - else: - self.client.set(key, value) - except Exception: - if not self.ignore_memcache_errors: - raise diff --git a/venv/lib/python3.9/site-packages/jinja2/compiler.py b/venv/lib/python3.9/site-packages/jinja2/compiler.py deleted file mode 100644 index a4ff6a1..0000000 --- a/venv/lib/python3.9/site-packages/jinja2/compiler.py +++ /dev/null @@ -1,1998 +0,0 @@ -"""Compiles nodes from the parser into Python code.""" - -import typing as t -from contextlib import contextmanager -from functools import update_wrapper -from io import StringIO -from itertools import chain -from keyword import iskeyword as is_python_keyword - -from markupsafe import escape -from markupsafe import Markup - -from . import nodes -from .exceptions import TemplateAssertionError -from .idtracking import Symbols -from .idtracking import VAR_LOAD_ALIAS -from .idtracking import VAR_LOAD_PARAMETER -from .idtracking import VAR_LOAD_RESOLVE -from .idtracking import VAR_LOAD_UNDEFINED -from .nodes import EvalContext -from .optimizer import Optimizer -from .utils import _PassArg -from .utils import concat -from .visitor import NodeVisitor - -if t.TYPE_CHECKING: - import typing_extensions as te - - from .environment import Environment - -F = t.TypeVar("F", bound=t.Callable[..., t.Any]) - -operators = { - "eq": "==", - "ne": "!=", - "gt": ">", - "gteq": ">=", - "lt": "<", - "lteq": "<=", - "in": "in", - "notin": "not in", -} - - -def optimizeconst(f: F) -> F: - def new_func( - self: "CodeGenerator", node: nodes.Expr, frame: "Frame", **kwargs: t.Any - ) -> t.Any: - # Only optimize if the frame is not volatile - if self.optimizer is not None and not frame.eval_ctx.volatile: - new_node = self.optimizer.visit(node, frame.eval_ctx) - - if new_node != node: - return self.visit(new_node, frame) - - return f(self, node, frame, **kwargs) - - return update_wrapper(new_func, f) # type: ignore[return-value] - - -def _make_binop(op: str) -> t.Callable[["CodeGenerator", nodes.BinExpr, "Frame"], None]: - @optimizeconst - def visitor(self: "CodeGenerator", node: nodes.BinExpr, frame: Frame) -> None: - if ( - self.environment.sandboxed and op in self.environment.intercepted_binops # type: ignore - ): - self.write(f"environment.call_binop(context, {op!r}, ") - self.visit(node.left, frame) - self.write(", ") - self.visit(node.right, frame) - else: - self.write("(") - self.visit(node.left, frame) - self.write(f" {op} ") - self.visit(node.right, frame) - - self.write(")") - - return visitor - - -def _make_unop( - op: str, -) -> t.Callable[["CodeGenerator", nodes.UnaryExpr, "Frame"], None]: - @optimizeconst - def visitor(self: "CodeGenerator", node: nodes.UnaryExpr, frame: Frame) -> None: - if ( - self.environment.sandboxed and op in self.environment.intercepted_unops # type: ignore - ): - self.write(f"environment.call_unop(context, {op!r}, ") - self.visit(node.node, frame) - else: - self.write("(" + op) - self.visit(node.node, frame) - - self.write(")") - - return visitor - - -def generate( - node: nodes.Template, - environment: "Environment", - name: t.Optional[str], - filename: t.Optional[str], - stream: t.Optional[t.TextIO] = None, - defer_init: bool = False, - optimized: bool = True, -) -> t.Optional[str]: - """Generate the python source for a node tree.""" - if not isinstance(node, nodes.Template): - raise TypeError("Can't compile non template nodes") - - generator = environment.code_generator_class( - environment, name, filename, stream, defer_init, optimized - ) - generator.visit(node) - - if stream is None: - return generator.stream.getvalue() # type: ignore - - return None - - -def has_safe_repr(value: t.Any) -> bool: - """Does the node have a safe representation?""" - if value is None or value is NotImplemented or value is Ellipsis: - return True - - if type(value) in {bool, int, float, complex, range, str, Markup}: - return True - - if type(value) in {tuple, list, set, frozenset}: - return all(has_safe_repr(v) for v in value) - - if type(value) is dict: # noqa E721 - return all(has_safe_repr(k) and has_safe_repr(v) for k, v in value.items()) - - return False - - -def find_undeclared( - nodes: t.Iterable[nodes.Node], names: t.Iterable[str] -) -> t.Set[str]: - """Check if the names passed are accessed undeclared. The return value - is a set of all the undeclared names from the sequence of names found. - """ - visitor = UndeclaredNameVisitor(names) - try: - for node in nodes: - visitor.visit(node) - except VisitorExit: - pass - return visitor.undeclared - - -class MacroRef: - def __init__(self, node: t.Union[nodes.Macro, nodes.CallBlock]) -> None: - self.node = node - self.accesses_caller = False - self.accesses_kwargs = False - self.accesses_varargs = False - - -class Frame: - """Holds compile time information for us.""" - - def __init__( - self, - eval_ctx: EvalContext, - parent: t.Optional["Frame"] = None, - level: t.Optional[int] = None, - ) -> None: - self.eval_ctx = eval_ctx - - # the parent of this frame - self.parent = parent - - if parent is None: - self.symbols = Symbols(level=level) - - # in some dynamic inheritance situations the compiler needs to add - # write tests around output statements. - self.require_output_check = False - - # inside some tags we are using a buffer rather than yield statements. - # this for example affects {% filter %} or {% macro %}. If a frame - # is buffered this variable points to the name of the list used as - # buffer. - self.buffer: t.Optional[str] = None - - # the name of the block we're in, otherwise None. - self.block: t.Optional[str] = None - - else: - self.symbols = Symbols(parent.symbols, level=level) - self.require_output_check = parent.require_output_check - self.buffer = parent.buffer - self.block = parent.block - - # a toplevel frame is the root + soft frames such as if conditions. - self.toplevel = False - - # the root frame is basically just the outermost frame, so no if - # conditions. This information is used to optimize inheritance - # situations. - self.rootlevel = False - - # variables set inside of loops and blocks should not affect outer frames, - # but they still needs to be kept track of as part of the active context. - self.loop_frame = False - self.block_frame = False - - # track whether the frame is being used in an if-statement or conditional - # expression as it determines which errors should be raised during runtime - # or compile time. - self.soft_frame = False - - def copy(self) -> "te.Self": - """Create a copy of the current one.""" - rv = object.__new__(self.__class__) - rv.__dict__.update(self.__dict__) - rv.symbols = self.symbols.copy() - return rv - - def inner(self, isolated: bool = False) -> "Frame": - """Return an inner frame.""" - if isolated: - return Frame(self.eval_ctx, level=self.symbols.level + 1) - return Frame(self.eval_ctx, self) - - def soft(self) -> "te.Self": - """Return a soft frame. A soft frame may not be modified as - standalone thing as it shares the resources with the frame it - was created of, but it's not a rootlevel frame any longer. - - This is only used to implement if-statements and conditional - expressions. - """ - rv = self.copy() - rv.rootlevel = False - rv.soft_frame = True - return rv - - __copy__ = copy - - -class VisitorExit(RuntimeError): - """Exception used by the `UndeclaredNameVisitor` to signal a stop.""" - - -class DependencyFinderVisitor(NodeVisitor): - """A visitor that collects filter and test calls.""" - - def __init__(self) -> None: - self.filters: t.Set[str] = set() - self.tests: t.Set[str] = set() - - def visit_Filter(self, node: nodes.Filter) -> None: - self.generic_visit(node) - self.filters.add(node.name) - - def visit_Test(self, node: nodes.Test) -> None: - self.generic_visit(node) - self.tests.add(node.name) - - def visit_Block(self, node: nodes.Block) -> None: - """Stop visiting at blocks.""" - - -class UndeclaredNameVisitor(NodeVisitor): - """A visitor that checks if a name is accessed without being - declared. This is different from the frame visitor as it will - not stop at closure frames. - """ - - def __init__(self, names: t.Iterable[str]) -> None: - self.names = set(names) - self.undeclared: t.Set[str] = set() - - def visit_Name(self, node: nodes.Name) -> None: - if node.ctx == "load" and node.name in self.names: - self.undeclared.add(node.name) - if self.undeclared == self.names: - raise VisitorExit() - else: - self.names.discard(node.name) - - def visit_Block(self, node: nodes.Block) -> None: - """Stop visiting a blocks.""" - - -class CompilerExit(Exception): - """Raised if the compiler encountered a situation where it just - doesn't make sense to further process the code. Any block that - raises such an exception is not further processed. - """ - - -class CodeGenerator(NodeVisitor): - def __init__( - self, - environment: "Environment", - name: t.Optional[str], - filename: t.Optional[str], - stream: t.Optional[t.TextIO] = None, - defer_init: bool = False, - optimized: bool = True, - ) -> None: - if stream is None: - stream = StringIO() - self.environment = environment - self.name = name - self.filename = filename - self.stream = stream - self.created_block_context = False - self.defer_init = defer_init - self.optimizer: t.Optional[Optimizer] = None - - if optimized: - self.optimizer = Optimizer(environment) - - # aliases for imports - self.import_aliases: t.Dict[str, str] = {} - - # a registry for all blocks. Because blocks are moved out - # into the global python scope they are registered here - self.blocks: t.Dict[str, nodes.Block] = {} - - # the number of extends statements so far - self.extends_so_far = 0 - - # some templates have a rootlevel extends. In this case we - # can safely assume that we're a child template and do some - # more optimizations. - self.has_known_extends = False - - # the current line number - self.code_lineno = 1 - - # registry of all filters and tests (global, not block local) - self.tests: t.Dict[str, str] = {} - self.filters: t.Dict[str, str] = {} - - # the debug information - self.debug_info: t.List[t.Tuple[int, int]] = [] - self._write_debug_info: t.Optional[int] = None - - # the number of new lines before the next write() - self._new_lines = 0 - - # the line number of the last written statement - self._last_line = 0 - - # true if nothing was written so far. - self._first_write = True - - # used by the `temporary_identifier` method to get new - # unique, temporary identifier - self._last_identifier = 0 - - # the current indentation - self._indentation = 0 - - # Tracks toplevel assignments - self._assign_stack: t.List[t.Set[str]] = [] - - # Tracks parameter definition blocks - self._param_def_block: t.List[t.Set[str]] = [] - - # Tracks the current context. - self._context_reference_stack = ["context"] - - @property - def optimized(self) -> bool: - return self.optimizer is not None - - # -- Various compilation helpers - - def fail(self, msg: str, lineno: int) -> "te.NoReturn": - """Fail with a :exc:`TemplateAssertionError`.""" - raise TemplateAssertionError(msg, lineno, self.name, self.filename) - - def temporary_identifier(self) -> str: - """Get a new unique identifier.""" - self._last_identifier += 1 - return f"t_{self._last_identifier}" - - def buffer(self, frame: Frame) -> None: - """Enable buffering for the frame from that point onwards.""" - frame.buffer = self.temporary_identifier() - self.writeline(f"{frame.buffer} = []") - - def return_buffer_contents( - self, frame: Frame, force_unescaped: bool = False - ) -> None: - """Return the buffer contents of the frame.""" - if not force_unescaped: - if frame.eval_ctx.volatile: - self.writeline("if context.eval_ctx.autoescape:") - self.indent() - self.writeline(f"return Markup(concat({frame.buffer}))") - self.outdent() - self.writeline("else:") - self.indent() - self.writeline(f"return concat({frame.buffer})") - self.outdent() - return - elif frame.eval_ctx.autoescape: - self.writeline(f"return Markup(concat({frame.buffer}))") - return - self.writeline(f"return concat({frame.buffer})") - - def indent(self) -> None: - """Indent by one.""" - self._indentation += 1 - - def outdent(self, step: int = 1) -> None: - """Outdent by step.""" - self._indentation -= step - - def start_write(self, frame: Frame, node: t.Optional[nodes.Node] = None) -> None: - """Yield or write into the frame buffer.""" - if frame.buffer is None: - self.writeline("yield ", node) - else: - self.writeline(f"{frame.buffer}.append(", node) - - def end_write(self, frame: Frame) -> None: - """End the writing process started by `start_write`.""" - if frame.buffer is not None: - self.write(")") - - def simple_write( - self, s: str, frame: Frame, node: t.Optional[nodes.Node] = None - ) -> None: - """Simple shortcut for start_write + write + end_write.""" - self.start_write(frame, node) - self.write(s) - self.end_write(frame) - - def blockvisit(self, nodes: t.Iterable[nodes.Node], frame: Frame) -> None: - """Visit a list of nodes as block in a frame. If the current frame - is no buffer a dummy ``if 0: yield None`` is written automatically. - """ - try: - self.writeline("pass") - for node in nodes: - self.visit(node, frame) - except CompilerExit: - pass - - def write(self, x: str) -> None: - """Write a string into the output stream.""" - if self._new_lines: - if not self._first_write: - self.stream.write("\n" * self._new_lines) - self.code_lineno += self._new_lines - if self._write_debug_info is not None: - self.debug_info.append((self._write_debug_info, self.code_lineno)) - self._write_debug_info = None - self._first_write = False - self.stream.write(" " * self._indentation) - self._new_lines = 0 - self.stream.write(x) - - def writeline( - self, x: str, node: t.Optional[nodes.Node] = None, extra: int = 0 - ) -> None: - """Combination of newline and write.""" - self.newline(node, extra) - self.write(x) - - def newline(self, node: t.Optional[nodes.Node] = None, extra: int = 0) -> None: - """Add one or more newlines before the next write.""" - self._new_lines = max(self._new_lines, 1 + extra) - if node is not None and node.lineno != self._last_line: - self._write_debug_info = node.lineno - self._last_line = node.lineno - - def signature( - self, - node: t.Union[nodes.Call, nodes.Filter, nodes.Test], - frame: Frame, - extra_kwargs: t.Optional[t.Mapping[str, t.Any]] = None, - ) -> None: - """Writes a function call to the stream for the current node. - A leading comma is added automatically. The extra keyword - arguments may not include python keywords otherwise a syntax - error could occur. The extra keyword arguments should be given - as python dict. - """ - # if any of the given keyword arguments is a python keyword - # we have to make sure that no invalid call is created. - kwarg_workaround = any( - is_python_keyword(t.cast(str, k)) - for k in chain((x.key for x in node.kwargs), extra_kwargs or ()) - ) - - for arg in node.args: - self.write(", ") - self.visit(arg, frame) - - if not kwarg_workaround: - for kwarg in node.kwargs: - self.write(", ") - self.visit(kwarg, frame) - if extra_kwargs is not None: - for key, value in extra_kwargs.items(): - self.write(f", {key}={value}") - if node.dyn_args: - self.write(", *") - self.visit(node.dyn_args, frame) - - if kwarg_workaround: - if node.dyn_kwargs is not None: - self.write(", **dict({") - else: - self.write(", **{") - for kwarg in node.kwargs: - self.write(f"{kwarg.key!r}: ") - self.visit(kwarg.value, frame) - self.write(", ") - if extra_kwargs is not None: - for key, value in extra_kwargs.items(): - self.write(f"{key!r}: {value}, ") - if node.dyn_kwargs is not None: - self.write("}, **") - self.visit(node.dyn_kwargs, frame) - self.write(")") - else: - self.write("}") - - elif node.dyn_kwargs is not None: - self.write(", **") - self.visit(node.dyn_kwargs, frame) - - def pull_dependencies(self, nodes: t.Iterable[nodes.Node]) -> None: - """Find all filter and test names used in the template and - assign them to variables in the compiled namespace. Checking - that the names are registered with the environment is done when - compiling the Filter and Test nodes. If the node is in an If or - CondExpr node, the check is done at runtime instead. - - .. versionchanged:: 3.0 - Filters and tests in If and CondExpr nodes are checked at - runtime instead of compile time. - """ - visitor = DependencyFinderVisitor() - - for node in nodes: - visitor.visit(node) - - for id_map, names, dependency in ( - (self.filters, visitor.filters, "filters"), - ( - self.tests, - visitor.tests, - "tests", - ), - ): - for name in sorted(names): - if name not in id_map: - id_map[name] = self.temporary_identifier() - - # add check during runtime that dependencies used inside of executed - # blocks are defined, as this step may be skipped during compile time - self.writeline("try:") - self.indent() - self.writeline(f"{id_map[name]} = environment.{dependency}[{name!r}]") - self.outdent() - self.writeline("except KeyError:") - self.indent() - self.writeline("@internalcode") - self.writeline(f"def {id_map[name]}(*unused):") - self.indent() - self.writeline( - f'raise TemplateRuntimeError("No {dependency[:-1]}' - f' named {name!r} found.")' - ) - self.outdent() - self.outdent() - - def enter_frame(self, frame: Frame) -> None: - undefs = [] - for target, (action, param) in frame.symbols.loads.items(): - if action == VAR_LOAD_PARAMETER: - pass - elif action == VAR_LOAD_RESOLVE: - self.writeline(f"{target} = {self.get_resolve_func()}({param!r})") - elif action == VAR_LOAD_ALIAS: - self.writeline(f"{target} = {param}") - elif action == VAR_LOAD_UNDEFINED: - undefs.append(target) - else: - raise NotImplementedError("unknown load instruction") - if undefs: - self.writeline(f"{' = '.join(undefs)} = missing") - - def leave_frame(self, frame: Frame, with_python_scope: bool = False) -> None: - if not with_python_scope: - undefs = [] - for target in frame.symbols.loads: - undefs.append(target) - if undefs: - self.writeline(f"{' = '.join(undefs)} = missing") - - def choose_async(self, async_value: str = "async ", sync_value: str = "") -> str: - return async_value if self.environment.is_async else sync_value - - def func(self, name: str) -> str: - return f"{self.choose_async()}def {name}" - - def macro_body( - self, node: t.Union[nodes.Macro, nodes.CallBlock], frame: Frame - ) -> t.Tuple[Frame, MacroRef]: - """Dump the function def of a macro or call block.""" - frame = frame.inner() - frame.symbols.analyze_node(node) - macro_ref = MacroRef(node) - - explicit_caller = None - skip_special_params = set() - args = [] - - for idx, arg in enumerate(node.args): - if arg.name == "caller": - explicit_caller = idx - if arg.name in ("kwargs", "varargs"): - skip_special_params.add(arg.name) - args.append(frame.symbols.ref(arg.name)) - - undeclared = find_undeclared(node.body, ("caller", "kwargs", "varargs")) - - if "caller" in undeclared: - # In older Jinja versions there was a bug that allowed caller - # to retain the special behavior even if it was mentioned in - # the argument list. However thankfully this was only really - # working if it was the last argument. So we are explicitly - # checking this now and error out if it is anywhere else in - # the argument list. - if explicit_caller is not None: - try: - node.defaults[explicit_caller - len(node.args)] - except IndexError: - self.fail( - "When defining macros or call blocks the " - 'special "caller" argument must be omitted ' - "or be given a default.", - node.lineno, - ) - else: - args.append(frame.symbols.declare_parameter("caller")) - macro_ref.accesses_caller = True - if "kwargs" in undeclared and "kwargs" not in skip_special_params: - args.append(frame.symbols.declare_parameter("kwargs")) - macro_ref.accesses_kwargs = True - if "varargs" in undeclared and "varargs" not in skip_special_params: - args.append(frame.symbols.declare_parameter("varargs")) - macro_ref.accesses_varargs = True - - # macros are delayed, they never require output checks - frame.require_output_check = False - frame.symbols.analyze_node(node) - self.writeline(f"{self.func('macro')}({', '.join(args)}):", node) - self.indent() - - self.buffer(frame) - self.enter_frame(frame) - - self.push_parameter_definitions(frame) - for idx, arg in enumerate(node.args): - ref = frame.symbols.ref(arg.name) - self.writeline(f"if {ref} is missing:") - self.indent() - try: - default = node.defaults[idx - len(node.args)] - except IndexError: - self.writeline( - f'{ref} = undefined("parameter {arg.name!r} was not provided",' - f" name={arg.name!r})" - ) - else: - self.writeline(f"{ref} = ") - self.visit(default, frame) - self.mark_parameter_stored(ref) - self.outdent() - self.pop_parameter_definitions() - - self.blockvisit(node.body, frame) - self.return_buffer_contents(frame, force_unescaped=True) - self.leave_frame(frame, with_python_scope=True) - self.outdent() - - return frame, macro_ref - - def macro_def(self, macro_ref: MacroRef, frame: Frame) -> None: - """Dump the macro definition for the def created by macro_body.""" - arg_tuple = ", ".join(repr(x.name) for x in macro_ref.node.args) - name = getattr(macro_ref.node, "name", None) - if len(macro_ref.node.args) == 1: - arg_tuple += "," - self.write( - f"Macro(environment, macro, {name!r}, ({arg_tuple})," - f" {macro_ref.accesses_kwargs!r}, {macro_ref.accesses_varargs!r}," - f" {macro_ref.accesses_caller!r}, context.eval_ctx.autoescape)" - ) - - def position(self, node: nodes.Node) -> str: - """Return a human readable position for the node.""" - rv = f"line {node.lineno}" - if self.name is not None: - rv = f"{rv} in {self.name!r}" - return rv - - def dump_local_context(self, frame: Frame) -> str: - items_kv = ", ".join( - f"{name!r}: {target}" - for name, target in frame.symbols.dump_stores().items() - ) - return f"{{{items_kv}}}" - - def write_commons(self) -> None: - """Writes a common preamble that is used by root and block functions. - Primarily this sets up common local helpers and enforces a generator - through a dead branch. - """ - self.writeline("resolve = context.resolve_or_missing") - self.writeline("undefined = environment.undefined") - self.writeline("concat = environment.concat") - # always use the standard Undefined class for the implicit else of - # conditional expressions - self.writeline("cond_expr_undefined = Undefined") - self.writeline("if 0: yield None") - - def push_parameter_definitions(self, frame: Frame) -> None: - """Pushes all parameter targets from the given frame into a local - stack that permits tracking of yet to be assigned parameters. In - particular this enables the optimization from `visit_Name` to skip - undefined expressions for parameters in macros as macros can reference - otherwise unbound parameters. - """ - self._param_def_block.append(frame.symbols.dump_param_targets()) - - def pop_parameter_definitions(self) -> None: - """Pops the current parameter definitions set.""" - self._param_def_block.pop() - - def mark_parameter_stored(self, target: str) -> None: - """Marks a parameter in the current parameter definitions as stored. - This will skip the enforced undefined checks. - """ - if self._param_def_block: - self._param_def_block[-1].discard(target) - - def push_context_reference(self, target: str) -> None: - self._context_reference_stack.append(target) - - def pop_context_reference(self) -> None: - self._context_reference_stack.pop() - - def get_context_ref(self) -> str: - return self._context_reference_stack[-1] - - def get_resolve_func(self) -> str: - target = self._context_reference_stack[-1] - if target == "context": - return "resolve" - return f"{target}.resolve" - - def derive_context(self, frame: Frame) -> str: - return f"{self.get_context_ref()}.derived({self.dump_local_context(frame)})" - - def parameter_is_undeclared(self, target: str) -> bool: - """Checks if a given target is an undeclared parameter.""" - if not self._param_def_block: - return False - return target in self._param_def_block[-1] - - def push_assign_tracking(self) -> None: - """Pushes a new layer for assignment tracking.""" - self._assign_stack.append(set()) - - def pop_assign_tracking(self, frame: Frame) -> None: - """Pops the topmost level for assignment tracking and updates the - context variables if necessary. - """ - vars = self._assign_stack.pop() - if ( - not frame.block_frame - and not frame.loop_frame - and not frame.toplevel - or not vars - ): - return - public_names = [x for x in vars if x[:1] != "_"] - if len(vars) == 1: - name = next(iter(vars)) - ref = frame.symbols.ref(name) - if frame.loop_frame: - self.writeline(f"_loop_vars[{name!r}] = {ref}") - return - if frame.block_frame: - self.writeline(f"_block_vars[{name!r}] = {ref}") - return - self.writeline(f"context.vars[{name!r}] = {ref}") - else: - if frame.loop_frame: - self.writeline("_loop_vars.update({") - elif frame.block_frame: - self.writeline("_block_vars.update({") - else: - self.writeline("context.vars.update({") - for idx, name in enumerate(sorted(vars)): - if idx: - self.write(", ") - ref = frame.symbols.ref(name) - self.write(f"{name!r}: {ref}") - self.write("})") - if not frame.block_frame and not frame.loop_frame and public_names: - if len(public_names) == 1: - self.writeline(f"context.exported_vars.add({public_names[0]!r})") - else: - names_str = ", ".join(map(repr, sorted(public_names))) - self.writeline(f"context.exported_vars.update(({names_str}))") - - # -- Statement Visitors - - def visit_Template( - self, node: nodes.Template, frame: t.Optional[Frame] = None - ) -> None: - assert frame is None, "no root frame allowed" - eval_ctx = EvalContext(self.environment, self.name) - - from .runtime import async_exported - from .runtime import exported - - if self.environment.is_async: - exported_names = sorted(exported + async_exported) - else: - exported_names = sorted(exported) - - self.writeline("from jinja2.runtime import " + ", ".join(exported_names)) - - # if we want a deferred initialization we cannot move the - # environment into a local name - envenv = "" if self.defer_init else ", environment=environment" - - # do we have an extends tag at all? If not, we can save some - # overhead by just not processing any inheritance code. - have_extends = node.find(nodes.Extends) is not None - - # find all blocks - for block in node.find_all(nodes.Block): - if block.name in self.blocks: - self.fail(f"block {block.name!r} defined twice", block.lineno) - self.blocks[block.name] = block - - # find all imports and import them - for import_ in node.find_all(nodes.ImportedName): - if import_.importname not in self.import_aliases: - imp = import_.importname - self.import_aliases[imp] = alias = self.temporary_identifier() - if "." in imp: - module, obj = imp.rsplit(".", 1) - self.writeline(f"from {module} import {obj} as {alias}") - else: - self.writeline(f"import {imp} as {alias}") - - # add the load name - self.writeline(f"name = {self.name!r}") - - # generate the root render function. - self.writeline( - f"{self.func('root')}(context, missing=missing{envenv}):", extra=1 - ) - self.indent() - self.write_commons() - - # process the root - frame = Frame(eval_ctx) - if "self" in find_undeclared(node.body, ("self",)): - ref = frame.symbols.declare_parameter("self") - self.writeline(f"{ref} = TemplateReference(context)") - frame.symbols.analyze_node(node) - frame.toplevel = frame.rootlevel = True - frame.require_output_check = have_extends and not self.has_known_extends - if have_extends: - self.writeline("parent_template = None") - self.enter_frame(frame) - self.pull_dependencies(node.body) - self.blockvisit(node.body, frame) - self.leave_frame(frame, with_python_scope=True) - self.outdent() - - # make sure that the parent root is called. - if have_extends: - if not self.has_known_extends: - self.indent() - self.writeline("if parent_template is not None:") - self.indent() - if not self.environment.is_async: - self.writeline("yield from parent_template.root_render_func(context)") - else: - self.writeline("agen = parent_template.root_render_func(context)") - self.writeline("try:") - self.indent() - self.writeline("async for event in agen:") - self.indent() - self.writeline("yield event") - self.outdent() - self.outdent() - self.writeline("finally: await agen.aclose()") - self.outdent(1 + (not self.has_known_extends)) - - # at this point we now have the blocks collected and can visit them too. - for name, block in self.blocks.items(): - self.writeline( - f"{self.func('block_' + name)}(context, missing=missing{envenv}):", - block, - 1, - ) - self.indent() - self.write_commons() - # It's important that we do not make this frame a child of the - # toplevel template. This would cause a variety of - # interesting issues with identifier tracking. - block_frame = Frame(eval_ctx) - block_frame.block_frame = True - undeclared = find_undeclared(block.body, ("self", "super")) - if "self" in undeclared: - ref = block_frame.symbols.declare_parameter("self") - self.writeline(f"{ref} = TemplateReference(context)") - if "super" in undeclared: - ref = block_frame.symbols.declare_parameter("super") - self.writeline(f"{ref} = context.super({name!r}, block_{name})") - block_frame.symbols.analyze_node(block) - block_frame.block = name - self.writeline("_block_vars = {}") - self.enter_frame(block_frame) - self.pull_dependencies(block.body) - self.blockvisit(block.body, block_frame) - self.leave_frame(block_frame, with_python_scope=True) - self.outdent() - - blocks_kv_str = ", ".join(f"{x!r}: block_{x}" for x in self.blocks) - self.writeline(f"blocks = {{{blocks_kv_str}}}", extra=1) - debug_kv_str = "&".join(f"{k}={v}" for k, v in self.debug_info) - self.writeline(f"debug_info = {debug_kv_str!r}") - - def visit_Block(self, node: nodes.Block, frame: Frame) -> None: - """Call a block and register it for the template.""" - level = 0 - if frame.toplevel: - # if we know that we are a child template, there is no need to - # check if we are one - if self.has_known_extends: - return - if self.extends_so_far > 0: - self.writeline("if parent_template is None:") - self.indent() - level += 1 - - if node.scoped: - context = self.derive_context(frame) - else: - context = self.get_context_ref() - - if node.required: - self.writeline(f"if len(context.blocks[{node.name!r}]) <= 1:", node) - self.indent() - self.writeline( - f'raise TemplateRuntimeError("Required block {node.name!r} not found")', - node, - ) - self.outdent() - - if not self.environment.is_async and frame.buffer is None: - self.writeline( - f"yield from context.blocks[{node.name!r}][0]({context})", node - ) - else: - self.writeline(f"gen = context.blocks[{node.name!r}][0]({context})") - self.writeline("try:") - self.indent() - self.writeline( - f"{self.choose_async()}for event in gen:", - node, - ) - self.indent() - self.simple_write("event", frame) - self.outdent() - self.outdent() - self.writeline( - f"finally: {self.choose_async('await gen.aclose()', 'gen.close()')}" - ) - - self.outdent(level) - - def visit_Extends(self, node: nodes.Extends, frame: Frame) -> None: - """Calls the extender.""" - if not frame.toplevel: - self.fail("cannot use extend from a non top-level scope", node.lineno) - - # if the number of extends statements in general is zero so - # far, we don't have to add a check if something extended - # the template before this one. - if self.extends_so_far > 0: - # if we have a known extends we just add a template runtime - # error into the generated code. We could catch that at compile - # time too, but i welcome it not to confuse users by throwing the - # same error at different times just "because we can". - if not self.has_known_extends: - self.writeline("if parent_template is not None:") - self.indent() - self.writeline('raise TemplateRuntimeError("extended multiple times")') - - # if we have a known extends already we don't need that code here - # as we know that the template execution will end here. - if self.has_known_extends: - raise CompilerExit() - else: - self.outdent() - - self.writeline("parent_template = environment.get_template(", node) - self.visit(node.template, frame) - self.write(f", {self.name!r})") - self.writeline("for name, parent_block in parent_template.blocks.items():") - self.indent() - self.writeline("context.blocks.setdefault(name, []).append(parent_block)") - self.outdent() - - # if this extends statement was in the root level we can take - # advantage of that information and simplify the generated code - # in the top level from this point onwards - if frame.rootlevel: - self.has_known_extends = True - - # and now we have one more - self.extends_so_far += 1 - - def visit_Include(self, node: nodes.Include, frame: Frame) -> None: - """Handles includes.""" - if node.ignore_missing: - self.writeline("try:") - self.indent() - - func_name = "get_or_select_template" - if isinstance(node.template, nodes.Const): - if isinstance(node.template.value, str): - func_name = "get_template" - elif isinstance(node.template.value, (tuple, list)): - func_name = "select_template" - elif isinstance(node.template, (nodes.Tuple, nodes.List)): - func_name = "select_template" - - self.writeline(f"template = environment.{func_name}(", node) - self.visit(node.template, frame) - self.write(f", {self.name!r})") - if node.ignore_missing: - self.outdent() - self.writeline("except TemplateNotFound:") - self.indent() - self.writeline("pass") - self.outdent() - self.writeline("else:") - self.indent() - - def loop_body() -> None: - self.indent() - self.simple_write("event", frame) - self.outdent() - - if node.with_context: - self.writeline( - f"gen = template.root_render_func(" - "template.new_context(context.get_all(), True," - f" {self.dump_local_context(frame)}))" - ) - self.writeline("try:") - self.indent() - self.writeline(f"{self.choose_async()}for event in gen:") - loop_body() - self.outdent() - self.writeline( - f"finally: {self.choose_async('await gen.aclose()', 'gen.close()')}" - ) - elif self.environment.is_async: - self.writeline( - "for event in (await template._get_default_module_async())" - "._body_stream:" - ) - loop_body() - else: - self.writeline("yield from template._get_default_module()._body_stream") - - if node.ignore_missing: - self.outdent() - - def _import_common( - self, node: t.Union[nodes.Import, nodes.FromImport], frame: Frame - ) -> None: - self.write(f"{self.choose_async('await ')}environment.get_template(") - self.visit(node.template, frame) - self.write(f", {self.name!r}).") - - if node.with_context: - f_name = f"make_module{self.choose_async('_async')}" - self.write( - f"{f_name}(context.get_all(), True, {self.dump_local_context(frame)})" - ) - else: - self.write(f"_get_default_module{self.choose_async('_async')}(context)") - - def visit_Import(self, node: nodes.Import, frame: Frame) -> None: - """Visit regular imports.""" - self.writeline(f"{frame.symbols.ref(node.target)} = ", node) - if frame.toplevel: - self.write(f"context.vars[{node.target!r}] = ") - - self._import_common(node, frame) - - if frame.toplevel and not node.target.startswith("_"): - self.writeline(f"context.exported_vars.discard({node.target!r})") - - def visit_FromImport(self, node: nodes.FromImport, frame: Frame) -> None: - """Visit named imports.""" - self.newline(node) - self.write("included_template = ") - self._import_common(node, frame) - var_names = [] - discarded_names = [] - for name in node.names: - if isinstance(name, tuple): - name, alias = name - else: - alias = name - self.writeline( - f"{frame.symbols.ref(alias)} =" - f" getattr(included_template, {name!r}, missing)" - ) - self.writeline(f"if {frame.symbols.ref(alias)} is missing:") - self.indent() - # The position will contain the template name, and will be formatted - # into a string that will be compiled into an f-string. Curly braces - # in the name must be replaced with escapes so that they will not be - # executed as part of the f-string. - position = self.position(node).replace("{", "{{").replace("}", "}}") - message = ( - "the template {included_template.__name__!r}" - f" (imported on {position})" - f" does not export the requested name {name!r}" - ) - self.writeline( - f"{frame.symbols.ref(alias)} = undefined(f{message!r}, name={name!r})" - ) - self.outdent() - if frame.toplevel: - var_names.append(alias) - if not alias.startswith("_"): - discarded_names.append(alias) - - if var_names: - if len(var_names) == 1: - name = var_names[0] - self.writeline(f"context.vars[{name!r}] = {frame.symbols.ref(name)}") - else: - names_kv = ", ".join( - f"{name!r}: {frame.symbols.ref(name)}" for name in var_names - ) - self.writeline(f"context.vars.update({{{names_kv}}})") - if discarded_names: - if len(discarded_names) == 1: - self.writeline(f"context.exported_vars.discard({discarded_names[0]!r})") - else: - names_str = ", ".join(map(repr, discarded_names)) - self.writeline( - f"context.exported_vars.difference_update(({names_str}))" - ) - - def visit_For(self, node: nodes.For, frame: Frame) -> None: - loop_frame = frame.inner() - loop_frame.loop_frame = True - test_frame = frame.inner() - else_frame = frame.inner() - - # try to figure out if we have an extended loop. An extended loop - # is necessary if the loop is in recursive mode if the special loop - # variable is accessed in the body if the body is a scoped block. - extended_loop = ( - node.recursive - or "loop" - in find_undeclared(node.iter_child_nodes(only=("body",)), ("loop",)) - or any(block.scoped for block in node.find_all(nodes.Block)) - ) - - loop_ref = None - if extended_loop: - loop_ref = loop_frame.symbols.declare_parameter("loop") - - loop_frame.symbols.analyze_node(node, for_branch="body") - if node.else_: - else_frame.symbols.analyze_node(node, for_branch="else") - - if node.test: - loop_filter_func = self.temporary_identifier() - test_frame.symbols.analyze_node(node, for_branch="test") - self.writeline(f"{self.func(loop_filter_func)}(fiter):", node.test) - self.indent() - self.enter_frame(test_frame) - self.writeline(self.choose_async("async for ", "for ")) - self.visit(node.target, loop_frame) - self.write(" in ") - self.write(self.choose_async("auto_aiter(fiter)", "fiter")) - self.write(":") - self.indent() - self.writeline("if ", node.test) - self.visit(node.test, test_frame) - self.write(":") - self.indent() - self.writeline("yield ") - self.visit(node.target, loop_frame) - self.outdent(3) - self.leave_frame(test_frame, with_python_scope=True) - - # if we don't have an recursive loop we have to find the shadowed - # variables at that point. Because loops can be nested but the loop - # variable is a special one we have to enforce aliasing for it. - if node.recursive: - self.writeline( - f"{self.func('loop')}(reciter, loop_render_func, depth=0):", node - ) - self.indent() - self.buffer(loop_frame) - - # Use the same buffer for the else frame - else_frame.buffer = loop_frame.buffer - - # make sure the loop variable is a special one and raise a template - # assertion error if a loop tries to write to loop - if extended_loop: - self.writeline(f"{loop_ref} = missing") - - for name in node.find_all(nodes.Name): - if name.ctx == "store" and name.name == "loop": - self.fail( - "Can't assign to special loop variable in for-loop target", - name.lineno, - ) - - if node.else_: - iteration_indicator = self.temporary_identifier() - self.writeline(f"{iteration_indicator} = 1") - - self.writeline(self.choose_async("async for ", "for "), node) - self.visit(node.target, loop_frame) - if extended_loop: - self.write(f", {loop_ref} in {self.choose_async('Async')}LoopContext(") - else: - self.write(" in ") - - if node.test: - self.write(f"{loop_filter_func}(") - if node.recursive: - self.write("reciter") - else: - if self.environment.is_async and not extended_loop: - self.write("auto_aiter(") - self.visit(node.iter, frame) - if self.environment.is_async and not extended_loop: - self.write(")") - if node.test: - self.write(")") - - if node.recursive: - self.write(", undefined, loop_render_func, depth):") - else: - self.write(", undefined):" if extended_loop else ":") - - self.indent() - self.enter_frame(loop_frame) - - self.writeline("_loop_vars = {}") - self.blockvisit(node.body, loop_frame) - if node.else_: - self.writeline(f"{iteration_indicator} = 0") - self.outdent() - self.leave_frame( - loop_frame, with_python_scope=node.recursive and not node.else_ - ) - - if node.else_: - self.writeline(f"if {iteration_indicator}:") - self.indent() - self.enter_frame(else_frame) - self.blockvisit(node.else_, else_frame) - self.leave_frame(else_frame) - self.outdent() - - # if the node was recursive we have to return the buffer contents - # and start the iteration code - if node.recursive: - self.return_buffer_contents(loop_frame) - self.outdent() - self.start_write(frame, node) - self.write(f"{self.choose_async('await ')}loop(") - if self.environment.is_async: - self.write("auto_aiter(") - self.visit(node.iter, frame) - if self.environment.is_async: - self.write(")") - self.write(", loop)") - self.end_write(frame) - - # at the end of the iteration, clear any assignments made in the - # loop from the top level - if self._assign_stack: - self._assign_stack[-1].difference_update(loop_frame.symbols.stores) - - def visit_If(self, node: nodes.If, frame: Frame) -> None: - if_frame = frame.soft() - self.writeline("if ", node) - self.visit(node.test, if_frame) - self.write(":") - self.indent() - self.blockvisit(node.body, if_frame) - self.outdent() - for elif_ in node.elif_: - self.writeline("elif ", elif_) - self.visit(elif_.test, if_frame) - self.write(":") - self.indent() - self.blockvisit(elif_.body, if_frame) - self.outdent() - if node.else_: - self.writeline("else:") - self.indent() - self.blockvisit(node.else_, if_frame) - self.outdent() - - def visit_Macro(self, node: nodes.Macro, frame: Frame) -> None: - macro_frame, macro_ref = self.macro_body(node, frame) - self.newline() - if frame.toplevel: - if not node.name.startswith("_"): - self.write(f"context.exported_vars.add({node.name!r})") - self.writeline(f"context.vars[{node.name!r}] = ") - self.write(f"{frame.symbols.ref(node.name)} = ") - self.macro_def(macro_ref, macro_frame) - - def visit_CallBlock(self, node: nodes.CallBlock, frame: Frame) -> None: - call_frame, macro_ref = self.macro_body(node, frame) - self.writeline("caller = ") - self.macro_def(macro_ref, call_frame) - self.start_write(frame, node) - self.visit_Call(node.call, frame, forward_caller=True) - self.end_write(frame) - - def visit_FilterBlock(self, node: nodes.FilterBlock, frame: Frame) -> None: - filter_frame = frame.inner() - filter_frame.symbols.analyze_node(node) - self.enter_frame(filter_frame) - self.buffer(filter_frame) - self.blockvisit(node.body, filter_frame) - self.start_write(frame, node) - self.visit_Filter(node.filter, filter_frame) - self.end_write(frame) - self.leave_frame(filter_frame) - - def visit_With(self, node: nodes.With, frame: Frame) -> None: - with_frame = frame.inner() - with_frame.symbols.analyze_node(node) - self.enter_frame(with_frame) - for target, expr in zip(node.targets, node.values): - self.newline() - self.visit(target, with_frame) - self.write(" = ") - self.visit(expr, frame) - self.blockvisit(node.body, with_frame) - self.leave_frame(with_frame) - - def visit_ExprStmt(self, node: nodes.ExprStmt, frame: Frame) -> None: - self.newline(node) - self.visit(node.node, frame) - - class _FinalizeInfo(t.NamedTuple): - const: t.Optional[t.Callable[..., str]] - src: t.Optional[str] - - @staticmethod - def _default_finalize(value: t.Any) -> t.Any: - """The default finalize function if the environment isn't - configured with one. Or, if the environment has one, this is - called on that function's output for constants. - """ - return str(value) - - _finalize: t.Optional[_FinalizeInfo] = None - - def _make_finalize(self) -> _FinalizeInfo: - """Build the finalize function to be used on constants and at - runtime. Cached so it's only created once for all output nodes. - - Returns a ``namedtuple`` with the following attributes: - - ``const`` - A function to finalize constant data at compile time. - - ``src`` - Source code to output around nodes to be evaluated at - runtime. - """ - if self._finalize is not None: - return self._finalize - - finalize: t.Optional[t.Callable[..., t.Any]] - finalize = default = self._default_finalize - src = None - - if self.environment.finalize: - src = "environment.finalize(" - env_finalize = self.environment.finalize - pass_arg = { - _PassArg.context: "context", - _PassArg.eval_context: "context.eval_ctx", - _PassArg.environment: "environment", - }.get( - _PassArg.from_obj(env_finalize) # type: ignore - ) - finalize = None - - if pass_arg is None: - - def finalize(value: t.Any) -> t.Any: # noqa: F811 - return default(env_finalize(value)) - - else: - src = f"{src}{pass_arg}, " - - if pass_arg == "environment": - - def finalize(value: t.Any) -> t.Any: # noqa: F811 - return default(env_finalize(self.environment, value)) - - self._finalize = self._FinalizeInfo(finalize, src) - return self._finalize - - def _output_const_repr(self, group: t.Iterable[t.Any]) -> str: - """Given a group of constant values converted from ``Output`` - child nodes, produce a string to write to the template module - source. - """ - return repr(concat(group)) - - def _output_child_to_const( - self, node: nodes.Expr, frame: Frame, finalize: _FinalizeInfo - ) -> str: - """Try to optimize a child of an ``Output`` node by trying to - convert it to constant, finalized data at compile time. - - If :exc:`Impossible` is raised, the node is not constant and - will be evaluated at runtime. Any other exception will also be - evaluated at runtime for easier debugging. - """ - const = node.as_const(frame.eval_ctx) - - if frame.eval_ctx.autoescape: - const = escape(const) - - # Template data doesn't go through finalize. - if isinstance(node, nodes.TemplateData): - return str(const) - - return finalize.const(const) # type: ignore - - def _output_child_pre( - self, node: nodes.Expr, frame: Frame, finalize: _FinalizeInfo - ) -> None: - """Output extra source code before visiting a child of an - ``Output`` node. - """ - if frame.eval_ctx.volatile: - self.write("(escape if context.eval_ctx.autoescape else str)(") - elif frame.eval_ctx.autoescape: - self.write("escape(") - else: - self.write("str(") - - if finalize.src is not None: - self.write(finalize.src) - - def _output_child_post( - self, node: nodes.Expr, frame: Frame, finalize: _FinalizeInfo - ) -> None: - """Output extra source code after visiting a child of an - ``Output`` node. - """ - self.write(")") - - if finalize.src is not None: - self.write(")") - - def visit_Output(self, node: nodes.Output, frame: Frame) -> None: - # If an extends is active, don't render outside a block. - if frame.require_output_check: - # A top-level extends is known to exist at compile time. - if self.has_known_extends: - return - - self.writeline("if parent_template is None:") - self.indent() - - finalize = self._make_finalize() - body: t.List[t.Union[t.List[t.Any], nodes.Expr]] = [] - - # Evaluate constants at compile time if possible. Each item in - # body will be either a list of static data or a node to be - # evaluated at runtime. - for child in node.nodes: - try: - if not ( - # If the finalize function requires runtime context, - # constants can't be evaluated at compile time. - finalize.const - # Unless it's basic template data that won't be - # finalized anyway. - or isinstance(child, nodes.TemplateData) - ): - raise nodes.Impossible() - - const = self._output_child_to_const(child, frame, finalize) - except (nodes.Impossible, Exception): - # The node was not constant and needs to be evaluated at - # runtime. Or another error was raised, which is easier - # to debug at runtime. - body.append(child) - continue - - if body and isinstance(body[-1], list): - body[-1].append(const) - else: - body.append([const]) - - if frame.buffer is not None: - if len(body) == 1: - self.writeline(f"{frame.buffer}.append(") - else: - self.writeline(f"{frame.buffer}.extend((") - - self.indent() - - for item in body: - if isinstance(item, list): - # A group of constant data to join and output. - val = self._output_const_repr(item) - - if frame.buffer is None: - self.writeline("yield " + val) - else: - self.writeline(val + ",") - else: - if frame.buffer is None: - self.writeline("yield ", item) - else: - self.newline(item) - - # A node to be evaluated at runtime. - self._output_child_pre(item, frame, finalize) - self.visit(item, frame) - self._output_child_post(item, frame, finalize) - - if frame.buffer is not None: - self.write(",") - - if frame.buffer is not None: - self.outdent() - self.writeline(")" if len(body) == 1 else "))") - - if frame.require_output_check: - self.outdent() - - def visit_Assign(self, node: nodes.Assign, frame: Frame) -> None: - self.push_assign_tracking() - - # ``a.b`` is allowed for assignment, and is parsed as an NSRef. However, - # it is only valid if it references a Namespace object. Emit a check for - # that for each ref here, before assignment code is emitted. This can't - # be done in visit_NSRef as the ref could be in the middle of a tuple. - seen_refs: t.Set[str] = set() - - for nsref in node.find_all(nodes.NSRef): - if nsref.name in seen_refs: - # Only emit the check for each reference once, in case the same - # ref is used multiple times in a tuple, `ns.a, ns.b = c, d`. - continue - - seen_refs.add(nsref.name) - ref = frame.symbols.ref(nsref.name) - self.writeline(f"if not isinstance({ref}, Namespace):") - self.indent() - self.writeline( - "raise TemplateRuntimeError" - '("cannot assign attribute on non-namespace object")' - ) - self.outdent() - - self.newline(node) - self.visit(node.target, frame) - self.write(" = ") - self.visit(node.node, frame) - self.pop_assign_tracking(frame) - - def visit_AssignBlock(self, node: nodes.AssignBlock, frame: Frame) -> None: - self.push_assign_tracking() - block_frame = frame.inner() - # This is a special case. Since a set block always captures we - # will disable output checks. This way one can use set blocks - # toplevel even in extended templates. - block_frame.require_output_check = False - block_frame.symbols.analyze_node(node) - self.enter_frame(block_frame) - self.buffer(block_frame) - self.blockvisit(node.body, block_frame) - self.newline(node) - self.visit(node.target, frame) - self.write(" = (Markup if context.eval_ctx.autoescape else identity)(") - if node.filter is not None: - self.visit_Filter(node.filter, block_frame) - else: - self.write(f"concat({block_frame.buffer})") - self.write(")") - self.pop_assign_tracking(frame) - self.leave_frame(block_frame) - - # -- Expression Visitors - - def visit_Name(self, node: nodes.Name, frame: Frame) -> None: - if node.ctx == "store" and ( - frame.toplevel or frame.loop_frame or frame.block_frame - ): - if self._assign_stack: - self._assign_stack[-1].add(node.name) - ref = frame.symbols.ref(node.name) - - # If we are looking up a variable we might have to deal with the - # case where it's undefined. We can skip that case if the load - # instruction indicates a parameter which are always defined. - if node.ctx == "load": - load = frame.symbols.find_load(ref) - if not ( - load is not None - and load[0] == VAR_LOAD_PARAMETER - and not self.parameter_is_undeclared(ref) - ): - self.write( - f"(undefined(name={node.name!r}) if {ref} is missing else {ref})" - ) - return - - self.write(ref) - - def visit_NSRef(self, node: nodes.NSRef, frame: Frame) -> None: - # NSRef is a dotted assignment target a.b=c, but uses a[b]=c internally. - # visit_Assign emits code to validate that each ref is to a Namespace - # object only. That can't be emitted here as the ref could be in the - # middle of a tuple assignment. - ref = frame.symbols.ref(node.name) - self.writeline(f"{ref}[{node.attr!r}]") - - def visit_Const(self, node: nodes.Const, frame: Frame) -> None: - val = node.as_const(frame.eval_ctx) - if isinstance(val, float): - self.write(str(val)) - else: - self.write(repr(val)) - - def visit_TemplateData(self, node: nodes.TemplateData, frame: Frame) -> None: - try: - self.write(repr(node.as_const(frame.eval_ctx))) - except nodes.Impossible: - self.write( - f"(Markup if context.eval_ctx.autoescape else identity)({node.data!r})" - ) - - def visit_Tuple(self, node: nodes.Tuple, frame: Frame) -> None: - self.write("(") - idx = -1 - for idx, item in enumerate(node.items): - if idx: - self.write(", ") - self.visit(item, frame) - self.write(",)" if idx == 0 else ")") - - def visit_List(self, node: nodes.List, frame: Frame) -> None: - self.write("[") - for idx, item in enumerate(node.items): - if idx: - self.write(", ") - self.visit(item, frame) - self.write("]") - - def visit_Dict(self, node: nodes.Dict, frame: Frame) -> None: - self.write("{") - for idx, item in enumerate(node.items): - if idx: - self.write(", ") - self.visit(item.key, frame) - self.write(": ") - self.visit(item.value, frame) - self.write("}") - - visit_Add = _make_binop("+") - visit_Sub = _make_binop("-") - visit_Mul = _make_binop("*") - visit_Div = _make_binop("/") - visit_FloorDiv = _make_binop("//") - visit_Pow = _make_binop("**") - visit_Mod = _make_binop("%") - visit_And = _make_binop("and") - visit_Or = _make_binop("or") - visit_Pos = _make_unop("+") - visit_Neg = _make_unop("-") - visit_Not = _make_unop("not ") - - @optimizeconst - def visit_Concat(self, node: nodes.Concat, frame: Frame) -> None: - if frame.eval_ctx.volatile: - func_name = "(markup_join if context.eval_ctx.volatile else str_join)" - elif frame.eval_ctx.autoescape: - func_name = "markup_join" - else: - func_name = "str_join" - self.write(f"{func_name}((") - for arg in node.nodes: - self.visit(arg, frame) - self.write(", ") - self.write("))") - - @optimizeconst - def visit_Compare(self, node: nodes.Compare, frame: Frame) -> None: - self.write("(") - self.visit(node.expr, frame) - for op in node.ops: - self.visit(op, frame) - self.write(")") - - def visit_Operand(self, node: nodes.Operand, frame: Frame) -> None: - self.write(f" {operators[node.op]} ") - self.visit(node.expr, frame) - - @optimizeconst - def visit_Getattr(self, node: nodes.Getattr, frame: Frame) -> None: - if self.environment.is_async: - self.write("(await auto_await(") - - self.write("environment.getattr(") - self.visit(node.node, frame) - self.write(f", {node.attr!r})") - - if self.environment.is_async: - self.write("))") - - @optimizeconst - def visit_Getitem(self, node: nodes.Getitem, frame: Frame) -> None: - # slices bypass the environment getitem method. - if isinstance(node.arg, nodes.Slice): - self.visit(node.node, frame) - self.write("[") - self.visit(node.arg, frame) - self.write("]") - else: - if self.environment.is_async: - self.write("(await auto_await(") - - self.write("environment.getitem(") - self.visit(node.node, frame) - self.write(", ") - self.visit(node.arg, frame) - self.write(")") - - if self.environment.is_async: - self.write("))") - - def visit_Slice(self, node: nodes.Slice, frame: Frame) -> None: - if node.start is not None: - self.visit(node.start, frame) - self.write(":") - if node.stop is not None: - self.visit(node.stop, frame) - if node.step is not None: - self.write(":") - self.visit(node.step, frame) - - @contextmanager - def _filter_test_common( - self, node: t.Union[nodes.Filter, nodes.Test], frame: Frame, is_filter: bool - ) -> t.Iterator[None]: - if self.environment.is_async: - self.write("(await auto_await(") - - if is_filter: - self.write(f"{self.filters[node.name]}(") - func = self.environment.filters.get(node.name) - else: - self.write(f"{self.tests[node.name]}(") - func = self.environment.tests.get(node.name) - - # When inside an If or CondExpr frame, allow the filter to be - # undefined at compile time and only raise an error if it's - # actually called at runtime. See pull_dependencies. - if func is None and not frame.soft_frame: - type_name = "filter" if is_filter else "test" - self.fail(f"No {type_name} named {node.name!r}.", node.lineno) - - pass_arg = { - _PassArg.context: "context", - _PassArg.eval_context: "context.eval_ctx", - _PassArg.environment: "environment", - }.get( - _PassArg.from_obj(func) # type: ignore - ) - - if pass_arg is not None: - self.write(f"{pass_arg}, ") - - # Back to the visitor function to handle visiting the target of - # the filter or test. - yield - - self.signature(node, frame) - self.write(")") - - if self.environment.is_async: - self.write("))") - - @optimizeconst - def visit_Filter(self, node: nodes.Filter, frame: Frame) -> None: - with self._filter_test_common(node, frame, True): - # if the filter node is None we are inside a filter block - # and want to write to the current buffer - if node.node is not None: - self.visit(node.node, frame) - elif frame.eval_ctx.volatile: - self.write( - f"(Markup(concat({frame.buffer}))" - f" if context.eval_ctx.autoescape else concat({frame.buffer}))" - ) - elif frame.eval_ctx.autoescape: - self.write(f"Markup(concat({frame.buffer}))") - else: - self.write(f"concat({frame.buffer})") - - @optimizeconst - def visit_Test(self, node: nodes.Test, frame: Frame) -> None: - with self._filter_test_common(node, frame, False): - self.visit(node.node, frame) - - @optimizeconst - def visit_CondExpr(self, node: nodes.CondExpr, frame: Frame) -> None: - frame = frame.soft() - - def write_expr2() -> None: - if node.expr2 is not None: - self.visit(node.expr2, frame) - return - - self.write( - f'cond_expr_undefined("the inline if-expression on' - f" {self.position(node)} evaluated to false and no else" - f' section was defined.")' - ) - - self.write("(") - self.visit(node.expr1, frame) - self.write(" if ") - self.visit(node.test, frame) - self.write(" else ") - write_expr2() - self.write(")") - - @optimizeconst - def visit_Call( - self, node: nodes.Call, frame: Frame, forward_caller: bool = False - ) -> None: - if self.environment.is_async: - self.write("(await auto_await(") - if self.environment.sandboxed: - self.write("environment.call(context, ") - else: - self.write("context.call(") - self.visit(node.node, frame) - extra_kwargs = {"caller": "caller"} if forward_caller else None - loop_kwargs = {"_loop_vars": "_loop_vars"} if frame.loop_frame else {} - block_kwargs = {"_block_vars": "_block_vars"} if frame.block_frame else {} - if extra_kwargs: - extra_kwargs.update(loop_kwargs, **block_kwargs) - elif loop_kwargs or block_kwargs: - extra_kwargs = dict(loop_kwargs, **block_kwargs) - self.signature(node, frame, extra_kwargs) - self.write(")") - if self.environment.is_async: - self.write("))") - - def visit_Keyword(self, node: nodes.Keyword, frame: Frame) -> None: - self.write(node.key + "=") - self.visit(node.value, frame) - - # -- Unused nodes for extensions - - def visit_MarkSafe(self, node: nodes.MarkSafe, frame: Frame) -> None: - self.write("Markup(") - self.visit(node.expr, frame) - self.write(")") - - def visit_MarkSafeIfAutoescape( - self, node: nodes.MarkSafeIfAutoescape, frame: Frame - ) -> None: - self.write("(Markup if context.eval_ctx.autoescape else identity)(") - self.visit(node.expr, frame) - self.write(")") - - def visit_EnvironmentAttribute( - self, node: nodes.EnvironmentAttribute, frame: Frame - ) -> None: - self.write("environment." + node.name) - - def visit_ExtensionAttribute( - self, node: nodes.ExtensionAttribute, frame: Frame - ) -> None: - self.write(f"environment.extensions[{node.identifier!r}].{node.name}") - - def visit_ImportedName(self, node: nodes.ImportedName, frame: Frame) -> None: - self.write(self.import_aliases[node.importname]) - - def visit_InternalName(self, node: nodes.InternalName, frame: Frame) -> None: - self.write(node.name) - - def visit_ContextReference( - self, node: nodes.ContextReference, frame: Frame - ) -> None: - self.write("context") - - def visit_DerivedContextReference( - self, node: nodes.DerivedContextReference, frame: Frame - ) -> None: - self.write(self.derive_context(frame)) - - def visit_Continue(self, node: nodes.Continue, frame: Frame) -> None: - self.writeline("continue", node) - - def visit_Break(self, node: nodes.Break, frame: Frame) -> None: - self.writeline("break", node) - - def visit_Scope(self, node: nodes.Scope, frame: Frame) -> None: - scope_frame = frame.inner() - scope_frame.symbols.analyze_node(node) - self.enter_frame(scope_frame) - self.blockvisit(node.body, scope_frame) - self.leave_frame(scope_frame) - - def visit_OverlayScope(self, node: nodes.OverlayScope, frame: Frame) -> None: - ctx = self.temporary_identifier() - self.writeline(f"{ctx} = {self.derive_context(frame)}") - self.writeline(f"{ctx}.vars = ") - self.visit(node.context, frame) - self.push_context_reference(ctx) - - scope_frame = frame.inner(isolated=True) - scope_frame.symbols.analyze_node(node) - self.enter_frame(scope_frame) - self.blockvisit(node.body, scope_frame) - self.leave_frame(scope_frame) - self.pop_context_reference() - - def visit_EvalContextModifier( - self, node: nodes.EvalContextModifier, frame: Frame - ) -> None: - for keyword in node.options: - self.writeline(f"context.eval_ctx.{keyword.key} = ") - self.visit(keyword.value, frame) - try: - val = keyword.value.as_const(frame.eval_ctx) - except nodes.Impossible: - frame.eval_ctx.volatile = True - else: - setattr(frame.eval_ctx, keyword.key, val) - - def visit_ScopedEvalContextModifier( - self, node: nodes.ScopedEvalContextModifier, frame: Frame - ) -> None: - old_ctx_name = self.temporary_identifier() - saved_ctx = frame.eval_ctx.save() - self.writeline(f"{old_ctx_name} = context.eval_ctx.save()") - self.visit_EvalContextModifier(node, frame) - for child in node.body: - self.visit(child, frame) - frame.eval_ctx.revert(saved_ctx) - self.writeline(f"context.eval_ctx.revert({old_ctx_name})") diff --git a/venv/lib/python3.9/site-packages/jinja2/constants.py b/venv/lib/python3.9/site-packages/jinja2/constants.py deleted file mode 100644 index 41a1c23..0000000 --- a/venv/lib/python3.9/site-packages/jinja2/constants.py +++ /dev/null @@ -1,20 +0,0 @@ -#: list of lorem ipsum words used by the lipsum() helper function -LOREM_IPSUM_WORDS = """\ -a ac accumsan ad adipiscing aenean aliquam aliquet amet ante aptent arcu at -auctor augue bibendum blandit class commodo condimentum congue consectetuer -consequat conubia convallis cras cubilia cum curabitur curae cursus dapibus -diam dictum dictumst dignissim dis dolor donec dui duis egestas eget eleifend -elementum elit enim erat eros est et etiam eu euismod facilisi facilisis fames -faucibus felis fermentum feugiat fringilla fusce gravida habitant habitasse hac -hendrerit hymenaeos iaculis id imperdiet in inceptos integer interdum ipsum -justo lacinia lacus laoreet lectus leo libero ligula litora lobortis lorem -luctus maecenas magna magnis malesuada massa mattis mauris metus mi molestie -mollis montes morbi mus nam nascetur natoque nec neque netus nibh nisi nisl non -nonummy nostra nulla nullam nunc odio orci ornare parturient pede pellentesque -penatibus per pharetra phasellus placerat platea porta porttitor posuere -potenti praesent pretium primis proin pulvinar purus quam quis quisque rhoncus -ridiculus risus rutrum sagittis sapien scelerisque sed sem semper senectus sit -sociis sociosqu sodales sollicitudin suscipit suspendisse taciti tellus tempor -tempus tincidunt torquent tortor tristique turpis ullamcorper ultrices -ultricies urna ut varius vehicula vel velit venenatis vestibulum vitae vivamus -viverra volutpat vulputate""" diff --git a/venv/lib/python3.9/site-packages/jinja2/debug.py b/venv/lib/python3.9/site-packages/jinja2/debug.py deleted file mode 100644 index eeeeee7..0000000 --- a/venv/lib/python3.9/site-packages/jinja2/debug.py +++ /dev/null @@ -1,191 +0,0 @@ -import sys -import typing as t -from types import CodeType -from types import TracebackType - -from .exceptions import TemplateSyntaxError -from .utils import internal_code -from .utils import missing - -if t.TYPE_CHECKING: - from .runtime import Context - - -def rewrite_traceback_stack(source: t.Optional[str] = None) -> BaseException: - """Rewrite the current exception to replace any tracebacks from - within compiled template code with tracebacks that look like they - came from the template source. - - This must be called within an ``except`` block. - - :param source: For ``TemplateSyntaxError``, the original source if - known. - :return: The original exception with the rewritten traceback. - """ - _, exc_value, tb = sys.exc_info() - exc_value = t.cast(BaseException, exc_value) - tb = t.cast(TracebackType, tb) - - if isinstance(exc_value, TemplateSyntaxError) and not exc_value.translated: - exc_value.translated = True - exc_value.source = source - # Remove the old traceback, otherwise the frames from the - # compiler still show up. - exc_value.with_traceback(None) - # Outside of runtime, so the frame isn't executing template - # code, but it still needs to point at the template. - tb = fake_traceback( - exc_value, None, exc_value.filename or "", exc_value.lineno - ) - else: - # Skip the frame for the render function. - tb = tb.tb_next - - stack = [] - - # Build the stack of traceback object, replacing any in template - # code with the source file and line information. - while tb is not None: - # Skip frames decorated with @internalcode. These are internal - # calls that aren't useful in template debugging output. - if tb.tb_frame.f_code in internal_code: - tb = tb.tb_next - continue - - template = tb.tb_frame.f_globals.get("__jinja_template__") - - if template is not None: - lineno = template.get_corresponding_lineno(tb.tb_lineno) - fake_tb = fake_traceback(exc_value, tb, template.filename, lineno) - stack.append(fake_tb) - else: - stack.append(tb) - - tb = tb.tb_next - - tb_next = None - - # Assign tb_next in reverse to avoid circular references. - for tb in reversed(stack): - tb.tb_next = tb_next - tb_next = tb - - return exc_value.with_traceback(tb_next) - - -def fake_traceback( # type: ignore - exc_value: BaseException, tb: t.Optional[TracebackType], filename: str, lineno: int -) -> TracebackType: - """Produce a new traceback object that looks like it came from the - template source instead of the compiled code. The filename, line - number, and location name will point to the template, and the local - variables will be the current template context. - - :param exc_value: The original exception to be re-raised to create - the new traceback. - :param tb: The original traceback to get the local variables and - code info from. - :param filename: The template filename. - :param lineno: The line number in the template source. - """ - if tb is not None: - # Replace the real locals with the context that would be - # available at that point in the template. - locals = get_template_locals(tb.tb_frame.f_locals) - locals.pop("__jinja_exception__", None) - else: - locals = {} - - globals = { - "__name__": filename, - "__file__": filename, - "__jinja_exception__": exc_value, - } - # Raise an exception at the correct line number. - code: CodeType = compile( - "\n" * (lineno - 1) + "raise __jinja_exception__", filename, "exec" - ) - - # Build a new code object that points to the template file and - # replaces the location with a block name. - location = "template" - - if tb is not None: - function = tb.tb_frame.f_code.co_name - - if function == "root": - location = "top-level template code" - elif function.startswith("block_"): - location = f"block {function[6:]!r}" - - if sys.version_info >= (3, 8): - code = code.replace(co_name=location) - else: - code = CodeType( - code.co_argcount, - code.co_kwonlyargcount, - code.co_nlocals, - code.co_stacksize, - code.co_flags, - code.co_code, - code.co_consts, - code.co_names, - code.co_varnames, - code.co_filename, - location, - code.co_firstlineno, - code.co_lnotab, - code.co_freevars, - code.co_cellvars, - ) - - # Execute the new code, which is guaranteed to raise, and return - # the new traceback without this frame. - try: - exec(code, globals, locals) - except BaseException: - return sys.exc_info()[2].tb_next # type: ignore - - -def get_template_locals(real_locals: t.Mapping[str, t.Any]) -> t.Dict[str, t.Any]: - """Based on the runtime locals, get the context that would be - available at that point in the template. - """ - # Start with the current template context. - ctx: t.Optional[Context] = real_locals.get("context") - - if ctx is not None: - data: t.Dict[str, t.Any] = ctx.get_all().copy() - else: - data = {} - - # Might be in a derived context that only sets local variables - # rather than pushing a context. Local variables follow the scheme - # l_depth_name. Find the highest-depth local that has a value for - # each name. - local_overrides: t.Dict[str, t.Tuple[int, t.Any]] = {} - - for name, value in real_locals.items(): - if not name.startswith("l_") or value is missing: - # Not a template variable, or no longer relevant. - continue - - try: - _, depth_str, name = name.split("_", 2) - depth = int(depth_str) - except ValueError: - continue - - cur_depth = local_overrides.get(name, (-1,))[0] - - if cur_depth < depth: - local_overrides[name] = (depth, value) - - # Modify the context with any derived context. - for name, (_, value) in local_overrides.items(): - if value is missing: - data.pop(name, None) - else: - data[name] = value - - return data diff --git a/venv/lib/python3.9/site-packages/jinja2/defaults.py b/venv/lib/python3.9/site-packages/jinja2/defaults.py deleted file mode 100644 index 638cad3..0000000 --- a/venv/lib/python3.9/site-packages/jinja2/defaults.py +++ /dev/null @@ -1,48 +0,0 @@ -import typing as t - -from .filters import FILTERS as DEFAULT_FILTERS # noqa: F401 -from .tests import TESTS as DEFAULT_TESTS # noqa: F401 -from .utils import Cycler -from .utils import generate_lorem_ipsum -from .utils import Joiner -from .utils import Namespace - -if t.TYPE_CHECKING: - import typing_extensions as te - -# defaults for the parser / lexer -BLOCK_START_STRING = "{%" -BLOCK_END_STRING = "%}" -VARIABLE_START_STRING = "{{" -VARIABLE_END_STRING = "}}" -COMMENT_START_STRING = "{#" -COMMENT_END_STRING = "#}" -LINE_STATEMENT_PREFIX: t.Optional[str] = None -LINE_COMMENT_PREFIX: t.Optional[str] = None -TRIM_BLOCKS = False -LSTRIP_BLOCKS = False -NEWLINE_SEQUENCE: "te.Literal['\\n', '\\r\\n', '\\r']" = "\n" -KEEP_TRAILING_NEWLINE = False - -# default filters, tests and namespace - -DEFAULT_NAMESPACE = { - "range": range, - "dict": dict, - "lipsum": generate_lorem_ipsum, - "cycler": Cycler, - "joiner": Joiner, - "namespace": Namespace, -} - -# default policies -DEFAULT_POLICIES: t.Dict[str, t.Any] = { - "compiler.ascii_str": True, - "urlize.rel": "noopener", - "urlize.target": None, - "urlize.extra_schemes": None, - "truncate.leeway": 5, - "json.dumps_function": None, - "json.dumps_kwargs": {"sort_keys": True}, - "ext.i18n.trimmed": False, -} diff --git a/venv/lib/python3.9/site-packages/jinja2/environment.py b/venv/lib/python3.9/site-packages/jinja2/environment.py deleted file mode 100644 index 0fc6e5b..0000000 --- a/venv/lib/python3.9/site-packages/jinja2/environment.py +++ /dev/null @@ -1,1672 +0,0 @@ -"""Classes for managing templates and their runtime and compile time -options. -""" - -import os -import typing -import typing as t -import weakref -from collections import ChainMap -from functools import lru_cache -from functools import partial -from functools import reduce -from types import CodeType - -from markupsafe import Markup - -from . import nodes -from .compiler import CodeGenerator -from .compiler import generate -from .defaults import BLOCK_END_STRING -from .defaults import BLOCK_START_STRING -from .defaults import COMMENT_END_STRING -from .defaults import COMMENT_START_STRING -from .defaults import DEFAULT_FILTERS # type: ignore[attr-defined] -from .defaults import DEFAULT_NAMESPACE -from .defaults import DEFAULT_POLICIES -from .defaults import DEFAULT_TESTS # type: ignore[attr-defined] -from .defaults import KEEP_TRAILING_NEWLINE -from .defaults import LINE_COMMENT_PREFIX -from .defaults import LINE_STATEMENT_PREFIX -from .defaults import LSTRIP_BLOCKS -from .defaults import NEWLINE_SEQUENCE -from .defaults import TRIM_BLOCKS -from .defaults import VARIABLE_END_STRING -from .defaults import VARIABLE_START_STRING -from .exceptions import TemplateNotFound -from .exceptions import TemplateRuntimeError -from .exceptions import TemplatesNotFound -from .exceptions import TemplateSyntaxError -from .exceptions import UndefinedError -from .lexer import get_lexer -from .lexer import Lexer -from .lexer import TokenStream -from .nodes import EvalContext -from .parser import Parser -from .runtime import Context -from .runtime import new_context -from .runtime import Undefined -from .utils import _PassArg -from .utils import concat -from .utils import consume -from .utils import import_string -from .utils import internalcode -from .utils import LRUCache -from .utils import missing - -if t.TYPE_CHECKING: - import typing_extensions as te - - from .bccache import BytecodeCache - from .ext import Extension - from .loaders import BaseLoader - -_env_bound = t.TypeVar("_env_bound", bound="Environment") - - -# for direct template usage we have up to ten living environments -@lru_cache(maxsize=10) -def get_spontaneous_environment(cls: t.Type[_env_bound], *args: t.Any) -> _env_bound: - """Return a new spontaneous environment. A spontaneous environment - is used for templates created directly rather than through an - existing environment. - - :param cls: Environment class to create. - :param args: Positional arguments passed to environment. - """ - env = cls(*args) - env.shared = True - return env - - -def create_cache( - size: int, -) -> t.Optional[t.MutableMapping[t.Tuple["weakref.ref[t.Any]", str], "Template"]]: - """Return the cache class for the given size.""" - if size == 0: - return None - - if size < 0: - return {} - - return LRUCache(size) # type: ignore - - -def copy_cache( - cache: t.Optional[t.MutableMapping[t.Any, t.Any]], -) -> t.Optional[t.MutableMapping[t.Tuple["weakref.ref[t.Any]", str], "Template"]]: - """Create an empty copy of the given cache.""" - if cache is None: - return None - - if type(cache) is dict: # noqa E721 - return {} - - return LRUCache(cache.capacity) # type: ignore - - -def load_extensions( - environment: "Environment", - extensions: t.Sequence[t.Union[str, t.Type["Extension"]]], -) -> t.Dict[str, "Extension"]: - """Load the extensions from the list and bind it to the environment. - Returns a dict of instantiated extensions. - """ - result = {} - - for extension in extensions: - if isinstance(extension, str): - extension = t.cast(t.Type["Extension"], import_string(extension)) - - result[extension.identifier] = extension(environment) - - return result - - -def _environment_config_check(environment: _env_bound) -> _env_bound: - """Perform a sanity check on the environment.""" - assert issubclass( - environment.undefined, Undefined - ), "'undefined' must be a subclass of 'jinja2.Undefined'." - assert ( - environment.block_start_string - != environment.variable_start_string - != environment.comment_start_string - ), "block, variable and comment start strings must be different." - assert environment.newline_sequence in { - "\r", - "\r\n", - "\n", - }, "'newline_sequence' must be one of '\\n', '\\r\\n', or '\\r'." - return environment - - -class Environment: - r"""The core component of Jinja is the `Environment`. It contains - important shared variables like configuration, filters, tests, - globals and others. Instances of this class may be modified if - they are not shared and if no template was loaded so far. - Modifications on environments after the first template was loaded - will lead to surprising effects and undefined behavior. - - Here are the possible initialization parameters: - - `block_start_string` - The string marking the beginning of a block. Defaults to ``'{%'``. - - `block_end_string` - The string marking the end of a block. Defaults to ``'%}'``. - - `variable_start_string` - The string marking the beginning of a print statement. - Defaults to ``'{{'``. - - `variable_end_string` - The string marking the end of a print statement. Defaults to - ``'}}'``. - - `comment_start_string` - The string marking the beginning of a comment. Defaults to ``'{#'``. - - `comment_end_string` - The string marking the end of a comment. Defaults to ``'#}'``. - - `line_statement_prefix` - If given and a string, this will be used as prefix for line based - statements. See also :ref:`line-statements`. - - `line_comment_prefix` - If given and a string, this will be used as prefix for line based - comments. See also :ref:`line-statements`. - - .. versionadded:: 2.2 - - `trim_blocks` - If this is set to ``True`` the first newline after a block is - removed (block, not variable tag!). Defaults to `False`. - - `lstrip_blocks` - If this is set to ``True`` leading spaces and tabs are stripped - from the start of a line to a block. Defaults to `False`. - - `newline_sequence` - The sequence that starts a newline. Must be one of ``'\r'``, - ``'\n'`` or ``'\r\n'``. The default is ``'\n'`` which is a - useful default for Linux and OS X systems as well as web - applications. - - `keep_trailing_newline` - Preserve the trailing newline when rendering templates. - The default is ``False``, which causes a single newline, - if present, to be stripped from the end of the template. - - .. versionadded:: 2.7 - - `extensions` - List of Jinja extensions to use. This can either be import paths - as strings or extension classes. For more information have a - look at :ref:`the extensions documentation `. - - `optimized` - should the optimizer be enabled? Default is ``True``. - - `undefined` - :class:`Undefined` or a subclass of it that is used to represent - undefined values in the template. - - `finalize` - A callable that can be used to process the result of a variable - expression before it is output. For example one can convert - ``None`` implicitly into an empty string here. - - `autoescape` - If set to ``True`` the XML/HTML autoescaping feature is enabled by - default. For more details about autoescaping see - :class:`~markupsafe.Markup`. As of Jinja 2.4 this can also - be a callable that is passed the template name and has to - return ``True`` or ``False`` depending on autoescape should be - enabled by default. - - .. versionchanged:: 2.4 - `autoescape` can now be a function - - `loader` - The template loader for this environment. - - `cache_size` - The size of the cache. Per default this is ``400`` which means - that if more than 400 templates are loaded the loader will clean - out the least recently used template. If the cache size is set to - ``0`` templates are recompiled all the time, if the cache size is - ``-1`` the cache will not be cleaned. - - .. versionchanged:: 2.8 - The cache size was increased to 400 from a low 50. - - `auto_reload` - Some loaders load templates from locations where the template - sources may change (ie: file system or database). If - ``auto_reload`` is set to ``True`` (default) every time a template is - requested the loader checks if the source changed and if yes, it - will reload the template. For higher performance it's possible to - disable that. - - `bytecode_cache` - If set to a bytecode cache object, this object will provide a - cache for the internal Jinja bytecode so that templates don't - have to be parsed if they were not changed. - - See :ref:`bytecode-cache` for more information. - - `enable_async` - If set to true this enables async template execution which - allows using async functions and generators. - """ - - #: if this environment is sandboxed. Modifying this variable won't make - #: the environment sandboxed though. For a real sandboxed environment - #: have a look at jinja2.sandbox. This flag alone controls the code - #: generation by the compiler. - sandboxed = False - - #: True if the environment is just an overlay - overlayed = False - - #: the environment this environment is linked to if it is an overlay - linked_to: t.Optional["Environment"] = None - - #: shared environments have this set to `True`. A shared environment - #: must not be modified - shared = False - - #: the class that is used for code generation. See - #: :class:`~jinja2.compiler.CodeGenerator` for more information. - code_generator_class: t.Type["CodeGenerator"] = CodeGenerator - - concat = "".join - - #: the context class that is used for templates. See - #: :class:`~jinja2.runtime.Context` for more information. - context_class: t.Type[Context] = Context - - template_class: t.Type["Template"] - - def __init__( - self, - block_start_string: str = BLOCK_START_STRING, - block_end_string: str = BLOCK_END_STRING, - variable_start_string: str = VARIABLE_START_STRING, - variable_end_string: str = VARIABLE_END_STRING, - comment_start_string: str = COMMENT_START_STRING, - comment_end_string: str = COMMENT_END_STRING, - line_statement_prefix: t.Optional[str] = LINE_STATEMENT_PREFIX, - line_comment_prefix: t.Optional[str] = LINE_COMMENT_PREFIX, - trim_blocks: bool = TRIM_BLOCKS, - lstrip_blocks: bool = LSTRIP_BLOCKS, - newline_sequence: "te.Literal['\\n', '\\r\\n', '\\r']" = NEWLINE_SEQUENCE, - keep_trailing_newline: bool = KEEP_TRAILING_NEWLINE, - extensions: t.Sequence[t.Union[str, t.Type["Extension"]]] = (), - optimized: bool = True, - undefined: t.Type[Undefined] = Undefined, - finalize: t.Optional[t.Callable[..., t.Any]] = None, - autoescape: t.Union[bool, t.Callable[[t.Optional[str]], bool]] = False, - loader: t.Optional["BaseLoader"] = None, - cache_size: int = 400, - auto_reload: bool = True, - bytecode_cache: t.Optional["BytecodeCache"] = None, - enable_async: bool = False, - ): - # !!Important notice!! - # The constructor accepts quite a few arguments that should be - # passed by keyword rather than position. However it's important to - # not change the order of arguments because it's used at least - # internally in those cases: - # - spontaneous environments (i18n extension and Template) - # - unittests - # If parameter changes are required only add parameters at the end - # and don't change the arguments (or the defaults!) of the arguments - # existing already. - - # lexer / parser information - self.block_start_string = block_start_string - self.block_end_string = block_end_string - self.variable_start_string = variable_start_string - self.variable_end_string = variable_end_string - self.comment_start_string = comment_start_string - self.comment_end_string = comment_end_string - self.line_statement_prefix = line_statement_prefix - self.line_comment_prefix = line_comment_prefix - self.trim_blocks = trim_blocks - self.lstrip_blocks = lstrip_blocks - self.newline_sequence = newline_sequence - self.keep_trailing_newline = keep_trailing_newline - - # runtime information - self.undefined: t.Type[Undefined] = undefined - self.optimized = optimized - self.finalize = finalize - self.autoescape = autoescape - - # defaults - self.filters = DEFAULT_FILTERS.copy() - self.tests = DEFAULT_TESTS.copy() - self.globals = DEFAULT_NAMESPACE.copy() - - # set the loader provided - self.loader = loader - self.cache = create_cache(cache_size) - self.bytecode_cache = bytecode_cache - self.auto_reload = auto_reload - - # configurable policies - self.policies = DEFAULT_POLICIES.copy() - - # load extensions - self.extensions = load_extensions(self, extensions) - - self.is_async = enable_async - _environment_config_check(self) - - def add_extension(self, extension: t.Union[str, t.Type["Extension"]]) -> None: - """Adds an extension after the environment was created. - - .. versionadded:: 2.5 - """ - self.extensions.update(load_extensions(self, [extension])) - - def extend(self, **attributes: t.Any) -> None: - """Add the items to the instance of the environment if they do not exist - yet. This is used by :ref:`extensions ` to register - callbacks and configuration values without breaking inheritance. - """ - for key, value in attributes.items(): - if not hasattr(self, key): - setattr(self, key, value) - - def overlay( - self, - block_start_string: str = missing, - block_end_string: str = missing, - variable_start_string: str = missing, - variable_end_string: str = missing, - comment_start_string: str = missing, - comment_end_string: str = missing, - line_statement_prefix: t.Optional[str] = missing, - line_comment_prefix: t.Optional[str] = missing, - trim_blocks: bool = missing, - lstrip_blocks: bool = missing, - newline_sequence: "te.Literal['\\n', '\\r\\n', '\\r']" = missing, - keep_trailing_newline: bool = missing, - extensions: t.Sequence[t.Union[str, t.Type["Extension"]]] = missing, - optimized: bool = missing, - undefined: t.Type[Undefined] = missing, - finalize: t.Optional[t.Callable[..., t.Any]] = missing, - autoescape: t.Union[bool, t.Callable[[t.Optional[str]], bool]] = missing, - loader: t.Optional["BaseLoader"] = missing, - cache_size: int = missing, - auto_reload: bool = missing, - bytecode_cache: t.Optional["BytecodeCache"] = missing, - enable_async: bool = missing, - ) -> "te.Self": - """Create a new overlay environment that shares all the data with the - current environment except for cache and the overridden attributes. - Extensions cannot be removed for an overlayed environment. An overlayed - environment automatically gets all the extensions of the environment it - is linked to plus optional extra extensions. - - Creating overlays should happen after the initial environment was set - up completely. Not all attributes are truly linked, some are just - copied over so modifications on the original environment may not shine - through. - - .. versionchanged:: 3.1.5 - ``enable_async`` is applied correctly. - - .. versionchanged:: 3.1.2 - Added the ``newline_sequence``, ``keep_trailing_newline``, - and ``enable_async`` parameters to match ``__init__``. - """ - args = dict(locals()) - del args["self"], args["cache_size"], args["extensions"], args["enable_async"] - - rv = object.__new__(self.__class__) - rv.__dict__.update(self.__dict__) - rv.overlayed = True - rv.linked_to = self - - for key, value in args.items(): - if value is not missing: - setattr(rv, key, value) - - if cache_size is not missing: - rv.cache = create_cache(cache_size) - else: - rv.cache = copy_cache(self.cache) - - rv.extensions = {} - for key, value in self.extensions.items(): - rv.extensions[key] = value.bind(rv) - if extensions is not missing: - rv.extensions.update(load_extensions(rv, extensions)) - - if enable_async is not missing: - rv.is_async = enable_async - - return _environment_config_check(rv) - - @property - def lexer(self) -> Lexer: - """The lexer for this environment.""" - return get_lexer(self) - - def iter_extensions(self) -> t.Iterator["Extension"]: - """Iterates over the extensions by priority.""" - return iter(sorted(self.extensions.values(), key=lambda x: x.priority)) - - def getitem( - self, obj: t.Any, argument: t.Union[str, t.Any] - ) -> t.Union[t.Any, Undefined]: - """Get an item or attribute of an object but prefer the item.""" - try: - return obj[argument] - except (AttributeError, TypeError, LookupError): - if isinstance(argument, str): - try: - attr = str(argument) - except Exception: - pass - else: - try: - return getattr(obj, attr) - except AttributeError: - pass - return self.undefined(obj=obj, name=argument) - - def getattr(self, obj: t.Any, attribute: str) -> t.Any: - """Get an item or attribute of an object but prefer the attribute. - Unlike :meth:`getitem` the attribute *must* be a string. - """ - try: - return getattr(obj, attribute) - except AttributeError: - pass - try: - return obj[attribute] - except (TypeError, LookupError, AttributeError): - return self.undefined(obj=obj, name=attribute) - - def _filter_test_common( - self, - name: t.Union[str, Undefined], - value: t.Any, - args: t.Optional[t.Sequence[t.Any]], - kwargs: t.Optional[t.Mapping[str, t.Any]], - context: t.Optional[Context], - eval_ctx: t.Optional[EvalContext], - is_filter: bool, - ) -> t.Any: - if is_filter: - env_map = self.filters - type_name = "filter" - else: - env_map = self.tests - type_name = "test" - - func = env_map.get(name) # type: ignore - - if func is None: - msg = f"No {type_name} named {name!r}." - - if isinstance(name, Undefined): - try: - name._fail_with_undefined_error() - except Exception as e: - msg = f"{msg} ({e}; did you forget to quote the callable name?)" - - raise TemplateRuntimeError(msg) - - args = [value, *(args if args is not None else ())] - kwargs = kwargs if kwargs is not None else {} - pass_arg = _PassArg.from_obj(func) - - if pass_arg is _PassArg.context: - if context is None: - raise TemplateRuntimeError( - f"Attempted to invoke a context {type_name} without context." - ) - - args.insert(0, context) - elif pass_arg is _PassArg.eval_context: - if eval_ctx is None: - if context is not None: - eval_ctx = context.eval_ctx - else: - eval_ctx = EvalContext(self) - - args.insert(0, eval_ctx) - elif pass_arg is _PassArg.environment: - args.insert(0, self) - - return func(*args, **kwargs) - - def call_filter( - self, - name: str, - value: t.Any, - args: t.Optional[t.Sequence[t.Any]] = None, - kwargs: t.Optional[t.Mapping[str, t.Any]] = None, - context: t.Optional[Context] = None, - eval_ctx: t.Optional[EvalContext] = None, - ) -> t.Any: - """Invoke a filter on a value the same way the compiler does. - - This might return a coroutine if the filter is running from an - environment in async mode and the filter supports async - execution. It's your responsibility to await this if needed. - - .. versionadded:: 2.7 - """ - return self._filter_test_common( - name, value, args, kwargs, context, eval_ctx, True - ) - - def call_test( - self, - name: str, - value: t.Any, - args: t.Optional[t.Sequence[t.Any]] = None, - kwargs: t.Optional[t.Mapping[str, t.Any]] = None, - context: t.Optional[Context] = None, - eval_ctx: t.Optional[EvalContext] = None, - ) -> t.Any: - """Invoke a test on a value the same way the compiler does. - - This might return a coroutine if the test is running from an - environment in async mode and the test supports async execution. - It's your responsibility to await this if needed. - - .. versionchanged:: 3.0 - Tests support ``@pass_context``, etc. decorators. Added - the ``context`` and ``eval_ctx`` parameters. - - .. versionadded:: 2.7 - """ - return self._filter_test_common( - name, value, args, kwargs, context, eval_ctx, False - ) - - @internalcode - def parse( - self, - source: str, - name: t.Optional[str] = None, - filename: t.Optional[str] = None, - ) -> nodes.Template: - """Parse the sourcecode and return the abstract syntax tree. This - tree of nodes is used by the compiler to convert the template into - executable source- or bytecode. This is useful for debugging or to - extract information from templates. - - If you are :ref:`developing Jinja extensions ` - this gives you a good overview of the node tree generated. - """ - try: - return self._parse(source, name, filename) - except TemplateSyntaxError: - self.handle_exception(source=source) - - def _parse( - self, source: str, name: t.Optional[str], filename: t.Optional[str] - ) -> nodes.Template: - """Internal parsing function used by `parse` and `compile`.""" - return Parser(self, source, name, filename).parse() - - def lex( - self, - source: str, - name: t.Optional[str] = None, - filename: t.Optional[str] = None, - ) -> t.Iterator[t.Tuple[int, str, str]]: - """Lex the given sourcecode and return a generator that yields - tokens as tuples in the form ``(lineno, token_type, value)``. - This can be useful for :ref:`extension development ` - and debugging templates. - - This does not perform preprocessing. If you want the preprocessing - of the extensions to be applied you have to filter source through - the :meth:`preprocess` method. - """ - source = str(source) - try: - return self.lexer.tokeniter(source, name, filename) - except TemplateSyntaxError: - self.handle_exception(source=source) - - def preprocess( - self, - source: str, - name: t.Optional[str] = None, - filename: t.Optional[str] = None, - ) -> str: - """Preprocesses the source with all extensions. This is automatically - called for all parsing and compiling methods but *not* for :meth:`lex` - because there you usually only want the actual source tokenized. - """ - return reduce( - lambda s, e: e.preprocess(s, name, filename), - self.iter_extensions(), - str(source), - ) - - def _tokenize( - self, - source: str, - name: t.Optional[str], - filename: t.Optional[str] = None, - state: t.Optional[str] = None, - ) -> TokenStream: - """Called by the parser to do the preprocessing and filtering - for all the extensions. Returns a :class:`~jinja2.lexer.TokenStream`. - """ - source = self.preprocess(source, name, filename) - stream = self.lexer.tokenize(source, name, filename, state) - - for ext in self.iter_extensions(): - stream = ext.filter_stream(stream) # type: ignore - - if not isinstance(stream, TokenStream): - stream = TokenStream(stream, name, filename) - - return stream - - def _generate( - self, - source: nodes.Template, - name: t.Optional[str], - filename: t.Optional[str], - defer_init: bool = False, - ) -> str: - """Internal hook that can be overridden to hook a different generate - method in. - - .. versionadded:: 2.5 - """ - return generate( # type: ignore - source, - self, - name, - filename, - defer_init=defer_init, - optimized=self.optimized, - ) - - def _compile(self, source: str, filename: str) -> CodeType: - """Internal hook that can be overridden to hook a different compile - method in. - - .. versionadded:: 2.5 - """ - return compile(source, filename, "exec") - - @typing.overload - def compile( - self, - source: t.Union[str, nodes.Template], - name: t.Optional[str] = None, - filename: t.Optional[str] = None, - raw: "te.Literal[False]" = False, - defer_init: bool = False, - ) -> CodeType: ... - - @typing.overload - def compile( - self, - source: t.Union[str, nodes.Template], - name: t.Optional[str] = None, - filename: t.Optional[str] = None, - raw: "te.Literal[True]" = ..., - defer_init: bool = False, - ) -> str: ... - - @internalcode - def compile( - self, - source: t.Union[str, nodes.Template], - name: t.Optional[str] = None, - filename: t.Optional[str] = None, - raw: bool = False, - defer_init: bool = False, - ) -> t.Union[str, CodeType]: - """Compile a node or template source code. The `name` parameter is - the load name of the template after it was joined using - :meth:`join_path` if necessary, not the filename on the file system. - the `filename` parameter is the estimated filename of the template on - the file system. If the template came from a database or memory this - can be omitted. - - The return value of this method is a python code object. If the `raw` - parameter is `True` the return value will be a string with python - code equivalent to the bytecode returned otherwise. This method is - mainly used internally. - - `defer_init` is use internally to aid the module code generator. This - causes the generated code to be able to import without the global - environment variable to be set. - - .. versionadded:: 2.4 - `defer_init` parameter added. - """ - source_hint = None - try: - if isinstance(source, str): - source_hint = source - source = self._parse(source, name, filename) - source = self._generate(source, name, filename, defer_init=defer_init) - if raw: - return source - if filename is None: - filename = "