docker config
This commit is contained in:
parent
dfc9049b39
commit
c3baa54215
57
.dockerignore
Normal file
57
.dockerignore
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
# Ambiente virtual
|
||||||
|
venv/
|
||||||
|
__pycache__/
|
||||||
|
*.py[cod]
|
||||||
|
*$py.class
|
||||||
|
*.so
|
||||||
|
.Python
|
||||||
|
env/
|
||||||
|
build/
|
||||||
|
develop-eggs/
|
||||||
|
dist/
|
||||||
|
downloads/
|
||||||
|
eggs/
|
||||||
|
.eggs/
|
||||||
|
lib/
|
||||||
|
lib64/
|
||||||
|
parts/
|
||||||
|
sdist/
|
||||||
|
var/
|
||||||
|
*.egg-info/
|
||||||
|
.installed.cfg
|
||||||
|
*.egg
|
||||||
|
|
||||||
|
# Arquivos específicos do Docker
|
||||||
|
.dockerignore
|
||||||
|
Dockerfile
|
||||||
|
docker-compose.yml
|
||||||
|
|
||||||
|
# Git
|
||||||
|
.git
|
||||||
|
.gitignore
|
||||||
|
|
||||||
|
# Logs e dados
|
||||||
|
logs/
|
||||||
|
*.log
|
||||||
|
data/
|
||||||
|
|
||||||
|
# Configuração local
|
||||||
|
.env
|
||||||
|
.env.local
|
||||||
|
.env.development
|
||||||
|
.env.test
|
||||||
|
.env.production
|
||||||
|
|
||||||
|
# IDEs e editores
|
||||||
|
.idea/
|
||||||
|
.vscode/
|
||||||
|
*.swp
|
||||||
|
*.swo
|
||||||
|
|
||||||
|
# Arquivos de teste
|
||||||
|
tests/
|
||||||
|
test_*
|
||||||
|
*_test.py
|
||||||
|
|
||||||
|
# Documentação
|
||||||
|
docs/
|
2
.env
2
.env
@ -26,7 +26,7 @@ TOOLS_CACHE_TTL=3600
|
|||||||
# Configurações JWT
|
# Configurações JWT
|
||||||
JWT_SECRET_KEY="f6884ef5be4c279686ff90f0ed9d4656685eef9807245019ac94a3fbe32b0938"
|
JWT_SECRET_KEY="f6884ef5be4c279686ff90f0ed9d4656685eef9807245019ac94a3fbe32b0938"
|
||||||
JWT_ALGORITHM="HS256"
|
JWT_ALGORITHM="HS256"
|
||||||
JWT_EXPIRATION_TIME=3600 # Em minutos
|
JWT_EXPIRATION_TIME=3600
|
||||||
|
|
||||||
# SendGrid
|
# SendGrid
|
||||||
SENDGRID_API_KEY="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"
|
SENDGRID_API_KEY="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"
|
||||||
|
@ -17,7 +17,8 @@ TOOLS_CACHE_TTL=3600
|
|||||||
# Configurações JWT
|
# Configurações JWT
|
||||||
JWT_SECRET_KEY="sua-chave-secreta-jwt"
|
JWT_SECRET_KEY="sua-chave-secreta-jwt"
|
||||||
JWT_ALGORITHM="HS256"
|
JWT_ALGORITHM="HS256"
|
||||||
JWT_EXPIRATION_TIME=30 # Em minutos
|
# Em minutos
|
||||||
|
JWT_EXPIRATION_TIME=30
|
||||||
|
|
||||||
# SendGrid
|
# SendGrid
|
||||||
SENDGRID_API_KEY="sua-sendgrid-api-key"
|
SENDGRID_API_KEY="sua-sendgrid-api-key"
|
||||||
|
@ -1,247 +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 VIRTUAL_ENV_PROMPT altogether.
|
|
||||||
if (Test-Path -Path Env:VIRTUAL_ENV_PROMPT) {
|
|
||||||
Remove-Item -Path env:VIRTUAL_ENV_PROMPT
|
|
||||||
}
|
|
||||||
|
|
||||||
# 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 virtual 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
|
|
||||||
}
|
|
||||||
$env:VIRTUAL_ENV_PROMPT = $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"
|
|
@ -1,69 +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
|
|
||||||
unset VIRTUAL_ENV_PROMPT
|
|
||||||
if [ ! "${1:-}" = "nondestructive" ] ; then
|
|
||||||
# Self destruct!
|
|
||||||
unset -f deactivate
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
# unset irrelevant variables
|
|
||||||
deactivate nondestructive
|
|
||||||
|
|
||||||
VIRTUAL_ENV=/home/davidson/Projects/study-ia/a2a-saas/.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
|
|
||||||
VIRTUAL_ENV_PROMPT='(.venv) '
|
|
||||||
export VIRTUAL_ENV_PROMPT
|
|
||||||
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
|
|
@ -1,26 +0,0 @@
|
|||||||
# This file must be used with "source bin/activate.csh" *from csh*.
|
|
||||||
# You cannot run it directly.
|
|
||||||
# Created by Davide Di Blasi <davidedb@gmail.com>.
|
|
||||||
# Ported to Python 3.3 venv by Andrew Svetlov <andrew.svetlov@gmail.com>
|
|
||||||
|
|
||||||
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; unsetenv VIRTUAL_ENV_PROMPT; test "\!:*" != "nondestructive" && unalias deactivate'
|
|
||||||
|
|
||||||
# Unset irrelevant variables.
|
|
||||||
deactivate nondestructive
|
|
||||||
|
|
||||||
setenv VIRTUAL_ENV /home/davidson/Projects/study-ia/a2a-saas/.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"
|
|
||||||
setenv VIRTUAL_ENV_PROMPT '(.venv) '
|
|
||||||
endif
|
|
||||||
|
|
||||||
alias pydoc python -m pydoc
|
|
||||||
|
|
||||||
rehash
|
|
@ -1,69 +0,0 @@
|
|||||||
# This file must be used with "source <venv>/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"
|
|
||||||
set -e _OLD_FISH_PROMPT_OVERRIDE
|
|
||||||
# prevents error when using nested fish instances (Issue #93858)
|
|
||||||
if functions -q _old_fish_prompt
|
|
||||||
functions -e fish_prompt
|
|
||||||
functions -c _old_fish_prompt fish_prompt
|
|
||||||
functions -e _old_fish_prompt
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
set -e VIRTUAL_ENV
|
|
||||||
set -e VIRTUAL_ENV_PROMPT
|
|
||||||
if test "$argv[1]" != "nondestructive"
|
|
||||||
# Self-destruct!
|
|
||||||
functions -e deactivate
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
# Unset irrelevant variables.
|
|
||||||
deactivate nondestructive
|
|
||||||
|
|
||||||
set -gx VIRTUAL_ENV /home/davidson/Projects/study-ia/a2a-saas/.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"
|
|
||||||
set -gx VIRTUAL_ENV_PROMPT '(.venv) '
|
|
||||||
end
|
|
@ -1,8 +0,0 @@
|
|||||||
#!/home/davidson/Projects/study-ia/a2a-saas/.venv/bin/python
|
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
import re
|
|
||||||
import sys
|
|
||||||
from google.adk.cli import main
|
|
||||||
if __name__ == '__main__':
|
|
||||||
sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0])
|
|
||||||
sys.exit(main())
|
|
@ -1,8 +0,0 @@
|
|||||||
#!/home/davidson/Projects/study-ia/a2a-saas/.venv/bin/python
|
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
import re
|
|
||||||
import sys
|
|
||||||
from distro.distro import main
|
|
||||||
if __name__ == '__main__':
|
|
||||||
sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0])
|
|
||||||
sys.exit(main())
|
|
@ -1,8 +0,0 @@
|
|||||||
#!/home/davidson/Projects/study-ia/a2a-saas/.venv/bin/python
|
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
import re
|
|
||||||
import sys
|
|
||||||
from dotenv.__main__ import cli
|
|
||||||
if __name__ == '__main__':
|
|
||||||
sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0])
|
|
||||||
sys.exit(cli())
|
|
@ -1,8 +0,0 @@
|
|||||||
#!/home/davidson/Projects/study-ia/a2a-saas/.venv/bin/python
|
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
import re
|
|
||||||
import sys
|
|
||||||
from numpy.f2py.f2py2e import main
|
|
||||||
if __name__ == '__main__':
|
|
||||||
sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0])
|
|
||||||
sys.exit(main())
|
|
@ -1,8 +0,0 @@
|
|||||||
#!/home/davidson/Projects/study-ia/a2a-saas/.venv/bin/python
|
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
import re
|
|
||||||
import sys
|
|
||||||
from fastapi.cli import main
|
|
||||||
if __name__ == '__main__':
|
|
||||||
sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0])
|
|
||||||
sys.exit(main())
|
|
@ -1,8 +0,0 @@
|
|||||||
#!/home/davidson/Projects/study-ia/a2a-saas/.venv/bin/python
|
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
import re
|
|
||||||
import sys
|
|
||||||
from httpx import main
|
|
||||||
if __name__ == '__main__':
|
|
||||||
sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0])
|
|
||||||
sys.exit(main())
|
|
@ -1,8 +0,0 @@
|
|||||||
#!/home/davidson/Projects/study-ia/a2a-saas/.venv/bin/python
|
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
import re
|
|
||||||
import sys
|
|
||||||
from huggingface_hub.commands.huggingface_cli import main
|
|
||||||
if __name__ == '__main__':
|
|
||||||
sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0])
|
|
||||||
sys.exit(main())
|
|
@ -1,8 +0,0 @@
|
|||||||
#!/home/davidson/Projects/study-ia/a2a-saas/.venv/bin/python
|
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
import re
|
|
||||||
import sys
|
|
||||||
from jsonschema.cli import main
|
|
||||||
if __name__ == '__main__':
|
|
||||||
sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0])
|
|
||||||
sys.exit(main())
|
|
@ -1,8 +0,0 @@
|
|||||||
#!/home/davidson/Projects/study-ia/a2a-saas/.venv/bin/python
|
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
import re
|
|
||||||
import sys
|
|
||||||
from litellm import run_server
|
|
||||||
if __name__ == '__main__':
|
|
||||||
sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0])
|
|
||||||
sys.exit(run_server())
|
|
@ -1,8 +0,0 @@
|
|||||||
#!/home/davidson/Projects/study-ia/a2a-saas/.venv/bin/python
|
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
import re
|
|
||||||
import sys
|
|
||||||
from mcp.cli import app
|
|
||||||
if __name__ == '__main__':
|
|
||||||
sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0])
|
|
||||||
sys.exit(app())
|
|
@ -1,8 +0,0 @@
|
|||||||
#!/home/davidson/Projects/study-ia/a2a-saas/.venv/bin/python
|
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
import re
|
|
||||||
import sys
|
|
||||||
from charset_normalizer import cli
|
|
||||||
if __name__ == '__main__':
|
|
||||||
sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0])
|
|
||||||
sys.exit(cli.cli_detect())
|
|
@ -1,8 +0,0 @@
|
|||||||
#!/home/davidson/Projects/study-ia/a2a-saas/.venv/bin/python
|
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
import re
|
|
||||||
import sys
|
|
||||||
from numpy._configtool import main
|
|
||||||
if __name__ == '__main__':
|
|
||||||
sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0])
|
|
||||||
sys.exit(main())
|
|
@ -1,8 +0,0 @@
|
|||||||
#!/home/davidson/Projects/study-ia/a2a-saas/.venv/bin/python
|
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
import re
|
|
||||||
import sys
|
|
||||||
from openai.cli import main
|
|
||||||
if __name__ == '__main__':
|
|
||||||
sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0])
|
|
||||||
sys.exit(main())
|
|
@ -1,8 +0,0 @@
|
|||||||
#!/home/davidson/Projects/study-ia/a2a-saas/.venv/bin/python
|
|
||||||
# -*- 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())
|
|
@ -1,8 +0,0 @@
|
|||||||
#!/home/davidson/Projects/study-ia/a2a-saas/.venv/bin/python
|
|
||||||
# -*- 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())
|
|
@ -1,8 +0,0 @@
|
|||||||
#!/home/davidson/Projects/study-ia/a2a-saas/.venv/bin/python
|
|
||||||
# -*- 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())
|
|
@ -1,8 +0,0 @@
|
|||||||
#!/home/davidson/Projects/study-ia/a2a-saas/.venv/bin/python
|
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
import re
|
|
||||||
import sys
|
|
||||||
from rsa.cli import decrypt
|
|
||||||
if __name__ == '__main__':
|
|
||||||
sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0])
|
|
||||||
sys.exit(decrypt())
|
|
@ -1,8 +0,0 @@
|
|||||||
#!/home/davidson/Projects/study-ia/a2a-saas/.venv/bin/python
|
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
import re
|
|
||||||
import sys
|
|
||||||
from rsa.cli import encrypt
|
|
||||||
if __name__ == '__main__':
|
|
||||||
sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0])
|
|
||||||
sys.exit(encrypt())
|
|
@ -1,8 +0,0 @@
|
|||||||
#!/home/davidson/Projects/study-ia/a2a-saas/.venv/bin/python
|
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
import re
|
|
||||||
import sys
|
|
||||||
from rsa.cli import keygen
|
|
||||||
if __name__ == '__main__':
|
|
||||||
sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0])
|
|
||||||
sys.exit(keygen())
|
|
@ -1,8 +0,0 @@
|
|||||||
#!/home/davidson/Projects/study-ia/a2a-saas/.venv/bin/python
|
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
import re
|
|
||||||
import sys
|
|
||||||
from rsa.util import private_to_public
|
|
||||||
if __name__ == '__main__':
|
|
||||||
sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0])
|
|
||||||
sys.exit(private_to_public())
|
|
@ -1,8 +0,0 @@
|
|||||||
#!/home/davidson/Projects/study-ia/a2a-saas/.venv/bin/python
|
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
import re
|
|
||||||
import sys
|
|
||||||
from rsa.cli import sign
|
|
||||||
if __name__ == '__main__':
|
|
||||||
sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0])
|
|
||||||
sys.exit(sign())
|
|
@ -1,8 +0,0 @@
|
|||||||
#!/home/davidson/Projects/study-ia/a2a-saas/.venv/bin/python
|
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
import re
|
|
||||||
import sys
|
|
||||||
from rsa.cli import verify
|
|
||||||
if __name__ == '__main__':
|
|
||||||
sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0])
|
|
||||||
sys.exit(verify())
|
|
@ -1 +0,0 @@
|
|||||||
/usr/bin/python
|
|
@ -1 +0,0 @@
|
|||||||
python
|
|
@ -1 +0,0 @@
|
|||||||
python
|
|
@ -1,8 +0,0 @@
|
|||||||
#!/home/davidson/Projects/study-ia/a2a-saas/.venv/bin/python
|
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
import re
|
|
||||||
import sys
|
|
||||||
from google.cloud.aiplatform.tensorboard.uploader_main import run_main
|
|
||||||
if __name__ == '__main__':
|
|
||||||
sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0])
|
|
||||||
sys.exit(run_main())
|
|
@ -1,8 +0,0 @@
|
|||||||
#!/home/davidson/Projects/study-ia/a2a-saas/.venv/bin/python
|
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
import re
|
|
||||||
import sys
|
|
||||||
from tqdm.cli import main
|
|
||||||
if __name__ == '__main__':
|
|
||||||
sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0])
|
|
||||||
sys.exit(main())
|
|
@ -1,8 +0,0 @@
|
|||||||
#!/home/davidson/Projects/study-ia/a2a-saas/.venv/bin/python
|
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
import re
|
|
||||||
import sys
|
|
||||||
from uvicorn.main import main
|
|
||||||
if __name__ == '__main__':
|
|
||||||
sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0])
|
|
||||||
sys.exit(main())
|
|
@ -1,8 +0,0 @@
|
|||||||
#!/home/davidson/Projects/study-ia/a2a-saas/.venv/bin/python
|
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
import re
|
|
||||||
import sys
|
|
||||||
from websockets.cli import main
|
|
||||||
if __name__ == '__main__':
|
|
||||||
sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0])
|
|
||||||
sys.exit(main())
|
|
@ -1,164 +0,0 @@
|
|||||||
/* -*- indent-tabs-mode: nil; tab-width: 4; -*- */
|
|
||||||
|
|
||||||
/* Greenlet object interface */
|
|
||||||
|
|
||||||
#ifndef Py_GREENLETOBJECT_H
|
|
||||||
#define Py_GREENLETOBJECT_H
|
|
||||||
|
|
||||||
|
|
||||||
#include <Python.h>
|
|
||||||
|
|
||||||
#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 */
|
|
@ -1 +0,0 @@
|
|||||||
pip
|
|
@ -1,21 +0,0 @@
|
|||||||
The MIT License (MIT)
|
|
||||||
|
|
||||||
Copyright (c) 2017 Laurent LAPORTE
|
|
||||||
|
|
||||||
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.
|
|
@ -1,195 +0,0 @@
|
|||||||
Metadata-Version: 2.2
|
|
||||||
Name: Deprecated
|
|
||||||
Version: 1.2.18
|
|
||||||
Summary: Python @deprecated decorator to deprecate old python classes, functions or methods.
|
|
||||||
Home-page: https://github.com/laurent-laporte-pro/deprecated
|
|
||||||
Author: Laurent LAPORTE
|
|
||||||
Author-email: laurent.laporte.pro@gmail.com
|
|
||||||
License: MIT
|
|
||||||
Project-URL: Documentation, https://deprecated.readthedocs.io/en/latest/
|
|
||||||
Project-URL: Source, https://github.com/laurent-laporte-pro/deprecated
|
|
||||||
Project-URL: Bug Tracker, https://github.com/laurent-laporte-pro/deprecated/issues
|
|
||||||
Keywords: deprecate,deprecated,deprecation,warning,warn,decorator
|
|
||||||
Platform: any
|
|
||||||
Classifier: Development Status :: 5 - Production/Stable
|
|
||||||
Classifier: Environment :: Web Environment
|
|
||||||
Classifier: Intended Audience :: Developers
|
|
||||||
Classifier: License :: OSI Approved :: MIT License
|
|
||||||
Classifier: Operating System :: OS Independent
|
|
||||||
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.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
|
|
||||||
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
||||||
Requires-Python: >=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*
|
|
||||||
Description-Content-Type: text/x-rst
|
|
||||||
License-File: LICENSE.rst
|
|
||||||
Requires-Dist: wrapt<2,>=1.10
|
|
||||||
Provides-Extra: dev
|
|
||||||
Requires-Dist: tox; extra == "dev"
|
|
||||||
Requires-Dist: PyTest; extra == "dev"
|
|
||||||
Requires-Dist: PyTest-Cov; extra == "dev"
|
|
||||||
Requires-Dist: bump2version<1; extra == "dev"
|
|
||||||
Requires-Dist: setuptools; python_version >= "3.12" and extra == "dev"
|
|
||||||
Dynamic: author
|
|
||||||
Dynamic: author-email
|
|
||||||
Dynamic: classifier
|
|
||||||
Dynamic: description
|
|
||||||
Dynamic: description-content-type
|
|
||||||
Dynamic: home-page
|
|
||||||
Dynamic: keywords
|
|
||||||
Dynamic: license
|
|
||||||
Dynamic: platform
|
|
||||||
Dynamic: project-url
|
|
||||||
Dynamic: provides-extra
|
|
||||||
Dynamic: requires-dist
|
|
||||||
Dynamic: requires-python
|
|
||||||
Dynamic: summary
|
|
||||||
|
|
||||||
|
|
||||||
Deprecated Library
|
|
||||||
------------------
|
|
||||||
|
|
||||||
Deprecated is Easy to Use
|
|
||||||
`````````````````````````
|
|
||||||
|
|
||||||
If you need to mark a function or a method as deprecated,
|
|
||||||
you can use the ``@deprecated`` decorator:
|
|
||||||
|
|
||||||
Save in a hello.py:
|
|
||||||
|
|
||||||
.. code:: python
|
|
||||||
|
|
||||||
from deprecated import deprecated
|
|
||||||
|
|
||||||
|
|
||||||
@deprecated(version='1.2.1', reason="You should use another function")
|
|
||||||
def some_old_function(x, y):
|
|
||||||
return x + y
|
|
||||||
|
|
||||||
|
|
||||||
class SomeClass(object):
|
|
||||||
@deprecated(version='1.3.0', reason="This method is deprecated")
|
|
||||||
def some_old_method(self, x, y):
|
|
||||||
return x + y
|
|
||||||
|
|
||||||
|
|
||||||
some_old_function(12, 34)
|
|
||||||
obj = SomeClass()
|
|
||||||
obj.some_old_method(5, 8)
|
|
||||||
|
|
||||||
|
|
||||||
And Easy to Setup
|
|
||||||
`````````````````
|
|
||||||
|
|
||||||
And run it:
|
|
||||||
|
|
||||||
.. code:: bash
|
|
||||||
|
|
||||||
$ pip install Deprecated
|
|
||||||
$ python hello.py
|
|
||||||
hello.py:15: DeprecationWarning: Call to deprecated function (or staticmethod) some_old_function.
|
|
||||||
(You should use another function) -- Deprecated since version 1.2.0.
|
|
||||||
some_old_function(12, 34)
|
|
||||||
hello.py:17: DeprecationWarning: Call to deprecated method some_old_method.
|
|
||||||
(This method is deprecated) -- Deprecated since version 1.3.0.
|
|
||||||
obj.some_old_method(5, 8)
|
|
||||||
|
|
||||||
|
|
||||||
You can document your code
|
|
||||||
``````````````````````````
|
|
||||||
|
|
||||||
Have you ever wonder how to document that some functions, classes, methods, etc. are deprecated?
|
|
||||||
This is now possible with the integrated Sphinx directives:
|
|
||||||
|
|
||||||
For instance, in hello_sphinx.py:
|
|
||||||
|
|
||||||
.. code:: python
|
|
||||||
|
|
||||||
from deprecated.sphinx import deprecated
|
|
||||||
from deprecated.sphinx import versionadded
|
|
||||||
from deprecated.sphinx import versionchanged
|
|
||||||
|
|
||||||
|
|
||||||
@versionadded(version='1.0', reason="This function is new")
|
|
||||||
def function_one():
|
|
||||||
'''This is the function one'''
|
|
||||||
|
|
||||||
|
|
||||||
@versionchanged(version='1.0', reason="This function is modified")
|
|
||||||
def function_two():
|
|
||||||
'''This is the function two'''
|
|
||||||
|
|
||||||
|
|
||||||
@deprecated(version='1.0', reason="This function will be removed soon")
|
|
||||||
def function_three():
|
|
||||||
'''This is the function three'''
|
|
||||||
|
|
||||||
|
|
||||||
function_one()
|
|
||||||
function_two()
|
|
||||||
function_three() # warns
|
|
||||||
|
|
||||||
help(function_one)
|
|
||||||
help(function_two)
|
|
||||||
help(function_three)
|
|
||||||
|
|
||||||
|
|
||||||
The result it immediate
|
|
||||||
```````````````````````
|
|
||||||
|
|
||||||
Run it:
|
|
||||||
|
|
||||||
.. code:: bash
|
|
||||||
|
|
||||||
$ python hello_sphinx.py
|
|
||||||
|
|
||||||
hello_sphinx.py:23: DeprecationWarning: Call to deprecated function (or staticmethod) function_three.
|
|
||||||
(This function will be removed soon) -- Deprecated since version 1.0.
|
|
||||||
function_three() # warns
|
|
||||||
|
|
||||||
Help on function function_one in module __main__:
|
|
||||||
|
|
||||||
function_one()
|
|
||||||
This is the function one
|
|
||||||
|
|
||||||
.. versionadded:: 1.0
|
|
||||||
This function is new
|
|
||||||
|
|
||||||
Help on function function_two in module __main__:
|
|
||||||
|
|
||||||
function_two()
|
|
||||||
This is the function two
|
|
||||||
|
|
||||||
.. versionchanged:: 1.0
|
|
||||||
This function is modified
|
|
||||||
|
|
||||||
Help on function function_three in module __main__:
|
|
||||||
|
|
||||||
function_three()
|
|
||||||
This is the function three
|
|
||||||
|
|
||||||
.. deprecated:: 1.0
|
|
||||||
This function will be removed soon
|
|
||||||
|
|
||||||
|
|
||||||
Links
|
|
||||||
`````
|
|
||||||
|
|
||||||
* `Python package index (PyPi) <https://pypi.org/project/Deprecated/>`_
|
|
||||||
* `GitHub website <https://github.com/laurent-laporte-pro/deprecated>`_
|
|
||||||
* `Read The Docs <https://readthedocs.org/projects/deprecated>`_
|
|
||||||
* `EBook on Lulu.com <http://www.lulu.com/commerce/index.php?fBuyContent=21305117>`_
|
|
||||||
* `StackOverFlow Q&A <https://stackoverflow.com/a/40301488/1513933>`_
|
|
||||||
* `Development version
|
|
||||||
<https://github.com/laurent-laporte-pro/deprecated/zipball/master#egg=Deprecated-dev>`_
|
|
||||||
|
|
@ -1,12 +0,0 @@
|
|||||||
Deprecated-1.2.18.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4
|
|
||||||
Deprecated-1.2.18.dist-info/LICENSE.rst,sha256=HoPt0VvkGbXVveNy4yXlJ_9PmRX1SOfHUxS0H2aZ6Dw,1081
|
|
||||||
Deprecated-1.2.18.dist-info/METADATA,sha256=4CrUw5Bl8_NsBuZYe0Nw-mIwQnVpT1CnmBYU9BqOuq8,5725
|
|
||||||
Deprecated-1.2.18.dist-info/RECORD,,
|
|
||||||
Deprecated-1.2.18.dist-info/WHEEL,sha256=9Hm2OB-j1QcCUq9Jguht7ayGIIZBRTdOXD1qg9cCgPM,109
|
|
||||||
Deprecated-1.2.18.dist-info/top_level.txt,sha256=nHbOYawKPQQE5lQl-toUB1JBRJjUyn_m_Mb8RVJ0RjA,11
|
|
||||||
deprecated/__init__.py,sha256=yZNbmDKXF4PLtp_Ikdb_9ObJLkHuFSUHvqidFTKKGFM,351
|
|
||||||
deprecated/__pycache__/__init__.cpython-310.pyc,,
|
|
||||||
deprecated/__pycache__/classic.cpython-310.pyc,,
|
|
||||||
deprecated/__pycache__/sphinx.cpython-310.pyc,,
|
|
||||||
deprecated/classic.py,sha256=7WXOt4Vf1NhrUznm8ypjS50CMyAdZwrGT58Lhb8fW14,10609
|
|
||||||
deprecated/sphinx.py,sha256=cOKnXbDyFAwDr5O7HBEpgQrx-J-qfp57sfdK_LabDxs,11109
|
|
@ -1,6 +0,0 @@
|
|||||||
Wheel-Version: 1.0
|
|
||||||
Generator: setuptools (75.8.0)
|
|
||||||
Root-Is-Purelib: true
|
|
||||||
Tag: py2-none-any
|
|
||||||
Tag: py3-none-any
|
|
||||||
|
|
@ -1 +0,0 @@
|
|||||||
deprecated
|
|
@ -1 +0,0 @@
|
|||||||
pip
|
|
@ -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.
|
|
@ -1,92 +0,0 @@
|
|||||||
Metadata-Version: 2.1
|
|
||||||
Name: MarkupSafe
|
|
||||||
Version: 3.0.2
|
|
||||||
Summary: Safely add untrusted strings to HTML/XML markup.
|
|
||||||
Maintainer-email: Pallets <contact@palletsprojects.com>
|
|
||||||
License: 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.
|
|
||||||
|
|
||||||
Project-URL: Donate, https://palletsprojects.com/donate
|
|
||||||
Project-URL: Documentation, https://markupsafe.palletsprojects.com/
|
|
||||||
Project-URL: Changes, https://markupsafe.palletsprojects.com/changes/
|
|
||||||
Project-URL: Source, https://github.com/pallets/markupsafe/
|
|
||||||
Project-URL: Chat, https://discord.gg/pallets
|
|
||||||
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
|
|
||||||
Requires-Python: >=3.9
|
|
||||||
Description-Content-Type: text/markdown
|
|
||||||
License-File: LICENSE.txt
|
|
||||||
|
|
||||||
# MarkupSafe
|
|
||||||
|
|
||||||
MarkupSafe implements a text object that escapes characters so it is
|
|
||||||
safe to use in HTML and XML. Characters that have special meanings are
|
|
||||||
replaced so that they display as the actual characters. This mitigates
|
|
||||||
injection attacks, meaning untrusted user input can safely be displayed
|
|
||||||
on a page.
|
|
||||||
|
|
||||||
|
|
||||||
## Examples
|
|
||||||
|
|
||||||
```pycon
|
|
||||||
>>> from markupsafe import Markup, escape
|
|
||||||
|
|
||||||
>>> # escape replaces special characters and wraps in Markup
|
|
||||||
>>> escape("<script>alert(document.cookie);</script>")
|
|
||||||
Markup('<script>alert(document.cookie);</script>')
|
|
||||||
|
|
||||||
>>> # wrap in Markup to mark text "safe" and prevent escaping
|
|
||||||
>>> Markup("<strong>Hello</strong>")
|
|
||||||
Markup('<strong>hello</strong>')
|
|
||||||
|
|
||||||
>>> escape(Markup("<strong>Hello</strong>"))
|
|
||||||
Markup('<strong>hello</strong>')
|
|
||||||
|
|
||||||
>>> # Markup is a str subclass
|
|
||||||
>>> # methods and operators escape their arguments
|
|
||||||
>>> template = Markup("Hello <em>{name}</em>")
|
|
||||||
>>> template.format(name='"World"')
|
|
||||||
Markup('Hello <em>"World"</em>')
|
|
||||||
```
|
|
||||||
|
|
||||||
## Donate
|
|
||||||
|
|
||||||
The Pallets organization develops and supports MarkupSafe 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
|
|
@ -1,14 +0,0 @@
|
|||||||
MarkupSafe-3.0.2.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4
|
|
||||||
MarkupSafe-3.0.2.dist-info/LICENSE.txt,sha256=SJqOEQhQntmKN7uYPhHg9-HTHwvY-Zp5yESOf_N9B-o,1475
|
|
||||||
MarkupSafe-3.0.2.dist-info/METADATA,sha256=aAwbZhSmXdfFuMM-rEHpeiHRkBOGESyVLJIuwzHP-nw,3975
|
|
||||||
MarkupSafe-3.0.2.dist-info/RECORD,,
|
|
||||||
MarkupSafe-3.0.2.dist-info/WHEEL,sha256=_kVlewavvOSnwZE_whBk3jlE_Ob-nL5GvlVcLkpXSD8,151
|
|
||||||
MarkupSafe-3.0.2.dist-info/top_level.txt,sha256=qy0Plje5IJuvsCBjejJyhDCjEAdcDLK_2agVcex8Z6U,11
|
|
||||||
markupsafe/__init__.py,sha256=sr-U6_27DfaSrj5jnHYxWN-pvhM27sjlDplMDPZKm7k,13214
|
|
||||||
markupsafe/__pycache__/__init__.cpython-310.pyc,,
|
|
||||||
markupsafe/__pycache__/_native.cpython-310.pyc,,
|
|
||||||
markupsafe/_native.py,sha256=hSLs8Jmz5aqayuengJJ3kdT5PwNpBWpKrmQSdipndC8,210
|
|
||||||
markupsafe/_speedups.c,sha256=O7XulmTo-epI6n2FtMVOrJXl8EAaIwD2iNYmBI5SEoQ,4149
|
|
||||||
markupsafe/_speedups.cpython-310-x86_64-linux-gnu.so,sha256=x4RoxWgyqAEokk-AZrWvrLDxLE-dm-zZSZYV_gOiLJA,34976
|
|
||||||
markupsafe/_speedups.pyi,sha256=ENd1bYe7gbBUf2ywyYWOGUpnXOHNJ-cgTNqetlW8h5k,41
|
|
||||||
markupsafe/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
@ -1,6 +0,0 @@
|
|||||||
Wheel-Version: 1.0
|
|
||||||
Generator: setuptools (75.2.0)
|
|
||||||
Root-Is-Purelib: false
|
|
||||||
Tag: cp310-cp310-manylinux_2_17_x86_64
|
|
||||||
Tag: cp310-cp310-manylinux2014_x86_64
|
|
||||||
|
|
@ -1 +0,0 @@
|
|||||||
markupsafe
|
|
@ -1 +0,0 @@
|
|||||||
pip
|
|
@ -1,20 +0,0 @@
|
|||||||
Copyright (c) 2017-2021 Ingy döt Net
|
|
||||||
Copyright (c) 2006-2016 Kirill Simonov
|
|
||||||
|
|
||||||
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.
|
|
@ -1,46 +0,0 @@
|
|||||||
Metadata-Version: 2.1
|
|
||||||
Name: PyYAML
|
|
||||||
Version: 6.0.2
|
|
||||||
Summary: YAML parser and emitter for Python
|
|
||||||
Home-page: https://pyyaml.org/
|
|
||||||
Download-URL: https://pypi.org/project/PyYAML/
|
|
||||||
Author: Kirill Simonov
|
|
||||||
Author-email: xi@resolvent.net
|
|
||||||
License: MIT
|
|
||||||
Project-URL: Bug Tracker, https://github.com/yaml/pyyaml/issues
|
|
||||||
Project-URL: CI, https://github.com/yaml/pyyaml/actions
|
|
||||||
Project-URL: Documentation, https://pyyaml.org/wiki/PyYAMLDocumentation
|
|
||||||
Project-URL: Mailing lists, http://lists.sourceforge.net/lists/listinfo/yaml-core
|
|
||||||
Project-URL: Source Code, https://github.com/yaml/pyyaml
|
|
||||||
Platform: Any
|
|
||||||
Classifier: Development Status :: 5 - Production/Stable
|
|
||||||
Classifier: Intended Audience :: Developers
|
|
||||||
Classifier: License :: OSI Approved :: MIT License
|
|
||||||
Classifier: Operating System :: OS Independent
|
|
||||||
Classifier: Programming Language :: Cython
|
|
||||||
Classifier: Programming Language :: Python
|
|
||||||
Classifier: Programming Language :: Python :: 3
|
|
||||||
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 :: Implementation :: CPython
|
|
||||||
Classifier: Programming Language :: Python :: Implementation :: PyPy
|
|
||||||
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
||||||
Classifier: Topic :: Text Processing :: Markup
|
|
||||||
Requires-Python: >=3.8
|
|
||||||
License-File: LICENSE
|
|
||||||
|
|
||||||
YAML is a data serialization format designed for human readability
|
|
||||||
and interaction with scripting languages. PyYAML is a YAML parser
|
|
||||||
and emitter for Python.
|
|
||||||
|
|
||||||
PyYAML features a complete YAML 1.1 parser, Unicode support, pickle
|
|
||||||
support, capable extension API, and sensible error messages. PyYAML
|
|
||||||
supports standard YAML tags and provides Python-specific tags that
|
|
||||||
allow to represent an arbitrary Python object.
|
|
||||||
|
|
||||||
PyYAML is applicable for a broad range of tasks from complex
|
|
||||||
configuration files to object serialization and persistence.
|
|
@ -1,43 +0,0 @@
|
|||||||
PyYAML-6.0.2.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4
|
|
||||||
PyYAML-6.0.2.dist-info/LICENSE,sha256=jTko-dxEkP1jVwfLiOsmvXZBAqcoKVQwfT5RZ6V36KQ,1101
|
|
||||||
PyYAML-6.0.2.dist-info/METADATA,sha256=9-odFB5seu4pGPcEv7E8iyxNF51_uKnaNGjLAhz2lto,2060
|
|
||||||
PyYAML-6.0.2.dist-info/RECORD,,
|
|
||||||
PyYAML-6.0.2.dist-info/WHEEL,sha256=baMMpUvyD0gnRdCe6fvqCg8rft4FNTdLqZQ01WfKJmc,152
|
|
||||||
PyYAML-6.0.2.dist-info/top_level.txt,sha256=rpj0IVMTisAjh_1vG3Ccf9v5jpCQwAz6cD1IVU5ZdhQ,11
|
|
||||||
_yaml/__init__.py,sha256=04Ae_5osxahpJHa3XBZUAf4wi6XX32gR8D6X6p64GEA,1402
|
|
||||||
_yaml/__pycache__/__init__.cpython-310.pyc,,
|
|
||||||
yaml/__init__.py,sha256=N35S01HMesFTe0aRRMWkPj0Pa8IEbHpE9FK7cr5Bdtw,12311
|
|
||||||
yaml/__pycache__/__init__.cpython-310.pyc,,
|
|
||||||
yaml/__pycache__/composer.cpython-310.pyc,,
|
|
||||||
yaml/__pycache__/constructor.cpython-310.pyc,,
|
|
||||||
yaml/__pycache__/cyaml.cpython-310.pyc,,
|
|
||||||
yaml/__pycache__/dumper.cpython-310.pyc,,
|
|
||||||
yaml/__pycache__/emitter.cpython-310.pyc,,
|
|
||||||
yaml/__pycache__/error.cpython-310.pyc,,
|
|
||||||
yaml/__pycache__/events.cpython-310.pyc,,
|
|
||||||
yaml/__pycache__/loader.cpython-310.pyc,,
|
|
||||||
yaml/__pycache__/nodes.cpython-310.pyc,,
|
|
||||||
yaml/__pycache__/parser.cpython-310.pyc,,
|
|
||||||
yaml/__pycache__/reader.cpython-310.pyc,,
|
|
||||||
yaml/__pycache__/representer.cpython-310.pyc,,
|
|
||||||
yaml/__pycache__/resolver.cpython-310.pyc,,
|
|
||||||
yaml/__pycache__/scanner.cpython-310.pyc,,
|
|
||||||
yaml/__pycache__/serializer.cpython-310.pyc,,
|
|
||||||
yaml/__pycache__/tokens.cpython-310.pyc,,
|
|
||||||
yaml/_yaml.cpython-310-x86_64-linux-gnu.so,sha256=20HV-cVpIFuOuVUTmQ1-PQIbyt0n8ctfXq7JCMIfbrU,2383664
|
|
||||||
yaml/composer.py,sha256=_Ko30Wr6eDWUeUpauUGT3Lcg9QPBnOPVlTnIMRGJ9FM,4883
|
|
||||||
yaml/constructor.py,sha256=kNgkfaeLUkwQYY_Q6Ff1Tz2XVw_pG1xVE9Ak7z-viLA,28639
|
|
||||||
yaml/cyaml.py,sha256=6ZrAG9fAYvdVe2FK_w0hmXoG7ZYsoYUwapG8CiC72H0,3851
|
|
||||||
yaml/dumper.py,sha256=PLctZlYwZLp7XmeUdwRuv4nYOZ2UBnDIUy8-lKfLF-o,2837
|
|
||||||
yaml/emitter.py,sha256=jghtaU7eFwg31bG0B7RZea_29Adi9CKmXq_QjgQpCkQ,43006
|
|
||||||
yaml/error.py,sha256=Ah9z-toHJUbE9j-M8YpxgSRM5CgLCcwVzJgLLRF2Fxo,2533
|
|
||||||
yaml/events.py,sha256=50_TksgQiE4up-lKo_V-nBy-tAIxkIPQxY5qDhKCeHw,2445
|
|
||||||
yaml/loader.py,sha256=UVa-zIqmkFSCIYq_PgSGm4NSJttHY2Rf_zQ4_b1fHN0,2061
|
|
||||||
yaml/nodes.py,sha256=gPKNj8pKCdh2d4gr3gIYINnPOaOxGhJAUiYhGRnPE84,1440
|
|
||||||
yaml/parser.py,sha256=ilWp5vvgoHFGzvOZDItFoGjD6D42nhlZrZyjAwa0oJo,25495
|
|
||||||
yaml/reader.py,sha256=0dmzirOiDG4Xo41RnuQS7K9rkY3xjHiVasfDMNTqCNw,6794
|
|
||||||
yaml/representer.py,sha256=IuWP-cAW9sHKEnS0gCqSa894k1Bg4cgTxaDwIcbRQ-Y,14190
|
|
||||||
yaml/resolver.py,sha256=9L-VYfm4mWHxUD1Vg4X7rjDRK_7VZd6b92wzq7Y2IKY,9004
|
|
||||||
yaml/scanner.py,sha256=YEM3iLZSaQwXcQRg2l2R4MdT0zGP2F9eHkKGKnHyWQY,51279
|
|
||||||
yaml/serializer.py,sha256=ChuFgmhU01hj4xgI8GaKv6vfM2Bujwa9i7d2FAHj7cA,4165
|
|
||||||
yaml/tokens.py,sha256=lTQIzSVw8Mg9wv459-TjiOQe6wVziqaRlqX2_89rp54,2573
|
|
@ -1,6 +0,0 @@
|
|||||||
Wheel-Version: 1.0
|
|
||||||
Generator: bdist_wheel (0.44.0)
|
|
||||||
Root-Is-Purelib: false
|
|
||||||
Tag: cp310-cp310-manylinux_2_17_x86_64
|
|
||||||
Tag: cp310-cp310-manylinux2014_x86_64
|
|
||||||
|
|
@ -1,2 +0,0 @@
|
|||||||
_yaml
|
|
||||||
yaml
|
|
Binary file not shown.
@ -1,132 +0,0 @@
|
|||||||
import sys
|
|
||||||
import os
|
|
||||||
import re
|
|
||||||
import importlib
|
|
||||||
import warnings
|
|
||||||
|
|
||||||
|
|
||||||
is_pypy = '__pypy__' in sys.builtin_module_names
|
|
||||||
|
|
||||||
|
|
||||||
warnings.filterwarnings('ignore',
|
|
||||||
r'.+ distutils\b.+ deprecated',
|
|
||||||
DeprecationWarning)
|
|
||||||
|
|
||||||
|
|
||||||
def warn_distutils_present():
|
|
||||||
if 'distutils' not in sys.modules:
|
|
||||||
return
|
|
||||||
if is_pypy and sys.version_info < (3, 7):
|
|
||||||
# PyPy for 3.6 unconditionally imports distutils, so bypass the warning
|
|
||||||
# https://foss.heptapod.net/pypy/pypy/-/blob/be829135bc0d758997b3566062999ee8b23872b4/lib-python/3/site.py#L250
|
|
||||||
return
|
|
||||||
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
|
|
||||||
warnings.warn("Setuptools is replacing distutils.")
|
|
||||||
mods = [name for name in sys.modules if re.match(r'distutils\b', name)]
|
|
||||||
for name in mods:
|
|
||||||
del sys.modules[name]
|
|
||||||
|
|
||||||
|
|
||||||
def enabled():
|
|
||||||
"""
|
|
||||||
Allow selection of distutils by environment variable.
|
|
||||||
"""
|
|
||||||
which = os.environ.get('SETUPTOOLS_USE_DISTUTILS', 'stdlib')
|
|
||||||
return which == 'local'
|
|
||||||
|
|
||||||
|
|
||||||
def ensure_local_distutils():
|
|
||||||
clear_distutils()
|
|
||||||
|
|
||||||
# With the DistutilsMetaFinder in place,
|
|
||||||
# perform an import to cause distutils to be
|
|
||||||
# loaded from setuptools._distutils. Ref #2906.
|
|
||||||
add_shim()
|
|
||||||
importlib.import_module('distutils')
|
|
||||||
remove_shim()
|
|
||||||
|
|
||||||
# check that submodules load as expected
|
|
||||||
core = importlib.import_module('distutils.core')
|
|
||||||
assert '_distutils' in core.__file__, core.__file__
|
|
||||||
|
|
||||||
|
|
||||||
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 DistutilsMetaFinder:
|
|
||||||
def find_spec(self, fullname, path, target=None):
|
|
||||||
if path is not None:
|
|
||||||
return
|
|
||||||
|
|
||||||
method_name = 'spec_for_{fullname}'.format(**locals())
|
|
||||||
method = getattr(self, method_name, lambda: None)
|
|
||||||
return method()
|
|
||||||
|
|
||||||
def spec_for_distutils(self):
|
|
||||||
import importlib.abc
|
|
||||||
import importlib.util
|
|
||||||
|
|
||||||
class DistutilsLoader(importlib.abc.Loader):
|
|
||||||
|
|
||||||
def create_module(self, spec):
|
|
||||||
return importlib.import_module('setuptools._distutils')
|
|
||||||
|
|
||||||
def exec_module(self, module):
|
|
||||||
pass
|
|
||||||
|
|
||||||
return importlib.util.spec_from_loader('distutils', DistutilsLoader())
|
|
||||||
|
|
||||||
def spec_for_pip(self):
|
|
||||||
"""
|
|
||||||
Ensure stdlib distutils when running under pip.
|
|
||||||
See pypa/pip#8761 for rationale.
|
|
||||||
"""
|
|
||||||
if self.pip_imported_during_build():
|
|
||||||
return
|
|
||||||
clear_distutils()
|
|
||||||
self.spec_for_distutils = lambda: None
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def pip_imported_during_build():
|
|
||||||
"""
|
|
||||||
Detect if pip is being imported in a build script. Ref #2355.
|
|
||||||
"""
|
|
||||||
import traceback
|
|
||||||
return any(
|
|
||||||
frame.f_globals['__file__'].endswith('setup.py')
|
|
||||||
for frame, line in traceback.walk_stack(None)
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
DISTUTILS_FINDER = DistutilsMetaFinder()
|
|
||||||
|
|
||||||
|
|
||||||
def add_shim():
|
|
||||||
sys.meta_path.insert(0, DISTUTILS_FINDER)
|
|
||||||
|
|
||||||
|
|
||||||
def remove_shim():
|
|
||||||
try:
|
|
||||||
sys.meta_path.remove(DISTUTILS_FINDER)
|
|
||||||
except ValueError:
|
|
||||||
pass
|
|
@ -1 +0,0 @@
|
|||||||
__import__('_distutils_hack').do_override()
|
|
@ -1,33 +0,0 @@
|
|||||||
# This is a stub package designed to roughly emulate the _yaml
|
|
||||||
# extension module, which previously existed as a standalone module
|
|
||||||
# and has been moved into the `yaml` package namespace.
|
|
||||||
# It does not perfectly mimic its old counterpart, but should get
|
|
||||||
# close enough for anyone who's relying on it even when they shouldn't.
|
|
||||||
import yaml
|
|
||||||
|
|
||||||
# in some circumstances, the yaml module we imoprted may be from a different version, so we need
|
|
||||||
# to tread carefully when poking at it here (it may not have the attributes we expect)
|
|
||||||
if not getattr(yaml, '__with_libyaml__', False):
|
|
||||||
from sys import version_info
|
|
||||||
|
|
||||||
exc = ModuleNotFoundError if version_info >= (3, 6) else ImportError
|
|
||||||
raise exc("No module named '_yaml'")
|
|
||||||
else:
|
|
||||||
from yaml._yaml import *
|
|
||||||
import warnings
|
|
||||||
warnings.warn(
|
|
||||||
'The _yaml extension module is now located at yaml._yaml'
|
|
||||||
' and its location is subject to change. To use the'
|
|
||||||
' LibYAML-based parser and emitter, import from `yaml`:'
|
|
||||||
' `from yaml import CLoader as Loader, CDumper as Dumper`.',
|
|
||||||
DeprecationWarning
|
|
||||||
)
|
|
||||||
del warnings
|
|
||||||
# Don't `del yaml` here because yaml is actually an existing
|
|
||||||
# namespace member of _yaml.
|
|
||||||
|
|
||||||
__name__ = '_yaml'
|
|
||||||
# If the module is top-level (i.e. not a part of any specific package)
|
|
||||||
# then the attribute should be set to ''.
|
|
||||||
# https://docs.python.org/3.8/library/types.html
|
|
||||||
__package__ = ''
|
|
@ -1 +0,0 @@
|
|||||||
pip
|
|
@ -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.
|
|
@ -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
|
|
||||||
|
|
||||||
<p align="center">
|
|
||||||
<a href="https://github.com/aio-libs/aiohappyeyeballs/actions/workflows/ci.yml?query=branch%3Amain">
|
|
||||||
<img src="https://img.shields.io/github/actions/workflow/status/aio-libs/aiohappyeyeballs/ci-cd.yml?branch=main&label=CI&logo=github&style=flat-square" alt="CI Status" >
|
|
||||||
</a>
|
|
||||||
<a href="https://aiohappyeyeballs.readthedocs.io">
|
|
||||||
<img src="https://img.shields.io/readthedocs/aiohappyeyeballs.svg?logo=read-the-docs&logoColor=fff&style=flat-square" alt="Documentation Status">
|
|
||||||
</a>
|
|
||||||
<a href="https://codecov.io/gh/aio-libs/aiohappyeyeballs">
|
|
||||||
<img src="https://img.shields.io/codecov/c/github/aio-libs/aiohappyeyeballs.svg?logo=codecov&logoColor=fff&style=flat-square" alt="Test coverage percentage">
|
|
||||||
</a>
|
|
||||||
</p>
|
|
||||||
<p align="center">
|
|
||||||
<a href="https://python-poetry.org/">
|
|
||||||
<img src="https://img.shields.io/badge/packaging-poetry-299bd7?style=flat-square&logo=data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAA4AAAASCAYAAABrXO8xAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAJJSURBVHgBfZLPa1NBEMe/s7tNXoxW1KJQKaUHkXhQvHgW6UHQQ09CBS/6V3hKc/AP8CqCrUcpmop3Cx48eDB4yEECjVQrlZb80CRN8t6OM/teagVxYZi38+Yz853dJbzoMV3MM8cJUcLMSUKIE8AzQ2PieZzFxEJOHMOgMQQ+dUgSAckNXhapU/NMhDSWLs1B24A8sO1xrN4NECkcAC9ASkiIJc6k5TRiUDPhnyMMdhKc+Zx19l6SgyeW76BEONY9exVQMzKExGKwwPsCzza7KGSSWRWEQhyEaDXp6ZHEr416ygbiKYOd7TEWvvcQIeusHYMJGhTwF9y7sGnSwaWyFAiyoxzqW0PM/RjghPxF2pWReAowTEXnDh0xgcLs8l2YQmOrj3N7ByiqEoH0cARs4u78WgAVkoEDIDoOi3AkcLOHU60RIg5wC4ZuTC7FaHKQm8Hq1fQuSOBvX/sodmNJSB5geaF5CPIkUeecdMxieoRO5jz9bheL6/tXjrwCyX/UYBUcjCaWHljx1xiX6z9xEjkYAzbGVnB8pvLmyXm9ep+W8CmsSHQQY77Zx1zboxAV0w7ybMhQmfqdmmw3nEp1I0Z+FGO6M8LZdoyZnuzzBdjISicKRnpxzI9fPb+0oYXsNdyi+d3h9bm9MWYHFtPeIZfLwzmFDKy1ai3p+PDls1Llz4yyFpferxjnyjJDSEy9CaCx5m2cJPerq6Xm34eTrZt3PqxYO1XOwDYZrFlH1fWnpU38Y9HRze3lj0vOujZcXKuuXm3jP+s3KbZVra7y2EAAAAAASUVORK5CYII=" alt="Poetry">
|
|
||||||
</a>
|
|
||||||
<a href="https://github.com/astral-sh/ruff">
|
|
||||||
<img src="https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/ruff/main/assets/badge/v2.json" alt="Ruff">
|
|
||||||
</a>
|
|
||||||
<a href="https://github.com/pre-commit/pre-commit">
|
|
||||||
<img src="https://img.shields.io/badge/pre--commit-enabled-brightgreen?logo=pre-commit&logoColor=white&style=flat-square" alt="pre-commit">
|
|
||||||
</a>
|
|
||||||
</p>
|
|
||||||
<p align="center">
|
|
||||||
<a href="https://pypi.org/project/aiohappyeyeballs/">
|
|
||||||
<img src="https://img.shields.io/pypi/v/aiohappyeyeballs.svg?logo=python&logoColor=fff&style=flat-square" alt="PyPI Version">
|
|
||||||
</a>
|
|
||||||
<img src="https://img.shields.io/pypi/pyversions/aiohappyeyeballs.svg?style=flat-square&logo=python&logoColor=fff" alt="Supported Python versions">
|
|
||||||
<img src="https://img.shields.io/pypi/l/aiohappyeyeballs.svg?style=flat-square" alt="License">
|
|
||||||
</p>
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
**Documentation**: <a href="https://aiohappyeyeballs.readthedocs.io" target="_blank">https://aiohappyeyeballs.readthedocs.io </a>
|
|
||||||
|
|
||||||
**Source Code**: <a href="https://github.com/aio-libs/aiohappyeyeballs" target="_blank">https://github.com/aio-libs/aiohappyeyeballs </a>
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
[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.
|
|
||||||
|
|
@ -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-310.pyc,,
|
|
||||||
aiohappyeyeballs/__pycache__/_staggered.cpython-310.pyc,,
|
|
||||||
aiohappyeyeballs/__pycache__/impl.cpython-310.pyc,,
|
|
||||||
aiohappyeyeballs/__pycache__/types.cpython-310.pyc,,
|
|
||||||
aiohappyeyeballs/__pycache__/utils.cpython-310.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
|
|
@ -1,4 +0,0 @@
|
|||||||
Wheel-Version: 1.0
|
|
||||||
Generator: poetry-core 2.1.1
|
|
||||||
Root-Is-Purelib: true
|
|
||||||
Tag: py3-none-any
|
|
@ -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",
|
|
||||||
)
|
|
@ -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
|
|
@ -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
|
|
@ -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]
|
|
@ -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")
|
|
@ -1 +0,0 @@
|
|||||||
pip
|
|
@ -1,251 +0,0 @@
|
|||||||
Metadata-Version: 2.4
|
|
||||||
Name: aiohttp
|
|
||||||
Version: 3.11.18
|
|
||||||
Summary: Async http client/server framework (asyncio)
|
|
||||||
Home-page: https://github.com/aio-libs/aiohttp
|
|
||||||
Maintainer: aiohttp team <team@aiohttp.org>
|
|
||||||
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/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: License :: OSI Approved :: Apache Software License
|
|
||||||
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: Topic :: Internet :: WWW/HTTP
|
|
||||||
Requires-Python: >=3.9
|
|
||||||
Description-Content-Type: text/x-rst
|
|
||||||
License-File: LICENSE.txt
|
|
||||||
Requires-Dist: aiohappyeyeballs>=2.3.0
|
|
||||||
Requires-Dist: aiosignal>=1.1.2
|
|
||||||
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.2.0; (sys_platform == "linux" or sys_platform == "darwin") and extra == "speedups"
|
|
||||||
Requires-Dist: Brotli; platform_python_implementation == "CPython" and extra == "speedups"
|
|
||||||
Requires-Dist: brotlicffi; platform_python_implementation != "CPython" 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://img.shields.io/endpoint?url=https://codspeed.io/badge.json
|
|
||||||
:target: https://codspeed.io/aio-libs/aiohttp
|
|
||||||
:alt: Codspeed.io status for aiohttp
|
|
||||||
|
|
||||||
.. image:: https://badge.fury.io/py/aiohttp.svg
|
|
||||||
:target: https://pypi.org/project/aiohttp
|
|
||||||
:alt: Latest PyPI package version
|
|
||||||
|
|
||||||
.. image:: https://readthedocs.org/projects/aiohttp/badge/?version=latest
|
|
||||||
:target: https://docs.aiohttp.org/
|
|
||||||
:alt: Latest Read The Docs
|
|
||||||
|
|
||||||
.. 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
|
|
||||||
|
|
||||||
|
|
||||||
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: <!doctype html> ...
|
|
||||||
|
|
||||||
Coming from `requests <https://requests.readthedocs.io/>`_ ? Read `why we need so many lines <https://aiohttp.readthedocs.io/en/latest/http_request_lifecycle.html>`_.
|
|
||||||
|
|
||||||
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
|
|
||||||
<http://aiohttp.readthedocs.io/en/latest/third_party.html>`_
|
|
||||||
* `Built with aiohttp
|
|
||||||
<http://aiohttp.readthedocs.io/en/latest/built_with.html>`_
|
|
||||||
* `Powered by aiohttp
|
|
||||||
<http://aiohttp.readthedocs.io/en/latest/powered_by.html>`_
|
|
||||||
|
|
||||||
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 <https://matrix.to/#/#aio-libs:matrix.org>`_
|
|
||||||
|
|
||||||
We support `Stack Overflow
|
|
||||||
<https://stackoverflow.com/questions/tagged/aiohttp>`_.
|
|
||||||
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
|
|
@ -1,131 +0,0 @@
|
|||||||
aiohttp-3.11.18.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4
|
|
||||||
aiohttp-3.11.18.dist-info/METADATA,sha256=UQ-0odI_X0zoX3I7iqbE9eoQmKQoLKI7mLXcW3TXvJQ,7734
|
|
||||||
aiohttp-3.11.18.dist-info/RECORD,,
|
|
||||||
aiohttp-3.11.18.dist-info/WHEEL,sha256=4C__1oc1ViJB-9YxJgpUHVRXF8dql_8MEU-gJuoIF8Q,151
|
|
||||||
aiohttp-3.11.18.dist-info/licenses/LICENSE.txt,sha256=n4DQ2311WpQdtFchcsJw7L2PCCuiFd3QlZhZQu2Uqes,588
|
|
||||||
aiohttp-3.11.18.dist-info/top_level.txt,sha256=iv-JIaacmTl-hSho3QmphcKnbRRYx1st47yjz_178Ro,8
|
|
||||||
aiohttp/.hash/_cparser.pxd.hash,sha256=hYa9Vje-oMs2eh_7MfCPOh2QW_1x1yCjcZuc7AmwLd0,121
|
|
||||||
aiohttp/.hash/_find_header.pxd.hash,sha256=_mbpD6vM-CVCKq3ulUvsOAz5Wdo88wrDzfpOsMQaMNA,125
|
|
||||||
aiohttp/.hash/_http_parser.pyx.hash,sha256=GBgZjCNbtZApPhf9-gHpS5Z2WMIzM-vgp5VSZIEvZfk,125
|
|
||||||
aiohttp/.hash/_http_writer.pyx.hash,sha256=uhOanbDG8R2Pxria3xMb15h7biBeeT3ioBoQNwqKYp8,125
|
|
||||||
aiohttp/.hash/hdrs.py.hash,sha256=v6IaKbsxjsdQxBzhb5AjP0x_9G3rUe84D7avf7AI4cs,116
|
|
||||||
aiohttp/__init__.py,sha256=0cJB-M8GgSmOQVpa6xqnk1pBf7pLBc4RcLde78nmzug,7840
|
|
||||||
aiohttp/__pycache__/__init__.cpython-310.pyc,,
|
|
||||||
aiohttp/__pycache__/abc.cpython-310.pyc,,
|
|
||||||
aiohttp/__pycache__/base_protocol.cpython-310.pyc,,
|
|
||||||
aiohttp/__pycache__/client.cpython-310.pyc,,
|
|
||||||
aiohttp/__pycache__/client_exceptions.cpython-310.pyc,,
|
|
||||||
aiohttp/__pycache__/client_proto.cpython-310.pyc,,
|
|
||||||
aiohttp/__pycache__/client_reqrep.cpython-310.pyc,,
|
|
||||||
aiohttp/__pycache__/client_ws.cpython-310.pyc,,
|
|
||||||
aiohttp/__pycache__/compression_utils.cpython-310.pyc,,
|
|
||||||
aiohttp/__pycache__/connector.cpython-310.pyc,,
|
|
||||||
aiohttp/__pycache__/cookiejar.cpython-310.pyc,,
|
|
||||||
aiohttp/__pycache__/formdata.cpython-310.pyc,,
|
|
||||||
aiohttp/__pycache__/hdrs.cpython-310.pyc,,
|
|
||||||
aiohttp/__pycache__/helpers.cpython-310.pyc,,
|
|
||||||
aiohttp/__pycache__/http.cpython-310.pyc,,
|
|
||||||
aiohttp/__pycache__/http_exceptions.cpython-310.pyc,,
|
|
||||||
aiohttp/__pycache__/http_parser.cpython-310.pyc,,
|
|
||||||
aiohttp/__pycache__/http_websocket.cpython-310.pyc,,
|
|
||||||
aiohttp/__pycache__/http_writer.cpython-310.pyc,,
|
|
||||||
aiohttp/__pycache__/log.cpython-310.pyc,,
|
|
||||||
aiohttp/__pycache__/multipart.cpython-310.pyc,,
|
|
||||||
aiohttp/__pycache__/payload.cpython-310.pyc,,
|
|
||||||
aiohttp/__pycache__/payload_streamer.cpython-310.pyc,,
|
|
||||||
aiohttp/__pycache__/pytest_plugin.cpython-310.pyc,,
|
|
||||||
aiohttp/__pycache__/resolver.cpython-310.pyc,,
|
|
||||||
aiohttp/__pycache__/streams.cpython-310.pyc,,
|
|
||||||
aiohttp/__pycache__/tcp_helpers.cpython-310.pyc,,
|
|
||||||
aiohttp/__pycache__/test_utils.cpython-310.pyc,,
|
|
||||||
aiohttp/__pycache__/tracing.cpython-310.pyc,,
|
|
||||||
aiohttp/__pycache__/typedefs.cpython-310.pyc,,
|
|
||||||
aiohttp/__pycache__/web.cpython-310.pyc,,
|
|
||||||
aiohttp/__pycache__/web_app.cpython-310.pyc,,
|
|
||||||
aiohttp/__pycache__/web_exceptions.cpython-310.pyc,,
|
|
||||||
aiohttp/__pycache__/web_fileresponse.cpython-310.pyc,,
|
|
||||||
aiohttp/__pycache__/web_log.cpython-310.pyc,,
|
|
||||||
aiohttp/__pycache__/web_middlewares.cpython-310.pyc,,
|
|
||||||
aiohttp/__pycache__/web_protocol.cpython-310.pyc,,
|
|
||||||
aiohttp/__pycache__/web_request.cpython-310.pyc,,
|
|
||||||
aiohttp/__pycache__/web_response.cpython-310.pyc,,
|
|
||||||
aiohttp/__pycache__/web_routedef.cpython-310.pyc,,
|
|
||||||
aiohttp/__pycache__/web_runner.cpython-310.pyc,,
|
|
||||||
aiohttp/__pycache__/web_server.cpython-310.pyc,,
|
|
||||||
aiohttp/__pycache__/web_urldispatcher.cpython-310.pyc,,
|
|
||||||
aiohttp/__pycache__/web_ws.cpython-310.pyc,,
|
|
||||||
aiohttp/__pycache__/worker.cpython-310.pyc,,
|
|
||||||
aiohttp/_cparser.pxd,sha256=8jGIg-VJ9p3llwCakUYDsPGxA4HiZe9dmK9Jmtlz-5g,4318
|
|
||||||
aiohttp/_find_header.pxd,sha256=0GfwFCPN2zxEKTO1_MA5sYq2UfzsG8kcV3aTqvwlz3g,68
|
|
||||||
aiohttp/_headers.pxi,sha256=n701k28dVPjwRnx5j6LpJhLTfj7dqu2vJt7f0O60Oyg,2007
|
|
||||||
aiohttp/_http_parser.cpython-310-x86_64-linux-gnu.so,sha256=8xfV_7c95oXwsIbfVZPQmDR8txHmEdfNI6sqhZt7dzU,2627272
|
|
||||||
aiohttp/_http_parser.pyx,sha256=wQdADj5LizwC_7nFGr8nIlk6GpoaQeQ0359H0HMKGuM,28241
|
|
||||||
aiohttp/_http_writer.cpython-310-x86_64-linux-gnu.so,sha256=foKhstAcSFs_xMxsDLgTpyPbd5nyrTO56dz71kbDNI0,473136
|
|
||||||
aiohttp/_http_writer.pyx,sha256=96seJigne4J3LVnB3DAzwTSV12nfZ7HR1JsaR0p13VI,4561
|
|
||||||
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-310.pyc,,
|
|
||||||
aiohttp/_websocket/__pycache__/helpers.cpython-310.pyc,,
|
|
||||||
aiohttp/_websocket/__pycache__/models.cpython-310.pyc,,
|
|
||||||
aiohttp/_websocket/__pycache__/reader.cpython-310.pyc,,
|
|
||||||
aiohttp/_websocket/__pycache__/reader_c.cpython-310.pyc,,
|
|
||||||
aiohttp/_websocket/__pycache__/reader_py.cpython-310.pyc,,
|
|
||||||
aiohttp/_websocket/__pycache__/writer.cpython-310.pyc,,
|
|
||||||
aiohttp/_websocket/helpers.py,sha256=P-XLv8IUaihKzDenVUqfKU5DJbWE5HvG8uhvUZK8Ic4,5038
|
|
||||||
aiohttp/_websocket/mask.cpython-310-x86_64-linux-gnu.so,sha256=L9ajs3rFmd9kYjyqLZRd3M1ab39YB9QrA9c5Qlbk7W0,223824
|
|
||||||
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-310-x86_64-linux-gnu.so,sha256=zQAL0oxgMBbHDM0hvOCsRHYpvslhApwtYTC_LvWp9FA,1650008
|
|
||||||
aiohttp/_websocket/reader_c.pxd,sha256=nl_njtDrzlQU0rjgGGjZDB-swguE0tX_bCPobkShVa4,2625
|
|
||||||
aiohttp/_websocket/reader_c.py,sha256=PGPGNljGjdyi-Vu0EJmSqeeUKYYpMUfOXXTm4XYGgkY,18358
|
|
||||||
aiohttp/_websocket/reader_py.py,sha256=PGPGNljGjdyi-Vu0EJmSqeeUKYYpMUfOXXTm4XYGgkY,18358
|
|
||||||
aiohttp/_websocket/writer.py,sha256=T3P36iMrzVPPC2XeScserHMD5vd9an6yizWzqDUkRZ0,7077
|
|
||||||
aiohttp/abc.py,sha256=JLMOxrKLGTDaPRLfraY1pl-xka53YiHhAH9yaF9QRXQ,6512
|
|
||||||
aiohttp/base_protocol.py,sha256=Tp8cxUPQvv9kUPk3w6lAzk6d2MAzV3scwI_3Go3C47c,3025
|
|
||||||
aiohttp/client.py,sha256=isdfGlM4O5ILr4F4gBABlybxo4MQ1tNaMm7zjMcrfrM,54309
|
|
||||||
aiohttp/client_exceptions.py,sha256=uyKbxI2peZhKl7lELBMx3UeusNkfpemPWpGFq0r6JeM,11367
|
|
||||||
aiohttp/client_proto.py,sha256=ThkL2fsULn00l1yjez4bHrGlnShVZaijMq-RvX-XsVc,10073
|
|
||||||
aiohttp/client_reqrep.py,sha256=VAgh0NxP2HvYWx6nX1Pr8FINc1m-W8-5q2zKeZV68n8,43925
|
|
||||||
aiohttp/client_ws.py,sha256=1CIjIXwyzOMIYw6AjUES4-qUwbyVHW1seJKQfg_Rta8,15109
|
|
||||||
aiohttp/compression_utils.py,sha256=0J3EAOR-0HehlYIudJXRu_Kr6hrYCY0IfuJ1px9MhQs,5681
|
|
||||||
aiohttp/connector.py,sha256=P3F6Bb1QI62mKPJxfK0Ru_7Q5YmvxKg7uHQOcS8UXUI,60545
|
|
||||||
aiohttp/cookiejar.py,sha256=PYR1K1mkLa24Hm6c9UEJnAitccNzz97CbsJyQ2ULAlU,17615
|
|
||||||
aiohttp/formdata.py,sha256=CUJnCWDNHFcXSYZ_TupaT6rHkY-Q7ghssvWzaYBPIo0,6552
|
|
||||||
aiohttp/hdrs.py,sha256=2rj5MyA-6yRdYPhW5UKkW4iNWhEAlGIOSBH5D4FmKNE,5111
|
|
||||||
aiohttp/helpers.py,sha256=bblNEhp4hFimEmxMdPNxEluBY17L5YUArHYvoxzoEe4,29614
|
|
||||||
aiohttp/http.py,sha256=8o8j8xH70OWjnfTWA9V44NR785QPxEPrUtzMXiAVpwc,1842
|
|
||||||
aiohttp/http_exceptions.py,sha256=RYmBycJvvPerKkgXXm8v145I1N-fbsgSpcsbNIC-gdE,2961
|
|
||||||
aiohttp/http_parser.py,sha256=UqerYPJzA1MqLmeG1jURhTNO1YhwUASK3QVcNEz0me8,36851
|
|
||||||
aiohttp/http_websocket.py,sha256=8VXFKw6KQUEmPg48GtRMB37v0gTK7A0inoxXuDxMZEc,842
|
|
||||||
aiohttp/http_writer.py,sha256=pRIyfOmL3cZmdWDWBBJ2cZEwEJzLWzlPPAJInaPLThI,7595
|
|
||||||
aiohttp/log.py,sha256=BbNKx9e3VMIm0xYjZI0IcBBoS7wjdeIeSaiJE7-qK2g,325
|
|
||||||
aiohttp/multipart.py,sha256=SABIvo3vhXzG4bLDZ0C4V3yG_86vAb-3Zb9Li7BVmI8,36944
|
|
||||||
aiohttp/payload.py,sha256=rCA9JJI_RMCik_7qNIaC1Bh21aXhABGYK2tsYeaHRQ4,15793
|
|
||||||
aiohttp/payload_streamer.py,sha256=ZzEYyfzcjGWkVkK3XR2pBthSCSIykYvY3Wr5cGQ2eTc,2211
|
|
||||||
aiohttp/py.typed,sha256=sow9soTwP9T_gEAQSVh7Gb8855h04Nwmhs2We-JRgZM,7
|
|
||||||
aiohttp/pytest_plugin.py,sha256=9_W52SURT-ap75wXSJmrAOvCl2DWr_aMHgM5qfQlH2s,12768
|
|
||||||
aiohttp/resolver.py,sha256=aFKe2klqUyrczmvB31_dju50J8_ROl8LwlbTXgqig7s,6469
|
|
||||||
aiohttp/streams.py,sha256=U-qTkuAqIfpJChuKEy-vYn8nQ_Z1MVcW0WO2DHiJz_o,22329
|
|
||||||
aiohttp/tcp_helpers.py,sha256=BSadqVWaBpMFDRWnhaaR941N9MiDZ7bdTrxgCb0CW-M,961
|
|
||||||
aiohttp/test_utils.py,sha256=ZJSzZWjC76KSbtwddTKcP6vHpUl_ozfAf3F93ewmHRU,23016
|
|
||||||
aiohttp/tracing.py,sha256=66XQwtdR5DHv8p953eeNL0l8o6iHDaNwH9bBaybHXD4,15137
|
|
||||||
aiohttp/typedefs.py,sha256=wUlqwe9Mw9W8jT3HsYJcYk00qP3EMPz3nTkYXmeNN48,1657
|
|
||||||
aiohttp/web.py,sha256=As5nqGQy4QXWMXSaOsh0JudSVVJVIt_nr3n0b8CaMb0,18422
|
|
||||||
aiohttp/web_app.py,sha256=Zre0QHM9JAp4d7jrj5NRxlPnfTrKLNuA42Rdsh8Q2TI,19554
|
|
||||||
aiohttp/web_exceptions.py,sha256=7nIuiwhZ39vJJ9KrWqArA5QcWbUdqkz2CLwEpJapeN8,10360
|
|
||||||
aiohttp/web_fileresponse.py,sha256=FRsS0p9r1KU5y8ceG0QXBYnrL6xggjbxcXSmI6qIR4k,16504
|
|
||||||
aiohttp/web_log.py,sha256=rX5D7xLOX2B6BMdiZ-chme_KfJfW5IXEoFwLfkfkajs,7865
|
|
||||||
aiohttp/web_middlewares.py,sha256=sFI0AgeNjdyAjuz92QtMIpngmJSOxrqe2Jfbs4BNUu0,4165
|
|
||||||
aiohttp/web_protocol.py,sha256=c8a0PKGqfhIAiq2RboMsy1NRza4dnj6gnXIWvJUeCF0,27015
|
|
||||||
aiohttp/web_request.py,sha256=S1m2Z_NLJ17XwuGC1em9bHWrtYcp_a1mNvqCrwY-FkQ,29637
|
|
||||||
aiohttp/web_response.py,sha256=hP4vgcpX8Vqp1ArwjxZh31M57Pzw_M4a4_DtfIdQE30,28571
|
|
||||||
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=sFkcsa8qLFkDp47_oW7Z7fiq7DcVXiff1Etn0QN8DJA,44000
|
|
||||||
aiohttp/web_ws.py,sha256=pyC31WpoQP9WIeCId9uJ4PKeFguESMb7DE3fcybT_RQ,22652
|
|
||||||
aiohttp/worker.py,sha256=zT0iWN5Xze194bO6_VjHou0x7lR_k0MviN6Kadnk22g,8152
|
|
@ -1,6 +0,0 @@
|
|||||||
Wheel-Version: 1.0
|
|
||||||
Generator: setuptools (79.0.0)
|
|
||||||
Root-Is-Purelib: false
|
|
||||||
Tag: cp310-cp310-manylinux_2_17_x86_64
|
|
||||||
Tag: cp310-cp310-manylinux2014_x86_64
|
|
||||||
|
|
@ -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.
|
|
@ -1 +0,0 @@
|
|||||||
aiohttp
|
|
@ -1 +0,0 @@
|
|||||||
f2318883e549f69de597009a914603b0f1b10381e265ef5d98af499ad973fb98 /home/runner/work/aiohttp/aiohttp/aiohttp/_cparser.pxd
|
|
@ -1 +0,0 @@
|
|||||||
d067f01423cddb3c442933b5fcc039b18ab651fcec1bc91c577693aafc25cf78 /home/runner/work/aiohttp/aiohttp/aiohttp/_find_header.pxd
|
|
@ -1 +0,0 @@
|
|||||||
c107400e3e4b8b3c02ffb9c51abf2722593a1a9a1a41e434df9f47d0730a1ae3 /home/runner/work/aiohttp/aiohttp/aiohttp/_http_parser.pyx
|
|
@ -1 +0,0 @@
|
|||||||
f7ab1e2628277b82772d59c1dc3033c13495d769df67b1d1d49b1a474a75dd52 /home/runner/work/aiohttp/aiohttp/aiohttp/_http_writer.pyx
|
|
@ -1 +0,0 @@
|
|||||||
dab8f933203eeb245d60f856e542a45b888d5a110094620e4811f90f816628d1 /home/runner/work/aiohttp/aiohttp/aiohttp/hdrs.py
|
|
@ -1,264 +0,0 @@
|
|||||||
__version__ = "3.11.18"
|
|
||||||
|
|
||||||
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 .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
|
|
||||||
"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",
|
|
||||||
"SocketTimeoutError",
|
|
||||||
"TCPConnector",
|
|
||||||
"TooManyRedirects",
|
|
||||||
"UnixConnector",
|
|
||||||
"NamedPipeConnector",
|
|
||||||
"WSServerHandshakeError",
|
|
||||||
"request",
|
|
||||||
# cookiejar
|
|
||||||
"CookieJar",
|
|
||||||
"DummyCookieJar",
|
|
||||||
# formdata
|
|
||||||
"FormData",
|
|
||||||
# helpers
|
|
||||||
"BasicAuth",
|
|
||||||
"ChainMapProxy",
|
|
||||||
"ETag",
|
|
||||||
# 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}")
|
|
@ -1,158 +0,0 @@
|
|||||||
from libc.stdint cimport int32_t, uint8_t, uint16_t, uint64_t
|
|
||||||
|
|
||||||
|
|
||||||
cdef extern from "../vendor/llhttp/build/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)
|
|
@ -1,2 +0,0 @@
|
|||||||
cdef extern from "_find_header.h":
|
|
||||||
int find_header(char *, int)
|
|
@ -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,
|
|
||||||
)
|
|
Binary file not shown.
@ -1,837 +0,0 @@
|
|||||||
#cython: language_level=3
|
|
||||||
#
|
|
||||||
# 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""
|
|
||||||
|
|
||||||
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(<cparser.llhttp_method_t> i).decode('ascii'))
|
|
||||||
|
|
||||||
|
|
||||||
cdef inline str http_method_str(int i):
|
|
||||||
if i < METHODS_COUNT:
|
|
||||||
return <str>_http_method[i]
|
|
||||||
else:
|
|
||||||
return "<unknown>"
|
|
||||||
|
|
||||||
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 '<RawRequestMessage(' + sinfo + ')>'
|
|
||||||
|
|
||||||
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 '<RawResponseMessage(' + sinfo + ')>'
|
|
||||||
|
|
||||||
|
|
||||||
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
|
|
||||||
|
|
||||||
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 _started
|
|
||||||
object _url
|
|
||||||
bytearray _buf
|
|
||||||
str _path
|
|
||||||
str _reason
|
|
||||||
list _headers
|
|
||||||
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 = <cparser.llhttp_t*> \
|
|
||||||
PyMem_Malloc(sizeof(cparser.llhttp_t))
|
|
||||||
if self._cparser is NULL:
|
|
||||||
raise MemoryError()
|
|
||||||
|
|
||||||
self._csettings = <cparser.llhttp_settings_t*> \
|
|
||||||
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=32768,
|
|
||||||
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 = <void*>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._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._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')
|
|
||||||
|
|
||||||
self._headers.append((name, value))
|
|
||||||
|
|
||||||
if name is CONTENT_ENCODING:
|
|
||||||
self._content_encoding = value
|
|
||||||
|
|
||||||
self._has_value = False
|
|
||||||
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:
|
|
||||||
allowed = upgrade and headers.get("upgrade", "").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
|
|
||||||
enc = enc.lower()
|
|
||||||
if enc in ('gzip', 'deflate', 'br'):
|
|
||||||
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 for satisfy transfer length header.")
|
|
||||||
elif self._cparser.flags & cparser.F_CONTENT_LENGTH:
|
|
||||||
raise ContentLengthError(
|
|
||||||
"Not enough data for 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
|
|
||||||
cdef cparser.llhttp_errno_t errno
|
|
||||||
|
|
||||||
PyObject_GetBuffer(data, &self.py_buf, PyBUF_SIMPLE)
|
|
||||||
data_len = <size_t>self.py_buf.len
|
|
||||||
|
|
||||||
errno = cparser.llhttp_execute(
|
|
||||||
self._cparser,
|
|
||||||
<char*>self.py_buf.buf,
|
|
||||||
data_len)
|
|
||||||
|
|
||||||
if errno is cparser.HPE_PAUSED_UPGRADE:
|
|
||||||
cparser.llhttp_resume_after_upgrade(self._cparser)
|
|
||||||
|
|
||||||
nb = cparser.llhttp_get_error_pos(self._cparser) - <char*>self.py_buf.buf
|
|
||||||
|
|
||||||
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 - <char*>self.py_buf.buf]
|
|
||||||
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=32768,
|
|
||||||
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=32768,
|
|
||||||
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)
|
|
||||||
|
|
||||||
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 = <HttpParser>parser.data
|
|
||||||
|
|
||||||
pyparser._started = True
|
|
||||||
pyparser._headers = []
|
|
||||||
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 = <HttpParser>parser.data
|
|
||||||
try:
|
|
||||||
if length > pyparser._max_line_size:
|
|
||||||
raise LineTooLong(
|
|
||||||
'Status line is too long', pyparser._max_line_size, length)
|
|
||||||
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 = <HttpParser>parser.data
|
|
||||||
cdef str reason
|
|
||||||
try:
|
|
||||||
if length > pyparser._max_line_size:
|
|
||||||
raise LineTooLong(
|
|
||||||
'Status line is too long', pyparser._max_line_size, length)
|
|
||||||
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 = <HttpParser>parser.data
|
|
||||||
cdef Py_ssize_t size
|
|
||||||
try:
|
|
||||||
pyparser._on_status_complete()
|
|
||||||
size = len(pyparser._raw_name) + length
|
|
||||||
if size > pyparser._max_field_size:
|
|
||||||
raise LineTooLong(
|
|
||||||
'Header name is too long', pyparser._max_field_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 = <HttpParser>parser.data
|
|
||||||
cdef Py_ssize_t size
|
|
||||||
try:
|
|
||||||
size = len(pyparser._raw_value) + length
|
|
||||||
if size > pyparser._max_field_size:
|
|
||||||
raise LineTooLong(
|
|
||||||
'Header value is too long', pyparser._max_field_size, 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 = <HttpParser>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 = <HttpParser>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 = <HttpParser>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 = <HttpParser>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 = <HttpParser>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)
|
|
Binary file not shown.
@ -1,160 +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 char BUFFER[BUF_SIZE]
|
|
||||||
|
|
||||||
cdef object _istr = istr
|
|
||||||
|
|
||||||
|
|
||||||
# ----------------- writer ---------------------------
|
|
||||||
|
|
||||||
cdef struct Writer:
|
|
||||||
char *buf
|
|
||||||
Py_ssize_t size
|
|
||||||
Py_ssize_t pos
|
|
||||||
|
|
||||||
|
|
||||||
cdef inline void _init_writer(Writer* writer):
|
|
||||||
writer.buf = &BUFFER[0]
|
|
||||||
writer.size = BUF_SIZE
|
|
||||||
writer.pos = 0
|
|
||||||
|
|
||||||
|
|
||||||
cdef inline void _release_writer(Writer* writer):
|
|
||||||
if writer.buf != BUFFER:
|
|
||||||
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 writer.buf == BUFFER:
|
|
||||||
buf = <char*>PyMem_Malloc(size)
|
|
||||||
if buf == NULL:
|
|
||||||
PyErr_NoMemory()
|
|
||||||
return -1
|
|
||||||
memcpy(buf, writer.buf, writer.size)
|
|
||||||
else:
|
|
||||||
buf = <char*>PyMem_Realloc(writer.buf, size)
|
|
||||||
if buf == NULL:
|
|
||||||
PyErr_NoMemory()
|
|
||||||
return -1
|
|
||||||
writer.buf = buf
|
|
||||||
writer.size = size
|
|
||||||
writer.buf[writer.pos] = <char>ch
|
|
||||||
writer.pos += 1
|
|
||||||
return 0
|
|
||||||
|
|
||||||
|
|
||||||
cdef inline int _write_utf8(Writer* writer, Py_UCS4 symbol):
|
|
||||||
cdef uint64_t utf = <uint64_t> symbol
|
|
||||||
|
|
||||||
if utf < 0x80:
|
|
||||||
return _write_byte(writer, <uint8_t>utf)
|
|
||||||
elif utf < 0x800:
|
|
||||||
if _write_byte(writer, <uint8_t>(0xc0 | (utf >> 6))) < 0:
|
|
||||||
return -1
|
|
||||||
return _write_byte(writer, <uint8_t>(0x80 | (utf & 0x3f)))
|
|
||||||
elif 0xD800 <= utf <= 0xDFFF:
|
|
||||||
# surogate pair, ignored
|
|
||||||
return 0
|
|
||||||
elif utf < 0x10000:
|
|
||||||
if _write_byte(writer, <uint8_t>(0xe0 | (utf >> 12))) < 0:
|
|
||||||
return -1
|
|
||||||
if _write_byte(writer, <uint8_t>(0x80 | ((utf >> 6) & 0x3f))) < 0:
|
|
||||||
return -1
|
|
||||||
return _write_byte(writer, <uint8_t>(0x80 | (utf & 0x3f)))
|
|
||||||
elif utf > 0x10FFFF:
|
|
||||||
# symbol is too large
|
|
||||||
return 0
|
|
||||||
else:
|
|
||||||
if _write_byte(writer, <uint8_t>(0xf0 | (utf >> 18))) < 0:
|
|
||||||
return -1
|
|
||||||
if _write_byte(writer,
|
|
||||||
<uint8_t>(0x80 | ((utf >> 12) & 0x3f))) < 0:
|
|
||||||
return -1
|
|
||||||
if _write_byte(writer,
|
|
||||||
<uint8_t>(0x80 | ((utf >> 6) & 0x3f))) < 0:
|
|
||||||
return -1
|
|
||||||
return _write_byte(writer, <uint8_t>(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 = <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 == 0x0D or ch == 0x0A:
|
|
||||||
raise ValueError(
|
|
||||||
"Newline or carriage return 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
|
|
||||||
|
|
||||||
_init_writer(&writer)
|
|
||||||
|
|
||||||
try:
|
|
||||||
if _write_str(&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)
|
|
@ -1 +0,0 @@
|
|||||||
b01999d409b29bd916e067bc963d5f2d9ee63cfc9ae0bccb769910131417bf93 /home/runner/work/aiohttp/aiohttp/aiohttp/_websocket/mask.pxd
|
|
@ -1 +0,0 @@
|
|||||||
0478ceb55d0ed30ef1a7da742cd003449bc69a07cf9fdb06789bd2b347cbfffe /home/runner/work/aiohttp/aiohttp/aiohttp/_websocket/mask.pyx
|
|
@ -1 +0,0 @@
|
|||||||
9e5fe78ed0ebce5414d2b8e01868d90c1facc20b84d2d5ff6c23e86e44a155ae /home/runner/work/aiohttp/aiohttp/aiohttp/_websocket/reader_c.pxd
|
|
@ -1 +0,0 @@
|
|||||||
"""WebSocket protocol versions 13 and 8."""
|
|
@ -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)
|
|
Binary file not shown.
@ -1,3 +0,0 @@
|
|||||||
"""Cython declarations for websocket masking."""
|
|
||||||
|
|
||||||
cpdef void _websocket_mask_cython(bytes mask, bytearray data)
|
|
@ -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 = <unsigned char*>PyByteArray_AsString(data)
|
|
||||||
mask_buf = <const unsigned char*>PyBytes_AsString(mask)
|
|
||||||
uint32_msk = (<uint32_t*>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:
|
|
||||||
(<uint64_t*>in_buf)[0] ^= uint64_msk
|
|
||||||
in_buf += 8
|
|
||||||
data_len -= 8
|
|
||||||
|
|
||||||
|
|
||||||
while data_len >= 4:
|
|
||||||
(<uint32_t*>in_buf)[0] ^= uint32_msk
|
|
||||||
in_buf += 4
|
|
||||||
data_len -= 4
|
|
||||||
|
|
||||||
for i in range(0, data_len):
|
|
||||||
in_buf[i] ^= mask_buf[i]
|
|
@ -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."""
|
|
@ -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
|
|
Binary file not shown.
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user